Fix homeroom courses having annoucements mistakenly hidden

Fixes: LS-2507
flag=none

test plan:
- With a k5 account, create a role without :read_announcements permission

- Have 2 courses (say A and B)  with announcements

- Enroll the teacher into course A using the default teacher role

- Enroll the teacher into course B using the role you created.

- Make course A a homeroom course.

- Favorite both courses

- Visit the homeroom page as the teacher

- Check that the announcements for course A are shown

- Check that the announcements for course B are hidden

Change-Id: Ic02a35abd5afda0ba17b6408dd01328a59b8428b
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/271572
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Reviewed-by: Ed Schiebel <eschiebel@instructure.com>
QA-Review: Ed Schiebel <eschiebel@instructure.com>
Product-Review: Luis Oliveira <luis.oliveira@instructure.com>
This commit is contained in:
Math Costa 2021-08-17 00:32:17 -03:00 committed by Luis Oliveira
parent 6f849ee3ca
commit c58d0cc0af
18 changed files with 218 additions and 149 deletions

View File

@ -88,7 +88,6 @@ class AnnouncementsApiController < ApplicationController
# @returns [DiscussionTopic]
def index
courses = api_find_all(Course, @course_ids)
return unless courses.all? { |course| authorized_action(course, @current_user, :read_announcements) }
scope = Announcement.where(:context_type => 'Course', :context_id => courses)

View File

