Skip to content

Commit

Permalink
Merge pull request #183 from OpenDSA/textbooks
Browse files Browse the repository at this point in the history
Textbooks
  • Loading branch information
kwasimbnyarko authored Nov 1, 2024
2 parents b3dc336 + f9a778c commit f996c33
Show file tree
Hide file tree
Showing 12 changed files with 346 additions and 172 deletions.
68 changes: 55 additions & 13 deletions app/assets/javascripts/course_offerings.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(function () {
var check_completeness, form_alert, handle_submit, init, reset_alert_area, valid_token;
var check_completeness, form_alert, handle_submit, handle_generate_textbook, init, reset_alert_area, valid_token;

$(document).ready(function () {

Expand All @@ -21,7 +21,12 @@
$(this).prop('disabled', true);
return handle_submit();
});


$('#btn-gen-textbook').click(function () {
$(this).prop('disabled', true);
return handle_generate_textbook();
});

$('#display').click(function () {
return handle_select_student();
//return handle_display();
Expand Down Expand Up @@ -123,18 +128,22 @@
return $('#alerts').append(alert_box);
};

check_completeness = function () {
check_completeness = function (isTextbook) {
var messages;
messages = [];
if ($('#lms-instance-select').val() === '') {
messages.push('One of the LMS instances has to be selected.');
}
if (!valid_token) {
messages.push('You have to provide an access token for the selected Canvas instance.');
}
if ($('#lms-course-num').val() === '') {
messages.push('You have to write LMS course Id.');

if (!isTextbook){
if (!valid_token) {
messages.push('You have to provide an access token for the selected Canvas instance.');
}
if ($('#lms-course-num').val() === '') {
messages.push('You have to write LMS course Id.');
}
if ($('#lms-instance-select').val() === '') {
messages.push('One of the LMS instances has to be selected.');
}
}

// if ($('#lms-course-code').val() === '') {
// messages.push('You have to write LMS course name.');
// }
Expand Down Expand Up @@ -175,10 +184,43 @@
console.error(error);
});
};


handle_generate_textbook = function () {
var organization_id, course_id, term_id, label, inst_book_id, fd, messages, url;
messages = check_completeness(true);
if (messages.length !== 0) {
form_alert(messages);
$('#btn-submit-co').prop('disabled', false);
return;
}
organization_id = $('#organization-select').val();
course_id = $('#course-select').val();
term_id = $('#term-select').val();
label = $('#label').val();
inst_book_id = $('#inst-book-select').val();
fd = new FormData;
fd.append('organization_id', organization_id);
fd.append('course_id', course_id);
fd.append('term_id', term_id);
fd.append('label', label);
fd.append('inst_book_id', inst_book_id);
url = '/textbooks'
return $.ajax({
url: url,
type: 'post',
data: fd,
processData: false,
contentType: false,
success: function (data) {
return window.location.href = data['url'];
}
});
};


handle_submit = function () {
var lms_instance_id, lms_course_num, lms_course_code, organization_id, course_id, term_id, label, late_policy_id, inst_book_id, fd, messages, url;
messages = check_completeness();
messages = check_completeness(false);
if (messages.length !== 0) {
form_alert(messages);
$('#btn-submit-co').prop('disabled', false);
Expand Down
1 change: 1 addition & 0 deletions app/controllers/course_offerings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ def create
else
err_string = 'There was a problem while creating the course offering.'
url = url_for new_course_offerings_path(notice: err_string)

end
end

Expand Down
56 changes: 56 additions & 0 deletions app/controllers/textbooks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
class TextbooksController < ApplicationController

def create
# Textbooks are CourseOffering with no LMS interaction
# Hence the LMS instance TEXTBOOK is used for all CourseOfferings
# that are TEXTBOOKS
lms_instance = LmsInstance.find_by(url: "TEXTBOOK")
course = Course.find_by(id: params[:course_id])
term = Term.find_by(id: params[:term_id])
inst_book = InstBook.find_by(id: params[:inst_book_id])

course_offering = CourseOffering.where(
"course_id=? and term_id=? and label=? and lms_instance_id=?",
params[:course_id], params[:term_id], params[:label], lms_instance.id
).first

if course_offering.blank?
course_offering = CourseOffering.new(
course: course,
term: term,
label: params[:label],
lms_instance: lms_instance,
lms_course_num: 9999999
)

cloned_book = inst_book.get_clone(current_user)

if course_offering.save!
cloned_book.course_offering_id = course_offering.id
cloned_book.save!

enrollment = CourseEnrollment.new
enrollment.course_offering_id = course_offering.id
enrollment.user_id = current_user.id
enrollment.course_role_id = CourseRole.instructor.id
enrollment.save!
else
err_string = 'There was a problem while creating the course offering.'
url = url_for new_course_offerings_path(notice: err_string)
end
end

if !url
url = url_for(organization_course_path(
course_offering.course.organization,
course_offering.course,
course_offering.term
))
end

respond_to do |format|
format.json { render json: {url: url} }
end
end

end
16 changes: 15 additions & 1 deletion app/jobs/compile_book_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def perform
config_path = config_file_path[15..-1] # without the public/OpenDSA
require 'net/http'
uri = URI(ENV["config_api_link"])
res = Net::HTTP.post_form(uri, 'config_file_path' => config_path, 'build_path' => build_path, 'rake' => false)

res = Net::HTTP.post_form(uri, 'config_file_path' => config_path, 'build_path' => build_path, 'rake' => is_textbook(@inst_book))
unless res.kind_of? Net::HTTPSuccess
Rails.logger.info(res['stderr_compressed'])
end
Expand All @@ -54,4 +55,17 @@ def book_path(inst_book)
sanitize_filename(term.slug) + "/" +
sanitize_filename(course_offering.label)
end


def is_textbook(inst_book)
course_offering = CourseOffering.where(:id => inst_book.course_offering_id).first

textbook_instance = LmsInstance.find_by(url: "TEXTBOOK")
if course_offering.lms_instance_id == textbook_instance.id
Rails.logger.info("Compiling Standalone Book")
end

course_offering.lms_instance_id == textbook_instance.id
end

end
30 changes: 25 additions & 5 deletions app/models/inst_book.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,11 @@ def extract_av_data_from_rst

# Check if rst_folder to prevent Dir.glob from failing
return av_data unless Dir.exist?(rst_folder)

Dir.glob("#{rst_folder}/**/*.rst").each do |rst_file_path|
module_name = File.basename(rst_file_path, ".rst")
av_data[module_name] = { avmetadata: {}, inlineav: [], avembed: [] }
in_metadata_block = false

File.foreach(rst_file_path) do |line|
if line.strip == '.. avmetadata::'
in_metadata_block = true
Expand All @@ -164,12 +163,32 @@ def extract_av_data_from_rst
end
end
end

av_data
end
end

def get_clone(currentUser)
return clone(currentUser)
end
private

def extract_metadata_from_line(line)
key, value = line.strip.split(': ', 2)
[key[1..].to_sym, value] if key && value
end

def extract_inlineav_name_from_line(line)
match = line.match(/\.\. inlineav:: (\w+)/)
match[1] if match # Returns the inlineav short name or nil if no match
end

def extract_avembed_data_from_line(line)
match = line.match(/\.\. avembed:: Exercises\/\w+\/(\w+)\.html/)
match[1] if match # Returns the 3rd level word or nil if no match
end



# --------------------------------------------------------------------------------

# FIXME: shouldn't this method be removed? It appears to be out-dated?
# FIXME: the real code is now in views/inst_books/show.json.builder
def to_builder
Expand Down Expand Up @@ -271,6 +290,7 @@ def clone(current_user)
inst_chapters.each do |chapter|
inst_chapter = chapter.clone(b)
end

return b
end

Expand Down
25 changes: 17 additions & 8 deletions app/views/course_offerings/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
%a{href: home_guide_path}
instructor's guide
for more information.
%h4.text-danger All fields are required.
%h4.text-danger All fields are required
%h4.text-danger Note: LMS fields are not required to create textbooks

/ .form-group
/ = label_tag :name, 'Canvas course Name', class: 'control-label col-xs-2'
Expand Down Expand Up @@ -79,35 +80,43 @@
/ %i.fa.fa-info-circle.action{ data: { toggle: 'modal', target: '#inst-book-help-modal' } }
.form-group
= label_tag :lms_instance_select, 'Canvas Instance:', class: 'control-label col-xs-1'
= label_tag :lms_instance_select, 'LMS Instance:', class: 'control-label col-xs-1'
.col-xs-3
= collection_select nil, nil, LmsInstance.all, :id, :url, { prompt: 'Select', selected: nil },
{ id: 'lms-instance-select', class: 'form-control' }

#lms-access-token-group.form-group
= label_tag :name, 'Canvas access token', class: 'control-label col-xs-2'
= label_tag :name, 'LMS access token', class: 'control-label col-xs-2'
.col-lg-4.col-md-4.col-xs-4
= text_field_tag :lms_access_token, nil, id: 'lms-access-token', class: 'form-control', maxlength: 100, disabled: 'true'
%small.col-xs-11.text.text-warning#lms-access-token-desc
Your access token allows the OpenDSA application to generate the book instance in your Canvas course on your behalf. First, you need to generate Canvas access token by following
Your access token allows the OpenDSA application to generate the book instance in your LMS course on your behalf. First, you need to generate LMS access token by following
the instructions <a href="https://guides.instructure.com/m/4214/l/40399-how-do-i-obtain-an-api-access-token-for-an-account" target="_blank">here</a>. Second, go to the OpenDSA
= link_to "LMS Accesses", admin_lms_accesses_path, :target => "_blank"
page to add or update your access token.
#lms-access-update-btn.col-xs-1
= link_to admin_lms_accesses_path, title: "Update your access token for the selected Canvas instance", class: 'btn btn-default', :target => "_blank" do
= link_to admin_lms_accesses_path, title: "Update your access token for the selected LMS instance", class: 'btn btn-default', :target => "_blank" do
%i.glyphicon.glyphicon-new-window
#lms-access-token-check.col-xs-1.fa.fa-check

.form-group
= label_tag :name, 'Canvas course Id', class: 'control-label col-xs-2'
= label_tag :name, 'LMS course Id', class: 'control-label col-xs-2'
.col-lg-4.col-md-4.col-xs-4
= text_field_tag :lms_course_id, nil, id: 'lms-course-num', class: 'form-control', maxlength: 25
%small.col-xs-11.text.text-warning
Create a new course at the selected canvas instance and copy the course Id here (e.g. Course Id of https://canvas.instructure.com/courses/1076903 is 1076903).
Create a new course at the selected LMS instance and copy the course Id here (e.g. Course Id of https://canvas.instructure.com/courses/1076903 is 1076903).

.form-group
.col-xs-offset-2.col-xs-2
%button#btn-submit-co.btn.btn-primary Submit
%button#btn-submit-co.btn.btn-primary Create New Course Offering

.form-group
.col-xs-offset-2.col-xs-2
- textbook_lms_instance = LmsInstance.find_by(url: "TEXTBOOK")
%button#btn-gen-textbook.btn.btn-primary{disabled:textbook_lms_instance.blank?} Create Non LMS Textbook
%small.col-xs-11.text.text-warning
= textbook_lms_instance.blank? ? 'Textbook LMS Instance not found' : ''


#lms-instance-help-modal.modal.fade{role: 'dialog', tabindex: '-1' }
.modal-dialog.modal-md{ style: 'overflow-y: scroll; max-height:85% margin-top: 50px; margin-bottom:50px;' }
Expand Down
Loading

0 comments on commit f996c33

Please sign in to comment.