diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb
index dfb8d9fafd..84bf9fb2b9 100644
--- a/app/controllers/courses_controller.rb
+++ b/app/controllers/courses_controller.rb
@@ -47,6 +47,13 @@ def show
redirect_unless_secret_correct
return if performed?
end
+ if current_user&.course_admin?(@course) && !@course.all_activities_accessible?
+ flash.now[:alert] = I18n.t('courses.show.has_private_exercises')
+ flash.now[:extra] = {
+ 'message' => I18n.t('courses.show.has_private_help'),
+ 'url' => contact_url
+ }
+ end
@title = @course.name
@series = policy_scope(@course.series).includes(:evaluation)
@series_loaded = params[:secret].present? ? @course.series.count : 2
@@ -134,7 +141,6 @@ def create
respond_to do |format|
if @course.save
- flash[:alert] = I18n.t('courses.create.added_private_exercises') unless @course.exercises.where(access: :private).count.zero?
@course.administrating_members << current_user unless @course.administrating_members.include?(current_user)
format.html { redirect_to @course, notice: I18n.t('controllers.created', model: Course.model_name.human) }
format.json { render :show, status: :created, location: @course }
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index cb474ba282..095bf7e834 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -197,12 +197,12 @@ def model_update_response(success, model, return_path)
toast = t('controllers.updated', model: model.model_name.human)
format.json { head :no_content }
format.js { render locals: { toast: toast } }
- format.html { redirect_to return_path, notice: toast }
+ format.html { redirect_back fallback_location: return_path, notice: toast }
else
alert = t('controllers.update_failed', model: model.model_name.human)
format.json { head :unprocessable_entity }
format.js { render status: :bad_request, locals: { toast: alert } }
- format.html { redirect_to return_path, alert: alert }
+ format.html { redirect_back fallback_location: return_path, alert: alert }
end
end
end
diff --git a/app/models/activity.rb b/app/models/activity.rb
index 8a640304e4..d73fefe262 100644
--- a/app/models/activity.rb
+++ b/app/models/activity.rb
@@ -264,7 +264,6 @@ def accessible?(user, course)
else
return false unless course.visible_activities.pluck(:id).include? id
end
- return true if user&.repository_admin? repository
return false unless access_public? \
|| repository.allowed_courses.pluck(:id).include?(course&.id)
return true if user&.member_of? course
diff --git a/app/models/course.rb b/app/models/course.rb
index a98676dea3..eb98f95db0 100644
--- a/app/models/course.rb
+++ b/app/models/course.rb
@@ -211,6 +211,10 @@ def secret_required?(user = nil)
true
end
+ def all_activities_accessible?
+ activities.where(access: :private).where.not(repository_id: usable_repositories).count.zero?
+ end
+
def invalidate_subscribed_members_count_cache
Rails.cache.delete(format(SUBSCRIBED_MEMBERS_COUNT_CACHE_STRING, id: id))
end
diff --git a/app/views/activities/_series_activities_table.html.erb b/app/views/activities/_series_activities_table.html.erb
index 98816c6af0..47aba42e1c 100644
--- a/app/views/activities/_series_activities_table.html.erb
+++ b/app/views/activities/_series_activities_table.html.erb
@@ -60,6 +60,16 @@
<%= link_to activity.name, activity_path(activity) %>
<% else %>
<%= activity.name %>
+ <% if current_user.course_admin?(@course) && current_user.repository_admin?(activity.repository) %>
+ <%= form_with url: add_course_repository_path(activity.repository) do |form| %>
+ <%= form.hidden_field :course_id, value: @course.id %>
+
+ <% end %>
+ <% elsif current_user.course_admin?(@course) %>
+ " data-bs-toggle="tooltip" data-bs-placement="right">
+ <% end %>
<% end %>
diff --git a/config/locales/views/activities/en.yml b/config/locales/views/activities/en.yml
index 589e93b85c..775ef89520 100644
--- a/config/locales/views/activities/en.yml
+++ b/config/locales/views/activities/en.yml
@@ -117,3 +117,6 @@ en:
config_info: 'Take a look at the %{doc_site} for more information about configuring exercises.'
doc_site: 'documentation site'
activity_invalid: This exercise's configuration is invalid.
+ series_activities_table:
+ course_has_no_rights_with_fix: This course is not allowed to use this private exercise. Click here to grant this course those rights.
+ course_has_no_rights_with_contact: This course is not allowed to use this private exercise. Contact the author to grant rights or remove this exercise from the course.
diff --git a/config/locales/views/activities/nl.yml b/config/locales/views/activities/nl.yml
index ecb9bd1126..a08cc81ffd 100644
--- a/config/locales/views/activities/nl.yml
+++ b/config/locales/views/activities/nl.yml
@@ -118,3 +118,6 @@ nl:
config_info: 'Neem een kijkje op de %{doc_site} voor meer informatie over het configureren van oefeningen.'
doc_site: 'documentatiesite'
activity_invalid: Deze oefening heeft geen geldige configuratie.
+ series_activities_table:
+ course_has_no_rights_with_fix: Deze cursus heeft niet de rechten om deze privé-oefening te gebruiken. Klik hier om deze rechten te geven.
+ course_has_no_rights_with_contact: Deze cursus heeft niet de rechten om deze privé-oefening te gebruiken. Contacteer de auteur of verwijder deze oefening uit de cursus.
diff --git a/config/locales/views/courses/en.yml b/config/locales/views/courses/en.yml
index c8f3db212d..4a96d6bfaa 100644
--- a/config/locales/views/courses/en.yml
+++ b/config/locales/views/courses/en.yml
@@ -88,6 +88,8 @@ en:
other: "You can't remove a course with more than %{count} submissions yourself."
contact_html: "Contact us if you want to delete the course anyway."
show:
+ has_private_exercises: "This course uses private exercises that it hasn't been granted the rights to."
+ has_private_help: "Contact us if you don't know how to solve this."
course: Course
hidden_show_link: "Secret link"
visibility-visible_for_all-info: "This course is visible for everyone: everyone can access this course from the course overview, and the contents are visible for everyone."
@@ -175,8 +177,6 @@ en:
exercise_count: Exercises
content_count: Reading activities
more_statistics: "More statistics >"
- create:
- added_private_exercises: "Private exercises were added while creating this course. To use these exercises, this course will need to be granted permission from the relevant repositories."
copy_courses_table:
info: "Course"
users: "# users"
diff --git a/config/locales/views/courses/nl.yml b/config/locales/views/courses/nl.yml
index a9266d9651..202e1f0536 100644
--- a/config/locales/views/courses/nl.yml
+++ b/config/locales/views/courses/nl.yml
@@ -96,6 +96,8 @@ nl:
other: "Je kan een cursus met meer dan %{count} oplossingen niet zelf verwijderen."
contact_html: "Contacteer ons als je de cursus toch wilt verwijderen."
show:
+ has_private_exercises: "Deze cursus gebruikt privé-oefeningen waartoe die geen rechten heeft."
+ has_private_help: "Contacteer ons als je niet weet hoe je dit kan oplossen."
course: Cursus
hidden_show_link: 'Geheime link'
visibility-visible_for_all-info: 'Deze cursus is zichtbaar voor iedereen: ze wordt opgelijst in het cursusoverzicht en de inhoud is toegankelijk voor iedereen.'
@@ -171,8 +173,6 @@ nl:
content_count: Leesactiviteiten
submitted_solutions: Ingediende oplossingen
more_statistics: "Meer statistieken >"
- create:
- added_private_exercises: "Er werden privé oefeningen toegevoegd tijdens het aanmaken van deze cursus. Om deze oefeningen te kunnen gebruiken zal deze cursus toestemming moeten krijgen van de relevante repository's."
copy_courses_table:
info: "Cursus"
users: "# gebruikers"
@@ -204,7 +204,7 @@ nl:
enable: Schakel vragen in.
disable: Schakel vragen uit.
ical:
- serie_deadline: "Deadline voor %{serie_name} van cursus %{course_name}: %{serie_url}"
+ serie_deadline: "Deadline voor %{serie_name} van cursus %{course_name}: %{serie_url}"
submissions:
show:
questions:
diff --git a/test/controllers/courses_controller_test.rb b/test/controllers/courses_controller_test.rb
index c332f5b4eb..0617b57823 100644
--- a/test/controllers/courses_controller_test.rb
+++ b/test/controllers/courses_controller_test.rb
@@ -13,6 +13,13 @@ class CoursesControllerTest < ActionDispatch::IntegrationTest
test_crud_actions
+ test 'should render with inaccessible activities' do
+ @instance.series << create(:series)
+ @instance.series.first.activities << create(:exercise, access: :private)
+ get course_url(@instance)
+ assert_response :success
+ end
+
test 'should reset token' do
old_secret = @instance.secret
post reset_token_course_url(@instance)
diff --git a/test/models/course_test.rb b/test/models/course_test.rb
index 65973fe5bb..b9c9046f2b 100644
--- a/test/models/course_test.rb
+++ b/test/models/course_test.rb
@@ -249,4 +249,15 @@ class CourseTest < ActiveSupport::TestCase
assert course.destroy
assert_equal code, submission.reload.code
end
+
+ test 'all_activities_accessible? should be correct' do
+ course = create :course, series_count: 1, exercises_per_series: 0
+ ex = create :exercise, access: :public
+ course.series.first.exercises << ex
+ assert course.all_activities_accessible?
+ ex.update(access: :private)
+ assert_not course.all_activities_accessible?
+ course.usable_repositories << ex.repository
+ assert course.all_activities_accessible?
+ end
end