master courses: hide edit/delete for restricted wiki pages
proof of concept for first-pass all-or-nothing restrictions closes #MC-50 Change-Id: I937aeb24892e4fca0b31d5cd2d05058e7ea01679 Reviewed-on: https://gerrit.instructure.com/98553 Tested-by: Jenkins Reviewed-by: Jeremy Stanley <jeremy@instructure.com> Product-Review: James Williams <jamesw@instructure.com> QA-Review: James Williams <jamesw@instructure.com>
This commit is contained in:
parent
1e14794c0b
commit
84494e877d
|
@ -1985,7 +1985,8 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
if @page
|
if @page
|
||||||
hash[:WIKI_PAGE] = wiki_page_json(@page, @current_user, session, true, :deep_check_if_needed => true)
|
check_for_restrictions = master_courses? && @context.wiki.grants_right?(@current_user, :manage)
|
||||||
|
hash[:WIKI_PAGE] = wiki_page_json(@page, @current_user, session, true, :deep_check_if_needed => true, :include_master_course_restrictions => check_for_restrictions)
|
||||||
hash[:WIKI_PAGE_REVISION] = (current_version = @page.versions.current) ? StringifyIds.stringify_id(current_version.number) : nil
|
hash[:WIKI_PAGE_REVISION] = (current_version = @page.versions.current) ? StringifyIds.stringify_id(current_version.number) : nil
|
||||||
hash[:WIKI_PAGE_SHOW_PATH] = named_context_url(@context, :context_wiki_page_path, @page)
|
hash[:WIKI_PAGE_SHOW_PATH] = named_context_url(@context, :context_wiki_page_path, @page)
|
||||||
hash[:WIKI_PAGE_EDIT_PATH] = named_context_url(@context, :edit_context_wiki_page_path, @page)
|
hash[:WIKI_PAGE_EDIT_PATH] = named_context_url(@context, :edit_context_wiki_page_path, @page)
|
||||||
|
|
|
@ -250,7 +250,10 @@ class WikiPagesApiController < ApplicationController
|
||||||
scope = scope.order(order_clause)
|
scope = scope.order(order_clause)
|
||||||
|
|
||||||
wiki_pages = Api.paginate(scope, self, pages_route)
|
wiki_pages = Api.paginate(scope, self, pages_route)
|
||||||
render :json => wiki_pages_json(wiki_pages, @current_user, session)
|
|
||||||
|
check_for_restrictions = master_courses? && @context.wiki.grants_right?(@current_user, :manage)
|
||||||
|
MasterCourses::Restrictor.preload_restrictions(wiki_pages) if check_for_restrictions
|
||||||
|
render :json => wiki_pages_json(wiki_pages, @current_user, session, :include_master_course_restrictions => check_for_restrictions)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -391,6 +394,7 @@ class WikiPagesApiController < ApplicationController
|
||||||
# @returns Page
|
# @returns Page
|
||||||
def destroy
|
def destroy
|
||||||
if authorized_action(@page, @current_user, :delete)
|
if authorized_action(@page, @current_user, :delete)
|
||||||
|
return render_unauthorized_action if editing_restricted?(@page)
|
||||||
if !@was_front_page
|
if !@was_front_page
|
||||||
@page.destroy
|
@page.destroy
|
||||||
process_front_page
|
process_front_page
|
||||||
|
|
|
@ -110,6 +110,8 @@ class WikiPagesController < ApplicationController
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
if @page.grants_any_right?(@current_user, session, :update, :update_content)
|
if @page.grants_any_right?(@current_user, session, :update, :update_content)
|
||||||
|
return render_unauthorized_action if editing_restricted?(@page)
|
||||||
|
|
||||||
js_env ConditionalRelease::Service.env_for @context
|
js_env ConditionalRelease::Service.env_for @context
|
||||||
if !ConditionalRelease::Service.enabled_in_context?(@context) ||
|
if !ConditionalRelease::Service.enabled_in_context?(@context) ||
|
||||||
enforce_assignment_visible(@page)
|
enforce_assignment_visible(@page)
|
||||||
|
|
|
@ -58,9 +58,9 @@ module MasterCourses::Restrictor
|
||||||
|
|
||||||
case edit_type
|
case edit_type
|
||||||
when :all
|
when :all
|
||||||
MasterCourses::LOCK_TYPES.all?{|type| restrictions[type]}
|
self.class.base_class.restricted_column_settings.keys.all?{|type| restrictions[type]} # make it possible to only have restrictions on one type
|
||||||
when :any
|
when :any
|
||||||
MasterCourses::LOCK_TYPES.any?{|type| restrictions[type]}
|
self.class.base_class.restricted_column_settings.keys.any?{|type| restrictions[type]}
|
||||||
when *MasterCourses::LOCK_TYPES
|
when *MasterCourses::LOCK_TYPES
|
||||||
!!restrictions[edit_type]
|
!!restrictions[edit_type]
|
||||||
else
|
else
|
||||||
|
@ -137,6 +137,7 @@ module MasterCourses::Restrictor
|
||||||
locked_types << type
|
locked_types << type
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
locked_types
|
locked_types
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,11 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{#if CAN.UPDATE_CONTENT}}
|
{{#unless restricted_by_master_course}}
|
||||||
<a href="{{wiki_page_edit_path}}" class="btn edit-wiki"><i class="icon-edit"></i> {{#t 'buttons.edit'}}Edit{{/t}}</a>
|
{{#if CAN.UPDATE_CONTENT}}
|
||||||
{{/if}}
|
<a href="{{wiki_page_edit_path}}" class="btn edit-wiki"><i class="icon-edit"></i> {{#t 'buttons.edit'}}Edit{{/t}}</a>
|
||||||
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
{{#if CAN.ACCESS_GEAR_MENU}}
|
{{#if CAN.ACCESS_GEAR_MENU}}
|
||||||
<div class="inline-block">
|
<div class="inline-block">
|
||||||
<a class="btn al-trigger" tabindex="0" role="button" href="#">
|
<a class="btn al-trigger" tabindex="0" role="button" href="#">
|
||||||
|
@ -42,9 +44,11 @@
|
||||||
<span class="screenreader-only">{{#t 'toolbar_menu.settings'}}Settings{{/t}}</span>
|
<span class="screenreader-only">{{#t 'toolbar_menu.settings'}}Settings{{/t}}</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="al-options">
|
<ul class="al-options">
|
||||||
{{#if CAN.DELETE}}
|
{{#unless restricted_by_master_course}}
|
||||||
<li><a href="#" class="icon-trash delete_page{{#unless deletable}} disabled{{/unless}}" {{#unless deletable}}aria-disabled="true"{{/unless}}>{{#t "delete_wiki"}}Delete{{/t}}</a></li>
|
{{#if CAN.DELETE}}
|
||||||
{{/if}}
|
<li><a href="#" class="icon-trash delete_page{{#unless deletable}} disabled{{/unless}}" {{#unless deletable}}aria-disabled="true"{{/unless}}>{{#t "delete_wiki"}}Delete{{/t}}</a></li>
|
||||||
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
{{#if CAN.READ_REVISIONS}}
|
{{#if CAN.READ_REVISIONS}}
|
||||||
<li><a href="{{wiki_page_history_path}}" class="icon-clock view_page_history">{{#t "view_page_history_wiki"}}View Page History{{/t}}</a></li>
|
<li><a href="{{wiki_page_history_path}}" class="icon-clock view_page_history">{{#t "view_page_history_wiki"}}View Page History{{/t}}</a></li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
<span class="screenreader-only">{{#t 'menu.settings'}}Settings{{/t}}</span>
|
<span class="screenreader-only">{{#t 'menu.settings'}}Settings{{/t}}</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="al-options">
|
<ul class="al-options">
|
||||||
<li><a href="#" class="icon-edit edit-menu-item" title="{{#t 'menu.edit'}}Edit{{/t}}">{{#t 'menu.edit'}}Edit{{/t}}</a></li>
|
{{#unless restricted_by_master_course}}
|
||||||
<li><a href="#" class="icon-trash delete-menu-item{{#unless deletable}} disabled{{/unless}}" title="{{#t 'menu.delete'}}Delete{{/t}}" {{#unless deletable}}aria-disabled="true"{{/unless}}>{{#t 'menu.delete'}}Delete{{/t}}</a></li>
|
<li><a href="#" class="icon-edit edit-menu-item" title="{{#t 'menu.edit'}}Edit{{/t}}">{{#t 'menu.edit'}}Edit{{/t}}</a></li>
|
||||||
|
<li><a href="#" class="icon-trash delete-menu-item{{#unless deletable}} disabled{{/unless}}" title="{{#t 'menu.delete'}}Delete{{/t}}" {{#unless deletable}}aria-disabled="true"{{/unless}}>{{#t 'menu.delete'}}Delete{{/t}}</a></li>
|
||||||
|
{{/unless}}
|
||||||
{{#unless front_page}}
|
{{#unless front_page}}
|
||||||
<li><a href="#" class="icon-document use-as-front-page-menu-item{{#unless published}} disabled{{/unless}}" title="{{#t 'menu.use_front_page'}}Use as Front Page{{/t}}" {{#unless published}}aria-disabled="true"{{/unless}}>{{#t 'menu.use_front_page'}}Use as Front Page{{/t}}</a></li>
|
<li><a href="#" class="icon-document use-as-front-page-menu-item{{#unless published}} disabled{{/unless}}" title="{{#t 'menu.use_front_page'}}Use as Front Page{{/t}}" {{#unless published}}aria-disabled="true"{{/unless}}>{{#t 'menu.use_front_page'}}Use as Front Page{{/t}}</a></li>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
|
@ -49,11 +49,14 @@ module Api::V1::WikiPage
|
||||||
hash['body'] = api_user_content(wiki_page.body)
|
hash['body'] = api_user_content(wiki_page.body)
|
||||||
wiki_page.increment_view_count(current_user, wiki_page.context)
|
wiki_page.increment_view_count(current_user, wiki_page.context)
|
||||||
end
|
end
|
||||||
|
if opts[:include_master_course_restrictions]
|
||||||
|
hash['restricted_by_master_course'] = wiki_page.editing_restricted?
|
||||||
|
end
|
||||||
hash
|
hash
|
||||||
end
|
end
|
||||||
|
|
||||||
def wiki_pages_json(wiki_pages, current_user, session)
|
def wiki_pages_json(wiki_pages, current_user, session, opts={})
|
||||||
wiki_pages.map { |page| wiki_page_json(page, current_user, session, false) }
|
wiki_pages.map { |page| wiki_page_json(page, current_user, session, false, opts) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def wiki_page_revision_json(version, current_user, current_session, include_content = true, latest_version = nil)
|
def wiki_page_revision_json(version, current_user, current_session, include_content = true, latest_version = nil)
|
||||||
|
|
|
@ -479,8 +479,8 @@ END
|
||||||
},
|
},
|
||||||
'master_courses' =>
|
'master_courses' =>
|
||||||
{
|
{
|
||||||
display_name: -> { I18n.t('Master Courses') },
|
display_name: -> { I18n.t('Blueprint Courses') }, # this won't be confusing at all
|
||||||
description: -> { I18n.t('Enable the creation of Master Courses') },
|
description: -> { I18n.t('Enable the creation of Blueprint Courses') },
|
||||||
applies_to: 'RootAccount',
|
applies_to: 'RootAccount',
|
||||||
state: 'hidden',
|
state: 'hidden',
|
||||||
beta: true,
|
beta: true,
|
||||||
|
|
|
@ -59,15 +59,7 @@ describe MasterCourses::CollectionRestrictor do
|
||||||
expect(@aq.editing_restricted?(:content)).to be_truthy
|
expect(@aq.editing_restricted?(:content)).to be_truthy
|
||||||
expect(@aq.editing_restricted?(:settings)).to be_falsey
|
expect(@aq.editing_restricted?(:settings)).to be_falsey
|
||||||
expect(@aq.editing_restricted?(:any)).to be_truthy
|
expect(@aq.editing_restricted?(:any)).to be_truthy
|
||||||
expect(@aq.editing_restricted?(:all)).to be_falsey
|
expect(@aq.editing_restricted?(:all)).to be_truthy # in retrospect - if we're only classifying content as restricted then this should probably be true
|
||||||
end
|
|
||||||
|
|
||||||
it "should return true if fully locked" do
|
|
||||||
@tag.update_attribute(:restrictions, {:content => true, :settings => true})
|
|
||||||
expect(@aq.editing_restricted?(:content)).to be_truthy
|
|
||||||
expect(@aq.editing_restricted?(:settings)).to be_truthy
|
|
||||||
expect(@aq.editing_restricted?(:any)).to be_truthy
|
|
||||||
expect(@aq.editing_restricted?(:all)).to be_truthy
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
require_relative '../common'
|
||||||
|
|
||||||
|
describe "master courses - child courses - wiki page locking" do
|
||||||
|
include_context "in-process server selenium tests"
|
||||||
|
|
||||||
|
before :once do
|
||||||
|
Account.default.enable_feature!(:master_courses)
|
||||||
|
|
||||||
|
@copy_from = course_factory(:active_all => true)
|
||||||
|
@template = MasterCourses::MasterTemplate.set_as_master_course(@copy_from)
|
||||||
|
@original_page = @copy_from.wiki.wiki_pages.create!(:title => "blah", :body => "bloo")
|
||||||
|
@tag = @template.create_content_tag_for!(@original_page)
|
||||||
|
|
||||||
|
course_with_teacher(:active_all => true)
|
||||||
|
@copy_to = @course
|
||||||
|
@page_copy = @copy_to.wiki.wiki_pages.new(:title => "blah", :body => "bloo") # just create a copy directly instead of doing a real migraiton
|
||||||
|
@page_copy.migration_id = @tag.migration_id
|
||||||
|
@page_copy.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
user_session(@teacher)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not show the edit/delete cog-menu options on the index when locked" do
|
||||||
|
@tag.update_attribute(:restrictions, {:content => true, :settings => true})
|
||||||
|
|
||||||
|
get "/courses/#{@copy_to.id}/pages"
|
||||||
|
|
||||||
|
f('.al-trigger').click
|
||||||
|
expect(f('.al-options')).to_not contain_css('.edit-menu-item')
|
||||||
|
expect(f('.al-options')).to_not contain_css('.delete-menu-item')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should show the edit/delete cog-menu options on the index when not locked" do
|
||||||
|
get "/courses/#{@copy_to.id}/pages"
|
||||||
|
|
||||||
|
f('.al-trigger').click
|
||||||
|
expect(f('.al-options')).to contain_css('.edit-menu-item')
|
||||||
|
expect(f('.al-options')).to contain_css('.delete-menu-item')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not show the edit/delete options on the show page when locked" do
|
||||||
|
@tag.update_attribute(:restrictions, {:content => true, :settings => true})
|
||||||
|
|
||||||
|
get "/courses/#{@copy_to.id}/pages/#{@page_copy.url}"
|
||||||
|
|
||||||
|
expect(f('#content')).to_not contain_css('.edit-wiki')
|
||||||
|
f('.al-trigger').click
|
||||||
|
expect(f('.al-options')).to_not contain_css('.delete_page')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should show the edit/delete cog-menu options on the index when not locked" do
|
||||||
|
get "/courses/#{@copy_to.id}/pages/#{@page_copy.url}"
|
||||||
|
|
||||||
|
expect(f('#content')).to contain_css('.edit-wiki')
|
||||||
|
f('.al-trigger').click
|
||||||
|
expect(f('.al-options')).to contain_css('.delete_page')
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue