Skip to content

Commit

Permalink
Merge pull request #5507 from gabina/remove-course-template-from-user…
Browse files Browse the repository at this point in the history
…page-and-talkpage-when-user-disenrolls

Remove course template from user page and user talk page when user disenrolls
  • Loading branch information
ragesoss authored Oct 17, 2023
2 parents 37880bc + 00cf010 commit 202395c
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 15 deletions.
43 changes: 30 additions & 13 deletions app/controllers/users/enrollment_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,28 +104,36 @@ def student_role?
def remove
set_course_and_user
return if @user.nil?
# For events controlled by Event Center, only non-student roles
# can be changed on the Dashboard. Student role is handled
# via WikimediaEventCenterController.
if @course.controlled_by_event_center? && student_role?
render json: { message: I18n.t('courses.controlled_by_event_center') }, status: :unauthorized
return
end

@course_user = CoursesUsers.find_by(user: @user, course: @course,
role: enroll_params[:role])
if @course_user.nil? # This will happen if the user was already removed.
render 'users', formats: :json
return
end
ensure_role_is_authorized { return }
ensure_course_user_exists { return }

remove_assignment_templates
make_disenrollment_edits

@course_user.destroy # destroying the course_user also destroys associated Assignments.

render 'users', formats: :json
update_course_page_and_assignment_talk_templates
end

# For events controlled by Event Center, only non-student roles
# can be changed on the Dashboard. Student role is handled
# via WikimediaEventCenterController.
def ensure_role_is_authorized
return unless @course.controlled_by_event_center? && student_role?
render json: { message: I18n.t('courses.controlled_by_event_center') }, status: :unauthorized
yield
end

def ensure_course_user_exists
@course_user = CoursesUsers.find_by(user: @user, course: @course,
role: enroll_params[:role])
return unless @course_user.nil? # This will happen if the user was already removed.
render 'users', formats: :json
yield
end

# If the user has Assignments, update article talk pages to remove them from
# the assignment templates.
def remove_assignment_templates
Expand All @@ -136,6 +144,15 @@ def remove_assignment_templates
end
end

# Remove enrollment templates from user page and user talk page.
def make_disenrollment_edits
return unless student_role?
# for students only, remove templates from userpage and user talk page
DisenrollFromCourseWorker.schedule_edits(course: @course,
editing_user: current_user,
disenrolling_user: @user)
end

##################
# Finding a user #
##################
Expand Down
25 changes: 25 additions & 0 deletions app/workers/disenroll_from_course_worker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

require_dependency "#{Rails.root}/lib/wiki_course_edits"

class DisenrollFromCourseWorker
include Sidekiq::Worker
sidekiq_options lock: :until_executed

def self.schedule_edits(course:, editing_user:, disenrolling_user:)
perform_async(course.id, editing_user.id, disenrolling_user.id)
end

def perform(course_id, editing_user_id, disenrolling_user_id)
course = Course.find(course_id)
editing_user = User.find(editing_user_id)
disenrolling_user = User.find(disenrolling_user_id)
WikiCourseEdits.new(action: :disenroll_from_course,
course:,
current_user: editing_user,
disenrolling_user:)
WikiCourseEdits.new(action: :update_course,
course:,
current_user: editing_user)
end
end
31 changes: 30 additions & 1 deletion lib/wiki_course_edits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,25 @@ def enroll_in_course(enrolling_user:)
add_template_to_sandbox
end

# Removes existing template from the disenrolling student's userpage, and
# also from their talk page
def disenroll_from_course(disenrolling_user:)
generator = WikiUserpageOutput.new(@course)

@disenrolling_user = disenrolling_user
# Remove existing template from the user page
template = generator.enrollment_template
user_page = "User:#{@disenrolling_user.username}"
summary = generator.disenrollment_summary
remove_content_from_page(user_page, template, summary)

# Remove existing template from the user's talk page
talk_template = generator.enrollment_talk_template
talk_page = "User_talk:#{disenrolling_user.username}"
talk_summary = "removing {{#{template_name(@templates, 'user_talk')}}}"
remove_content_from_page(talk_page, talk_template, talk_summary)
end

# Updates the assignment template for every Assignment for the course.
# Usually, this is done incrementally so that a call to this method will only
# update the assignments that were changed in the action that triggered it.
Expand Down Expand Up @@ -114,7 +133,7 @@ def validate(action)
yield unless @course.wiki_course_page_enabled?
when :update_assignments, :remove_assignment
yield unless @course.assignment_edits_enabled?
when :enroll_in_course
when :enroll_in_course, :disenroll_from_course
yield unless @course.enrollment_edits_enabled?
end
end
Expand Down Expand Up @@ -163,6 +182,16 @@ def add_template_to_sandbox
sandbox_template:, current_user: @current_user)
end

def remove_content_from_page(page_title, content, summary)
initial_page_content = @wiki_api.get_page_content(page_title)

