Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions conf/defaults.config
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,7 @@ $authen{admin_module} = ['WeBWorK::Authen::Basic_TheLastOption'];
modify_tags => "admin",
edit_restricted_files => "admin",

# Permission to render problems using the WebworkWebservice.
# Permission to render problems using the render_rpc endpoint.
# Users with only webservice_render_problem can render problems with a provided filename.
# Users with both permissions can also render problems with providing the problem source.
# Note the Problem Editor requires having both permissions.
Expand Down Expand Up @@ -1303,7 +1303,7 @@ $pgRoot = $pg{directories}{root};
################################################################################
# Webservices
################################################################################
# The following options only apply to actions performed via requests to $webwork_url/instructor_rpc.
# The following options only apply to actions performed via API requests to $webwork_url/api.
$webservices = {
# Enable createCourse, addUser, dropUser, deleteUser, editUser, and changeUserPassword
enableCourseActions => 0,
Expand Down
12 changes: 3 additions & 9 deletions htdocs/js/GatewayQuiz/gateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,6 @@
}
};

const basicWebserviceURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/instructor_rpc`;

const updateTimeDelta = async () => {
const authenParams = {};
const user = document.getElementsByName('user')[0];
Expand All @@ -166,14 +164,10 @@
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);

const response = await fetch(basicWebserviceURL, {
const response = await fetch(`${webworkConfig?.webwork_url ?? '/webwork2'}/api/getCurrentServerTime`, {
method: 'post',
mode: 'same-origin',
body: new URLSearchParams({
...authenParams,
rpc_command: 'getCurrentServerTime',
courseID: timerDiv.dataset.courseId
}),
body: new URLSearchParams({ ...authenParams, courseID: timerDiv.dataset.courseId }),
signal: controller.signal
}).catch(() => {
/* Errors are ignored */
Expand All @@ -183,7 +177,7 @@

if (response && response.ok) {
const data = await response.json();
timeDelta = Math.round(new Date().getTime() / 1000) - data.result_data.currentServerTime;
timeDelta = Math.round(new Date().getTime() / 1000) - data.currentServerTime;
}
};

Expand Down
61 changes: 34 additions & 27 deletions htdocs/js/PGProblemEditor/pgproblemeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
bsToast.show();
};

const webserviceURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/instructor_rpc`;
const apiURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/api`;

// Send a request to the server to save the temporary file for the currently edited file.
// This temporary file could be used for recovery, and is displayed if the page is reloaded.
Expand All @@ -136,7 +136,6 @@
const sessionKey = document.getElementsByName('key')[0];
if (sessionKey) request_object.key = sessionKey.value;

request_object.rpc_command = 'saveFile';
request_object.outputFilePath = document.getElementsByName('temp_file_path')[0]?.value ?? '';
request_object.fileContents =
webworkConfig?.pgCodeMirror?.source ?? document.getElementById('problemContents')?.value ?? '';
Expand All @@ -151,11 +150,14 @@
revertRadio.checked = true;
}

fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
fetch(`${apiURL}/saveFile`, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
.then((response) => response.json())
.then((data) => {
showMessage(data.server_response, data.result_data);
if (data.result_data) {
if (data.error) {
showMessage(data.error);
} else {
showMessage(data.message, true);

// Add the temporary file coloring and change the current file to the saved file.
document.querySelectorAll('.set-file-info').forEach((nfo) => nfo.classList.add('temporaryFile'));
for (const currentFile of document.querySelectorAll('.current-file')) {
Expand Down Expand Up @@ -217,35 +219,37 @@
const sessionKey = document.getElementsByName('key')[0];
if (sessionKey) request_object.key = sessionKey.value;

request_object.rpc_command = 'tidyPGCode';
request_object.pgCode =
webworkConfig?.pgCodeMirror?.source ?? document.getElementById('problemContents')?.value ?? '';

fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
fetch(`${apiURL}/tidyPGCode`, {
method: 'post',
mode: 'same-origin',
body: new URLSearchParams(request_object)
})
.then((response) => response.json())
.then((data) => {
if (data.error) throw new Error(data.error);
if (!data.result_data) throw new Error('An invalid response was received.');
if (data.result_data.status) {
if (data.result_data.errors) {
if (data.status) {
if (data.errors) {
renderArea.innerHTML =
'<div class="alert alert-danger p-1 m-2">' +
'<p class="fw-bold">PG perltidy errors:</p>' +
'<pre><code>' +
data.result_data.errors
data.errors
.replace(/^[\s\S]*Begin Error Output Stream\n\n/, '')
.replace(/\n\d*: To save a full \.LOG file rerun with -g/, '') +
'</code></pre>';
}
showMessage('Errors occurred perltidying code.', false);
return;
}
if (request_object.pgCode === data.result_data.tidiedPGCode) {
if (request_object.pgCode === data.tidiedPGCode) {
showMessage('There were no changes to the code.', true);
if (!(renderArea.firstChild instanceof HTMLIFrameElement)) render();
} else {
if (webworkConfig?.pgCodeMirror) webworkConfig.pgCodeMirror.source = data.result_data.tidiedPGCode;
else document.getElementById('problemContents').value = data.result_data.tidiedPGCode;
if (webworkConfig?.pgCodeMirror) webworkConfig.pgCodeMirror.source = data.tidiedPGCode;
else document.getElementById('problemContents').value = data.tidiedPGCode;
saveTempFile();
showMessage('Successfully perltidied code.', true);
if (!(renderArea.firstChild instanceof HTMLIFrameElement)) render();
Expand All @@ -263,30 +267,31 @@
const sessionKey = document.getElementsByName('key')[0];
if (sessionKey) request_object.key = sessionKey.value;

request_object.rpc_command = 'convertCodeToPGML';
request_object.pgCode =
webworkConfig?.pgCodeMirror?.source ?? document.getElementById('problemContents')?.value ?? '';

fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
fetch(`${apiURL}/convertCodeToPGML`, {
method: 'post',
mode: 'same-origin',
body: new URLSearchParams(request_object)
})
.then((response) => response.json())
.then((data) => {
if (data.error) throw new Error(data.error);
if (!data.result_data) throw new Error('An invalid response was received.');
if (data.result_data.error) {
if (data.error) {
renderArea.innerHTML =
'<div class="alert alert-danger p-1 m-2">' +
'<p class="fw-bold">PGML conversion error:</p>' +
data.result_data.error +
data.error +
'</div>';

showMessage('Errors occurred when converting code to PGML.', false);
return;
}
if (request_object.pgCode === data.result_data.pgmlCode) {
if (request_object.pgCode === data.pgmlCode) {
showMessage('There were no changes to the code.', true);
} else {
if (webworkConfig?.pgCodeMirror) webworkConfig.pgCodeMirror.source = data.result_data.pgmlCode;
else document.getElementById('problemContents').value = data.result_data.pgmlCode;
if (webworkConfig?.pgCodeMirror) webworkConfig.pgCodeMirror.source = data.pgmlCode;
else document.getElementById('problemContents').value = data.pgmlCode;
saveTempFile();
showMessage('Successfully converted code to PGML', true);
if (!(renderArea.firstChild instanceof HTMLIFrameElement)) render();
Expand All @@ -304,16 +309,18 @@
const sessionKey = document.getElementsByName('key')[0];
if (sessionKey) request_object.key = sessionKey.value;

request_object.rpc_command = 'runPGCritic';
request_object.pgCode =
webworkConfig?.pgCodeMirror?.source ?? document.getElementById('problemContents')?.value ?? '';

fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
fetch(`${apiURL}/runPGCritic`, {
method: 'post',
mode: 'same-origin',
body: new URLSearchParams(request_object)
})
.then((response) => response.json())
.then((data) => {
if (data.error) throw new Error(data.error);
if (!data.result_data) throw new Error('An invalid response was received.');
renderArea.innerHTML = data.result_data.html;
renderArea.innerHTML = data.html;
scrollToRenderArea();
})
.catch((err) => showMessage(`Error: ${err?.message ?? err}`));
Expand Down
41 changes: 21 additions & 20 deletions htdocs/js/ProblemGrader/singleproblemgrader.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,29 +107,31 @@
}

// Save the score.
const basicWebserviceURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/instructor_rpc`;
const apiURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/api`;

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);

try {
const response = await fetch(basicWebserviceURL, {
method: 'post',
mode: 'same-origin',
body: new URLSearchParams({
...authenParams,
rpc_command: saveData.versionId !== '0' ? 'putProblemVersion' : 'putUserProblem',
courseID: saveData.courseId,
user_id: saveData.studentId,
set_id: saveData.setId,
version_id: saveData.versionId,
problem_id: saveData.problemId,
status: parseInt(scoreInput.value) / 100,
...(saveData.saveSubStatus === '1' ? { sub_status: parseInt(scoreInput.value) / 100 } : {}),
mark_graded: true
}),
signal: controller.signal
});
const response = await fetch(
`${apiURL}/${saveData.versionId !== '0' ? 'putProblemVersion' : 'putUserProblem'}`,
{
method: 'post',
mode: 'same-origin',
body: new URLSearchParams({
...authenParams,
courseID: saveData.courseId,
user_id: saveData.studentId,
set_id: saveData.setId,
version_id: saveData.versionId,
problem_id: saveData.problemId,
status: parseInt(scoreInput.value) / 100,
...(saveData.saveSubStatus === '1' ? { sub_status: parseInt(scoreInput.value) / 100 } : {}),
mark_graded: true
}),
signal: controller.signal
}
);

clearTimeout(timeoutId);

Expand Down Expand Up @@ -170,11 +172,10 @@
const timeoutId = setTimeout(() => controller.abort(), 10000);

try {
const response = await fetch(basicWebserviceURL, {
const response = await fetch(`${apiURL}/putPastAnswer`, {
method: 'post',
body: new URLSearchParams({
...authenParams,
rpc_command: 'putPastAnswer',
courseID: saveData.courseId,
answer_id: saveData.pastAnswerId,
comment_string: comment
Expand Down
Loading