@ -509,6 +509,14 @@ class AssignmentsController < ApplicationController
rce_js_env
add_crumb @context.elementary_enabled? ? t("Important Info") : t('#crumbs.syllabus', "Syllabus")
active_tab = "Syllabus"
@course_home_sub_navigation_tools =
ContextExternalTool.all_tools_for(@context, placements: :course_home_sub_navigation,
root_account: @domain_root_account, current_user: @current_user).to_a
unless @context.grants_right?(@current_user, session, :manage_content)
@course_home_sub_navigation_tools.reject! {|tool| tool.course_home_sub_navigation(:visibility) == 'admins'}
end
if authorized_action(@context, @current_user, [:read, :read_syllabus])
return unless tab_enabled?(@context.class::TAB_SYLLABUS)
@groups = @context.assignment_groups.active.order(

View File

@ -2104,6 +2104,7 @@ class CoursesController < ApplicationController
@course_home_view ||= default_view
@course_home_view = "k5_dashboard" if @context.elementary_subject_course?
@course_home_view = "announcements" if @context.elementary_homeroom_course?
@course_home_view = "syllabus" if @context.elementary_homeroom_course? && !@context.grants_right?(@current_user, session, :read_announcements)
course_env_variables = {}
# env.COURSE variables that apply to both classic and k5 courses
@ -2163,7 +2164,7 @@ class CoursesController < ApplicationController
when 'syllabus'
set_active_tab "syllabus"
rce_js_env
add_crumb(t('#crumbs.syllabus', "Syllabus"))
add_crumb @context.elementary_enabled? ? t("Important Info") : t('#crumbs.syllabus', "Syllabus")
@groups = @context.assignment_groups.active.order(
:position,
AssignmentGroup.best_unicode_collation_key('name')
@ -2234,7 +2235,8 @@ class CoursesController < ApplicationController
CONTEXT_MODULE_ASSIGNMENT_INFO_URL: context_url(@context, :context_context_modules_assignment_info_url),
PERMISSIONS: {
manage: @context.grants_right?(@current_user, session, :manage),
read_as_admin: @context.grants_right?(@current_user, session, :read_as_admin)
read_as_admin: @context.grants_right?(@current_user, session, :read_as_admin),
read_announcements: @context.grants_right?(@current_user, session, :read_announcements)
},
STUDENT_PLANNER_ENABLED: planner_enabled?,
TABS: @context.tabs_available(@current_user, course_subject_tabs: true),

View File

@ -59,6 +59,7 @@ class CourseForMenuPresenter
isK5Subject: course.elementary_subject_course?,
isHomeroom: course.homeroom_course,
canManage: course.grants_right?(@user, :manage_content),
canReadAnnouncements: course.grants_right?(@user, :read_announcements),
image: course.image,
color: course.elementary_enabled? ? course.course_color : nil,
position: position.present? ? position.to_i : nil,

View File

@ -28,8 +28,12 @@
<%= page_title %>
<% end %>
<% unless @context.elementary_enabled? %>
<% provide :right_side do %>
<% provide :right_side do %>
<% if @context.elementary_homeroom_course? && !@context.grants_right?(@current_user, session, :read_announcements) # Sylalbus is serving as course_home %>
<%= render :partial => '/courses/course_show_secondary' %>
<% end %>
<% unless @context.elementary_enabled? %>
<%= render :partial => 'assignments/syllabus_right_side' %>
<% end %>
<% end %>

View File

@ -0,0 +1,126 @@
<div id="course_show_secondary">
<% @can_manage = can_do(@context, @current_user, :manage) %>
<% @can_create_announcements = @context.announcements.temp_record.grants_right?(@current_user, session, :create) %>
<% if can_do(@context, @current_user, :change_course_state, :manage_courses_publish) && (@context.unpublished? || @context.unpublishable?) %>
<div id="course_status">
<h3>
<%= t('headers.course_status', %{Course Status}) %>
</h3>
<%= render :partial => '/courses/publish_buttons', :locals => {redirect_to_settings: false} %>
</div>
<% end %>
<% if can_do(@context, @current_user, :manage_content) %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :context_content_migrations_url) %>">
<i class="icon-import"></i>
<%= t('links.import', %{Import Existing Content}) %>
</a>
<% end %>
<% if @can_manage || @can_create_announcements || @course_home_view != 'feed' || @course_home_sub_navigation_tools.present? %>
<div class="course-options">
<%= external_tools_menu_items(@course_home_sub_navigation_tools, {link_class: "btn button-sidebar-wide course-home-sub-navigation-lti", settings_key: :course_home_sub_navigation}) %>
<% if @can_manage && !@context.elementary_homeroom_course? %>
<div id="choose_home_page"></div>
<div id="choose_home_page_not_modules"></div>
<% end %>
<% if @course_home_view != 'feed' && !@context.elementary_homeroom_course? %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :context_url, :view => 'feed') %>">
<i class="icon-stats"></i>
<%= t('links.view_course_stream', %{View Course Stream}) %>
</a>
<% end %>
<% if @can_manage && !@domain_root_account.try(:feature_enabled?, :new_user_tutorial) && !@context.elementary_homeroom_course? %>
<script>
Object.assign(
ENV,
<%= raw StringifyIds.recursively_stringify_ids({
COURSE_WIZARD: {
just_saved: @context_just_saved,
checklist_states: {
import_step: !@context.attachments.active.exists?,
assignment_step: !@context.assignments.active.exists?,
add_student_step: !@context.students.exists?,
navigation_step: @context.tab_configuration.empty?,
home_page_step: true,
# The current wizard just always marks this as complete.
calendar_event_step: !@context.calendar_events.active.exists?,
add_ta_step: !@context.tas.exists?,
publish_step: @context.workflow_state === 'available'
},
urls: {
content_import: context_url(@context, :context_content_migrations_url),
add_assignments: context_url(@context, :context_assignments_url, wizard: 1),
add_students: course_users_path(course_id: @context),
add_files: context_url(@context, :context_files_url, wizard: 1),
select_navigation: context_url(@context, :context_details_url),
course_calendar: calendar_path(course_id: @context),
add_tas: course_users_path(course_id: @context),
publish_course: course_path(@context)
},
permissions: {
can_change_course_publish_state: can_do(@context, @current_user, :change_course_state, :manage_courses_publish)
}
}
}).to_json %>
)
</script>
<% js_bundle :course_wizard %>
<% css_bundle :course_wizard %>
<a href="#" class="btn button-sidebar-wide wizard_popup_link <%= 'auto_open' if @context.created? || @context.claimed? %>">
<i class="icon-question"></i> <%= t('links.course_setup', %{Course Setup Checklist}) %>
</a>
<% end %>
<% if @can_create_announcements && !@context.elementary_homeroom_course? %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :new_context_discussion_topic_url, :is_announcement => true) %>"><i class="icon-announcement"></i> <%= t('links.new_announcement', %{New Announcement}) %>
</a>
<% end %>
<% course_custom_links.each do |link| %>
<a class="btn button-sidebar-wide" href="<%= link[:url] %>"><i class="<%= link[:icon_class] %>" role="presentation"></i> <%= link[:text] %></a>
<% end %>
</div>
<% end %>
<% if @context.available? && @context.self_enrollment_enabled? && @context.open_enrollment && (!@context_enrollment || !@context_enrollment.active?) %>
<a href="<%= enroll_url(@context.self_enrollment_code) %>" class="btn button-sidebar-wide self_enrollment_link">
<i class="icon-user-add"></i>
<%= t('links.join_course', %{Join this Course}) %>
</a>
<% elsif @context_enrollment && @context_enrollment.self_enrolled && @context_enrollment.active? %>
<a href="#" class="btn button-sidebar-wide self_unenrollment_link">
<i class="icon-end"></i>
<%= t('links.drop_course', %{Drop this Course}) %>
</a>
<div id="self_unenrollment_dialog" style="display: none;">
<h2><i class="icon-warning"></i> <%= t('headings.confirm_unenroll', %{Confirm Unenrollment}) %></h2>
<%= t('details.confirm_unenroll', %{Are you sure you want to unenroll in this course? You will no longer be able to see the course roster or communicate directly with the teachers, and you will no longer see course events in your stream and as notifications.}) %>
<div class="button-container">
<a href="<%= course_self_unenrollment_path(@context, @context_enrollment.uuid) %>" class="btn btn-primary action"><i class="icon-end"></i> <span><%= t('links.drop_course', %{Drop this Course}) %></span></a>
<a href="#" class="btn dialog_closer"><%= t('#buttons.cancel', %{Cancel}) %></a>
</div>
</div>
<% end %>
<% if @context_enrollment&.student? %>
<a class="btn button-sidebar-wide" href="<%= calendar_url_for(@context) %>">
<i class="icon-calendar-day"></i>
<%= t('links.view_course_calendar', %{View Course Calendar}) %>
</a>
<% end %>
<% if @context_enrollment %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :context_url, :view => 'notifications') %>">
<i class="icon-<%= @course_notifications_enabled ? "unmuted" : "muted" %>"></i>
<%= t('links.view_course_notification_settings', %{View Course Notifications}) %>
</a>
<% end %>
<%= render :partial => '/courses/to_do_list', :locals => {:contexts => [@context], :show_legacy_todo_list => !@context_enrollment&.student?} %>
<%= render :partial => "/courses/group_list", :locals => {:group_list => @user_groups} %>
<%= nbsp unless @current_user %>
</div>