# If content to remove does not exist on initial page, then there is nothing
# to remove
return unless initial_page_content&.include?(content)
new_page_content = initial_page_content.gsub(/#{Regexp.quote(content)}(\n)?/, '')
@wiki_editor.post_whole_page(@current_user, page_title, new_page_content, summary)
end

def repost_with_sanitized_links(wiki_title, wiki_text, summary, spamlist)
bad_links = spamlist['matches']
bad_links = bad_links.values if bad_links.is_a?(Hash)
Expand Down
9 changes: 9 additions & 0 deletions lib/wiki_userpage_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ def sandbox_template(dashboard_url)
"{{#{dashboard_url} sandbox#{course_type_param}}}"
end

def disenrollment_summary
case @course.type
when 'FellowsCohort'
"User is no longer participating in #{@course.slug}."
else
"User has disenrolled in [[#{@course.wiki_title}]]."
end
end

private

def course_page_param
Expand Down
76 changes: 75 additions & 1 deletion spec/lib/wiki_course_edits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,22 @@
let(:course) { create(:course, id: 1, submitted: true, home_wiki:, slug:) }
let(:user) { create(:user) }
let(:enrolling_user) { create(:user, username: 'Belajane41') }
let(:disenrolling_user) { create(:user, username: 'Belajane41') }
# rubocop:disable Layout/LineLength
let(:user_page_content) do
'{{dashboard.wikiedu.org student editor | course = [[Wikipedia:Wiki_Ed/Missouri_SandT/History_of_Science_(Fall_2019)]] | slug = Missouri_SandT/History_of_Science_(Fall_2019) }}'
"{{dashboard.wikiedu.org student editor | course = [[Wikipedia:Wiki_Ed/Missouri_SandT/History_of_Science_(Fall_2019)]] | slug = Missouri_SandT/History_of_Science_(Fall_2019) }}\nAny other user page content"
end
let(:user_page_talk_content) do
"{{dashboard.wikiedu.org talk course link | course = [[Wikipedia:Wiki_Ed/Missouri_SandT/History_of_Science_(Fall_2019)]] | slug = Missouri_SandT/History_of_Science_(Fall_2019) }}\nAny other user talk page content"
end
# rubocop:enable Layout/LineLength
let(:user_template) { WikiUserpageOutput.new(course).enrollment_template }
let(:talk_template) { WikiUserpageOutput.new(course).enrollment_talk_template }
let(:sandbox_template) { WikiUserpageOutput.new(course).sandbox_template(ENV['dashboard_url']) }

let(:user_page_content_without_enrollment) { '{{a user page content}}' }
let(:user_talk_page_content_without_enrollment) { '{{a user talk page content}}' }

before do
stub_oauth_edit
end
Expand Down Expand Up @@ -217,6 +224,73 @@
end
end

describe '#disenroll_from_course' do
it 'respects the enrollment_edits_enabled edit_settings flag' do
course.update(flags: { 'edit_settings' => { 'enrollment_edits_enabled' => false } })
allow_any_instance_of(WikiApi).to receive(:get_page_content).and_return(
user_page_content,
user_page_talk_content
)
expect_any_instance_of(WikiEdits).not_to receive(:post_whole_page)
described_class.new(action: :disenroll_from_course,
course:,
current_user: user,
disenrolling_user:)
end

it 'does nothing if get_page_content returns nil' do
allow_any_instance_of(WikiApi).to receive(:get_page_content).and_return(nil)
expect_any_instance_of(WikiEdits).not_to receive(:post_whole_page)
described_class.new(action: :disenroll_from_course,
course:,
current_user: user,
disenrolling_user:)
end

it 'does nothing if page content does not include templates' do
allow_any_instance_of(WikiApi).to receive(:get_page_content).and_return(
user_page_content_without_enrollment,
user_talk_page_content_without_enrollment
)
expect_any_instance_of(WikiEdits).not_to receive(:post_whole_page)
described_class.new(action: :disenroll_from_course,
course:,
current_user: user,
disenrolling_user:)
end

it 'removes enrollment template from user page if it exists' do
allow_any_instance_of(WikiApi).to receive(:get_page_content).and_return(
user_page_content,
user_talk_page_content_without_enrollment
)
expect_any_instance_of(WikiEdits).to receive(:post_whole_page).with(
user, 'User:Belajane41', 'Any other user page content',
'User has disenrolled in [[Wikipedia:Wiki_Ed/Missouri_SandT/'\
'History_of_Science_(Fall_2019)]].'
)
described_class.new(action: :disenroll_from_course,
course:,
current_user: user,
disenrolling_user:)
end

it 'removes enrollment template from user talk page if it exists' do
allow_any_instance_of(WikiApi).to receive(:get_page_content).and_return(
user_page_content_without_enrollment,
user_page_talk_content
)
expect_any_instance_of(WikiEdits).to receive(:post_whole_page).with(
user, 'User_talk:Belajane41', 'Any other user talk page content',
'removing {{dashboard.wikiedu.org talk course link}}'
)
described_class.new(action: :disenroll_from_course,
course:,
current_user: user,
disenrolling_user:)
end
end

describe '#update_assignments' do
let(:instructor) { create(:user, username: 'Instructor') }
let(:selfie) { create(:article, title: 'Selfie') }
Expand Down

0 comments on commit 202395c

Please sign in to comment.