--- loncom/interface/lonhelper.pm 2003/05/02 19:20:51 1.17 +++ loncom/interface/lonhelper.pm 2003/06/12 13:52:06 1.37 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # .helper XML handler to implement the LON-CAPA helper # -# $Id: lonhelper.pm,v 1.17 2003/05/02 19:20:51 bowersj2 Exp $ +# $Id: lonhelper.pm,v 1.37 2003/06/12 13:52:06 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -53,7 +53,10 @@ Each state contains one or more state el messages, resource selections, or date queries. The helper tag is required to have one attribute, "title", which is the name -of the helper itself, such as "Parameter helper". +of the helper itself, such as "Parameter helper". The helper tag may optionally +have a "requiredpriv" attribute, specifying the priviledge a user must have +to use the helper, or get denied access. See loncom/auth/rolesplain.tab for +useful privs. Default is full access, which is often wrong! =head2 State tags @@ -193,10 +196,38 @@ my $substate; # end of the element tag is located. my $paramHash; +# Note from Jeremy 5-8-2003: It is *vital* that the real handler be called +# as a subroutine from the handler, or very mysterious things might happen. +# I don't know exactly why, but it seems that the scope where the Apache +# server enters the perl handler is treated differently from the rest of +# the handler. This also seems to manifest itself in the debugger as entering +# the perl handler in seemingly random places (sometimes it starts in the +# compiling phase, sometimes in the handler execution phase where it runs +# the code and stepping into the "1;" the module ends with goes into the handler, +# sometimes starting directly with the handler); I think the cause is related. +# In the debugger, this means that breakpoints are ignored until you step into +# a function and get out of what must be a "faked up scope" in the Apache-> +# mod_perl connection. In this code, it was manifesting itself in the existence +# of two seperate file-scoped $helper variables, one set to the value of the +# helper in the helper constructor, and one referenced by the handler on the +# "$helper->process()" line. The second was therefore never set, and was still +# undefined when I tried to call process on it. +# By pushing the "real handler" down into the "real scope", everybody except the +# actual handler function directly below this comment gets the same $helper and +# everybody is happy. +# The upshot of all of this is that for safety when a handler is using +# file-scoped variables in LON-CAPA, the handler should be pushed down one +# call level, as I do here, to ensure that the top-level handler function does +# not get a different file scope from the rest of the code. +sub handler { + my $r = shift; + return real_handler($r); +} + # For debugging purposes, one can send a second parameter into this # function, the 'uri' of the helper you wish to have rendered, and # call this from other handlers. -sub handler { +sub real_handler { my $r = shift; my $uri = shift; if (!defined($uri)) { $uri = $r->uri(); } @@ -206,6 +237,7 @@ sub handler { my $file; read $fh, $file, 100000000; + # Send header, don't cache this page if ($r->header_only) { if ($ENV{'browser.mathml'}) { @@ -228,10 +260,17 @@ sub handler { # xml parsing &Apache::lonxml::xmlparse($r, 'helper', $file); + my $allowed = $helper->allowedCheck(); + if (!$allowed) { + $ENV{'user.error.msg'} = $ENV{'request.uri'}.':'.$helper->{REQUIRED_PRIV}. + ":0:0:Permission denied to access this helper."; + return HTTP_NOT_ACCEPTABLE; + } + $helper->process(); $r->print($helper->display()); - return OK; + return OK; } sub registerHelperTags { @@ -255,7 +294,7 @@ sub start_helper { registerHelperTags(); - Apache::lonhelper::helper->new($token->[2]{'title'}); + Apache::lonhelper::helper->new($token->[2]{'title'}, $token->[2]{'requiredpriv'}); return ''; } @@ -314,6 +353,7 @@ sub new { my $self = {}; $self->{TITLE} = shift; + $self->{REQUIRED_PRIV} = shift; # If there is a state from the previous form, use that. If there is no # state, use the start state parameter. @@ -326,8 +366,6 @@ sub new { $self->{STATE} = "START"; } - Apache::loncommon::get_unprocessed_cgi($ENV{QUERY_STRING}); - $self->{TOKEN} = $ENV{'form.TOKEN'}; # If a token was passed, we load that in. Otherwise, we need to create a # new storage file @@ -432,10 +470,24 @@ sub declareVar { my $envname = 'form.' . $var . '.forminput'; if (defined($ENV{$envname})) { - $self->{VARS}->{$var} = $ENV{$envname}; + if (ref($ENV{$envname})) { + $self->{VARS}->{$var} = join('|||', @{$ENV{$envname}}); + } else { + $self->{VARS}->{$var} = $ENV{$envname}; + } } } +sub allowedCheck { + my $self = shift; + + if (!defined($self->{REQUIRED_PRIV})) { + return 1; + } + + return Apache::lonnet::allowed($self->{REQUIRED_PRIV}, $ENV{'request.course.id'}); +} + sub changeState { my $self = shift; $self->{STATE} = shift; @@ -516,19 +568,24 @@ sub display { $bodytag HEADER - if (!$state->overrideForm()) { $result.="