Skip to content

Commit 481d26f

Browse files
authored
Merge pull request #11 from drdrew42/expand-catalog
2 parents 673c76d + e7bb999 commit 481d26f

File tree

6 files changed

+170
-36
lines changed

6 files changed

+170
-36
lines changed

lib/RenderApp.pm

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ sub startup {
9696
$r->any('/render-api/cat')->to('IO#catalog');
9797
$r->any('/render-api/find')->to('IO#search');
9898
$r->post('/render-api/upload')->to('IO#upload');
99+
$r->delete('/render-api/remove')->to('IO#remove');
100+
$r->post('/render-api/clone')->to('IO#clone');
99101
$r->post('/render-api/sma')->to('IO#findNewVersion');
100102
$r->post('/render-api/unique')->to('IO#findUniqueSeeds');
101103
$r->post('/render-api/tags')->to('IO#setTags');

lib/RenderApp/Controller/FormatRenderedProblem.pm

+26-21
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ sub formatRenderedProblem {
102102
my $problemHeadText = $rh_result->{header_text}//''; ##head_text vs header_text
103103
my $problemPostHeaderText = $rh_result->{post_header_text}//'';
104104
my $rh_answers = $rh_result->{answers}//{};
105-
my $answerOrder = $rh_result->{flags}->{ANSWER_ENTRY_ORDER}; #[sort keys %{ $rh_result->{answers} }];
105+
my $answerOrder = $rh_result->{flags}->{ANSWER_ENTRY_ORDER}//[]; #[sort keys %{ $rh_result->{answers} }];
106106
my $encoded_source = $self->encoded_source//'';
107107
my $sourceFilePath = $self->{sourceFilePath}//'';
108108
my $problemSourceURL = $self->{inputs_ref}->{problemSourceURL};
@@ -166,9 +166,9 @@ sub formatRenderedProblem {
166166
my $sessionJWT = $self->{return_object}{sessionJWT} // '';
167167

168168
my $previewMode = defined( $self->{inputs_ref}{previewAnswers} ) || 0;
169-
my $checkMode = defined( $self->{inputs_ref}{checkAnswers} ) || 0;
170-
my $submitMode = defined( $self->{inputs_ref}{submitAnswers} ) || 0;
169+
# showCorrectMode needs more security -- ww2 uses want/can/will
171170
my $showCorrectMode = defined( $self->{inputs_ref}{showCorrectAnswers} ) || 0;
171+
my $submitMode = defined($self->{inputs_ref}{submitAnswers}) || $self->{inputs_ref}{answersSubmitted} || 0;
172172

173173
# problemUUID can be added to the request as a parameter. It adds a prefix
174174
# to the identifier used by the format so that several different problems
@@ -180,6 +180,8 @@ sub formatRenderedProblem {
180180
// $rh_result->{flags}{showPartialCorrectAnswers};
181181
my $showSummary = $self->{inputs_ref}{showSummary} // 1; #default to show summary for the moment
182182
my $formLanguage = $self->{inputs_ref}{language} // 'en';
183+
my $showTable = $self->{inputs_ref}{hideAttemptsTable} ? 0 : 1;
184+
my $showMessages = $self->{inputs_ref}{hideMessages} ? 0 : 1;
183185
my $scoreSummary = '';
184186

185187
my $COURSE_LANG_AND_DIR = get_lang_and_dir($formLanguage);
@@ -191,24 +193,27 @@ sub formatRenderedProblem {
191193
my $PROBLEM_LANG_AND_DIR = join(" ", map { qq{$_="$PROBLEM_LANG_AND_DIR{$_}"} } keys %PROBLEM_LANG_AND_DIR);
192194
my $mt = WeBWorK::Localize::getLangHandle($self->{inputs_ref}{language} // 'en');
193195

194-
my $tbl = WeBWorK::Utils::AttemptsTable->new(
195-
$rh_answers,
196-
answersSubmitted => $self->{inputs_ref}{answersSubmitted}//0,
197-
answerOrder => $answerOrder//[],
198-
displayMode => $self->{inputs_ref}{displayMode},
199-
showAnswerNumbers => 0,
200-
showAttemptAnswers => 0,
201-
showAttemptPreviews => ($previewMode or $submitMode or $showCorrectMode),
202-
showAttemptResults => ($submitMode and $showPartialCorrectAnswers),
203-
showCorrectAnswers => ($showCorrectMode),
204-
showMessages => ($previewMode or $submitMode or $showCorrectMode),
205-
showSummary => ( ($showSummary and ($submitMode or $showCorrectMode) )//0 )?1:0,
206-
maketext => WeBWorK::Localize::getLoc($formLanguage//'en'),
207-
summary => $problemResult->{summary} //'', # can be set by problem grader???
208-
);
209-
210-
my $answerTemplate = $tbl->answerTemplate;
211-
$tbl->imgGen->render(body_text => \$answerTemplate) if $tbl->displayMode eq 'images';
196+
my $answerTemplate = '';
197+
if ($submitMode && $showTable) {
198+
my $tbl = WeBWorK::Utils::AttemptsTable->new(
199+
$rh_answers,
200+
answersSubmitted => 1,
201+
answerOrder => $answerOrder,
202+
displayMode => $displayMode,
203+
showAnswerNumbers => 0,
204+
showAttemptAnswers => 0,
205+
showAttemptPreviews => 1,
206+
showAttemptResults => $showPartialCorrectAnswers,
207+
showCorrectAnswers => $showCorrectMode,
208+
showMessages => $showMessages,
209+
showSummary => $showSummary,
210+
maketext => WeBWorK::Localize::getLoc($formLanguage),
211+
summary => $problemResult->{summary} // '', # can be set by problem grader???
212+
);
213+
214+
$answerTemplate = $tbl->answerTemplate;
215+
$tbl->imgGen->render(body_text => \$answerTemplate) if $tbl->displayMode eq 'images';
216+
}
212217

213218
# warn "imgGen is ", $tbl->imgGen;
214219
#warn "answerOrder ", $tbl->answerOrder;

lib/RenderApp/Controller/IO.pm

+87-3
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,91 @@ sub upload {
118118
return $c->render( text => 'File successfully uploaded', status => 200 );
119119
}
120120

121+
sub remove {
122+
my $c = shift;
123+
my $required = [];
124+
push @$required,
125+
{
126+
field => 'removeFilePath',
127+
checkType => 'like',
128+
check => $regex->{privateOnly},
129+
};
130+
my $validatedInput = $c->validateRequest( { required => $required } );
131+
return unless $validatedInput;
132+
133+
my $file_path = $validatedInput->{removeFilePath};
134+
my $file = Mojo::File->new($file_path);
135+
136+
return $c->render( text => 'Path does not exist', status => 404 )
137+
unless (-e $file);
138+
139+
if (-d $file) {
140+
return $c->render( text => 'Directory is not empty', status => 400 )
141+
unless ($file->list({ dir => 1 })->size == 0);
142+
143+
$file->remove_tree;
144+
} else {
145+
$file->remove;
146+
}
147+
148+
return $c->render( text => 'Path deleted' );
149+
}
150+
151+
sub clone {
152+
my $c = shift;
153+
my $required = [];
154+
push @$required,
155+
{
156+
field => 'sourceFilePath',
157+
checkType => 'like',
158+
check => $regex->{privateOnly},
159+
};
160+
push @$required,
161+
{
162+
field => 'targetFilePath',
163+
checkType => 'like',
164+
check => $regex->{privateOnly},
165+
};
166+
my $validatedInput = $c->validateRequest( { required => $required } );
167+
return unless $validatedInput;
168+
169+
my $source_path = $validatedInput->{sourceFilePath};
170+
my $source_file = Mojo::File->new($source_path);
171+
my $target_path = $validatedInput->{targetFilePath};
172+
my $target_file = Mojo::File->new($target_path);
173+
174+
return $c->render( text => 'source does not exist', status => 404 )
175+
unless (-e $source_file);
176+
177+
return $c->render( text => 'target already exists', status => 400 )
178+
if (-e $target_file);
179+
180+
# allow cloning of directories - problems with static assets
181+
# no recursing through directories!
182+
if (-d $source_file) {
183+
return $c->render( text => 'source does not contain clone-able files', status => 400)
184+
if ($source_file->list->size == 0);
185+
186+
return $c->render( text => 'target must also be a directory', status => 400)
187+
unless ($target_path =~ m!.*/$!);
188+
189+
$target_file->make_path;
190+
for ($source_file->list->each) {
191+
$_->copy_to($target_path . $_->basename);
192+
}
193+
} else {
194+
return $c->render( text => 'you may not create new directories with this method', status => 400)
195+
unless (-e $target_file->dirname);
196+
197+
return($c->render( text => 'file extensions do not match'))
198+
unless ($source_file->extname eq $target_file->extname);
199+
200+
$source_file->copy_to($target_file);
201+
}
202+
203+
return $c->render( text => 'clone successful' );
204+
}
205+
121206
async sub catalog {
122207
my $c = shift;
123208
my $required = [];
@@ -169,13 +254,12 @@ sub depthSearch_p {
169254
my $wanted = sub {
170255
# measure depth relative to root_path
171256
( my $rel = $File::Find::name ) =~ s!^\Q$root_path\E/?!!;
257+
return unless $rel;
172258
my $path = $File::Find::name;
173259
$File::Find::prune = 1
174260
if File::Spec::Functions::splitdir($rel) >= $depth;
175261
$path = $path . '/' if -d $File::Find::name;
176-
# only report .pg files and directories
177-
$all{$rel} = $path
178-
if ( $rel =~ /\S/ && ( $path =~ m!.+/$! || $path =~ m!.+\.pg$! ) );
262+
$all{$rel} = $path;
179263
};
180264
File::Find::find { wanted => $wanted, no_chdir => 1 }, $root_path;
181265
return \%all, 200;

lib/RenderApp/Controller/Render.pm

+12-10
Original file line numberDiff line numberDiff line change
@@ -154,24 +154,26 @@ async sub problem {
154154
my $response = shift->result;
155155

156156
$answerJWTresponse->{status} = int($response->code);
157-
if ($response->is_success) {
157+
# answerURL responses are expected to be JSON
158+
if ($response->json) {
159+
# munge data with default response object
160+
$answerJWTresponse = { %$answerJWTresponse, %{$response->json} };
161+
} else {
162+
# otherwise throw the whole body as the message
158163
$answerJWTresponse->{message} = $response->body;
159164
}
160-
elsif ($response->is_error) {
161-
$answerJWTresponse->{message} = '[' . $c->logID . '] ' . $response->message;
162-
}
163-
164-
$answerJWTresponse->{message} =~ s/"/\\"/g;
165-
$answerJWTresponse->{message} =~ s/'/\'/g;
166165
})->
167166
catch(sub {
168-
my $response = shift;
169-
$c->log->error($response);
167+
my $err = shift;
168+
$c->log->error($err);
170169

171170
$answerJWTresponse->{status} = 500;
172-
$answerJWTresponse->{message} = '[' . $c->logID . '] ' . $response;
171+
$answerJWTresponse->{message} = '[' . $c->logID . '] ' . $err;
173172
});
173+
174174
$answerJWTresponse = encode_json($answerJWTresponse);
175+
# this will become a string literal, so single-quote characters must be escaped
176+
$answerJWTresponse =~ s/'/\\'/g;
175177
$c->log->info("answerJWT response ".$answerJWTresponse);
176178

177179
$ww_return_hash->{renderedHTML} =~ s/JWTanswerURLstatus/$answerJWTresponse/g;

lib/WebworkClient/jwe_secure_format.pl

+42-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
<title>WeBWorK using host: $SITE_URL</title>
3333
</head>
34-
<body>
34+
<body onLoad="window.parent.postMessage('loaded', '*')" >
3535
<div class="container-fluid">
3636
<div class="row">
3737
<div class="col-12 problem">
@@ -56,6 +56,47 @@
5656
console.log("response message ", JSON.parse('JWTanswerURLstatus'));
5757
window.parent.postMessage('JWTanswerURLstatus', '*');
5858
}
59+
60+
window.addEventListener('message', event => {
61+
let message;
62+
try {
63+
message = JSON.parse(event.data);
64+
}
65+
catch (e) {
66+
return;
67+
}
68+
69+
if (message.hasOwnProperty('elements')) {
70+
message.elements.forEach((incoming) => {
71+
let elements;
72+
if (incoming.hasOwnProperty('selector')) {
73+
elements = window.document.querySelectorAll(incoming.selector);
74+
if (incoming.hasOwnProperty('style')) {
75+
elements.forEach(el => {el.style.cssText = incoming.style});
76+
}
77+
if (incoming.hasOwnProperty('class')) {
78+
elements.forEach(el => {el.className = incoming.class});
79+
}
80+
}
81+
});
82+
event.source.postMessage('updated elements', event.origin);
83+
}
84+
85+
if (message.hasOwnProperty('templates')) {
86+
message.templates.forEach((cssString) => {
87+
const element = document.createElement('style');
88+
element.innerText = cssString;
89+
document.head.insertAdjacentElement('beforeend', element);
90+
});
91+
event.source.postMessage('updated templates', event.origin);
92+
}
93+
94+
if (message.hasOwnProperty('showSolutions')) {
95+
const elements = Array.from(window.document.querySelectorAll('.knowl[data-type="solution"]'));
96+
const solutions = elements.map(el => el.dataset.knowlContents);
97+
event.source.postMessage(JSON.stringify({solutions: solutions}), event.origin);
98+
}
99+
});
59100
</script>
60101
</body>
61102
</html>

lib/WebworkClient/standard_format.pl

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969
<input type="submit" name="previewAnswers" class="btn btn-primary" value="$STRING_Preview" />
7070
<input type="submit" name="submitAnswers" class="btn btn-primary" value="$STRING_Submit"/>
71-
<input type="submit" name="showCorrectAns" class="btn btn-primary" value="$STRING_ShowCorrect"/>
71+
<input type="submit" name="showCorrectAnswers" class="btn btn-primary" value="$STRING_ShowCorrect"/>
7272
</p>
7373
</form>
7474
<HR>

0 commit comments

Comments
 (0)