View File

@ -22,135 +22,10 @@
<% unless @context.elementary_subject_course? %>
<% provide :right_side do %>
<div id="course_show_secondary">
<% @can_manage = can_do(@context, @current_user, :manage) %>
<% @can_create_announcements = @context.announcements.temp_record.grants_right?(@current_user, session, :create) %>
<% if can_do(@context, @current_user, :change_course_state, :manage_courses_publish) && (@context.unpublished? || @context.unpublishable?) %>
<div id="course_status">
<h3>
<%= t('headers.course_status', %{Course Status}) %>
</h3>
<%= render :partial => 'publish_buttons', :locals => {redirect_to_settings: false} %>
</div>
<% end %>
<% if can_do(@context, @current_user, :manage_content) %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :context_content_migrations_url) %>">
<i class="icon-import"></i>
<%= t('links.import', %{Import Existing Content}) %>
</a>
<% end %>
<% if @can_manage || @can_create_announcements || @course_home_view != 'feed' || @course_home_sub_navigation_tools.present? %>
<div class="course-options">
<%= external_tools_menu_items(@course_home_sub_navigation_tools, {link_class: "btn button-sidebar-wide course-home-sub-navigation-lti", settings_key: :course_home_sub_navigation}) %>
<% if @can_manage && !@context.elementary_homeroom_course? %>
<div id="choose_home_page"></div>
<div id="choose_home_page_not_modules"></div>
<% end %>
<% if @course_home_view != 'feed' && !@context.elementary_homeroom_course? %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :context_url, :view => 'feed') %>">
<i class="icon-stats"></i>
<%= t('links.view_course_stream', %{View Course Stream}) %>
</a>
<% end %>
<% if @can_manage && !@domain_root_account.try(:feature_enabled?, :new_user_tutorial) && !@context.elementary_homeroom_course? %>
<script>
Object.assign(
ENV,
<%= raw StringifyIds.recursively_stringify_ids({
COURSE_WIZARD: {
just_saved: @context_just_saved,
checklist_states: {
import_step: !@context.attachments.active.exists?,
assignment_step: !@context.assignments.active.exists?,
add_student_step: !@context.students.exists?,
navigation_step: @context.tab_configuration.empty?,
home_page_step: true,
# The current wizard just always marks this as complete.
calendar_event_step: !@context.calendar_events.active.exists?,
add_ta_step: !@context.tas.exists?,
publish_step: @context.workflow_state === 'available'
},
urls: {
content_import: context_url(@context, :context_content_migrations_url),
add_assignments: context_url(@context, :context_assignments_url, wizard: 1),
add_students: course_users_path(course_id: @context),
add_files: context_url(@context, :context_files_url, wizard: 1),
select_navigation: context_url(@context, :context_details_url),
course_calendar: calendar_path(course_id: @context),
add_tas: course_users_path(course_id: @context),
publish_course: course_path(@context)
},
permissions: {
can_change_course_publish_state: can_do(@context, @current_user, :change_course_state, :manage_courses_publish)
}
}
}).to_json %>
)
</script>
<% js_bundle :course_wizard %>
<% css_bundle :course_wizard %>
<a href="#" class="btn button-sidebar-wide wizard_popup_link <%= 'auto_open' if @context.created? || @context.claimed? %>">
<i class="icon-question"></i> <%= t('links.course_setup', %{Course Setup Checklist}) %>
</a>
<% end %>
<% if @can_create_announcements && !@context.elementary_homeroom_course? %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :new_context_discussion_topic_url, :is_announcement => true) %>"><i class="icon-announcement"></i> <%= t('links.new_announcement', %{New Announcement}) %>
</a>
<% end %>
<% course_custom_links.each do |link| %>
<a class="btn button-sidebar-wide" href="<%= link[:url] %>"><i class="<%= link[:icon_class] %>" role="presentation"></i> <%= link[:text] %></a>
<% end %>
</div>
<% end %>
<% if @context.available? && @context.self_enrollment_enabled? && @context.open_enrollment && (!@context_enrollment || !@context_enrollment.active?) %>
<a href="<%= enroll_url(@context.self_enrollment_code) %>" class="btn button-sidebar-wide self_enrollment_link">
<i class="icon-user-add"></i>
<%= t('links.join_course', %{Join this Course}) %>
</a>
<% elsif @context_enrollment && @context_enrollment.self_enrolled && @context_enrollment.active? %>
<a href="#" class="btn button-sidebar-wide self_unenrollment_link">
<i class="icon-end"></i>
<%= t('links.drop_course', %{Drop this Course}) %>
</a>
<div id="self_unenrollment_dialog" style="display: none;">
<h2><i class="icon-warning"></i> <%= t('headings.confirm_unenroll', %{Confirm Unenrollment}) %></h2>
<%= t('details.confirm_unenroll', %{Are you sure you want to unenroll in this course? You will no longer be able to see the course roster or communicate directly with the teachers, and you will no longer see course events in your stream and as notifications.}) %>
<div class="button-container">
<a href="<%= course_self_unenrollment_path(@context, @context_enrollment.uuid) %>" class="btn btn-primary action"><i class="icon-end"></i> <span><%= t('links.drop_course', %{Drop this Course}) %></span></a>
<a href="#" class="btn dialog_closer"><%= t('#buttons.cancel', %{Cancel}) %></a>
</div>
</div>
<% end %>
<% if @context_enrollment&.student? %>
<a class="btn button-sidebar-wide" href="<%= calendar_url_for(@context) %>">
<i class="icon-calendar-day"></i>
<%= t('links.view_course_calendar', %{View Course Calendar}) %>
</a>
<% end %>
<% if @context_enrollment %>
<a class="btn button-sidebar-wide" href="<%= context_url(@context, :context_url, :view => 'notifications') %>">
<i class="icon-<%= @course_notifications_enabled ? "unmuted" : "muted" %>"></i>
<%= t('links.view_course_notification_settings', %{View Course Notifications}) %>
</a>
<% end %>
<%= render :partial => 'to_do_list', :locals => {:contexts => [@context], :show_legacy_todo_list => !@context_enrollment&.student?} %>
<%= render :partial => "group_list", :locals => {:group_list => @user_groups} %>
<%= nbsp unless @current_user %>
</div>
<%= render :partial => 'courses/course_show_secondary' %>
<% if @course_home_view == 'assignments' %>
<%= render :partial => 'assignments/assignments_list_right_side', :locals => {:course_home => true} %>
<% elsif @course_home_view == 'syllabus' %>
<% elsif @course_home_view == 'syllabus' && !@context.elementary_enabled? %>
<%= render :partial => 'assignments/syllabus_right_side', :locals => {:course_home => true} %>
<% elsif @context.elementary_homeroom_course? %>
<% elsif !@context_enrollment&.student? %>
@ -188,9 +63,9 @@
<% elsif @course_home_view == 'modules' %>
<%= render :partial => 'context_modules/content_next', :locals => {:course_home => true} %>
<% elsif @course_home_view == 'assignments' %>
<% elsif @context.elementary_homeroom_course? %>
<% elsif @course_home_view == 'syllabus' %>
<%= render :partial => 'assignments/syllabus_content', :locals => {:course_home => true} %>
<% elsif @context.elementary_homeroom_course? %>
<% elsif @course_home_view == 'k5_dashboard' %>
<div id="course-dashboard-container"></div>
<div id="k5-modules-container" style="display: none; padding-top: 17px;">

