allow module items to be published/unpublished through API
adds undocumented arguments to context module items API update action, identical to the context modules API test plan: * to publish a module item, update through the API with the argument 'module_item[published]=1' * to unpublish an item, use 'module_item[published]=0' * NOTE: the published/unpublished status of an item will not affect whether the item is viewable/usable by students * confirm that publishing/unpublishing an item syncs the state with the associated content (e.g. a wiki page's published/unpublished state) closes #CNVS-5943 Change-Id: I80c45a787a5cf8ac7b3bc569056d9590ab2f74bc Reviewed-on: https://gerrit.instructure.com/20633 Reviewed-by: Jeremy Stanley <jeremy@instructure.com> Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Clare Strong <clare@instructure.com> Product-Review: Bracken Mosbacker <bracken@instructure.com>
This commit is contained in:
parent
80fd695001
commit
2ecc8bc16b
|
@ -87,7 +87,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
if authorized_action(@context, @current_user, :read)
|
||||
mod = @context.modules_visible_to(@current_user).find(params[:module_id])
|
||||
route = polymorphic_url([:api_v1, @context, mod, :items])
|
||||
scope = mod.content_tags.active
|
||||
scope = mod.content_tags_visible_to(@current_user)
|
||||
items = Api.paginate(scope, self, route)
|
||||
prog = @context.grants_right?(@current_user, session, :participate_as_student) ? mod.evaluate_for(@current_user) : nil
|
||||
render :json => items.map { |item| module_item_json(item, @current_user, session, mod, prog) }
|
||||
|
@ -106,7 +106,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
def show
|
||||
if authorized_action(@context, @current_user, :read)
|
||||
mod = @context.modules_visible_to(@current_user).find(params[:module_id])
|
||||
item = mod.content_tags.active.find(params[:id])
|
||||
item = mod.content_tags_visible_to(@current_user).find(params[:id])
|
||||
prog = @context.grants_right?(@current_user, session, :participate_as_student) ? mod.evaluate_for(@current_user) : nil
|
||||
render :json => module_item_json(item, @current_user, session, mod, prog)
|
||||
end
|
||||
|
@ -182,6 +182,10 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
item_params[:url] = params[:module_item][:external_url]
|
||||
|
||||
if (@tag = @module.add_item(item_params)) && set_position && set_completion_requirement
|
||||
if @domain_root_account.enable_draft?
|
||||
@tag.workflow_state = 'unpublished'
|
||||
@tag.save
|
||||
end
|
||||
@module.touch
|
||||
render :json => module_item_json(@tag, @current_user, session, @module, nil)
|
||||
elsif @tag
|
||||
|
@ -207,6 +211,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
# "must_submit", "min_score": Only apply to "Assignment" and "Quiz" types
|
||||
# Inapplicable types will be ignored
|
||||
# @argument module_item[completion_requirement][min_score] [Required for completion_requirement type 'min_score'] minimum score required to complete
|
||||
# @undocumented @argument module_item[published] [Optional] Whether the module item is published and visible to students
|
||||
#
|
||||
# @example_request
|
||||
#
|
||||
|
@ -220,7 +225,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
#
|
||||
# @returns Module Item
|
||||
def update
|
||||
@tag = @context.context_module_tags.find(params[:id])
|
||||
@tag = @context.context_module_tags.not_deleted.find(params[:id])
|
||||
if authorized_action(@tag.context_module, @current_user, :update)
|
||||
return render :json => {:message => "missing module item parameter"}, :status => :bad_request unless params[:module_item]
|
||||
|
||||
|
@ -229,6 +234,16 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
@tag.indent = params[:module_item][:indent] if params[:module_item][:indent]
|
||||
@tag.new_tab = value_to_boolean(params[:module_item][:new_tab]) if params[:module_item][:new_tab]
|
||||
|
||||
if params[:module_item].has_key?(:published)
|
||||
if value_to_boolean(params[:module_item][:published])
|
||||
@tag.publish
|
||||
else
|
||||
@tag.unpublish
|
||||
end
|
||||
@tag.update_asset_workflow_state!
|
||||
@tag.context_module.save
|
||||
end
|
||||
|
||||
if @tag.save && set_position && set_completion_requirement
|
||||
@tag.update_asset_name! if params[:module_item][:title]
|
||||
render :json => module_item_json(@tag, @current_user, session, @tag.context_module, nil)
|
||||
|
@ -250,7 +265,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
#
|
||||
# @returns Module Item
|
||||
def destroy
|
||||
@tag = @context.context_module_tags.find(params[:id])
|
||||
@tag = @context.context_module_tags.not_deleted.find(params[:id])
|
||||
if authorized_action(@tag.context_module, @current_user, :update)
|
||||
@module = @tag.context_module
|
||||
@tag.destroy
|
||||
|
@ -263,7 +278,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
return true unless @tag && params[:module_item][:position]
|
||||
|
||||
@tag.reload
|
||||
if @tag.insert_at_position(params[:module_item][:position], @tag.context_module.content_tags.active)
|
||||
if @tag.insert_at_position(params[:module_item][:position], @tag.context_module.content_tags.not_deleted)
|
||||
# see ContextModulesController#reorder_items
|
||||
@tag.touch_context_module
|
||||
ContentTag.update_could_be_locked(@tag.context_module.content_tags)
|
||||
|
@ -276,6 +291,7 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
return false
|
||||
end
|
||||
end
|
||||
protected :set_position
|
||||
|
||||
def set_completion_requirement
|
||||
return true unless @tag && params[:module_item][:completion_requirement]
|
||||
|
@ -296,4 +312,5 @@ class ContextModuleItemsApiController < ApplicationController
|
|||
@module.completion_requirements = reqs
|
||||
@module.save
|
||||
end
|
||||
protected :set_completion_requirement
|
||||
end
|
||||
|
|
|
@ -136,7 +136,10 @@ class ContextModulesApiController < ApplicationController
|
|||
modules.each do |mod|
|
||||
case event
|
||||
when 'publish'
|
||||
mod.publish unless mod.active?
|
||||
unless mod.active?
|
||||
mod.publish
|
||||
mod.publish_items!
|
||||
end
|
||||
when 'unpublish'
|
||||
mod.unpublish unless mod.unpublished?
|
||||
when 'delete'
|
||||
|
@ -207,8 +210,7 @@ class ContextModulesApiController < ApplicationController
|
|||
# @argument module[require_sequential_progress] [Optional] Whether module items must be unlocked in order
|
||||
# @argument module[prerequisite_module_ids][] [Optional] IDs of Modules that must be completed before this one is unlocked
|
||||
# Prerequisite modules must precede this module (i.e. have a lower position value), otherwise they will be ignored
|
||||
# @undocumented @argument module[publish] [Optional] Set to publish the module
|
||||
# @undocumented @argument module[unpublish] [Optional] Set to unpublish the module
|
||||
# @undocumented @argument module[published] [Optional] Whether the module is published and visible to students
|
||||
#
|
||||
# @example_request
|
||||
#
|
||||
|
@ -235,10 +237,13 @@ class ContextModulesApiController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
if params[:module].delete :publish
|
||||
@module.publish
|
||||
elsif params[:module].delete :unpublish
|
||||
@module.unpublish
|
||||
if params[:module].has_key?(:published)
|
||||
if value_to_boolean(params[:module][:published])
|
||||
@module.publish
|
||||
@module.publish_items!
|
||||
else
|
||||
@module.unpublish
|
||||
end
|
||||
end
|
||||
|
||||
if @module.update_attributes(module_parameters) && set_position
|
||||
|
|
|
@ -245,7 +245,7 @@ class ContextModulesController < ApplicationController
|
|||
@module = @context.modules_visible_to(@current_user).find(params[:id])
|
||||
respond_to do |format|
|
||||
format.html { redirect_to named_context_url(@context, :context_context_modules_url, :anchor => "module_#{params[:id]}") }
|
||||
format.json { render :json => (@module.content_tags.active.to_json) }
|
||||
format.json { render :json => (@module.content_tags_visible_to(@current_user).to_json) }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -330,7 +330,7 @@ class ContextModulesController < ApplicationController
|
|||
end
|
||||
|
||||
def remove_item
|
||||
@tag = @context.context_module_tags.find(params[:id])
|
||||
@tag = @context.context_module_tags.not_deleted.find(params[:id])
|
||||
if authorized_action(@tag.context_module, @current_user, :update)
|
||||
@module = @tag.context_module
|
||||
@tag.destroy
|
||||
|
@ -340,7 +340,7 @@ class ContextModulesController < ApplicationController
|
|||
end
|
||||
|
||||
def update_item
|
||||
@tag = @context.context_module_tags.find(params[:id])
|
||||
@tag = @context.context_module_tags.not_deleted.find(params[:id])
|
||||
if authorized_action(@tag.context_module, @current_user, :update)
|
||||
@tag.title = params[:content_tag][:title] if params[:content_tag] && params[:content_tag][:title]
|
||||
@tag.url = params[:content_tag][:url] if %w(ExternalUrl ContextExternalTool).include?(@tag.content_type) && params[:content_tag] && params[:content_tag][:url]
|
||||
|
@ -378,6 +378,7 @@ class ContextModulesController < ApplicationController
|
|||
if authorized_action(@module, @current_user, :update)
|
||||
if params.delete :publish
|
||||
@module.publish
|
||||
@module.publish_items!
|
||||
elsif params.delete :unpublish
|
||||
@module.unpublish
|
||||
end
|
||||
|
|
|
@ -56,11 +56,21 @@ class ContentTag < ActiveRecord::Base
|
|||
end
|
||||
|
||||
workflow do
|
||||
state :active
|
||||
state :active do
|
||||
event :unpublish, :transitions_to => :unpublished
|
||||
end
|
||||
state :unpublished do
|
||||
event :publish, :transitions_to => :active
|
||||
end
|
||||
state :deleted
|
||||
end
|
||||
|
||||
|
||||
scope :active, where("content_tags.workflow_state<>'deleted'")
|
||||
# Note: right now, being unpublished won't affect any
|
||||
# behavior with the content tag itself.
|
||||
# The next step (#CNVS-5491) will be to replace this line with the following:
|
||||
#scope :active, where(:workflow_state => 'active')
|
||||
scope :not_deleted, where("content_tags.workflow_state<>'deleted'")
|
||||
|
||||
attr_accessor :skip_touch
|
||||
def touch_context_module
|
||||
|
@ -161,7 +171,7 @@ class ContentTag < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def update_asset_name!
|
||||
return if !self.sync_title_to_asset_title?
|
||||
return unless self.sync_title_to_asset_title?
|
||||
correct_context = self.content && self.content.respond_to?(:context) && self.content.context == self.context
|
||||
if correct_context
|
||||
if self.content.respond_to?("name=") && self.content.respond_to?("name") && self.content.name != self.title
|
||||
|
@ -174,6 +184,29 @@ class ContentTag < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def update_asset_workflow_state!
|
||||
return unless self.sync_workflow_state_to_asset?
|
||||
correct_context = self.content && self.content.respond_to?(:context) && self.content.context == self.context
|
||||
if correct_context
|
||||
asset_workflow_state = nil
|
||||
if self.unpublished? && self.content.respond_to?(:unpublished?)
|
||||
asset_workflow_state = 'unpublished'
|
||||
elsif self.active?
|
||||
if self.content.respond_to?(:active?)
|
||||
asset_workflow_state = 'active'
|
||||
elsif self.content.respond_to?(:available?)
|
||||
asset_workflow_state = 'available'
|
||||
elsif self.content.respond_to?(:published?)
|
||||
asset_workflow_state = 'published'
|
||||
end
|
||||
end
|
||||
if asset_workflow_state
|
||||
self.content.update_attribute(:workflow_state, asset_workflow_state)
|
||||
self.class.update_for(self.content)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.delete_for(asset)
|
||||
ContentTag.find_all_by_content_id_and_content_type(asset.id, asset.class.to_s).each{|t| t.destroy }
|
||||
ContentTag.find_all_by_context_id_and_context_type(asset.id, asset.class.to_s).each{|t| t.destroy }
|
||||
|
@ -226,21 +259,39 @@ class ContentTag < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.update_for(asset)
|
||||
tags = ContentTag.where(:content_id => asset, :content_type => asset.class.to_s).select([:id, :tag_type, :content_type, :context_module_id]).all
|
||||
tag_ids = tags.select{|t| t.sync_title_to_asset_title? }.map(&:id)
|
||||
tags = ContentTag.where(:content_id => asset, :content_type => asset.class.to_s).not_deleted.select([:id, :tag_type, :content_type, :context_module_id]).all
|
||||
module_ids = tags.select{|t| t.context_module_id }.map(&:context_module_id)
|
||||
|
||||
# update title
|
||||
tag_ids = tags.select{|t| t.sync_title_to_asset_title? }.map(&:id)
|
||||
attr_hash = {:updated_at => Time.now.utc}
|
||||
{:display_name => :title, :name => :title, :title => :title}.each do |attr, val|
|
||||
attr_hash[val] = asset.send(attr) if asset.respond_to?(attr)
|
||||
end
|
||||
attr_hash[:workflow_state] = 'deleted' if asset.respond_to?(:workflow_state) && asset.workflow_state == 'deleted'
|
||||
ContentTag.where(:id => tag_ids).update_all(attr_hash)
|
||||
|
||||
# update workflow_state
|
||||
tag_ids = tags.select{|t| t.sync_workflow_state_to_asset? }.map(&:id)
|
||||
attr_hash = {:updated_at => Time.now.utc}
|
||||
if asset.respond_to?(:workflow_state)
|
||||
if ['active', 'available', 'published'].include?(asset.workflow_state)
|
||||
attr_hash[:workflow_state] = 'active'
|
||||
elsif ['unpublished', 'deleted'].include?(asset.workflow_state)
|
||||
attr_hash[:workflow_state] = asset.workflow_state
|
||||
end
|
||||
end
|
||||
ContentTag.where(:id => tag_ids).update_all(attr_hash) if attr_hash[:workflow_state]
|
||||
|
||||
ContentTag.touch_context_modules(module_ids)
|
||||
end
|
||||
|
||||
def sync_title_to_asset_title?
|
||||
self.tag_type != "learning_outcome_association" && !['ContextExternalTool', 'Attachment'].member?(self.content_type)
|
||||
end
|
||||
|
||||
def sync_workflow_state_to_asset?
|
||||
['Assignment', 'WikiPage'].include?(self.content_type)
|
||||
end
|
||||
|
||||
def context_module_action(user, action, points=nil)
|
||||
self.context_module.update_for(user, action, self, points) if self.context_module
|
||||
|
|
|
@ -109,6 +109,13 @@ class ContextModule < ActiveRecord::Base
|
|||
scope :unpublished, where(:workflow_state => 'unpublished')
|
||||
scope :not_deleted, where("context_modules.workflow_state<>'deleted'")
|
||||
|
||||
def publish_items!
|
||||
self.content_tags.select{|t| t.unpublished?}.each do |tag|
|
||||
tag.publish
|
||||
tag.update_asset_workflow_state!
|
||||
end
|
||||
end
|
||||
|
||||
def update_student_progressions(user=nil)
|
||||
# modules are ordered by position, so running through them in order will
|
||||
# automatically handle issues with dependencies loading in the correct
|
||||
|
@ -240,6 +247,14 @@ class ContextModule < ActiveRecord::Base
|
|||
write_attribute(:completion_requirements, val)
|
||||
end
|
||||
|
||||
def content_tags_visible_to(user)
|
||||
if self.grants_right?(user, :update)
|
||||
self.content_tags.not_deleted
|
||||
else
|
||||
self.content_tags.active
|
||||
end
|
||||
end
|
||||
|
||||
def add_item(params, added_item=nil, opts={})
|
||||
params[:type] = params[:type].underscore if params[:type]
|
||||
position = opts[:position] || (self.content_tags.active.map(&:position).compact.max || 0) + 1
|
||||
|
@ -254,6 +269,8 @@ class ContextModule < ActiveRecord::Base
|
|||
elsif params[:type] == "quiz"
|
||||
item = opts[:quiz] || self.context.quizzes.active.find_by_id(params[:id])
|
||||
end
|
||||
workflow_state = item.workflow_state if item && item.respond_to?(:workflow_state) && ['active', 'unpublished'].include?(item.workflow_state)
|
||||
workflow_state ||= 'active'
|
||||
if params[:type] == 'external_url'
|
||||
title = params[:title]
|
||||
added_item ||= self.content_tags.build(:context => self.context)
|
||||
|
@ -268,7 +285,7 @@ class ContextModule < ActiveRecord::Base
|
|||
added_item.content_type = 'ExternalUrl'
|
||||
added_item.context_module_id = self.id
|
||||
added_item.indent = params[:indent] || 0
|
||||
added_item.workflow_state = 'active'
|
||||
added_item.workflow_state = workflow_state
|
||||
added_item.save
|
||||
added_item
|
||||
elsif params[:type] == 'context_external_tool' || params[:type] == 'external_tool'
|
||||
|
@ -290,7 +307,7 @@ class ContextModule < ActiveRecord::Base
|
|||
}
|
||||
added_item.context_module_id = self.id
|
||||
added_item.indent = params[:indent] || 0
|
||||
added_item.workflow_state = 'active'
|
||||
added_item.workflow_state = workflow_state
|
||||
added_item.save
|
||||
added_item
|
||||
elsif params[:type] == 'context_module_sub_header' || params[:type] == 'sub_header'
|
||||
|
@ -306,7 +323,7 @@ class ContextModule < ActiveRecord::Base
|
|||
added_item.content_type = 'ContextModuleSubHeader'
|
||||
added_item.context_module_id = self.id
|
||||
added_item.indent = params[:indent] || 0
|
||||
added_item.workflow_state = 'active'
|
||||
added_item.workflow_state = workflow_state
|
||||
added_item.save
|
||||
added_item
|
||||
else
|
||||
|
@ -322,7 +339,7 @@ class ContextModule < ActiveRecord::Base
|
|||
}
|
||||
added_item.context_module_id = self.id
|
||||
added_item.indent = params[:indent] || 0
|
||||
added_item.workflow_state = 'active'
|
||||
added_item.workflow_state = workflow_state
|
||||
added_item.save
|
||||
added_item
|
||||
end
|
||||
|
|
|
@ -123,8 +123,12 @@ class WikiPage < ActiveRecord::Base
|
|||
after_save :remove_changed_flag
|
||||
|
||||
workflow do
|
||||
state :active
|
||||
state :unpublished
|
||||
state :active do
|
||||
event :unpublish, :transitions_to => :unpublished
|
||||
end
|
||||
state :unpublished do
|
||||
event :publish, :transitions_to => :active
|
||||
end
|
||||
state :post_delayed do
|
||||
event :delayed_post, :transitions_to => :active
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ module Api::V1::ContextModule
|
|||
include Api::V1::Json
|
||||
include Api::V1::User
|
||||
|
||||
MODULE_JSON_ATTRS = %w(id position name unlock_at workflow_state)
|
||||
MODULE_JSON_ATTRS = %w(id position name unlock_at)
|
||||
|
||||
MODULE_ITEM_JSON_ATTRS = %w(id position title indent)
|
||||
|
||||
|
@ -32,6 +32,7 @@ module Api::V1::ContextModule
|
|||
hash['state'] = progression.workflow_state
|
||||
hash['completed_at'] = progression.completed_at
|
||||
end
|
||||
hash['published'] = context_module.active? if context_module.grants_right?(current_user, :update)
|
||||
hash
|
||||
end
|
||||
|
||||
|
@ -91,6 +92,8 @@ module Api::V1::ContextModule
|
|||
hash['completion_requirement'] = ch
|
||||
end
|
||||
|
||||
hash['published'] = content_tag.active? if context_module.grants_right?(current_user, :update)
|
||||
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
|
|
@ -61,6 +61,7 @@ describe "Module Items API", :type => :integration do
|
|||
end
|
||||
|
||||
it "should list module items" do
|
||||
@assignment_tag.unpublish
|
||||
json = api_call(:get, "/api/v1/courses/#{@course.id}/modules/#{@module1.id}/items",
|
||||
:controller => "context_module_items_api", :action => "index", :format => "json",
|
||||
:course_id => "#{@course.id}", :module_id => "#{@module1.id}")
|
||||
|
@ -74,7 +75,8 @@ describe "Module Items API", :type => :integration do
|
|||
"url" => "http://www.example.com/api/v1/courses/#{@course.id}/assignments/#{@assignment.id}",
|
||||
"title" => @assignment_tag.title,
|
||||
"indent" => 0,
|
||||
"completion_requirement" => { "type" => "must_submit" }
|
||||
"completion_requirement" => { "type" => "must_submit" },
|
||||
"published" => false
|
||||
},
|
||||
{
|
||||
"type" => "Quiz",
|
||||
|
@ -85,7 +87,8 @@ describe "Module Items API", :type => :integration do
|
|||
"position" => 2,
|
||||
"title" => @quiz_tag.title,
|
||||
"indent" => 0,
|
||||
"completion_requirement" => { "type" => "min_score", "min_score" => 10 }
|
||||
"completion_requirement" => { "type" => "min_score", "min_score" => 10 },
|
||||
"published" => true
|
||||
},
|
||||
{
|
||||
"type" => "Discussion",
|
||||
|
@ -96,14 +99,16 @@ describe "Module Items API", :type => :integration do
|
|||
"url" => "http://www.example.com/api/v1/courses/#{@course.id}/discussion_topics/#{@topic.id}",
|
||||
"title" => @topic_tag.title,
|
||||
"indent" => 0,
|
||||
"completion_requirement" => { "type" => "must_contribute" }
|
||||
"completion_requirement" => { "type" => "must_contribute" },
|
||||
"published" => true
|
||||
},
|
||||
{
|
||||
"type" => "SubHeader",
|
||||
"id" => @subheader_tag.id,
|
||||
"position" => 4,
|
||||
"title" => @subheader_tag.title,
|
||||
"indent" => 0
|
||||
"indent" => 0,
|
||||
"published" => true
|
||||
},
|
||||
{
|
||||
"type" => "ExternalUrl",
|
||||
|
@ -113,7 +118,8 @@ describe "Module Items API", :type => :integration do
|
|||
"position" => 5,
|
||||
"title" => @external_url_tag.title,
|
||||
"indent" => 1,
|
||||
"completion_requirement" => { "type" => "must_view" }
|
||||
"completion_requirement" => { "type" => "must_view" },
|
||||
"published" => true
|
||||
}
|
||||
]
|
||||
end
|
||||
|
@ -131,9 +137,11 @@ describe "Module Items API", :type => :integration do
|
|||
"title" => @wiki_page_tag.title,
|
||||
"indent" => 0,
|
||||
"url" => "http://www.example.com/api/v1/courses/#{@course.id}/pages/#{@wiki_page.url}",
|
||||
"page_url" => @wiki_page.url
|
||||
"page_url" => @wiki_page.url,
|
||||
"published" => true
|
||||
}
|
||||
|
||||
@attachment_tag.unpublish
|
||||
json = api_call(:get, "/api/v1/courses/#{@course.id}/modules/#{@module2.id}/items/#{@attachment_tag.id}",
|
||||
:controller => "context_module_items_api", :action => "show", :format => "json",
|
||||
:course_id => "#{@course.id}", :module_id => "#{@module2.id}",
|
||||
|
@ -146,7 +154,8 @@ describe "Module Items API", :type => :integration do
|
|||
"position" => 2,
|
||||
"title" => @attachment_tag.title,
|
||||
"indent" => 0,
|
||||
"url" => "http://www.example.com/api/v1/files/#{@attachment.id}"
|
||||
"url" => "http://www.example.com/api/v1/files/#{@attachment.id}",
|
||||
"published" => false
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -414,6 +423,53 @@ describe "Module Items API", :type => :integration do
|
|||
req = @module1.completion_requirements.find{|h| h[:id] == json['id'].to_i}
|
||||
req.should be_nil
|
||||
end
|
||||
|
||||
it "should publish module items" do
|
||||
course_with_student(:course => @course, :active_all => true)
|
||||
@user = @teacher
|
||||
|
||||
@assignment.submit_homework(@student, :body => "done!")
|
||||
|
||||
@assignment_tag.unpublish
|
||||
@assignment_tag.workflow_state.should == 'unpublished'
|
||||
@module1.save
|
||||
|
||||
# Uncomment this after implenting stricter content_tags.active scope - #CNVS-5491
|
||||
#@module1.evaluate_for(@student).workflow_state.should == 'unlocked'
|
||||
|
||||
json = api_call(:put, "/api/v1/courses/#{@course.id}/modules/#{@module1.id}/items/#{@assignment_tag.id}",
|
||||
{:controller => "context_module_items_api", :action => "update", :format => "json",
|
||||
:course_id => "#{@course.id}", :module_id => "#{@module1.id}", :id => "#{@assignment_tag.id}"},
|
||||
{:module_item => {:published => '1'}}
|
||||
)
|
||||
json['published'].should == true
|
||||
|
||||
@assignment_tag.reload
|
||||
@assignment_tag.workflow_state.should == 'active'
|
||||
end
|
||||
|
||||
it "should unpublish module items" do
|
||||
course_with_student(:course => @course, :active_all => true)
|
||||
@user = @teacher
|
||||
|
||||
@assignment.submit_homework(@student, :body => "done!")
|
||||
|
||||
@module1.evaluate_for(@student).workflow_state.should == 'started'
|
||||
|
||||
json = api_call(:put, "/api/v1/courses/#{@course.id}/modules/#{@module1.id}/items/#{@assignment_tag.id}",
|
||||
{:controller => "context_module_items_api", :action => "update", :format => "json",
|
||||
:course_id => "#{@course.id}", :module_id => "#{@module1.id}", :id => "#{@assignment_tag.id}"},
|
||||
{:module_item => {:published => '0'}}
|
||||
)
|
||||
json['published'].should == false
|
||||
|
||||
@assignment_tag.reload
|
||||
@assignment_tag.workflow_state.should == 'unpublished'
|
||||
|
||||
@module1.reload
|
||||
# Uncomment this after implenting stricter content_tags.active scope - #CNVS-5491
|
||||
#@module1.evaluate_for(@student).workflow_state.should == 'unlocked'
|
||||
end
|
||||
end
|
||||
|
||||
it "should delete a module item" do
|
||||
|
@ -434,11 +490,12 @@ describe "Module Items API", :type => :integration do
|
|||
end
|
||||
|
||||
it "should list module items" do
|
||||
@assignment_tag.unpublish
|
||||
json = api_call(:get, "/api/v1/courses/#{@course.id}/modules/#{@module1.id}/items",
|
||||
:controller => "context_module_items_api", :action => "index", :format => "json",
|
||||
:course_id => "#{@course.id}", :module_id => "#{@module1.id}")
|
||||
|
||||
json.map{|item| item['id']}.sort.should == @module1.content_tags.map(&:id).sort
|
||||
json.map{|item| item['id']}.sort.should == @module1.content_tags.active.map(&:id).sort
|
||||
|
||||
#also for locked modules that have completion requirements
|
||||
@assignment2 = @course.assignments.create!(:name => "pls submit", :submission_types => ["online_text_entry"])
|
||||
|
@ -471,6 +528,15 @@ describe "Module Items API", :type => :integration do
|
|||
json['completion_requirement']['completed'].should be_true
|
||||
end
|
||||
|
||||
it "should not show unpublished items" do
|
||||
pending 'restricting content_tags.active scope - #CNVS-5491'
|
||||
@assignment_tag.unpublish
|
||||
json = api_call(:get, "/api/v1/courses/#{@course.id}/modules/#{@module1.id}/items/#{@assignment_tag.id}",
|
||||
{:controller => "context_module_items_api", :action => "show", :format => "json",
|
||||
:course_id => "#{@course.id}", :module_id => "#{@module1.id}",
|
||||
:id => "#{@assignment_tag.id}"}, {}, {}, {:expected_status => 404})
|
||||
end
|
||||
|
||||
it "should mark viewed and redirect external URLs" do
|
||||
raw_api_call(:get, "/api/v1/courses/#{@course.id}/module_item_redirect/#{@external_url_tag.id}",
|
||||
:controller => "context_module_items_api", :action => "redirect",
|
||||
|
|
|
@ -72,7 +72,7 @@ describe "Modules API", :type => :integration do
|
|||
"require_sequential_progress" => false,
|
||||
"prerequisite_module_ids" => [],
|
||||
"id" => @module1.id,
|
||||
"workflow_state" => "active"
|
||||
"published" => true
|
||||
},
|
||||
{
|
||||
"name" => @module2.name,
|
||||
|
@ -81,7 +81,7 @@ describe "Modules API", :type => :integration do
|
|||
"require_sequential_progress" => true,
|
||||
"prerequisite_module_ids" => [@module1.id],
|
||||
"id" => @module2.id,
|
||||
"workflow_state" => "active"
|
||||
"published" => true
|
||||
},
|
||||
{
|
||||
"name" => @module3.name,
|
||||
|
@ -90,7 +90,7 @@ describe "Modules API", :type => :integration do
|
|||
"require_sequential_progress" => false,
|
||||
"prerequisite_module_ids" => [],
|
||||
"id" => @module3.id,
|
||||
"workflow_state" => "unpublished"
|
||||
"published" => false
|
||||
}
|
||||
]
|
||||
end
|
||||
|
@ -106,7 +106,7 @@ describe "Modules API", :type => :integration do
|
|||
"require_sequential_progress" => true,
|
||||
"prerequisite_module_ids" => [@module1.id],
|
||||
"id" => @module2.id,
|
||||
"workflow_state" => "active"
|
||||
"published" => true
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -121,7 +121,7 @@ describe "Modules API", :type => :integration do
|
|||
"require_sequential_progress" => false,
|
||||
"prerequisite_module_ids" => [],
|
||||
"id" => @module3.id,
|
||||
"workflow_state" => "unpublished"
|
||||
"published" => false
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -153,13 +153,23 @@ describe "Modules API", :type => :integration do
|
|||
@test_modules[2..3].each { |m| m.update_attribute(:workflow_state , 'unpublished') }
|
||||
@test_modules.map { |tm| tm.workflow_state }.should == %w(active active unpublished unpublished)
|
||||
@modules_to_update = [@test_modules[1], @test_modules[3]]
|
||||
|
||||
@wiki_page = @course.wiki.wiki_page
|
||||
@wiki_page.workflow_state = 'unpublished'; @wiki_page.save!
|
||||
@wiki_page_tag = @test_modules[3].add_item(:id => @wiki_page.id, :type => 'wiki_page')
|
||||
|
||||
@ids_to_update = @modules_to_update.map(&:id)
|
||||
end
|
||||
|
||||
it "should publish modules" do
|
||||
it "should publish modules (and their tags)" do
|
||||
json = api_call(:put, @path, @path_opts, { :event => 'publish', :module_ids => @ids_to_update })
|
||||
json['completed'].sort.should == @ids_to_update
|
||||
@test_modules.map { |tm| tm.reload.workflow_state }.should == %w(active active unpublished active)
|
||||
|
||||
@wiki_page_tag.reload
|
||||
@wiki_page_tag.active?.should == true
|
||||
@wiki_page.reload
|
||||
@wiki_page.active?.should == true
|
||||
end
|
||||
|
||||
it "should unpublish modules" do
|
||||
|
@ -237,6 +247,11 @@ describe "Modules API", :type => :integration do
|
|||
@module1 = @course.context_modules.create(:name => "unpublished")
|
||||
@module1.workflow_state = 'unpublished'
|
||||
@module1.save!
|
||||
|
||||
@wiki_page = @course.wiki.wiki_page
|
||||
@wiki_page.workflow_state = 'unpublished'; @wiki_page.save!
|
||||
@wiki_page_tag = @module1.add_item(:id => @wiki_page.id, :type => 'wiki_page')
|
||||
|
||||
@module2 = @course.context_modules.create!(:name => "published")
|
||||
end
|
||||
|
||||
|
@ -286,24 +301,29 @@ describe "Modules API", :type => :integration do
|
|||
@module2.position.should == 2
|
||||
end
|
||||
|
||||
it "should publish modules" do
|
||||
it "should publish modules (and their tags)" do
|
||||
json = api_call(:put, "/api/v1/courses/#{@course.id}/modules/#{@module1.id}",
|
||||
{:controller => "context_modules_api", :action => "update", :format => "json",
|
||||
:course_id => "#{@course.id}", :id => "#{@module1.id}"},
|
||||
{:module => {:publish => '1'}}
|
||||
{:module => {:published => '1'}}
|
||||
)
|
||||
json['workflow_state'].should == 'active'
|
||||
json['published'].should == true
|
||||
@module1.reload
|
||||
@module1.active?.should == true
|
||||
|
||||
@wiki_page_tag.reload
|
||||
@wiki_page_tag.active?.should == true
|
||||
@wiki_page.reload
|
||||
@wiki_page.active?.should == true
|
||||
end
|
||||
|
||||
it "should unpublish modules" do
|
||||
json = api_call(:put, "/api/v1/courses/#{@course.id}/modules/#{@module2.id}",
|
||||
{:controller => "context_modules_api", :action => "update", :format => "json",
|
||||
:course_id => "#{@course.id}", :id => "#{@module2.id}"},
|
||||
{:module => {:unpublish => '1'}}
|
||||
{:module => {:published => '0'}}
|
||||
)
|
||||
json['workflow_state'].should == 'unpublished'
|
||||
json['published'].should == false
|
||||
@module2.reload
|
||||
@module2.unpublished?.should == true
|
||||
end
|
||||
|
@ -485,7 +505,7 @@ describe "Modules API", :type => :integration do
|
|||
:controller => "context_modules_api", :action => "index", :format => "json",
|
||||
:course_id => "#{@course.id}")
|
||||
json.length.should == 2
|
||||
json.each{|cm| cm['workflow_state'].should == 'active'}
|
||||
json.each{|cm| @course.context_modules.find(cm['id']).workflow_state.should == 'active'}
|
||||
end
|
||||
|
||||
it "should not show a single unpublished module" do
|
||||
|
|
|
@ -160,6 +160,56 @@ describe ContentTag do
|
|||
@assignment.reload
|
||||
@assignment.title.should == 'some assignment (renamed)'
|
||||
end
|
||||
|
||||
it "should publish/unpublish the tag if the linked wiki page is published/unpublished" do
|
||||
course
|
||||
@page = @course.wiki.wiki_pages.create!(:title => "some page")
|
||||
@page.workflow_state = 'unpublished'
|
||||
@page.save!
|
||||
@module = @course.context_modules.create!(:name => "module")
|
||||
@tag = @module.add_item({:type => 'WikiPage', :title => 'some page', :id => @page.id})
|
||||
@tag.workflow_state.should == 'unpublished'
|
||||
|
||||
@page.reload
|
||||
@page.workflow_state = 'active'
|
||||
@page.save!
|
||||
@tag.reload
|
||||
@tag.workflow_state.should == 'active'
|
||||
|
||||
@page.reload
|
||||
@page.workflow_state = 'unpublished'
|
||||
@page.save!
|
||||
@tag.reload
|
||||
@tag.workflow_state.should == 'unpublished'
|
||||
end
|
||||
|
||||
it "should publish/unpublish the linked wiki page (and its tags) if the tag is published/unpublished" do
|
||||
course
|
||||
@page = @course.wiki.wiki_pages.create!(:title => "some page")
|
||||
@page.workflow_state = 'unpublished'
|
||||
@page.save!
|
||||
@module = @course.context_modules.create!(:name => "module")
|
||||
@tag = @module.add_item({:type => 'WikiPage', :title => 'some page', :id => @page.id})
|
||||
@tag2 = @module.add_item({:type => 'WikiPage', :title => 'some page', :id => @page.id})
|
||||
|
||||
@tag.reload
|
||||
@tag.workflow_state = 'active'
|
||||
@tag.save!
|
||||
@tag.update_asset_workflow_state!
|
||||
@page.reload
|
||||
@page.workflow_state.should == 'active'
|
||||
@tag2.reload
|
||||
@tag2.workflow_state.should == 'active'
|
||||
|
||||
@tag.reload
|
||||
@tag.workflow_state = 'unpublished'
|
||||
@tag.save!
|
||||
@tag.update_asset_workflow_state!
|
||||
@page.reload
|
||||
@page.workflow_state.should == 'unpublished'
|
||||
@tag2.reload
|
||||
@tag2.workflow_state.should == 'unpublished'
|
||||
end
|
||||
|
||||
it "should not rename tag if linked attachment is renamed" do
|
||||
course
|
||||
|
|
Loading…
Reference in New Issue