1877 lines
77 KiB
Ruby
1877 lines
77 KiB
Ruby
#
|
|
# Copyright (C) 2011 - 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'
|
|
require_relative '../sharding_spec_helper'
|
|
|
|
describe DiscussionTopicsController do
|
|
before :once do
|
|
course_with_teacher(active_all: true)
|
|
course_with_observer(active_all: true, course: @course)
|
|
@observer_enrollment = @enrollment
|
|
ta_in_course(active_all: true, course: @course)
|
|
student_in_course(active_all: true, course: @course)
|
|
end
|
|
|
|
let(:now) { Time.zone.now.change(usec: 0) }
|
|
|
|
def course_topic(opts={})
|
|
@topic = @course.discussion_topics.build(:title => "some topic", :pinned => opts.fetch(:pinned, false))
|
|
user = opts[:user] || @user
|
|
if user && !opts[:skip_set_user]
|
|
@topic.user = user
|
|
end
|
|
|
|
if opts[:with_assignment]
|
|
@topic.assignment = @course.assignments.build(:submission_types => 'discussion_topic', :title => @topic.title)
|
|
@topic.assignment.infer_times
|
|
@topic.assignment.saved_by = :discussion_topic
|
|
end
|
|
|
|
@topic.save
|
|
@topic.reload
|
|
@topic
|
|
end
|
|
|
|
def topic_entry
|
|
@entry = @topic.discussion_entries.create(:message => "some message", :user => @user)
|
|
end
|
|
|
|
describe "GET 'index'" do
|
|
it "should require authorization" do
|
|
get 'index', params: {:course_id => @course.id}
|
|
assert_unauthorized
|
|
end
|
|
|
|
it "should require the course to be published for students" do
|
|
@course.claim
|
|
user_session(@student)
|
|
get 'index', params: {:course_id => @course.id}
|
|
assert_unauthorized
|
|
end
|
|
|
|
it 'does not show announcements without :read_announcements' do
|
|
@course.account.role_overrides.create!(permission: 'read_announcements', role: student_role, enabled: false)
|
|
get 'index', params: {course_id: @course.id}
|
|
assert_unauthorized
|
|
end
|
|
|
|
it "should load for :view_group_pages students" do
|
|
@course.account.role_overrides.create!(
|
|
role: student_role,
|
|
permission: 'view_group_pages',
|
|
enabled: true
|
|
)
|
|
@group_category = @course.group_categories.create(:name => 'gc')
|
|
@group = @course.groups.create!(:group_category => @group_category)
|
|
user_session(@student)
|
|
|
|
get 'index', params: {:group_id => @group.id}
|
|
expect(response).to be_successful
|
|
end
|
|
|
|
context "graded group discussion" do
|
|
before do
|
|
@course.account.role_overrides.create!(
|
|
role: student_role,
|
|
permission: 'view_group_pages',
|
|
enabled: true
|
|
)
|
|
|
|
group_discussion_assignment
|
|
@child_topic = @topic.child_topics.first
|
|
@child_topic.root_topic_id = @topic.id
|
|
@group = @child_topic.context
|
|
@group.add_user(@student)
|
|
@assignment.only_visible_to_overrides = true
|
|
@assignment.save!
|
|
end
|
|
|
|
it "should return graded and visible group discussions properly" do
|
|
cs = @student.enrollments.first.course_section
|
|
create_section_override_for_assignment(@assignment, {course_section: cs})
|
|
|
|
user_session(@student)
|
|
|
|
get 'index', params: {:group_id => @group.id}
|
|
expect(response).to be_successful
|
|
expect(assigns["topics"]).to include(@child_topic)
|
|
end
|
|
|
|
it "should assign the create permission if the term is concluded and course is open" do
|
|
@course.update_attribute(:restrict_enrollments_to_course_dates, true)
|
|
term = @course.account.enrollment_terms.create!(:name => 'mew', :end_at => Time.now.utc - 1.minute)
|
|
@course.enrollment_term = term
|
|
@course.update_attribute(:conclude_at, Time.now.utc + 1.hour)
|
|
@course.save!
|
|
user_session(@teacher)
|
|
|
|
get 'index', params: {:course_id => @course.id}
|
|
|
|
expect(assigns[:js_env][:permissions][:create]).to be_truthy
|
|
end
|
|
|
|
it "should not assign the create permission if the term and course are concluded" do
|
|
term = @course.account.enrollment_terms.create!(
|
|
:name => 'mew',
|
|
:start_at => 6.months.ago(now),
|
|
:end_at => 1.months.ago(now)
|
|
)
|
|
@course.enrollment_term = term
|
|
@course.update!(start_at: 5.months.ago(now), conclude_at: 2.months.ago(now))
|
|
user_session(@teacher)
|
|
|
|
get 'index', params: {:course_id => @course.id}
|
|
|
|
expect(assigns[:js_env][:permissions][:create]).to be_falsy
|
|
end
|
|
|
|
it "should not return graded group discussions if a student has no visibility" do
|
|
user_session(@student)
|
|
|
|
get 'index', params: {:group_id => @group.id}
|
|
expect(response).to be_successful
|
|
expect(assigns["topics"]).not_to include(@child_topic)
|
|
end
|
|
|
|
it 'should redirect to correct mastery paths edit page' do
|
|
user_session(@teacher)
|
|
allow(ConditionalRelease::Service).to receive(:enabled_in_context?).and_return(true)
|
|
allow(ConditionalRelease::Service).to receive(:env_for).and_return({ dummy: 'value' })
|
|
get :edit, params: {group_id: @group.id, id: @child_topic.id}
|
|
redirect_path = "/courses/#{@course.id}/discussion_topics/#{@topic.id}/edit"
|
|
expect(response).to redirect_to(redirect_path)
|
|
end
|
|
end
|
|
|
|
context "cross-sharding" do
|
|
specs_require_sharding
|
|
|
|
it 'returns the topic across shards' do
|
|
@topic = @course.discussion_topics.create!(title: 'student topic', message: 'Hello', user: @student)
|
|
user_session(@student)
|
|
@shard1.activate do
|
|
get 'index', params: { course_id: @course.id }, format: :json
|
|
expect(assigns[:topics]).to include(@topic)
|
|
end
|
|
|
|
@shard2.activate do
|
|
get 'index', params: { course_id: @course.id }, format: :json
|
|
expect(assigns[:topics]).to include(@topic)
|
|
end
|
|
end
|
|
end
|
|
|
|
it "should return non-graded group discussions properly" do
|
|
@course.account.role_overrides.create!(
|
|
role: student_role,
|
|
permission: 'view_group_pages',
|
|
enabled: true
|
|
)
|
|
|
|
group_category(context: @course)
|
|
membership = group_with_user(group_category: @group_category, user: @student, context: @course)
|
|
@topic = @group.discussion_topics.create(:title => "group topic")
|
|
@topic.context = @group
|
|
@topic.save!
|
|
|
|
user_session(@student)
|
|
|
|
get 'index', params: {:group_id => @group.id}
|
|
expect(response).to be_successful
|
|
expect(assigns["topics"]).to include(@topic)
|
|
end
|
|
|
|
it "non-graded group discussions include root data if json request" do
|
|
delayed_post_time = 1.day.from_now
|
|
lock_at_time = 2.days.from_now
|
|
user_session(@teacher)
|
|
group_topic = group_discussion_topic_model(
|
|
:context => @course, :delayed_post_at => delayed_post_time, :lock_at => lock_at_time
|
|
)
|
|
group_topic.save!
|
|
group_id = group_topic.child_topics.first.group.id
|
|
get 'index', params: { group_id: group_id }, :format => :json
|
|
expect(response).to be_successful
|
|
parsed_json = json_parse(response.body)
|
|
expect(parsed_json.length).to eq 1
|
|
parsed_topic = parsed_json.first
|
|
# barf
|
|
expect(parsed_topic["delayed_post_at"].to_json).to eq delayed_post_time.to_json
|
|
expect(parsed_topic["lock_at"].to_json).to eq lock_at_time.to_json
|
|
end
|
|
|
|
it "sets DIRECT_SHARE_ENABLED when enabled" do
|
|
@course.account.enable_feature!(:direct_share)
|
|
user_session(@teacher)
|
|
get 'index', params: {course_id: @course.id}
|
|
expect(response).to be_successful
|
|
expect(assigns[:js_env][:DIRECT_SHARE_ENABLED]).to be(true)
|
|
end
|
|
|
|
it "does not set DIRECT_SHARE_ENABLED if the user does not have manage_content" do
|
|
@course.account.enable_feature!(:direct_share)
|
|
user_session(@student)
|
|
get 'index', params: {course_id: @course.id}
|
|
expect(response).to be_successful
|
|
expect(assigns[:js_env][:DIRECT_SHARE_ENABLED]).to be(false)
|
|
end
|
|
|
|
it "does not set DIRECT_SHARE_ENABLED when disabled" do
|
|
user_session(@teacher)
|
|
get 'index', params: {course_id: @course.id}
|
|
expect(response).to be_successful
|
|
expect(assigns[:js_env][:DIRECT_SHARE_ENABLED]).to be(false)
|
|
end
|
|
|
|
it "does not set DIRECT_SHARE_ENABLED when viewing a group" do
|
|
@course.account.enable_feature!(:direct_share)
|
|
user_session(@teacher)
|
|
group = @course.groups.create!
|
|
get 'index', params: {group_id: group.id}
|
|
expect(response).to be_successful
|
|
expect(assigns[:js_env][:DIRECT_SHARE_ENABLED]).to be(false)
|
|
end
|
|
end
|
|
|
|
describe "GET 'show'" do
|
|
it "should require authorization" do
|
|
course_topic
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
assert_unauthorized
|
|
end
|
|
|
|
it "should require the course to be published for students" do
|
|
course_topic
|
|
@course.claim
|
|
user_session(@student)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
assert_unauthorized
|
|
end
|
|
|
|
it "should return unauthorized if a user does not have visibilities" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept!
|
|
Enrollment.limit_privileges_to_course_section!(@course, @teacher, true)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section2])
|
|
ann.save!
|
|
get :show, params: {course_id: @course.id, id: ann.id}
|
|
get :edit, params: {course_id: @course.id, id: ann.id}
|
|
expect(response.status).to equal(401)
|
|
end
|
|
|
|
it "js_env TOTAL_USER_COUNT and IS_ANNOUNCEMENT are set correctly for section specific announcements" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section1])
|
|
ann.save!
|
|
get 'show', params: {:course_id => @course.id, :id => ann}
|
|
expect(assigns[:js_env][:TOTAL_USER_COUNT]).to eq(5)
|
|
end
|
|
|
|
it "js_env COURSE_SECTIONS is set correctly for section specific announcements" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section1])
|
|
ann.save!
|
|
get 'show', params: {:course_id => @course.id, :id => ann}
|
|
expect(assigns[:js_env][:DISCUSSION][:TOPIC][:COURSE_SECTIONS].first["name"]).to eq(section1.name)
|
|
end
|
|
|
|
it "js_env COURSE_SECTIONS should have correct count" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
|
|
student1, student2 = create_users(2, return_type: :record)
|
|
student_in_section(section1, user: student1)
|
|
student_in_section(section1, user: student2)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section1])
|
|
ann.save!
|
|
student1.enrollments.first.conclude
|
|
get 'show', params: {:course_id => @course.id, :id => ann}
|
|
expect(assigns[:js_env][:DISCUSSION][:TOPIC][:COURSE_SECTIONS].first[:user_count]).to eq(1)
|
|
end
|
|
|
|
it "js_env disable_keyboard_shortcuts should follow feature flag" do
|
|
@student.enable_feature! :disable_keyboard_shortcuts
|
|
user_session @student
|
|
@discussion = @course.discussion_topics.create!(:user => @teacher, message: 'hello')
|
|
get 'show', params: {:course_id => @course.id, :id => @discussion.id}
|
|
expect(assigns[:js_env][:disable_keyboard_shortcuts]).to be_truthy
|
|
end
|
|
|
|
it "should not work for announcements in a public course" do
|
|
@course.update_attribute(:is_public, true)
|
|
@announcement = @course.announcements.create!(
|
|
:title => "some announcement",
|
|
:message => "some message"
|
|
)
|
|
get 'show', params: {:course_id => @course.id, :id => @announcement.id}
|
|
expect(response).to_not be_successful
|
|
end
|
|
|
|
it "should not display announcements in private courses to users who aren't logged in" do
|
|
announcement = @course.announcements.create!(title: 'Test announcement', message: 'Message')
|
|
get('show', params: {course_id: @course.id, id: announcement.id})
|
|
assert_unauthorized
|
|
end
|
|
|
|
context 'section specific announcements' do
|
|
before(:once) do
|
|
course_with_teacher(active_course: true)
|
|
@section = @course.course_sections.create!(name: 'test section')
|
|
|
|
@announcement = @course.announcements.create!(:user => @teacher, message: 'hello my favorite section!')
|
|
@announcement.is_section_specific = true
|
|
@announcement.course_sections = [@section]
|
|
@announcement.save!
|
|
|
|
@student1, @student2 = create_users(2, return_type: :record)
|
|
@course.enroll_student(@student1, :enrollment_state => 'active')
|
|
@course.enroll_student(@student2, :enrollment_state => 'active')
|
|
student_in_section(@section, user: @student1)
|
|
end
|
|
|
|
it "should be visible to students in specific section" do
|
|
user_session(@student1)
|
|
get 'show', params: {:course_id => @course.id, :id => @announcement.id}
|
|
expect(response).to be_successful
|
|
end
|
|
|
|
it "should not be visible to students not in specific section announcements" do
|
|
user_session(@student2)
|
|
get('show', params: {course_id: @course.id, id: @announcement.id})
|
|
expect(response).to be_redirect
|
|
expect(response.location).to eq course_announcements_url @course
|
|
end
|
|
end
|
|
|
|
context 'section specific discussions' do
|
|
before(:once) do
|
|
course_with_teacher(active_course: true)
|
|
@section = @course.course_sections.create!(name: 'test section')
|
|
|
|
@discussion = @course.discussion_topics.create!(:user => @teacher, message: 'hello my favorite section!')
|
|
@discussion.is_section_specific = true
|
|
@discussion.course_sections = [@section]
|
|
@discussion.save!
|
|
|
|
@student1, @student2 = create_users(2, return_type: :record)
|
|
@course.enroll_student(@student1, :enrollment_state => 'active')
|
|
@course.enroll_student(@student2, :enrollment_state => 'active')
|
|
student_in_section(@section, user: @student1)
|
|
end
|
|
|
|
it "should be visible to students in specific section" do
|
|
user_session(@student1)
|
|
get 'show', params: {:course_id => @course.id, :id => @discussion.id}
|
|
expect(response).to be_successful
|
|
end
|
|
|
|
it "should not be visible to students not in specific section discussions" do
|
|
user_session(@student2)
|
|
get('show', params: {course_id: @course.id, id: @discussion.id})
|
|
expect(response).to be_redirect
|
|
expect(response.location).to eq course_discussion_topics_url @course
|
|
end
|
|
end
|
|
|
|
context "discussion topic with assignment with overrides" do
|
|
render_views
|
|
|
|
before :once do
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
@section = @course.course_sections.create!(:name => "I <3 Discusions")
|
|
@override = assignment_override_model(:assignment => @topic.assignment,
|
|
:due_at => Time.now,
|
|
:set => @section)
|
|
end
|
|
|
|
it "doesn't show the topic to unassigned students" do
|
|
@topic.assignment.update_attribute(:only_visible_to_overrides, true)
|
|
user_session(@student)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_redirect
|
|
expect(response.location).to eq course_discussion_topics_url @course
|
|
end
|
|
|
|
it "doesn't show overrides to students" do
|
|
user_session(@student)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
expect(response.body).not_to match 'discussion-topic-due-dates'
|
|
due_date = OverrideListPresenter.new.due_at(@topic.assignment)
|
|
expect(response.body).to match "due #{due_date}"
|
|
end
|
|
|
|
it "doesn't show overrides for observers" do
|
|
user_session(@observer)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
expect(response.body).not_to match 'discussion-topic-due-dates'
|
|
due_date = OverrideListPresenter.new.due_at(@topic.assignment.overridden_for(@observer))
|
|
expect(response.body).to match "due #{due_date}"
|
|
end
|
|
|
|
it "does show overrides to teachers" do
|
|
user_session(@teacher)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
expect(response.body).to match 'discussion-topic-due-dates'
|
|
end
|
|
|
|
end
|
|
|
|
it "should assign variables" do
|
|
user_session(@student)
|
|
course_topic
|
|
topic_entry
|
|
@topic.reload
|
|
expect(@topic.discussion_entries).not_to be_empty
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
expect(assigns[:topic]).not_to be_nil
|
|
expect(assigns[:topic]).to eql(@topic)
|
|
end
|
|
|
|
it "should display speedgrader when not for a large course" do
|
|
user_session(@teacher)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]).to be_truthy
|
|
end
|
|
|
|
it "should hide speedgrader when for a large course" do
|
|
user_session(@teacher)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
allow_any_instance_of(Course).to receive(:large_roster?).and_return(true)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]).to be_nil
|
|
end
|
|
|
|
it "shows speedgrader when user can view all grades but not manage grades" do
|
|
@course.account.role_overrides.create!(permission: 'manage_grades', role: ta_role, enabled: false)
|
|
user_session(@ta)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
get 'show', params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]).to be_truthy
|
|
end
|
|
|
|
it "shows speedgrader when user can manage grades but not view all grades" do
|
|
@course.account.role_overrides.create!(permission: 'view_all_grades', role: ta_role, enabled: false)
|
|
user_session(@ta)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
get 'show', params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]).to be_truthy
|
|
end
|
|
|
|
it "does not show speedgrader when user can neither view all grades nor manage grades" do
|
|
@course.account.role_overrides.create!(permission: 'view_all_grades', role: ta_role, enabled: false)
|
|
@course.account.role_overrides.create!(permission: 'manage_grades', role: ta_role, enabled: false)
|
|
user_session(@ta)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
get 'show', params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]).to be_nil
|
|
end
|
|
|
|
it "shows speedgrader when course concluded and user can read as admin" do
|
|
user_session(@teacher)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
@course.soft_conclude!
|
|
expect(@course.grants_right?(@teacher, :read_as_admin)).to be true
|
|
get 'show', params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]).to be_truthy
|
|
end
|
|
|
|
it "should setup speedgrader template for variable substitution" do
|
|
user_session(@teacher)
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
|
|
# this is essentially a unit test for app/coffeescripts/models/Entry.coffee,
|
|
# making sure that we get back the expected format for this url template
|
|
template = assigns[:js_env][:DISCUSSION][:SPEEDGRADER_URL_TEMPLATE]
|
|
url = template.gsub(/%3Astudent_id/, '123')
|
|
expect(url).to match "student_id=123"
|
|
end
|
|
|
|
it "should mark as read when viewed" do
|
|
user_session(@student)
|
|
course_topic(:skip_set_user => true)
|
|
|
|
expect(@topic.read_state(@student)).to eq 'unread'
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(@topic.reload.read_state(@student)).to eq 'read'
|
|
end
|
|
|
|
it "should mark as read when topic is in the future as teacher" do
|
|
course_topic(:skip_set_user => true)
|
|
teacher2 = @course.shard.activate { user_factory() }
|
|
teacher2enrollment = @course.enroll_user(teacher2, "TeacherEnrollment")
|
|
teacher2.save!
|
|
teacher2enrollment.course = @course # set the reverse association
|
|
teacher2enrollment.workflow_state = 'active'
|
|
teacher2enrollment.save!
|
|
@course.reload
|
|
@topic.available_from = 1.day.from_now
|
|
@topic.save!
|
|
@topic.reload
|
|
expect(@topic.read_state(teacher2)).to eq 'unread'
|
|
user_session(teacher2)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(@topic.reload.read_state(teacher2)).to eq 'read'
|
|
end
|
|
|
|
it "should not mark as read if not visible" do
|
|
user_session(@student)
|
|
course_topic(:skip_set_user => true)
|
|
mod = @course.context_modules.create! name: 'no soup for you', unlock_at: 1.year.from_now
|
|
mod.add_item(type: 'discussion_topic', id: @topic.id)
|
|
mod.save!
|
|
expect(@topic.read_state(@student)).to eq 'unread'
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(@topic.reload.read_state(@student)).to eq 'unread'
|
|
end
|
|
|
|
it "should mark as read if visible but locked" do
|
|
user_session(@student)
|
|
course_topic(:skip_set_user => true)
|
|
@announcement = @course.announcements.create!(
|
|
:title => "some announcement",
|
|
:message => "some message",
|
|
:unlock_at => 1.week.ago,
|
|
:lock_at => 1.day.ago
|
|
)
|
|
expect(@announcement.read_state(@student)).to eq 'unread'
|
|
get 'show', params: {:course_id => @course.id, :id => @announcement.id}
|
|
expect(@announcement.reload.read_state(@student)).to eq 'read'
|
|
end
|
|
|
|
it "should allow concluded teachers to see discussions" do
|
|
user_session(@teacher)
|
|
course_topic
|
|
@enrollment.conclude
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
get 'index', params: {:course_id => @course.id}
|
|
expect(response).to be_successful
|
|
end
|
|
|
|
it "should allow concluded students to see discussions" do
|
|
user_session(@student)
|
|
course_topic
|
|
@enrollment.conclude
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
get 'index', params: {:course_id => @course.id}
|
|
expect(response).to be_successful
|
|
end
|
|
|
|
context 'group discussions' do
|
|
before(:once) do
|
|
@group_category = @course.group_categories.create(:name => 'category 1')
|
|
@group1 = @course.groups.create!(:group_category => @group_category)
|
|
@group2 = @course.groups.create!(:group_category => @group_category)
|
|
|
|
group_category2 = @course.group_categories.create(:name => 'category 2')
|
|
@course.groups.create!(:group_category => group_category2)
|
|
|
|
course_topic(user: @teacher, with_assignment: true)
|
|
@topic.group_category = @group_category
|
|
@topic.save!
|
|
|
|
@group1.add_user(@student)
|
|
end
|
|
|
|
it "should assign groups from the topic's category" do
|
|
user_session(@teacher)
|
|
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:groups].size).to eql(2)
|
|
end
|
|
|
|
it "should only show applicable groups if DA applies" do
|
|
user_session(@teacher)
|
|
|
|
asmt = @topic.assignment
|
|
asmt.only_visible_to_overrides = true
|
|
override = asmt.assignment_overrides.build
|
|
override.set = @group2
|
|
override.save!
|
|
asmt.save!
|
|
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response).to be_successful
|
|
expect(assigns[:groups]).to eq([@group2])
|
|
end
|
|
|
|
it "should redirect to group for student if DA applies to section" do
|
|
user_session(@student)
|
|
|
|
asmt = @topic.assignment
|
|
asmt.only_visible_to_overrides = true
|
|
override = asmt.assignment_overrides.build
|
|
override.set = @course.default_section
|
|
override.save!
|
|
asmt.save!
|
|
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
redirect_path = "/groups/#{@group1.id}/discussion_topics?root_discussion_topic_id=#{@topic.id}"
|
|
expect(response).to redirect_to redirect_path
|
|
end
|
|
|
|
it "should redirect to the student's group" do
|
|
user_session(@student)
|
|
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
redirect_path = "/groups/#{@group1.id}/discussion_topics?root_discussion_topic_id=#{@topic.id}"
|
|
expect(response).to redirect_to redirect_path
|
|
end
|
|
|
|
it "should redirect to the student's group even if students can view all groups" do
|
|
@course.account.role_overrides.create!(
|
|
role: student_role,
|
|
permission: 'view_group_pages',
|
|
enabled: true
|
|
)
|
|
user_session(@student)
|
|
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
redirect_path = "/groups/#{@group1.id}/discussion_topics?root_discussion_topic_id=#{@topic.id}"
|
|
expect(response).to redirect_to redirect_path
|
|
end
|
|
|
|
it "should not change the name of the child topic when navigating to it" do
|
|
user_session(@student)
|
|
|
|
child_topic = @topic.child_topic_for(@student)
|
|
old_title = child_topic.title
|
|
|
|
get 'index', params: {:group_id => @group1.id, :root_discussion_topic_id => @topic.id}
|
|
|
|
expect(@topic.child_topic_for(@student).title).to eq old_title
|
|
end
|
|
|
|
it "should plumb the module_item_id through group discussion redirect" do
|
|
user_session(@student)
|
|
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id, :module_item_id => 789}
|
|
expect(response).to be_redirect
|
|
expect(response.location).to include "/groups/#{@group1.id}/discussion_topics?"
|
|
expect(response.location).to include "module_item_id=789"
|
|
end
|
|
|
|
it "should plumb the module_item_id through child discussion redirect" do
|
|
user_session(@student)
|
|
|
|
get 'index', params: {:group_id => @group1.id, :root_discussion_topic_id => @topic.id, :module_item_id => 789}
|
|
expect(response).to be_redirect
|
|
expect(response.location).to include "/groups/#{@group1.id}/discussion_topics/#{@topic.child_topic_for(@student).id}?"
|
|
expect(response.location).to include "module_item_id=789"
|
|
end
|
|
end
|
|
|
|
context 'publishing' do
|
|
render_views
|
|
|
|
it "hides the publish icon for announcements" do
|
|
user_session(@teacher)
|
|
@context = @course
|
|
@announcement = @course.announcements.create!(
|
|
:title => "some announcement",
|
|
:message => "some message"
|
|
)
|
|
get 'show', params: {:course_id => @course.id, :id => @announcement.id}
|
|
expect(response.body).not_to match "topic_publish_button"
|
|
end
|
|
end
|
|
|
|
context "posting first to view setting" do
|
|
before(:once) do
|
|
@observer_enrollment.associated_user = @student
|
|
@observer_enrollment.save
|
|
@observer.reload
|
|
|
|
@context = @course
|
|
discussion_topic_model
|
|
@topic.require_initial_post = true
|
|
@topic.save
|
|
end
|
|
|
|
it "should allow admins to see posts without posting" do
|
|
@topic.reply_from(:user => @student, :text => 'hai')
|
|
user_session(@teacher)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:initial_post_required]).to be_falsey
|
|
end
|
|
|
|
it "shouldn't allow student who hasn't posted to see" do
|
|
@topic.reply_from(:user => @teacher, :text => 'hai')
|
|
user_session(@student)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:initial_post_required]).to be_truthy
|
|
end
|
|
|
|
it "shouldn't allow student's observer who hasn't posted to see" do
|
|
@topic.reply_from(:user => @teacher, :text => 'hai')
|
|
user_session(@observer)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:initial_post_required]).to be_truthy
|
|
end
|
|
|
|
it "should allow student who has posted to see" do
|
|
@topic.reply_from(:user => @student, :text => 'hai')
|
|
user_session(@student)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:initial_post_required]).to be_falsey
|
|
end
|
|
|
|
it "should allow student's observer who has posted to see" do
|
|
@topic.reply_from(:user => @student, :text => 'hai')
|
|
user_session(@observer)
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:initial_post_required]).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "student context cards" do
|
|
before(:once) do
|
|
course_topic user: @teacher
|
|
@course.root_account.enable_feature! :student_context_cards
|
|
end
|
|
|
|
it "is disabed for students" do
|
|
user_session(@student)
|
|
get :show, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:STUDENT_CONTEXT_CARDS_ENABLED]).to be_falsey
|
|
end
|
|
|
|
it "is disabled for teachers when feature_flag is off" do
|
|
@course.root_account.disable_feature! :student_context_cards
|
|
user_session(@teacher)
|
|
get :show, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:STUDENT_CONTEXT_CARDS_ENABLED]).to be_falsey
|
|
end
|
|
|
|
it "is enabled for teachers when feature_flag is on" do
|
|
user_session(@teacher)
|
|
get :show, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:STUDENT_CONTEXT_CARDS_ENABLED]).to eq true
|
|
end
|
|
end
|
|
|
|
it "successfully redirects no authorization for a public course" do
|
|
@course.update(is_public: true)
|
|
course_topic
|
|
get 'show', params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(response.code).to eq "302"
|
|
expect(ErrorReport.last).to be_nil
|
|
end
|
|
end
|
|
|
|
describe "GET 'new'" do
|
|
it "should maintain date and time when passed params" do
|
|
user_session(@teacher)
|
|
due_at = 1.day.from_now
|
|
get 'new', params: {course_id: @course.id, due_at: due_at.iso8601}
|
|
expect(assigns[:js_env][:DISCUSSION_TOPIC][:ATTRIBUTES][:assignment][:due_at]).to eq due_at.iso8601
|
|
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)
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_env][:DUE_DATE_REQUIRED_FOR_ACCOUNT]).to eq(true)
|
|
end
|
|
|
|
it "js_env DUE_DATE_REQUIRED_FOR_ACCOUNT is false when AssignmentUtil.due_date_required_for_account? == false" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:due_date_required_for_account?).and_return(false)
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_env][:DUE_DATE_REQUIRED_FOR_ACCOUNT]).to eq(false)
|
|
end
|
|
|
|
it "js_env MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT is true when AssignmentUtil.name_length_required_for_account? == true" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:name_length_required_for_account?).and_return(true)
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_env][:MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT]).to eq(true)
|
|
end
|
|
|
|
it "js_env MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT is false when AssignmentUtil.name_length_required_for_account? == false" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:name_length_required_for_account?).and_return(false)
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_env][:MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT]).to eq(false)
|
|
end
|
|
|
|
it "js_env MAX_NAME_LENGTH is a 15 when AssignmentUtil.assignment_max_name_length returns 15" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:assignment_max_name_length).and_return(15)
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_env][:MAX_NAME_LENGTH]).to eq(15)
|
|
end
|
|
|
|
it "js_env SIS_NAME is Foo Bar when AssignmentUtil.post_to_sis_friendly_name is Foo Bar" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:post_to_sis_friendly_name).and_return('Foo Bar')
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_env][:SIS_NAME]).to eq('Foo Bar')
|
|
end
|
|
|
|
it "js_bundles includes discussion_topics_edit_react when ff is on" do
|
|
user_session(@teacher)
|
|
@course.account.enable_feature!(:react_announcement_discussion_edit)
|
|
get 'new', params: {:course_id => @course.id}
|
|
expect(assigns[:js_bundles].first).to include(:discussion_topics_edit_react)
|
|
end
|
|
end
|
|
|
|
describe "GET 'new'" do
|
|
it "creates a default assignment group if none exist" do
|
|
user_session(@teacher)
|
|
get :new, params: {course_id: @course.id}
|
|
expect(@course.assignment_groups.count).not_to eq 0
|
|
end
|
|
|
|
it "announcement" do
|
|
user_session(@teacher)
|
|
@course.group_weighting_scheme = 'percent'
|
|
@course.save!
|
|
get :new, params: {course_id: @course.id, is_announcement: true}
|
|
expect(assigns[:js_env][:CONTEXT_ID]).to eq(@course.id)
|
|
end
|
|
end
|
|
|
|
describe "GET 'edit'" do
|
|
before(:once) do
|
|
course_topic
|
|
end
|
|
|
|
include_context "grading periods within controller" do
|
|
let(:course) { @course }
|
|
let(:teacher) { @teacher }
|
|
let(:request_params) { [:edit, params: {course_id: course, id: @topic}] }
|
|
end
|
|
|
|
it "should not explode with mgp and group context" do
|
|
group1 = Factories::GradingPeriodGroupHelper.new.create_for_account(@course.root_account)
|
|
group1.enrollment_terms << @course.enrollment_term
|
|
user_session(@teacher)
|
|
group = group_model(:context => @course)
|
|
group_topic = group.discussion_topics.create!(:title => "title")
|
|
get(:edit, params: {group_id: group, id: group_topic})
|
|
expect(response).to be_successful
|
|
expect(assigns[:js_env]).to have_key(:active_grading_periods)
|
|
end
|
|
|
|
it "js_env SECTION_LIST is set correctly for section specific announcements on a limited privileges user" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept!
|
|
Enrollment.limit_privileges_to_course_section!(@course, @teacher, true)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section1])
|
|
ann.save!
|
|
get :edit, params: {course_id: @course.id, id: ann.id}
|
|
|
|
# 2 because there is a default course created in the course_with_teacher factory
|
|
expect(assigns[:js_env]["SECTION_LIST"].length).to eq(2)
|
|
end
|
|
|
|
it "js_env SECTION_LIST is set correctly for section specific announcements on a not limited privileges user" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept!
|
|
Enrollment.limit_privileges_to_course_section!(@course, @teacher, false)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section1])
|
|
ann.save!
|
|
get :edit, params: {course_id: @course.id, id: ann.id}
|
|
|
|
# 3 because there is a default course created in the course_with_teacher factory
|
|
expect(assigns[:js_env]["SECTION_LIST"].length).to eq(3)
|
|
end
|
|
|
|
it "returns unauthorized for a user that does not have visibilites to view thiss" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept!
|
|
Enrollment.limit_privileges_to_course_section!(@course, @teacher, true)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section2])
|
|
ann.save!
|
|
get :edit, params: {course_id: @course.id, id: ann.id}
|
|
assert_unauthorized
|
|
end
|
|
|
|
it "js_env SELECTED_SECTION_LIST is set correctly for section specific announcements" do
|
|
user_session(@teacher)
|
|
section1 = course.course_sections.create!(name: "Section 1")
|
|
section2 = course.course_sections.create!(name: "Section 2")
|
|
course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept(true)
|
|
course.enroll_teacher(@teacher, section: section2, allow_multiple_enrollments: true).accept(true)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section1])
|
|
ann.save!
|
|
get :edit, params: {course_id: @course.id, id: ann.id}
|
|
expect(assigns[:js_env]["SELECTED_SECTION_LIST"]).to eq([{:id=>section1.id, :name=>section1.name}])
|
|
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)
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:DUE_DATE_REQUIRED_FOR_ACCOUNT]).to eq(true)
|
|
end
|
|
|
|
it "js_env DUE_DATE_REQUIRED_FOR_ACCOUNT is false when AssignmentUtil.due_date_required_for_account? == false" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:due_date_required_for_account?).and_return(false)
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:DUE_DATE_REQUIRED_FOR_ACCOUNT]).to eq(false)
|
|
end
|
|
|
|
it "js_env MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT is true when AssignmentUtil.name_length_required_for_account? == true" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:name_length_required_for_account?).and_return(true)
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT]).to eq(true)
|
|
end
|
|
|
|
it "js_env MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT is false when AssignmentUtil.name_length_required_for_account? == false" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:name_length_required_for_account?).and_return(false)
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:MAX_NAME_LENGTH_REQUIRED_FOR_ACCOUNT]).to eq(false)
|
|
end
|
|
|
|
it "js_env MAX_NAME_LENGTH is a 15 when AssignmentUtil.assignment_max_name_length returns 15" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:assignment_max_name_length).and_return(15)
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(assigns[:js_env][:MAX_NAME_LENGTH]).to eq(15)
|
|
end
|
|
|
|
it "js_env SIS_NAME is Foo Bar when AssignmentUtil.post_to_sis_friendly_name is Foo Bar" do
|
|
user_session(@teacher)
|
|
allow(AssignmentUtil).to receive(:post_to_sis_friendly_name).and_return('Foo Bar')
|
|
get :edit, params: {:course_id => @course.id, :id => @topic.id}
|
|
expect(assigns[:js_env][:SIS_NAME]).to eq('Foo Bar')
|
|
end
|
|
|
|
context 'conditional-release' do
|
|
before do
|
|
user_session(@teacher)
|
|
end
|
|
|
|
it 'should include environment variables if enabled' do
|
|
allow(ConditionalRelease::Service).to receive(:enabled_in_context?).and_return(true)
|
|
allow(ConditionalRelease::Service).to receive(:env_for).and_return({ dummy: 'value' })
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(response).to be_successful
|
|
expect(controller.js_env[:dummy]).to eq 'value'
|
|
end
|
|
|
|
it 'should not include environment variables when disabled' do
|
|
allow(ConditionalRelease::Service).to receive(:enabled_in_context?).and_return(false)
|
|
allow(ConditionalRelease::Service).to receive(:env_for).and_return({ dummy: 'value' })
|
|
get :edit, params: {course_id: @course.id, id: @topic.id}
|
|
expect(response).to be_successful
|
|
expect(controller.js_env).not_to have_key :dummy
|
|
end
|
|
end
|
|
|
|
context 'usage rights - teacher' do
|
|
before { user_session(@teacher) }
|
|
before :once do
|
|
attachment_model
|
|
@topic_with_file = @course.discussion_topics.create!(title: "some topic", attachment: @attachment)
|
|
end
|
|
|
|
shared_examples_for 'no usage rights returned' do
|
|
it 'does not return usage rights on discussion topic attachment' do
|
|
get :edit, params: {course_id: @course.id, id: @topic_with_file.id}
|
|
expect(assigns[:js_env][:DISCUSSION_TOPIC][:ATTRIBUTES]['attachments'][0].key?('usage_rights')).to be false
|
|
end
|
|
end
|
|
|
|
shared_examples_for 'usage rights returned' do
|
|
it 'returns usage rights on discussion topic attachment' do
|
|
get :edit, params: {course_id: @course.id, id: @topic_with_file.id}
|
|
expect(assigns[:js_env][:DISCUSSION_TOPIC][:ATTRIBUTES]['attachments'][0].key?('usage_rights')).to be true
|
|
end
|
|
end
|
|
|
|
context 'with usage_rights_discussion_topics disabled' do
|
|
before { @course.root_account.disable_feature!(:usage_rights_discussion_topics) }
|
|
|
|
context 'enabled on course' do
|
|
before { @course.update!(usage_rights_required: true) }
|
|
|
|
include_examples 'no usage rights returned'
|
|
end
|
|
|
|
context 'disabled on course' do
|
|
before { @course.update!(usage_rights_required: false) }
|
|
|
|
include_examples 'no usage rights returned'
|
|
end
|
|
end
|
|
|
|
context 'with usage_rights_discussion_topics enabled' do
|
|
before { @course.root_account.enable_feature!(:usage_rights_discussion_topics) }
|
|
|
|
context 'enabled on course' do
|
|
before { @course.update!(usage_rights_required: true) }
|
|
|
|
include_examples 'usage rights returned'
|
|
end
|
|
|
|
context 'disabled on course' do
|
|
before { @course.update!(usage_rights_required: false) }
|
|
|
|
include_examples 'no usage rights returned'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'student planner' do
|
|
before :each do
|
|
course_topic
|
|
end
|
|
|
|
it 'should create a topic with a todo date' do
|
|
user_session(@teacher)
|
|
todo_date = 1.day.from_now.in_time_zone('America/New_York')
|
|
post 'create', params: {course_id: @course.id, todo_date: todo_date, title: 'Discussion 1'}, format: 'json'
|
|
expect(JSON.parse(response.body)['todo_date']).to eq todo_date.in_time_zone('UTC').iso8601
|
|
end
|
|
|
|
it 'should update a topic with a todo date' do
|
|
user_session(@teacher)
|
|
todo_date = 1.day.from_now.in_time_zone('America/New_York')
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id, todo_date: todo_date.iso8601(6)}, format: 'json'
|
|
expect(@topic.reload.todo_date).to eq todo_date
|
|
end
|
|
|
|
it 'should remove a todo date from a topic' do
|
|
user_session(@teacher)
|
|
@topic.update(todo_date: 1.day.from_now.in_time_zone('America/New_York'))
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id, todo_date: nil}, format: 'json'
|
|
expect(@topic.reload.todo_date).to be nil
|
|
end
|
|
|
|
it 'should not allow a student to update the to-do date' do
|
|
user_session(@student)
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id, todo_date: 1.day.from_now}, format: 'json'
|
|
expect(@topic.reload.todo_date).to eq nil
|
|
end
|
|
|
|
it 'should not allow a todo date on a graded topic' do
|
|
user_session(@teacher)
|
|
assign = @course.assignments.create!(title: 'Graded Topic 1', submission_types: 'discussion_topic')
|
|
topic = assign.discussion_topic
|
|
put 'update', params: {course_id: @course.id, topic_id: topic.id, todo_date: 1.day.from_now}, format: 'json'
|
|
expect(response.code).to eq '400'
|
|
end
|
|
|
|
it 'should not allow changing a topic to graded and adding a todo date' do
|
|
user_session(@teacher)
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id, todo_date: 1.day.from_now,
|
|
assignment: {submission_types: ['discussion_topic'], name: 'Graded Topic 1'}}, format: 'json'
|
|
expect(response.code).to eq '400'
|
|
end
|
|
|
|
it 'should allow a todo date when changing a topic from graded to ungraded' do
|
|
user_session(@teacher)
|
|
todo_date = 1.day.from_now
|
|
assign = @course.assignments.create!(title: 'Graded Topic 1', submission_types: 'discussion_topic')
|
|
topic = assign.discussion_topic
|
|
put 'update', params: {course_id: @course.id, topic_id: topic.id, todo_date: todo_date.iso8601(6),
|
|
assignment: {set_assignment: false, name: 'Graded Topic 1'}}, format: 'json'
|
|
expect(response.code).to eq '200'
|
|
expect(topic.reload.assignment).to be nil
|
|
expect(topic.todo_date).to eq todo_date
|
|
end
|
|
|
|
it 'should remove an existing todo date when changing a topic from ungraded to graded' do
|
|
user_session(@teacher)
|
|
@topic.update(todo_date: 1.day.from_now)
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
assignment: {submission_types: ['discussion_topic'], name: 'Graded Topic 1'}}, format: 'json'
|
|
expect(response.code).to eq '200'
|
|
expect(@topic.reload.assignment).to be_truthy
|
|
expect(@topic.todo_date).to be nil
|
|
end
|
|
end
|
|
|
|
describe "GET 'public_feed.atom'" do
|
|
before(:once) do
|
|
course_topic
|
|
end
|
|
|
|
it "should require authorization" do
|
|
get 'public_feed', params: {:feed_code => @course.feed_code + 'x'}, :format => 'atom'
|
|
expect(assigns[:problem]).to eql("The verification code is invalid.")
|
|
end
|
|
|
|
it "should include absolute path for rel='self' link" do
|
|
get 'public_feed', params: {:feed_code => @course.feed_code}, :format => 'atom'
|
|
feed = Atom::Feed.load_feed(response.body) rescue nil
|
|
expect(feed).not_to be_nil
|
|
expect(feed.links.first.rel).to match(/self/)
|
|
expect(feed.links.first.href).to match(/http:\/\//)
|
|
end
|
|
|
|
it "should not include entries in an anonymous feed" do
|
|
get 'public_feed', params: {:feed_code => @course.feed_code}, :format => 'atom'
|
|
feed = Atom::Feed.load_feed(response.body) rescue nil
|
|
expect(feed).not_to be_nil
|
|
expect(feed.entries).to be_empty
|
|
end
|
|
|
|
it "should include an author for each entry with an enrollment feed" do
|
|
get 'public_feed', params: {:feed_code => @course.teacher_enrollments.first.feed_code}, :format => 'atom'
|
|
feed = Atom::Feed.load_feed(response.body) rescue nil
|
|
expect(feed).not_to be_nil
|
|
expect(feed.entries).not_to be_empty
|
|
expect(feed.entries.all?{|e| e.authors.present?}).to be_truthy
|
|
end
|
|
end
|
|
|
|
describe 'POST create:' do
|
|
before(:once) do
|
|
Setting.set('enable_page_views', 'db')
|
|
end
|
|
before(:each) do
|
|
allow(controller).to receive_messages(:form_authenticity_token => 'abc', :form_authenticity_param => 'abc')
|
|
end
|
|
|
|
def topic_params(course, opts={})
|
|
{
|
|
:course_id => course.id,
|
|
:title => 'Topic Title',
|
|
:is_announcement => false,
|
|
:discussion_type => 'side_comment',
|
|
:require_initial_post => true,
|
|
:podcast_has_student_posts => false,
|
|
:delayed_post_at => '',
|
|
:locked => true,
|
|
:lock_at => '',
|
|
:message => 'Message',
|
|
:delay_posting => false,
|
|
:threaded => false,
|
|
:specific_sections => 'all'
|
|
}.merge(opts)
|
|
end
|
|
|
|
def group_topic_params(group, opts={})
|
|
params = topic_params(group, opts)
|
|
params[:group_id] = group.id
|
|
params.delete(:course_id)
|
|
params
|
|
end
|
|
|
|
def assignment_params(course, opts={})
|
|
course.require_assignment_group
|
|
{
|
|
assignment: {
|
|
points_possible: 1,
|
|
grading_type: 'points',
|
|
assignment_group_id: @course.assignment_groups.first.id,
|
|
}.merge(opts)
|
|
}
|
|
end
|
|
|
|
describe "create_announcements_unlocked preference" do
|
|
before(:each) do
|
|
@teacher.create_announcements_unlocked(false)
|
|
user_session(@teacher)
|
|
end
|
|
|
|
it 'is updated when creating new announcements' do
|
|
post_params = topic_params(@course, {is_announcement: true, locked: false})
|
|
post('create', params: post_params, format: :json)
|
|
@teacher.reload
|
|
expect(@teacher.create_announcements_unlocked?).to be_truthy
|
|
end
|
|
|
|
it 'is not updated when creating new discussions' do
|
|
post_params = topic_params(@course, {is_announcement: false, locked: false})
|
|
post('create', params: post_params, format: :json)
|
|
@teacher.reload
|
|
expect(@teacher.create_announcements_unlocked?).to be_falsey
|
|
end
|
|
end
|
|
|
|
describe 'the new topic' do
|
|
let(:topic) { assigns[:topic] }
|
|
before(:each) do
|
|
user_session(@student)
|
|
post 'create', params: topic_params(@course), :format => :json
|
|
end
|
|
|
|
specify { expect(topic).to be_a DiscussionTopic }
|
|
specify { expect(topic.user).to eq @user }
|
|
specify { expect(topic.delayed_post_at).to be_nil }
|
|
specify { expect(topic.lock_at).to be_nil }
|
|
specify { expect(topic.workflow_state).to eq 'active' }
|
|
specify { expect(topic.id).not_to be_nil }
|
|
specify { expect(topic.title).to eq 'Topic Title' }
|
|
specify { expect(topic.is_announcement).to be_falsey }
|
|
specify { expect(topic.discussion_type).to eq 'side_comment' }
|
|
specify { expect(topic.message).to eq 'Message' }
|
|
specify { expect(topic.threaded).to be_falsey }
|
|
end
|
|
|
|
# TODO: fix this terribleness
|
|
describe 'section specific discussions' do
|
|
before(:each) do
|
|
user_session(@teacher)
|
|
@section1 = @course.course_sections.create!(name: "Section 1")
|
|
@section2 = @course.course_sections.create!(name: "Section 2")
|
|
@section3 = @course.course_sections.create!(name: "Section 3")
|
|
@section4 = @course.course_sections.create!(name: "Section 4")
|
|
@course.enroll_teacher(@teacher, section: @section1, allow_multiple_enrollments: true).accept!
|
|
@course.enroll_teacher(@teacher, section: @section2, allow_multiple_enrollments: true).accept!
|
|
Enrollment.limit_privileges_to_course_section!(@course, @teacher, true)
|
|
end
|
|
|
|
it 'creates an announcement with sections' do
|
|
post 'create',
|
|
params: topic_params(@course, {is_announcement: true, specific_sections: @section1.id.to_s}),
|
|
:format => :json
|
|
expect(response).to be_successful
|
|
expect(DiscussionTopic.last.course_sections.first).to eq @section1
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 1
|
|
end
|
|
|
|
it 'section-specific-teachers can create course-wide discussions' do
|
|
old_count = DiscussionTopic.count
|
|
post 'create',
|
|
params: topic_params(@course, {is_announcement: true}),
|
|
:format => :json
|
|
expect(response).to be_successful
|
|
expect(DiscussionTopic.count).to eq old_count + 1
|
|
expect(DiscussionTopic.last.is_section_specific).to be_falsey
|
|
end
|
|
|
|
it 'section-specfic-teachers cannot create wrong-section discussions' do
|
|
old_count = DiscussionTopic.count
|
|
post 'create',
|
|
params: topic_params(@course, {is_announcement: true, specific_sections: @section3.id.to_s}),
|
|
:format => :json
|
|
expect(response).to have_http_status 400
|
|
expect(DiscussionTopic.count).to eq old_count
|
|
end
|
|
|
|
it 'admins can see section-specific discussions' do
|
|
admin = account_admin_user(account: @course.root_account, role: admin_role, active_user: true)
|
|
user_session(admin)
|
|
topic = @course.discussion_topics.create!
|
|
topic.is_section_specific = true
|
|
topic.course_sections << @section1
|
|
topic.save!
|
|
get 'index', params: { :course_id => @course.id }, :format => :json
|
|
expect(response).to be_successful
|
|
expect(assigns[:topics].length).to eq(1)
|
|
end
|
|
|
|
it 'admins can create section-specific discussions' do
|
|
admin = account_admin_user(account: @course.root_account, role: admin_role, active_user: true)
|
|
user_session(admin)
|
|
post 'create',
|
|
params: topic_params(@course, {is_announcement: true, specific_sections: @section1.id.to_s}),
|
|
:format => :json
|
|
expect(response).to be_successful
|
|
expect(DiscussionTopic.last.course_sections.first).to eq @section1
|
|
end
|
|
|
|
it 'creates a discussion with sections' do
|
|
post 'create',
|
|
params: topic_params(@course, {specific_sections: @section1.id.to_s}), :format => :json
|
|
expect(response).to be_successful
|
|
expect(DiscussionTopic.last.course_sections.first).to eq @section1
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 1
|
|
end
|
|
|
|
it 'does not allow creation of group discussions that are section specific' do
|
|
@group_category = @course.group_categories.create(:name => 'gc')
|
|
@group = @course.groups.create!(:group_category => @group_category)
|
|
post 'create',
|
|
params: group_topic_params(@group, {specific_sections: @section1.id.to_s}), :format => :json
|
|
expect(response).to have_http_status 400
|
|
expect(DiscussionTopic.count).to eq 0
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 0
|
|
end
|
|
|
|
# Note that this is different then group discussions. This is the
|
|
# "This is a Group Discussion" checkbox on a course discussion edit page,
|
|
# whereas that one is creating a discussion in a group page.
|
|
it 'does not allow creation of discussions with groups that are section specific' do
|
|
@group_category = @course.group_categories.create(:name => 'gc')
|
|
@group = @course.groups.create!(:group_category => @group_category)
|
|
param_overrides = {
|
|
specific_sections: "#{@section1.id},#{@section2.id}",
|
|
group_category_id: @group_category.id,
|
|
}
|
|
post('create', params: topic_params(@course, param_overrides), format: :json)
|
|
expect(response).to have_http_status 400
|
|
expect(DiscussionTopic.count).to eq 0
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 0
|
|
end
|
|
|
|
it 'does not allow creation of graded discussions that are section specific' do
|
|
obj_params = topic_params(@course, {specific_sections: @section1.id.to_s})
|
|
.merge(assignment_params(@course))
|
|
expect(DiscussionTopic.count).to eq 0
|
|
post('create', params: obj_params, format: :json)
|
|
expect(response).to have_http_status 422
|
|
expect(DiscussionTopic.count).to eq 0
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 0
|
|
end
|
|
|
|
it 'does not allow creation of disuccions to sections that are not visible to the user' do
|
|
# This teacher does not have permissino for section 3 and 4
|
|
sections = [@section1.id, @section2.id, @section3.id, @section4.id].join(",")
|
|
post 'create', params: topic_params(@course, {specific_sections: sections}), :format => :json
|
|
expect(response).to have_http_status 400
|
|
expect(DiscussionTopic.count).to eq 0
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 0
|
|
end
|
|
end
|
|
|
|
it "should require authorization to create a discussion" do
|
|
@course.update_attribute(:is_public, true)
|
|
post 'create', params: topic_params(@course, {is_announcement: false}), :format => :json
|
|
assert_unauthorized
|
|
end
|
|
|
|
it "should require authorization to create an announcement" do
|
|
@course.update_attribute(:is_public, true)
|
|
post 'create', params: topic_params(@course, {is_announcement: true}), :format => :json
|
|
assert_unauthorized
|
|
end
|
|
|
|
it 'logs an asset access record for the discussion topic' do
|
|
user_session(@student)
|
|
post 'create', params: topic_params(@course), :format => :json
|
|
accessed_asset = assigns[:accessed_asset]
|
|
expect(accessed_asset[:category]).to eq 'topics'
|
|
expect(accessed_asset[:level]).to eq 'participate'
|
|
end
|
|
|
|
it 'creates an announcement that is locked by default' do
|
|
user_session(@teacher)
|
|
params = topic_params(@course, {is_announcement: true})
|
|
params.delete(:locked)
|
|
post('create', params: params, format: :json)
|
|
expect(response).to be_successful
|
|
expect(DiscussionTopic.last.locked).to be_truthy
|
|
end
|
|
|
|
it 'creates a discussion topic that is not locked by default' do
|
|
user_session(@teacher)
|
|
params = topic_params(@course, {is_announcement: false})
|
|
params.delete(:locked)
|
|
post('create', params: params, format: :json)
|
|
expect(response).to be_successful
|
|
expect(DiscussionTopic.last.locked).to be_falsy
|
|
end
|
|
|
|
it 'registers a page view' do
|
|
user_session(@student)
|
|
post 'create', params: topic_params(@course), :format => :json
|
|
page_view = assigns[:page_view]
|
|
expect(page_view).not_to be_nil
|
|
expect(page_view.http_method).to eq 'post'
|
|
expect(page_view.url).to match %r{^http://test\.host/api/v1/courses/\d+/discussion_topics}
|
|
expect(page_view.participated).to be_truthy
|
|
end
|
|
|
|
it 'does not dispatch assignment created notification for unpublished graded topics' do
|
|
notification = Notification.create(:name => "Assignment Created")
|
|
obj_params = topic_params(@course).merge(assignment_params(@course))
|
|
user_session(@teacher)
|
|
post 'create', params: obj_params, :format => :json
|
|
json = JSON.parse response.body
|
|
topic = DiscussionTopic.find(json['id'])
|
|
expect(topic).to be_unpublished
|
|
expect(topic.assignment).to be_unpublished
|
|
expect(@student.recent_stream_items.map {|item| item.data['notification_id']}).not_to include notification.id
|
|
end
|
|
|
|
it 'does not dispatch new topic notification when hidden by selective release' do
|
|
notification = Notification.create(name: 'New Discussion Topic', category: 'TestImmediately')
|
|
@student.communication_channels.create!(path: 'student@example.com') {|cc| cc.workflow_state = 'active'}
|
|
new_section = @course.course_sections.create!
|
|
obj_params = topic_params(@course, published: true).merge(assignment_params(@course, only_visible_to_overrides: true, assignment_overrides: [{course_section_id: new_section.id}]))
|
|
user_session(@teacher)
|
|
post 'create', params: obj_params, :format => :json
|
|
json = JSON.parse response.body
|
|
topic = DiscussionTopic.find(json['id'])
|
|
expect(topic).to be_published
|
|
expect(topic.assignment).to be_published
|
|
expect(@student.email_channel.messages).to be_empty
|
|
expect(@student.recent_stream_items.map {|item| item.data}).not_to include topic
|
|
end
|
|
|
|
it 'does dispatch new topic notification when not hidden' do
|
|
notification = Notification.create(name: 'New Discussion Topic', category: 'TestImmediately')
|
|
@student.communication_channels.create!(path: 'student@example.com') {|cc| cc.workflow_state = 'active'}
|
|
obj_params = topic_params(@course, published: true)
|
|
user_session(@teacher)
|
|
post 'create', params: obj_params, :format => :json
|
|
json = JSON.parse response.body
|
|
topic = DiscussionTopic.find(json['id'])
|
|
expect(topic).to be_published
|
|
expect(@student.email_channel.messages.map(&:context)).to include(topic)
|
|
end
|
|
|
|
it 'does dispatch new topic notification when published' do
|
|
notification = Notification.create(name: 'New Discussion Topic', category: 'TestImmediately')
|
|
@student.communication_channels.create!(path: 'student@example.com') {|cc| cc.workflow_state = 'active'}
|
|
obj_params = topic_params(@course, published: false)
|
|
user_session(@teacher)
|
|
post 'create', params: obj_params, :format => :json
|
|
|
|
json = JSON.parse response.body
|
|
topic = DiscussionTopic.find(json['id'])
|
|
expect(@student.email_channel.messages).to be_empty
|
|
|
|
put 'update', params: {course_id: @course.id, topic_id: topic.id, title: 'Updated Topic', published: true}, format: 'json'
|
|
expect(@student.email_channel.messages.map(&:context)).to include(topic)
|
|
end
|
|
|
|
it 'dispatches an assignment stream item with the correct title' do
|
|
notification = Notification.create(:name => "Assignment Created")
|
|
obj_params = topic_params(@course).
|
|
merge(assignment_params(@course)).
|
|
merge({published: true})
|
|
user_session(@teacher)
|
|
post 'create', params: obj_params, :format => :json
|
|
si = @student.recent_stream_items.detect do |item|
|
|
item.data['notification_id'] == notification.id
|
|
end
|
|
expect(si.data['subject']).to eq "Assignment Created - #{obj_params[:title]}, #{@course.name}"
|
|
end
|
|
|
|
it 'does not allow for anonymous peer review assignment' do
|
|
obj_params = topic_params(@course).merge(assignment_params(@course))
|
|
obj_params[:assignment][:anonymous_peer_reviews] = true
|
|
user_session(@teacher)
|
|
post 'create', params: obj_params, :format => :json
|
|
json = JSON.parse response.body
|
|
expect(json['assignment']['anonymous_peer_reviews']).to be_falsey
|
|
end
|
|
|
|
context 'usage rights - student' do
|
|
let(:data) { fixture_file_upload("docs/txt.txt", "text/plain", true) }
|
|
|
|
before { user_session(@student) }
|
|
|
|
shared_examples_for 'no usage rights set' do
|
|
it 'does not return usage rights on discussion topic attachment' do
|
|
post 'create', params: topic_params(@course, attachment: data), :format => :json
|
|
expect(Attachment.last.reload.usage_rights).to be_nil
|
|
end
|
|
end
|
|
|
|
shared_examples_for 'usage rights set' do
|
|
it 'returns usage rights on discussion topic attachment' do
|
|
post 'create', params: topic_params(@course, attachment: data), :format => :json
|
|
expect(Attachment.last.reload.usage_rights).not_to be_nil
|
|
end
|
|
end
|
|
|
|
context 'with usage_rights_discussion_topics disabled' do
|
|
before { @course.root_account.disable_feature!(:usage_rights_discussion_topics) }
|
|
|
|
context 'enabled on course' do
|
|
before { @course.update!(usage_rights_required: true) }
|
|
|
|
include_examples 'no usage rights set'
|
|
end
|
|
|
|
context 'disabled on course' do
|
|
before { @course.update!(usage_rights_required: false) }
|
|
|
|
include_examples 'no usage rights set'
|
|
end
|
|
end
|
|
|
|
context 'with usage_rights_discussion_topics enabled' do
|
|
before { @course.root_account.enable_feature!(:usage_rights_discussion_topics) }
|
|
|
|
context 'enabled on course' do
|
|
before { @course.update!(usage_rights_required: true) }
|
|
|
|
include_examples 'usage rights set'
|
|
end
|
|
|
|
context 'disabled on course' do
|
|
before { @course.update!(usage_rights_required: false) }
|
|
|
|
include_examples 'no usage rights set'
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "PUT: update" do
|
|
before(:once) do
|
|
@topic = DiscussionTopic.create!(context: @course, title: 'Test Topic',
|
|
delayed_post_at: '2013-01-01T00:00:00UTC', lock_at: '2013-01-02T00:00:00UTC')
|
|
end
|
|
before(:each) do
|
|
user_session(@teacher)
|
|
end
|
|
|
|
describe "create_announcements_unlocked preference" do
|
|
|
|
before(:each) do
|
|
@teacher.create_announcements_unlocked(false)
|
|
user_session(@teacher)
|
|
end
|
|
|
|
it 'is not updated when updating an existing announcements' do
|
|
topic = Announcement.create!(
|
|
context: @course,
|
|
title: 'Test Announcement',
|
|
message: 'Foo',
|
|
locked: 'true'
|
|
)
|
|
put_params = {course_id: @course.id, topic_id: topic.id, locked: false}
|
|
put('update', params: put_params)
|
|
@teacher.reload
|
|
expect(@teacher.create_announcements_unlocked?).to be_falsey
|
|
end
|
|
|
|
it 'is not updated when creating an existing discussions' do
|
|
topic = DiscussionTopic.create!(
|
|
context: @course,
|
|
title: 'Test Topic',
|
|
message: 'Foo',
|
|
locked: 'true'
|
|
)
|
|
put_params = {course_id: @course.id, topic_id: topic.id, locked: false}
|
|
put('update', params: put_params)
|
|
@teacher.reload
|
|
expect(@teacher.create_announcements_unlocked?).to be_falsey
|
|
end
|
|
end
|
|
|
|
it 'does not allow setting specific sections for group discussions' do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept(true)
|
|
@course.enroll_teacher(@teacher, section: section2, allow_multiple_enrollments: true).accept(true)
|
|
|
|
group_category = @course.group_categories.create(:name => 'gc')
|
|
group = @course.groups.create!(:group_category => group_category)
|
|
topic = DiscussionTopic.create!(context: group, title: 'Test Topic',
|
|
delayed_post_at: '2013-01-01T00:00:00UTC', lock_at: '2013-01-02T00:00:00UTC')
|
|
put('update', params: {
|
|
id: topic.id,
|
|
group_id: group.id,
|
|
topic_id: topic.id,
|
|
specific_sections: section2.id,
|
|
title: 'Updated Topic',
|
|
})
|
|
expect(response).to have_http_status 422
|
|
expect(DiscussionTopic.count).to eq 2
|
|
expect(DiscussionTopicSectionVisibility.count).to eq 0
|
|
end
|
|
|
|
it "does not allow updating a section specific announcement you do not have visibilities for" do
|
|
user_session(@teacher)
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@course.enroll_teacher(@teacher, section: section1, allow_multiple_enrollments: true).accept!
|
|
Enrollment.limit_privileges_to_course_section!(@course, @teacher, true)
|
|
ann = @course.announcements.create!(message: "testing", is_section_specific: true, course_sections: [section2])
|
|
ann.save!
|
|
|
|
put('update', params: {
|
|
course_id: @course.id,
|
|
topic_id: ann.id,
|
|
specific_sections: section1.id,
|
|
title: 'Updated Topic',
|
|
})
|
|
expect(response).to have_http_status 400
|
|
end
|
|
|
|
it "Allows an admin to update a section-specific discussion" do
|
|
account = @course.root_account
|
|
section = @course.course_sections.create!(name: "Section")
|
|
admin = account_admin_user(account: account, role: admin_role, active_user: true)
|
|
user_session(admin)
|
|
topic = @course.discussion_topics.create!(title: "foo", message: "bar", user: @teacher)
|
|
put('update', params: {
|
|
course_id: @course.id,
|
|
topic_id: topic.id,
|
|
specific_sections: section.id,
|
|
title: "foobers"
|
|
})
|
|
expect(response).to have_http_status 200
|
|
end
|
|
|
|
it "triggers module progression recalculation if needed after changing sections" do
|
|
section1 = @course.course_sections.create!(name: "Section")
|
|
section2 = @course.course_sections.create!(name: "Section2")
|
|
topic = @course.discussion_topics.create!(title: "foo", message: "bar", user: @teacher)
|
|
mod = @course.context_modules.create!
|
|
tag = mod.add_item({:id => topic.id, :type => 'discussion_topic'})
|
|
mod.completion_requirements = {tag.id => {:type => 'must_view'}}
|
|
mod.save!
|
|
prog = mod.evaluate_for(@student)
|
|
expect(prog).to be_unlocked
|
|
|
|
user_session(@teacher)
|
|
put 'update', params: {course_id: @course.id, topic_id: topic.id, specific_sections: section2.id}
|
|
expect(response).to be_successful
|
|
|
|
expect(prog.reload).to be_completed
|
|
end
|
|
|
|
it "triggers module progression recalculation if undoing section specificness" do
|
|
section1 = @course.course_sections.create!(name: "Section")
|
|
section2 = @course.course_sections.create!(name: "Section2")
|
|
topic = @course.discussion_topics.create!(title: "foo", message: "bar", user: @teacher,
|
|
is_section_specific: true, course_sections: [section2])
|
|
mod = @course.context_modules.create!
|
|
tag = mod.add_item({:id => topic.id, :type => 'discussion_topic'})
|
|
mod.completion_requirements = {tag.id => {:type => 'must_view'}}
|
|
|
|
user_session(@teacher)
|
|
expect_any_instantiation_of(mod).to receive(:invalidate_progressions)
|
|
put 'update', params: {course_id: @course.id, topic_id: topic.id, specific_sections: 'all'}
|
|
expect(response).to be_successful
|
|
end
|
|
|
|
it "can turn graded topic into ungraded section-specific topic in one edit" do
|
|
user_session(@teacher)
|
|
assign = @course.assignments.create!(title: 'Graded Topic 1', submission_types: 'discussion_topic')
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
topic = assign.discussion_topic
|
|
put('update', params: {
|
|
course_id: @course.id,
|
|
topic_id: topic.id,
|
|
assignment: { set_assignment: "0" },
|
|
specific_sections: section1.id
|
|
})
|
|
expect(response).to have_http_status 200
|
|
topic.reload
|
|
expect(topic.assignment).to be_nil
|
|
end
|
|
|
|
it "should not clear lock_at if locked is not changed" do
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic',
|
|
lock_at: @topic.lock_at, delayed_post_at: @topic.delayed_post_at,
|
|
locked: false})
|
|
expect(response).to have_http_status 200
|
|
expect(@topic.reload).not_to be_locked
|
|
expect(@topic.lock_at).not_to be_nil
|
|
end
|
|
|
|
it "should be able to turn off locked and delayed_post_at date in same request" do
|
|
@topic.delayed_post_at = '2013-01-02T00:00:00UTC'
|
|
@topic.locked = true
|
|
@topic.save!
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic',
|
|
locked: false,
|
|
delayed_post_at: nil})
|
|
expect(response).to have_http_status 200
|
|
expect(assigns[:topic].title).to eq 'Updated Topic'
|
|
expect(assigns[:topic].locked).to eq false
|
|
expect(assigns[:topic].delayed_post_at).to be_nil
|
|
expect(@topic.reload).not_to be_locked
|
|
expect(@topic.delayed_post_at).to be_nil
|
|
end
|
|
|
|
it "should be able to turn on locked and delayed_post_at date in same request" do
|
|
@topic.delayed_post_at = nil
|
|
@topic.locked = false
|
|
@topic.save!
|
|
delayed_post_time = Time.new(2018, 04, 15)
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic',
|
|
locked: true,
|
|
delayed_post_at: delayed_post_time.to_s})
|
|
expect(response).to have_http_status 200
|
|
expect(assigns[:topic].title).to eq 'Updated Topic'
|
|
expect(assigns[:topic].locked).to eq true
|
|
expect(assigns[:topic].delayed_post_at.year).to eq 2018
|
|
expect(assigns[:topic].delayed_post_at.month).to eq 4
|
|
expect(@topic.reload).to be_locked
|
|
expect(@topic.delayed_post_at.year).to eq 2018
|
|
expect(@topic.delayed_post_at.month).to eq 4
|
|
end
|
|
|
|
it "should not change the editor if only pinned was changed" do
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id, pinned: '1'}, format: 'json')
|
|
@topic.reload
|
|
expect(@topic.pinned).to be_truthy
|
|
expect(@topic.editor).to_not eq @teacher
|
|
end
|
|
|
|
it "should not clear delayed_post_at if published is not changed" do
|
|
@topic.workflow_state = 'post_delayed'
|
|
@topic.save!
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic',
|
|
lock_at: @topic.lock_at, delayed_post_at: @topic.delayed_post_at,
|
|
published: false})
|
|
expect(@topic.reload).not_to be_published
|
|
expect(@topic.delayed_post_at).not_to be_nil
|
|
end
|
|
|
|
it "should unlock discussions with a lock_at attribute if lock state changes" do
|
|
@topic.lock!
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic',
|
|
lock_at: @topic.lock_at, delayed_post_at: @topic.delayed_post_at,
|
|
locked: false})
|
|
|
|
expect(@topic.reload).not_to be_locked
|
|
expect(@topic.lock_at).to be_nil
|
|
end
|
|
|
|
it "should set workflow to post_delayed when delayed_post_at and lock_at are in the future" do
|
|
put(:update, params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated topic', delayed_post_at: Time.zone.now + 5.days})
|
|
expect(@topic.reload).to be_post_delayed
|
|
end
|
|
|
|
it "should not clear lock_at if lock state hasn't changed" do
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic', lock_at: @topic.lock_at,
|
|
locked: true})
|
|
expect(@topic.reload).to be_locked
|
|
expect(@topic.lock_at).not_to be_nil
|
|
end
|
|
|
|
it "should set draft state on discussions with delayed_post_at" do
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id,
|
|
title: 'Updated Topic',
|
|
lock_at: @topic.lock_at, delayed_post_at: @topic.delayed_post_at,
|
|
published: false})
|
|
|
|
expect(@topic.reload).not_to be_published
|
|
end
|
|
|
|
it "attaches a file and handles duplicates" do
|
|
data = fixture_file_upload("docs/txt.txt", "text/plain", true)
|
|
attachment_model :context => @course, :uploaded_data => data, :folder => Folder.unfiled_folder(@course)
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id, attachment: data}, format: 'json'
|
|
expect(response).to be_successful
|
|
json = JSON.parse(response.body)
|
|
new_file = Attachment.find(json['attachments'][0]['id'])
|
|
expect(new_file.display_name).to match /txt-[0-9]+\.txt/
|
|
expect(json['attachments'][0]['display_name']).to eq new_file.display_name
|
|
end
|
|
|
|
it "should delete attachments" do
|
|
attachment = @topic.attachment = attachment_model(context: @course)
|
|
@topic.lock_at = Time.now + 1.week
|
|
@topic.unlock_at = Time.now - 1.week
|
|
@topic.save!
|
|
@topic.unlock!
|
|
put('update', params: {course_id: @course.id, topic_id: @topic.id, remove_attachment: '1'}, format: 'json')
|
|
expect(response).to be_successful
|
|
|
|
expect(@topic.reload.attachment).to be_nil
|
|
expect(attachment.reload).to be_deleted
|
|
end
|
|
|
|
it "uses inst-fs if it is enabled" do
|
|
allow(InstFS).to receive(:enabled?).and_return(true)
|
|
uuid = "1234-abcd"
|
|
allow(InstFS).to receive(:direct_upload).and_return(uuid)
|
|
|
|
data = fixture_file_upload("docs/txt.txt", "text/plain", true)
|
|
attachment_model :context => @course, :uploaded_data => data, :folder => Folder.unfiled_folder(@course)
|
|
put 'update', params: {course_id: @course.id, topic_id: @topic.id, attachment: data}, format: 'json'
|
|
|
|
@topic.reload
|
|
expect(@topic.attachment.instfs_uuid).to eq(uuid)
|
|
|
|
end
|
|
|
|
it "editing section-specific topic to not-specific should clear out visibilities" do
|
|
@announcement = Announcement.create!(context: @course, title: 'Test Announcement',
|
|
message: 'Foo', delayed_post_at: '2013-01-01T00:00:00UTC',
|
|
lock_at: '2013-01-02T00:00:00UTC')
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@announcement.is_section_specific = true
|
|
@announcement.course_sections = [section1, section2]
|
|
@announcement.save!
|
|
put('update', params: {course_id: @course.id, topic_id: @announcement.id, message: 'Foobar',
|
|
is_announcement: true, specific_sections: "all"})
|
|
expect(response).to be_successful
|
|
visibilities = DiscussionTopicSectionVisibility.active.
|
|
where(:discussion_topic_id => @announcement.id)
|
|
expect(visibilities.empty?).to eq true
|
|
end
|
|
|
|
it 'does not remove specific sections if key is missing in PUT json' do
|
|
@announcement = Announcement.create!(context: @course, title: 'Test Announcement',
|
|
message: 'Foo', delayed_post_at: '2013-01-01T00:00:00UTC',
|
|
lock_at: '2013-01-02T00:00:00UTC')
|
|
section1 = @course.course_sections.create!(name: "Section 1")
|
|
section2 = @course.course_sections.create!(name: "Section 2")
|
|
@announcement.is_section_specific = true
|
|
@announcement.course_sections = [section1, section2]
|
|
@announcement.save!
|
|
|
|
put('update', params: {course_id: @course.id, topic_id: @announcement.id, message: 'Foobar',
|
|
is_announcement: true})
|
|
expect(response).to be_successful
|
|
visibilities = DiscussionTopicSectionVisibility.active.
|
|
where(:discussion_topic_id => @announcement.id)
|
|
expect(visibilities.count).to eq 2
|
|
end
|
|
end
|
|
|
|
describe "POST 'reorder'" do
|
|
it "should reorder pinned topics" do
|
|
user_session(@teacher)
|
|
|
|
# add noise
|
|
@course.announcements.create!(message: 'asdf')
|
|
course_topic
|
|
|
|
topics = 3.times.map { course_topic(pinned: true) }
|
|
expect(topics.map(&:position)).to eq [1, 2, 3]
|
|
t1, t2, _ = topics
|
|
post 'reorder', params: {:course_id => @course.id, :order => "#{t2.id},#{t1.id}"}, :format => 'json'
|
|
expect(response).to be_successful
|
|
topics.each &:reload
|
|
expect(topics.map(&:position)).to eq [2, 1, 3]
|
|
end
|
|
end
|
|
end
|