View File

@ -65,11 +65,21 @@ describe "Announcements API", type: :request do
expect(json['message']).to include 'Invalid context_codes'
end
it "requires :read_announcements permission on all courses" do
random_course = Course.create!
api_call_as_user(@teacher, :get, "/api/v1/announcements",
@params.merge(:context_codes => [ "course_#{@course1.id}", "course_#{random_course.id}" ]),
{}, {}, { :expected_status => 401 })
it "filters out announcements with :read_announcements permission lacking" do
@account = Account.default
custom_role = custom_teacher_role('No Announcement Viewing')
@account.role_overrides.create!(role: custom_role, enabled: false, permission: :read_announcements)
course_with_teacher(active_all: true, user: @teacher, role: custom_role)
@other_course = @course
@other_course.announcements.create :title => "Announcement That Should Be Filtered", :message => '1'
context_codes = ["course_#{@course1.id}", "course_#{@course2.id}", "course_#{@other_course.id}"]
json = api_call_as_user @teacher, :get, "/api/v1/announcements",
@params.merge(:context_codes => context_codes), {}, {},
{ :expected_status => 200 }
expect(json.length).to eq 6
end
it "returns announcements for the the surrounding 14 days by default" do

View File

@ -1658,7 +1658,7 @@ describe CoursesController do
user_session(@teacher)
get 'show', params: {:id => @course.id}
expect(assigns[:js_env][:PERMISSIONS]).to eq({manage: true, read_as_admin: true})
expect(assigns[:js_env][:PERMISSIONS]).to eq({manage: true, read_announcements: true, read_as_admin: true})
end
it "sets COURSE.color appropriately in js_env" do
@ -1681,6 +1681,17 @@ describe CoursesController do
expect(bundle.size).to eq 1
end
it "sets the course_home_view to 'Important Info' if the teacher has no announcement reading permission for the homeroom" do
@course.homeroom_course = true
@course.save!
@course.account.role_overrides.create!(permission: :read_announcements, role: teacher_role, enabled: false)
user_session(@teacher)
get 'show', params: {:id => @course.id}
expect(assigns[:course_home_view]).to eq 'syllabus'
end
it "sets COURSE.has_syllabus_body to true when syllabus exists" do
@course.syllabus_body = "Welcome"
@course.save!

