Skip to content

Commit f996c33

Browse files
Merge pull request #183 from OpenDSA/textbooks
Textbooks
2 parents b3dc336 + f9a778c commit f996c33

File tree

12 files changed

+346
-172
lines changed

12 files changed

+346
-172
lines changed

app/assets/javascripts/course_offerings.js

+55-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
(function () {
2-
var check_completeness, form_alert, handle_submit, init, reset_alert_area, valid_token;
2+
var check_completeness, form_alert, handle_submit, handle_generate_textbook, init, reset_alert_area, valid_token;
33

44
$(document).ready(function () {
55

@@ -21,7 +21,12 @@
2121
$(this).prop('disabled', true);
2222
return handle_submit();
2323
});
24-
24+
25+
$('#btn-gen-textbook').click(function () {
26+
$(this).prop('disabled', true);
27+
return handle_generate_textbook();
28+
});
29+
2530
$('#display').click(function () {
2631
return handle_select_student();
2732
//return handle_display();
@@ -123,18 +128,22 @@
123128
return $('#alerts').append(alert_box);
124129
};
125130

126-
check_completeness = function () {
131+
check_completeness = function (isTextbook) {
127132
var messages;
128133
messages = [];
129-
if ($('#lms-instance-select').val() === '') {
130-
messages.push('One of the LMS instances has to be selected.');
131-
}
132-
if (!valid_token) {
133-
messages.push('You have to provide an access token for the selected Canvas instance.');
134-
}
135-
if ($('#lms-course-num').val() === '') {
136-
messages.push('You have to write LMS course Id.');
134+
135+
if (!isTextbook){
136+
if (!valid_token) {
137+
messages.push('You have to provide an access token for the selected Canvas instance.');
138+
}
139+
if ($('#lms-course-num').val() === '') {
140+
messages.push('You have to write LMS course Id.');
141+
}
142+
if ($('#lms-instance-select').val() === '') {
143+
messages.push('One of the LMS instances has to be selected.');
144+
}
137145
}
146+
138147
// if ($('#lms-course-code').val() === '') {
139148
// messages.push('You have to write LMS course name.');
140149
// }
@@ -175,10 +184,43 @@
175184
console.error(error);
176185
});
177186
};
178-
187+
188+
handle_generate_textbook = function () {
189+
var organization_id, course_id, term_id, label, inst_book_id, fd, messages, url;
190+
messages = check_completeness(true);
191+
if (messages.length !== 0) {
192+
form_alert(messages);
193+
$('#btn-submit-co').prop('disabled', false);
194+
return;
195+
}
196+
organization_id = $('#organization-select').val();
197+
course_id = $('#course-select').val();
198+
term_id = $('#term-select').val();
199+
label = $('#label').val();
200+
inst_book_id = $('#inst-book-select').val();
201+
fd = new FormData;
202+
fd.append('organization_id', organization_id);
203+
fd.append('course_id', course_id);
204+
fd.append('term_id', term_id);
205+
fd.append('label', label);
206+
fd.append('inst_book_id', inst_book_id);
207+
url = '/textbooks'
208+
return $.ajax({
209+
url: url,
210+
type: 'post',
211+
data: fd,
212+
processData: false,
213+
contentType: false,
214+
success: function (data) {
215+
return window.location.href = data['url'];
216+
}
217+
});
218+
};
219+
220+
179221
handle_submit = function () {
180222
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;
181-
messages = check_completeness();
223+
messages = check_completeness(false);
182224
if (messages.length !== 0) {
183225
form_alert(messages);
184226
$('#btn-submit-co').prop('disabled', false);

app/controllers/course_offerings_controller.rb

+1
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ def create
308308
else
309309
err_string = 'There was a problem while creating the course offering.'
310310
url = url_for new_course_offerings_path(notice: err_string)
311+
311312
end
312313
end
313314

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
class TextbooksController < ApplicationController
2+
3+
def create
4+
# Textbooks are CourseOffering with no LMS interaction
5+
# Hence the LMS instance TEXTBOOK is used for all CourseOfferings
6+
# that are TEXTBOOKS
7+
lms_instance = LmsInstance.find_by(url: "TEXTBOOK")
8+
course = Course.find_by(id: params[:course_id])
9+
term = Term.find_by(id: params[:term_id])
10+
inst_book = InstBook.find_by(id: params[:inst_book_id])
11+
12+
course_offering = CourseOffering.where(
13+
"course_id=? and term_id=? and label=? and lms_instance_id=?",
14+
params[:course_id], params[:term_id], params[:label], lms_instance.id
15+
).first
16+
17+
if course_offering.blank?
18+
course_offering = CourseOffering.new(
19+
course: course,
20+
term: term,
21+
label: params[:label],
22+
lms_instance: lms_instance,
23+
lms_course_num: 9999999
24+
)
25+
26+
cloned_book = inst_book.get_clone(current_user)
27+
28+
if course_offering.save!
29+
cloned_book.course_offering_id = course_offering.id
30+
cloned_book.save!
31+
32+
enrollment = CourseEnrollment.new
33+
enrollment.course_offering_id = course_offering.id
34+
enrollment.user_id = current_user.id
35+
enrollment.course_role_id = CourseRole.instructor.id
36+
enrollment.save!
37+
else
38+
err_string = 'There was a problem while creating the course offering.'
39+
url = url_for new_course_offerings_path(notice: err_string)
40+
end
41+
end
42+
43+
if !url
44+
url = url_for(organization_course_path(
45+
course_offering.course.organization,
46+
course_offering.course,
47+
course_offering.term
48+
))
49+
end
50+
51+
respond_to do |format|
52+
format.json { render json: {url: url} }
53+
end
54+
end
55+
56+
end

app/jobs/compile_book_job.rb

+15-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ def perform
2828
config_path = config_file_path[15..-1] # without the public/OpenDSA
2929
require 'net/http'
3030
uri = URI(ENV["config_api_link"])
31-
res = Net::HTTP.post_form(uri, 'config_file_path' => config_path, 'build_path' => build_path, 'rake' => false)
31+
32+
res = Net::HTTP.post_form(uri, 'config_file_path' => config_path, 'build_path' => build_path, 'rake' => is_textbook(@inst_book))
3233
unless res.kind_of? Net::HTTPSuccess
3334
Rails.logger.info(res['stderr_compressed'])
3435
end
@@ -54,4 +55,17 @@ def book_path(inst_book)
5455
sanitize_filename(term.slug) + "/" +
5556
sanitize_filename(course_offering.label)
5657
end
58+
59+
60+
def is_textbook(inst_book)
61+
course_offering = CourseOffering.where(:id => inst_book.course_offering_id).first
62+
63+
textbook_instance = LmsInstance.find_by(url: "TEXTBOOK")
64+
if course_offering.lms_instance_id == textbook_instance.id
65+
Rails.logger.info("Compiling Standalone Book")
66+
end
67+
68+
course_offering.lms_instance_id == textbook_instance.id
69+
end
70+
5771
end

app/models/inst_book.rb

+25-5
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,11 @@ def extract_av_data_from_rst
141141

142142
# Check if rst_folder to prevent Dir.glob from failing
143143
return av_data unless Dir.exist?(rst_folder)
144-
144+
145145
Dir.glob("#{rst_folder}/**/*.rst").each do |rst_file_path|
146146
module_name = File.basename(rst_file_path, ".rst")
147147
av_data[module_name] = { avmetadata: {}, inlineav: [], avembed: [] }
148148
in_metadata_block = false
149-
150149
File.foreach(rst_file_path) do |line|
151150
if line.strip == '.. avmetadata::'
152151
in_metadata_block = true
@@ -164,12 +163,32 @@ def extract_av_data_from_rst
164163
end
165164
end
166165
end
167-
168166
av_data
169-
end
167+
end
168+
169+
def get_clone(currentUser)
170+
return clone(currentUser)
171+
end
172+
private
173+
174+
def extract_metadata_from_line(line)
175+
key, value = line.strip.split(': ', 2)
176+
[key[1..].to_sym, value] if key && value
177+
end
178+
179+
def extract_inlineav_name_from_line(line)
180+
match = line.match(/\.\. inlineav:: (\w+)/)
181+
match[1] if match # Returns the inlineav short name or nil if no match
182+
end
183+
184+
def extract_avembed_data_from_line(line)
185+
match = line.match(/\.\. avembed:: Exercises\/\w+\/(\w+)\.html/)
186+
match[1] if match # Returns the 3rd level word or nil if no match
187+
end
188+
189+
170190

171191
# --------------------------------------------------------------------------------
172-
173192
# FIXME: shouldn't this method be removed? It appears to be out-dated?
174193
# FIXME: the real code is now in views/inst_books/show.json.builder
175194
def to_builder
@@ -271,6 +290,7 @@ def clone(current_user)
271290
inst_chapters.each do |chapter|
272291
inst_chapter = chapter.clone(b)
273292
end
293+
274294
return b
275295
end
276296

app/views/course_offerings/_form.html.haml

+17-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
%a{href: home_guide_path}
99
instructor's guide
1010
for more information.
11-
%h4.text-danger All fields are required.
11+
%h4.text-danger All fields are required
12+
%h4.text-danger Note: LMS fields are not required to create textbooks
1213

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

8788
#lms-access-token-group.form-group
88-
= label_tag :name, 'Canvas access token', class: 'control-label col-xs-2'
89+
= label_tag :name, 'LMS access token', class: 'control-label col-xs-2'
8990
.col-lg-4.col-md-4.col-xs-4
9091
= text_field_tag :lms_access_token, nil, id: 'lms-access-token', class: 'form-control', maxlength: 100, disabled: 'true'
9192
%small.col-xs-11.text.text-warning#lms-access-token-desc
92-
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
93+
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
9394
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
9495
= link_to "LMS Accesses", admin_lms_accesses_path, :target => "_blank"
9596
page to add or update your access token.
9697
#lms-access-update-btn.col-xs-1
97-
= link_to admin_lms_accesses_path, title: "Update your access token for the selected Canvas instance", class: 'btn btn-default', :target => "_blank" do
98+
= link_to admin_lms_accesses_path, title: "Update your access token for the selected LMS instance", class: 'btn btn-default', :target => "_blank" do
9899
%i.glyphicon.glyphicon-new-window
99100
#lms-access-token-check.col-xs-1.fa.fa-check
100101

101102
.form-group
102-
= label_tag :name, 'Canvas course Id', class: 'control-label col-xs-2'
103+
= label_tag :name, 'LMS course Id', class: 'control-label col-xs-2'
103104
.col-lg-4.col-md-4.col-xs-4
104105
= text_field_tag :lms_course_id, nil, id: 'lms-course-num', class: 'form-control', maxlength: 25
105106
%small.col-xs-11.text.text-warning
106-
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).
107+
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).
107108

108109
.form-group
109110
.col-xs-offset-2.col-xs-2
110-
%button#btn-submit-co.btn.btn-primary Submit
111+
%button#btn-submit-co.btn.btn-primary Create New Course Offering
112+
113+
.form-group
114+
.col-xs-offset-2.col-xs-2
115+
- textbook_lms_instance = LmsInstance.find_by(url: "TEXTBOOK")
116+
%button#btn-gen-textbook.btn.btn-primary{disabled:textbook_lms_instance.blank?} Create Non LMS Textbook
117+
%small.col-xs-11.text.text-warning
118+
= textbook_lms_instance.blank? ? 'Textbook LMS Instance not found' : ''
119+
111120

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

0 commit comments

Comments
 (0)