Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a setting to courses to limit registration to institutional accounts #3752

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 3 additions & 15 deletions app/controllers/courses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion app/helpers/courses_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion app/models/activity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 6 additions & 2 deletions app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
5 changes: 4 additions & 1 deletion bin/server
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions config/locales/models/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions config/locales/models/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions config/locales/views/courses/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 <span class="fill-institution">the configured institution</span> 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.
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
description-help_html: A description is optional. <a href="https://docs.dodona.be/en/references/exercise-description/#markdown" target="_blank">Markdown</a> formatting can be used.
visibility-label: For whom is this course visible?
registration-label: Who can register for this course?
Expand All @@ -27,6 +28,7 @@ en:
registration-open_for_all_html: Everyone
registration-open_for_institution_html: Only users of <span class="fill-institution">the configured institution</span>
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"
Expand Down Expand Up @@ -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 an institution: only they can register for this course. Registrations are closed for users who signed in using a private account, such as a personal gmail or outlook account."
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down
3 changes: 3 additions & 0 deletions config/locales/views/courses/nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 <span class="fill-institution">de ingestelde onderwijsinstelling</span> 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 privaat account, zoals een persoonlijk gmail of outlook account, kunnen niet registreren.
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
description-help_html: Een beschrijving is optioneel en kan in <a href="https://docs.dodona.be/nl/references/exercise-description/#markdown" target="_blank">Markdown</a> geschreven worden.
visibility-label: Voor wie is deze cursus zichtbaar?
registration-label: Wie kan zich registreren voor deze cursus?
Expand All @@ -27,6 +28,7 @@ nl:
registration-open_for_all_html: Iedereen
registration-open_for_institution_html: Enkel gebruikers van <span class="fill-institution">de ingestelde onderwijsinstelling</span>
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"
Expand Down Expand Up @@ -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: enkel zij kunnen zich registreren voor deze cursus. De registraties zijn gesloten voor gebruikers die zijn ingelogd met een privaat account, zoals een persoonlijk gmail of outlook account.'
jorg-vr marked this conversation as resolved.
Show resolved Hide resolved
moderated-info: 'Deze cursus is gemodereerd: Gebruikers die zich registreren moeten expliciet goedgekeurd worden door een cursusbeheerder.'
subscribe: Registreren
request_registration: Registratieverzoek indienen
Expand Down
2 changes: 2 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
26 changes: 25 additions & 1 deletion test/controllers/courses_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/courses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"