View File

@ -30,6 +30,7 @@ ready(() => {
<K5Course
canManage={ENV.PERMISSIONS.manage}
canReadAsAdmin={ENV.PERMISSIONS.read_as_admin}
canReadAnnouncements={ENV.PERMISSIONS.read_announcements}
currentUser={ENV.current_user}
id={ENV.COURSE.id}
bannerImageUrl={ENV.COURSE.banner_image_url}

View File

@ -280,6 +280,7 @@ export function K5Course({
timeZone,
canManage = false,
canReadAsAdmin,
canReadAnnouncements,
plannerEnabled = false,
hideFinalGrades,
currentUser,
@ -422,7 +423,8 @@ export function K5Course({
id,
shortName: name,
href: `/courses/${id}`,
canManage
canManage,
canReadAnnouncements
})
return (
@ -500,6 +502,7 @@ K5Course.propTypes = {
cardImageUrl: PropTypes.string,
canManage: PropTypes.bool,
canReadAsAdmin: PropTypes.bool.isRequired,
canReadAnnouncements: PropTypes.bool.isRequired,
color: PropTypes.string,
defaultTab: PropTypes.string,
plannerEnabled: PropTypes.bool,

View File

@ -44,6 +44,7 @@ export default function HomeroomAnnouncementsLayout({homeroomAnnouncements, load
courseName={homeroom.courseName}
courseUrl={homeroom.courseUrl}
canEdit={homeroom.canEdit}
canReadAnnouncements={homeroom.canReadAnnouncements}
published={homeroom.published}
showCourseDetails
firstAnnouncement={homeroom.announcement}

View File

@ -26,6 +26,7 @@ const homeroomAnnouncements = [
courseName: 'Homeroom - Mr. Jessie',
courseUrl: 'http://google.com/course',
canEdit: true,
canReadAnnouncements: true,
announcement: {
title: 'Welcome to Class!',
message: '<p>Yayyyy</p>',
@ -43,6 +44,7 @@ const homeroomAnnouncements = [
courseName: 'Homeroom 0144232',
courseUrl: 'http://google.com/course2',
canEdit: true,
canReadAnnouncements: true,
announcement: {
title: 'Sign the permission slip!',
message: '<p>Hello</p>',
@ -55,6 +57,7 @@ const homeroomAnnouncements = [
courseName: 'New Homeroom',
courseUrl: 'http://google.com',
canEdit: true,
canReadAnnouncements: true,
published: true
}
]
@ -86,7 +89,8 @@ describe('HomeroomAnnouncementsLayout', () => {
courseId: 1236,
courseName: 'New Homeroom',
courseUrl: 'http://google.com',
canEdit: true
canEdit: true,
canReadAnnouncements: true
}
]
})}
@ -107,7 +111,8 @@ describe('HomeroomAnnouncementsLayout', () => {
courseId: 1236,
courseName: 'New Homeroom',
courseUrl: 'http://google.com',
canEdit: false
canEdit: false,
canReadAnnouncements: true
}
]
})}

View File

@ -18,7 +18,7 @@
import I18n from 'i18n!empty_homeroom_announcement'
import React from 'react'
import {string} from 'prop-types'
import {string, bool} from 'prop-types'
import {View} from '@instructure/ui-view'
import {Heading} from '@instructure/ui-heading'
import {Link} from '@instructure/ui-link'
@ -45,7 +45,7 @@ K5AddAnnouncementButton.propTypes = {
courseName: string.isRequired
}
export default function EmptyK5Announcement({courseUrl, courseName}) {
export default function EmptyK5Announcement({courseUrl, courseName, canReadAnnouncements}) {
return (
<View>
<Heading level="h3" as="h2" margin="medium 0 small">
@ -54,9 +54,13 @@ export default function EmptyK5Announcement({courseUrl, courseName}) {
</Link>
</Heading>
<Text as="div">
{I18n.t('New announcements show up in this area. Create a new announcement now.')}
{canReadAnnouncements
? I18n.t('New announcements show up in this area. Create a new announcement now.')
: I18n.t('You do not have permission to view announcements in this course.')}
</Text>
<K5AddAnnouncementButton courseUrl={courseUrl} courseName={courseName} />
{canReadAnnouncements && (
<K5AddAnnouncementButton courseUrl={courseUrl} courseName={courseName} />
)}
<PresentationContent>
<hr />
</PresentationContent>
@ -66,5 +70,6 @@ export default function EmptyK5Announcement({courseUrl, courseName}) {
EmptyK5Announcement.propTypes = {
courseUrl: string.isRequired,
courseName: string.isRequired
courseName: string.isRequired,
canReadAnnouncements: bool.isRequired
}

View File

@ -77,6 +77,7 @@ export default function K5Announcement({
courseUrl,
published,
canEdit,
canReadAnnouncements,
showCourseDetails,
firstAnnouncement
}) {
@ -323,7 +324,7 @@ export default function K5Announcement({
<Text data-testid="no-recent-announcements" color="secondary" size="large">
{I18n.t('No recent announcements')}
</Text>
{canEdit && (
{canEdit && canReadAnnouncements && (
<View as="div">
<K5AddAnnouncementButton courseName={courseName} courseUrl={courseUrl} />
</View>
@ -363,7 +364,13 @@ export default function K5Announcement({
// if there are no announcements at all, show teachers something
if (canEdit && noAnnouncementsAtAll()) {
return <EmptyK5Announcement courseUrl={courseUrl} courseName={courseName} />
return (
<EmptyK5Announcement
courseUrl={courseUrl}
courseName={courseName}
canReadAnnouncements={canReadAnnouncements}
/>
)
}
return (
@ -410,6 +417,7 @@ K5Announcement.propTypes = {
courseUrl: PropTypes.string,
published: PropTypes.bool,
canEdit: PropTypes.bool.isRequired,
canReadAnnouncements: PropTypes.bool.isRequired,
showCourseDetails: PropTypes.bool.isRequired,
// announcement
firstAnnouncement: K5AnnouncementType

View File

@ -24,6 +24,7 @@ describe('EmptyK5Announcement', () => {
const getProps = (overrides = {}) => ({
courseName: "Mr. Smith's Homeroom 2",
courseUrl: 'http://google.com/courseurl2',
canReadAnnouncements: true,
...overrides
})
@ -41,6 +42,13 @@ describe('EmptyK5Announcement', () => {
).toBeInTheDocument()
})
it('shows permission related text when applicable', () => {
const {getByText} = render(<EmptyK5Announcement {...getProps({canReadAnnouncements: false})} />)
expect(
getByText('You do not have permission to view announcements in this course.')
).toBeInTheDocument()
})
it('shows a button to create a new announcement with correct url', () => {
const {getByRole} = render(<EmptyK5Announcement {...getProps()} />)
const button = getByRole('link', {name: "Create a new announcement for Mr. Smith's Homeroom 2"})

View File

@ -28,6 +28,7 @@ describe('K5Announcement', () => {
courseName: "Mrs. Jensen's Homeroom",
courseUrl: 'http://google.com/courseurl',
canEdit: true,
canReadAnnouncements: true,
published: true,
showCourseDetails: true,
...overrides

View File

@ -282,6 +282,7 @@ export const parseAnnouncementDetails = (announcement, course) => {
courseName: course.shortName,
courseUrl: course.href,
canEdit: course.canManage,
canReadAnnouncements: course.canReadAnnouncements,
published: course.published
}
if (announcement) {