Parent Directory
|
Revision Log
Revision 1374 -
(view)
(download)
(as text)
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator.pm
| 1 : | sh002i | 455 | ################################################################################ |
| 2 : | sh002i | 494 | # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project |
| 3 : | sh002i | 455 | # $Id$ |
| 4 : | ################################################################################ | ||
| 5 : | |||
| 6 : | malsyned | 313 | package WeBWorK::ContentGenerator; |
| 7 : | malsyned | 305 | |
| 8 : | sh002i | 455 | =head1 NAME |
| 9 : | |||
| 10 : | WeBWorK::ContentGenerator - base class for modules that generate page content. | ||
| 11 : | |||
| 12 : | =cut | ||
| 13 : | |||
| 14 : | malsyned | 441 | use strict; |
| 15 : | use warnings; | ||
| 16 : | malsyned | 323 | use Apache::Constants qw(:common); |
| 17 : | sh002i | 455 | use CGI qw(); |
| 18 : | sh002i | 469 | use URI::Escape; |
| 19 : | sh002i | 1225 | use WeBWorK::Authz; |
| 20 : | sh002i | 817 | use WeBWorK::DB; |
| 21 : | sh002i | 476 | use WeBWorK::Utils qw(readFile); |
| 22 : | malsyned | 390 | |
| 23 : | sh002i | 469 | ################################################################################ |
| 24 : | # This is a very unruly file, so I'm going to use very large comments to divide | ||
| 25 : | # it into logical sections. | ||
| 26 : | ################################################################################ | ||
| 27 : | malsyned | 390 | |
| 28 : | sh002i | 817 | # new(Apache::Request, WeBWorK::CourseEnvironment) - create a new instance of a |
| 29 : | sh002i | 469 | # content generator. Usually only called by the dispatcher, although one might |
| 30 : | # be able to use it for things like "sub-requests". Uh... uh... I have to think | ||
| 31 : | # about that one. The dispatcher uses this idiom: | ||
| 32 : | # | ||
| 33 : | # WeBWorK::ContentGenerator::WHATEVER->new($r, $ce)->go(@whatever); | ||
| 34 : | # | ||
| 35 : | # and throws away the result ;) | ||
| 36 : | # | ||
| 37 : | sh002i | 819 | sub new($$$$) { |
| 38 : | my ($invocant, $r, $ce, $db) = @_; | ||
| 39 : | malsyned | 323 | my $class = ref($invocant) || $invocant; |
| 40 : | sh002i | 809 | my $self = { |
| 41 : | r => $r, | ||
| 42 : | ce => $ce, | ||
| 43 : | sh002i | 819 | db => $db, |
| 44 : | malsyned | 1017 | authz => WeBWorK::Authz->new($r, $ce, $db) |
| 45 : | sh002i | 809 | }; |
| 46 : | malsyned | 305 | bless $self, $class; |
| 47 : | return $self; | ||
| 48 : | } | ||
| 49 : | |||
| 50 : | sh002i | 469 | ################################################################################ |
| 51 : | # Invocation and template processing | ||
| 52 : | ################################################################################ | ||
| 53 : | malsyned | 323 | |
| 54 : | sh002i | 469 | # go(@otherArguments) - render a page, using methods from the particular |
| 55 : | # subclass of ContentGenerator. @otherArguments is passed to each method, so | ||
| 56 : | # that the dispatcher can pass CG-specific data. The order of calls looks like | ||
| 57 : | # this: | ||
| 58 : | # | ||
| 59 : | # * &pre_header_initialize - give subclasses a chance to do initialization | ||
| 60 : | # necessary for generating the HTTP header. | ||
| 61 : | # * &header - this class provides a standard HTTP header with Content-Type | ||
| 62 : | # text/html. Subclasses are welcome to overload this for things like | ||
| 63 : | # an image-creation content generator or a PDF generator. | ||
| 64 : | # * &initialize - let subclasses do post-header initialization. | ||
| 65 : | # * any "template escapes" defined in the system template and supported by | ||
| 66 : | # the subclass. Generic implementations of &title and &body are provided. | ||
| 67 : | # | ||
| 68 : | sub go { | ||
| 69 : | my $self = shift; | ||
| 70 : | sh002i | 1225 | |
| 71 : | sh002i | 469 | my $r = $self->{r}; |
| 72 : | sh002i | 809 | my $courseEnvironment = $self->{ce}; |
| 73 : | sh002i | 1131 | |
| 74 : | sh002i | 469 | $self->pre_header_initialize(@_) if $self->can("pre_header_initialize"); |
| 75 : | $self->header(@_); | ||
| 76 : | return OK if $r->header_only; | ||
| 77 : | malsyned | 313 | |
| 78 : | sh002i | 469 | $self->initialize(@_) if $self->can("initialize"); |
| 79 : | $self->template($courseEnvironment->{templates}->{system}, @_); | ||
| 80 : | sh002i | 1225 | |
| 81 : | sh002i | 469 | return OK; |
| 82 : | } | ||
| 83 : | |||
| 84 : | # template(STRING, @otherArguments) - parse a template, looking for escapes of | ||
| 85 : | # the form <!--#NAME ARG1="FOO" ARG2="BAR"--> and calling a member function NAME | ||
| 86 : | # (if available) for each NAME. The escapes are called like: | ||
| 87 : | # | ||
| 88 : | # $self->NAME(@otherArguments, \%escapeArguments) | ||
| 89 : | # | ||
| 90 : | # where @otherArguments originates in the dispatcher and %escapeArguments is | ||
| 91 : | # parsed out of the escape itself (i.e. ARG1 => FOO, ARG2 => BAR) | ||
| 92 : | # | ||
| 93 : | sub template { | ||
| 94 : | my ($self, $templateFile) = (shift, shift); | ||
| 95 : | my $r = $self->{r}; | ||
| 96 : | sh002i | 809 | my $courseEnvironment = $self->{ce}; |
| 97 : | malsyned | 512 | my @ifstack = (1); # Start off in printing mode |
| 98 : | # say $ifstack[-1] to get the result of the last <#!--if--> | ||
| 99 : | sh002i | 469 | |
| 100 : | sh002i | 476 | # so even though the variable $/ APPEARS to contain a newline, |
| 101 : | # <TEMPLATE> is slurping the whole file into the first element of | ||
| 102 : | # @template ONLY AFTER THE TRANSLATOR RUNS. WTF!!! | ||
| 103 : | # | ||
| 104 : | #open(TEMPLATE, $templateFile) or die "Couldn't open template $templateFile"; | ||
| 105 : | #my @template = <TEMPLATE>; | ||
| 106 : | #close TEMPLATE; | ||
| 107 : | # | ||
| 108 : | # Let's try something else instead: | ||
| 109 : | my @template = split /\n/, readFile($templateFile); | ||
| 110 : | |||
| 111 : | sh002i | 469 | foreach my $line (@template) { |
| 112 : | # This is incremental regex processing. | ||
| 113 : | # the /c is so that pos($line) doesn't die when the regex fails. | ||
| 114 : | while ($line =~ m/\G(.*?)<!--#(\w*)((?:\s+.*?)?)-->/gc) { | ||
| 115 : | my ($before, $function, $raw_args) = ($1, $2, $3); | ||
| 116 : | sh002i | 555 | my @args = ($raw_args =~ /\S/) ? cook_args($raw_args) : (); |
| 117 : | |||
| 118 : | malsyned | 512 | if ($ifstack[-1]) { |
| 119 : | print $before; | ||
| 120 : | } | ||
| 121 : | sh002i | 555 | |
| 122 : | sh002i | 558 | if ($function eq "if") { |
| 123 : | malsyned | 748 | # a predicate can only be true if everything else on the ifstack is already true, for ANDing |
| 124 : | push @ifstack, ($self->$function(@_, [@args]) && $ifstack[-1]); | ||
| 125 : | sh002i | 558 | } elsif ($function eq "else" and @ifstack > 1) { |
| 126 : | $ifstack[-1] = not $ifstack[-1]; | ||
| 127 : | } elsif ($function eq "endif" and @ifstack > 1) { | ||
| 128 : | pop @ifstack; | ||
| 129 : | } elsif ($ifstack[-1]) { | ||
| 130 : | sh002i | 562 | if ($self->can($function)) { |
| 131 : | malsyned | 1042 | my @result = $self->$function(@_, {@args}); |
| 132 : | if (@result) { | ||
| 133 : | print @result; | ||
| 134 : | } else { | ||
| 135 : | warn "Template escape $function returned an empty list."; | ||
| 136 : | malsyned | 1017 | } |
| 137 : | sh002i | 562 | } |
| 138 : | sh002i | 476 | } |
| 139 : | malsyned | 313 | } |
| 140 : | sh002i | 469 | |
| 141 : | malsyned | 512 | if ($ifstack[-1]) { |
| 142 : | sh002i | 562 | print substr($line, (defined pos $line) ? pos $line : 0), "\n"; |
| 143 : | malsyned | 512 | } |
| 144 : | malsyned | 313 | } |
| 145 : | sh002i | 469 | } |
| 146 : | |||
| 147 : | # cook_args(STRING) - parses a string of the form ARG1="FOO" ARG2="BAR". Returns | ||
| 148 : | malsyned | 512 | # a list which pairs into key/values and fits nicely in {}s. |
| 149 : | sh002i | 469 | # |
| 150 : | sh002i | 798 | sub cook_args($) { # ... also used by bin/wwdb, so watch out |
| 151 : | sh002i | 469 | my ($raw_args) = @_; |
| 152 : | malsyned | 512 | my @args = (); |
| 153 : | malsyned | 353 | |
| 154 : | malsyned | 508 | # Boy I love m//g in scalar context! Go read the camel book, heathen. |
| 155 : | # First, get the whole token with the quotes on both ends... | ||
| 156 : | while ($raw_args =~ m/\G\s*(\w*)="((?:[^"\\]|\\.)*)"/g) { | ||
| 157 : | my ($key, $value) = ($1, $2); | ||
| 158 : | # ... then, rip out all the protecty backspaces | ||
| 159 : | malsyned | 522 | $value =~ s/\\(.)/$1/g; |
| 160 : | malsyned | 512 | push @args, $key => $value; |
| 161 : | sh002i | 469 | } |
| 162 : | |||
| 163 : | malsyned | 512 | return @args; |
| 164 : | malsyned | 313 | } |
| 165 : | |||
| 166 : | sh002i | 558 | # This is different. It probably shouldn't print anything (except in debugging cases) |
| 167 : | # and it should return a boolean, not a string. &if is called in a nonstandard way | ||
| 168 : | # by &template, with $args as an arrayref instead of a hashref. this is a hack! yay! | ||
| 169 : | |||
| 170 : | # OK, this is a pluggin architecture. it iterates through attributes of the "if" tag, | ||
| 171 : | # and for each predicate $p, it calls &if_$p in an object-oriented way, continuing the | ||
| 172 : | # grand templating theme of an object-oriented pluggable architecture using ->can($). | ||
| 173 : | sub if { | ||
| 174 : | my ($self, $args) = @_[0,-1]; | ||
| 175 : | # A single if "or"s it's components. Nesting produces "and". | ||
| 176 : | |||
| 177 : | my @args = @$args; # Hahahahaha, get it?! | ||
| 178 : | |||
| 179 : | if (@args % 2 != 0) { | ||
| 180 : | # flip out and kill people, but do not commit seppuku | ||
| 181 : | print '<!--&if recieved an uneven number of arguments. This shouldn\'t happen, but I\'ll let it slide.-->\n'; | ||
| 182 : | } | ||
| 183 : | |||
| 184 : | while (@args > 1) { | ||
| 185 : | my ($key, $value) = (shift @args, shift @args); | ||
| 186 : | |||
| 187 : | # a non-existent &if_$key is the same as a false result, but we're ORing, so it's OK | ||
| 188 : | my $sub = "if_$key"; # perl doesn't like it when you try to construct a string right in a method invocation | ||
| 189 : | if ($self->can("if_$key") and $self->$sub("$value")) { | ||
| 190 : | return 1; | ||
| 191 : | } | ||
| 192 : | } | ||
| 193 : | |||
| 194 : | return 0; | ||
| 195 : | } | ||
| 196 : | |||
| 197 : | sh002i | 469 | ################################################################################ |
| 198 : | # Macros used by content generators to render common idioms | ||
| 199 : | ################################################################################ | ||
| 200 : | |||
| 201 : | # pathMacro(HASHREF, LIST) - helper macro for <!--#path--> escape: the hash | ||
| 202 : | # reference contains the "style", "image", and "text" arguments to the escape. | ||
| 203 : | # The LIST consists of ordered key-value pairs of the form: | ||
| 204 : | # | ||
| 205 : | # "Page Name" => URL | ||
| 206 : | # | ||
| 207 : | # If the page should not have a link associated with it, the URL should be left | ||
| 208 : | # empty. Authentication data is added to the URL so you don't have to. A fully- | ||
| 209 : | # formed path line is returned, suitable for returning by a function | ||
| 210 : | # implementing the #path escape. | ||
| 211 : | # | ||
| 212 : | sub pathMacro { | ||
| 213 : | malsyned | 323 | my $self = shift; |
| 214 : | sh002i | 469 | my %args = %{ shift() }; |
| 215 : | my @path = @_; | ||
| 216 : | my $sep; | ||
| 217 : | if ($args{style} eq "image") { | ||
| 218 : | $sep = CGI::img({-src=>$args{image}, -alt=>$args{text}}); | ||
| 219 : | } else { | ||
| 220 : | $sep = $args{text}; | ||
| 221 : | } | ||
| 222 : | my $auth = $self->url_authen_args; | ||
| 223 : | my @result; | ||
| 224 : | while (@path) { | ||
| 225 : | my $name = shift @path; | ||
| 226 : | my $url = shift @path; | ||
| 227 : | push @result, $url | ||
| 228 : | ? CGI::a({-href=>"$url?$auth"}, $name) | ||
| 229 : | : $name; | ||
| 230 : | } | ||
| 231 : | gage | 1024 | return join($sep, @result) . "\n"; |
| 232 : | sh002i | 469 | } |
| 233 : | |||
| 234 : | sub siblingsMacro { | ||
| 235 : | my $self = shift; | ||
| 236 : | my @siblings = @_; | ||
| 237 : | my $sep = CGI::br(); | ||
| 238 : | my $auth = $self->url_authen_args; | ||
| 239 : | my @result; | ||
| 240 : | while (@siblings) { | ||
| 241 : | my $name = shift @siblings; | ||
| 242 : | my $url = shift @siblings; | ||
| 243 : | push @result, $url | ||
| 244 : | ? CGI::a({-href=>"$url?$auth"}, $name) | ||
| 245 : | : $name; | ||
| 246 : | } | ||
| 247 : | return join($sep, @result), "\n"; | ||
| 248 : | } | ||
| 249 : | |||
| 250 : | sub navMacro { | ||
| 251 : | my $self = shift; | ||
| 252 : | my %args = %{ shift() }; | ||
| 253 : | sh002i | 692 | my $tail = shift; |
| 254 : | sh002i | 469 | my @links = @_; |
| 255 : | my $auth = $self->url_authen_args; | ||
| 256 : | sh002i | 809 | my $ce = $self->{ce}; |
| 257 : | malsyned | 795 | my $prefix = $ce->{webworkURLs}->{htdocs}."/images"; |
| 258 : | sh002i | 469 | my @result; |
| 259 : | while (@links) { | ||
| 260 : | my $name = shift @links; | ||
| 261 : | my $url = shift @links; | ||
| 262 : | malsyned | 757 | my $img = shift @links; |
| 263 : | malsyned | 795 | my $html = |
| 264 : | ($img && $args{style} eq "images") | ||
| 265 : | ? CGI::img( | ||
| 266 : | {src=>($prefix."/".$img.$args{imagesuffix}), | ||
| 267 : | border=>"", | ||
| 268 : | alt=>"$name"}) | ||
| 269 : | : $name; | ||
| 270 : | malsyned | 757 | unless($img && !$url) { |
| 271 : | push @result, $url | ||
| 272 : | ? CGI::a({-href=>"$url?$auth$tail"}, $html) | ||
| 273 : | : $html; | ||
| 274 : | } | ||
| 275 : | sh002i | 469 | } |
| 276 : | gage | 1024 | return join($args{separator}, @result) . "\n"; |
| 277 : | sh002i | 469 | } |
| 278 : | |||
| 279 : | # hidden_fields(LIST) - return hidden <INPUT> tags for each field mentioned in | ||
| 280 : | # LIST (or all fields if list is empty), taking data from the current request. | ||
| 281 : | # | ||
| 282 : | sub hidden_fields($;@) { | ||
| 283 : | my $self = shift; | ||
| 284 : | malsyned | 323 | my $r = $self->{r}; |
| 285 : | sh002i | 469 | my @fields = @_; |
| 286 : | @fields or @fields = $r->param; | ||
| 287 : | sh002i | 809 | my $courseEnvironment = $self->{ce}; |
| 288 : | malsyned | 323 | my $html = ""; |
| 289 : | |||
| 290 : | sh002i | 469 | foreach my $param (@fields) { |
| 291 : | malsyned | 323 | my $value = $r->param($param); |
| 292 : | malsyned | 447 | $html .= CGI::input({-type=>"hidden",-name=>"$param",-value=>"$value"}); |
| 293 : | malsyned | 323 | } |
| 294 : | return $html; | ||
| 295 : | } | ||
| 296 : | |||
| 297 : | sh002i | 469 | # hidden_authen_fields() - use hidden_fields to return hidden <INPUT> tags for |
| 298 : | # request fields used in authentication. | ||
| 299 : | # | ||
| 300 : | sub hidden_authen_fields($) { | ||
| 301 : | my $self = shift; | ||
| 302 : | return $self->hidden_fields("user","effectiveUser","key"); | ||
| 303 : | } | ||
| 304 : | sh002i | 425 | |
| 305 : | sh002i | 469 | # url_args(LIST) - return a URL query string (without the leading `?') |
| 306 : | # containing values for each field mentioned in LIST, or all fields if list is | ||
| 307 : | # empty. Data is taken from the current request. | ||
| 308 : | # | ||
| 309 : | sub url_args($;@) { | ||
| 310 : | sh002i | 425 | my $self = shift; |
| 311 : | my $r = $self->{r}; | ||
| 312 : | my @fields = @_; | ||
| 313 : | @fields or @fields = $r->param; | ||
| 314 : | sh002i | 809 | my $courseEnvironment = $self->{ce}; |
| 315 : | sh002i | 425 | |
| 316 : | sh002i | 469 | my @pairs; |
| 317 : | malsyned | 441 | foreach my $param (@fields) { |
| 318 : | sh002i | 469 | my $value = $r->param($param) || ""; |
| 319 : | push @pairs, uri_escape($param) . "=" . uri_escape($value); | ||
| 320 : | sh002i | 425 | } |
| 321 : | sh002i | 469 | |
| 322 : | return join("&", @pairs); | ||
| 323 : | sh002i | 425 | } |
| 324 : | |||
| 325 : | sh002i | 469 | # url_authen_args() - use url_args to return a URL query string for request |
| 326 : | # fields used in authentication. | ||
| 327 : | # | ||
| 328 : | sub url_authen_args($) { | ||
| 329 : | my $self = shift; | ||
| 330 : | my $r = $self->{r}; | ||
| 331 : | return $self->url_args("user","effectiveUser","key"); | ||
| 332 : | malsyned | 390 | } |
| 333 : | |||
| 334 : | sh002i | 469 | # print_form_data(BEGIN, MIDDLE, END, OMIT) - return a string containing request |
| 335 : | # fields not matched by OMIT, placing BEGIN before each field name, MIDDLE | ||
| 336 : | # between each field and its value, and END after each value. Values are taken | ||
| 337 : | # from the current request. OMIT is a quoted reguar expression. | ||
| 338 : | # | ||
| 339 : | sub print_form_data { | ||
| 340 : | my ($self, $begin, $middle, $end, $qr_omit) = @_; | ||
| 341 : | my $return_string = ""; | ||
| 342 : | my $r=$self->{r}; | ||
| 343 : | my @form_data = $r->param; | ||
| 344 : | foreach my $name (@form_data) { | ||
| 345 : | next if ($qr_omit and $name =~ /$qr_omit/); | ||
| 346 : | my @values = $r->param($name); | ||
| 347 : | foreach my $variable (qw(begin name middle value end)) { | ||
| 348 : | no strict 'refs'; | ||
| 349 : | ${$variable} = "" unless defined ${$variable}; | ||
| 350 : | } | ||
| 351 : | foreach my $value (@values) { | ||
| 352 : | $return_string .= "$begin$name$middle$value$end"; | ||
| 353 : | } | ||
| 354 : | } | ||
| 355 : | return $return_string; | ||
| 356 : | malsyned | 390 | } |
| 357 : | |||
| 358 : | sh002i | 737 | sub errorOutput($$$) { |
| 359 : | my ($self, $error, $details) = @_; | ||
| 360 : | return | ||
| 361 : | gage | 1152 | CGI::h3("Software Error"), |
| 362 : | sh002i | 737 | CGI::p(<<EOF), |
| 363 : | sh002i | 1131 | WeBWorK has encountered a software error while attempting to process this |
| 364 : | problem. It is likely that there is an error in the problem itself. If you are | ||
| 365 : | a student, contact your professor to have the error corrected. If you are a | ||
| 366 : | professor, please consut the error output below for more informaiton. | ||
| 367 : | sh002i | 737 | EOF |
| 368 : | sh002i | 1142 | CGI::h3("Error messages"), CGI::p(CGI::tt($error)), |
| 369 : | CGI::h3("Error context"), CGI::p(CGI::tt($details)); | ||
| 370 : | sh002i | 737 | } |
| 371 : | |||
| 372 : | sub warningOutput($$) { | ||
| 373 : | my ($self, $warnings) = @_; | ||
| 374 : | |||
| 375 : | sh002i | 1169 | my @warnings = split m/\n+/, $warnings; |
| 376 : | |||
| 377 : | sh002i | 737 | return |
| 378 : | gage | 1152 | CGI::h3("Software Warnings"), |
| 379 : | sh002i | 737 | CGI::p(<<EOF), |
| 380 : | sh002i | 1131 | WeBWorK has encountered warnings while attempting to process this problem. It |
| 381 : | is likely that this indicates an error or ambiguity in the problem itself. If | ||
| 382 : | you are a student, contact your professor to have the problem corrected. If you | ||
| 383 : | sh002i | 1142 | are a professor, please consut the warning output below for more informaiton. |
| 384 : | sh002i | 737 | EOF |
| 385 : | CGI::h3("Warning messages"), | ||
| 386 : | sh002i | 1169 | CGI::ul(CGI::li(\@warnings)), |
| 387 : | sh002i | 737 | ; |
| 388 : | } | ||
| 389 : | |||
| 390 : | sh002i | 469 | ################################################################################ |
| 391 : | # Generic versions of template escapes | ||
| 392 : | ################################################################################ | ||
| 393 : | malsyned | 390 | |
| 394 : | sh002i | 469 | # Reminder: here are the template functions currently defined: |
| 395 : | sh002i | 1131 | # FIXME: this list is out of date!!!!!!!! |
| 396 : | sh002i | 469 | # |
| 397 : | sh002i | 555 | # head |
| 398 : | sh002i | 469 | # path |
| 399 : | # style = text|image | ||
| 400 : | # image = URL of image | ||
| 401 : | # text = text separator | ||
| 402 : | sh002i | 675 | # loginstatus |
| 403 : | sh002i | 505 | # links |
| 404 : | sh002i | 469 | # siblings |
| 405 : | # nav | ||
| 406 : | # style = text|image | ||
| 407 : | # imageprefix = prefix to image URL | ||
| 408 : | # imagesuffix = suffix to image URL | ||
| 409 : | # separator = HTML to place in between links | ||
| 410 : | # title | ||
| 411 : | # body | ||
| 412 : | malsyned | 313 | |
| 413 : | malsyned | 349 | sub header { |
| 414 : | malsyned | 305 | my $self = shift; |
| 415 : | sh002i | 469 | my $r = $self->{r}; |
| 416 : | malsyned | 349 | $r->content_type('text/html'); |
| 417 : | $r->send_http_header(); | ||
| 418 : | } | ||
| 419 : | |||
| 420 : | sh002i | 682 | sub loginstatus { |
| 421 : | my $self = shift; | ||
| 422 : | my $r = $self->{r}; | ||
| 423 : | my $user = $r->param("user"); | ||
| 424 : | my $eUser = $r->param("effectiveUser"); | ||
| 425 : | my $key = $r->param("key"); | ||
| 426 : | return "" unless $key; | ||
| 427 : | sh002i | 692 | my $exitURL = $r->uri() . "?user=$user&key=$key"; |
| 428 : | malsyned | 765 | print CGI::small("User:", "$user"); |
| 429 : | sh002i | 682 | if ($user ne $eUser) { |
| 430 : | sh002i | 692 | print CGI::br(), CGI::font({-color=>'red'}, |
| 431 : | malsyned | 765 | CGI::small("Acting as:", "$eUser") |
| 432 : | sh002i | 692 | ), |
| 433 : | CGI::br(), CGI::a({-href=>$exitURL}, | ||
| 434 : | CGI::small("Stop Acting") | ||
| 435 : | ); | ||
| 436 : | sh002i | 682 | } |
| 437 : | return ""; | ||
| 438 : | } | ||
| 439 : | |||
| 440 : | sh002i | 1131 | # FIXME: drunk code. rewrite. |
| 441 : | sh002i | 667 | # also, this should be structured s.t. subclasses can add items to the links |
| 442 : | # area, i.e. "stacking" | ||
| 443 : | sh002i | 505 | sub links { |
| 444 : | malsyned | 353 | my $self = shift; |
| 445 : | sh002i | 809 | my $ce = $self->{ce}; |
| 446 : | sh002i | 817 | my $db = $self->{db}; |
| 447 : | sh002i | 526 | my $userName = $self->{r}->param("user"); |
| 448 : | my $courseName = $ce->{courseName}; | ||
| 449 : | sh002i | 469 | my $root = $ce->{webworkURLs}->{root}; |
| 450 : | sh002i | 817 | my $permLevel = $db->getPermissionLevel($userName)->permission(); |
| 451 : | my $key = $db->getKey($userName)->key(); | ||
| 452 : | sh002i | 646 | return "" unless defined $key; |
| 453 : | sh002i | 526 | |
| 454 : | sh002i | 667 | # URLs to parts of the system |
| 455 : | malsyned | 836 | my $probSets = "$root/$courseName/?" . $self->url_authen_args(); |
| 456 : | my $prefs = "$root/$courseName/options/?" . $self->url_authen_args(); | ||
| 457 : | my $instructor = "$root/$courseName/instructor/?" . $self->url_authen_args(); | ||
| 458 : | gage | 1358 | my $sets = "$root/$courseName/instructor/sets/?" . $self->url_authen_args(); |
| 459 : | gage | 1374 | my $users = "$root/$courseName/instructor/users/?" . $self->url_authen_args(); |
| 460 : | my $email = "$root/$courseName/instructor/send_mail/?" . $self->url_authen_args(); | ||
| 461 : | malsyned | 836 | my $help = "$ce->{webworkURLs}->{docs}?" . $self->url_authen_args(); |
| 462 : | my $logout = "$root/$courseName/logout/?" . $self->url_authen_args(); | ||
| 463 : | sh002i | 526 | |
| 464 : | gage | 1358 | return join("", |
| 465 : | CGI::a({-href=>$probSets}, "Problem Sets"), CGI::br(), | ||
| 466 : | gage | 1360 | CGI::a({-href=>$prefs}, "User Prefs"), CGI::br(), |
| 467 : | CGI::a({-href=>$help}, "Help"), CGI::br(), | ||
| 468 : | CGI::a({-href=>$logout}, "Log Out"), CGI::br(), | ||
| 469 : | sh002i | 667 | ($permLevel > 0 |
| 470 : | gage | 1358 | ? join("", |
| 471 : | gage | 1374 | CGI::hr(), |
| 472 : | CGI::a({-href=>$instructor}, "Instructor") , CGI::br(), | ||
| 473 : | ' ',CGI::a({-href=>$sets}, "Set List") , CGI::br(), | ||
| 474 : | ' ',CGI::a({-href=>$users}, "Class List") , CGI::br(), | ||
| 475 : | ' ',CGI::a({-href=>$email}, "Send Email") , CGI::br(), | ||
| 476 : | |||
| 477 : | ) : "" | ||
| 478 : | gage | 1358 | ), |
| 479 : | ); | ||
| 480 : | malsyned | 353 | } |
| 481 : | |||
| 482 : | malsyned | 525 | # &if_can will return 1 if the current object->can("do $_[1]") |
| 483 : | sub if_can ($$) { | ||
| 484 : | my ($self, $arg) = (@_); | ||
| 485 : | |||
| 486 : | if ($self->can("$arg")) { | ||
| 487 : | return 1; | ||
| 488 : | } else { | ||
| 489 : | return 0; | ||
| 490 : | } | ||
| 491 : | } | ||
| 492 : | |||
| 493 : | malsyned | 748 | # Every content generator is logged in unless it says otherwise. |
| 494 : | sub if_loggedin($$) { | ||
| 495 : | my ($self, $arg) = (@_); | ||
| 496 : | |||
| 497 : | return $arg; | ||
| 498 : | } | ||
| 499 : | |||
| 500 : | sh002i | 1131 | # Handling of errors in submissions |
| 501 : | |||
| 502 : | malsyned | 1017 | sub if_submiterror($$) { |
| 503 : | my ($self, $arg) = @_; | ||
| 504 : | if (exists $self->{submitError}) { | ||
| 505 : | return $arg; | ||
| 506 : | } else { | ||
| 507 : | return !$arg; | ||
| 508 : | } | ||
| 509 : | } | ||
| 510 : | |||
| 511 : | sh002i | 1131 | sub submiterror { |
| 512 : | my ($self) = @_; | ||
| 513 : | if (exists $self->{submitError}) { | ||
| 514 : | return $self->{submitError}; | ||
| 515 : | } else { | ||
| 516 : | return ""; | ||
| 517 : | } | ||
| 518 : | } | ||
| 519 : | |||
| 520 : | # General warning handling | ||
| 521 : | |||
| 522 : | sub if_warnings($$) { | ||
| 523 : | my ($self, $arg) = @_; | ||
| 524 : | return $self->{r}->notes("warnings") ? $arg : !$arg; | ||
| 525 : | } | ||
| 526 : | |||
| 527 : | sub warnings { | ||
| 528 : | my ($self) = @_; | ||
| 529 : | my $r = $self->{r}; | ||
| 530 : | if ($r->notes("warnings")) { | ||
| 531 : | return $self->warningOutput($r->notes("warnings")); | ||
| 532 : | } else { | ||
| 533 : | return ""; | ||
| 534 : | } | ||
| 535 : | } | ||
| 536 : | |||
| 537 : | malsyned | 313 | 1; |
| 538 : | malsyned | 508 | |
| 539 : | __END__ | ||
| 540 : | |||
| 541 : | =head1 AUTHOR | ||
| 542 : | |||
| 543 : | Written by Dennis Lambe Jr., malsyned (at) math.rochester.edu | ||
| 544 : | and Sam Hathaway, sh002i (at) math.rochester.edu. | ||
| 545 : | |||
| 546 : | =cut |
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |