From 22e323cae5a2ac2ee3816e1437de7ffa31ae0de4 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 15 Dec 2020 14:55:00 -0600 Subject: [PATCH 01/56] Update raw templates for Jinja2 --- .../sphinx_bootstrap/layout.html | 46 +++++++++---------- .../sphinx_bootstrap/subchaptoc.html | 29 +++++++----- 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html index d7dc45ecb..f2c86731b 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html @@ -1,7 +1,7 @@ {% extends "basic/layout.html" %} {% if dynamic_pages == 'True' %} - {% set appname = '{{ =request.application }}' %} + {% set appname = '{{ request.application }}' %} {% endif %} @@ -41,7 +41,7 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ =course_name }} + {{ course_name }} {% endraw %} {% else %} {% if course_title -%}{{ course_title|e }}{%- else -%}{{ course_id|e }}{%- endif -%} @@ -234,17 +234,17 @@ {% raw %} eBookConfig.useRunestoneServices = true; eBookConfig.host = ''; - eBookConfig.app = eBookConfig.host + '/' + '{{= request.application }}'; - eBookConfig.course = '{{= course_name }}'; - eBookConfig.basecourse = '{{= base_course }}'; - eBookConfig.isLoggedIn = {{= is_logged_in}}; - eBookConfig.email = '{{= user_email }}'; - eBookConfig.isInstructor = {{= is_instructor }}; - eBookConfig.username = '{{= user_id}}'; - eBookConfig.readings = {{= readings}}; - eBookConfig.activities = {{= XML(activity_info) }} - eBookConfig.downloadsEnabled = {{=downloads_enabled}}; - eBookConfig.allow_pairs = {{=allow_pairs}} + eBookConfig.app = eBookConfig.host + '/' + '{{ request.application }}'; + eBookConfig.course = '{{ course_name }}'; + eBookConfig.basecourse = '{{ base_course }}'; + eBookConfig.isLoggedIn = {{ is_logged_in}}; + eBookConfig.email = '{{ user_email }}'; + eBookConfig.isInstructor = {{ is_instructor }}; + eBookConfig.username = '{{ user_id}}'; + eBookConfig.readings = {{ readings}}; + eBookConfig.activities = {{ activity_info }} + eBookConfig.downloadsEnabled = {{downloads_enabled}}; + eBookConfig.allow_pairs = {{allow_pairs}} {% endraw %} {% else %} eBookConfig.useRunestoneServices = {% if use_services == 'true' -%}true{%- else -%}false{%- endif -%}; @@ -272,9 +272,9 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if response.serve_ad and settings.adsenseid: }} - - {{ pass }} + {% if settings.serve_ad and settings.adsenseid %} + + {% endif %} {% endraw %} {% endif %} @@ -310,16 +310,16 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if settings.num_banners > 0 and settings.show_rs_banner: }} + {% if settings.num_banners > 0 and settings.show_rs_banner %}
- + Please Support Runestone
- {{ pass }} + {% endif %} {% endraw %} {% endif %} @@ -370,10 +370,10 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if request.application == 'runestone':}} + {% if request.application == 'runestone' %} - {{ pass }} + {% endif %} {% endraw %} {% if minimal_outside_links != 'True' %} diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html index 5f0c3639d..145058256 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html @@ -1,14 +1,19 @@ - + From 723cb349a3576b912bdc5af68bc44ebf8e6bbcfe Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 17 Dec 2020 13:59:34 -0600 Subject: [PATCH 02/56] update endpoint for logBookEvent --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index c17b2e25c..8f54f197c 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -77,7 +77,7 @@ export default class RunestoneBase { eventInfo.percent = this.percent; } if (eBookConfig.useRunestoneServices && eBookConfig.logLevel > 0) { - let request = new Request(eBookConfig.ajaxURL + "hsblog", { + let request = new Request("/logger/bookevent", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(eventInfo), From 075020ad579755792fbce3875e3ee319969e93a5 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 15 Dec 2020 14:55:00 -0600 Subject: [PATCH 03/56] Update raw templates for Jinja2 --- .../sphinx_bootstrap/layout.html | 48 +++++++++---------- .../sphinx_bootstrap/subchaptoc.html | 29 ++++++----- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html index 74eef922b..91b0df534 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html @@ -1,7 +1,7 @@ {% extends "basic/layout.html" %} {% if dynamic_pages == 'True' %} - {% set appname = '{{ =request.application }}' %} + {% set appname = '{{ request.application }}' %} {% endif %} @@ -41,7 +41,7 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ =course_name }} + {{ course_name }} {% endraw %} {% else %} {% if course_title -%}{{ course_title|e }}{%- else -%}{{ course_id|e }}{%- endif -%} @@ -234,18 +234,18 @@ {% raw %} eBookConfig.useRunestoneServices = true; eBookConfig.host = ''; - eBookConfig.app = eBookConfig.host + '/' + '{{= request.application }}'; - eBookConfig.course = '{{= course_name }}'; - eBookConfig.basecourse = '{{= base_course }}'; - eBookConfig.isLoggedIn = {{= is_logged_in}}; - eBookConfig.email = '{{= user_email }}'; - eBookConfig.isInstructor = {{= is_instructor }}; - eBookConfig.username = '{{= user_id}}'; - eBookConfig.readings = {{= readings}}; - eBookConfig.activities = {{= XML(activity_info) }} - eBookConfig.downloadsEnabled = {{=downloads_enabled}}; - eBookConfig.allow_pairs = {{=allow_pairs}} - eBookConfig.enableCompareMe = {{=enable_compare_me }}; + eBookConfig.app = eBookConfig.host + '/' + '{{ request.application }}'; + eBookConfig.course = '{{ course_name }}'; + eBookConfig.basecourse = '{{ base_course }}'; + eBookConfig.isLoggedIn = {{ is_logged_in}}; + eBookConfig.email = '{{ user_email }}'; + eBookConfig.isInstructor = {{ is_instructor }}; + eBookConfig.username = '{{ user_id}}'; + eBookConfig.readings = {{ readings}}; + eBookConfig.activities = {{ activity_info }} + eBookConfig.downloadsEnabled = {{ downloads_enabled}}; + eBookConfig.allow_pairs = {{ allow_pairs}} + eBookConfig.enableCompareMe = {{ enable_compare_me }}; {% endraw %} {% else %} eBookConfig.useRunestoneServices = {% if use_services == 'true' -%}true{%- else -%}false{%- endif -%}; @@ -274,9 +274,9 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if response.serve_ad and settings.adsenseid: }} - - {{ pass }} + {% if settings.serve_ad and settings.adsenseid %} + + {% endif %} {% endraw %} {% endif %} @@ -299,16 +299,16 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if settings.num_banners > 0 and settings.show_rs_banner: }} + {% if settings.num_banners > 0 and settings.show_rs_banner %}
- + Please Support Runestone
- {{ pass }} + {% endif %} {% endraw %} {% endif %} @@ -359,10 +359,10 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if request.application == 'runestone':}} + {% if request.application == 'runestone' %} - {{ pass }} + {% endif %} {% endraw %} {% if minimal_outside_links != 'True' %} diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html index 5f0c3639d..145058256 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html @@ -1,14 +1,19 @@ - + From dc8fd330e7a9688bfcb0b4fd8791b60ae6d1d5eb Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 5 May 2021 14:54:16 -0500 Subject: [PATCH 04/56] Move timezone offset to fetch --- runestone/common/js/bookfuncs.js | 34 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index b307aae97..f830200f9 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,9 +99,8 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${ - position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { @@ -196,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } @@ -206,12 +205,29 @@ class PageProgressBar { export var pageProgressTracker = {}; -function handlePageSetup() { +async function handlePageSetup() { var mess; - if (eBookConfig.useRunestoneServices) { - jQuery.get(eBookConfig.ajaxURL + "set_tz_offset", { - timezoneoffset: new Date().getTimezoneOffset() / 60, - }); + let headers = new Headers({ + "Content-type": "application/json; charset=utf-8", + Accept: "application/json", + }); + let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 } + let request = new Request( + "/logger/set_tz_offset", + { + method: "POST", + body: JSON.stringify(data), + headers: headers, + } + ); + try { + let response = await fetch(request); + if (response.status != 200) { + console.log(`Failed to set timezone! ${response.statusText}`) + } + data = await response.json(); + } catch (e) { + } if (eBookConfig.isLoggedIn) { From 024b8502f2ac6329e703d8784a71e38861fee7fd Mon Sep 17 00:00:00 2001 From: bjones1 Date: Thu, 6 May 2021 01:17:21 +0000 Subject: [PATCH 05/56] Fix: Enable use with SQLite. --- runestone/server/componentdb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runestone/server/componentdb.py b/runestone/server/componentdb.py index f0c8f732e..8105a208c 100644 --- a/runestone/server/componentdb.py +++ b/runestone/server/componentdb.py @@ -123,7 +123,9 @@ def setup(app): logger.info("Connecting to DB") try: dburl = get_dburl() - engine = create_engine(dburl, client_encoding="utf8", convert_unicode=True) + # SQLite doesn't support ``client_encoding``, while PostgreSQL does. + encoding = dict(client_encoding="utf8") if dburl.startswith("postgresql") else {} + engine = create_engine(dburl, convert_unicode=True, **encoding) Session = sessionmaker() engine.connect() Session.configure(bind=engine) @@ -383,6 +385,7 @@ def addQuestionToDB(self): question_name=id_, ) sess.execute(ins) + sess.commit() def addQNumberToDB(app, node, qnumber): From 20355b509a7e53b69677522da1e3a912641e63b7 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 6 May 2021 07:25:08 -0500 Subject: [PATCH 06/56] use new url for runlog --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 8f54f197c..e49decf16 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -118,7 +118,7 @@ export default class RunestoneBase { eventInfo.save_code = "True"; } if (eBookConfig.useRunestoneServices && eBookConfig.logLevel > 0) { - let request = new Request(eBookConfig.ajaxURL + "runlog.json", { + let request = new Request("/logger/runlog", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(eventInfo), From e10e7e8bf8a706137e9a2143a9467bb3f1f4592e Mon Sep 17 00:00:00 2001 From: bjones1 Date: Mon, 10 May 2021 15:19:11 +0000 Subject: [PATCH 07/56] Fix: Use consistant naming between ajax and db tables. --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index c9b15bb96..401b2afc0 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -82,7 +82,7 @@ export default class RunestoneBase { return; } let post_return; - eventInfo.course = eBookConfig.course; + eventInfo.course_name = eBookConfig.course; eventInfo.clientLoginStatus = eBookConfig.isLoggedIn; eventInfo.timezoneoffset = new Date().getTimezoneOffset() / 60; if (this.percent) { From ea93387ee3663877d48a2378fa285cb10252506e Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 10 May 2021 16:18:57 -0700 Subject: [PATCH 08/56] update processing for getassessment --- runestone/common/js/runestonebase.js | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index c9b15bb96..181b9bc11 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -20,7 +20,9 @@ import { pageProgressTracker } from "./bookfuncs.js"; export default class RunestoneBase { constructor(opts) { - this.component_ready_promise = new Promise(resolve => this._component_ready_resolve_fn = resolve) + this.component_ready_promise = new Promise( + (resolve) => (this._component_ready_resolve_fn = resolve) + ); this.optional = false; if (opts) { this.sid = opts.sid; @@ -57,7 +59,7 @@ export default class RunestoneBase { // is to look for doAssignment in the URL and then grab // the assignment name from the heading. if (location.href.indexOf("doAssignment") >= 0) { - this.timedWrapper = $("h1#assignment_name").text() + this.timedWrapper = $("h1#assignment_name").text(); } else { this.timedWrapper = null; } @@ -102,7 +104,9 @@ export default class RunestoneBase { post_return = response.json(); } catch (e) { if (this.isTimed) { - alert(`Error: Your action was not saved! The error was ${e}`); + alert( + `Error: Your action was not saved! The error was ${e}` + ); } console.log(`Error: ${e}`); } @@ -192,19 +196,23 @@ export default class RunestoneBase { data.sid = this.sid; } if (!eBookConfig.practice_mode && this.assessmentTaken) { - let request = new Request( - eBookConfig.ajaxURL + "getAssessResults", - { - method: "POST", - body: JSON.stringify(data), - headers: this.jsonHeaders, - } - ); + let request = new Request("/assessment/results", { + method: "POST", + body: JSON.stringify(data), + headers: this.jsonHeaders, + }); try { let response = await fetch(request); - data = await response.json(); - this.repopulateFromStorage(data); - this.csresolver("server"); + if (response.ok) { + data = await response.json(); + data = data.detail; + this.repopulateFromStorage(data); + this.csresolver("server"); + } else { + alert( + `HTTP Error getting results: ${response.statusText}` + ); + } } catch (err) { try { this.checkLocalStorage(); From 166a1a468e9da82506d4b358d6d3aa910e8c8913 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:21:56 -0700 Subject: [PATCH 09/56] Better use of response detail from new server --- runestone/common/js/bookfuncs.js | 31 +++++++++++++--------------- runestone/common/js/runestonebase.js | 9 +++++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index ff8435879..0faf8675b 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,13 +99,13 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${ + position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { - text: - "This page is not part of the last reading assignment you visited.", + text: "This page is not part of the last reading assignment you visited.", }); } $("#main-content").append(l); @@ -195,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } @@ -211,23 +211,20 @@ async function handlePageSetup() { "Content-type": "application/json; charset=utf-8", Accept: "application/json", }); - let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 } - let request = new Request( - "/logger/set_tz_offset", - { - method: "POST", - body: JSON.stringify(data), - headers: headers, - } - ); + let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 }; + let request = new Request("/logger/set_tz_offset", { + method: "POST", + body: JSON.stringify(data), + headers: headers, + }); try { let response = await fetch(request); - if (response.status != 200) { - console.log(`Failed to set timezone! ${response.statusText}`) + if (!response.ok) { + console.error(`Failed to set timezone! ${response.statusText}`); } data = await response.json(); } catch (e) { - + console.error(`Error setting timezone ${e}`); } if (eBookConfig.isLoggedIn) { diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 2d6d67053..d8215000c 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -99,9 +99,12 @@ export default class RunestoneBase { try { let response = await fetch(request); if (!response.ok) { - throw new Error("Failed to save the log entry"); + let detail = await response.json(); + console.error(detail); + throw new Error(`Failed to save the log entry ${detail}`); + } else { + post_return = response.json(); } - post_return = response.json(); } catch (e) { if (this.isTimed) { alert( @@ -260,7 +263,7 @@ export default class RunestoneBase { */ repopulateFromStorage(data) { // decide whether to use the server's answer (if there is one) or to load from storage - if (data !== null && this.shouldUseServer(data)) { + if (data !== null && data !== "no data" && this.shouldUseServer(data)) { this.restoreAnswers(data); this.setLocalStorage(data); } else { From 627236b98de301e546fbce5330a9abfdc7d792a4 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:22:13 -0700 Subject: [PATCH 10/56] bump esversion --- .jshintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jshintrc b/.jshintrc index 5950318e8..84c4059c0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -7,7 +7,7 @@ "allVisualizers", "console" ], - "esversion": 6, + "esversion": 8, "quotmark": true, "strict": "implied", "sub": true, From c2f1c0d90b762ec222f6d3f566d1881ef60ac1a4 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 12 May 2021 13:46:58 +0000 Subject: [PATCH 11/56] Docs: correct Intersphinx links. --- index.rst | 2 +- runestone/common/js/runestonebase.js | 12 ++++-------- runestone/timed/js/timed.js | 2 ++ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/index.rst b/index.rst index 926725c4a..4aa8134d4 100644 --- a/index.rst +++ b/index.rst @@ -3,7 +3,7 @@ Runestone Components ******************** This site documents the working of the Runestone Components. See the `Runestone Interactive Overview `_ or the `Runestone instructor's guide `_. -Demo linking to the Runestone Server docs: `assignments/grades_report endpoint`. +Demo linking to the Runestone Server docs: :ref:`assignments/grades_report endpoint`. Getting started diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index d8215000c..2d9b2e23b 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -74,10 +74,8 @@ export default class RunestoneBase { }); } - // .. _logBookEvent: - // - // logBookEvent - // ------------ + // _`logBookEvent` + //---------------- // This function sends the provided ``eventInfo`` to the `hsblog endpoint` of the server. Awaiting this function returns either ``undefined`` (if Runestone services are not available) or the data returned by the server as a JavaScript object (already JSON-decoded). async logBookEvent(eventInfo) { if (this.graderactive) { @@ -127,10 +125,8 @@ export default class RunestoneBase { return post_return; } - // .. _logRunEvent: - // - // logRunEvent - // ----------- + // -`logRunEvent` + //--------------- // This function sends the provided ``eventInfo`` to the `runlog endpoint`. When awaited, this function returns the data (decoded from JSON) the server sent back. async logRunEvent(eventInfo) { let post_promise = "done"; diff --git a/runestone/timed/js/timed.js b/runestone/timed/js/timed.js index f5ae73402..1b96d6cee 100644 --- a/runestone/timed/js/timed.js +++ b/runestone/timed/js/timed.js @@ -997,6 +997,8 @@ export default class Timed extends RunestoneBase { }); localStorage.setItem(this.localStorageKey(), storageObj); } + // _`timed exam endpoint parameters` + //---------------------------------- logScore() { this.logBookEvent({ event: "timedExam", From 36daed5d556f1a81e5308b2c820c9d4e0dbd828c Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 26 May 2021 16:34:15 +0100 Subject: [PATCH 12/56] Fix: Provide sensible default values for more fields. --- runestone/server/componentdb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runestone/server/componentdb.py b/runestone/server/componentdb.py index 8105a208c..9184bf3a0 100644 --- a/runestone/server/componentdb.py +++ b/runestone/server/componentdb.py @@ -336,6 +336,7 @@ def addQuestionToDB(self): practice=practice, topic=topics, from_source=from_source, + review_flag='F', optional=optional, description=et, **meta_opts, @@ -583,7 +584,6 @@ def addAssignmentToDB( return course_id = getCourseID(course_name) - last_changed = datetime.now() sel = select([assignments]).where( and_(assignments.c.name == name, assignments.c.course == course_id) ) @@ -622,6 +622,7 @@ def addAssignmentToDB( visible=visible, time_limit=time_limit, from_source="T", + released="F", ) res = sess.execute(ins) a_id = res.inserted_primary_key[0] From 79373e8381b077e72769ee2b9af986e24d18c539 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 15 Dec 2020 14:55:00 -0600 Subject: [PATCH 13/56] Update raw templates for Jinja2 --- .../sphinx_bootstrap/layout.html | 48 +++++++++---------- .../sphinx_bootstrap/subchaptoc.html | 29 ++++++----- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html index 77d19456b..0dadc54ff 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html @@ -1,7 +1,7 @@ {% extends "basic/layout.html" %} {% if dynamic_pages == 'True' %} - {% set appname = '{{ =request.application }}' %} + {% set appname = '{{ request.application }}' %} {% endif %} @@ -41,7 +41,7 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ =course_name }} + {{ course_name }} {% endraw %} {% else %} {% if course_title -%}{{ course_title|e }}{%- else -%}{{ course_id|e }}{%- endif -%} @@ -234,18 +234,18 @@ {% raw %} eBookConfig.useRunestoneServices = true; eBookConfig.host = ''; - eBookConfig.app = eBookConfig.host + '/' + '{{= request.application }}'; - eBookConfig.course = '{{= course_name }}'; - eBookConfig.basecourse = '{{= base_course }}'; - eBookConfig.isLoggedIn = {{= is_logged_in}}; - eBookConfig.email = '{{= user_email }}'; - eBookConfig.isInstructor = {{= is_instructor }}; - eBookConfig.username = '{{= user_id}}'; - eBookConfig.readings = {{= readings}}; - eBookConfig.activities = {{= XML(activity_info) }} - eBookConfig.downloadsEnabled = {{=downloads_enabled}}; - eBookConfig.allow_pairs = {{=allow_pairs}} - eBookConfig.enableCompareMe = {{=enable_compare_me }}; + eBookConfig.app = eBookConfig.host + '/' + '{{ request.application }}'; + eBookConfig.course = '{{ course_name }}'; + eBookConfig.basecourse = '{{ base_course }}'; + eBookConfig.isLoggedIn = {{ is_logged_in}}; + eBookConfig.email = '{{ user_email }}'; + eBookConfig.isInstructor = {{ is_instructor }}; + eBookConfig.username = '{{ user_id}}'; + eBookConfig.readings = {{ readings}}; + eBookConfig.activities = {{ activity_info }} + eBookConfig.downloadsEnabled = {{downloads_enabled}}; + eBookConfig.allow_pairs = {{allow_pairs}} + eBookConfig.enableCompareMe = {{enable_compare_me}}; {% endraw %} {% else %} eBookConfig.useRunestoneServices = {% if use_services == 'true' -%}true{%- else -%}false{%- endif -%}; @@ -274,9 +274,9 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if response.serve_ad and settings.adsenseid: }} - - {{ pass }} + {% if settings.serve_ad and settings.adsenseid %} + + {% endif %} {% endraw %} {% endif %} @@ -299,16 +299,16 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if settings.num_banners > 0 and settings.show_rs_banner: }} + {% if settings.num_banners > 0 and settings.show_rs_banner %} - {{ pass }} + {% endif %} {% endraw %} {% endif %} @@ -359,10 +359,10 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if request.application == 'runestone':}} + {% if request.application == 'runestone' %} - {{ pass }} + {% endif %} {% endraw %} {% if minimal_outside_links != 'True' %} diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html index 5f0c3639d..145058256 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html @@ -1,14 +1,19 @@ - + From 75a3dfcd3da54e3e1569b1493ee1f4d954fbbf53 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 17 Dec 2020 13:59:34 -0600 Subject: [PATCH 14/56] update endpoint for logBookEvent --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 619e8474e..5f8295769 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -89,7 +89,7 @@ export default class RunestoneBase { eventInfo.percent = this.percent; } if (eBookConfig.useRunestoneServices && eBookConfig.logLevel > 0) { - let request = new Request(eBookConfig.ajaxURL + "hsblog", { + let request = new Request("/logger/bookevent", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(eventInfo), From 5c8f9ed6867cd61303601783ca4e53e51ac2d7c2 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 30 Dec 2020 11:31:01 -0600 Subject: [PATCH 15/56] clarify what is provided for course_name --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 5f8295769..baf53a917 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -82,7 +82,7 @@ export default class RunestoneBase { return; } let post_return; - eventInfo.course = eBookConfig.course; + eventInfo.course_name = eBookConfig.course; eventInfo.clientLoginStatus = eBookConfig.isLoggedIn; eventInfo.timezoneoffset = new Date().getTimezoneOffset() / 60; if (this.percent) { From f1f0d3a2f622ad7d564bb9812a1ae85804d47662 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 7 Jun 2021 11:06:05 -0500 Subject: [PATCH 16/56] update url for assessment results --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index baf53a917..421117443 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -193,7 +193,7 @@ export default class RunestoneBase { } if (!eBookConfig.practice_mode && this.assessmentTaken) { let request = new Request( - eBookConfig.ajaxURL + "getAssessResults", + "/assessment/results", { method: "POST", body: JSON.stringify(data), From 70f6179b0e6a3d7180e5a473e5070e637df00951 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 8 Jun 2021 16:40:32 -0500 Subject: [PATCH 17/56] update for gethist and runlog --- runestone/activecode/js/activecode.js | 32 +++++++++++++++------------ runestone/common/js/runestonebase.js | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index bf60c122b..6e60dcecf 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -470,8 +470,8 @@ export class ActiveCode extends RunestoneBase { if (!didAgree) { didAgree = confirm( "Pair Programming should only be used with the consent of your instructor." + - "Your partner must be a registered member of the class and have agreed to pair with you." + - "By clicking OK you certify that both of these conditions have been met." + "Your partner must be a registered member of the class and have agreed to pair with you." + + "By clicking OK you certify that both of these conditions have been met." ); if (didAgree) { localStorage.setItem("partnerAgree", "true"); @@ -514,13 +514,13 @@ export class ActiveCode extends RunestoneBase { $(butt).attr( "href", "http://" + - chatcodesServer + - "/new?" + - $.param({ - topic: window.location.host + "-" + this.divid, - code: this.editor.getValue(), - lang: "Python", - }) + chatcodesServer + + "/new?" + + $.param({ + topic: window.location.host + "-" + this.divid, + code: this.editor.getValue(), + lang: "Python", + }) ); this.chatButton = butt; chatBar.appendChild(butt); @@ -574,7 +574,7 @@ export class ActiveCode extends RunestoneBase { // If this is timed and already taken we should restore history info this.renderScrubber(); } else { - let request = new Request(eBookConfig.ajaxURL + "gethist.json", { + let request = new Request("/assessment/gethist", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(reqData), @@ -582,6 +582,10 @@ export class ActiveCode extends RunestoneBase { try { response = await fetch(request); let data = await response.json(); + if (!response.ok) { + throw new Error(`Failed to get the history data: ${data.detail}`); + } + data = data.detail; if (data.history !== undefined) { this.history = this.history.concat(data.history); for (let t in data.timestamps) { @@ -591,7 +595,7 @@ export class ActiveCode extends RunestoneBase { } } } catch (e) { - console.log("unable to fetch history"); + console.log(`unable to fetch history: ${e}`); } this.renderScrubber(pos_last); } @@ -907,7 +911,7 @@ export class ActiveCode extends RunestoneBase { }); } - toggleEditorVisibility() {} + toggleEditorVisibility() { } addErrorMessage(err) { // Add the error message @@ -1045,7 +1049,7 @@ Yet another is that there is an internal error. The internal error message is: var xl = eval(x); xl = xl.map(pyStr); x = xl.join(" "); - } catch (err) {} + } catch (err) { } } } $(this.output).css("visibility", "visible"); @@ -1149,7 +1153,7 @@ Yet another is that there is an internal error. The internal error message is: if ( this.historyScrubber && this.history[$(this.historyScrubber).slider("value")] != - this.editor.getValue() + this.editor.getValue() ) { saveCode = "True"; this.history.push(this.editor.getValue()); diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 421117443..2e673f834 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -137,7 +137,7 @@ export default class RunestoneBase { eventInfo.save_code = "True"; } if (eBookConfig.useRunestoneServices && eBookConfig.logLevel > 0) { - let request = new Request(eBookConfig.ajaxURL + "runlog.json", { + let request = new Request("/logger/runlog", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(eventInfo), From 9b5a74ef3b028aae252faadd6192fdfc613323b7 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 10 Jun 2021 11:35:53 -0500 Subject: [PATCH 18/56] make version 6.0.0dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index afe459016..72bbb9521 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ with open("requirements.txt", "r", encoding="utf-8") as fh: dependencies = [l.strip() for l in fh] -VERSION = "5.6.1" +VERSION = "6.0.0dev" # These pre-install hooks are useful to make sure any pre-requisite # programs that are not pip installable are in place. From 294c0554a2de699cefef2eb392d4a003ff7d8be9 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 5 May 2021 14:54:16 -0500 Subject: [PATCH 19/56] Move timezone offset to fetch --- runestone/common/js/bookfuncs.js | 34 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index 977c4f775..671b156d8 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,9 +99,8 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${ - position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { @@ -196,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } @@ -206,12 +205,29 @@ class PageProgressBar { export var pageProgressTracker = {}; -function handlePageSetup() { +async function handlePageSetup() { var mess; - if (eBookConfig.useRunestoneServices) { - jQuery.get(eBookConfig.ajaxURL + "set_tz_offset", { - timezoneoffset: new Date().getTimezoneOffset() / 60, - }); + let headers = new Headers({ + "Content-type": "application/json; charset=utf-8", + Accept: "application/json", + }); + let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 } + let request = new Request( + "/logger/set_tz_offset", + { + method: "POST", + body: JSON.stringify(data), + headers: headers, + } + ); + try { + let response = await fetch(request); + if (response.status != 200) { + console.log(`Failed to set timezone! ${response.statusText}`) + } + data = await response.json(); + } catch (e) { + } if (eBookConfig.isLoggedIn) { From bcb3eca6bfa703bc8340d1778998db6bc7aacca4 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Thu, 6 May 2021 01:17:21 +0000 Subject: [PATCH 20/56] Fix: Enable use with SQLite. --- runestone/server/componentdb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runestone/server/componentdb.py b/runestone/server/componentdb.py index 4ce690175..f5cfb5522 100644 --- a/runestone/server/componentdb.py +++ b/runestone/server/componentdb.py @@ -128,7 +128,9 @@ def setup(app): logger.info("Connecting to DB") try: dburl = get_dburl() - engine = create_engine(dburl, client_encoding="utf8", convert_unicode=True) + # SQLite doesn't support ``client_encoding``, while PostgreSQL does. + encoding = dict(client_encoding="utf8") if dburl.startswith("postgresql") else {} + engine = create_engine(dburl, convert_unicode=True, **encoding) Session = sessionmaker() engine.connect() Session.configure(bind=engine) @@ -388,6 +390,7 @@ def addQuestionToDB(self): question_name=id_, ) sess.execute(ins) + sess.commit() def addQNumberToDB(app, node, qnumber): From 52e3dfc97cf65c8d3c866c71ff4c88ca8eca9630 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 26 May 2021 16:34:37 +0100 Subject: [PATCH 21/56] Fix: Update for newer feedback format from the bookserver. --- runestone/fitb/js/fitb.js | 1 + 1 file changed, 1 insertion(+) diff --git a/runestone/fitb/js/fitb.js b/runestone/fitb/js/fitb.js index ae960292a..c20c7ec17 100644 --- a/runestone/fitb/js/fitb.js +++ b/runestone/fitb/js/fitb.js @@ -227,6 +227,7 @@ export default class FITB extends RunestoneBase { correct: this.correct ? "T" : "F", div_id: this.divid, }); + data = data.detail; if (!this.feedbackArray) { // On success, update the feedback from the server's grade. this.setLocalStorage({ From 1716eba995d69285eafefe562b6ab706523d0503 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Sun, 30 May 2021 00:05:16 +0100 Subject: [PATCH 22/56] Fix: Update to newer feedback format from the server for lp questions. --- .../css/runestone-custom-sphinx-bootstrap.css | 2 +- runestone/lp/js/lp.js | 83 ++++++++++++++++--- runestone/lp/lp.py | 4 +- 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/runestone/common/css/runestone-custom-sphinx-bootstrap.css b/runestone/common/css/runestone-custom-sphinx-bootstrap.css index a5b65f95f..a8c5f80a4 100644 --- a/runestone/common/css/runestone-custom-sphinx-bootstrap.css +++ b/runestone/common/css/runestone-custom-sphinx-bootstrap.css @@ -863,7 +863,7 @@ ul.dropdown-menu.globaltoc { /* Style lp textareas. */ -textarea#lp-result { +textarea.lp-result { width: 100%; height: 10em; font-family: monospace; diff --git a/runestone/lp/js/lp.js b/runestone/lp/js/lp.js index 60358767b..1575f78dc 100644 --- a/runestone/lp/js/lp.js +++ b/runestone/lp/js/lp.js @@ -48,9 +48,9 @@ class LP extends RunestoneBase { this.containerDiv = this.element; this.divid = this.element.id; // Store the DOM element (the textarea) where compile results will be displayed. - this.resultElement = $(this.element).siblings("textarea"); - // Store the DOM element (a span) where feedback will be displayed. - this.feedbackElement = $(this.element).siblings("div"); + this.resultElement = $(this.element).siblings(".lp-result"); + // Store the DOM element (a div) where feedback will be displayed. + this.feedbackElement = $(this.element).siblings(".lp-feedback").children("div"); // Use a nice editor. let that = this; this.textAreas = []; @@ -78,13 +78,62 @@ class LP extends RunestoneBase { this.checkServer("lp_build", true); } + // Data structures: + // + // Format of data stored locally and on the server*:: + // + // - answer: JSON-encoded string containing { + // code_snippets: [ + // str, snippet 1, ... + // ], + // (optional) resultString: str, output from build. + // } + // - correct: (optional) float, a percentage from 0 to 100. + // - timestamp: date/time in UTC. + // + // Format of data sent to the server*:: + // + // - answer: JSON-encoded string containing only the code_snippets + // array, not resultString. There's no point in sending the + // previous resultString, since the server will compute a new + // one. + // - event: "lp_build" + // - act: "", since the useinfo table requires it. It's not + // otherwise used. + // - path: str, giving the relative path to this web page. Used + // to find the source code which produced this page in order + // to do snippet replacement. + // - div_id: str, the div_id of this component. + // + // Format of data received from the server:: + // + // If there was an error: + // - errors: [ + // str, error message 1, ... + // ] + // + // Otherwise: + // - answer: JSON-encoded string containing { + // resultString: str, output from build. + // Note that the code_snippets aren't sent back, to save + // bandwidth. + // } + // - correct: float, a percentage from 0 to 100. + // - timestamp: str, the server's timestamp. + // + // * For simplicity, I omitted the common fields (course, etc.) and discussed only fields unique to this component. + async onSaveAndRun(_eventObject) { + // Prevent multiple click while the build is running. + $(this.element).attr("disabled", true); $(this.resultElement).val("Building..."); $(this.feedbackElement).text("").attr(""); // Since the Save and run button was clicked, we assume the code snippets have been changed; therefore, don't store ``correct`` or ``answer.resultString`` because they are out of date. - let answer = { code_snippets: this.textareasToData() }; + // + // Store the answer as a string, since this is what goes in to / comes out from the database. We have to translate this back to a data structure when restoring from the db or local storage. + let code_snippets = this.textareasToData(); this.setLocalStorage({ - answer: answer, + answer: JSON.stringify({code_snippets: code_snippets}), timestamp: new Date(), }); // Store the answer that the server returns, which includes additional data (correct/incorrect, feedback from the build, etc.). @@ -92,8 +141,9 @@ class LP extends RunestoneBase { try { serverAnswer = await this.logBookEvent({ event: "lp_build", - // All values must be strings, or the resulting values on the server side come out confused. - answer: JSON.stringify(answer), + answer: JSON.stringify(code_snippets), + // This is required by useinfo, but not used. + act: "", // Find the relative path to this web page. Slice off the leading ``/``. path: window.location.href .replace(eBookConfig.app, "") @@ -105,13 +155,19 @@ class LP extends RunestoneBase { .val(`Error contacting server: {err}.`) .attr("class", "alert alert-danger"); return; + } finally { + // Always re-enable the button after the server responds. + $(this.element).attr("disabled", false); } + serverAnswer = serverAnswer.detail; // The server doesn't return the ``code_snippets``, for efficiency. Include those. If an error was returned, note that there is no ``answer`` yet. if (!("answer" in serverAnswer)) { - serverAnswer["answer"] = {}; + serverAnswer.answer = {}; } - serverAnswer["answer"]["code_snippets"] = this.textareasToData(); + serverAnswer.answer.code_snippets = code_snippets; this.displayAnswer(serverAnswer); + // JSON-encode the answer for storage. + serverAnswer.answer = JSON.stringify(serverAnswer.answer); this.setLocalStorage(serverAnswer); } @@ -142,6 +198,7 @@ class LP extends RunestoneBase { $(this.resultElement).scrollTop(this.resultElement[0].scrollHeight); } } + // Store the contents of each textarea into an array of strings. textareasToData() { return $.map(this.textAreas, function (obj, index) { @@ -149,6 +206,7 @@ class LP extends RunestoneBase { return obj.getValue(); }); } + // Store an array of strings in ``data.code_snippets`` into each textarea. dataToTextareas(data) { // Find all code snippet textareas. @@ -157,11 +215,15 @@ class LP extends RunestoneBase { value.setValue((data.answer.code_snippets || "")[index] || ""); }); } + // Restore answers from storage retrieval done in RunestoneBase. restoreAnswers(data) { + // We store the answer as a JSON-encoded string in the db / local storage. Restore the actual data structure from it. + data.answer = JSON.parse(data.answer); this.dataToTextareas(data); this.displayAnswer(data); } + checkLocalStorage() { // Loads previous answers from local storage if they exist. var storedData; @@ -181,6 +243,7 @@ class LP extends RunestoneBase { } } } + setLocalStorage(data) { localStorage.setItem(this.localStorageKey(), JSON.stringify(data)); } @@ -192,7 +255,7 @@ class LP extends RunestoneBase { $(document).bind("runestone:login-complete", function () { $("[data-component=lp_build]").each(function (index) { try { - LPList[this.id] = new LP({ + window.LPList[this.id] = new LP({ orig: this, useRunestoneServices: eBookConfig.useRunestoneServices, }); diff --git a/runestone/lp/lp.py b/runestone/lp/lp.py index bba8b9fbf..89cd6a2f7 100644 --- a/runestone/lp/lp.py +++ b/runestone/lp/lp.py @@ -164,9 +164,9 @@ def depart_lp_node(self, node): {}
- +
-
+
""".format( "".join(self.body), node.runestone_options["language"], id_ ) From 63b712e27b78f15f3930a9ce390467b309737e95 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 10 May 2021 16:18:57 -0700 Subject: [PATCH 23/56] update processing for getassessment --- runestone/common/js/runestonebase.js | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 2e673f834..2d6d67053 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -20,7 +20,9 @@ import { pageProgressTracker } from "./bookfuncs.js"; export default class RunestoneBase { constructor(opts) { - this.component_ready_promise = new Promise(resolve => this._component_ready_resolve_fn = resolve) + this.component_ready_promise = new Promise( + (resolve) => (this._component_ready_resolve_fn = resolve) + ); this.optional = false; if (opts) { this.sid = opts.sid; @@ -57,7 +59,7 @@ export default class RunestoneBase { // is to look for doAssignment in the URL and then grab // the assignment name from the heading. if (location.href.indexOf("doAssignment") >= 0) { - this.timedWrapper = $("h1#assignment_name").text() + this.timedWrapper = $("h1#assignment_name").text(); } else { this.timedWrapper = null; } @@ -102,7 +104,9 @@ export default class RunestoneBase { post_return = response.json(); } catch (e) { if (this.isTimed) { - alert(`Error: Your action was not saved! The error was ${e}`); + alert( + `Error: Your action was not saved! The error was ${e}` + ); } console.log(`Error: ${e}`); } @@ -192,19 +196,23 @@ export default class RunestoneBase { data.sid = this.sid; } if (!eBookConfig.practice_mode && this.assessmentTaken) { - let request = new Request( - "/assessment/results", - { - method: "POST", - body: JSON.stringify(data), - headers: this.jsonHeaders, - } - ); + let request = new Request("/assessment/results", { + method: "POST", + body: JSON.stringify(data), + headers: this.jsonHeaders, + }); try { let response = await fetch(request); - data = await response.json(); - this.repopulateFromStorage(data); - this.csresolver("server"); + if (response.ok) { + data = await response.json(); + data = data.detail; + this.repopulateFromStorage(data); + this.csresolver("server"); + } else { + alert( + `HTTP Error getting results: ${response.statusText}` + ); + } } catch (err) { try { this.checkLocalStorage(); From cef664495fb9843fb18b9772a2b7e2d0961e8558 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:21:56 -0700 Subject: [PATCH 24/56] Better use of response detail from new server --- runestone/common/js/bookfuncs.js | 31 +++++++++++++--------------- runestone/common/js/runestonebase.js | 9 +++++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index 671b156d8..3a887c841 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,13 +99,13 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${ + position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { - text: - "This page is not part of the last reading assignment you visited.", + text: "This page is not part of the last reading assignment you visited.", }); } $("#main-content").append(l); @@ -195,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } @@ -211,23 +211,20 @@ async function handlePageSetup() { "Content-type": "application/json; charset=utf-8", Accept: "application/json", }); - let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 } - let request = new Request( - "/logger/set_tz_offset", - { - method: "POST", - body: JSON.stringify(data), - headers: headers, - } - ); + let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 }; + let request = new Request("/logger/set_tz_offset", { + method: "POST", + body: JSON.stringify(data), + headers: headers, + }); try { let response = await fetch(request); - if (response.status != 200) { - console.log(`Failed to set timezone! ${response.statusText}`) + if (!response.ok) { + console.error(`Failed to set timezone! ${response.statusText}`); } data = await response.json(); } catch (e) { - + console.error(`Error setting timezone ${e}`); } if (eBookConfig.isLoggedIn) { diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 2d6d67053..d8215000c 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -99,9 +99,12 @@ export default class RunestoneBase { try { let response = await fetch(request); if (!response.ok) { - throw new Error("Failed to save the log entry"); + let detail = await response.json(); + console.error(detail); + throw new Error(`Failed to save the log entry ${detail}`); + } else { + post_return = response.json(); } - post_return = response.json(); } catch (e) { if (this.isTimed) { alert( @@ -260,7 +263,7 @@ export default class RunestoneBase { */ repopulateFromStorage(data) { // decide whether to use the server's answer (if there is one) or to load from storage - if (data !== null && this.shouldUseServer(data)) { + if (data !== null && data !== "no data" && this.shouldUseServer(data)) { this.restoreAnswers(data); this.setLocalStorage(data); } else { From 79eb08b5756c7617a481de170dfe71135fa1fdb4 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:22:13 -0700 Subject: [PATCH 25/56] bump esversion --- .jshintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jshintrc b/.jshintrc index 5950318e8..84c4059c0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -7,7 +7,7 @@ "allVisualizers", "console" ], - "esversion": 6, + "esversion": 8, "quotmark": true, "strict": "implied", "sub": true, From 29bad630f3c79006003f1e4d96ac53d2ea6ac257 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 12 May 2021 13:46:58 +0000 Subject: [PATCH 26/56] Docs: correct Intersphinx links. --- index.rst | 2 ++ runestone/common/js/runestonebase.js | 12 ++++-------- runestone/timed/js/timed.js | 2 ++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.rst b/index.rst index 29ee51628..4aa8134d4 100644 --- a/index.rst +++ b/index.rst @@ -3,6 +3,8 @@ Runestone Components ******************** This site documents the working of the Runestone Components. See the `Runestone Interactive Overview `_ or the `Runestone instructor's guide `_. +Demo linking to the Runestone Server docs: :ref:`assignments/grades_report endpoint`. + Getting started =============== diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index d8215000c..2d9b2e23b 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -74,10 +74,8 @@ export default class RunestoneBase { }); } - // .. _logBookEvent: - // - // logBookEvent - // ------------ + // _`logBookEvent` + //---------------- // This function sends the provided ``eventInfo`` to the `hsblog endpoint` of the server. Awaiting this function returns either ``undefined`` (if Runestone services are not available) or the data returned by the server as a JavaScript object (already JSON-decoded). async logBookEvent(eventInfo) { if (this.graderactive) { @@ -127,10 +125,8 @@ export default class RunestoneBase { return post_return; } - // .. _logRunEvent: - // - // logRunEvent - // ----------- + // -`logRunEvent` + //--------------- // This function sends the provided ``eventInfo`` to the `runlog endpoint`. When awaited, this function returns the data (decoded from JSON) the server sent back. async logRunEvent(eventInfo) { let post_promise = "done"; diff --git a/runestone/timed/js/timed.js b/runestone/timed/js/timed.js index f5ae73402..1b96d6cee 100644 --- a/runestone/timed/js/timed.js +++ b/runestone/timed/js/timed.js @@ -997,6 +997,8 @@ export default class Timed extends RunestoneBase { }); localStorage.setItem(this.localStorageKey(), storageObj); } + // _`timed exam endpoint parameters` + //---------------------------------- logScore() { this.logBookEvent({ event: "timedExam", From 1c7be0d4a4eac600f74e412fe8fb12344c4265e5 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 26 May 2021 16:34:15 +0100 Subject: [PATCH 27/56] Fix: Provide sensible default values for more fields. --- runestone/server/componentdb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runestone/server/componentdb.py b/runestone/server/componentdb.py index f5cfb5522..3ca7c27be 100644 --- a/runestone/server/componentdb.py +++ b/runestone/server/componentdb.py @@ -341,6 +341,7 @@ def addQuestionToDB(self): practice=practice, topic=topics, from_source=from_source, + review_flag='F', optional=optional, description=et, **meta_opts, @@ -588,7 +589,6 @@ def addAssignmentToDB( return course_id = getCourseID(course_name) - last_changed = datetime.now() sel = select([assignments]).where( and_(assignments.c.name == name, assignments.c.course == course_id) ) @@ -627,6 +627,7 @@ def addAssignmentToDB( visible=visible, time_limit=time_limit, from_source="T", + released="F", ) res = sess.execute(ins) a_id = res.inserted_primary_key[0] From 7e1ba8d14ba5f2cccc14a85d85ce221570194ad8 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 10 Jun 2021 11:35:53 -0500 Subject: [PATCH 28/56] make version 6.0.0dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index afe459016..72bbb9521 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ with open("requirements.txt", "r", encoding="utf-8") as fh: dependencies = [l.strip() for l in fh] -VERSION = "5.6.1" +VERSION = "6.0.0dev" # These pre-install hooks are useful to make sure any pre-requisite # programs that are not pip installable are in place. From 52e52eb8665292551a55d55282ae26c65338da81 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Mon, 31 May 2021 16:18:26 +0100 Subject: [PATCH 29/56] Fix: Log data to answer, instead of act field. --- runestone/clickableArea/js/clickable.js | 4 +++- runestone/shortanswer/js/shortanswer.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/runestone/clickableArea/js/clickable.js b/runestone/clickableArea/js/clickable.js index 9329fe901..3a0b19327 100644 --- a/runestone/clickableArea/js/clickable.js +++ b/runestone/clickableArea/js/clickable.js @@ -400,9 +400,11 @@ export default class ClickableArea extends RunestoneBase { } logCurrentAnswer() { + const answer = this.givenIndexArray.join(";"); this.logBookEvent({ event: "clickableArea", - act: this.givenIndexArray.join(";"), + answer: answer, + act: answer, div_id: this.divid, correct: this.correct ? "T" : "F", }); diff --git a/runestone/shortanswer/js/shortanswer.js b/runestone/shortanswer/js/shortanswer.js index e011c9aac..aaeaab245 100644 --- a/runestone/shortanswer/js/shortanswer.js +++ b/runestone/shortanswer/js/shortanswer.js @@ -152,6 +152,7 @@ export default class ShortAnswer extends RunestoneBase { this.logBookEvent({ event: "shortanswer", act: value, + answer: value, div_id: this.divid, }); } From 1a4c91606ae6cae0dbffe414cf5a735a3c244d23 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 15 Dec 2020 14:55:00 -0600 Subject: [PATCH 30/56] Update raw templates for Jinja2 --- .../sphinx_bootstrap/layout.html | 48 +++++++++---------- .../sphinx_bootstrap/subchaptoc.html | 29 ++++++----- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html index 77d19456b..0dadc54ff 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/layout.html @@ -1,7 +1,7 @@ {% extends "basic/layout.html" %} {% if dynamic_pages == 'True' %} - {% set appname = '{{ =request.application }}' %} + {% set appname = '{{ request.application }}' %} {% endif %} @@ -41,7 +41,7 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ =course_name }} + {{ course_name }} {% endraw %} {% else %} {% if course_title -%}{{ course_title|e }}{%- else -%}{{ course_id|e }}{%- endif -%} @@ -234,18 +234,18 @@ {% raw %} eBookConfig.useRunestoneServices = true; eBookConfig.host = ''; - eBookConfig.app = eBookConfig.host + '/' + '{{= request.application }}'; - eBookConfig.course = '{{= course_name }}'; - eBookConfig.basecourse = '{{= base_course }}'; - eBookConfig.isLoggedIn = {{= is_logged_in}}; - eBookConfig.email = '{{= user_email }}'; - eBookConfig.isInstructor = {{= is_instructor }}; - eBookConfig.username = '{{= user_id}}'; - eBookConfig.readings = {{= readings}}; - eBookConfig.activities = {{= XML(activity_info) }} - eBookConfig.downloadsEnabled = {{=downloads_enabled}}; - eBookConfig.allow_pairs = {{=allow_pairs}} - eBookConfig.enableCompareMe = {{=enable_compare_me }}; + eBookConfig.app = eBookConfig.host + '/' + '{{ request.application }}'; + eBookConfig.course = '{{ course_name }}'; + eBookConfig.basecourse = '{{ base_course }}'; + eBookConfig.isLoggedIn = {{ is_logged_in}}; + eBookConfig.email = '{{ user_email }}'; + eBookConfig.isInstructor = {{ is_instructor }}; + eBookConfig.username = '{{ user_id}}'; + eBookConfig.readings = {{ readings}}; + eBookConfig.activities = {{ activity_info }} + eBookConfig.downloadsEnabled = {{downloads_enabled}}; + eBookConfig.allow_pairs = {{allow_pairs}} + eBookConfig.enableCompareMe = {{enable_compare_me}}; {% endraw %} {% else %} eBookConfig.useRunestoneServices = {% if use_services == 'true' -%}true{%- else -%}false{%- endif -%}; @@ -274,9 +274,9 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if response.serve_ad and settings.adsenseid: }} - - {{ pass }} + {% if settings.serve_ad and settings.adsenseid %} + + {% endif %} {% endraw %} {% endif %} @@ -299,16 +299,16 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if settings.num_banners > 0 and settings.show_rs_banner: }} + {% if settings.num_banners > 0 and settings.show_rs_banner %} - {{ pass }} + {% endif %} {% endraw %} {% endif %} @@ -359,10 +359,10 @@ {% if dynamic_pages == 'True' %} {% raw %} - {{ if request.application == 'runestone':}} + {% if request.application == 'runestone' %} - {{ pass }} + {% endif %} {% endraw %} {% if minimal_outside_links != 'True' %} diff --git a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html index 5f0c3639d..145058256 100644 --- a/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html +++ b/runestone/common/project_template/_templates/plugin_layouts/sphinx_bootstrap/subchaptoc.html @@ -1,14 +1,19 @@ - + From a27183e10d6e5f306149815238c3fa637f35c624 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 17 Dec 2020 13:59:34 -0600 Subject: [PATCH 31/56] update endpoint for logBookEvent --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 619e8474e..5f8295769 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -89,7 +89,7 @@ export default class RunestoneBase { eventInfo.percent = this.percent; } if (eBookConfig.useRunestoneServices && eBookConfig.logLevel > 0) { - let request = new Request(eBookConfig.ajaxURL + "hsblog", { + let request = new Request("/logger/bookevent", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(eventInfo), From 334b1ff5f608e7674d50bade0907fcd2a917f9d3 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 30 Dec 2020 11:31:01 -0600 Subject: [PATCH 32/56] clarify what is provided for course_name --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 5f8295769..baf53a917 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -82,7 +82,7 @@ export default class RunestoneBase { return; } let post_return; - eventInfo.course = eBookConfig.course; + eventInfo.course_name = eBookConfig.course; eventInfo.clientLoginStatus = eBookConfig.isLoggedIn; eventInfo.timezoneoffset = new Date().getTimezoneOffset() / 60; if (this.percent) { From ea9d16ebdbc25d29f3bd3f026bed6bb748162c1d Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 7 Jun 2021 11:06:05 -0500 Subject: [PATCH 33/56] update url for assessment results --- runestone/common/js/runestonebase.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index baf53a917..421117443 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -193,7 +193,7 @@ export default class RunestoneBase { } if (!eBookConfig.practice_mode && this.assessmentTaken) { let request = new Request( - eBookConfig.ajaxURL + "getAssessResults", + "/assessment/results", { method: "POST", body: JSON.stringify(data), From 2a85455434d46b5aa6c35aa9715247048b309e3c Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 8 Jun 2021 16:40:32 -0500 Subject: [PATCH 34/56] update for gethist and runlog --- runestone/activecode/js/activecode.js | 32 +++++++++++++++------------ runestone/common/js/runestonebase.js | 2 +- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index bf60c122b..6e60dcecf 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -470,8 +470,8 @@ export class ActiveCode extends RunestoneBase { if (!didAgree) { didAgree = confirm( "Pair Programming should only be used with the consent of your instructor." + - "Your partner must be a registered member of the class and have agreed to pair with you." + - "By clicking OK you certify that both of these conditions have been met." + "Your partner must be a registered member of the class and have agreed to pair with you." + + "By clicking OK you certify that both of these conditions have been met." ); if (didAgree) { localStorage.setItem("partnerAgree", "true"); @@ -514,13 +514,13 @@ export class ActiveCode extends RunestoneBase { $(butt).attr( "href", "http://" + - chatcodesServer + - "/new?" + - $.param({ - topic: window.location.host + "-" + this.divid, - code: this.editor.getValue(), - lang: "Python", - }) + chatcodesServer + + "/new?" + + $.param({ + topic: window.location.host + "-" + this.divid, + code: this.editor.getValue(), + lang: "Python", + }) ); this.chatButton = butt; chatBar.appendChild(butt); @@ -574,7 +574,7 @@ export class ActiveCode extends RunestoneBase { // If this is timed and already taken we should restore history info this.renderScrubber(); } else { - let request = new Request(eBookConfig.ajaxURL + "gethist.json", { + let request = new Request("/assessment/gethist", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(reqData), @@ -582,6 +582,10 @@ export class ActiveCode extends RunestoneBase { try { response = await fetch(request); let data = await response.json(); + if (!response.ok) { + throw new Error(`Failed to get the history data: ${data.detail}`); + } + data = data.detail; if (data.history !== undefined) { this.history = this.history.concat(data.history); for (let t in data.timestamps) { @@ -591,7 +595,7 @@ export class ActiveCode extends RunestoneBase { } } } catch (e) { - console.log("unable to fetch history"); + console.log(`unable to fetch history: ${e}`); } this.renderScrubber(pos_last); } @@ -907,7 +911,7 @@ export class ActiveCode extends RunestoneBase { }); } - toggleEditorVisibility() {} + toggleEditorVisibility() { } addErrorMessage(err) { // Add the error message @@ -1045,7 +1049,7 @@ Yet another is that there is an internal error. The internal error message is: var xl = eval(x); xl = xl.map(pyStr); x = xl.join(" "); - } catch (err) {} + } catch (err) { } } } $(this.output).css("visibility", "visible"); @@ -1149,7 +1153,7 @@ Yet another is that there is an internal error. The internal error message is: if ( this.historyScrubber && this.history[$(this.historyScrubber).slider("value")] != - this.editor.getValue() + this.editor.getValue() ) { saveCode = "True"; this.history.push(this.editor.getValue()); diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 421117443..2e673f834 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -137,7 +137,7 @@ export default class RunestoneBase { eventInfo.save_code = "True"; } if (eBookConfig.useRunestoneServices && eBookConfig.logLevel > 0) { - let request = new Request(eBookConfig.ajaxURL + "runlog.json", { + let request = new Request("/logger/runlog", { method: "POST", headers: this.jsonHeaders, body: JSON.stringify(eventInfo), From db198590c4a97f22c9d19c47902c78d875998ab2 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 5 May 2021 14:54:16 -0500 Subject: [PATCH 35/56] Move timezone offset to fetch --- runestone/common/js/bookfuncs.js | 34 +++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index 977c4f775..671b156d8 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,9 +99,8 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${ - position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { @@ -196,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } @@ -206,12 +205,29 @@ class PageProgressBar { export var pageProgressTracker = {}; -function handlePageSetup() { +async function handlePageSetup() { var mess; - if (eBookConfig.useRunestoneServices) { - jQuery.get(eBookConfig.ajaxURL + "set_tz_offset", { - timezoneoffset: new Date().getTimezoneOffset() / 60, - }); + let headers = new Headers({ + "Content-type": "application/json; charset=utf-8", + Accept: "application/json", + }); + let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 } + let request = new Request( + "/logger/set_tz_offset", + { + method: "POST", + body: JSON.stringify(data), + headers: headers, + } + ); + try { + let response = await fetch(request); + if (response.status != 200) { + console.log(`Failed to set timezone! ${response.statusText}`) + } + data = await response.json(); + } catch (e) { + } if (eBookConfig.isLoggedIn) { From 36304c84ef8025913521c8bd75e61b62161d6a29 Mon Sep 17 00:00:00 2001 From: bjones1 Date: Thu, 6 May 2021 01:17:21 +0000 Subject: [PATCH 36/56] Fix: Enable use with SQLite. --- runestone/server/componentdb.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runestone/server/componentdb.py b/runestone/server/componentdb.py index 4ce690175..f5cfb5522 100644 --- a/runestone/server/componentdb.py +++ b/runestone/server/componentdb.py @@ -128,7 +128,9 @@ def setup(app): logger.info("Connecting to DB") try: dburl = get_dburl() - engine = create_engine(dburl, client_encoding="utf8", convert_unicode=True) + # SQLite doesn't support ``client_encoding``, while PostgreSQL does. + encoding = dict(client_encoding="utf8") if dburl.startswith("postgresql") else {} + engine = create_engine(dburl, convert_unicode=True, **encoding) Session = sessionmaker() engine.connect() Session.configure(bind=engine) @@ -388,6 +390,7 @@ def addQuestionToDB(self): question_name=id_, ) sess.execute(ins) + sess.commit() def addQNumberToDB(app, node, qnumber): From bd6d0fd20e5ffd17fc71c5e06064db2e106ce12c Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 10 May 2021 16:18:57 -0700 Subject: [PATCH 37/56] update processing for getassessment --- runestone/common/js/runestonebase.js | 36 +++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 2e673f834..2d6d67053 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -20,7 +20,9 @@ import { pageProgressTracker } from "./bookfuncs.js"; export default class RunestoneBase { constructor(opts) { - this.component_ready_promise = new Promise(resolve => this._component_ready_resolve_fn = resolve) + this.component_ready_promise = new Promise( + (resolve) => (this._component_ready_resolve_fn = resolve) + ); this.optional = false; if (opts) { this.sid = opts.sid; @@ -57,7 +59,7 @@ export default class RunestoneBase { // is to look for doAssignment in the URL and then grab // the assignment name from the heading. if (location.href.indexOf("doAssignment") >= 0) { - this.timedWrapper = $("h1#assignment_name").text() + this.timedWrapper = $("h1#assignment_name").text(); } else { this.timedWrapper = null; } @@ -102,7 +104,9 @@ export default class RunestoneBase { post_return = response.json(); } catch (e) { if (this.isTimed) { - alert(`Error: Your action was not saved! The error was ${e}`); + alert( + `Error: Your action was not saved! The error was ${e}` + ); } console.log(`Error: ${e}`); } @@ -192,19 +196,23 @@ export default class RunestoneBase { data.sid = this.sid; } if (!eBookConfig.practice_mode && this.assessmentTaken) { - let request = new Request( - "/assessment/results", - { - method: "POST", - body: JSON.stringify(data), - headers: this.jsonHeaders, - } - ); + let request = new Request("/assessment/results", { + method: "POST", + body: JSON.stringify(data), + headers: this.jsonHeaders, + }); try { let response = await fetch(request); - data = await response.json(); - this.repopulateFromStorage(data); - this.csresolver("server"); + if (response.ok) { + data = await response.json(); + data = data.detail; + this.repopulateFromStorage(data); + this.csresolver("server"); + } else { + alert( + `HTTP Error getting results: ${response.statusText}` + ); + } } catch (err) { try { this.checkLocalStorage(); From 39298d258b6fe972641de7a77b28a50933ed1da1 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:21:56 -0700 Subject: [PATCH 38/56] Better use of response detail from new server --- runestone/common/js/bookfuncs.js | 31 +++++++++++++--------------- runestone/common/js/runestonebase.js | 9 +++++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index 671b156d8..3a887c841 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,13 +99,13 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${ + position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { - text: - "This page is not part of the last reading assignment you visited.", + text: "This page is not part of the last reading assignment you visited.", }); } $("#main-content").append(l); @@ -195,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } @@ -211,23 +211,20 @@ async function handlePageSetup() { "Content-type": "application/json; charset=utf-8", Accept: "application/json", }); - let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 } - let request = new Request( - "/logger/set_tz_offset", - { - method: "POST", - body: JSON.stringify(data), - headers: headers, - } - ); + let data = { timezoneoffset: new Date().getTimezoneOffset() / 60 }; + let request = new Request("/logger/set_tz_offset", { + method: "POST", + body: JSON.stringify(data), + headers: headers, + }); try { let response = await fetch(request); - if (response.status != 200) { - console.log(`Failed to set timezone! ${response.statusText}`) + if (!response.ok) { + console.error(`Failed to set timezone! ${response.statusText}`); } data = await response.json(); } catch (e) { - + console.error(`Error setting timezone ${e}`); } if (eBookConfig.isLoggedIn) { diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index 2d6d67053..d8215000c 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -99,9 +99,12 @@ export default class RunestoneBase { try { let response = await fetch(request); if (!response.ok) { - throw new Error("Failed to save the log entry"); + let detail = await response.json(); + console.error(detail); + throw new Error(`Failed to save the log entry ${detail}`); + } else { + post_return = response.json(); } - post_return = response.json(); } catch (e) { if (this.isTimed) { alert( @@ -260,7 +263,7 @@ export default class RunestoneBase { */ repopulateFromStorage(data) { // decide whether to use the server's answer (if there is one) or to load from storage - if (data !== null && this.shouldUseServer(data)) { + if (data !== null && data !== "no data" && this.shouldUseServer(data)) { this.restoreAnswers(data); this.setLocalStorage(data); } else { From 8df3a8871570ca483f050bf29ec674c61b73fb07 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:22:13 -0700 Subject: [PATCH 39/56] bump esversion --- .jshintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jshintrc b/.jshintrc index 5950318e8..84c4059c0 100644 --- a/.jshintrc +++ b/.jshintrc @@ -7,7 +7,7 @@ "allVisualizers", "console" ], - "esversion": 6, + "esversion": 8, "quotmark": true, "strict": "implied", "sub": true, From 18bf3557a3e7795b5fb9925f76416626d204f31d Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 12 May 2021 13:46:58 +0000 Subject: [PATCH 40/56] Docs: correct Intersphinx links. --- index.rst | 2 ++ runestone/common/js/runestonebase.js | 12 ++++-------- runestone/timed/js/timed.js | 2 ++ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/index.rst b/index.rst index 29ee51628..4aa8134d4 100644 --- a/index.rst +++ b/index.rst @@ -3,6 +3,8 @@ Runestone Components ******************** This site documents the working of the Runestone Components. See the `Runestone Interactive Overview `_ or the `Runestone instructor's guide `_. +Demo linking to the Runestone Server docs: :ref:`assignments/grades_report endpoint`. + Getting started =============== diff --git a/runestone/common/js/runestonebase.js b/runestone/common/js/runestonebase.js index d8215000c..2d9b2e23b 100644 --- a/runestone/common/js/runestonebase.js +++ b/runestone/common/js/runestonebase.js @@ -74,10 +74,8 @@ export default class RunestoneBase { }); } - // .. _logBookEvent: - // - // logBookEvent - // ------------ + // _`logBookEvent` + //---------------- // This function sends the provided ``eventInfo`` to the `hsblog endpoint` of the server. Awaiting this function returns either ``undefined`` (if Runestone services are not available) or the data returned by the server as a JavaScript object (already JSON-decoded). async logBookEvent(eventInfo) { if (this.graderactive) { @@ -127,10 +125,8 @@ export default class RunestoneBase { return post_return; } - // .. _logRunEvent: - // - // logRunEvent - // ----------- + // -`logRunEvent` + //--------------- // This function sends the provided ``eventInfo`` to the `runlog endpoint`. When awaited, this function returns the data (decoded from JSON) the server sent back. async logRunEvent(eventInfo) { let post_promise = "done"; diff --git a/runestone/timed/js/timed.js b/runestone/timed/js/timed.js index f5ae73402..1b96d6cee 100644 --- a/runestone/timed/js/timed.js +++ b/runestone/timed/js/timed.js @@ -997,6 +997,8 @@ export default class Timed extends RunestoneBase { }); localStorage.setItem(this.localStorageKey(), storageObj); } + // _`timed exam endpoint parameters` + //---------------------------------- logScore() { this.logBookEvent({ event: "timedExam", From c15361776925dccc66c92b991de3359069993a8e Mon Sep 17 00:00:00 2001 From: bjones1 Date: Wed, 26 May 2021 16:34:15 +0100 Subject: [PATCH 41/56] Fix: Provide sensible default values for more fields. --- runestone/server/componentdb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runestone/server/componentdb.py b/runestone/server/componentdb.py index f5cfb5522..3ca7c27be 100644 --- a/runestone/server/componentdb.py +++ b/runestone/server/componentdb.py @@ -341,6 +341,7 @@ def addQuestionToDB(self): practice=practice, topic=topics, from_source=from_source, + review_flag='F', optional=optional, description=et, **meta_opts, @@ -588,7 +589,6 @@ def addAssignmentToDB( return course_id = getCourseID(course_name) - last_changed = datetime.now() sel = select([assignments]).where( and_(assignments.c.name == name, assignments.c.course == course_id) ) @@ -627,6 +627,7 @@ def addAssignmentToDB( visible=visible, time_limit=time_limit, from_source="T", + released="F", ) res = sess.execute(ins) a_id = res.inserted_primary_key[0] From 87c8cff02a2d684b7fadfb1f85f19afbcb5e8037 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 10 Jun 2021 11:35:53 -0500 Subject: [PATCH 42/56] make version 6.0.0dev --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index afe459016..72bbb9521 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ with open("requirements.txt", "r", encoding="utf-8") as fh: dependencies = [l.strip() for l in fh] -VERSION = "5.6.1" +VERSION = "6.0.0dev" # These pre-install hooks are useful to make sure any pre-requisite # programs that are not pip installable are in place. From 7aa5019358ee5edb24a852b926acdd936bc8bb60 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 5 May 2021 14:54:16 -0500 Subject: [PATCH 43/56] Move timezone offset to fetch --- runestone/common/js/bookfuncs.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index 3a887c841..15293d40c 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,9 +99,8 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${ - position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { @@ -195,7 +194,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } From 10055dd4e88c8e68c3337482f79f43050df7c518 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 11 May 2021 17:21:56 -0700 Subject: [PATCH 44/56] Better use of response detail from new server --- runestone/common/js/bookfuncs.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/runestone/common/js/bookfuncs.js b/runestone/common/js/bookfuncs.js index 15293d40c..3a887c841 100644 --- a/runestone/common/js/bookfuncs.js +++ b/runestone/common/js/bookfuncs.js @@ -99,8 +99,9 @@ function addReadingList() { name: "link", class: "btn btn-lg ' + 'buttonConfirmCompletion'", href: nxt_link, - text: `Continue to page ${position + 2 - } of ${num_readings} in the reading assignment.`, + text: `Continue to page ${ + position + 2 + } of ${num_readings} in the reading assignment.`, }); } else { l = $("
", { @@ -194,7 +195,7 @@ class PageProgressBar { if ( val == 100.0 && $("#completionButton").text().toLowerCase() === - "mark as completed" + "mark as completed" ) { $("#completionButton").click(); } From 9df9f8f7406dd8809cac4ece24280b1712fb78c0 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 15 Jun 2021 10:28:28 -0500 Subject: [PATCH 45/56] add ref label --- runestone/activecode/js/activecode.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runestone/activecode/js/activecode.js b/runestone/activecode/js/activecode.js index 6e60dcecf..7d2500977 100755 --- a/runestone/activecode/js/activecode.js +++ b/runestone/activecode/js/activecode.js @@ -554,6 +554,8 @@ export class ActiveCode extends RunestoneBase { $(this.runButton).text($.i18n("msg_activecode_save_run")); } + // _`addHistoryScrubber` + // --------------------- // Activecode -- If the code has not changed wrt the scrubber position value then don't save the code or reposition the scrubber // -- still call runlog, but add a parameter to not save the code // add an initial load history button From 5bc9de55011cb576b863d70174a54ef021c1cf56 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 16 Jun 2021 10:59:34 -0500 Subject: [PATCH 46/56] add bookfuncs to every page --- webpack.index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webpack.index.js b/webpack.index.js index 7e380f54e..35216a3f3 100644 --- a/webpack.index.js +++ b/webpack.index.js @@ -38,6 +38,7 @@ import "./runestone/common/project_template/_templates/plugin_layouts/sphinx_boo import "./runestone/common/css/runestone-custom-sphinx-bootstrap.css"; // Misc +import "./runestone/common/js/bookfuncs.js"; import "./runestone/common/js/user-highlights.js"; // These belong in dynamic imports for the obvious component; however, these components don't include a ``data-component`` attribute. @@ -95,7 +96,7 @@ export function runestone_auto_import() { $("[data-component]").map( // Extract the value of the data-component attribute. (index, element) => $(element).attr("data-component") - // Switch from a jQuery object back to an array, passing that to the Set constructor. + // Switch from a jQuery object back to an array, passing that to the Set constructor. ).get() ); From 3fbc9ee474db5e5d16640edd0555aabfd87db373 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Wed, 16 Jun 2021 11:00:37 -0500 Subject: [PATCH 47/56] use new endpoint for decorating toc --- runestone/common/js/user-highlights.js | 44 ++++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/runestone/common/js/user-highlights.js b/runestone/common/js/user-highlights.js index 68d73283a..7b6502e70 100644 --- a/runestone/common/js/user-highlights.js +++ b/runestone/common/js/user-highlights.js @@ -43,10 +43,10 @@ function getCompletions() { } $("#main-content").append( '
" + completionClass + + '" id="completionButton">' + + completionMsg + + "
" ); } }); @@ -57,8 +57,8 @@ function showLastPositionBanner() { if (typeof lastPositionVal !== "undefined") { $("body").append( '' + parseInt(lastPositionVal) + + 'px;"/>' ); $("html, body").animate({ scrollTop: parseInt(lastPositionVal) }, 1000); } @@ -158,6 +158,8 @@ function addNavigationAndCompletionButtons() { }); } +// _ decorateTableOfContents +// ------------------------- function decorateTableOfContents() { if ( window.location.href.toLowerCase().indexOf("toc.html") != -1 || @@ -183,8 +185,8 @@ function decorateTableOfContents() { .addClass("completed") .append( '- Completed this topic on ' + - item.endDate + - "" + item.endDate + + "" ) .children() .first() @@ -205,8 +207,8 @@ function decorateTableOfContents() { .addClass("active") .append( 'Last read this topic on ' + - item.endDate + - "" + item.endDate + + "" ) .children() .first() @@ -229,7 +231,7 @@ function decorateTableOfContents() { } }); var data = { course: eBookConfig.course }; - jQuery.get(eBookConfig.ajaxURL + "getlastpage", data, function (data) { + jQuery.get("/logger/getlastpage", data, function (data) { var lastPageData; if (data != "None") { lastPageData = $.parseJSON(data); @@ -238,16 +240,16 @@ function decorateTableOfContents() { .show() .html( '
You were Last Reading: ' + - lastPageData[0].lastPageChapter + - (lastPageData[0].lastPageSubchapter - ? " > " + - lastPageData[0].lastPageSubchapter - : "") + - ' Continue Reading
' + lastPageData[0].lastPageChapter + + (lastPageData[0].lastPageSubchapter + ? " > " + + lastPageData[0].lastPageSubchapter + : "") + + ' Continue Reading
' ); } } From 3cf96c7ee837f290e2240927ef9ca5db770c00fe Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 17 Jun 2021 09:22:29 -0500 Subject: [PATCH 48/56] fix updatelastpage --- runestone/common/js/user-highlights.js | 29 ++++++++++++++------------ 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/runestone/common/js/user-highlights.js b/runestone/common/js/user-highlights.js index 7b6502e70..1679a8e13 100644 --- a/runestone/common/js/user-highlights.js +++ b/runestone/common/js/user-highlights.js @@ -25,13 +25,13 @@ function getCompletions() { var data = { lastPageUrl: currentPathname }; jQuery .ajax({ - url: eBookConfig.ajaxURL + "getCompletionStatus", + url: "/logger/getCompletionStatus", data: data, async: false, }) .done(function (data) { if (data != "None") { - var completionData = $.parseJSON(data); + var completionData = data.detail; var completionClass, completionMsg; if (completionData[0].completionStatus == 1) { completionClass = "buttonConfirmCompletion"; @@ -165,12 +165,12 @@ function decorateTableOfContents() { window.location.href.toLowerCase().indexOf("toc.html") != -1 || window.location.href.toLowerCase().indexOf("index.html") != -1 ) { - jQuery.get(eBookConfig.ajaxURL + "getAllCompletionStatus", function ( + jQuery.get("/logger/getAllCompletionStatus", function ( data ) { var subChapterList; if (data != "None") { - subChapterList = $.parseJSON(data); + subChapterList = data; var allSubChapterURLs = $("#main-content div li a"); $.each(subChapterList, function (index, item) { @@ -234,21 +234,21 @@ function decorateTableOfContents() { jQuery.get("/logger/getlastpage", data, function (data) { var lastPageData; if (data != "None") { - lastPageData = $.parseJSON(data); - if (lastPageData[0].lastPageChapter != null) { + lastPageData = data.detail; + if (lastPageData.lastPageChapter != null) { $("#continue-reading") .show() .html( '
You were Last Reading: ' + - lastPageData[0].lastPageChapter + - (lastPageData[0].lastPageSubchapter + lastPageData.lastPageChapter + + (lastPageData.lastPageSubchapter ? " > " + - lastPageData[0].lastPageSubchapter + lastPageData.lastPageSubchapter : "") + ' Continue Reading
' ); } @@ -287,8 +287,11 @@ function processPageState(completionFlag) { console.log(e); }); jQuery.ajax({ - url: eBookConfig.ajaxURL + "updatelastpage", - data: data, + url: "/logger/updatelastpage", + contentType: "application/json; charset=utf-8", + dataType: "json", + data: JSON.stringify(data), + method: "POST", async: true, }); } From 56856b2d47a9205bf4ef30fa125623cb56601df4 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 17 Jun 2021 17:51:53 -0500 Subject: [PATCH 49/56] get detail add refrence links --- runestone/common/js/user-highlights.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runestone/common/js/user-highlights.js b/runestone/common/js/user-highlights.js index 1679a8e13..f8c3bc81a 100644 --- a/runestone/common/js/user-highlights.js +++ b/runestone/common/js/user-highlights.js @@ -170,7 +170,7 @@ function decorateTableOfContents() { ) { var subChapterList; if (data != "None") { - subChapterList = data; + subChapterList = data.detail; var allSubChapterURLs = $("#main-content div li a"); $.each(subChapterList, function (index, item) { @@ -267,6 +267,8 @@ function enableCompletions() { // call enable user highlights after login $(document).bind("runestone:login", enableCompletions); +// _ processPageState +// ------------------------- function processPageState(completionFlag) { /*Log last page visited*/ var currentPathname = window.location.pathname; From ff939ea992f32d9e99953f09f7dbc9a7c8c41238 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 21 Jun 2021 17:20:28 -0500 Subject: [PATCH 50/56] ensure we update page status --- runestone/common/js/user-highlights.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runestone/common/js/user-highlights.js b/runestone/common/js/user-highlights.js index f8c3bc81a..4be2cdba5 100644 --- a/runestone/common/js/user-highlights.js +++ b/runestone/common/js/user-highlights.js @@ -122,6 +122,9 @@ function addNavigationAndCompletionButtons() { } else { completionFlag = 1; } + // Make sure we mark this page as visited regardless of how flakey + // the onunload handlers become. + processPageState(completionFlag); $("#completionButton").on("click", function () { if ($(this).hasClass("buttonAskCompletion")) { $(this) From fd82dc40de62d49e3280f3648f295016ad58bfda Mon Sep 17 00:00:00 2001 From: bjones1 Date: Fri, 25 Jun 2021 13:06:54 +0100 Subject: [PATCH 51/56] Fix: Match name sent to server with table name in db. --- runestone/dragndrop/js/dragndrop.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runestone/dragndrop/js/dragndrop.js b/runestone/dragndrop/js/dragndrop.js index 54fdd4ed4..a179bac18 100644 --- a/runestone/dragndrop/js/dragndrop.js +++ b/runestone/dragndrop/js/dragndrop.js @@ -403,7 +403,7 @@ export default class DragNDrop extends RunestoneBase { event: "dragNdrop", act: answer, answer: answer, - minHeight: this.minheight, + min_height: this.minheight, div_id: this.divid, correct: this.correct, correctNum: this.correctNum, @@ -454,7 +454,7 @@ export default class DragNDrop extends RunestoneBase { restoreAnswers(data) { // Restore answers from storage retrieval done in RunestoneBase this.hasStoredDropzones = true; - this.minheight = data.minHeight; + this.minheight = data.min_height; this.pregnantIndexArray = data.answer.split(";"); this.finishSettingUp(); } @@ -471,7 +471,7 @@ export default class DragNDrop extends RunestoneBase { this.hasStoredDropzones = true; try { storedObj = JSON.parse(ex); - this.minheight = storedObj.minHeight; + this.minheight = storedObj.min_height; } catch (err) { // error while parsing; likely due to bad value stored in storage console.log(err.message); @@ -488,7 +488,7 @@ export default class DragNDrop extends RunestoneBase { event: "dragNdrop", act: answer, answer: answer, - minHeight: this.minheight, + min_height: this.minheight, div_id: this.divid, correct: storedObj.correct, }); @@ -522,7 +522,7 @@ export default class DragNDrop extends RunestoneBase { var correct = data.correct; var storageObj = { answer: this.pregnantIndexArray.join(";"), - minHeight: this.minheight, + min_height: this.minheight, timestamp: timeStamp, correct: correct, }; From 45228d47bd2c3f4439eb490cd2691a83adcbb5c0 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Sun, 11 Jul 2021 19:20:26 -0500 Subject: [PATCH 52/56] more bookserver updates --- runestone/mchoice/js/mchoice.js | 5 +++-- runestone/poll/js/poll.js | 31 +++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/runestone/mchoice/js/mchoice.js b/runestone/mchoice/js/mchoice.js index a3a5f522b..65fcbe9b2 100644 --- a/runestone/mchoice/js/mchoice.js +++ b/runestone/mchoice/js/mchoice.js @@ -571,7 +571,7 @@ export default class MultipleChoice extends RunestoneBase { return res; } compareModal(data, status, whatever) { - var datadict = JSON.parse(data)[0]; + var datadict = data.detail; var answers = datadict.answerDict; var misc = datadict.misc; var kl = Object.keys(answers).sort(); @@ -625,12 +625,13 @@ export default class MultipleChoice extends RunestoneBase { var el = $(html); el.modal(); } + // _`compareAnswers` compareAnswers() { var data = {}; data.div_id = this.divid; data.course = eBookConfig.course; jQuery.get( - eBookConfig.ajaxURL + "getaggregateresults", + "/assessment/getaggregateresults", data, this.compareModal.bind(this) ); diff --git a/runestone/poll/js/poll.js b/runestone/poll/js/poll.js index 319991bb0..148071745 100644 --- a/runestone/poll/js/poll.js +++ b/runestone/poll/js/poll.js @@ -148,24 +148,23 @@ export default class Poll extends RunestoneBase { data.div_id = this.divid; data.course = eBookConfig.course; jQuery.get( - eBookConfig.ajaxURL + "getpollresults", + "/assessment/getpollresults", data, this.showPollResults ); } } - showPollResults(data) { + showPollResults(results) { //displays the results returned by the server - var results = eval(data); - var total = results[0]; - var opt_list = results[1]; - var count_list = results[2]; - var div_id = results[3]; - var my_vote = results[4]; + results = results.detail; + var total = results["total"]; + var optCounts = results["opt_counts"] + var div_id = results["div_id"]; + // var my_vote = results[4]; // resture current users vote - if (my_vote > -1) { - this.optsArray[my_vote].checked = "checked"; - } + // if (my_vote > -1) { + // this.optsArray[my_vote].checked = "checked"; + // } // show results summary if appropriate if ( (this.resultsViewer === "all" && @@ -177,11 +176,11 @@ export default class Poll extends RunestoneBase { ); var list = $(document.createElement("div")); $(list).addClass("results-container"); - for (var i = 0; i < this.optionList.length; i++) { + for (let i in optCounts) { var count; var percent; - if (count_list[i]) { - count = count_list[i]; + if (optCounts[i] > 0) { + count = optCounts[i] percent = (count / total) * 100; } else { count = 0; @@ -215,7 +214,7 @@ export default class Poll extends RunestoneBase { } this.indicate_component_ready(); } - disableOptions() {} + disableOptions() { } checkPollStorage() { //checks the localstorage to see if the poll has been completed already var _this = this; @@ -226,7 +225,7 @@ export default class Poll extends RunestoneBase { data.div_id = this.divid; data.course = eBookConfig.course; jQuery.get( - eBookConfig.ajaxURL + "getpollresults", + "/assessment/getpollresults", data, this.showPollResults.bind(this) ).fail(this.indicate_component_ready.bind(this)); From 51b4de34abf3211cd27a680ac8ac3a43296583ab Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Mon, 12 Jul 2021 15:26:32 -0500 Subject: [PATCH 53/56] Polls are restored correctly --- runestone/poll/js/poll.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/runestone/poll/js/poll.js b/runestone/poll/js/poll.js index 148071745..9c185d83f 100644 --- a/runestone/poll/js/poll.js +++ b/runestone/poll/js/poll.js @@ -160,11 +160,11 @@ export default class Poll extends RunestoneBase { var total = results["total"]; var optCounts = results["opt_counts"] var div_id = results["div_id"]; - // var my_vote = results[4]; - // resture current users vote - // if (my_vote > -1) { - // this.optsArray[my_vote].checked = "checked"; - // } + var my_vote = results["my_vote"]; + // restore current users vote + if (my_vote > -1) { + this.optsArray[my_vote].checked = "checked"; + } // show results summary if appropriate if ( (this.resultsViewer === "all" && @@ -176,7 +176,7 @@ export default class Poll extends RunestoneBase { ); var list = $(document.createElement("div")); $(list).addClass("results-container"); - for (let i in optCounts) { + for (var i = 0; i < this.optionList.length; i++) { var count; var percent; if (optCounts[i] > 0) { From 3c0f505306b0ec27275a83ef66f5381ca84c71c4 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Tue, 13 Jul 2021 07:46:55 -0500 Subject: [PATCH 54/56] update fitb for bookserver --- runestone/fitb/js/fitb.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/runestone/fitb/js/fitb.js b/runestone/fitb/js/fitb.js index 3c1789ab8..6cb5dca1e 100644 --- a/runestone/fitb/js/fitb.js +++ b/runestone/fitb/js/fitb.js @@ -230,7 +230,7 @@ export default class FITB extends RunestoneBase { this.renderFeedback(); } return data; -} + } /*============================== === Evaluation of answer and === @@ -342,19 +342,20 @@ export default class FITB extends RunestoneBase { enableCompareButton() { this.compareButton.disabled = false; } + // _`compareFITBAnswers` compareFITBAnswers() { var data = {}; data.div_id = this.divid; data.course = eBookConfig.course; jQuery.get( - eBookConfig.ajaxURL + "gettop10Answers", + "/assessment/gettop10Answers", data, this.compareFITB ); } compareFITB(data, status, whatever) { - var answers = eval(data)[0]; - var misc = eval(data)[1]; + var answers = data.detail.res; + var misc = data.detail.miscdata; var body = ""; body += ""; for (var row in answers) { @@ -366,12 +367,6 @@ export default class FITB extends RunestoneBase { " times"; } body += "
AnswerCount
"; - if (misc["yourpct"] !== "unavailable") { - body += - "

You have " + - misc["yourpct"] + - "% correct for all questions

"; - } var html = "