diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb
index eee1204eec..22d12f794a 100644
--- a/app/controllers/courses_controller.rb
+++ b/app/controllers/courses_controller.rb
@@ -342,26 +342,14 @@ def subscribe
success_method = method(:signup_succeeded_response)
end
- case @course.registration
- when 'open_for_all'
+ if @course.open_for_user?(current_user)
if try_to_subscribe_current_user status: status
success_method.call(format)
else
subscription_failed_response format
end
- when 'open_for_institution'
- if @course.institution == current_user.institution
- if try_to_subscribe_current_user status: status
- success_method.call(format)
- else
- subscription_failed_response format
- end
- else
- format.html { redirect_to(course_url(@course, secret: params[:secret]), alert: I18n.t('courses.registration.closed')) }
- format.json { render json: { errors: ['course closed'] }, status: :unprocessable_entity }
- end
- when 'closed'
- format.html { redirect_to(@course, alert: I18n.t('courses.registration.closed')) }
+ else
+ format.html { redirect_to(course_url(@course, secret: params[:secret]), alert: I18n.t('courses.registration.closed')) }
format.json { render json: { errors: ['course closed'] }, status: :unprocessable_entity }
end
end
diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb
index bfd92b3ced..150b7ebdac 100644
--- a/app/helpers/courses_helper.rb
+++ b/app/helpers/courses_helper.rb
@@ -7,7 +7,7 @@ def registration_action_for(**args)
membership = args[:membership]
if membership.nil? || membership.unsubscribed?
- if course.open_for_all? || (course.open_for_institution? && (course.institution == current_user&.institution || current_user.nil?))
+ if course.open_for_user?(current_user) || current_user.nil?
if course.moderated
link_to t('courses.show.request_registration'),
subscribe_course_path(@course, secret: secret),
diff --git a/app/models/activity.rb b/app/models/activity.rb
index ddd41e9baa..b50b33f36a 100644
--- a/app/models/activity.rb
+++ b/app/models/activity.rb
@@ -280,7 +280,7 @@ def accessible?(user, course)
return true if user&.member_of? course
return false if course.moderated && access_private?
- course.open_for_all? || (course.open_for_institution? && course.institution == user&.institution)
+ course.open_for_user?(user)
else
return true if user&.repository_admin? repository
diff --git a/app/models/course.rb b/app/models/course.rb
index ccdcb94043..8ab82f33d4 100644
--- a/app/models/course.rb
+++ b/app/models/course.rb
@@ -55,7 +55,7 @@ class Course < ApplicationRecord
has_many :course_labels, dependent: :destroy
enum visibility: { visible_for_all: 0, visible_for_institution: 1, hidden: 2 }
- enum registration: { open_for_all: 0, open_for_institution: 1, closed: 2 }
+ enum registration: { open_for_all: 3, open_for_institutional_users: 0, open_for_institution: 1, closed: 2 }
# TODO: Remove and use activities?
has_many :content_pages,
@@ -168,7 +168,7 @@ class Course < ApplicationRecord
# Default year & enum values
after_initialize do |course|
self.visibility ||= 'visible_for_all'
- self.registration ||= 'open_for_all'
+ self.registration ||= 'open_for_institutional_users'
unless year
now = Time.zone.now
y = now.year
@@ -214,6 +214,10 @@ def all_activities_accessible?
activities.where(access: :private).where.not(repository_id: usable_repositories).count.zero?
end
+ def open_for_user?(user)
+ open_for_all? || (open_for_institution? && institution == user&.institution) || (open_for_institutional_users? && user&.institutional?)
+ end
+
def invalidate_subscribed_members_count_cache
Rails.cache.delete(format(SUBSCRIBED_MEMBERS_COUNT_CACHE_STRING, id: id))
end
diff --git a/app/models/user.rb b/app/models/user.rb
index f25178af9d..9d0c7d5763 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -272,6 +272,14 @@ def repository_admin?(repository)
@repository_admin.include?(repository.id)
end
+ def personal?
+ institution.nil?
+ end
+
+ def institutional?
+ institution.present?
+ end
+
def attempted_exercises(options)
s = submissions.judged
s = s.in_course(options[:course]) if options[:course].present?
diff --git a/bin/server b/bin/server
index 4ae98c895a..ce5526cbbd 100755
--- a/bin/server
+++ b/bin/server
@@ -1,4 +1,7 @@
#!/bin/bash
bundle install
yarn install
-bundle exec rails s -p 3000 & bundle exec rails jobs:work & yarn build:css --watch & NODE_ENV=development yarn build:js --watch
+bundle exec rails s -p 3000 &
+bundle exec rails jobs:work &
+yarn build:css --watch &
+NODE_ENV=development yarn build:js --watch
diff --git a/config/locales/models/en.yml b/config/locales/models/en.yml
index 3ef3a83b32..623d3b5a85 100644
--- a/config/locales/models/en.yml
+++ b/config/locales/models/en.yml
@@ -55,6 +55,7 @@ en:
open_for_all: Open for everyone
open_for_institution: Only open for members of the configured institution
closed: Closed
+ open_for_institutional_users: Open for all users that belong to an institution
institution: Institution
activity:
name: Name
diff --git a/config/locales/models/nl.yml b/config/locales/models/nl.yml
index 16f8ef964e..6a7335b43c 100644
--- a/config/locales/models/nl.yml
+++ b/config/locales/models/nl.yml
@@ -56,6 +56,7 @@ nl:
open_for_all: Open voor iedereen
open_for_institution: Enkel open voor gebruikers van de ingestelde onderwijsinstelling
closed: Gesloten
+ open_for_institutional_users: Open voor alle gebruikers die tot een onderwijsinstelling behoren
institution: Onderwijsinstelling
activity:
name: Naam
diff --git a/config/locales/views/courses/en.yml b/config/locales/views/courses/en.yml
index 499de39501..e4d7cc81c9 100644
--- a/config/locales/views/courses/en.yml
+++ b/config/locales/views/courses/en.yml
@@ -17,6 +17,7 @@ en:
registration-open_for_all-help_html: Anyone can register for this course.
registration-open_for_institution-help_html: Only members of the configured institution can register for this course.
registration-closed-help_html: All new registrations are disabled.
+ registration-open_for_institutional_users-help_html: Anyone that belongs to an institution can register for this course. Users that signed in using a private account, such as a personal Gmail or Outlook account, cannot register.
description-help_html: A description is optional. Markdown formatting can be used.
visibility-label: For whom is this course visible?
registration-label: Who can register for this course?
@@ -27,6 +28,7 @@ en:
registration-open_for_all_html: Everyone
registration-open_for_institution_html: Only users of the configured institution
registration-closed_html: Nobody
+ registration-open_for_institutional_users_html: Everyone that belongs to an institution
no_institution: "No institution"
copy_admins: "Course admins"
copy_options: "Copy options"
@@ -98,6 +100,7 @@ en:
registration-open_for_all-info: "Registrations are open for everyone: all users can register for this course."
registration-open_for_institution-info: "Registrations are open for members of %{institution}: only they can register for this course."
registration-closed-info: "Registrations are closed: users can't register until you change the registration settings. Users who are currently registered still have access."
+ registration-open_for_institutional_users-info: "Registrations are open for users that belong to any institution. Registrations are closed for users who signed in using a private account, such as a personal Gmail or Outlook account."
moderated-info: "This course is moderated. Users who register will have to be explicitly approved by a course admin."
subscribe: Register
request_registration: Request registration
diff --git a/config/locales/views/courses/nl.yml b/config/locales/views/courses/nl.yml
index 527d887c87..c8f43ed09d 100644
--- a/config/locales/views/courses/nl.yml
+++ b/config/locales/views/courses/nl.yml
@@ -17,6 +17,7 @@ nl:
registration-open_for_all-help_html: Iedereen kan zich voor deze cursus registreren.
registration-open_for_institution-help_html: Enkel gebruikers van de ingestelde onderwijsinstelling kunnen zich voor deze cursus registreren.
registration-closed-help_html: Er zijn geen nieuwe registraties mogelijk.
+ registration-open_for_institutional_users-help_html: Iedereen die tot een instelling behoort kan zich voor deze cursus registreren. Gebruikers die zijn ingelogd met een privéaccount, zoals een persoonlijk Gmail- of Outlook-account, kunnen zich niet registreren.
description-help_html: Een beschrijving is optioneel en kan in Markdown geschreven worden.
visibility-label: Voor wie is deze cursus zichtbaar?
registration-label: Wie kan zich registreren voor deze cursus?
@@ -27,6 +28,7 @@ nl:
registration-open_for_all_html: Iedereen
registration-open_for_institution_html: Enkel gebruikers van de ingestelde onderwijsinstelling
registration-closed_html: Niemand
+ registration-open_for_institutional_users_html: Alle gebruikers die tot een onderwijsinstelling behoren
no_institution: "Geen onderwijsinstelling"
copy_admins: "Cursusbeheerders"
copy_options: "Opties voor het kopiëren"
@@ -107,6 +109,7 @@ nl:
registration-open_for_all-info: 'De registraties staan open voor iedereen: gebruikers die op de registratie-knop klikken worden geregistreerd.'
registration-open_for_institution-info: 'De registraties staan open voor gebruikers van %{institution}: enkel zij kunnen zich registreren voor deze cursus.'
registration-closed-info: 'De registraties zijn gesloten: niemand kan zich nog registreren tot de registratie-instelling wordt aangepast. Gebruikers die geregistreerd zijn behouden hun toegang.'
+ registration-open_for_institutional_users-info: 'De registraties staan open voor gebruikers die tot een instelling behoren. De registraties zijn gesloten voor gebruikers die zijn ingelogd met een privéaccount, zoals een persoonlijk Gmail- of Outlook-account.'
moderated-info: 'Deze cursus is gemodereerd: Gebruikers die zich registreren moeten expliciet goedgekeurd worden door een cursusbeheerder.'
subscribe: Registreren
request_registration: Registratieverzoek indienen
diff --git a/db/seeds.rb b/db/seeds.rb
index 5148a1e5ac..9e34165229 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -198,6 +198,8 @@ def fill_series_with_realistic_submissions(s)
courses = []
+
+ courses << Course.create(description: 'This is a test course.', name: 'Open for Institutional users course', year: academic_year, registration: 'open_for_institutional_users', visibility: 'visible_for_all', moderated: false, teacher: 'Prof. Gobelijn')
courses << Course.create(description: 'This is a test course.', name: 'Open for All Test Course', year: academic_year, registration: 'open_for_all', visibility: 'visible_for_all', moderated: false, teacher: 'Prof. Gobelijn')
courses << Course.create(description: 'This is a test course.', name: 'Open for Institution Test Course', year: academic_year, registration: 'open_for_institution', visibility: 'visible_for_institution', moderated: false, teacher: 'Prof. Gobelijn', institution: ugent)
courses << Course.create(description: 'This is a test course.', name: 'Open Moderated Test Course', year: academic_year, registration: 'open_for_all', visibility: 'visible_for_all', moderated: true, teacher: 'Prof. Barabas')
diff --git a/test/controllers/courses_controller_test.rb b/test/controllers/courses_controller_test.rb
index 1ab409a008..ad7eb0c931 100644
--- a/test/controllers/courses_controller_test.rb
+++ b/test/controllers/courses_controller_test.rb
@@ -158,7 +158,7 @@ def with_users_signed_in(users)
test 'should get course page with secret' do
add_not_subscribed
with_users_signed_in @not_subscribed.compact do |who, user|
- %w[visible_for_all visible_for_institution hidden].product(%w[open_for_all open_for_institution closed], [true, false]).each do |v, r, m|
+ %w[visible_for_all visible_for_institution hidden].product(%w[open_for_all open_for_institutional_users open_for_institution closed], [true, false]).each do |v, r, m|
@course.update(visibility: v, registration: r, moderated: m)
get course_url(@course, secret: @course.secret, format: :json)
assert_response :success, "#{who} should get registration page"
@@ -712,6 +712,30 @@ def with_users_signed_in(users)
assert_not response.body.include?(subscribe_course_path(@course, secret: @course.secret))
end
+ test 'personal user should not be able to subscribe to open_for_institutional_users course' do
+ add_externals
+ @course.update(registration: :open_for_institutional_users)
+ user = @externals.first
+ user.update(institution: nil)
+ sign_in user
+ post subscribe_course_url(@course)
+ assert_not @course.subscribed_members.include?(user)
+ post subscribe_course_url(@course, secret: @course.secret)
+ assert_not @course.subscribed_members.include?(user)
+ end
+
+ test 'institutional user should be able to subscribe to open_for_institutional_users course' do
+ add_externals
+ @course.update(registration: :open_for_institutional_users)
+ user = @externals.first
+ user.update(institution: (create :institution))
+ sign_in user
+ post subscribe_course_url(@course)
+ assert @course.subscribed_members.include?(user)
+ post subscribe_course_url(@course, secret: @course.secret)
+ assert @course.subscribed_members.include?(user)
+ end
+
test 'should not destroy course as student' do
add_students
sign_in @students.first
diff --git a/test/fixtures/courses.yml b/test/fixtures/courses.yml
index 031c3afd1e..1da0126d5e 100644
--- a/test/fixtures/courses.yml
+++ b/test/fixtures/courses.yml
@@ -25,5 +25,6 @@ course1:
year: 2021-2022
description: This is the description of course 1
visibility: 0 # visible for all
- registration: 0 # open for all
+ registration: 3 # open for all
teacher: Prof. Zonnebloem
+ secret: "PuDCHk3A7qCEAbxKXPpz"