-
Notifications
You must be signed in to change notification settings - Fork 650
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 admin view to copy courses from production instance of dashboard (#5528) #5528
Changes from all commits
9778158
ec400de
fa0fb2d
c5d444e
8402f55
0be03bb
2bfd966
048de68
65188da
fff45d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# frozen_string_literal: true | ||
|
||
#= Controller for Copy Course tool | ||
class CopyCourseController < ApplicationController | ||
respond_to :html | ||
before_action :require_admin_permissions | ||
def index; end | ||
|
||
def copy | ||
service = CopyCourse.new(url: params[:url]) | ||
response = service.make_copy | ||
if response[:error].present? | ||
redirect_to(copy_course_path, | ||
flash: { error: "Course not created: #{response[:error]}" }) | ||
else | ||
course = response[:course] | ||
redirect_to copy_course_path, | ||
notice: "Course #{course.title} was created."\ | ||
" <a href=\"/courses/#{course.slug}\">Go to course</a>" | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
# frozen_string_literal: true | ||
|
||
#= Copy course from another server | ||
class CopyCourse | ||
def initialize(url:) | ||
@url = url | ||
end | ||
|
||
def make_copy | ||
@course_data = retrieve_course_data | ||
copy_main_course_data | ||
add_tracked_wikis | ||
@cat_data = retrieve_categories_data | ||
copy_tracked_categories_data | ||
@users_data = retrieve_users_data | ||
copy_users_data | ||
return { course: @course, error: nil } | ||
rescue ActiveRecord::RecordInvalid, StandardError => e | ||
return { course: nil, error: e.message } | ||
end | ||
|
||
private | ||
|
||
def copy_main_course_data | ||
# Extract the attributes we want to copy | ||
params_to_copy = %w[school title term description start end subject slug timeline_start | ||
timeline_end type flags] | ||
copied_data = {} | ||
params_to_copy.each { |p| copied_data[p] = @course_data[p] } | ||
@home_wiki = Wiki.get_or_create(language: @course_data['home_wiki']['language'], | ||
project: @course_data['home_wiki']['project']) | ||
copied_data['home_wiki_id'] = @home_wiki.id | ||
copied_data['passcode'] = GeneratePasscode.call # set a random passcode | ||
if copied_data['flags'].key?('update_logs') | ||
copied_data['flags']['update_logs'] = | ||
fix_update_logs_parsing(copied_data['flags']['update_logs']) | ||
end | ||
# Create the course | ||
@course = Course.create!(copied_data) | ||
end | ||
|
||
# When parsing update_logs from flags, keys are set as strings instead of integers | ||
# This causes problems, so we need to force the keys to be integers. | ||
def fix_update_logs_parsing(update_logs) | ||
update_logs.transform_keys(&:to_i) | ||
end | ||
|
||
def add_tracked_wikis | ||
@course_data['wikis'].each do |wiki_hash| | ||
wiki = Wiki.get_or_create(language: wiki_hash['language'], project: wiki_hash['project']) | ||
next if wiki.id == @home_wiki.id # home wiki was automatically added already | ||
@course.wikis << wiki | ||
end | ||
end | ||
|
||
def copy_tracked_categories_data | ||
@cat_data.each do |cat_hash| | ||
wiki = Wiki.get_or_create(language: cat_hash['wiki']['language'], | ||
project: cat_hash['wiki']['project']) | ||
cat = Category.find_or_create_by!( | ||
depth: cat_hash['depth'], | ||
source: cat_hash['source'], | ||
name: cat_hash['name'], | ||
wiki: | ||
) | ||
@course.categories << cat | ||
end | ||
end | ||
|
||
def copy_users_data | ||
@users_data.each do |user_hash| | ||
user = User.find_or_create_by!(username: user_hash['username']) | ||
CoursesUsers.create!(user_id: user.id, role: user_hash['role'], course_id: @course.id) | ||
end | ||
end | ||
|
||
def get_request(path) | ||
uri = URI(@url + path) | ||
response = Net::HTTP.get_response(uri) | ||
raise "Error getting data from #{uri}" unless response.is_a?(Net::HTTPSuccess) | ||
response | ||
end | ||
|
||
def retrieve_course_data | ||
response = get_request('/course.json') | ||
JSON.parse(response.body)['course'] | ||
end | ||
|
||
def retrieve_categories_data | ||
response = get_request('/categories.json') | ||
JSON.parse(response.body)['course']['categories'] | ||
end | ||
|
||
def retrieve_users_data | ||
response = get_request('/users.json') | ||
JSON.parse(response.body)['course']['users'] | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
- content_for :before_title, 'Admin - ' | ||
|
||
.container.dashboard | ||
%header | ||
%h1 | ||
= 'Copy course from another server' | ||
|
||
%section | ||
.container | ||
%hr | ||
|
||
.container | ||
= form_tag copy_course_path, class: 'explore-courses', method: :post do | ||
= text_field_tag(:url, '', placeholder: 'Copy course URL here...') | ||
%button{type: 'submit'} | ||
%i.icon.icon-check |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
- if flash[:notice] | ||
.notification= flash[:notice] | ||
.notification= flash[:notice].html_safe | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this change for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh I cherry-picked this from the previous PR. |
||
|
||
- unless ENV['sitenotice'].blank? | ||
.notification.sitenotice= raw ENV['sitenotice'].dup.force_encoding("UTF-8") | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
describe CopyCourseController, type: :request do | ||
describe '#index' do | ||
let(:user) { create(:user) } | ||
let(:admin) { create(:admin) } | ||
|
||
context 'when the user is an admin' do | ||
before do | ||
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(admin) | ||
end | ||
|
||
it 'shows the feature to copy the course' do | ||
get copy_course_path | ||
expect(response.status).to eq(200) | ||
end | ||
end | ||
|
||
context 'when the user is not an admin' do | ||
before do | ||
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(user) | ||
end | ||
|
||
it 'returns a 401 error' do | ||
get copy_course_path | ||
expect(response.status).to eq(401) | ||
end | ||
end | ||
end | ||
|
||
describe '#copy' do | ||
let(:admin) { create(:admin) } | ||
let(:subject) { post copy_course_path, params: { url: 'someurl.com' } } | ||
|
||
context 'when the copy fails for some reason' do | ||
before do | ||
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(admin) | ||
allow_any_instance_of(CopyCourse).to receive(:make_copy).and_return( | ||
{ course: nil, error: 'An interesting error happened' } | ||
) | ||
end | ||
|
||
it 'renders the error' do | ||
subject | ||
expect(response).to redirect_to(copy_course_path) | ||
expect(flash[:error]).to eq('Course not created: An interesting error happened') | ||
end | ||
end | ||
|
||
context 'when the copy is successful' do | ||
before do | ||
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(admin) | ||
allow_any_instance_of(CopyCourse).to receive(:make_copy).and_return( | ||
{ course: create(:basic_course), error: nil } | ||
) | ||
end | ||
|
||
it 'renders the success message' do | ||
subject | ||
expect(response).to redirect_to(copy_course_path) | ||
expect(flash[:notice]).to eq('Course Black life matters was created.'\ | ||
' <a href="/courses/none/Black_life_'\ | ||
'matters_(none)">Go to course</a>') | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ordered the links alphabetically