version 1.552, 2007/07/17 23:10:14
|
version 1.1075.2.161.2.24, 2024/03/29 00:45:24
|
Line 61 use POSIX qw(strftime mktime);
|
Line 61 use POSIX qw(strftime mktime);
|
use Apache::lonmenu(); |
use Apache::lonmenu(); |
use Apache::lonenc(); |
use Apache::lonenc(); |
use Apache::lonlocal; |
use Apache::lonlocal; |
|
use Apache::lonnavmaps(); |
use HTML::Entities; |
use HTML::Entities; |
use Apache::lonhtmlcommon(); |
use Apache::lonhtmlcommon(); |
use Apache::loncoursedata(); |
use Apache::loncoursedata(); |
use Apache::lontexconvert(); |
use Apache::lontexconvert(); |
use Apache::lonclonecourse(); |
use Apache::lonclonecourse(); |
|
use Apache::lonuserutils(); |
|
use Apache::lonuserstate(); |
|
use Apache::courseclassifier(); |
use LONCAPA qw(:DEFAULT :match); |
use LONCAPA qw(:DEFAULT :match); |
|
use LONCAPA::map(); |
|
use HTTP::Request; |
|
use DateTime::TimeZone; |
|
use DateTime::Locale; |
|
use Encode(); |
|
use Authen::Captcha; |
|
use Captcha::reCAPTCHA; |
|
use JSON::DWIW; |
|
use LWP::UserAgent; |
|
use Crypt::DES; |
|
use DynaLoader; # for Crypt::DES version |
|
use File::Copy(); |
|
use File::Path(); |
|
use String::CRC32(); |
|
use Short::URL(); |
|
|
# ---------------------------------------------- Designs |
# ---------------------------------------------- Designs |
use vars qw(%defaultdesign); |
use vars qw(%defaultdesign); |
Line 78 my $readit;
|
Line 97 my $readit;
|
## Global Variables |
## Global Variables |
## |
## |
|
|
|
|
|
# ----------------------------------------------- SSI with retries: |
|
# |
|
|
|
=pod |
|
|
|
=head1 Server Side include with retries: |
|
|
|
=over 4 |
|
|
|
=item * &ssi_with_retries(resource,retries form) |
|
|
|
Performs an ssi with some number of retries. Retries continue either |
|
until the result is ok or until the retry count supplied by the |
|
caller is exhausted. |
|
|
|
Inputs: |
|
|
|
=over 4 |
|
|
|
resource - Identifies the resource to insert. |
|
|
|
retries - Count of the number of retries allowed. |
|
|
|
form - Hash that identifies the rendering options. |
|
|
|
=back |
|
|
|
Returns: |
|
|
|
=over 4 |
|
|
|
content - The content of the response. If retries were exhausted this is empty. |
|
|
|
response - The response from the last attempt (which may or may not have been successful. |
|
|
|
=back |
|
|
|
=back |
|
|
|
=cut |
|
|
|
sub ssi_with_retries { |
|
my ($resource, $retries, %form) = @_; |
|
|
|
|
|
my $ok = 0; # True if we got a good response. |
|
my $content; |
|
my $response; |
|
|
|
# Try to get the ssi done. within the retries count: |
|
|
|
do { |
|
($content, $response) = &Apache::lonnet::ssi($resource, %form); |
|
$ok = $response->is_success; |
|
if (!$ok) { |
|
&Apache::lonnet::logthis("Failed ssi_with_retries on $resource: ".$response->is_success.', '.$response->code.', '.$response->message); |
|
} |
|
$retries--; |
|
} while (!$ok && ($retries > 0)); |
|
|
|
if (!$ok) { |
|
$content = ''; # On error return an empty content. |
|
} |
|
return ($content, $response); |
|
|
|
} |
|
|
|
|
|
|
# ----------------------------------------------- Filetypes/Languages/Copyright |
# ----------------------------------------------- Filetypes/Languages/Copyright |
my %language; |
my %language; |
my %supported_language; |
my %supported_language; |
|
my %latex_language; # For choosing hyphenation in <transl..> |
|
my %latex_language_bykey; # for choosing hyphenation from metadata |
my %cprtag; |
my %cprtag; |
my %scprtag; |
my %scprtag; |
my %fe; my %fd; my %fm; |
my %fe; my %fd; my %fm; |
Line 109 BEGIN {
|
Line 200 BEGIN {
|
{ |
{ |
my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}. |
my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}. |
'/language.tab'; |
'/language.tab'; |
if ( open(my $fh,"<$langtabfile") ) { |
if ( open(my $fh,'<',$langtabfile) ) { |
while (my $line = <$fh>) { |
while (my $line = <$fh>) { |
next if ($line=~/^\#/); |
next if ($line=~/^\#/); |
chomp($line); |
chomp($line); |
my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line)); |
my ($key,$two,$country,$three,$enc,$val,$sup,$latex)=(split(/\t/,$line)); |
$language{$key}=$val.' - '.$enc; |
$language{$key}=$val.' - '.$enc; |
if ($sup) { |
if ($sup) { |
$supported_language{$key}=$sup; |
$supported_language{$key}=$sup; |
} |
} |
|
if ($latex) { |
|
$latex_language_bykey{$key} = $latex; |
|
$latex_language{$two} = $latex; |
|
} |
} |
} |
close($fh); |
close($fh); |
} |
} |
Line 126 BEGIN {
|
Line 221 BEGIN {
|
{ |
{ |
my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. |
my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. |
'/copyright.tab'; |
'/copyright.tab'; |
if ( open (my $fh,"<$copyrightfile") ) { |
if ( open (my $fh,'<',$copyrightfile) ) { |
while (my $line = <$fh>) { |
while (my $line = <$fh>) { |
next if ($line=~/^\#/); |
next if ($line=~/^\#/); |
chomp($line); |
chomp($line); |
Line 140 BEGIN {
|
Line 235 BEGIN {
|
{ |
{ |
my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. |
my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}. |
'/source_copyright.tab'; |
'/source_copyright.tab'; |
if ( open (my $fh,"<$sourcecopyrightfile") ) { |
if ( open (my $fh,'<',$sourcecopyrightfile) ) { |
while (my $line = <$fh>) { |
while (my $line = <$fh>) { |
next if ($line =~ /^\#/); |
next if ($line =~ /^\#/); |
chomp($line); |
chomp($line); |
Line 154 BEGIN {
|
Line 249 BEGIN {
|
# -------------------------------------------------------------- default domain designs |
# -------------------------------------------------------------- default domain designs |
my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; |
my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; |
my $designfile = $designdir.'/default.tab'; |
my $designfile = $designdir.'/default.tab'; |
if ( open (my $fh,"<$designfile") ) { |
if ( open (my $fh,'<',$designfile) ) { |
while (my $line = <$fh>) { |
while (my $line = <$fh>) { |
next if ($line =~ /^\#/); |
next if ($line =~ /^\#/); |
chomp($line); |
chomp($line); |
Line 168 BEGIN {
|
Line 263 BEGIN {
|
{ |
{ |
my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}. |
my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}. |
'/filecategories.tab'; |
'/filecategories.tab'; |
if ( open (my $fh,"<$categoryfile") ) { |
if ( open (my $fh,'<',$categoryfile) ) { |
while (my $line = <$fh>) { |
while (my $line = <$fh>) { |
next if ($line =~ /^\#/); |
next if ($line =~ /^\#/); |
chomp($line); |
chomp($line); |
my ($extension,$category)=(split(/\s+/,$line,2)); |
my ($extension,$category)=(split(/\s+/,$line,2)); |
push @{$category_extensions{lc($category)}},$extension; |
push(@{$category_extensions{lc($category)}},$extension); |
} |
} |
close($fh); |
close($fh); |
} |
} |
Line 183 BEGIN {
|
Line 278 BEGIN {
|
{ |
{ |
my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}. |
my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}. |
'/filetypes.tab'; |
'/filetypes.tab'; |
if ( open (my $fh,"<$typesfile") ) { |
if ( open (my $fh,'<',$typesfile) ) { |
while (my $line = <$fh>) { |
while (my $line = <$fh>) { |
next if ($line =~ /^\#/); |
next if ($line =~ /^\#/); |
chomp($line); |
chomp($line); |
Line 198 BEGIN {
|
Line 293 BEGIN {
|
} |
} |
} |
} |
&Apache::lonnet::logthis( |
&Apache::lonnet::logthis( |
"<font color=yellow>INFO: Read file types</font>"); |
"<span style='color:yellow;'>INFO: Read file types</span>"); |
$readit=1; |
$readit=1; |
} # end of unless($readit) |
} # end of unless($readit) |
|
|
Line 214 BEGIN {
|
Line 309 BEGIN {
|
|
|
=over 4 |
=over 4 |
|
|
=item * browser_and_searcher_javascript () |
=item * &browser_and_searcher_javascript() |
|
|
X<browsing, javascript>X<searching, javascript>Returns a string |
X<browsing, javascript>X<searching, javascript>Returns a string |
containing javascript with two functions, C<openbrowser> and |
containing javascript with two functions, C<openbrowser> and |
C<opensearcher>. Returned string does not contain E<lt>scriptE<gt> |
C<opensearcher>. Returned string does not contain E<lt>scriptE<gt> |
tags. |
tags. |
|
|
=item * openbrowser(formname,elementname,only,omit) [javascript] |
=item * &openbrowser(formname,elementname,only,omit) [javascript] |
|
|
inputs: formname, elementname, only, omit |
inputs: formname, elementname, only, omit |
|
|
Line 234 with the given extension. Can be a comm
|
Line 329 with the given extension. Can be a comm
|
Specifying 'omit' will restrict the browser to NOT displaying files |
Specifying 'omit' will restrict the browser to NOT displaying files |
with the given extension. Can be a comma separated list. |
with the given extension. Can be a comma separated list. |
|
|
=item * opensearcher(formname, elementname) [javascript] |
=item * &opensearcher(formname,elementname) [javascript] |
|
|
Inputs: formname, elementname |
Inputs: formname, elementname |
|
|
Line 257 sub browser_and_searcher_javascript {
|
Line 352 sub browser_and_searcher_javascript {
|
} |
} |
url += 'catalogmode=interactive&'; |
url += 'catalogmode=interactive&'; |
url += 'mode=$mode&'; |
url += 'mode=$mode&'; |
|
url += 'inhibitmenu=yes&'; |
url += 'form=' + formname + '&'; |
url += 'form=' + formname + '&'; |
if (only != null) { |
if (only != null) { |
url += 'only=' + only + '&'; |
url += 'only=' + only + '&'; |
Line 318 sub storeresurl {
|
Line 414 sub storeresurl {
|
unless ($resurl=~/^\/res/) { return 0; } |
unless ($resurl=~/^\/res/) { return 0; } |
$resurl=~s/\/$//; |
$resurl=~s/\/$//; |
&Apache::lonnet::put('environment',{'lastresurl' => $resurl}); |
&Apache::lonnet::put('environment',{'lastresurl' => $resurl}); |
&Apache::lonnet::appenv('environment.lastresurl' => $resurl); |
&Apache::lonnet::appenv({'environment.lastresurl' => $resurl}); |
return 1; |
return 1; |
} |
} |
|
|
Line 332 sub studentbrowser_javascript {
|
Line 428 sub studentbrowser_javascript {
|
|| ($env{'request.role'}=~/^(au|dc|su)/) |
|| ($env{'request.role'}=~/^(au|dc|su)/) |
) { return ''; } |
) { return ''; } |
return (<<'ENDSTDBRW'); |
return (<<'ENDSTDBRW'); |
<script type="text/javascript" language="Javascript" > |
<script type="text/javascript" language="Javascript"> |
|
// <![CDATA[ |
var stdeditbrowser; |
var stdeditbrowser; |
function openstdbrowser(formname,uname,udom,roleflag) { |
function openstdbrowser(formname,uname,udom,clicker,roleflag,ignorefilter,courseadv,uident) { |
var url = '/adm/pickstudent?'; |
var url = '/adm/pickstudent?'; |
var filter; |
var filter; |
eval('filter=document.'+formname+'.'+uname+'.value;'); |
if (!ignorefilter) { |
|
eval('filter=document.'+formname+'.'+uname+'.value;'); |
|
} |
if (filter != null) { |
if (filter != null) { |
if (filter != '') { |
if (filter != '') { |
url += 'filter='+filter+'&'; |
url += 'filter='+filter+'&'; |
} |
} |
} |
} |
url += 'form=' + formname + '&unameelement='+uname+ |
url += 'form=' + formname + '&unameelement='+uname+ |
'&udomelement='+udom; |
'&udomelement='+udom+ |
|
'&clicker='+clicker; |
if (roleflag) { url+="&roles=1"; } |
if (roleflag) { url+="&roles=1"; } |
|
if (courseadv == 'condition') { |
|
if (document.getElementById('courseadv')) { |
|
courseadv = document.getElementById('courseadv').value; |
|
} |
|
} |
|
if ((courseadv == 'only') || (courseadv == 'none')) { url+="&courseadv="+courseadv; } |
|
if (uident !== '') { url+="&identelement="+uident; } |
var title = 'Student_Browser'; |
var title = 'Student_Browser'; |
var options = 'scrollbars=1,resizable=1,menubar=0'; |
var options = 'scrollbars=1,resizable=1,menubar=0'; |
options += ',width=700,height=600'; |
options += ',width=700,height=600'; |
stdeditbrowser = open(url,title,options,'1'); |
stdeditbrowser = open(url,title,options,'1'); |
stdeditbrowser.focus(); |
stdeditbrowser.focus(); |
} |
} |
|
// ]]> |
</script> |
</script> |
ENDSTDBRW |
ENDSTDBRW |
} |
} |
|
|
|
sub resourcebrowser_javascript { |
|
unless ($env{'request.course.id'}) { return ''; } |
|
return (<<'ENDRESBRW'); |
|
<script type="text/javascript" language="Javascript"> |
|
// <![CDATA[ |
|
var reseditbrowser; |
|
function openresbrowser(formname,reslink) { |
|
var url = '/adm/pickresource?form='+formname+'&reslink='+reslink; |
|
var title = 'Resource_Browser'; |
|
var options = 'scrollbars=1,resizable=1,menubar=0'; |
|
options += ',width=700,height=500'; |
|
reseditbrowser = open(url,title,options,'1'); |
|
reseditbrowser.focus(); |
|
} |
|
// ]]> |
|
</script> |
|
ENDRESBRW |
|
} |
|
|
sub selectstudent_link { |
sub selectstudent_link { |
my ($form,$unameele,$udomele)=@_; |
my ($form,$unameele,$udomele,$courseadv,$clickerid,$identelem)=@_; |
|
my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','". |
|
&Apache::lonhtmlcommon::entity_encode($unameele)."','". |
|
&Apache::lonhtmlcommon::entity_encode($udomele)."'"; |
if ($env{'request.course.id'}) { |
if ($env{'request.course.id'}) { |
if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'}) |
if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'}) |
&& !&Apache::lonnet::allowed('srm',$env{'request.course.id'}. |
&& !&Apache::lonnet::allowed('srm',$env{'request.course.id'}. |
'/'.$env{'request.course.sec'})) { |
'/'.$env{'request.course.sec'})) { |
return ''; |
return ''; |
} |
} |
return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele. |
$callargs.=",'".&Apache::lonhtmlcommon::entity_encode($clickerid)."'"; |
'","'.$udomele.'");'."'>".&mt('Select User')."</a>"; |
if ($courseadv eq 'only') { |
|
$callargs .= ",'',1,'$courseadv'"; |
|
} elsif ($courseadv eq 'none') { |
|
$callargs .= ",'','','$courseadv'"; |
|
} elsif ($courseadv eq 'condition') { |
|
$callargs .= ",'','','$courseadv'"; |
|
} elsif ($identelem ne '') { |
|
$callargs .= ",'','',''"; |
|
} |
|
if ($identelem ne '') { |
|
$callargs .= ",'".&Apache::lonhtmlcommon::entity_encode($identelem)."'"; |
|
} |
|
return '<span class="LC_nobreak">'. |
|
'<a href="javascript:openstdbrowser('.$callargs.');">'. |
|
&mt('Select User').'</a></span>'; |
} |
} |
if ($env{'request.role'}=~/^(au|dc|su)/) { |
if ($env{'request.role'}=~/^(au|dc|su)/) { |
return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele. |
$callargs .= ",'',1"; |
'","'.$udomele.'",1);'."'>".&mt('Select User')."</a>"; |
return '<span class="LC_nobreak">'. |
|
'<a href="javascript:openstdbrowser('.$callargs.');">'. |
|
&mt('Select User').'</a></span>'; |
} |
} |
return ''; |
return ''; |
} |
} |
|
|
|
sub selectresource_link { |
|
my ($form,$reslink,$arg)=@_; |
|
|
|
my $callargs = "'".&Apache::lonhtmlcommon::entity_encode($form)."','". |
|
&Apache::lonhtmlcommon::entity_encode($reslink)."'"; |
|
unless ($env{'request.course.id'}) { return $arg; } |
|
return '<span class="LC_nobreak">'. |
|
'<a href="javascript:openresbrowser('.$callargs.');">'. |
|
$arg.'</a></span>'; |
|
} |
|
|
|
|
|
|
|
sub authorbrowser_javascript { |
|
return <<"ENDAUTHORBRW"; |
|
<script type="text/javascript" language="JavaScript"> |
|
// <![CDATA[ |
|
var stdeditbrowser; |
|
|
|
function openauthorbrowser(formname,udom) { |
|
var url = '/adm/pickauthor?'; |
|
url += 'form='+formname+'&roledom='+udom; |
|
var title = 'Author_Browser'; |
|
var options = 'scrollbars=1,resizable=1,menubar=0'; |
|
options += ',width=700,height=600'; |
|
stdeditbrowser = open(url,title,options,'1'); |
|
stdeditbrowser.focus(); |
|
} |
|
|
|
// ]]> |
|
</script> |
|
ENDAUTHORBRW |
|
} |
|
|
sub coursebrowser_javascript { |
sub coursebrowser_javascript { |
my ($domainfilter,$sec_element,$formname)=@_; |
my ($domainfilter,$sec_element,$formname,$role_element,$crstype, |
my $crs_or_grp_alert = &mt('Please select the type of LON-CAPA entity - Course or Group - for which you wish to add/modify a user role'); |
$credits_element,$instcode) = @_; |
my $output = ' |
my $wintitle = 'Course_Browser'; |
<script type="text/javascript"> |
if ($crstype eq 'Community') { |
|
$wintitle = 'Community_Browser'; |
|
} |
|
my $id_functions = &javascript_index_functions(); |
|
my $output = ' |
|
<script type="text/javascript" language="JavaScript"> |
|
// <![CDATA[ |
var stdeditbrowser;'."\n"; |
var stdeditbrowser;'."\n"; |
$output .= <<"ENDSTDBRW"; |
|
function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,crstype) { |
$output .= <<"ENDSTDBRW"; |
|
function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,type,type_elem) { |
var url = '/adm/pickcourse?'; |
var url = '/adm/pickcourse?'; |
var domainfilter = ''; |
|
var formid = getFormIdByName(formname); |
var formid = getFormIdByName(formname); |
if (formid > -1) { |
var domainfilter = getDomainFromSelectbox(formname,udom); |
var domid = getIndexByName(formid,udom); |
|
if (domid > -1) { |
|
if (document.forms[formid].elements[domid].type == 'select-one') { |
|
domainfilter=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value; |
|
} |
|
if (document.forms[formid].elements[domid].type == 'hidden') { |
|
domainfilter=document.forms[formid].elements[domid].value; |
|
} |
|
} |
|
} |
|
if (domainfilter != null) { |
if (domainfilter != null) { |
if (domainfilter != '') { |
if (domainfilter != '') { |
url += 'domainfilter='+domainfilter+'&'; |
url += 'domainfilter='+domainfilter+'&'; |
Line 405 sub coursebrowser_javascript {
|
Line 581 sub coursebrowser_javascript {
|
'&cdomelement='+udom+ |
'&cdomelement='+udom+ |
'&cnameelement='+desc; |
'&cnameelement='+desc; |
if (extra_element !=null && extra_element != '') { |
if (extra_element !=null && extra_element != '') { |
if (formname == 'rolechoice') { |
if (formname == 'rolechoice' || formname == 'studentform') { |
url += '&roleelement='+extra_element; |
url += '&roleelement='+extra_element; |
if (domainfilter == null || domainfilter == '') { |
if (domainfilter == null || domainfilter == '') { |
url += '&domainfilter='+extra_element; |
url += '&domainfilter='+extra_element; |
Line 414 sub coursebrowser_javascript {
|
Line 590 sub coursebrowser_javascript {
|
else { |
else { |
if (formname == 'portform') { |
if (formname == 'portform') { |
url += '&setroles='+extra_element; |
url += '&setroles='+extra_element; |
|
} else { |
|
if (formname == 'rules') { |
|
url += '&fixeddom='+extra_element; |
|
} |
} |
} |
} |
} |
} |
} |
if (multflag !=null && multflag != '') { |
if (type != null && type != '') { |
url += '&multiple='+multflag; |
url += '&type='+type; |
} |
} |
if (crstype == 'Course/Group') { |
if (type_elem != null && type_elem != '') { |
if (formname == 'cu') { |
url += '&typeelement='+type_elem; |
crstype = document.cu.crstype.options[document.cu.crstype.selectedIndex].value; |
} |
if (crstype == "") { |
if (formname == 'ccrs') { |
alert("$crs_or_grp_alert"); |
var ownername = document.forms[formid].ccuname.value; |
return; |
var ownerdom = document.forms[formid].ccdomain.options[document.forms[formid].ccdomain.selectedIndex].value; |
} |
url += '&cloner='+ownername+':'+ownerdom; |
|
if (type == 'Course') { |
|
url += '&crscode='+document.forms[formid].crscode.value; |
} |
} |
} |
} |
if (crstype !=null && crstype != '') { |
if (formname == 'requestcrs') { |
url += '&type='+crstype; |
url += '&crsdom=$domainfilter&crscode=$instcode'; |
|
} |
|
if (multflag !=null && multflag != '') { |
|
url += '&multiple='+multflag; |
} |
} |
var title = 'Course_Browser'; |
var title = '$wintitle'; |
var options = 'scrollbars=1,resizable=1,menubar=0'; |
var options = 'scrollbars=1,resizable=1,menubar=0'; |
options += ',width=700,height=600'; |
options += ',width=700,height=600'; |
stdeditbrowser = open(url,title,options,'1'); |
stdeditbrowser = open(url,title,options,'1'); |
stdeditbrowser.focus(); |
stdeditbrowser.focus(); |
} |
} |
|
$id_functions |
|
ENDSTDBRW |
|
if (($sec_element ne '') || ($role_element ne '') || ($credits_element ne '')) { |
|
$output .= &setsec_javascript($sec_element,$formname,$role_element, |
|
$credits_element); |
|
} |
|
$output .= ' |
|
// ]]> |
|
</script>'; |
|
return $output; |
|
} |
|
|
function getFormIdByName(formname) { |
sub javascript_index_functions { |
for (var i=0;i<document.forms.length;i++) { |
return <<"ENDJS"; |
if (document.forms[i].name == formname) { |
|
return i; |
function getFormIdByName(formname) { |
|
for (var i=0;i<document.forms.length;i++) { |
|
if (document.forms[i].name == formname) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
function getIndexByName(formid,item) { |
|
for (var i=0;i<document.forms[formid].elements.length;i++) { |
|
if (document.forms[formid].elements[i].name == item) { |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
function getDomainFromSelectbox(formname,udom) { |
|
var userdom; |
|
var formid = getFormIdByName(formname); |
|
if (formid > -1) { |
|
var domid = getIndexByName(formid,udom); |
|
if (domid > -1) { |
|
if (document.forms[formid].elements[domid].type == 'select-one') { |
|
userdom=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value; |
|
} |
|
if (document.forms[formid].elements[domid].type == 'hidden') { |
|
userdom=document.forms[formid].elements[domid].value; |
} |
} |
} |
} |
return -1; |
|
} |
} |
|
return userdom; |
|
} |
|
|
|
ENDJS |
|
|
function getIndexByName(formid,item) { |
} |
for (var i=0;i<document.forms[formid].elements.length;i++) { |
|
if (document.forms[formid].elements[i].name == item) { |
sub javascript_array_indexof { |
return i; |
return <<ENDJS; |
|
<script type="text/javascript" language="JavaScript"> |
|
// <![CDATA[ |
|
|
|
if (!Array.prototype.indexOf) { |
|
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { |
|
"use strict"; |
|
if (this === void 0 || this === null) { |
|
throw new TypeError(); |
|
} |
|
var t = Object(this); |
|
var len = t.length >>> 0; |
|
if (len === 0) { |
|
return -1; |
|
} |
|
var n = 0; |
|
if (arguments.length > 0) { |
|
n = Number(arguments[1]); |
|
if (n !== n) { // shortcut for verifying if it's NaN |
|
n = 0; |
|
} else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { |
|
n = (n > 0 || -1) * Math.floor(Math.abs(n)); |
|
} |
|
} |
|
if (n >= len) { |
|
return -1; |
|
} |
|
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); |
|
for (; k < len; k++) { |
|
if (k in t && t[k] === searchElement) { |
|
return k; |
} |
} |
} |
} |
return -1; |
return -1; |
} |
} |
ENDSTDBRW |
} |
if ($sec_element ne '') { |
|
$output .= &setsec_javascript($sec_element,$formname); |
// ]]> |
|
</script> |
|
|
|
ENDJS |
|
|
|
} |
|
|
|
sub userbrowser_javascript { |
|
my $id_functions = &javascript_index_functions(); |
|
return <<"ENDUSERBRW"; |
|
|
|
function openuserbrowser(formname,uname,udom,ulast,ufirst,uemail,hideudom,crsdom,caller) { |
|
var url = '/adm/pickuser?'; |
|
var userdom = getDomainFromSelectbox(formname,udom); |
|
if (userdom != null) { |
|
if (userdom != '') { |
|
url += 'srchdom='+userdom+'&'; |
|
} |
} |
} |
$output .= ' |
url += 'form=' + formname + '&unameelement='+uname+ |
</script>'; |
'&udomelement='+udom+ |
return $output; |
'&ulastelement='+ulast+ |
|
'&ufirstelement='+ufirst+ |
|
'&uemailelement='+uemail+ |
|
'&hideudomelement='+hideudom+ |
|
'&coursedom='+crsdom; |
|
if ((caller != null) && (caller != undefined)) { |
|
url += '&caller='+caller; |
|
} |
|
var title = 'User_Browser'; |
|
var options = 'scrollbars=1,resizable=1,menubar=0'; |
|
options += ',width=700,height=600'; |
|
var stdeditbrowser = open(url,title,options,'1'); |
|
stdeditbrowser.focus(); |
|
} |
|
|
|
function fix_domain (formname,udom,origdom,uname) { |
|
var formid = getFormIdByName(formname); |
|
if (formid > -1) { |
|
var unameid = getIndexByName(formid,uname); |
|
var domid = getIndexByName(formid,udom); |
|
var hidedomid = getIndexByName(formid,origdom); |
|
if (hidedomid > -1) { |
|
var fixeddom = document.forms[formid].elements[hidedomid].value; |
|
var unameval = document.forms[formid].elements[unameid].value; |
|
if ((fixeddom != '') && (fixeddom != undefined) && (fixeddom != null) && (unameval != '') && (unameval != undefined) && (unameval != null)) { |
|
if (domid > -1) { |
|
var slct = document.forms[formid].elements[domid]; |
|
if (slct.type == 'select-one') { |
|
var i; |
|
for (i=0;i<slct.length;i++) { |
|
if (slct.options[i].value==fixeddom) { slct.selectedIndex=i; } |
|
} |
|
} |
|
if (slct.type == 'hidden') { |
|
slct.value = fixeddom; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
$id_functions |
|
ENDUSERBRW |
} |
} |
|
|
sub setsec_javascript { |
sub setsec_javascript { |
my ($sec_element,$formname) = @_; |
my ($sec_element,$formname,$role_element,$credits_element) = @_; |
|
my (@courserolenames,@communityrolenames,$rolestr,$courserolestr, |
|
$communityrolestr); |
|
if ($role_element ne '') { |
|
my @allroles = ('st','ta','ep','in','ad'); |
|
foreach my $crstype ('Course','Community') { |
|
if ($crstype eq 'Community') { |
|
foreach my $role (@allroles) { |
|
push(@communityrolenames,&Apache::lonnet::plaintext($role,$crstype)); |
|
} |
|
push(@communityrolenames,&Apache::lonnet::plaintext('co')); |
|
} else { |
|
foreach my $role (@allroles) { |
|
push(@courserolenames,&Apache::lonnet::plaintext($role,$crstype)); |
|
} |
|
push(@courserolenames,&Apache::lonnet::plaintext('cc')); |
|
} |
|
} |
|
$rolestr = '"'.join('","',@allroles).'"'; |
|
$courserolestr = '"'.join('","',@courserolenames).'"'; |
|
$communityrolestr = '"'.join('","',@communityrolenames).'"'; |
|
} |
my $setsections = qq| |
my $setsections = qq| |
function setSect(sectionlist) { |
function setSect(sectionlist) { |
var sectionsArray = sectionlist.split(","); |
var sectionsArray = new Array(); |
|
if ((sectionlist != '') && (typeof sectionlist != "undefined")) { |
|
sectionsArray = sectionlist.split(","); |
|
} |
var numSections = sectionsArray.length; |
var numSections = sectionsArray.length; |
document.$formname.$sec_element.length = 0; |
document.$formname.$sec_element.length = 0; |
if (numSections == 0) { |
if (numSections == 0) { |
Line 497 function setSect(sectionlist) {
|
Line 839 function setSect(sectionlist) {
|
} |
} |
} |
} |
} |
} |
|
|
|
function setRole(crstype) { |
|; |
|; |
|
if ($role_element eq '') { |
|
$setsections .= ' return; |
|
} |
|
'; |
|
} else { |
|
$setsections .= qq| |
|
var elementLength = document.$formname.$role_element.length; |
|
var allroles = Array($rolestr); |
|
var courserolenames = Array($courserolestr); |
|
var communityrolenames = Array($communityrolestr); |
|
if (elementLength != undefined) { |
|
if (document.$formname.$role_element.options[5].value == 'cc') { |
|
if (crstype == 'Course') { |
|
return; |
|
} else { |
|
allroles[5] = 'co'; |
|
for (var i=0; i<6; i++) { |
|
document.$formname.$role_element.options[i].value = allroles[i]; |
|
document.$formname.$role_element.options[i].text = communityrolenames[i]; |
|
} |
|
} |
|
} else { |
|
if (crstype == 'Community') { |
|
return; |
|
} else { |
|
allroles[5] = 'cc'; |
|
for (var i=0; i<6; i++) { |
|
document.$formname.$role_element.options[i].value = allroles[i]; |
|
document.$formname.$role_element.options[i].text = courserolenames[i]; |
|
} |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|; |
|
} |
|
if ($credits_element) { |
|
$setsections .= qq| |
|
function setCredits(defaultcredits) { |
|
document.$formname.$credits_element.value = defaultcredits; |
|
return; |
|
} |
|
|; |
|
} |
return $setsections; |
return $setsections; |
} |
} |
|
|
|
|
sub selectcourse_link { |
sub selectcourse_link { |
my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype)=@_; |
my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype, |
return "<a href='".'javascript:opencrsbrowser("'.$form.'","'.$unameele. |
$typeelement) = @_; |
'","'.$udomele.'","'.$desc.'","'.$extra_element.'","'.$multflag.'","'.$selecttype.'");'."'>".&mt('Select Course')."</a>"; |
my $type = $selecttype; |
|
my $linktext = &mt('Select Course'); |
|
if ($selecttype eq 'Community') { |
|
$linktext = &mt('Select Community'); |
|
} elsif ($selecttype eq 'Course/Community') { |
|
$linktext = &mt('Select Course/Community'); |
|
$type = ''; |
|
} elsif ($selecttype eq 'Select') { |
|
$linktext = &mt('Select'); |
|
$type = ''; |
|
} |
|
return '<span class="LC_nobreak">' |
|
."<a href='" |
|
.'javascript:opencrsbrowser("'.$form.'","'.$unameele |
|
.'","'.$udomele.'","'.$desc.'","'.$extra_element |
|
.'","'.$multflag.'","'.$type.'","'.$typeelement.'");' |
|
."'>".$linktext.'</a>' |
|
.'</span>'; |
|
} |
|
|
|
sub selectauthor_link { |
|
my ($form,$udom)=@_; |
|
return '<a href="javascript:openauthorbrowser('."'$form','$udom'".');">'. |
|
&mt('Select Author').'</a>'; |
|
} |
|
|
|
sub selectuser_link { |
|
my ($form,$unameelem,$domelem,$lastelem,$firstelem,$emailelem,$hdomelem, |
|
$coursedom,$linktext,$caller) = @_; |
|
return '<a href="javascript:openuserbrowser('."'$form','$unameelem','$domelem',". |
|
"'$lastelem','$firstelem','$emailelem','$hdomelem','$coursedom','$caller'". |
|
');">'.$linktext.'</a>'; |
} |
} |
|
|
sub check_uncheck_jscript { |
sub check_uncheck_jscript { |
Line 513 sub check_uncheck_jscript {
|
Line 932 sub check_uncheck_jscript {
|
function checkAll(field) { |
function checkAll(field) { |
if (field.length > 0) { |
if (field.length > 0) { |
for (i = 0; i < field.length; i++) { |
for (i = 0; i < field.length; i++) { |
field[i].checked = true ; |
if (!field[i].disabled) { |
|
field[i].checked = true; |
|
} |
} |
} |
} else { |
} else { |
field.checked = true |
if (!field.disabled) { |
|
field.checked = true; |
|
} |
} |
} |
} |
} |
|
|
Line 533 ENDSCRT
|
Line 956 ENDSCRT
|
return $jscript; |
return $jscript; |
} |
} |
|
|
|
sub select_timezone { |
|
my ($name,$selected,$onchange,$includeempty,$id,$disabled)=@_; |
|
my $output='<select name="'.$name.'" '.$id.$onchange.$disabled.'>'."\n"; |
|
if ($includeempty) { |
|
$output .= '<option value=""'; |
|
if (($selected eq '') || ($selected eq 'local')) { |
|
$output .= ' selected="selected" '; |
|
} |
|
$output .= '> </option>'; |
|
} |
|
my @timezones = DateTime::TimeZone->all_names; |
|
foreach my $tzone (@timezones) { |
|
$output.= '<option value="'.$tzone.'"'; |
|
if ($tzone eq $selected) { |
|
$output.=' selected="selected"'; |
|
} |
|
$output.=">$tzone</option>\n"; |
|
} |
|
$output.="</select>"; |
|
return $output; |
|
} |
|
|
|
sub select_datelocale { |
|
my ($name,$selected,$onchange,$includeempty,$disabled)=@_; |
|
my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n"; |
|
if ($includeempty) { |
|
$output .= '<option value=""'; |
|
if ($selected eq '') { |
|
$output .= ' selected="selected" '; |
|
} |
|
$output .= '> </option>'; |
|
} |
|
my @languages = &Apache::lonlocal::preferred_languages(); |
|
my (@possibles,%locale_names); |
|
my @locales = DateTime::Locale->ids(); |
|
foreach my $id (@locales) { |
|
if ($id ne '') { |
|
my ($en_terr,$native_terr); |
|
my $loc = DateTime::Locale->load($id); |
|
if (ref($loc)) { |
|
$en_terr = $loc->name(); |
|
$native_terr = $loc->native_name(); |
|
if (grep(/^en$/,@languages) || !@languages) { |
|
if ($en_terr ne '') { |
|
$locale_names{$id} = '('.$en_terr.')'; |
|
} elsif ($native_terr ne '') { |
|
$locale_names{$id} = $native_terr; |
|
} |
|
} else { |
|
if ($native_terr ne '') { |
|
$locale_names{$id} = $native_terr.' '; |
|
} elsif ($en_terr ne '') { |
|
$locale_names{$id} = '('.$en_terr.')'; |
|
} |
|
} |
|
$locale_names{$id} = Encode::encode('UTF-8',$locale_names{$id}); |
|
push(@possibles,$id); |
|
} |
|
} |
|
} |
|
foreach my $item (sort(@possibles)) { |
|
$output.= '<option value="'.$item.'"'; |
|
if ($item eq $selected) { |
|
$output.=' selected="selected"'; |
|
} |
|
$output.=">$item"; |
|
if ($locale_names{$item} ne '') { |
|
$output.=' '.$locale_names{$item}; |
|
} |
|
$output.="</option>\n"; |
|
} |
|
$output.="</select>"; |
|
return $output; |
|
} |
|
|
|
sub select_language { |
|
my ($name,$selected,$includeempty,$noedit) = @_; |
|
my %langchoices; |
|
if ($includeempty) { |
|
%langchoices = ('' => 'No language preference'); |
|
} |
|
foreach my $id (&languageids()) { |
|
my $code = &supportedlanguagecode($id); |
|
if ($code) { |
|
$langchoices{$code} = &plainlanguagedescription($id); |
|
} |
|
} |
|
%langchoices = &Apache::lonlocal::texthash(%langchoices); |
|
return &select_form($selected,$name,\%langchoices,undef,$noedit); |
|
} |
|
|
=pod |
=pod |
|
|
=item * linked_select_forms(...) |
=item * &linked_select_forms(...) |
|
|
linked_select_forms returns a string containing a <script></script> block |
linked_select_forms returns a string containing a <script></script> block |
and html for two <select> menus. The select menus will be linked in that |
and html for two <select> menus. The select menus will be linked in that |
changing the value of the first menu will result in new values being placed |
changing the value of the first menu will result in new values being placed |
in the second menu. The values in the select menu will appear in alphabetical |
in the second menu. The values in the select menu will appear in alphabetical |
order. |
order unless a defined order is provided. |
|
|
linked_select_forms takes the following ordered inputs: |
linked_select_forms takes the following ordered inputs: |
|
|
Line 560 linked_select_forms takes the following
|
Line 1073 linked_select_forms takes the following
|
|
|
=item * $hashref, a reference to a hash containing the data for the menus. |
=item * $hashref, a reference to a hash containing the data for the menus. |
|
|
|
=item * $menuorder, the order of values in the first menu |
|
|
|
=item * $onchangefirst, additional javascript call to execute for an onchange |
|
event for the first <select> tag |
|
|
|
=item * $onchangesecond, additional javascript call to execute for an onchange |
|
event for the second <select> tag |
|
|
=back |
=back |
|
|
Below is an example of such a hash. Only the 'text', 'default', and |
Below is an example of such a hash. Only the 'text', 'default', and |
Line 576 $menu{$choice1}->{'select2'}.
|
Line 1097 $menu{$choice1}->{'select2'}.
|
B2 => "Choice B2", |
B2 => "Choice B2", |
B3 => "Choice B3", |
B3 => "Choice B3", |
B4 => "Choice B4" |
B4 => "Choice B4" |
} |
}, |
|
order => ['B4','B3','B1','B2'], |
}, |
}, |
A2 => { text =>"Choice A2" , |
A2 => { text =>"Choice A2" , |
default => "C2", |
default => "C2", |
Line 584 $menu{$choice1}->{'select2'}.
|
Line 1106 $menu{$choice1}->{'select2'}.
|
C1 => "Choice C1", |
C1 => "Choice C1", |
C2 => "Choice C2", |
C2 => "Choice C2", |
C3 => "Choice C3" |
C3 => "Choice C3" |
} |
}, |
|
order => ['C2','C1','C3'], |
}, |
}, |
A3 => { text =>"Choice A3" , |
A3 => { text =>"Choice A3" , |
default => "D6", |
default => "D6", |
Line 596 $menu{$choice1}->{'select2'}.
|
Line 1119 $menu{$choice1}->{'select2'}.
|
D5 => "Choice D5", |
D5 => "Choice D5", |
D6 => "Choice D6", |
D6 => "Choice D6", |
D7 => "Choice D7" |
D7 => "Choice D7" |
} |
}, |
|
order => ['D4','D3','D2','D1','D7','D6','D5'], |
} |
} |
); |
); |
|
|
Line 608 sub linked_select_forms {
|
Line 1132 sub linked_select_forms {
|
$firstdefault, |
$firstdefault, |
$firstselectname, |
$firstselectname, |
$secondselectname, |
$secondselectname, |
$hashref |
$hashref, |
|
$menuorder, |
|
$onchangefirst, |
|
$onchangesecond |
) = @_; |
) = @_; |
my $second = "document.$formname.$secondselectname"; |
my $second = "document.$formname.$secondselectname"; |
my $first = "document.$formname.$firstselectname"; |
my $first = "document.$formname.$firstselectname"; |
# output the javascript to do the changing |
# output the javascript to do the changing |
my $result = ''; |
my $result = ''; |
$result.="<script type=\"text/javascript\">\n"; |
$result.='<script type="text/javascript" language="JavaScript">'."\n"; |
|
$result.="// <![CDATA[\n"; |
$result.="var select2data = new Object();\n"; |
$result.="var select2data = new Object();\n"; |
$" = '","'; |
$" = '","'; |
my $debug = ''; |
my $debug = ''; |
Line 622 sub linked_select_forms {
|
Line 1150 sub linked_select_forms {
|
$result.="select2data.d_$s1 = new Object();\n"; |
$result.="select2data.d_$s1 = new Object();\n"; |
$result.="select2data.d_$s1.def = new String('". |
$result.="select2data.d_$s1.def = new String('". |
$hashref->{$s1}->{'default'}."');\n"; |
$hashref->{$s1}->{'default'}."');\n"; |
$result.="select2data.d_$s1.values = new Array("; |
$result.="select2data.d_$s1.values = new Array("; |
my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } )); |
my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } )); |
|
if (ref($hashref->{$s1}->{'order'}) eq 'ARRAY') { |
|
@s2values = @{$hashref->{$s1}->{'order'}}; |
|
} |
$result.="\"@s2values\");\n"; |
$result.="\"@s2values\");\n"; |
$result.="select2data.d_$s1.texts = new Array("; |
$result.="select2data.d_$s1.texts = new Array("; |
my @s2texts; |
my @s2texts; |
foreach my $value (@s2values) { |
foreach my $value (@s2values) { |
push @s2texts, $hashref->{$s1}->{'select2'}->{$value}; |
push(@s2texts, $hashref->{$s1}->{'select2'}->{$value}); |
} |
} |
$result.="\"@s2texts\");\n"; |
$result.="\"@s2texts\");\n"; |
} |
} |
Line 657 function select1_changed() {
|
Line 1188 function select1_changed() {
|
} |
} |
} |
} |
} |
} |
|
// ]]> |
</script> |
</script> |
END |
END |
# output the initial values for the selection lists |
# output the initial values for the selection lists |
$result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n"; |
$result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed();$onchangefirst\">\n"; |
foreach my $value (sort(keys(%$hashref))) { |
my @order = sort(keys(%{$hashref})); |
|
if (ref($menuorder) eq 'ARRAY') { |
|
@order = @{$menuorder}; |
|
} |
|
foreach my $value (@order) { |
$result.=" <option value=\"$value\" "; |
$result.=" <option value=\"$value\" "; |
$result.=" selected=\"selected\" " if ($value eq $firstdefault); |
$result.=" selected=\"selected\" " if ($value eq $firstdefault); |
$result.=">".&mt($hashref->{$value}->{'text'})."</option>\n"; |
$result.=">".&mt($hashref->{$value}->{'text'})."</option>\n"; |
Line 669 END
|
Line 1205 END
|
$result .= "</select>\n"; |
$result .= "</select>\n"; |
my %select2 = %{$hashref->{$firstdefault}->{'select2'}}; |
my %select2 = %{$hashref->{$firstdefault}->{'select2'}}; |
$result .= $middletext; |
$result .= $middletext; |
$result .= "<select size=\"1\" name=\"$secondselectname\">\n"; |
$result .= "<select size=\"1\" name=\"$secondselectname\""; |
|
if ($onchangesecond) { |
|
$result .= ' onchange="'.$onchangesecond.'"'; |
|
} |
|
$result .= ">\n"; |
my $seconddefault = $hashref->{$firstdefault}->{'default'}; |
my $seconddefault = $hashref->{$firstdefault}->{'default'}; |
foreach my $value (sort(keys(%select2))) { |
|
|
my @secondorder = sort(keys(%select2)); |
|
if (ref($hashref->{$firstdefault}->{'order'}) eq 'ARRAY') { |
|
@secondorder = @{$hashref->{$firstdefault}->{'order'}}; |
|
} |
|
foreach my $value (@secondorder) { |
$result.=" <option value=\"$value\" "; |
$result.=" <option value=\"$value\" "; |
$result.=" selected=\"selected\" " if ($value eq $seconddefault); |
$result.=" selected=\"selected\" " if ($value eq $seconddefault); |
$result.=">".&mt($select2{$value})."</option>\n"; |
$result.=">".&mt($select2{$value})."</option>\n"; |
Line 683 END
|
Line 1228 END
|
|
|
=pod |
=pod |
|
|
=item * help_open_topic($topic, $text, $stayOnPage, $width, $height) |
=item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid,$links_target) |
|
|
Returns a string corresponding to an HTML link to the given help |
Returns a string corresponding to an HTML link to the given help |
$topic, where $topic corresponds to the name of a .tex file in |
$topic, where $topic corresponds to the name of a .tex file in |
Line 701 a new window using Javascript. (Default
|
Line 1246 a new window using Javascript. (Default
|
|
|
$width and $height are optional numerical parameters that will |
$width and $height are optional numerical parameters that will |
override the width and height of the popped up window, which may |
override the width and height of the popped up window, which may |
be useful for certain help topics with big pictures included. |
be useful for certain help topics with big pictures included. |
|
|
|
$imgid is the id of the img tag used for the help icon. This may be |
|
used in a javascript call to switch the image src. See |
|
lonhtmlcommon::htmlareaselectactive() for an example. |
|
|
|
$links_target will optionally be set to a target (_top, _parent or _self). |
|
|
=cut |
=cut |
|
|
sub help_open_topic { |
sub help_open_topic { |
my ($topic, $text, $stayOnPage, $width, $height) = @_; |
my ($topic, $text, $stayOnPage, $width, $height, $imgid, $links_target) = @_; |
$text = "" if (not defined $text); |
$text = "" if (not defined $text); |
$stayOnPage = 0 if (not defined $stayOnPage); |
$stayOnPage = 0 if (not defined $stayOnPage); |
if ($env{'browser.interface'} eq 'textual') { |
$width = 500 if (not defined $width); |
$stayOnPage=1; |
|
} |
|
$width = 350 if (not defined $width); |
|
$height = 400 if (not defined $height); |
$height = 400 if (not defined $height); |
my $filename = $topic; |
my $filename = $topic; |
$filename =~ s/ /_/g; |
$filename =~ s/ /_/g; |
|
|
my $template = ""; |
my $template = ""; |
my $link; |
my $link; |
|
|
$topic=~s/\W/\_/g; |
$topic=~s/\W/\_/g; |
|
|
if (!$stayOnPage) |
if (!$stayOnPage) { |
{ |
if ($env{'browser.mobile'}) { |
$link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))"; |
$link = "javascript:openMyModal('/adm/help/${filename}.hlp',$width,$height,'yes');"; |
} |
} else { |
else |
$link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))"; |
{ |
} |
|
} elsif ($stayOnPage eq 'popup') { |
|
$link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))"; |
|
} else { |
$link = "/adm/help/${filename}.hlp"; |
$link = "/adm/help/${filename}.hlp"; |
} |
} |
|
|
# Add the text |
# Add the text |
if ($text ne "") |
my $target = ' target="_top"'; |
{ |
if ($links_target) { |
$template .= |
$target = ' target="'.$links_target.'"'; |
"<table bgcolor='#3333AA' cellspacing='1' cellpadding='1' border='0'><tr>". |
} elsif ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) || |
"<td bgcolor='#5555FF'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; |
(($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) { |
|
$target = ''; |
|
} |
|
if ($text ne "") { |
|
$template.='<span class="LC_help_open_topic">' |
|
.'<a'.$target.' href="'.$link.'">' |
|
.$text.'</a>'; |
} |
} |
|
|
# Add the graphic |
# (Always) Add the graphic |
my $title = &mt('Online Help'); |
my $title = &mt('Online Help'); |
my $helpicon=&lonhttpdurl("/adm/help/gif/smallHelp.gif"); |
my $helpicon=&lonhttpdurl("/adm/help/help.png"); |
$template .= <<"ENDTEMPLATE"; |
if ($imgid ne '') { |
<a target="_top" href="$link" title="$title"><img src="$helpicon" border="0" alt="(Help: $topic)" /></a> |
$imgid = ' id="'.$imgid.'"'; |
ENDTEMPLATE |
} |
if ($text ne '') { $template.='</td></tr></table>' }; |
$template.=' <a'.$target.' href="'.$link.'" title="'.$title.'">' |
|
.'<img src="'.$helpicon.'" border="0"' |
|
.' alt="'.&mt('Help: [_1]',$topic).'"' |
|
.' title="'.$title.'" style="vertical-align:middle;"'.$imgid |
|
.' /></a>'; |
|
if ($text ne "") { |
|
$template.='</span>'; |
|
} |
return $template; |
return $template; |
|
|
} |
} |
Line 753 ENDTEMPLATE
|
Line 1317 ENDTEMPLATE
|
# This is a quicky function for Latex cheatsheet editing, since it |
# This is a quicky function for Latex cheatsheet editing, since it |
# appears in at least four places |
# appears in at least four places |
sub helpLatexCheatsheet { |
sub helpLatexCheatsheet { |
my $other = shift; |
my ($topic,$text,$not_author,$stayOnPage) = @_; |
|
my $out; |
my $addOther = ''; |
my $addOther = ''; |
if ($other) { |
if ($topic) { |
$addOther = Apache::loncommon::help_open_topic($other, shift, |
$addOther = '<span>'.&help_open_topic($topic,&mt($text),$stayOnPage, undef, 600).'</span> '; |
undef, undef, 600) . |
} |
'</td><td>'; |
$out = '<span>' # Start cheatsheet |
} |
.$addOther |
return '<table><tr><td>'. |
.'<span>' |
$addOther . |
.&help_open_topic('Greek_Symbols',&mt('Greek Symbols'),$stayOnPage,undef,600) |
&Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols', |
.'</span> <span>' |
undef,undef,600) |
.&help_open_topic('Other_Symbols',&mt('Other Symbols'),$stayOnPage,undef,600) |
.'</td><td>'. |
.'</span>'; |
&Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols', |
unless ($not_author) { |
undef,undef,600) |
$out .= ' <span>' |
.'</td></tr></table>'; |
.&help_open_topic('Authoring_Output_Tags',&mt('Output Tags'),$stayOnPage,undef,600) |
|
.'</span> <span>' |
|
.&help_open_topic('Authoring_Multilingual_Problems',&mt('Languages'),$stayOnPage,undef,600) |
|
.'</span>'; |
|
} |
|
$out .= '</span>'; # End cheatsheet |
|
return $out; |
} |
} |
|
|
sub general_help { |
sub general_help { |
my $helptopic='Student_Intro'; |
my $helptopic='Student_Intro'; |
if ($env{'request.role'}=~/^(ca|au)/) { |
if ($env{'request.role'}=~/^(ca|au)/) { |
$helptopic='Authoring_Intro'; |
$helptopic='Authoring_Intro'; |
} elsif ($env{'request.role'}=~/^cc/) { |
} elsif ($env{'request.role'}=~/^(cc|co)/) { |
$helptopic='Course_Coordination_Intro'; |
$helptopic='Course_Coordination_Intro'; |
|
} elsif ($env{'request.role'}=~/^dc/) { |
|
$helptopic='Domain_Coordination_Intro'; |
} |
} |
return $helptopic; |
return $helptopic; |
} |
} |
Line 792 sub update_help_link {
|
Line 1365 sub update_help_link {
|
my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage"; |
my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage"; |
my $output .= <<"ENDOUTPUT"; |
my $output .= <<"ENDOUTPUT"; |
<script type="text/javascript"> |
<script type="text/javascript"> |
|
// <![CDATA[ |
banner_link = '$banner_link'; |
banner_link = '$banner_link'; |
|
// ]]> |
</script> |
</script> |
ENDOUTPUT |
ENDOUTPUT |
return $output; |
return $output; |
Line 800 ENDOUTPUT
|
Line 1375 ENDOUTPUT
|
|
|
# now just updates the help link and generates a blue icon |
# now just updates the help link and generates a blue icon |
sub help_open_menu { |
sub help_open_menu { |
my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text) |
my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text,$links_target) |
= @_; |
= @_; |
&Apache::lonnet::logthis("stayonpage is $stayOnPage"); |
$stayOnPage = 1; |
$stayOnPage = 0 if (not defined $stayOnPage); |
|
# formerly only used pop-up help (stayOnPage = 0) |
|
# if environment.remote is on (using remote control UI) |
|
# if ($env{'browser.interface'} eq 'textual' || |
|
# $env{'environment.remote'} eq 'off' ) { |
|
# $stayOnPage=1; |
|
#} |
|
# Now making pop-up help the default even with remote control |
|
if ($env{'browser.interface'} eq 'textual') { |
|
$stayOnPage=1; |
|
} |
|
my $output; |
my $output; |
if ($component_help) { |
if ($component_help) { |
if (!$text) { |
if (!$text) { |
$output=&help_open_topic($component_help,undef,$stayOnPage, |
$output=&help_open_topic($component_help,undef,$stayOnPage, |
$width,$height); |
$width,$height,'',$links_target); |
} else { |
} else { |
my $help_text; |
my $help_text; |
$help_text=&unescape($topic); |
$help_text=&unescape($topic); |
$output='<table><tr><td>'. |
$output='<table><tr><td>'. |
&help_open_topic($component_help,$help_text,$stayOnPage, |
&help_open_topic($component_help,$help_text,$stayOnPage, |
$width,$height).'</td></tr></table>'; |
$width,$height,'',$links_target).'</td></tr></table>'; |
} |
} |
} |
} |
my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage); |
my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage); |
Line 832 sub help_open_menu {
|
Line 1396 sub help_open_menu {
|
} |
} |
|
|
sub top_nav_help { |
sub top_nav_help { |
my ($text) = @_; |
my ($text,$linkattr) = @_; |
|
|
$text = &mt($text); |
$text = &mt($text); |
|
my $stay_on_page; |
my $stayOnPage = |
unless ($env{'environment.remote'} eq 'on') { |
($env{'browser.interface'} eq 'textual' || |
$stay_on_page = 1; |
$env{'environment.remote'} eq 'off' ); |
} |
my $link= ($stayOnPage) ? "javascript:helpMenu('display')" |
my ($link,$banner_link); |
: "javascript:helpMenu('open')"; |
unless ($env{'request.noversionuri'} =~ m{^/adm/helpmenu}) { |
my $banner_link = &update_help_link(undef,undef,undef,undef,$stayOnPage); |
$link = ($stay_on_page) ? "javascript:helpMenu('display')" |
|
: "javascript:helpMenu('open')"; |
|
$banner_link = &update_help_link(undef,undef,undef,undef,$stay_on_page); |
|
} |
my $title = &mt('Get help'); |
my $title = &mt('Get help'); |
|
if ($link) { |
return <<"END"; |
return <<"END"; |
$banner_link |
$banner_link |
<a href="$link" title="$title">$text</a> |
<a href="$link" title="$title" $linkattr>$text</a> |
END |
END |
|
} else { |
|
return ' '.$text.' '; |
|
} |
} |
} |
|
|
sub help_menu_js { |
sub help_menu_js { |
my ($text) = @_; |
my ($httphost) = @_; |
|
my $stayOnPage = 1; |
my $stayOnPage = |
|
($env{'browser.interface'} eq 'textual' || |
|
$env{'environment.remote'} eq 'off' ); |
|
|
|
my $width = 620; |
my $width = 620; |
my $height = 600; |
my $height = 600; |
my $helptopic=&general_help(); |
my $helptopic=&general_help(); |
my $details_link = '/adm/help/'.$helptopic.'.hlp'; |
my $details_link = $httphost.'/adm/help/'.$helptopic.'.hlp'; |
my $nothing=&Apache::lonhtmlcommon::javascript_nothing(); |
my $nothing=&Apache::lonhtmlcommon::javascript_nothing(); |
my $start_page = |
my $start_page = |
&Apache::loncommon::start_page('Help Menu', undef, |
&Apache::loncommon::start_page('Help Menu', undef, |
{'frameset' => 1, |
{'frameset' => 1, |
'js_ready' => 1, |
'js_ready' => 1, |
|
'use_absolute' => $httphost, |
'add_entries' => { |
'add_entries' => { |
'border' => '0', |
'border' => '0', |
'rows' => "105,*",},}); |
'rows' => "110,*",},}); |
my $end_page = |
my $end_page = |
&Apache::loncommon::end_page({'frameset' => 1, |
&Apache::loncommon::end_page({'frameset' => 1, |
'js_ready' => 1,}); |
'js_ready' => 1,}); |
|
|
my $template .= <<"ENDTEMPLATE"; |
my $template .= <<"ENDTEMPLATE"; |
<script type="text/javascript"> |
<script type="text/javascript"> |
// <!-- BEGIN LON-CAPA Internal |
|
// <![CDATA[ |
// <![CDATA[ |
|
// <!-- BEGIN LON-CAPA Internal |
var banner_link = ''; |
var banner_link = ''; |
function helpMenu(target) { |
function helpMenu(target) { |
var caller = this; |
var caller = this; |
Line 898 function helpMenu(target) {
|
Line 1463 function helpMenu(target) {
|
return; |
return; |
} |
} |
function writeHelp(caller) { |
function writeHelp(caller) { |
caller.document.writeln('$start_page<frame name="bannerframe" src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page') |
caller.document.writeln('$start_page\\n<frame name="bannerframe" src="'+banner_link+'" marginwidth="0" marginheight="0" frameborder="0">\\n'); |
caller.document.close() |
caller.document.writeln('<frame name="bodyframe" src="$details_link" marginwidth="0" marginheight="0" frameborder="0">\\n$end_page'); |
caller.focus() |
caller.document.close(); |
|
caller.focus(); |
} |
} |
// ]]> |
|
// END LON-CAPA Internal --> |
// END LON-CAPA Internal --> |
|
// ]]> |
</script> |
</script> |
ENDTEMPLATE |
ENDTEMPLATE |
return $template; |
return $template; |
Line 914 sub help_open_bug {
|
Line 1480 sub help_open_bug {
|
unless ($env{'user.adv'}) { return ''; } |
unless ($env{'user.adv'}) { return ''; } |
unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; } |
unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; } |
$text = "" if (not defined $text); |
$text = "" if (not defined $text); |
$stayOnPage = 0 if (not defined $stayOnPage); |
|
if ($env{'browser.interface'} eq 'textual' || |
|
$env{'environment.remote'} eq 'off' ) { |
|
$stayOnPage=1; |
$stayOnPage=1; |
} |
|
$width = 600 if (not defined $width); |
$width = 600 if (not defined $width); |
$height = 600 if (not defined $height); |
$height = 600 if (not defined $height); |
|
|
Line 935 sub help_open_bug {
|
Line 1497 sub help_open_bug {
|
{ |
{ |
$link = $url; |
$link = $url; |
} |
} |
|
|
|
my $target = '_top'; |
|
if ((($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) || |
|
(($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'} eq '_self'))) { |
|
$target = '_blank'; |
|
} |
|
|
# Add the text |
# Add the text |
if ($text ne "") |
if ($text ne "") |
{ |
{ |
$template .= |
$template .= |
"<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>". |
"<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>". |
"<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; |
"<td bgcolor='#FF5555'><a target=\"$target\" href=\"$link\"><span style=\"color:#FFFFFF;font-size:10pt;\">$text</span></a>"; |
} |
} |
|
|
# Add the graphic |
# Add the graphic |
my $title = &mt('Report a Bug'); |
my $title = &mt('Report a Bug'); |
my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif"); |
my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif"); |
$template .= <<"ENDTEMPLATE"; |
$template .= <<"ENDTEMPLATE"; |
<a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a> |
<a target="$target" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a> |
ENDTEMPLATE |
ENDTEMPLATE |
if ($text ne '') { $template.='</td></tr></table>' }; |
if ($text ne '') { $template.='</td></tr></table>' }; |
return $template; |
return $template; |
Line 959 sub help_open_faq {
|
Line 1528 sub help_open_faq {
|
unless ($env{'user.adv'}) { return ''; } |
unless ($env{'user.adv'}) { return ''; } |
unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; } |
unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; } |
$text = "" if (not defined $text); |
$text = "" if (not defined $text); |
$stayOnPage = 0 if (not defined $stayOnPage); |
|
if ($env{'browser.interface'} eq 'textual' || |
|
$env{'environment.remote'} eq 'off' ) { |
|
$stayOnPage=1; |
$stayOnPage=1; |
} |
|
$width = 350 if (not defined $width); |
$width = 350 if (not defined $width); |
$height = 400 if (not defined $height); |
$height = 400 if (not defined $height); |
|
|
Line 985 sub help_open_faq {
|
Line 1550 sub help_open_faq {
|
{ |
{ |
$template .= |
$template .= |
"<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>". |
"<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>". |
"<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>"; |
"<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><span style=\"color:#FFFFFF; font-size:10pt;\">$text</span></a>"; |
} |
} |
|
|
# Add the graphic |
# Add the graphic |
Line 1004 ENDTEMPLATE
|
Line 1569 ENDTEMPLATE
|
|
|
=pod |
=pod |
|
|
=item * change_content_javascript(): |
=item * &change_content_javascript(): |
|
|
This and the next function allow you to create small sections of an |
This and the next function allow you to create small sections of an |
otherwise static HTML page that you can update on the fly with |
otherwise static HTML page that you can update on the fly with |
Line 1059 DOMBASED
|
Line 1624 DOMBASED
|
|
|
=pod |
=pod |
|
|
=item * changable_area($name, $origContent): |
=item * &changable_area($name,$origContent): |
|
|
This provides a "changable area" that can be modified on the fly via |
This provides a "changable area" that can be modified on the fly via |
the Javascript code provided in C<change_content_javascript>. $name is |
the Javascript code provided in C<change_content_javascript>. $name is |
Line 1083 sub changable_area {
|
Line 1648 sub changable_area {
|
|
|
=pod |
=pod |
|
|
|
=item * &viewport_geometry_js |
|
|
|
Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser. |
|
|
|
=cut |
|
|
|
|
|
sub viewport_geometry_js { |
|
return <<"GEOMETRY"; |
|
var Geometry = {}; |
|
function init_geometry() { |
|
if (Geometry.init) { return }; |
|
Geometry.init=1; |
|
if (window.innerHeight) { |
|
Geometry.getViewportHeight = function() { return window.innerHeight; }; |
|
Geometry.getViewportWidth = function() { return window.innerWidth; }; |
|
Geometry.getHorizontalScroll = function() { return window.pageXOffset; }; |
|
Geometry.getVerticalScroll = function() { return window.pageYOffset; }; |
|
} |
|
else if (document.documentElement && document.documentElement.clientHeight) { |
|
Geometry.getViewportHeight = |
|
function() { return document.documentElement.clientHeight; }; |
|
Geometry.getViewportWidth = |
|
function() { return document.documentElement.clientWidth; }; |
|
|
|
Geometry.getHorizontalScroll = |
|
function() { return document.documentElement.scrollLeft; }; |
|
Geometry.getVerticalScroll = |
|
function() { return document.documentElement.scrollTop; }; |
|
} |
|
else if (document.body.clientHeight) { |
|
Geometry.getViewportHeight = |
|
function() { return document.body.clientHeight; }; |
|
Geometry.getViewportWidth = |
|
function() { return document.body.clientWidth; }; |
|
Geometry.getHorizontalScroll = |
|
function() { return document.body.scrollLeft; }; |
|
Geometry.getVerticalScroll = |
|
function() { return document.body.scrollTop; }; |
|
} |
|
} |
|
|
|
GEOMETRY |
|
} |
|
|
|
=pod |
|
|
|
=item * &viewport_size_js() |
|
|
|
Provides a javascript function to set values of two form elements - width and height (elements are passed in as arguments to the javascript function) to the dimensions of the user's browser window. |
|
|
|
=cut |
|
|
|
sub viewport_size_js { |
|
my $geometry = &viewport_geometry_js(); |
|
return <<"DIMS"; |
|
|
|
$geometry |
|
|
|
function getViewportDims(width,height) { |
|
init_geometry(); |
|
width.value = Geometry.getViewportWidth(); |
|
height.value = Geometry.getViewportHeight(); |
|
return; |
|
} |
|
|
|
DIMS |
|
} |
|
|
|
=pod |
|
|
|
=item * &resize_textarea_js() |
|
|
|
emits the needed javascript to resize a textarea to be as big as possible |
|
|
|
creates a function resize_textrea that takes two IDs first should be |
|
the id of the element to resize, second should be the id of a div that |
|
surrounds everything that comes after the textarea, this routine needs |
|
to be attached to the <body> for the onload and onresize events. |
|
|
|
=cut |
|
|
|
sub resize_textarea_js { |
|
my $geometry = &viewport_geometry_js(); |
|
return <<"RESIZE"; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
$geometry |
|
|
|
function getX(element) { |
|
var x = 0; |
|
while (element) { |
|
x += element.offsetLeft; |
|
element = element.offsetParent; |
|
} |
|
return x; |
|
} |
|
function getY(element) { |
|
var y = 0; |
|
while (element) { |
|
y += element.offsetTop; |
|
element = element.offsetParent; |
|
} |
|
return y; |
|
} |
|
|
|
|
|
function resize_textarea(textarea_id,bottom_id) { |
|
init_geometry(); |
|
var textarea = document.getElementById(textarea_id); |
|
//alert(textarea); |
|
|
|
var textarea_top = getY(textarea); |
|
var textarea_height = textarea.offsetHeight; |
|
var bottom = document.getElementById(bottom_id); |
|
var bottom_top = getY(bottom); |
|
var bottom_height = bottom.offsetHeight; |
|
var window_height = Geometry.getViewportHeight(); |
|
var fudge = 23; |
|
var new_height = window_height-fudge-textarea_top-bottom_height; |
|
if (new_height < 300) { |
|
new_height = 300; |
|
} |
|
textarea.style.height=new_height+'px'; |
|
} |
|
// ]]> |
|
</script> |
|
RESIZE |
|
|
|
} |
|
|
|
sub colorfuleditor_js { |
|
return <<"COLORFULEDIT" |
|
<script type="text/javascript"> |
|
// <![CDATA[> |
|
function fold_box(curDepth, lastresource){ |
|
|
|
// we need a list because there can be several blocks you need to fold in one tag |
|
var block = document.getElementsByName('foldblock_'+curDepth); |
|
// but there is only one folding button per tag |
|
var foldbutton = document.getElementById('folding_btn_'+curDepth); |
|
|
|
if(block.item(0).style.display == 'none'){ |
|
|
|
foldbutton.value = '@{[&mt("Hide")]}'; |
|
for (i = 0; i < block.length; i++){ |
|
block.item(i).style.display = ''; |
|
} |
|
}else{ |
|
|
|
foldbutton.value = '@{[&mt("Show")]}'; |
|
for (i = 0; i < block.length; i++){ |
|
// block.item(i).style.visibility = 'collapse'; |
|
block.item(i).style.display = 'none'; |
|
} |
|
}; |
|
saveState(lastresource); |
|
} |
|
|
|
function saveState (lastresource) { |
|
|
|
var tag_list = getTagList(); |
|
if(tag_list != null){ |
|
var timestamp = new Date().getTime(); |
|
var key = lastresource; |
|
|
|
// the value pattern is: 'time;key1,value1;key2,value2; ... ' |
|
// starting with timestamp |
|
var value = timestamp+';'; |
|
|
|
// building the list of key-value pairs |
|
for(var i = 0; i < tag_list.length; i++){ |
|
value += tag_list[i]+','; |
|
value += document.getElementsByName(tag_list[i])[0].style.display+';'; |
|
} |
|
|
|
// only iterate whole storage if nothing to override |
|
if(localStorage.getItem(key) == null){ |
|
|
|
// prevent storage from growing large |
|
if(localStorage.length > 50){ |
|
var regex_getTimestamp = /^(?:\d)+;/; |
|
var oldest_timestamp = regex_getTimestamp.exec(localStorage.key(0)); |
|
var oldest_key; |
|
|
|
for(var i = 1; i < localStorage.length; i++){ |
|
if (regex_getTimestamp.exec(localStorage.key(i)) < oldest_timestamp) { |
|
oldest_key = localStorage.key(i); |
|
oldest_timestamp = regex_getTimestamp.exec(oldest_key); |
|
} |
|
} |
|
localStorage.removeItem(oldest_key); |
|
} |
|
} |
|
localStorage.setItem(key,value); |
|
} |
|
} |
|
|
|
// restore folding status of blocks (on page load) |
|
function restoreState (lastresource) { |
|
if(localStorage.getItem(lastresource) != null){ |
|
var key = lastresource; |
|
var value = localStorage.getItem(key); |
|
var regex_delTimestamp = /^\d+;/; |
|
|
|
value.replace(regex_delTimestamp, ''); |
|
|
|
var valueArr = value.split(';'); |
|
var pairs; |
|
var elements; |
|
for (var i = 0; i < valueArr.length; i++){ |
|
pairs = valueArr[i].split(','); |
|
elements = document.getElementsByName(pairs[0]); |
|
|
|
for (var j = 0; j < elements.length; j++){ |
|
elements[j].style.display = pairs[1]; |
|
if (pairs[1] == "none"){ |
|
var regex_id = /([_\\d]+)\$/; |
|
regex_id.exec(pairs[0]); |
|
document.getElementById("folding_btn"+RegExp.\$1).value = "Show"; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
function getTagList () { |
|
|
|
var stringToSearch = document.lonhomework.innerHTML; |
|
|
|
var ret = new Array(); |
|
var regex_findBlock = /(foldblock_.*?)"/g; |
|
var tag_list = stringToSearch.match(regex_findBlock); |
|
|
|
if(tag_list != null){ |
|
for(var i = 0; i < tag_list.length; i++){ |
|
ret.push(tag_list[i].replace(/"/, '')); |
|
} |
|
} |
|
return ret; |
|
} |
|
|
|
function saveScrollPosition (resource) { |
|
var tag_list = getTagList(); |
|
|
|
// we dont always want to jump to the first block |
|
// 170 is roughly above the "Problem Editing" header. we just want to save if the user scrolled down further than this |
|
if(\$(window).scrollTop() > 170){ |
|
if(tag_list != null){ |
|
var result; |
|
for(var i = 0; i < tag_list.length; i++){ |
|
if(isElementInViewport(tag_list[i])){ |
|
result += tag_list[i]+';'; |
|
} |
|
} |
|
sessionStorage.setItem('anchor_'+resource, result); |
|
} |
|
} else { |
|
// we dont need to save zero, just delete the item to leave everything tidy |
|
sessionStorage.removeItem('anchor_'+resource); |
|
} |
|
} |
|
|
|
function restoreScrollPosition(resource){ |
|
|
|
var elem = sessionStorage.getItem('anchor_'+resource); |
|
if(elem != null){ |
|
var tag_list = elem.split(';'); |
|
var elem_list; |
|
|
|
for(var i = 0; i < tag_list.length; i++){ |
|
elem_list = document.getElementsByName(tag_list[i]); |
|
|
|
if(elem_list.length > 0){ |
|
elem = elem_list[0]; |
|
break; |
|
} |
|
} |
|
elem.scrollIntoView(); |
|
} |
|
} |
|
|
|
function isElementInViewport(el) { |
|
|
|
// change to last element instead of first |
|
var elem = document.getElementsByName(el); |
|
var rect = elem[0].getBoundingClientRect(); |
|
|
|
return ( |
|
rect.top >= 0 && |
|
rect.left >= 0 && |
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ |
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ |
|
); |
|
} |
|
|
|
function autosize(depth){ |
|
var cmInst = window['cm'+depth]; |
|
var fitsizeButton = document.getElementById('fitsize'+depth); |
|
|
|
// is fixed size, switching to dynamic |
|
if (sessionStorage.getItem("autosized_"+depth) == null) { |
|
cmInst.setSize("","auto"); |
|
fitsizeButton.value = "@{[&mt('Fixed size')]}"; |
|
sessionStorage.setItem("autosized_"+depth, "yes"); |
|
|
|
// is dynamic size, switching to fixed |
|
} else { |
|
cmInst.setSize("","300px"); |
|
fitsizeButton.value = "@{[&mt('Dynamic size')]}"; |
|
sessionStorage.removeItem("autosized_"+depth); |
|
} |
|
} |
|
|
|
|
|
|
|
// ]]> |
|
</script> |
|
COLORFULEDIT |
|
} |
|
|
|
sub xmleditor_js { |
|
return <<XMLEDIT |
|
<script type="text/javascript" src="/adm/jQuery/addons/jquery-scrolltofixed.js"></script> |
|
<script type="text/javascript"> |
|
// <![CDATA[> |
|
|
|
function saveScrollPosition (resource) { |
|
|
|
var scrollPos = \$(window).scrollTop(); |
|
sessionStorage.setItem(resource,scrollPos); |
|
} |
|
|
|
function restoreScrollPosition(resource){ |
|
|
|
var scrollPos = sessionStorage.getItem(resource); |
|
\$(window).scrollTop(scrollPos); |
|
} |
|
|
|
// unless internet explorer |
|
if (!(window.navigator.appName == "Microsoft Internet Explorer" && (document.documentMode || document.compatMode))){ |
|
|
|
\$(document).ready(function() { |
|
\$(".LC_edit_actionbar").scrollToFixed(\{zIndex: 100\}); |
|
}); |
|
} |
|
|
|
// inserts text at cursor position into codemirror (xml editor only) |
|
function insertText(text){ |
|
cm.focus(); |
|
var curPos = cm.getCursor(); |
|
cm.replaceRange(text.replace(/ESCAPEDSCRIPT/g,'script'), {line: curPos.line,ch: curPos.ch}); |
|
} |
|
// ]]> |
|
</script> |
|
XMLEDIT |
|
} |
|
|
|
sub insert_folding_button { |
|
my $curDepth = $Apache::lonxml::curdepth; |
|
my $lastresource = $env{'request.ambiguous'}; |
|
|
|
return "<input type=\"button\" id=\"folding_btn_$curDepth\" |
|
value=\"".&mt('Hide')."\" onclick=\"fold_box('$curDepth','$lastresource')\">"; |
|
} |
|
|
|
=pod |
|
|
|
=item * &iframe_wrapper_headjs() |
|
|
|
emits javascript containing two global vars to facilitate handling of resizing |
|
by code in iframe_wrapper_resizejs() used when an iframe is present in a page |
|
with standard LON-CAPA menus. |
|
|
|
=cut |
|
|
|
# |
|
# Where iframe is in use, if window.onload() executes before the custom resize function |
|
# has been defined (jQuery), two global javascript vars (LCnotready and LCresizedef) |
|
# are used to ensure document.ready() triggers a call to resize, so the iframe contents |
|
# do not obscure the Functions menu. |
|
# |
|
|
|
sub iframe_wrapper_headjs { |
|
return <<"ENDJS"; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
var LCnotready = 0; |
|
var LCresizedef = 0; |
|
// ]]> |
|
</script> |
|
|
|
ENDJS |
|
|
|
} |
|
|
|
=pod |
|
|
|
=item * &iframe_wrapper_resizejs() |
|
|
|
emits javascript used to handle resizing for a page containing |
|
an iframe, to ensure that the iframe does not obscure any |
|
standard LON-CAPA menu items. |
|
|
=back |
=back |
|
|
=head1 Excel and CSV file utility routines |
|
|
|
=over 4 |
=cut |
|
|
|
# |
|
# jQuery to use when iframe is in use and a page resize occurs. |
|
# This script will ensure that the iframe does not obscure any |
|
# standard LON-CAPA inline menus (primary, secondary, and/or |
|
# breadcrumbs and Functions menus. Expects javascript from |
|
# &iframe_wrapper_headjs() to be in head portion of the web page, |
|
# e.g., by inclusion in second arg passed to &start_page(). |
|
# |
|
|
|
sub iframe_wrapper_resizejs { |
|
my $offset = 5; |
|
&get_unprocessed_cgi($ENV{'QUERY_STRING'},['inhibitmenu']); |
|
if (($env{'form.inhibitmenu'} eq 'yes') || ($env{'form.only_body'})) { |
|
$offset = 0; |
|
} |
|
return &Apache::lonhtmlcommon::scripttag(<<SCRIPT); |
|
\$(document).ready( function() { |
|
\$(window).unbind('resize').resize(function(){ |
|
var header = null; |
|
var offset = $offset; |
|
var height = 0; |
|
var hdrtop = 0; |
|
if (\$('div.LC_menus_content:first').length) { |
|
if (\$('div.LC_menus_content:first').hasClass ("shown")) { |
|
header = \$('div.LC_menus_content:first'); |
|
offset = 12; |
|
} |
|
} else if (\$('div.LC_head_subbox:first').length) { |
|
header = \$('div.LC_head_subbox:first'); |
|
offset = 9; |
|
} else { |
|
if (\$('#LC_breadcrumbs').length) { |
|
header = \$('#LC_breadcrumbs'); |
|
} |
|
} |
|
if (header != null && header.length) { |
|
height = header.height(); |
|
hdrtop = header.position().top; |
|
} |
|
var pos = height + hdrtop + offset; |
|
\$('.LC_iframecontainer').css('top', pos); |
|
}); |
|
LCresizedef = 1; |
|
if (LCnotready == 1) { |
|
LCnotready = 0; |
|
\$(window).trigger('resize'); |
|
} |
|
}); |
|
window.onload = function(){ |
|
if (LCresizedef) { |
|
LCnotready = 0; |
|
\$(window).trigger('resize'); |
|
} else { |
|
LCnotready = 1; |
|
} |
|
}; |
|
SCRIPT |
|
|
|
} |
|
|
|
=pod |
|
|
|
=head1 Excel and CSV file utility routines |
|
|
=cut |
=cut |
|
|
Line 1096 sub changable_area {
|
Line 2127 sub changable_area {
|
|
|
=pod |
=pod |
|
|
=item * csv_translate($text) |
=over 4 |
|
|
|
=item * &csv_translate($text) |
|
|
Translate $text to allow it to be output as a 'comma separated values' |
Translate $text to allow it to be output as a 'comma separated values' |
format. |
format. |
Line 1117 sub csv_translate {
|
Line 2150 sub csv_translate {
|
|
|
=pod |
=pod |
|
|
=item * define_excel_formats |
=item * &define_excel_formats() |
|
|
Define some commonly used Excel cell formats. |
Define some commonly used Excel cell formats. |
|
|
Line 1147 Inputs: $workbook
|
Line 2180 Inputs: $workbook
|
|
|
Returns: $format, a hash reference. |
Returns: $format, a hash reference. |
|
|
|
|
=cut |
=cut |
|
|
############################################################### |
############################################################### |
Line 1173 sub define_excel_formats {
|
Line 2207 sub define_excel_formats {
|
|
|
=pod |
=pod |
|
|
=item * create_workbook |
=item * &create_workbook() |
|
|
Create an Excel worksheet. If it fails, output message on the |
Create an Excel worksheet. If it fails, output message on the |
request object and return undefs. |
request object and return undefs. |
Line 1198 sub create_workbook {
|
Line 2232 sub create_workbook {
|
my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); |
my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); |
if (! defined($workbook)) { |
if (! defined($workbook)) { |
$r->log_error("Error creating excel spreadsheet $filename: $!"); |
$r->log_error("Error creating excel spreadsheet $filename: $!"); |
$r->print('<p>'.&mt("Unable to create new Excel file. ". |
$r->print( |
"This error has been logged. ". |
'<p class="LC_error">' |
"Please alert your LON-CAPA administrator"). |
.&mt('Problems occurred in creating the new Excel file.') |
'</p>'); |
.' '.&mt('This error has been logged.') |
|
.' '.&mt('Please alert your LON-CAPA administrator.') |
|
.'</p>' |
|
); |
return (undef); |
return (undef); |
} |
} |
# |
# |
$workbook->set_tempdir('/home/httpd/perl/tmp'); |
$workbook->set_tempdir(LONCAPA::tempdir()); |
# |
# |
my $format = &Apache::loncommon::define_excel_formats($workbook); |
my $format = &Apache::loncommon::define_excel_formats($workbook); |
return ($workbook,$filename,$format); |
return ($workbook,$filename,$format); |
Line 1216 sub create_workbook {
|
Line 2253 sub create_workbook {
|
|
|
=pod |
=pod |
|
|
=item * create_text_file |
=item * &create_text_file() |
|
|
Create a file to write to and eventually make available to the user. |
Create a file to write to and eventually make available to the user. |
If file creation fails, outputs an error message on the request object and |
If file creation fails, outputs an error message on the request object and |
Line 1241 sub create_text_file {
|
Line 2278 sub create_text_file {
|
$fh = Apache::File->new('>/home/httpd'.$filename); |
$fh = Apache::File->new('>/home/httpd'.$filename); |
if (! defined($fh)) { |
if (! defined($fh)) { |
$r->log_error("Couldn't open $filename for output $!"); |
$r->log_error("Couldn't open $filename for output $!"); |
$r->print("Problems occured in creating the output file. ". |
$r->print( |
"This error has been logged. ". |
'<p class="LC_error">' |
"Please alert your LON-CAPA administrator."); |
.&mt('Problems occurred in creating the output file.') |
|
.' '.&mt('This error has been logged.') |
|
.' '.&mt('Please alert your LON-CAPA administrator.') |
|
.'</p>' |
|
); |
} |
} |
return ($fh,$filename) |
return ($fh,$filename) |
} |
} |
Line 1272 sub domain_select {
|
Line 2313 sub domain_select {
|
return &multiple_select_form($name,$value,4,\%domains); |
return &multiple_select_form($name,$value,4,\%domains); |
} else { |
} else { |
$domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))]; |
$domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))]; |
return &select_form($name,$value,%domains); |
return &select_form($name,$value,\%domains); |
} |
} |
} |
} |
|
|
Line 1284 sub domain_select {
|
Line 2325 sub domain_select {
|
|
|
=over 4 |
=over 4 |
|
|
=cut |
=item * &multiple_select_form($name,$value,$size,$hash,$order) |
|
|
=item * multiple_select_form($name,$value,$size,$hash,$order) |
|
|
|
Returns a string containing a <select> element int multiple mode |
Returns a string containing a <select> element int multiple mode |
|
|
Line 1312 sub multiple_select_form {
|
Line 2351 sub multiple_select_form {
|
$size = scalar(keys(%$hash)); |
$size = scalar(keys(%$hash)); |
} |
} |
} |
} |
$output.="\n<select name='$name' size='$size' multiple='1'>"; |
$output.="\n".'<select name="'.$name.'" size="'.$size.'" multiple="multiple">'; |
my @order; |
my @order; |
if (ref($order) eq 'ARRAY') { |
if (ref($order) eq 'ARRAY') { |
@order = @{$order}; |
@order = @{$order}; |
Line 1336 sub multiple_select_form {
|
Line 2375 sub multiple_select_form {
|
|
|
=pod |
=pod |
|
|
=item * select_form($defdom,$name,%hash) |
=item * &select_form($defdom,$name,$hashref,$onchange,$readonly) |
|
|
Returns a string containing a <select name='$name' size='1'> form to |
Returns a string containing a <select name='$name' size='1'> form to |
allow a user to select options from a hash option_name => displayed text. |
allow a user to select options from a ref to a hash containing: |
|
option_name => displayed text. An optional $onchange can include |
|
a javascript onchange item, e.g., onchange="this.form.submit();". |
|
An optional arg -- $readonly -- if true will cause the select form |
|
to be disabled, e.g., for the case where an instructor has a section- |
|
specific role, and is viewing/modifying parameters. |
|
|
See lonrights.pm for an example invocation and use. |
See lonrights.pm for an example invocation and use. |
|
|
=cut |
=cut |
|
|
#------------------------------------------- |
#------------------------------------------- |
sub select_form { |
sub select_form { |
my ($def,$name,%hash) = @_; |
my ($def,$name,$hashref,$onchange,$readonly) = @_; |
my $selectform = "<select name=\"$name\" size=\"1\">\n"; |
return unless (ref($hashref) eq 'HASH'); |
|
if ($onchange) { |
|
$onchange = ' onchange="'.$onchange.'"'; |
|
} |
|
my $disabled; |
|
if ($readonly) { |
|
$disabled = ' disabled="disabled"'; |
|
} |
|
my $selectform = "<select name=\"$name\" size=\"1\"$onchange$disabled>\n"; |
my @keys; |
my @keys; |
if (exists($hash{'select_form_order'})) { |
if (exists($hashref->{'select_form_order'})) { |
@keys=@{$hash{'select_form_order'}}; |
@keys=@{$hashref->{'select_form_order'}}; |
} else { |
} else { |
@keys=sort(keys(%hash)); |
@keys=sort(keys(%{$hashref})); |
} |
} |
foreach my $key (@keys) { |
foreach my $key (@keys) { |
$selectform.= |
$selectform.= |
'<option value="'.&HTML::Entities::encode($key,'"<>&').'" '. |
'<option value="'.&HTML::Entities::encode($key,'"<>&').'" '. |
($key eq $def ? 'selected="selected" ' : ''). |
($key eq $def ? 'selected="selected" ' : ''). |
">".&mt($hash{$key})."</option>\n"; |
">".$hashref->{$key}."</option>\n"; |
} |
} |
$selectform.="</select>"; |
$selectform.="</select>"; |
return $selectform; |
return $selectform; |
Line 1367 sub select_form {
|
Line 2420 sub select_form {
|
# For display filters |
# For display filters |
|
|
sub display_filter { |
sub display_filter { |
|
my ($context) = @_; |
if (!$env{'form.show'}) { $env{'form.show'}=10; } |
if (!$env{'form.show'}) { $env{'form.show'}=10; } |
if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; } |
if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; } |
return '<nobr><label>'.&mt('Records [_1]', |
my $phraseinput = 'hidden'; |
|
my $includeinput = 'hidden'; |
|
my ($checked,$includetypestext); |
|
if ($env{'form.displayfilter'} eq 'containing') { |
|
$phraseinput = 'text'; |
|
if ($context eq 'parmslog') { |
|
$includeinput = 'checkbox'; |
|
if ($env{'form.includetypes'}) { |
|
$checked = ' checked="checked"'; |
|
} |
|
$includetypestext = &mt('Include parameter types'); |
|
} |
|
} else { |
|
$includetypestext = ' '; |
|
} |
|
my ($additional,$secondid,$thirdid); |
|
if ($context eq 'parmslog') { |
|
$additional = |
|
'<label><input type="'.$includeinput.'" name="includetypes"'. |
|
$checked.' name="includetypes" value="1" id="includetypes" />'. |
|
' <span id="includetypestext">'.$includetypestext.'</span>'. |
|
'</label>'; |
|
$secondid = 'includetypes'; |
|
$thirdid = 'includetypestext'; |
|
} |
|
my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context', |
|
'$secondid','$thirdid')"; |
|
return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]', |
&Apache::lonmeta::selectbox('show',$env{'form.show'},undef, |
&Apache::lonmeta::selectbox('show',$env{'form.show'},undef, |
(&mt('all'),10,20,50,100,1000,10000))). |
(&mt('all'),10,20,50,100,1000,10000))). |
'</label></nobr> <nobr>'. |
'</label></span> <span class="LC_nobreak">'. |
&mt('Filter [_1]', |
&mt('Filter: [_1]', |
&select_form($env{'form.displayfilter'}, |
&select_form($env{'form.displayfilter'}, |
'displayfilter', |
'displayfilter', |
('currentfolder' => 'Current folder/page', |
{'currentfolder' => 'Current folder/page', |
'containing' => 'Containing phrase', |
'containing' => 'Containing phrase', |
'none' => 'None'))). |
'none' => 'None'},$onchange)).' '. |
'<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></nobr>'; |
'<input type="'.$phraseinput.'" name="containingphrase" id="containingphrase" size="30" value="'. |
|
&HTML::Entities::encode($env{'form.containingphrase'}). |
|
'" />'.$additional; |
|
} |
|
|
|
sub display_filter_js { |
|
my $includetext = &mt('Include parameter types'); |
|
return <<"ENDJS"; |
|
|
|
function toggleHistoryOptions(setter,firstid,context,secondid,thirdid) { |
|
var firstType = 'hidden'; |
|
if (setter.options[setter.selectedIndex].value == 'containing') { |
|
firstType = 'text'; |
|
} |
|
firstObject = document.getElementById(firstid); |
|
if (typeof(firstObject) == 'object') { |
|
if (firstObject.type != firstType) { |
|
changeInputType(firstObject,firstType); |
|
} |
|
} |
|
if (context == 'parmslog') { |
|
var secondType = 'hidden'; |
|
if (firstType == 'text') { |
|
secondType = 'checkbox'; |
|
} |
|
secondObject = document.getElementById(secondid); |
|
if (typeof(secondObject) == 'object') { |
|
if (secondObject.type != secondType) { |
|
changeInputType(secondObject,secondType); |
|
} |
|
} |
|
var textItem = document.getElementById(thirdid); |
|
var currtext = textItem.innerHTML; |
|
var newtext; |
|
if (firstType == 'text') { |
|
newtext = '$includetext'; |
|
} else { |
|
newtext = ' '; |
|
} |
|
if (currtext != newtext) { |
|
textItem.innerHTML = newtext; |
|
} |
|
} |
|
return; |
|
} |
|
|
|
function changeInputType(oldObject,newType) { |
|
var newObject = document.createElement('input'); |
|
newObject.type = newType; |
|
if (oldObject.size) { |
|
newObject.size = oldObject.size; |
|
} |
|
if (oldObject.value) { |
|
newObject.value = oldObject.value; |
|
} |
|
if (oldObject.name) { |
|
newObject.name = oldObject.name; |
|
} |
|
if (oldObject.id) { |
|
newObject.id = oldObject.id; |
|
} |
|
oldObject.parentNode.replaceChild(newObject,oldObject); |
|
return; |
|
} |
|
|
|
ENDJS |
} |
} |
|
|
sub gradeleveldescription { |
sub gradeleveldescription { |
Line 1423 sub select_level_form {
|
Line 2569 sub select_level_form {
|
|
|
=pod |
=pod |
|
|
=item * select_dom_form($defdom,$name,$includeempty) |
=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) |
|
|
Returns a string containing a <select name='$name' size='1'> form to |
Returns a string containing a <select name='$name' size='1'> form to |
allow a user to select the domain to preform an operation in. |
allow a user to select the domain to preform an operation in. |
Line 1432 See loncreateuser.pm for an example invo
|
Line 2578 See loncreateuser.pm for an example invo
|
If the $includeempty flag is set, it also includes an empty choice ("no domain |
If the $includeempty flag is set, it also includes an empty choice ("no domain |
selected"); |
selected"); |
|
|
|
If the $showdomdesc flag is set, the domain name is followed by the domain description. |
|
|
|
The optional $onchange argument specifies what should occur if the domain selector is changed, e.g., 'this.form.submit()' if the form is to be automatically submitted. |
|
|
|
The optional $incdoms is a reference to an array of domains which will be the only available options. |
|
|
|
The optional $excdoms is a reference to an array of domains which will be excluded from the available options. |
|
|
|
The optional $disabled argument, if true, adds the disabled attribute to the select tag. |
|
|
=cut |
=cut |
|
|
#------------------------------------------- |
#------------------------------------------- |
sub select_dom_form { |
sub select_dom_form { |
my ($defdom,$name,$includeempty) = @_; |
my ($defdom,$name,$includeempty,$showdomdesc,$onchange,$incdoms,$excdoms,$disabled) = @_; |
my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains()); |
if ($onchange) { |
|
$onchange = ' onchange="'.$onchange.'"'; |
|
} |
|
if ($disabled) { |
|
$disabled = ' disabled="disabled"'; |
|
} |
|
my (@domains,%exclude); |
|
if (ref($incdoms) eq 'ARRAY') { |
|
@domains = sort {lc($a) cmp lc($b)} (@{$incdoms}); |
|
} else { |
|
@domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains()); |
|
} |
if ($includeempty) { @domains=('',@domains); } |
if ($includeempty) { @domains=('',@domains); } |
my $selectdomain = "<select name=\"$name\" size=\"1\">\n"; |
if (ref($excdoms) eq 'ARRAY') { |
|
map { $exclude{$_} = 1; } @{$excdoms}; |
|
} |
|
my $selectdomain = "<select name=\"$name\" size=\"1\"$onchange$disabled>\n"; |
foreach my $dom (@domains) { |
foreach my $dom (@domains) { |
|
next if ($exclude{$dom}); |
$selectdomain.="<option value=\"$dom\" ". |
$selectdomain.="<option value=\"$dom\" ". |
($dom eq $defdom ? 'selected="selected" ' : ''). |
($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom; |
">$dom</option>\n"; |
if ($showdomdesc) { |
|
if ($dom ne '') { |
|
my $domdesc = &Apache::lonnet::domain($dom,'description'); |
|
if ($domdesc ne '') { |
|
$selectdomain .= ' ('.$domdesc.')'; |
|
} |
|
} |
|
} |
|
$selectdomain .= "</option>\n"; |
} |
} |
$selectdomain.="</select>"; |
$selectdomain.="</select>"; |
return $selectdomain; |
return $selectdomain; |
Line 1453 sub select_dom_form {
|
Line 2632 sub select_dom_form {
|
|
|
=pod |
=pod |
|
|
=item * home_server_option_list($domain) |
=item * &home_server_form_item($domain,$name,$defaultflag) |
|
|
|
input: 4 arguments (two required, two optional) - |
|
$domain - domain of new user |
|
$name - name of form element |
|
$default - Value of 'default' causes a default item to be first |
|
option, and selected by default. |
|
$hide - Value of 'hide' causes hiding of the name of the server, |
|
if 1 server found, or default, if 0 found. |
|
output: returns 2 items: |
|
(a) form element which contains either: |
|
(i) <select name="$name"> |
|
<option value="$hostid1">$hostid $servers{$hostid}</option> |
|
<option value="$hostid2">$hostid $servers{$hostid}</option> |
|
</select> |
|
form item if there are multiple library servers in $domain, or |
|
(ii) an <input type="hidden" name="$name" value="$hostid" /> form item |
|
if there is only one library server in $domain. |
|
|
returns a string which contains an <option> list to be used in a |
(b) number of library servers found. |
<select> form input. See loncreateuser.pm for an example. |
|
|
See loncreateuser.pm for example of use. |
|
|
=cut |
=cut |
|
|
#------------------------------------------- |
#------------------------------------------- |
sub home_server_option_list { |
sub home_server_form_item { |
my $domain = shift; |
my ($domain,$name,$default,$hide) = @_; |
my %servers = &Apache::lonnet::get_servers($domain,'library'); |
my %servers = &Apache::lonnet::get_servers($domain,'library'); |
my $result = ''; |
my $result; |
foreach my $hostid (sort(keys(%servers))) { |
my $numlib = keys(%servers); |
$result.= |
if ($numlib > 1) { |
'<option value="'.$hostid.'">'. |
$result .= '<select name="'.$name.'" />'."\n"; |
$hostid.' '.$servers{$hostid}."</option>\n"; |
if ($default) { |
|
$result .= '<option value="default" selected="selected">'.&mt('default'). |
|
'</option>'."\n"; |
|
} |
|
foreach my $hostid (sort(keys(%servers))) { |
|
$result.= '<option value="'.$hostid.'">'. |
|
$hostid.' '.$servers{$hostid}."</option>\n"; |
|
} |
|
$result .= '</select>'."\n"; |
|
} elsif ($numlib == 1) { |
|
my $hostid; |
|
foreach my $item (keys(%servers)) { |
|
$hostid = $item; |
|
} |
|
$result .= '<input type="hidden" name="'.$name.'" value="'. |
|
$hostid.'" />'; |
|
if (!$hide) { |
|
$result .= $hostid.' '.$servers{$hostid}; |
|
} |
|
$result .= "\n"; |
|
} elsif ($default) { |
|
$result .= '<input type="hidden" name="'.$name. |
|
'" value="default" />'; |
|
if (!$hide) { |
|
$result .= &mt('default'); |
|
} |
|
$result .= "\n"; |
} |
} |
return $result; |
return ($result,$numlib); |
} |
} |
|
|
=pod |
=pod |
Line 1509 Outputs:
|
Line 2732 Outputs:
|
|
|
=item * $clientos |
=item * $clientos |
|
|
|
=item * $clientmobile |
|
|
|
=item * $clientinfo |
|
|
|
=item * $clientosversion |
|
|
=back |
=back |
|
|
=back |
=back |
Line 1527 sub decode_user_agent {
|
Line 2756 sub decode_user_agent {
|
my $clientversion='0'; |
my $clientversion='0'; |
my $clientmathml=''; |
my $clientmathml=''; |
my $clientunicode='0'; |
my $clientunicode='0'; |
|
my $clientmobile=0; |
|
my $clientosversion=''; |
for (my $i=0;$i<=$#browsertype;$i++) { |
for (my $i=0;$i<=$#browsertype;$i++) { |
my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]); |
my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\%/,$browsertype[$i]); |
if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) { |
if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) { |
$clientbrowser=$bname; |
$clientbrowser=$bname; |
$httpbrowser=~/$vreg/i; |
$httpbrowser=~/$vreg/i; |
Line 1538 sub decode_user_agent {
|
Line 2769 sub decode_user_agent {
|
} |
} |
} |
} |
my $clientos='unknown'; |
my $clientos='unknown'; |
|
my $clientinfo; |
if (($httpbrowser=~/linux/i) || |
if (($httpbrowser=~/linux/i) || |
($httpbrowser=~/unix/i) || |
($httpbrowser=~/unix/i) || |
($httpbrowser=~/ux/i) || |
($httpbrowser=~/ux/i) || |
Line 1547 sub decode_user_agent {
|
Line 2779 sub decode_user_agent {
|
if ($httpbrowser=~/next/i) { $clientos='next'; } |
if ($httpbrowser=~/next/i) { $clientos='next'; } |
if (($httpbrowser=~/mac/i) || |
if (($httpbrowser=~/mac/i) || |
($httpbrowser=~/powerpc/i)) { $clientos='mac'; } |
($httpbrowser=~/powerpc/i)) { $clientos='mac'; } |
if ($httpbrowser=~/win/i) { $clientos='win'; } |
if ($httpbrowser=~/win/i) { |
|
$clientos='win'; |
|
if ($httpbrowser =~/Windows\s+NT\s+(\d+\.\d+)/i) { |
|
$clientosversion = $1; |
|
} |
|
} |
if ($httpbrowser=~/embed/i) { $clientos='pda'; } |
if ($httpbrowser=~/embed/i) { $clientos='pda'; } |
|
if ($httpbrowser=~/(Android|iPod|iPad|iPhone|webOS|Blackberry|Windows Phone|Opera m(?:ob|in)|Fennec)/i) { |
|
$clientmobile=lc($1); |
|
} |
|
if ($httpbrowser=~ m{Firefox/(\d+\.\d+)}) { |
|
$clientinfo = 'firefox-'.$1; |
|
} elsif ($httpbrowser=~ m{chromeframe/(\d+\.\d+)\.}) { |
|
$clientinfo = 'chromeframe-'.$1; |
|
} |
return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, |
return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, |
$clientunicode,$clientos,); |
$clientunicode,$clientos,$clientmobile,$clientinfo, |
|
$clientosversion); |
} |
} |
|
|
############################################################### |
############################################################### |
Line 1569 sub decode_user_agent {
|
Line 2815 sub decode_user_agent {
|
|
|
=over 4 |
=over 4 |
|
|
=item * authform_xxxxxx |
=item * &authform_xxxxxx() |
|
|
The authform_xxxxxx subroutines provide javascript and html forms which |
The authform_xxxxxx subroutines provide javascript and html forms which |
handle some of the conveniences required for authentication forms. |
handle some of the conveniences required for authentication forms. |
This is not an optimal method, but it works. |
This is not an optimal method, but it works. |
|
|
See loncreateuser.pm for invocation and use examples. |
|
|
|
=over 4 |
=over 4 |
|
|
=item * authform_header |
=item * authform_header |
Line 1591 See loncreateuser.pm for invocation and
|
Line 2835 See loncreateuser.pm for invocation and
|
|
|
=item * authform_filesystem |
=item * authform_filesystem |
|
|
|
=item * authform_lti |
|
|
=back |
=back |
|
|
=back |
See loncreateuser.pm for invocation and use examples. |
|
|
=cut |
=cut |
|
|
Line 1623 END
|
Line 2869 END
|
} |
} |
|
|
my $radioval = "'nochange'"; |
my $radioval = "'nochange'"; |
if (exists($in{'curr_authtype'}) && |
if (defined($in{'curr_authtype'})) { |
defined($in{'curr_authtype'}) && |
if ($in{'curr_authtype'} ne '') { |
$in{'curr_authtype'} ne '') { |
$radioval = "'".$in{'curr_authtype'}."arg'"; |
$radioval = "'$in{'curr_authtype'}arg'"; |
} |
} |
} |
my $argfield = 'null'; |
my $argfield = 'null'; |
if ( grep/^mode$/,(keys %in) ) { |
if (defined($in{'mode'})) { |
if ($in{'mode'} eq 'modifycourse') { |
if ($in{'mode'} eq 'modifycourse') { |
if ( grep/^curr_authtype$/,(keys %in) ) { |
if (defined($in{'curr_autharg'})) { |
$radioval = "'$in{'curr_authtype'}'"; |
if ($in{'curr_autharg'} ne '') { |
} |
|
if ( grep/^curr_autharg$/,(keys %in) ) { |
|
unless ($in{'curr_autharg'} eq '') { |
|
$argfield = "'$in{'curr_autharg'}'"; |
$argfield = "'$in{'curr_autharg'}'"; |
} |
} |
} |
} |
Line 1687 function changed_text(choice,currentform
|
Line 2930 function changed_text(choice,currentform
|
} |
} |
|
|
function set_auth_radio_buttons(newvalue,currentform) { |
function set_auth_radio_buttons(newvalue,currentform) { |
|
var numauthchoices = currentform.login.length; |
|
if (typeof numauthchoices == "undefined") { |
|
return; |
|
} |
var i=0; |
var i=0; |
while (i < currentform.login.length) { |
while (i < numauthchoices) { |
if (currentform.login[i].value == newvalue) { break; } |
if (currentform.login[i].value == newvalue) { break; } |
i++; |
i++; |
} |
} |
if (i == currentform.login.length) { |
if (i == numauthchoices) { |
return; |
return; |
} |
} |
current.radiovalue = newvalue; |
current.radiovalue = newvalue; |
Line 1703 END
|
Line 2950 END
|
return $result; |
return $result; |
} |
} |
|
|
sub authform_authorwarning{ |
sub authform_authorwarning { |
my $result=''; |
my $result=''; |
$result='<i>'. |
$result='<i>'. |
&mt('As a general rule, only authors or co-authors should be '. |
&mt('As a general rule, only authors or co-authors should be '. |
Line 1712 sub authform_authorwarning{
|
Line 2959 sub authform_authorwarning{
|
return $result; |
return $result; |
} |
} |
|
|
sub authform_nochange{ |
sub authform_nochange { |
my %in = ( |
my %in = ( |
formname => 'document.cu', |
formname => 'document.cu', |
kerb_def_dom => 'MSU.EDU', |
kerb_def_dom => 'MSU.EDU', |
@_, |
@_, |
); |
); |
my $result = '<label>'.&mt('[_1] Do not change login data', |
my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); |
'<input type="radio" name="login" value="nochange" '. |
my $result; |
'checked="checked" onclick="'. |
if (!$authnum) { |
|
$result = &mt('Under your current role you are not permitted to change login settings for this user'); |
|
} else { |
|
$result = '<label>'.&mt('[_1] Do not change login data', |
|
'<input type="radio" name="login" value="nochange" '. |
|
'checked="checked" onclick="'. |
"javascript:changed_radio('nochange',$in{'formname'});".'" />'). |
"javascript:changed_radio('nochange',$in{'formname'});".'" />'). |
'</label>'; |
'</label>'; |
|
} |
return $result; |
return $result; |
} |
} |
|
|
sub authform_kerberos{ |
sub authform_kerberos { |
my %in = ( |
my %in = ( |
formname => 'document.cu', |
formname => 'document.cu', |
kerb_def_dom => 'MSU.EDU', |
kerb_def_dom => 'MSU.EDU', |
kerb_def_auth => 'krb4', |
kerb_def_auth => 'krb4', |
@_, |
@_, |
); |
); |
my ($check4,$check5,$krbarg); |
my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype, |
|
$autharg,$jscall,$disabled); |
|
my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); |
if ($in{'kerb_def_auth'} eq 'krb5') { |
if ($in{'kerb_def_auth'} eq 'krb5') { |
$check5 = " checked=\"on\""; |
$check5 = ' checked="checked"'; |
} else { |
} else { |
$check4 = " checked=\"on\""; |
$check4 = ' checked="checked"'; |
|
} |
|
if ($in{'readonly'}) { |
|
$disabled = ' disabled="disabled"'; |
} |
} |
$krbarg = $in{'kerb_def_dom'}; |
$krbarg = $in{'kerb_def_dom'}; |
|
if (defined($in{'curr_authtype'})) { |
my $krbcheck = ""; |
if ($in{'curr_authtype'} eq 'krb') { |
if ( grep/^curr_authtype$/,(keys %in) ) { |
$krbcheck = ' checked="checked"'; |
if ($in{'curr_authtype'} =~ m/^krb/) { |
if (defined($in{'mode'})) { |
$krbcheck = " checked=\"on\""; |
if ($in{'mode'} eq 'modifyuser') { |
if ( grep/^curr_autharg$/,(keys %in) ) { |
$krbcheck = ''; |
|
} |
|
} |
|
if (defined($in{'curr_kerb_ver'})) { |
|
if ($in{'curr_krb_ver'} eq '5') { |
|
$check5 = ' checked="checked"'; |
|
$check4 = ''; |
|
} else { |
|
$check4 = ' checked="checked"'; |
|
$check5 = ''; |
|
} |
|
} |
|
if (defined($in{'curr_autharg'})) { |
$krbarg = $in{'curr_autharg'}; |
$krbarg = $in{'curr_autharg'}; |
} |
} |
|
if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) { |
|
if (defined($in{'curr_autharg'})) { |
|
$result = |
|
&mt('Currently Kerberos authenticated with domain [_1] Version [_2].', |
|
$in{'curr_autharg'},$krbver); |
|
} else { |
|
$result = |
|
&mt('Currently Kerberos authenticated, Version [_1].',$krbver); |
|
} |
|
return $result; |
|
} |
|
} |
|
} else { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="hidden" name="login" value="krb" />'; |
} |
} |
} |
} |
|
if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) { |
my $jscall = "javascript:changed_radio('krb',$in{'formname'});"; |
return; |
my $result .= &mt |
} elsif ($authtype eq '') { |
|
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifycourse') { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="radio" name="login" value="krb"'.$disabled.' />'; |
|
} |
|
} |
|
} |
|
} |
|
$jscall = "javascript:changed_radio('krb',$in{'formname'});"; |
|
if ($authtype eq '') { |
|
$authtype = '<input type="radio" name="login" value="krb" '. |
|
'onclick="'.$jscall.'" onchange="'.$jscall.'"'. |
|
$krbcheck.$disabled.' />'; |
|
} |
|
if (($can_assign{'krb4'} && $can_assign{'krb5'}) || |
|
($can_assign{'krb4'} && !$can_assign{'krb5'} && |
|
$in{'curr_authtype'} eq 'krb5') || |
|
(!$can_assign{'krb4'} && $can_assign{'krb5'} && |
|
$in{'curr_authtype'} eq 'krb4')) { |
|
$result .= &mt |
('[_1] Kerberos authenticated with domain [_2] '. |
('[_1] Kerberos authenticated with domain [_2] '. |
'[_3] Version 4 [_4] Version 5 [_5]', |
'[_3] Version 4 [_4] Version 5 [_5]', |
'<label><input type="radio" name="login" value="krb" '. |
'<label>'.$authtype, |
'onclick="'.$jscall.'" onchange="'.$jscall.'"'.$krbcheck.' />', |
|
'</label><input type="text" size="10" name="krbarg" '. |
'</label><input type="text" size="10" name="krbarg" '. |
'value="'.$krbarg.'" '. |
'value="'.$krbarg.'" '. |
'onchange="'.$jscall.'" />', |
'onchange="'.$jscall.'"'.$disabled.' />', |
'<label><input type="radio" name="krbver" value="4" '.$check4.' />', |
'<label><input type="radio" name="krbver" value="4" '.$check4.$disabled.' />', |
'</label><label><input type="radio" name="krbver" value="5" '.$check5.' />', |
'</label><label><input type="radio" name="krbver" value="5" '.$check5.$disabled.' />', |
'</label>'); |
'</label>'); |
|
} elsif ($can_assign{'krb4'}) { |
|
$result .= &mt |
|
('[_1] Kerberos authenticated with domain [_2] '. |
|
'[_3] Version 4 [_4]', |
|
'<label>'.$authtype, |
|
'</label><input type="text" size="10" name="krbarg" '. |
|
'value="'.$krbarg.'" '. |
|
'onchange="'.$jscall.'"'.$disabled.' />', |
|
'<label><input type="hidden" name="krbver" value="4" />', |
|
'</label>'); |
|
} elsif ($can_assign{'krb5'}) { |
|
$result .= &mt |
|
('[_1] Kerberos authenticated with domain [_2] '. |
|
'[_3] Version 5 [_4]', |
|
'<label>'.$authtype, |
|
'</label><input type="text" size="10" name="krbarg" '. |
|
'value="'.$krbarg.'" '. |
|
'onchange="'.$jscall.'"'.$disabled.' />', |
|
'<label><input type="hidden" name="krbver" value="5" />', |
|
'</label>'); |
|
} |
return $result; |
return $result; |
} |
} |
|
|
sub authform_internal{ |
sub authform_internal { |
my %args = ( |
my %in = ( |
formname => 'document.cu', |
formname => 'document.cu', |
kerb_def_dom => 'MSU.EDU', |
kerb_def_dom => 'MSU.EDU', |
@_, |
@_, |
); |
); |
|
my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall,$disabled); |
my $intcheck = ""; |
my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); |
my $intarg = 'value=""'; |
if ($in{'readonly'}) { |
if ( grep/^curr_authtype$/,(keys %args) ) { |
$disabled = ' disabled="disabled"'; |
if ($args{'curr_authtype'} eq 'int') { |
} |
$intcheck = " checked=\"on\""; |
if (defined($in{'curr_authtype'})) { |
if ( grep/^curr_autharg$/,(keys %args) ) { |
if ($in{'curr_authtype'} eq 'int') { |
$intarg = "value=\"$args{'curr_autharg'}\""; |
if ($can_assign{'int'}) { |
|
$intcheck = 'checked="checked" '; |
|
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifyuser') { |
|
$intcheck = ''; |
|
} |
|
} |
|
if (defined($in{'curr_autharg'})) { |
|
$intarg = $in{'curr_autharg'}; |
|
} |
|
} else { |
|
$result = &mt('Currently internally authenticated.'); |
|
return $result; |
} |
} |
} |
} |
|
} else { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="hidden" name="login" value="int" />'; |
|
} |
} |
} |
|
if (!$can_assign{'int'}) { |
my $jscall = "javascript:changed_radio('int',$args{'formname'});"; |
return; |
my $result.=&mt |
} elsif ($authtype eq '') { |
|
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifycourse') { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="radio" name="login" value="int"'.$disabled.' />'; |
|
} |
|
} |
|
} |
|
} |
|
$jscall = "javascript:changed_radio('int',$in{'formname'});"; |
|
if ($authtype eq '') { |
|
$authtype = '<input type="radio" name="login" value="int" '.$intcheck. |
|
' onchange="'.$jscall.'" onclick="'.$jscall.'"'.$disabled.' />'; |
|
} |
|
$autharg = '<input type="password" size="10" name="intarg" value="'. |
|
$intarg.'" onchange="'.$jscall.'"'.$disabled.' />'; |
|
$result = &mt |
('[_1] Internally authenticated (with initial password [_2])', |
('[_1] Internally authenticated (with initial password [_2])', |
'<label><input type="radio" name="login" value="int" '.$intcheck. |
'<label>'.$authtype,'</label>'.$autharg); |
' onchange="'.$jscall.'" onclick="'.$jscall.'" />', |
$result.='<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.intarg.type='."'text'".' } else { this.form.intarg.type='."'password'".' }"'.$disabled.' />'.&mt('Visible input').'</label>'; |
'</label><input type="text" size="10" name="intarg" '.$intarg. |
|
' onchange="'.$jscall.'" />'); |
|
return $result; |
return $result; |
} |
} |
|
|
sub authform_local{ |
sub authform_local { |
my %in = ( |
my %in = ( |
formname => 'document.cu', |
formname => 'document.cu', |
kerb_def_dom => 'MSU.EDU', |
kerb_def_dom => 'MSU.EDU', |
@_, |
@_, |
); |
); |
|
my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall,$disabled); |
my $loccheck = ""; |
my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); |
my $locarg = 'value=""'; |
if ($in{'readonly'}) { |
if ( grep/^curr_authtype$/,(keys %in) ) { |
$disabled = ' disabled="disabled"'; |
|
} |
|
if (defined($in{'curr_authtype'})) { |
if ($in{'curr_authtype'} eq 'loc') { |
if ($in{'curr_authtype'} eq 'loc') { |
$loccheck = " checked=\"on\""; |
if ($can_assign{'loc'}) { |
if ( grep/^curr_autharg$/,(keys %in) ) { |
$loccheck = 'checked="checked" '; |
$locarg = "value=\"$in{'curr_autharg'}\""; |
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifyuser') { |
|
$loccheck = ''; |
|
} |
|
} |
|
if (defined($in{'curr_autharg'})) { |
|
$locarg = $in{'curr_autharg'}; |
|
} |
|
} else { |
|
$result = &mt('Currently using local (institutional) authentication.'); |
|
return $result; |
} |
} |
} |
} |
|
} else { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="hidden" name="login" value="loc" />'; |
|
} |
} |
} |
|
if (!$can_assign{'loc'}) { |
my $jscall = "javascript:changed_radio('loc',$in{'formname'});"; |
return; |
my $result.=&mt('[_1] Local Authentication with argument [_2]', |
} elsif ($authtype eq '') { |
'<label><input type="radio" name="login" value="loc" '.$loccheck. |
if (defined($in{'mode'})) { |
' onchange="'.$jscall.'" onclick="'.$jscall.'" />', |
if ($in{'mode'} eq 'modifycourse') { |
'</label><input type="text" size="10" name="locarg" '.$locarg. |
if ($authnum == 1) { |
' onchange="'.$jscall.'" />'); |
$authtype = '<input type="radio" name="login" value="loc"'.$disabled.' />'; |
|
} |
|
} |
|
} |
|
} |
|
$jscall = "javascript:changed_radio('loc',$in{'formname'});"; |
|
if ($authtype eq '') { |
|
$authtype = '<input type="radio" name="login" value="loc" '. |
|
$loccheck.' onchange="'.$jscall.'" onclick="'. |
|
$jscall.'"'.$disabled.' />'; |
|
} |
|
$autharg = '<input type="text" size="10" name="locarg" value="'. |
|
$locarg.'" onchange="'.$jscall.'"'.$disabled.' />'; |
|
$result = &mt('[_1] Local Authentication with argument [_2]', |
|
'<label>'.$authtype,'</label>'.$autharg); |
return $result; |
return $result; |
} |
} |
|
|
sub authform_filesystem{ |
sub authform_filesystem { |
my %in = ( |
my %in = ( |
formname => 'document.cu', |
formname => 'document.cu', |
kerb_def_dom => 'MSU.EDU', |
kerb_def_dom => 'MSU.EDU', |
@_, |
@_, |
); |
); |
my $jscall = "javascript:changed_radio('fsys',$in{'formname'});"; |
my ($fsyscheck,$result,$authtype,$autharg,$jscall,$disabled); |
my $result.= &mt |
my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); |
|
if ($in{'readonly'}) { |
|
$disabled = ' disabled="disabled"'; |
|
} |
|
if (defined($in{'curr_authtype'})) { |
|
if ($in{'curr_authtype'} eq 'fsys') { |
|
if ($can_assign{'fsys'}) { |
|
$fsyscheck = 'checked="checked" '; |
|
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifyuser') { |
|
$fsyscheck = ''; |
|
} |
|
} |
|
} else { |
|
$result = &mt('Currently Filesystem Authenticated.'); |
|
return $result; |
|
} |
|
} |
|
} else { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="hidden" name="login" value="fsys" />'; |
|
} |
|
} |
|
if (!$can_assign{'fsys'}) { |
|
return; |
|
} elsif ($authtype eq '') { |
|
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifycourse') { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="radio" name="login" value="fsys"'.$disabled.' />'; |
|
} |
|
} |
|
} |
|
} |
|
$jscall = "javascript:changed_radio('fsys',$in{'formname'});"; |
|
if ($authtype eq '') { |
|
$authtype = '<input type="radio" name="login" value="fsys" '. |
|
$fsyscheck.' onchange="'.$jscall.'" onclick="'. |
|
$jscall.'"'.$disabled.' />'; |
|
} |
|
$autharg = '<input type="password" size="10" name="fsysarg" value=""'. |
|
' onchange="'.$jscall.'"'.$disabled.' />'; |
|
$result = &mt |
('[_1] Filesystem Authenticated (with initial password [_2])', |
('[_1] Filesystem Authenticated (with initial password [_2])', |
'<label><input type="radio" name="login" value="fsys" '. |
'<label>'.$authtype,'</label>'.$autharg); |
'onchange="'.$jscall.'" onclick="'.$jscall.'" />', |
|
'</label><input type="text" size="10" name="fsysarg" value="" '. |
|
'onchange="'.$jscall.'" />'); |
|
return $result; |
return $result; |
} |
} |
|
|
############################################################### |
sub authform_lti { |
## Get Authentication Defaults for Domain ## |
my %in = ( |
############################################################### |
formname => 'document.cu', |
|
kerb_def_dom => 'MSU.EDU', |
=pod |
@_, |
|
); |
=head1 Domains and Authentication |
my ($lticheck,$result,$authtype,$autharg,$jscall,$disabled); |
|
my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'}); |
Returns default authentication type and an associated argument as |
if ($in{'readonly'}) { |
listed in file 'domain.tab'. |
$disabled = ' disabled="disabled"'; |
|
} |
=over 4 |
if (defined($in{'curr_authtype'})) { |
|
if ($in{'curr_authtype'} eq 'lti') { |
=item * get_auth_defaults |
if ($can_assign{'lti'}) { |
|
$lticheck = 'checked="checked" '; |
get_auth_defaults($target_domain) returns the default authentication |
if (defined($in{'mode'})) { |
type and an associated argument (initial password or a kerberos domain). |
if ($in{'mode'} eq 'modifyuser') { |
These values are stored in lonTabs/domain.tab |
$lticheck = ''; |
|
} |
($def_auth, $def_arg) = &get_auth_defaults($target_domain); |
} |
|
} else { |
If target_domain is not found in domain.tab, returns nothing (''). |
$result = &mt('Currently LTI Authenticated.'); |
|
return $result; |
|
} |
|
} |
|
} else { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="hidden" name="login" value="lti" />'; |
|
} |
|
} |
|
if (!$can_assign{'lti'}) { |
|
return; |
|
} elsif ($authtype eq '') { |
|
if (defined($in{'mode'})) { |
|
if ($in{'mode'} eq 'modifycourse') { |
|
if ($authnum == 1) { |
|
$authtype = '<input type="radio" name="login" value="lti"'.$disabled.' />'; |
|
} |
|
} |
|
} |
|
} |
|
$jscall = "javascript:changed_radio('lti',$in{'formname'});"; |
|
if (($authtype eq '') && (($in{'mode'} eq 'modifycourse') || ($in{'curr_authtype'} ne 'lti'))) { |
|
$authtype = '<input type="radio" name="login" value="lti" '. |
|
$lticheck.' onchange="'.$jscall.'" onclick="'. |
|
$jscall.'"'.$disabled.' />'; |
|
} |
|
$autharg = '<input type="hidden" name="ltiarg" value="" />'; |
|
if ($authtype) { |
|
$result = &mt('[_1] LTI Authenticated', |
|
'<label>'.$authtype.'</label>'.$autharg); |
|
} else { |
|
$result = '<b>'.&mt('LTI Authenticated').'</b>'. |
|
$autharg; |
|
} |
|
return $result; |
|
} |
|
|
=cut |
sub get_assignable_auth { |
|
my ($dom) = @_; |
|
if ($dom eq '') { |
|
$dom = $env{'request.role.domain'}; |
|
} |
|
my %can_assign = ( |
|
krb4 => 1, |
|
krb5 => 1, |
|
int => 1, |
|
loc => 1, |
|
); |
|
my %domconfig = &Apache::lonnet::get_dom('configuration',['usercreation'],$dom); |
|
if (ref($domconfig{'usercreation'}) eq 'HASH') { |
|
if (ref($domconfig{'usercreation'}{'authtypes'}) eq 'HASH') { |
|
my $authhash = $domconfig{'usercreation'}{'authtypes'}; |
|
my $context; |
|
if ($env{'request.role'} =~ /^au/) { |
|
$context = 'author'; |
|
} elsif ($env{'request.role'} =~ /^(dc|dh)/) { |
|
$context = 'domain'; |
|
} elsif ($env{'request.course.id'}) { |
|
$context = 'course'; |
|
} |
|
if ($context) { |
|
if (ref($authhash->{$context}) eq 'HASH') { |
|
%can_assign = %{$authhash->{$context}}; |
|
} |
|
} |
|
} |
|
} |
|
my $authnum = 0; |
|
foreach my $key (keys(%can_assign)) { |
|
if ($can_assign{$key}) { |
|
$authnum ++; |
|
} |
|
} |
|
if ($can_assign{'krb4'} && $can_assign{'krb5'}) { |
|
$authnum --; |
|
} |
|
return ($authnum,%can_assign); |
|
} |
|
|
|
sub check_passwd_rules { |
|
my ($domain,$plainpass) = @_; |
|
my %passwdconf = &Apache::lonnet::get_passwdconf($domain); |
|
my ($min,$max,@chars,@brokerule,$warning); |
|
$min = $Apache::lonnet::passwdmin; |
|
if (ref($passwdconf{'chars'}) eq 'ARRAY') { |
|
if ($passwdconf{'min'} =~ /^\d+$/) { |
|
if ($passwdconf{'min'} > $min) { |
|
$min = $passwdconf{'min'}; |
|
} |
|
} |
|
if ($passwdconf{'max'} =~ /^\d+$/) { |
|
$max = $passwdconf{'max'}; |
|
} |
|
@chars = @{$passwdconf{'chars'}}; |
|
} |
|
if (($min) && (length($plainpass) < $min)) { |
|
push(@brokerule,'min'); |
|
} |
|
if (($max) && (length($plainpass) > $max)) { |
|
push(@brokerule,'max'); |
|
} |
|
if (@chars) { |
|
my %rules; |
|
map { $rules{$_} = 1; } @chars; |
|
if ($rules{'uc'}) { |
|
unless ($plainpass =~ /[A-Z]/) { |
|
push(@brokerule,'uc'); |
|
} |
|
} |
|
if ($rules{'lc'}) { |
|
unless ($plainpass =~ /[a-z]/) { |
|
push(@brokerule,'lc'); |
|
} |
|
} |
|
if ($rules{'num'}) { |
|
unless ($plainpass =~ /\d/) { |
|
push(@brokerule,'num'); |
|
} |
|
} |
|
if ($rules{'spec'}) { |
|
unless ($plainpass =~ /[!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~]/) { |
|
push(@brokerule,'spec'); |
|
} |
|
} |
|
} |
|
if (@brokerule) { |
|
my %rulenames = &Apache::lonlocal::texthash( |
|
uc => 'At least one upper case letter', |
|
lc => 'At least one lower case letter', |
|
num => 'At least one number', |
|
spec => 'At least one non-alphanumeric', |
|
); |
|
$rulenames{'uc'} .= ': ABCDEFGHIJKLMNOPQRSTUVWXYZ'; |
|
$rulenames{'lc'} .= ': abcdefghijklmnopqrstuvwxyz'; |
|
$rulenames{'num'} .= ': 0123456789'; |
|
$rulenames{'spec'} .= ': !"\#$%&\'()*+,-./:;<=>?@[\]^_\`{|}~'; |
|
$rulenames{'min'} = &mt('Minimum password length: [_1]',$min); |
|
$rulenames{'max'} = &mt('Maximum password length: [_1]',$max); |
|
$warning = &mt('Password did not satisfy the following:').'<ul>'; |
|
foreach my $rule ('min','max','uc','lc','num','spec') { |
|
if (grep(/^$rule$/,@brokerule)) { |
|
$warning .= '<li>'.$rulenames{$rule}.'</li>'; |
|
} |
|
} |
|
$warning .= '</ul>'; |
|
} |
|
if (wantarray) { |
|
return @brokerule; |
|
} |
|
return $warning; |
|
} |
|
|
#------------------------------------------- |
sub passwd_validation_js { |
sub get_auth_defaults { |
my ($currpasswdval,$domain,$context,$id) = @_; |
my $domain=shift; |
my (%passwdconf,$alertmsg); |
return (&Apache::lonnet::domain($domain,'auth_def'), |
if ($context eq 'linkprot') { |
&Apache::lonnet::domain($domain,'auth_arg_def')); |
my %domconfig = &Apache::lonnet::get_dom('configuration',['ltisec'],$domain); |
|
if (ref($domconfig{'ltisec'}) eq 'HASH') { |
|
if (ref($domconfig{'ltisec'}{'rules'}) eq 'HASH') { |
|
%passwdconf = %{$domconfig{'ltisec'}{'rules'}}; |
|
} |
|
} |
|
if ($id eq 'add') { |
|
$alertmsg = &mt('Secret for added launcher did not satisfy requirement(s):').'\n\n'; |
|
} elsif ($id =~ /^\d+$/) { |
|
my $pos = $id+1; |
|
$alertmsg = &mt('Secret for launcher [_1] did not satisfy requirement(s):','#'.$pos).'\n\n'; |
|
} else { |
|
$alertmsg = &mt('A secret did not satisfy requirement(s):').'\n\n'; |
|
} |
|
} else { |
|
%passwdconf = &Apache::lonnet::get_passwdconf($domain); |
|
$alertmsg = &mt('Initial password did not satisfy requirement(s):').'\n\n'; |
|
} |
|
my ($min,$max,@chars,$numrules,$intargjs,%alert); |
|
$numrules = 0; |
|
$min = $Apache::lonnet::passwdmin; |
|
if (ref($passwdconf{'chars'}) eq 'ARRAY') { |
|
if ($passwdconf{'min'} =~ /^\d+$/) { |
|
if ($passwdconf{'min'} > $min) { |
|
$min = $passwdconf{'min'}; |
|
} |
|
} |
|
if ($passwdconf{'max'} =~ /^\d+$/) { |
|
$max = $passwdconf{'max'}; |
|
$numrules ++; |
|
} |
|
@chars = @{$passwdconf{'chars'}}; |
|
if (@chars) { |
|
$numrules ++; |
|
} |
|
} |
|
if ($min > 0) { |
|
$numrules ++; |
|
} |
|
if (($min > 0) || ($max ne '') || (@chars > 0)) { |
|
if ($min) { |
|
$alert{'min'} = &mt('minimum [quant,_1,character]',$min).'\n'; |
|
} |
|
if ($max) { |
|
$alert{'max'} = &mt('maximum [quant,_1,character]',$max).'\n'; |
|
} |
|
my (@charalerts,@charrules); |
|
if (@chars) { |
|
if (grep(/^uc$/,@chars)) { |
|
push(@charalerts,&mt('contain at least one upper case letter')); |
|
push(@charrules,'uc'); |
|
} |
|
if (grep(/^lc$/,@chars)) { |
|
push(@charalerts,&mt('contain at least one lower case letter')); |
|
push(@charrules,'lc'); |
|
} |
|
if (grep(/^num$/,@chars)) { |
|
push(@charalerts,&mt('contain at least one number')); |
|
push(@charrules,'num'); |
|
} |
|
if (grep(/^spec$/,@chars)) { |
|
push(@charalerts,&mt('contain at least one non-alphanumeric')); |
|
push(@charrules,'spec'); |
|
} |
|
} |
|
$intargjs = qq| var rulesmsg = '';\n|. |
|
qq| var currpwval = $currpasswdval;\n|; |
|
if ($min) { |
|
$intargjs .= qq| |
|
if (currpwval.length < $min) { |
|
rulesmsg += ' - $alert{min}'; |
|
} |
|
|; |
|
} |
|
if ($max) { |
|
$intargjs .= qq| |
|
if (currpwval.length > $max) { |
|
rulesmsg += ' - $alert{max}'; |
|
} |
|
|; |
|
} |
|
if (@chars > 0) { |
|
my $charrulestr = '"'.join('","',@charrules).'"'; |
|
my $charalertstr = '"'.join('","',@charalerts).'"'; |
|
$intargjs .= qq| var brokerules = new Array();\n|. |
|
qq| var charrules = new Array($charrulestr);\n|. |
|
qq| var charalerts = new Array($charalertstr);\n|; |
|
my %rules; |
|
map { $rules{$_} = 1; } @chars; |
|
if ($rules{'uc'}) { |
|
$intargjs .= qq| |
|
var ucRegExp = /[A-Z]/; |
|
if (!ucRegExp.test(currpwval)) { |
|
brokerules.push('uc'); |
|
} |
|
|; |
|
} |
|
if ($rules{'lc'}) { |
|
$intargjs .= qq| |
|
var lcRegExp = /[a-z]/; |
|
if (!lcRegExp.test(currpwval)) { |
|
brokerules.push('lc'); |
|
} |
|
|; |
|
} |
|
if ($rules{'num'}) { |
|
$intargjs .= qq| |
|
var numRegExp = /[0-9]/; |
|
if (!numRegExp.test(currpwval)) { |
|
brokerules.push('num'); |
|
} |
|
|; |
|
} |
|
if ($rules{'spec'}) { |
|
$intargjs .= q| |
|
var specRegExp = /[!"#$%&'()*+,\-.\/:;<=>?@[\\^\]_`{\|}~]/; |
|
if (!specRegExp.test(currpwval)) { |
|
brokerules.push('spec'); |
|
} |
|
|; |
|
} |
|
$intargjs .= qq| |
|
if (brokerules.length > 0) { |
|
for (var i=0; i<brokerules.length; i++) { |
|
for (var j=0; j<charrules.length; j++) { |
|
if (brokerules[i] == charrules[j]) { |
|
rulesmsg += ' - '+charalerts[j]+'\\n'; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|; |
|
} |
|
$intargjs .= qq| |
|
if (rulesmsg != '') { |
|
rulesmsg = '$alertmsg'+rulesmsg; |
|
alert(rulesmsg); |
|
return false; |
|
} |
|
|; |
|
} |
|
return ($numrules,$intargjs); |
} |
} |
############################################################### |
|
## End Get Authentication Defaults for Domain ## |
|
############################################################### |
|
|
|
############################################################### |
############################################################### |
## Get Kerberos Defaults for Domain ## |
## Get Kerberos Defaults for Domain ## |
Line 1885 sub get_auth_defaults {
|
Line 3595 sub get_auth_defaults {
|
|
|
=pod |
=pod |
|
|
=item * get_kerberos_defaults |
=item * &get_kerberos_defaults() |
|
|
get_kerberos_defaults($target_domain) returns the default kerberos |
get_kerberos_defaults($target_domain) returns the default kerberos |
version and domain. If not found in domain.tabs, it defaults to |
version and domain. If not found, it defaults to version 4 and the |
version 4 and the domain of the server. |
domain of the server. |
|
|
|
=over 4 |
|
|
($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain); |
($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain); |
|
|
|
=back |
|
|
|
=back |
|
|
=cut |
=cut |
|
|
#------------------------------------------- |
#------------------------------------------- |
sub get_kerberos_defaults { |
sub get_kerberos_defaults { |
my $domain=shift; |
my $domain=shift; |
my ($krbdef,$krbdefdom) = |
my ($krbdef,$krbdefdom); |
&Apache::loncommon::get_auth_defaults($domain); |
my %domdefaults = &Apache::lonnet::get_domain_defaults($domain); |
unless ($krbdef =~/^krb/ && $krbdefdom) { |
if (($domdefaults{'auth_def'} =~/^krb(4|5)$/) && ($domdefaults{'auth_arg_def'} ne '')) { |
|
$krbdef = $domdefaults{'auth_def'}; |
|
$krbdefdom = $domdefaults{'auth_arg_def'}; |
|
} else { |
$ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/; |
$ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/; |
my $krbdefdom=$1; |
my $krbdefdom=$1; |
$krbdefdom=~tr/a-z/A-Z/; |
$krbdefdom=~tr/a-z/A-Z/; |
Line 1909 sub get_kerberos_defaults {
|
Line 3628 sub get_kerberos_defaults {
|
return ($krbdef,$krbdefdom); |
return ($krbdef,$krbdefdom); |
} |
} |
|
|
=pod |
|
|
|
=back |
|
|
|
=cut |
|
|
|
############################################################### |
############################################################### |
## Thesaurus Functions ## |
## Thesaurus Functions ## |
Line 1925 sub get_kerberos_defaults {
|
Line 3639 sub get_kerberos_defaults {
|
|
|
=over 4 |
=over 4 |
|
|
=item * initialize_keywords |
=item * &initialize_keywords() |
|
|
Initializes the package variable %Keywords if it is empty. Uses the |
Initializes the package variable %Keywords if it is empty. Uses the |
package variable $thesaurus_db_file. |
package variable $thesaurus_db_file. |
Line 1962 sub initialize_keywords {
|
Line 3676 sub initialize_keywords {
|
# Remove special values from %Keywords. |
# Remove special values from %Keywords. |
foreach my $value ('total.count','average.count') { |
foreach my $value ('total.count','average.count') { |
delete($Keywords{$value}) if (exists($Keywords{$value})); |
delete($Keywords{$value}) if (exists($Keywords{$value})); |
} |
} |
return 1; |
return 1; |
} |
} |
|
|
Line 1970 sub initialize_keywords {
|
Line 3684 sub initialize_keywords {
|
|
|
=pod |
=pod |
|
|
=item * keyword($word) |
=item * &keyword($word) |
|
|
Returns true if $word is a keyword. A keyword is a word that appears more |
Returns true if $word is a keyword. A keyword is a word that appears more |
than the average number of times in the thesaurus database. Calls |
than the average number of times in the thesaurus database. Calls |
Line 1991 sub keyword {
|
Line 3705 sub keyword {
|
|
|
=pod |
=pod |
|
|
=item * get_related_words |
=item * &get_related_words() |
|
|
Look up a word in the thesaurus. Takes a scalar argument and returns |
Look up a word in the thesaurus. Takes a scalar argument and returns |
an array of words. If the keyword is not in the thesaurus, an empty array |
an array of words. If the keyword is not in the thesaurus, an empty array |
Line 2000 database which holds them.
|
Line 3714 database which holds them.
|
|
|
Uses global $thesaurus_db_file. |
Uses global $thesaurus_db_file. |
|
|
|
|
=cut |
=cut |
|
|
############################################################### |
############################################################### |
Line 2049 sub get_related_words {
|
Line 3764 sub get_related_words {
|
|
|
=over 4 |
=over 4 |
|
|
=item * plainname($uname,$udom,$first) |
=item * &plainname($uname,$udom,$first) |
|
|
Takes a users logon name and returns it as a string in |
Takes a users logon name and returns it as a string in |
"first middle last generation" form |
"first middle last generation" form |
Line 2078 sub plainname {
|
Line 3793 sub plainname {
|
# -------------------------------------------------------------------- Nickname |
# -------------------------------------------------------------------- Nickname |
=pod |
=pod |
|
|
=item * nickname($uname,$udom) |
=item * &nickname($uname,$udom) |
|
|
Gets a users name and returns it as a string as |
Gets a users name and returns it as a string as |
|
|
Line 2128 sub getnames {
|
Line 3843 sub getnames {
|
} |
} |
|
|
# -------------------------------------------------------------------- getemails |
# -------------------------------------------------------------------- getemails |
|
|
=pod |
=pod |
|
|
=item * getemails($uname,$udom) |
=item * &getemails($uname,$udom) |
|
|
Gets a user's email information and returns it as a hash with keys: |
Gets a user's email information and returns it as a hash with keys: |
notification, critnotification, permanentemail |
notification, critnotification, permanentemail |
|
|
For notification and critnotification, values are comma-separated lists |
For notification and critnotification, values are comma-separated lists |
of e-mail address(es); for permanentemail, value is a single e-mail address. |
of e-mail addresses; for permanentemail, value is a single e-mail address. |
|
|
|
|
=cut |
=cut |
|
|
|
|
sub getemails { |
sub getemails { |
my ($uname,$udom)=@_; |
my ($uname,$udom)=@_; |
if ($udom eq 'public' && $uname eq 'public') { |
if ($udom eq 'public' && $uname eq 'public') { |
Line 2170 sub flush_email_cache {
|
Line 3888 sub flush_email_cache {
|
&Apache::lonnet::devalidate_cache_new('emailscache',$id); |
&Apache::lonnet::devalidate_cache_new('emailscache',$id); |
} |
} |
|
|
|
# -------------------------------------------------------------------- getlangs |
|
|
|
=pod |
|
|
|
=item * &getlangs($uname,$udom) |
|
|
|
Gets a user's language preference and returns it as a hash with key: |
|
language. |
|
|
|
=cut |
|
|
|
|
|
sub getlangs { |
|
my ($uname,$udom) = @_; |
|
if (!$udom) { $udom =$env{'user.domain'}; } |
|
if (!$uname) { $uname=$env{'user.name'}; } |
|
my $id=$uname.':'.$udom; |
|
my ($langs,$cached)=&Apache::lonnet::is_cached_new('userlangs',$id); |
|
if ($cached) { |
|
return %{$langs}; |
|
} else { |
|
my %loadlangs=&Apache::lonnet::get('environment',['languages'], |
|
$udom,$uname); |
|
&Apache::lonnet::do_cache_new('userlangs',$id,\%loadlangs); |
|
return %loadlangs; |
|
} |
|
} |
|
|
|
sub flush_langs_cache { |
|
my ($uname,$udom)=@_; |
|
if (!$udom) { $udom =$env{'user.domain'}; } |
|
if (!$uname) { $uname=$env{'user.name'}; } |
|
return if ($udom eq 'public' && $uname eq 'public'); |
|
my $id=$uname.':'.$udom; |
|
&Apache::lonnet::devalidate_cache_new('userlangs',$id); |
|
} |
|
|
# ------------------------------------------------------------------ Screenname |
# ------------------------------------------------------------------ Screenname |
|
|
=pod |
=pod |
|
|
=item * screenname($uname,$udom) |
=item * &screenname($uname,$udom) |
|
|
Gets a users screenname and returns it as a string |
Gets a users screenname and returns it as a string |
|
|
Line 2189 sub screenname {
|
Line 3944 sub screenname {
|
} |
} |
|
|
|
|
|
# ------------------------------------------------------------- Confirm Wrapper |
|
=pod |
|
|
|
=item * &confirmwrapper($message) |
|
|
|
Wrap messages about completion of operation in box |
|
|
|
=cut |
|
|
|
sub confirmwrapper { |
|
my ($message)=@_; |
|
if ($message) { |
|
return "\n".'<div class="LC_confirm_box">'."\n" |
|
.$message."\n" |
|
.'</div>'."\n"; |
|
} else { |
|
return $message; |
|
} |
|
} |
|
|
# ------------------------------------------------------------- Message Wrapper |
# ------------------------------------------------------------- Message Wrapper |
|
|
sub messagewrapper { |
sub messagewrapper { |
Line 2199 sub messagewrapper {
|
Line 3974 sub messagewrapper {
|
'&subject='.&escape($subject).'&text='.&escape($text).'" '. |
'&subject='.&escape($subject).'&text='.&escape($text).'" '. |
'title="'.&mt('Send message').'">'.$link.'</a>'; |
'title="'.&mt('Send message').'">'.$link.'</a>'; |
} |
} |
|
|
# --------------------------------------------------------------- Notes Wrapper |
# --------------------------------------------------------------- Notes Wrapper |
|
|
sub noteswrapper { |
sub noteswrapper { |
my ($link,$un,$do)=@_; |
my ($link,$un,$do)=@_; |
return |
return |
"<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>"; |
"<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>"; |
} |
} |
|
|
# ------------------------------------------------------------- Aboutme Wrapper |
# ------------------------------------------------------------- Aboutme Wrapper |
|
|
sub aboutmewrapper { |
sub aboutmewrapper { |
my ($link,$username,$domain,$target)=@_; |
my ($link,$username,$domain,$target,$class)=@_; |
if (!defined($username) && !defined($domain)) { |
if (!defined($username) && !defined($domain)) { |
return; |
return; |
} |
} |
return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'. |
return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'. |
($target?' target="$target"':'').' title="'.&mt("View this user's personal page").'">'.$link.'</a>'; |
($target?' target="'.$target.'"':'').($class?' class="'.$class.'"':'').' title="'.&mt("View this user's personal information page").'">'.$link.'</a>'; |
} |
} |
|
|
# ------------------------------------------------------------ Syllabus Wrapper |
# ------------------------------------------------------------ Syllabus Wrapper |
|
|
|
|
sub syllabuswrapper { |
sub syllabuswrapper { |
my ($linktext,$coursedir,$domain,$fontcolor)=@_; |
my ($linktext,$coursedir,$domain)=@_; |
if ($fontcolor) { |
|
$linktext='<font color="'.$fontcolor.'">'.$linktext.'</font>'; |
|
} |
|
return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>}; |
return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>}; |
} |
} |
|
|
|
sub aboutme_on { |
|
my ($uname,$udom)=@_; |
|
unless ($uname) { $uname=$env{'user.name'}; } |
|
unless ($udom) { $udom=$env{'user.domain'}; } |
|
return if ($udom eq 'public' && $uname eq 'public'); |
|
my $hashkey=$uname.':'.$udom; |
|
my ($aboutme,$cached)=&Apache::lonnet::is_cached_new('aboutme',$hashkey); |
|
if ($cached) { |
|
return $aboutme; |
|
} |
|
$aboutme = &Apache::lonnet::usertools_access($uname,$udom,'aboutme'); |
|
&Apache::lonnet::do_cache_new('aboutme',$hashkey,$aboutme,3600); |
|
return $aboutme; |
|
} |
|
|
|
sub devalidate_aboutme_cache { |
|
my ($uname,$udom)=@_; |
|
if (!$udom) { $udom =$env{'user.domain'}; } |
|
if (!$uname) { $uname=$env{'user.name'}; } |
|
return if ($udom eq 'public' && $uname eq 'public'); |
|
my $id=$uname.':'.$udom; |
|
&Apache::lonnet::devalidate_cache_new('aboutme',$id); |
|
} |
|
|
|
# ----------------------------------------------------------------------------- |
|
|
sub track_student_link { |
sub track_student_link { |
my ($linktext,$sname,$sdom,$target,$start) = @_; |
my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_; |
my $link ="/adm/trackstudent?"; |
my $link ="/adm/trackstudent?"; |
my $title = 'View recent activity'; |
my $title = 'View recent activity'; |
if (defined($sname) && $sname !~ /^\s*$/ && |
if (defined($sname) && $sname !~ /^\s*$/ && |
Line 2243 sub track_student_link {
|
Line 4042 sub track_student_link {
|
$target = ''; |
$target = ''; |
} |
} |
if ($start) { $link.='&start='.$start; } |
if ($start) { $link.='&start='.$start; } |
|
if ($only_body) { $link .= '&only_body=1'; } |
|
$title = &mt($title); |
|
$linktext = &mt($linktext); |
return qq{<a href="$link" title="$title" $target>$linktext</a>}. |
return qq{<a href="$link" title="$title" $target>$linktext</a>}. |
&help_open_topic('View_recent_activity'); |
&help_open_topic('View_recent_activity'); |
} |
} |
|
|
|
sub slot_reservations_link { |
|
my ($linktext,$sname,$sdom,$target) = @_; |
|
my $link ="/adm/slotrequest?command=showresv&origin=aboutme"; |
|
my $title = 'View slot reservation history'; |
|
if (defined($sname) && $sname !~ /^\s*$/ && |
|
defined($sdom) && $sdom !~ /^\s*$/) { |
|
$link .= "&uname=$sname&udom=$sdom"; |
|
$title .= ' of this student'; |
|
} |
|
if (defined($target) && $target !~ /^\s*$/) { |
|
$target = qq{target="$target"}; |
|
} else { |
|
$target = ''; |
|
} |
|
$title = &mt($title); |
|
$linktext = &mt($linktext); |
|
return qq{<a href="$link" title="$title" $target>$linktext</a>}; |
|
# FIXME uncomment when help item created: &help_open_topic('Slot_Reservation_History'); |
|
|
|
} |
|
|
# ===================================================== Display a student photo |
# ===================================================== Display a student photo |
|
|
|
|
Line 2269 sub student_image_tag {
|
Line 4091 sub student_image_tag {
|
|
|
=over 4 |
=over 4 |
|
|
=item * languageids() |
=item * &languageids() |
|
|
returns list of all language ids |
returns list of all language ids |
|
|
Line 2281 sub languageids {
|
Line 4103 sub languageids {
|
|
|
=pod |
=pod |
|
|
=item * languagedescription() |
=item * &languagedescription() |
|
|
returns description of a specified language id |
returns description of a specified language id |
|
|
Line 2294 sub languagedescription {
|
Line 4116 sub languagedescription {
|
($supported_language{$code}?' ('.&mt('interface available').')':''); |
($supported_language{$code}?' ('.&mt('interface available').')':''); |
} |
} |
|
|
|
=pod |
|
|
|
=item * &plainlanguagedescription |
|
|
|
Returns both the plain language description (e.g. 'Creoles and Pidgins, English-based (Other)') |
|
and the language character encoding (e.g. ISO) separated by a ' - ' string. |
|
|
|
=cut |
|
|
sub plainlanguagedescription { |
sub plainlanguagedescription { |
my $code=shift; |
my $code=shift; |
return $language{$code}; |
return $language{$code}; |
} |
} |
|
|
|
=pod |
|
|
|
=item * &supportedlanguagecode |
|
|
|
Returns the supported language code (e.g. sptutf maps to pt) given a language |
|
code. |
|
|
|
=cut |
|
|
sub supportedlanguagecode { |
sub supportedlanguagecode { |
my $code=shift; |
my $code=shift; |
return $supported_language{$code}; |
return $supported_language{$code}; |
Line 2306 sub supportedlanguagecode {
|
Line 4146 sub supportedlanguagecode {
|
|
|
=pod |
=pod |
|
|
=item * copyrightids() |
=item * &latexlanguage() |
|
|
|
Given a language key code returns the correspondnig language to use |
|
to select the correct hyphenation on LaTeX printouts. This is undef if there |
|
is no supported hyphenation for the language code. |
|
|
|
=cut |
|
|
|
sub latexlanguage { |
|
my $code = shift; |
|
return $latex_language{$code}; |
|
} |
|
|
|
=pod |
|
|
|
=item * &latexhyphenation() |
|
|
|
Same as above but what's supplied is the language as it might be stored |
|
in the metadata. |
|
|
|
=cut |
|
|
|
sub latexhyphenation { |
|
my $key = shift; |
|
return $latex_language_bykey{$key}; |
|
} |
|
|
|
=pod |
|
|
|
=item * ©rightids() |
|
|
returns list of all copyrights |
returns list of all copyrights |
|
|
Line 2318 sub copyrightids {
|
Line 4187 sub copyrightids {
|
|
|
=pod |
=pod |
|
|
=item * copyrightdescription() |
=item * ©rightdescription() |
|
|
returns description of a specified copyright id |
returns description of a specified copyright id |
|
|
Line 2330 sub copyrightdescription {
|
Line 4199 sub copyrightdescription {
|
|
|
=pod |
=pod |
|
|
=item * source_copyrightids() |
=item * &source_copyrightids() |
|
|
returns list of all source copyrights |
returns list of all source copyrights |
|
|
Line 2342 sub source_copyrightids {
|
Line 4211 sub source_copyrightids {
|
|
|
=pod |
=pod |
|
|
=item * source_copyrightdescription() |
=item * &source_copyrightdescription() |
|
|
returns description of a specified source copyright id |
returns description of a specified source copyright id |
|
|
Line 2354 sub source_copyrightdescription {
|
Line 4223 sub source_copyrightdescription {
|
|
|
=pod |
=pod |
|
|
=item * filecategories() |
=item * &filecategories() |
|
|
returns list of all file categories |
returns list of all file categories |
|
|
Line 2366 sub filecategories {
|
Line 4235 sub filecategories {
|
|
|
=pod |
=pod |
|
|
=item * filecategorytypes() |
=item * &filecategorytypes() |
|
|
returns list of file types belonging to a given file |
returns list of file types belonging to a given file |
category |
category |
Line 2380 sub filecategorytypes {
|
Line 4249 sub filecategorytypes {
|
|
|
=pod |
=pod |
|
|
=item * fileembstyle() |
=item * &fileembstyle() |
|
|
returns embedding style for a specified file type |
returns embedding style for a specified file type |
|
|
Line 2398 sub filemimetype {
|
Line 4267 sub filemimetype {
|
sub filecategoryselect { |
sub filecategoryselect { |
my ($name,$value)=@_; |
my ($name,$value)=@_; |
return &select_form($value,$name, |
return &select_form($value,$name, |
'' => &mt('Any category'), |
{'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))}); |
map { $_,$_ } sort(keys(%category_extensions))); |
|
} |
} |
|
|
=pod |
=pod |
|
|
=item * filedescription() |
=item * &filedescription() |
|
|
returns description for a specified file type |
returns description for a specified file type |
|
|
Line 2418 sub filedescription {
|
Line 4286 sub filedescription {
|
|
|
=pod |
=pod |
|
|
=item * filedescriptionex() |
=item * &filedescriptionex() |
|
|
returns description for a specified file type with |
returns description for a specified file type with |
extra formatting |
extra formatting |
Line 2450 sub fileextensions {
|
Line 4318 sub fileextensions {
|
|
|
sub display_languages { |
sub display_languages { |
my %languages=(); |
my %languages=(); |
foreach my $lang (&preferred_languages()) { |
foreach my $lang (&Apache::lonlocal::preferred_languages()) { |
$languages{$lang}=1; |
$languages{$lang}=1; |
} |
} |
&get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']); |
&get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']); |
Line 2462 sub display_languages {
|
Line 4330 sub display_languages {
|
return %languages; |
return %languages; |
} |
} |
|
|
sub preferred_languages { |
sub languages { |
my @languages=(); |
my ($possible_langs) = @_; |
if ($env{'course.'.$env{'request.course.id'}.'.languages'}) { |
my @preferred_langs = &Apache::lonlocal::preferred_languages(); |
@languages=(@languages,split(/\s*(\,|\;|\:)\s*/, |
if (!ref($possible_langs)) { |
$env{'course.'.$env{'request.course.id'}.'.languages'})); |
if( wantarray ) { |
} |
return @preferred_langs; |
if ($env{'environment.languages'}) { |
} else { |
@languages=(@languages, |
return $preferred_langs[0]; |
split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'})); |
} |
} |
} |
my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0]; |
my %possibilities = map { $_ => 1 } (@$possible_langs); |
if ($browser) { |
my @preferred_possibilities; |
@languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser)); |
foreach my $preferred_lang (@preferred_langs) { |
} |
if (exists($possibilities{$preferred_lang})) { |
if (&Apache::lonnet::domain($env{'user.domain'},'lang_def')) { |
push(@preferred_possibilities, $preferred_lang); |
@languages=(@languages, |
|
&Apache::lonnet::domain($env{'user.domain'}, |
|
'lang_def')); |
|
} |
|
if (&Apache::lonnet::domain($env{'request.role.domain'},'lang_def')) { |
|
@languages=(@languages, |
|
&Apache::lonnet::domain($env{'request.role.domain'}, |
|
'lang_def')); |
|
} |
|
if (&Apache::lonnet::domain($Apache::lonnet::perlvar{'lonDefDomain'}, |
|
'lang_def')) { |
|
@languages=(@languages, |
|
&Apache::lonnet::domain($Apache::lonnet::perlvar{'lonDefDomain'}, |
|
'lang_def')); |
|
} |
|
# turn "en-ca" into "en-ca,en" |
|
my @genlanguages; |
|
foreach my $lang (@languages) { |
|
unless ($lang=~/\w/) { next; } |
|
push (@genlanguages,$lang); |
|
if ($lang=~/(\-|\_)/) { |
|
push(@genlanguages,(split(/(\-|\_)/,$lang))[0]); |
|
} |
} |
} |
} |
return @genlanguages; |
if( wantarray ) { |
|
return @preferred_possibilities; |
|
} |
|
return $preferred_possibilities[0]; |
|
} |
|
|
|
sub user_lang { |
|
my ($touname,$toudom,$fromcid) = @_; |
|
my @userlangs; |
|
if (($fromcid ne '') && ($env{'course.'.$fromcid.'.languages'} ne '')) { |
|
@userlangs=(@userlangs,split(/\s*(\,|\;|\:)\s*/, |
|
$env{'course.'.$fromcid.'.languages'})); |
|
} else { |
|
my %langhash = &getlangs($touname,$toudom); |
|
if ($langhash{'languages'} ne '') { |
|
@userlangs = split(/\s*(\,|\;|\:)\s*/,$langhash{'languages'}); |
|
} else { |
|
my %domdefs = &Apache::lonnet::get_domain_defaults($toudom); |
|
if ($domdefs{'lang_def'} ne '') { |
|
@userlangs = ($domdefs{'lang_def'}); |
|
} |
|
} |
|
} |
|
my @languages=&Apache::lonlocal::get_genlanguages(@userlangs); |
|
my $user_lh = Apache::localize->get_handle(@languages); |
|
return $user_lh; |
} |
} |
|
|
|
|
############################################################### |
############################################################### |
## Student Answer Attempts ## |
## Student Answer Attempts ## |
############################################################### |
############################################################### |
Line 2514 sub preferred_languages {
|
Line 4386 sub preferred_languages {
|
|
|
=over 4 |
=over 4 |
|
|
=item * get_previous_attempt($symb, $username, $domain, $course, |
=item * &get_previous_attempt($symb, $username, $domain, $course, |
$getattempt, $regexp, $gradesub) |
$getattempt, $regexp, $gradesub, $usec, $identifier) |
|
|
Return string with previous attempt on problem. Arguments: |
Return string with previous attempt on problem. Arguments: |
|
|
Line 2537 Return string with previous attempt on p
|
Line 4409 Return string with previous attempt on p
|
|
|
=item * $gradesub: routine that processes the string if it matches $regexp |
=item * $gradesub: routine that processes the string if it matches $regexp |
|
|
|
=item * $usec: section of the desired student |
|
|
|
=item * $identifier: counter for student (multiple students one problem) or |
|
problem (one student; whole sequence). |
|
|
=back |
=back |
|
|
The output string is a table containing all desired attempts, if any. |
The output string is a table containing all desired attempts, if any. |
Line 2544 The output string is a table containing
|
Line 4421 The output string is a table containing
|
=cut |
=cut |
|
|
sub get_previous_attempt { |
sub get_previous_attempt { |
my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_; |
my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub,$usec,$identifier)=@_; |
my $prevattempts=''; |
my $prevattempts=''; |
no strict 'refs'; |
no strict 'refs'; |
if ($symb) { |
if ($symb) { |
Line 2554 sub get_previous_attempt {
|
Line 4431 sub get_previous_attempt {
|
my %lasthash=(); |
my %lasthash=(); |
my $version; |
my $version; |
for ($version=1;$version<=$returnhash{'version'};$version++) { |
for ($version=1;$version<=$returnhash{'version'};$version++) { |
foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) { |
foreach my $key (reverse(sort(split(/\:/,$returnhash{$version.':keys'})))) { |
$lasthash{$key}=$returnhash{$version.':'.$key}; |
if ($key =~ /\.rawrndseed$/) { |
|
my ($id) = ($key =~ /^(.+)\.rawrndseed$/); |
|
$lasthash{$id.'.rndseed'} = $returnhash{$version.':'.$key}; |
|
} else { |
|
$lasthash{$key}=$returnhash{$version.':'.$key}; |
|
} |
} |
} |
} |
} |
$prevattempts='<table border="0" width="100%"><tr><td bgcolor="#777777">'; |
$prevattempts=&start_data_table().&start_data_table_header_row(); |
$prevattempts.='<table border="0" width="100%"><tr bgcolor="#e6ffff"><td>History</td>'; |
$prevattempts.='<th>'.&mt('History').'</th>'; |
|
my (%typeparts,%lasthidden,%regraded,%hidestatus); |
|
my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'}); |
foreach my $key (sort(keys(%lasthash))) { |
foreach my $key (sort(keys(%lasthash))) { |
my ($ign,@parts) = split(/\./,$key); |
my ($ign,@parts) = split(/\./,$key); |
if ($#parts > 0) { |
if ($#parts > 0) { |
my $data=$parts[-1]; |
my $data=$parts[-1]; |
|
next if ($data eq 'foilorder'); |
pop(@parts); |
pop(@parts); |
$prevattempts.='<td>Part '.join('.',@parts).'<br />'.$data.' </td>'; |
$prevattempts.='<th>'.&mt('Part ').join('.',@parts).'<br />'.$data.' </th>'; |
|
if ($data eq 'type') { |
|
unless ($showsurv) { |
|
my $id = join(',',@parts); |
|
$typeparts{$ign.'.'.$id} = $lasthash{$key}; |
|
if (($lasthash{$key} eq 'anonsurvey') || ($lasthash{$key} eq 'anonsurveycred')) { |
|
$lasthidden{$ign.'.'.$id} = 1; |
|
} |
|
} |
|
if ($identifier ne '') { |
|
my $id = join(',',@parts); |
|
if (&Apache::lonnet::EXT("resource.$id.problemstatus",$symb, |
|
$domain,$username,$usec,undef,$course) =~ /^no/) { |
|
$hidestatus{$ign.'.'.$id} = 1; |
|
} |
|
} |
|
} elsif ($data eq 'regrader') { |
|
if (($identifier ne '') && (@parts)) { |
|
my $id = join(',',@parts); |
|
$regraded{$ign.'.'.$id} = 1; |
|
} |
|
} |
} else { |
} else { |
if ($#parts == 0) { |
if ($#parts == 0) { |
$prevattempts.='<th>'.$parts[0].'</th>'; |
$prevattempts.='<th>'.$parts[0].'</th>'; |
Line 2574 sub get_previous_attempt {
|
Line 4480 sub get_previous_attempt {
|
} |
} |
} |
} |
} |
} |
|
$prevattempts.=&end_data_table_header_row(); |
if ($getattempt eq '') { |
if ($getattempt eq '') { |
|
my (%solved,%resets,%probstatus); |
|
if (($identifier ne '') && (keys(%regraded) > 0)) { |
|
for ($version=1;$version<=$returnhash{'version'};$version++) { |
|
foreach my $id (keys(%regraded)) { |
|
if (($returnhash{$version.':'.$id.'.regrader'}) && |
|
($returnhash{$version.':'.$id.'.tries'} eq '') && |
|
($returnhash{$version.':'.$id.'.award'} eq '')) { |
|
push(@{$resets{$id}},$version); |
|
} |
|
} |
|
} |
|
} |
for ($version=1;$version<=$returnhash{'version'};$version++) { |
for ($version=1;$version<=$returnhash{'version'};$version++) { |
$prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>'; |
my (@hidden,@unsolved); |
foreach my $key (sort(keys(%lasthash))) { |
if (%typeparts) { |
my $value; |
foreach my $id (keys(%typeparts)) { |
if ($key =~ /timestamp/) { |
if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || |
$value=scalar(localtime($returnhash{$version.':'.$key})); |
($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) { |
} else { |
push(@hidden,$id); |
$value=$returnhash{$version.':'.$key}; |
} elsif ($identifier ne '') { |
} |
unless (($returnhash{$version.':'.$id.'.type'} eq 'survey') || |
$prevattempts.='<td>'.&unescape($value).' </td>'; |
($returnhash{$version.':'.$id.'.type'} eq 'surveycred') || |
} |
($hidestatus{$id})) { |
|
next if ((ref($resets{$id}) eq 'ARRAY') && grep(/^\Q$version\E$/,@{$resets{$id}})); |
|
if ($returnhash{$version.':'.$id.'.solved'} eq 'correct_by_student') { |
|
push(@{$solved{$id}},$version); |
|
} elsif (($returnhash{$version.':'.$id.'.solved'} ne '') && |
|
(ref($solved{$id}) eq 'ARRAY')) { |
|
my $skip; |
|
if (ref($resets{$id}) eq 'ARRAY') { |
|
foreach my $reset (@{$resets{$id}}) { |
|
if ($reset > $solved{$id}[-1]) { |
|
$skip=1; |
|
last; |
|
} |
|
} |
|
} |
|
unless ($skip) { |
|
my ($ign,$partslist) = split(/\./,$id,2); |
|
push(@unsolved,$partslist); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
$prevattempts.=&start_data_table_row(). |
|
'<td>'.&mt('Transaction [_1]',$version); |
|
if (@unsolved) { |
|
$prevattempts .= '<span class="LC_nobreak"><label>'. |
|
'<input type="checkbox" name="HIDE'.$identifier.'" value="'.$version.':'.join('_',@unsolved).'" />'. |
|
&mt('Hide').'</label></span>'; |
|
} |
|
$prevattempts .= '</td>'; |
|
if (@hidden) { |
|
foreach my $key (sort(keys(%lasthash))) { |
|
next if ($key =~ /\.foilorder$/); |
|
my $hide; |
|
foreach my $id (@hidden) { |
|
if ($key =~ /^\Q$id\E/) { |
|
$hide = 1; |
|
last; |
|
} |
|
} |
|
if ($hide) { |
|
my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/); |
|
if (($data eq 'award') || ($data eq 'awarddetail')) { |
|
my $value = &format_previous_attempt_value($key, |
|
$returnhash{$version.':'.$key}); |
|
$prevattempts.='<td>'.$value.' </td>'; |
|
} else { |
|
$prevattempts.='<td> </td>'; |
|
} |
|
} else { |
|
if ($key =~ /\./) { |
|
my $value = $returnhash{$version.':'.$key}; |
|
if ($key =~ /\.rndseed$/) { |
|
my ($id) = ($key =~ /^(.+)\.rndseed$/); |
|
if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) { |
|
$value = $returnhash{$version.':'.$id.'.rawrndseed'}; |
|
} |
|
} |
|
$prevattempts.='<td>'.&format_previous_attempt_value($key,$value). |
|
' </td>'; |
|
} else { |
|
$prevattempts.='<td> </td>'; |
|
} |
|
} |
|
} |
|
} else { |
|
foreach my $key (sort(keys(%lasthash))) { |
|
next if ($key =~ /\.foilorder$/); |
|
my $value = $returnhash{$version.':'.$key}; |
|
if ($key =~ /\.rndseed$/) { |
|
my ($id) = ($key =~ /^(.+)\.rndseed$/); |
|
if (exists($returnhash{$version.':'.$id.'.rawrndseed'})) { |
|
$value = $returnhash{$version.':'.$id.'.rawrndseed'}; |
|
} |
|
} |
|
$prevattempts.='<td>'.&format_previous_attempt_value($key,$value). |
|
' </td>'; |
|
} |
|
} |
|
$prevattempts.=&end_data_table_row(); |
} |
} |
} |
} |
$prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>'; |
my @currhidden = keys(%lasthidden); |
|
$prevattempts.=&start_data_table_row().'<td>'.&mt('Current').'</td>'; |
foreach my $key (sort(keys(%lasthash))) { |
foreach my $key (sort(keys(%lasthash))) { |
my $value; |
next if ($key =~ /\.foilorder$/); |
if ($key =~ /timestamp/) { |
if (%typeparts) { |
$value=scalar(localtime($lasthash{$key})); |
my $hidden; |
} else { |
foreach my $id (@currhidden) { |
$value=$lasthash{$key}; |
if ($key =~ /^\Q$id\E/) { |
} |
$hidden = 1; |
$value=&unescape($value); |
last; |
if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} |
} |
$prevattempts.='<td>'.$value.' </td>'; |
} |
|
if ($hidden) { |
|
my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/); |
|
if (($data eq 'award') || ($data eq 'awarddetail')) { |
|
my $value = &format_previous_attempt_value($key,$lasthash{$key}); |
|
if ($key =~/$regexp$/ && (defined &$gradesub)) { |
|
$value = &$gradesub($value); |
|
} |
|
$prevattempts.='<td>'.$value.' </td>'; |
|
} else { |
|
$prevattempts.='<td> </td>'; |
|
} |
|
} else { |
|
my $value = &format_previous_attempt_value($key,$lasthash{$key}); |
|
if ($key =~/$regexp$/ && (defined &$gradesub)) { |
|
$value = &$gradesub($value); |
|
} |
|
$prevattempts.='<td>'.$value.' </td>'; |
|
} |
|
} else { |
|
my $value = &format_previous_attempt_value($key,$lasthash{$key}); |
|
if ($key =~/$regexp$/ && (defined &$gradesub)) { |
|
$value = &$gradesub($value); |
|
} |
|
$prevattempts.='<td>'.$value.' </td>'; |
|
} |
} |
} |
$prevattempts.='</tr></table></td></tr></table>'; |
$prevattempts.= &end_data_table_row().&end_data_table(); |
} else { |
} else { |
$prevattempts='Nothing submitted - no attempts.'; |
my $msg; |
|
if ($symb =~ /ext\.tool$/) { |
|
$msg = &mt('No grade passed back.'); |
|
} else { |
|
$msg = &mt('Nothing submitted - no attempts.'); |
|
} |
|
$prevattempts= |
|
&start_data_table().&start_data_table_row(). |
|
'<td>'.$msg.'</td>'. |
|
&end_data_table_row().&end_data_table(); |
} |
} |
} else { |
} else { |
$prevattempts='No data.'; |
$prevattempts= |
|
&start_data_table().&start_data_table_row(). |
|
'<td>'.&mt('No data.').'</td>'. |
|
&end_data_table_row().&end_data_table(); |
} |
} |
} |
} |
|
|
|
sub format_previous_attempt_value { |
|
my ($key,$value) = @_; |
|
if (($key =~ /timestamp/) || ($key=~/duedate/)) { |
|
$value = &Apache::lonlocal::locallocaltime($value); |
|
} elsif (ref($value) eq 'ARRAY') { |
|
$value = '('.join(', ', @{ $value }).')'; |
|
} elsif ($key =~ /answerstring$/) { |
|
my %answers = &Apache::lonnet::str2hash($value); |
|
my @anskeys = sort(keys(%answers)); |
|
if (@anskeys == 1) { |
|
my $answer = $answers{$anskeys[0]}; |
|
if ($answer =~ m{\0}) { |
|
$answer =~ s{\0}{,}g; |
|
} |
|
my $tag_internal_answer_name = 'INTERNAL'; |
|
if ($anskeys[0] eq $tag_internal_answer_name) { |
|
$value = $answer; |
|
} else { |
|
$value = $anskeys[0].'='.$answer; |
|
} |
|
} else { |
|
foreach my $ans (@anskeys) { |
|
my $answer = $answers{$ans}; |
|
if ($answer =~ m{\0}) { |
|
$answer =~ s{\0}{,}g; |
|
} |
|
$value .= $ans.'='.$answer.'<br />';; |
|
} |
|
} |
|
} else { |
|
$value = &unescape($value); |
|
} |
|
return $value; |
|
} |
|
|
|
|
sub relative_to_absolute { |
sub relative_to_absolute { |
my ($url,$output)=@_; |
my ($url,$output)=@_; |
my $parser=HTML::TokeParser->new(\$output); |
my $parser=HTML::TokeParser->new(\$output); |
Line 2630 sub relative_to_absolute {
|
Line 4704 sub relative_to_absolute {
|
} |
} |
$thisdir=~s-/[^/]*$--; |
$thisdir=~s-/[^/]*$--; |
foreach my $link (@rlinks) { |
foreach my $link (@rlinks) { |
unless (($link=~/^http:\/\//i) || |
unless (($link=~/^https?\:\/\//i) || |
($link=~/^\//) || |
($link=~/^\//) || |
($link=~/^javascript:/i) || |
($link=~/^javascript:/i) || |
($link=~/^mailto:/i) || |
($link=~/^mailto:/i) || |
Line 2646 sub relative_to_absolute {
|
Line 4720 sub relative_to_absolute {
|
|
|
=pod |
=pod |
|
|
=item * get_student_view |
=item * &get_student_view() |
|
|
show a snapshot of what student was looking at |
show a snapshot of what student was looking at |
|
|
Line 2665 sub get_student_view {
|
Line 4739 sub get_student_view {
|
} |
} |
if (defined($target)) { $form{'grade_target'} = $target; } |
if (defined($target)) { $form{'grade_target'} = $target; } |
$feedurl=&Apache::lonnet::clutter($feedurl); |
$feedurl=&Apache::lonnet::clutter($feedurl); |
my $userview=&Apache::lonnet::ssi_body($feedurl,%form); |
my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form); |
$userview=~s/\<body[^\>]*\>//gi; |
$userview=~s/\<body[^\>]*\>//gi; |
$userview=~s/\<\/body\>//gi; |
$userview=~s/\<\/body\>//gi; |
$userview=~s/\<html\>//gi; |
$userview=~s/\<html\>//gi; |
Line 2674 sub get_student_view {
|
Line 4748 sub get_student_view {
|
$userview=~s/\<\/head\>//gi; |
$userview=~s/\<\/head\>//gi; |
$userview=~s/action\s*\=/would_be_action\=/gi; |
$userview=~s/action\s*\=/would_be_action\=/gi; |
$userview=&relative_to_absolute($feedurl,$userview); |
$userview=&relative_to_absolute($feedurl,$userview); |
return $userview; |
if (wantarray) { |
|
return ($userview,$response); |
|
} else { |
|
return $userview; |
|
} |
|
} |
|
|
|
sub get_student_view_with_retries { |
|
my ($symb,$retries,$username,$domain,$courseid,$target,$moreenv) = @_; |
|
|
|
my $ok = 0; # True if we got a good response. |
|
my $content; |
|
my $response; |
|
|
|
# Try to get the student_view done. within the retries count: |
|
|
|
do { |
|
($content, $response) = &get_student_view($symb,$username,$domain,$courseid,$target,$moreenv); |
|
$ok = $response->is_success; |
|
if (!$ok) { |
|
&Apache::lonnet::logthis("Failed get_student_view_with_retries on $symb: ".$response->is_success.', '.$response->code.', '.$response->message); |
|
} |
|
$retries--; |
|
} while (!$ok && ($retries > 0)); |
|
|
|
if (!$ok) { |
|
$content = ''; # On error return an empty content. |
|
} |
|
if (wantarray) { |
|
return ($content, $response); |
|
} else { |
|
return $content; |
|
} |
|
} |
|
|
|
sub css_links { |
|
my ($currsymb,$level) = @_; |
|
my ($links,@symbs,%cssrefs,%httpref); |
|
if ($level eq 'map') { |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (ref($navmap)) { |
|
my ($map,undef,$url)=&Apache::lonnet::decode_symb($currsymb); |
|
my @resources = $navmap->retrieveResources($map,sub { $_[0]->is_problem() },0,0); |
|
foreach my $res (@resources) { |
|
if (ref($res) && $res->symb()) { |
|
push(@symbs,$res->symb()); |
|
} |
|
} |
|
} |
|
} else { |
|
@symbs = ($currsymb); |
|
} |
|
foreach my $symb (@symbs) { |
|
my $css_href = &Apache::lonnet::EXT('resource.0.cssfile',$symb); |
|
if ($css_href =~ /\S/) { |
|
unless ($css_href =~ m{https?://}) { |
|
my $url = (&Apache::lonnet::decode_symb($symb))[-1]; |
|
my $proburl = &Apache::lonnet::clutter($url); |
|
my ($probdir) = ($proburl =~ m{(.+)/[^/]+$}); |
|
unless ($css_href =~ m{^/}) { |
|
$css_href = &Apache::lonnet::hreflocation($probdir,$css_href); |
|
} |
|
if ($css_href =~ m{^/(res|uploaded)/}) { |
|
unless (($httpref{'httpref.'.$css_href}) || |
|
(&Apache::lonnet::is_on_map($css_href))) { |
|
my $thisurl = $proburl; |
|
if ($env{'httpref.'.$proburl}) { |
|
$thisurl = $env{'httpref.'.$proburl}; |
|
} |
|
$httpref{'httpref.'.$css_href} = $thisurl; |
|
} |
|
} |
|
} |
|
$cssrefs{$css_href} = 1; |
|
} |
|
} |
|
if (keys(%httpref)) { |
|
&Apache::lonnet::appenv(\%httpref); |
|
} |
|
if (keys(%cssrefs)) { |
|
foreach my $css_href (keys(%cssrefs)) { |
|
next unless ($css_href =~ m{^(/res/|/uploaded/|https?://)}); |
|
$links .= '<link rel="stylesheet" type="text/css" href="'.$css_href.'" />'."\n"; |
|
} |
|
} |
|
return $links; |
} |
} |
|
|
=pod |
=pod |
|
|
=item * get_student_answers() |
=item * &get_student_answers() |
|
|
show a snapshot of how student was answering problem |
show a snapshot of how student was answering problem |
|
|
Line 2720 sub submlink {
|
Line 4879 sub submlink {
|
} |
} |
if (!$symb) { $symb=&Apache::lonnet::symbread(); } |
if (!$symb) { $symb=&Apache::lonnet::symbread(); } |
$symb=&escape($symb); |
$symb=&escape($symb); |
if ($target) { $target="target=\"$target\""; } |
if ($target) { $target=" target=\"$target\""; } |
return '<a href="/adm/grades?&command=submission&'. |
return |
'symb='.$symb.'&student='.$uname. |
'<a href="/adm/grades?command=submission'. |
'&userdom='.$udom.'" '.$target.'>'.$text.'</a>'; |
'&symb='.$symb. |
|
'&student='.$uname. |
|
'&userdom='.$udom.'"'. |
|
$target.'>'.$text.'</a>'; |
} |
} |
############################################## |
############################################## |
|
|
Line 2767 sub pprmlink {
|
Line 4929 sub pprmlink {
|
if (!$symb) { $symb=&Apache::lonnet::symbread(); } |
if (!$symb) { $symb=&Apache::lonnet::symbread(); } |
$symb=&escape($symb); |
$symb=&escape($symb); |
if ($target) { $target="target=\"$target\""; } |
if ($target) { $target="target=\"$target\""; } |
return '<a href="/adm/parmset?&command=set&'. |
return '<a href="/adm/parmset?command=set&'. |
'symb='.$symb.'&uname='.$uname. |
'symb='.$symb.'&uname='.$uname. |
'&udom='.$udom.'" '.$target.'>'.$text.'</a>'; |
'&udom='.$udom.'" '.$target.'>'.$text.'</a>'; |
} |
} |
############################################## |
############################################## |
|
|
Line 2783 sub pprmlink {
|
Line 4945 sub pprmlink {
|
|
|
|
|
sub timehash { |
sub timehash { |
my @ltime=localtime(shift); |
my ($thistime) = @_; |
return ( 'seconds' => $ltime[0], |
my $timezone = &Apache::lonlocal::gettimezone(); |
'minutes' => $ltime[1], |
my $dt = DateTime->from_epoch(epoch => $thistime) |
'hours' => $ltime[2], |
->set_time_zone($timezone); |
'day' => $ltime[3], |
my $wday = $dt->day_of_week(); |
'month' => $ltime[4]+1, |
if ($wday == 7) { $wday = 0; } |
'year' => $ltime[5]+1900, |
return ( 'second' => $dt->second(), |
'weekday' => $ltime[6], |
'minute' => $dt->minute(), |
'dayyear' => $ltime[7]+1, |
'hour' => $dt->hour(), |
'dlsav' => $ltime[8] ); |
'day' => $dt->day_of_month(), |
|
'month' => $dt->month(), |
|
'year' => $dt->year(), |
|
'weekday' => $wday, |
|
'dayyear' => $dt->day_of_year(), |
|
'dlsav' => $dt->is_dst() ); |
} |
} |
|
|
sub utc_string { |
sub utc_string { |
Line 2802 sub utc_string {
|
Line 4969 sub utc_string {
|
|
|
sub maketime { |
sub maketime { |
my %th=@_; |
my %th=@_; |
|
my ($epoch_time,$timezone,$dt); |
|
$timezone = &Apache::lonlocal::gettimezone(); |
|
eval { |
|
$dt = DateTime->new( year => $th{'year'}, |
|
month => $th{'month'}, |
|
day => $th{'day'}, |
|
hour => $th{'hour'}, |
|
minute => $th{'minute'}, |
|
second => $th{'second'}, |
|
time_zone => $timezone, |
|
); |
|
}; |
|
if (!$@) { |
|
$epoch_time = $dt->epoch; |
|
if ($epoch_time) { |
|
return $epoch_time; |
|
} |
|
} |
return POSIX::mktime( |
return POSIX::mktime( |
($th{'seconds'},$th{'minutes'},$th{'hours'}, |
($th{'seconds'},$th{'minutes'},$th{'hours'}, |
$th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1)); |
$th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1)); |
Line 2826 sub findallcourses {
|
Line 5011 sub findallcourses {
|
if (!%roles) { |
if (!%roles) { |
%roles = ( |
%roles = ( |
cc => 1, |
cc => 1, |
|
co => 1, |
in => 1, |
in => 1, |
ep => 1, |
ep => 1, |
ta => 1, |
ta => 1, |
Line 2846 sub findallcourses {
|
Line 5032 sub findallcourses {
|
if ($tstart) { |
if ($tstart) { |
next if ($tstart > $now); |
next if ($tstart > $now); |
} |
} |
my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec); |
my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role); |
(undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry); |
(undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry); |
|
my $value = $trole.'/'.$cdom.'/'; |
if ($secpart eq '') { |
if ($secpart eq '') { |
($cnum,$role) = split(/_/,$cnumpart); |
($cnum,$role) = split(/_/,$cnumpart); |
$sec = 'none'; |
$sec = 'none'; |
$realsec = ''; |
$value .= $cnum.'/'; |
} else { |
} else { |
$cnum = $cnumpart; |
$cnum = $cnumpart; |
($sec,$role) = split(/_/,$secpart); |
($sec,$role) = split(/_/,$secpart); |
$realsec = $sec; |
$value .= $cnum.'/'.$sec; |
|
} |
|
if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') { |
|
unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) { |
|
push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value); |
|
} |
|
} else { |
|
@{$courses{$cdom.'_'.$cnum}{$sec}} = ($value); |
} |
} |
$courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec; |
|
} |
} |
} else { |
} else { |
foreach my $key (keys(%env)) { |
foreach my $key (keys(%env)) { |
Line 2875 sub findallcourses {
|
Line 5068 sub findallcourses {
|
if ($now>$endtime) { $active=0; } |
if ($now>$endtime) { $active=0; } |
} |
} |
if ($active) { |
if ($active) { |
|
my $value = $role.'/'.$cdom.'/'.$cnum.'/'; |
if ($sec eq '') { |
if ($sec eq '') { |
$sec = 'none'; |
$sec = 'none'; |
|
} else { |
|
$value .= $sec; |
|
} |
|
if (ref($courses{$cdom.'_'.$cnum}{$sec}) eq 'ARRAY') { |
|
unless (grep(/^\Q$value\E$/,@{$courses{$cdom.'_'.$cnum}{$sec}})) { |
|
push(@{$courses{$cdom.'_'.$cnum}{$sec}},$value); |
|
} |
|
} else { |
|
@{$courses{$cdom.'_'.$cnum}{$sec}} = ($value); |
} |
} |
$courses{$cdom.'_'.$cnum}{$sec} = |
|
$role.'/'.$cdom.'/'.$cnum.'/'.$sec; |
|
} |
} |
} |
} |
} |
} |
Line 2890 sub findallcourses {
|
Line 5091 sub findallcourses {
|
############################################### |
############################################### |
|
|
sub blockcheck { |
sub blockcheck { |
my ($setters,$activity,$uname,$udom) = @_; |
my ($setters,$activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller) = @_; |
|
|
if (!defined($udom)) { |
unless (($activity eq 'docs') || ($activity eq 'reinit') || ($activity eq 'alert')) { |
$udom = $env{'user.domain'}; |
my ($has_evb,$check_ipaccess); |
|
my $dom = $env{'user.domain'}; |
|
if ($env{'request.course.id'}) { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $checkrole = "cm./$cdom/$cnum"; |
|
my $sec = $env{'request.course.sec'}; |
|
if ($sec ne '') { |
|
$checkrole .= "/$sec"; |
|
} |
|
if ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && |
|
($env{'request.role'} !~ /^st/)) { |
|
$has_evb = 1; |
|
} |
|
unless ($has_evb) { |
|
if (($activity eq 'printout') || ($activity eq 'grades') || ($activity eq 'search') || |
|
($activity eq 'boards') || ($activity eq 'groups') || ($activity eq 'chat')) { |
|
if ($udom eq $cdom) { |
|
$check_ipaccess = 1; |
|
} |
|
} |
|
} |
|
} elsif (($activity eq 'com') || ($activity eq 'port') || ($activity eq 'blogs') || |
|
($activity eq 'about') || ($activity eq 'wishlist') || ($activity eq 'passwd')) { |
|
my $checkrole; |
|
if ($env{'request.role.domain'} eq '') { |
|
$checkrole = "cm./$env{'user.domain'}/"; |
|
} else { |
|
$checkrole = "cm./$env{'request.role.domain'}/"; |
|
} |
|
if (($checkrole) && (&Apache::lonnet::allowed('evb',undef,undef,$checkrole))) { |
|
$has_evb = 1; |
|
} |
|
} |
|
unless ($has_evb || $check_ipaccess) { |
|
my @machinedoms = &Apache::lonnet::current_machine_domains(); |
|
if (($dom eq 'public') && ($activity eq 'port')) { |
|
$dom = $udom; |
|
} |
|
if (($dom ne '') && (grep(/^\Q$dom\E$/,@machinedoms))) { |
|
$check_ipaccess = 1; |
|
} else { |
|
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; |
|
my $internet_names = &Apache::lonnet::get_internet_names($lonhost); |
|
my $prim = &Apache::lonnet::domain($dom,'primary'); |
|
my $intdom = &Apache::lonnet::internet_dom($prim); |
|
if (($intdom ne '') && (ref($internet_names) eq 'ARRAY')) { |
|
if (grep(/^\Q$intdom\E$/,@{$internet_names})) { |
|
$check_ipaccess = 1; |
|
} |
|
} |
|
} |
|
} |
|
if ($check_ipaccess) { |
|
my ($ipaccessref,$cached)=&Apache::lonnet::is_cached_new('ipaccess',$dom); |
|
unless (defined($cached)) { |
|
my %domconfig = |
|
&Apache::lonnet::get_dom('configuration',['ipaccess'],$dom); |
|
$ipaccessref = &Apache::lonnet::do_cache_new('ipaccess',$dom,$domconfig{'ipaccess'},1800); |
|
} |
|
if ((ref($ipaccessref) eq 'HASH') && ($clientip)) { |
|
foreach my $id (keys(%{$ipaccessref})) { |
|
if (ref($ipaccessref->{$id}) eq 'HASH') { |
|
my $range = $ipaccessref->{$id}->{'ip'}; |
|
if ($range) { |
|
if (&Apache::lonnet::ip_match($clientip,$range)) { |
|
if (ref($ipaccessref->{$id}->{'commblocks'}) eq 'HASH') { |
|
if ($ipaccessref->{$id}->{'commblocks'}->{$activity} eq 'on') { |
|
return ('','','',$id,$dom); |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if (($activity eq 'wishlist') || ($activity eq 'annotate')) { |
|
return (); |
|
} |
} |
} |
if (!defined($uname)) { |
if (defined($udom) && defined($uname)) { |
|
# If uname and udom are for a course, check for blocks in the course. |
|
if (($is_course) || (&Apache::lonnet::is_course($udom,$uname))) { |
|
my ($startblock,$endblock,$triggerblock) = |
|
&get_blocks($setters,$activity,$udom,$uname,$url,$symb,$caller); |
|
return ($startblock,$endblock,$triggerblock); |
|
} |
|
} else { |
|
$udom = $env{'user.domain'}; |
$uname = $env{'user.name'}; |
$uname = $env{'user.name'}; |
} |
} |
|
|
# If uname and udom are for a course, check for blocks in the course. |
|
|
|
if (&Apache::lonnet::is_course($udom,$uname)) { |
|
my %records = &Apache::lonnet::dump('comm_block',$udom,$uname); |
|
my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname); |
|
return ($startblock,$endblock); |
|
} |
|
|
|
my $startblock = 0; |
my $startblock = 0; |
my $endblock = 0; |
my $endblock = 0; |
my %live_courses = &findallcourses(undef,$uname,$udom); |
my $triggerblock = ''; |
|
my %live_courses; |
|
unless (($activity eq 'wishlist') || ($activity eq 'annotate')) { |
|
%live_courses = &findallcourses(undef,$uname,$udom); |
|
} |
|
|
# If uname is for a user, and activity is course-specific, i.e., |
# If uname is for a user, and activity is course-specific, i.e., |
# boards, chat or groups, check for blocking in current course only. |
# boards, chat or groups, check for blocking in current course only. |
|
|
if (($activity eq 'boards' || $activity eq 'chat' || |
if (($activity eq 'boards' || $activity eq 'chat' || |
$activity eq 'groups') && ($env{'request.course.id'})) { |
$activity eq 'groups' || $activity eq 'printout' || |
|
$activity eq 'search' || $activity eq 'reinit' || |
|
$activity eq 'alert') && ($env{'request.course.id'})) { |
foreach my $key (keys(%live_courses)) { |
foreach my $key (keys(%live_courses)) { |
if ($key ne $env{'request.course.id'}) { |
if ($key ne $env{'request.course.id'}) { |
delete($live_courses{$key}); |
delete($live_courses{$key}); |
Line 2972 sub blockcheck {
|
Line 5259 sub blockcheck {
|
if ($otheruser) { |
if ($otheruser) { |
# Resource belongs to user other than current user. |
# Resource belongs to user other than current user. |
# Assemble privs for that user, and check for 'evb' priv. |
# Assemble privs for that user, and check for 'evb' priv. |
my ($trole,$tdom,$tnum,$tsec); |
my (%allroles,%userroles); |
my $entry = $live_courses{$course}{$sec}; |
if (ref($live_courses{$course}{$sec}) eq 'ARRAY') { |
if ($entry =~ /^cr/) { |
foreach my $entry (@{$live_courses{$course}{$sec}}) { |
($trole,$tdom,$tnum,$tsec) = |
my ($trole,$tdom,$tnum,$tsec); |
($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|); |
if ($entry =~ /^cr/) { |
} else { |
($trole,$tdom,$tnum,$tsec) = |
($trole,$tdom,$tnum,$tsec) = split(/\//,$entry); |
($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|); |
} |
} else { |
my ($spec,$area,$trest,%allroles,%userroles); |
($trole,$tdom,$tnum,$tsec) = split(/\//,$entry); |
$area = '/'.$tdom.'/'.$tnum; |
} |
$trest = $tnum; |
my ($spec,$area,$trest); |
if ($tsec ne '') { |
$area = '/'.$tdom.'/'.$tnum; |
$area .= '/'.$tsec; |
$trest = $tnum; |
$trest .= '/'.$tsec; |
if ($tsec ne '') { |
} |
$area .= '/'.$tsec; |
$spec = $trole.'.'.$area; |
$trest .= '/'.$tsec; |
if ($trole =~ /^cr/) { |
} |
&Apache::lonnet::custom_roleprivs(\%allroles,$trole, |
$spec = $trole.'.'.$area; |
$tdom,$spec,$trest,$area); |
if ($trole =~ /^cr/) { |
} else { |
&Apache::lonnet::custom_roleprivs(\%allroles,$trole, |
&Apache::lonnet::standard_roleprivs(\%allroles,$trole, |
$tdom,$spec,$trest,$area); |
$tdom,$spec,$trest,$area); |
} else { |
} |
&Apache::lonnet::standard_roleprivs(\%allroles,$trole, |
my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles); |
$tdom,$spec,$trest,$area); |
if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) { |
} |
if ($1) { |
} |
$no_userblock = 1; |
my ($author,$adv,$rar) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles); |
last; |
if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) { |
|
if ($1) { |
|
$no_userblock = 1; |
|
last; |
|
} |
} |
} |
} |
} |
} else { |
} else { |
Line 3019 sub blockcheck {
|
Line 5310 sub blockcheck {
|
# Retrieve blocking times and identity of blocker for course |
# Retrieve blocking times and identity of blocker for course |
# of specified user, unless user has 'evb' privilege. |
# of specified user, unless user has 'evb' privilege. |
|
|
my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum); |
my ($start,$end,$trigger) = |
|
&get_blocks($setters,$activity,$cdom,$cnum,$url,$symb,$caller); |
if (($start != 0) && |
if (($start != 0) && |
(($startblock == 0) || ($startblock > $start))) { |
(($startblock == 0) || ($startblock > $start))) { |
$startblock = $start; |
$startblock = $start; |
|
if ($trigger ne '') { |
|
$triggerblock = $trigger; |
|
} |
} |
} |
if (($end != 0) && |
if (($end != 0) && |
(($endblock == 0) || ($endblock < $end))) { |
(($endblock == 0) || ($endblock < $end))) { |
$endblock = $end; |
$endblock = $end; |
|
if ($trigger ne '') { |
|
$triggerblock = $trigger; |
|
} |
} |
} |
} |
} |
return ($startblock,$endblock); |
return ($startblock,$endblock,$triggerblock); |
} |
} |
|
|
sub get_blocks { |
sub get_blocks { |
my ($setters,$activity,$cdom,$cnum) = @_; |
my ($setters,$activity,$cdom,$cnum,$url,$symb,$caller) = @_; |
my $startblock = 0; |
my $startblock = 0; |
my $endblock = 0; |
my $endblock = 0; |
|
my $triggerblock = ''; |
my $course = $cdom.'_'.$cnum; |
my $course = $cdom.'_'.$cnum; |
$setters->{$course} = {}; |
$setters->{$course} = {}; |
$setters->{$course}{'staff'} = []; |
$setters->{$course}{'staff'} = []; |
$setters->{$course}{'times'} = []; |
$setters->{$course}{'times'} = []; |
my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum); |
$setters->{$course}{'triggers'} = []; |
foreach my $record (keys(%records)) { |
my (@blockers,%triggered); |
my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/); |
my $now = time; |
if ($start <= time && $end >= time) { |
my %commblocks = &Apache::lonnet::get_comm_blocks($cdom,$cnum); |
my ($staff_name,$staff_dom,$title,$blocks) = |
if ($activity eq 'docs') { |
&parse_block_record($records{$record}); |
my ($blocked,$nosymbcache,$noenccheck); |
if ($blocks->{$activity} eq 'on') { |
if (($caller eq 'blockedaccess') || ($caller eq 'blockingstatus')) { |
push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]); |
$blocked = 1; |
push(@{$$setters{$course}{'times'}}, [$start,$end]); |
$nosymbcache = 1; |
if ( ($startblock == 0) || ($startblock > $start) ) { |
$noenccheck = 1; |
$startblock = $start; |
} |
|
@blockers = &Apache::lonnet::has_comm_blocking('bre',$symb,$url,$nosymbcache,$noenccheck,$blocked,\%commblocks); |
|
foreach my $block (@blockers) { |
|
if ($block =~ /^firstaccess____(.+)$/) { |
|
my $item = $1; |
|
my $type = 'map'; |
|
my $timersymb = $item; |
|
if ($item eq 'course') { |
|
$type = 'course'; |
|
} elsif ($item =~ /___\d+___/) { |
|
$type = 'resource'; |
|
} else { |
|
$timersymb = &Apache::lonnet::symbread($item); |
|
} |
|
my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb}; |
|
my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb}; |
|
$triggered{$block} = { |
|
start => $start, |
|
end => $end, |
|
type => $type, |
|
}; |
|
} |
|
} |
|
} else { |
|
foreach my $block (keys(%commblocks)) { |
|
if ($block =~ m/^(\d+)____(\d+)$/) { |
|
my ($start,$end) = ($1,$2); |
|
if ($start <= time && $end >= time) { |
|
if (ref($commblocks{$block}) eq 'HASH') { |
|
if (ref($commblocks{$block}{'blocks'}) eq 'HASH') { |
|
if ($commblocks{$block}{'blocks'}{$activity} eq 'on') { |
|
unless(grep(/^\Q$block\E$/,@blockers)) { |
|
push(@blockers,$block); |
|
} |
|
} |
|
} |
|
} |
} |
} |
if ( ($endblock == 0) || ($endblock < $end) ) { |
} elsif ($block =~ /^firstaccess____(.+)$/) { |
$endblock = $end; |
my $item = $1; |
|
my $timersymb = $item; |
|
my $type = 'map'; |
|
if ($item eq 'course') { |
|
$type = 'course'; |
|
} elsif ($item =~ /___\d+___/) { |
|
$type = 'resource'; |
|
} else { |
|
$timersymb = &Apache::lonnet::symbread($item); |
|
} |
|
my $start = $env{'course.'.$cdom.'_'.$cnum.'.firstaccess.'.$timersymb}; |
|
my $end = $start + $env{'course.'.$cdom.'_'.$cnum.'.timerinterval.'.$timersymb}; |
|
if ($start && $end) { |
|
if (($start <= time) && ($end >= time)) { |
|
if (ref($commblocks{$block}) eq 'HASH') { |
|
if (ref($commblocks{$block}{'blocks'}) eq 'HASH') { |
|
if ($commblocks{$block}{'blocks'}{$activity} eq 'on') { |
|
unless(grep(/^\Q$block\E$/,@blockers)) { |
|
push(@blockers,$block); |
|
$triggered{$block} = { |
|
start => $start, |
|
end => $end, |
|
type => $type, |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
} |
} |
} |
} |
} |
} |
} |
} |
} |
return ($startblock,$endblock); |
foreach my $blocker (@blockers) { |
|
my ($staff_name,$staff_dom,$title,$blocks) = |
|
&parse_block_record($commblocks{$blocker}); |
|
push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]); |
|
my ($start,$end,$triggertype); |
|
if ($blocker =~ m/^(\d+)____(\d+)$/) { |
|
($start,$end) = ($1,$2); |
|
} elsif (ref($triggered{$blocker}) eq 'HASH') { |
|
$start = $triggered{$blocker}{'start'}; |
|
$end = $triggered{$blocker}{'end'}; |
|
$triggertype = $triggered{$blocker}{'type'}; |
|
} |
|
if ($start) { |
|
push(@{$$setters{$course}{'times'}}, [$start,$end]); |
|
if ($triggertype) { |
|
push(@{$$setters{$course}{'triggers'}},$triggertype); |
|
} else { |
|
push(@{$$setters{$course}{'triggers'}},0); |
|
} |
|
if ( ($startblock == 0) || ($startblock > $start) ) { |
|
$startblock = $start; |
|
if ($triggertype) { |
|
$triggerblock = $blocker; |
|
} |
|
} |
|
if ( ($endblock == 0) || ($endblock < $end) ) { |
|
$endblock = $end; |
|
if ($triggertype) { |
|
$triggerblock = $blocker; |
|
} |
|
} |
|
} |
|
} |
|
return ($startblock,$endblock,$triggerblock); |
} |
} |
|
|
sub parse_block_record { |
sub parse_block_record { |
Line 3081 sub parse_block_record {
|
Line 5477 sub parse_block_record {
|
return ($setuname,$setudom,$title,$blocks); |
return ($setuname,$setudom,$title,$blocks); |
} |
} |
|
|
sub build_block_table { |
sub blocking_status { |
my ($startblock,$endblock,$setters) = @_; |
my ($activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller) = @_; |
my %lt = &Apache::lonlocal::texthash( |
my %setters; |
'cacb' => 'Currently active communication blocks', |
|
'cour' => 'Course', |
# check for active blocking |
'dura' => 'Duration', |
if ($clientip eq '') { |
'blse' => 'Block set by' |
$clientip = &Apache::lonnet::get_requestor_ip(); |
); |
} |
my $output; |
my ($startblock,$endblock,$triggerblock,$by_ip,$blockdom) = |
$output = '<br />'.$lt{'cacb'}.':<br />'; |
&blockcheck(\%setters,$activity,$clientip,$uname,$udom,$url,$is_course,$symb,$caller); |
$output .= &start_data_table(); |
my $blocked = 0; |
$output .= ' |
if (($startblock && $endblock) || ($by_ip)) { |
<tr> |
$blocked = 1; |
<th>'.$lt{'cour'}.'</th> |
} |
<th>'.$lt{'dura'}.'</th> |
|
<th>'.$lt{'blse'}.'</th> |
# caller just wants to know whether a block is active |
</tr> |
if (!wantarray) { return $blocked; } |
'; |
|
foreach my $course (keys(%{$setters})) { |
# build a link to a popup window containing the details |
my %courseinfo=&Apache::lonnet::coursedescription($course); |
my $querystring = "?activity=$activity"; |
for (my $i=0; $i<@{$$setters{$course}{staff}}; $i++) { |
# $uname and $udom decide whose portfolio (or information page) the user is trying to look at |
my ($uname,$udom) = @{$$setters{$course}{staff}[$i]}; |
if (($activity eq 'port') || ($activity eq 'about') || ($activity eq 'passwd')) { |
my $fullname = &plainname($uname,$udom); |
$querystring .= "&udom=$udom" if ($udom =~ /^$match_domain$/); |
if (defined($env{'user.name'}) && defined($env{'user.domain'}) |
$querystring .= "&uname=$uname" if ($uname =~ /^$match_username$/); |
&& $env{'user.name'} ne 'public' |
} elsif ($activity eq 'docs') { |
&& $env{'user.domain'} ne 'public') { |
my $showurl = &Apache::lonenc::check_encrypt($url); |
$fullname = &aboutmewrapper($fullname,$uname,$udom); |
$querystring .= '&url='.&HTML::Entities::encode($showurl,'\'&"<>'); |
} |
if ($symb) { |
my ($openblock,$closeblock) = @{$$setters{$course}{times}[$i]}; |
my $showsymb = &Apache::lonenc::check_encrypt($symb); |
$openblock = &Apache::lonlocal::locallocaltime($openblock); |
$querystring .= '&symb='.&HTML::Entities::encode($showsymb,'\'&"<>'); |
$closeblock= &Apache::lonlocal::locallocaltime($closeblock); |
|
$output .= &Apache::loncommon::start_data_table_row(). |
|
'<td>'.$courseinfo{'description'}.'</td>'. |
|
'<td>'.$openblock.' to '.$closeblock.'</td>'. |
|
'<td>'.$fullname.'</td>'. |
|
&Apache::loncommon::end_data_table_row(); |
|
} |
} |
} |
} |
$output .= &end_data_table(); |
|
|
my $output .= <<'END_MYBLOCK'; |
|
function openWindow(url, wdwName, w, h, toolbar,scrollbar) { |
|
var options = "width=" + w + ",height=" + h + ","; |
|
options += "resizable=yes,scrollbars="+scrollbar+",status=no,"; |
|
options += "menubar=no,toolbar="+toolbar+",location=no,directories=no"; |
|
var newWin = window.open(url, wdwName, options); |
|
newWin.focus(); |
|
} |
|
END_MYBLOCK |
|
|
|
$output = Apache::lonhtmlcommon::scripttag($output); |
|
|
|
my $popupUrl = "/adm/blockingstatus/$querystring"; |
|
my $text = &mt('Communication Blocked'); |
|
my $class = 'LC_comblock'; |
|
if ($activity eq 'docs') { |
|
$text = &mt('Content Access Blocked'); |
|
$class = ''; |
|
} elsif ($activity eq 'printout') { |
|
$text = &mt('Printing Blocked'); |
|
} elsif ($activity eq 'passwd') { |
|
$text = &mt('Password Changing Blocked'); |
|
} elsif ($activity eq 'grades') { |
|
$text = &mt('Gradebook Blocked'); |
|
} elsif ($activity eq 'search') { |
|
$text = &mt('Search Blocked'); |
|
} elsif ($activity eq 'alert') { |
|
$text = &mt('Checking Critical Messages Blocked'); |
|
} elsif ($activity eq 'reinit') { |
|
$text = &mt('Checking Course Update Blocked'); |
|
} elsif ($activity eq 'about') { |
|
$text = &mt('Access to User Information Pages Blocked'); |
|
} elsif ($activity eq 'wishlist') { |
|
$text = &mt('Access to Stored Links Blocked'); |
|
} elsif ($activity eq 'annotate') { |
|
$text = &mt('Access to Annotations Blocked'); |
|
} |
|
$output .= <<"END_BLOCK"; |
|
<div class='$class'> |
|
<a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring' |
|
title='$text'> |
|
<img class='LC_noBorder LC_middle' title='$text' src='/res/adm/pages/comblock.png' alt='$text'/></a> |
|
<a onclick='openWindow("$popupUrl","Blocking Table",600,300,"no","no");return false;' href='/adm/blockingstatus/$querystring' |
|
title='$text'>$text</a> |
|
</div> |
|
|
|
END_BLOCK |
|
|
|
return ($blocked, $output); |
} |
} |
|
|
sub blocking_status { |
############################################### |
my ($activity,$uname,$udom) = @_; |
|
my %setters; |
sub check_ip_acc { |
my ($blocked,$output,$ownitem,$is_course); |
my ($acc,$clientip)=@_; |
my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom); |
&Apache::lonxml::debug("acc is $acc"); |
if ($startblock && $endblock) { |
if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) { |
$blocked = 1; |
return 1; |
if (wantarray) { |
} |
my $category; |
my $allowed=0; |
if ($activity eq 'boards') { |
my $ip; |
$category = 'Discussion posts in this course'; |
if (($ENV{'REMOTE_ADDR'} eq '127.0.0.1') || |
} elsif ($activity eq 'blogs') { |
($ENV{'REMOTE_ADDR'} eq &Apache::lonnet::get_host_ip($Apache::lonnet::perlvar{'lonHostID'}))) { |
$category = 'Blogs'; |
$ip = $env{'request.host'} || $ENV{'REMOTE_ADDR'} || $clientip; |
} elsif ($activity eq 'port') { |
} else { |
if (defined($uname) && defined($udom)) { |
my $remote_ip = &Apache::lonnet::get_requestor_ip(); |
if ($uname eq $env{'user.name'} && |
$ip = $remote_ip || $env{'request.host'} || $clientip; |
$udom eq $env{'user.domain'}) { |
} |
$ownitem = 1; |
|
} |
my $name; |
} |
my %access = ( |
$is_course = &Apache::lonnet::is_course($udom,$uname); |
allowfrom => 1, |
if ($ownitem) { |
denyfrom => 0, |
$category = 'Your portfolio files'; |
); |
} elsif ($is_course) { |
my @allows; |
my $coursedesc; |
my @denies; |
foreach my $course (keys(%setters)) { |
foreach my $item (split(',',$acc)) { |
my %courseinfo = |
$item =~ s/^\s*//; |
&Apache::lonnet::coursedescription($course); |
$item =~ s/\s*$//; |
$coursedesc = $courseinfo{'description'}; |
if ($item =~ /^\!(.+)$/) { |
} |
push(@denies,$1); |
$category = "Group files in the course '$coursedesc'"; |
} else { |
} else { |
push(@allows,$item); |
$category = 'Portfolio files belonging to '; |
} |
if ($env{'user.name'} eq 'public' && |
} |
$env{'user.domain'} eq 'public') { |
my $numdenies = scalar(@denies); |
$category .= &plainname($uname,$udom); |
my $numallows = scalar(@allows); |
} else { |
my $count = 0; |
$category .= &aboutmewrapper(&plainname($uname,$udom),$uname,$udom); |
foreach my $pattern (@denies,@allows) { |
} |
$count ++; |
} |
my $acctype = 'allowfrom'; |
} elsif ($activity eq 'groups') { |
if ($count <= $numdenies) { |
$category = 'Groups in this course'; |
$acctype = 'denyfrom'; |
|
} |
|
if ($pattern =~ /\*$/) { |
|
#35.8.* |
|
$pattern=~s/\*//; |
|
if ($ip =~ /^\Q$pattern\E/) { $allowed=$access{$acctype}; } |
|
} elsif ($pattern =~ /(\d+\.\d+\.\d+)\.\[(\d+)-(\d+)\]$/) { |
|
#35.8.3.[34-56] |
|
my $low=$2; |
|
my $high=$3; |
|
$pattern=$1; |
|
if ($ip =~ /^\Q$pattern\E/) { |
|
my $last=(split(/\./,$ip))[3]; |
|
if ($last <=$high && $last >=$low) { $allowed=$access{$acctype}; } |
|
} |
|
} elsif ($pattern =~ /^\*/) { |
|
#*.msu.edu |
|
$pattern=~s/\*//; |
|
if (!defined($name)) { |
|
use Socket; |
|
my $netaddr=inet_aton($ip); |
|
($name)=gethostbyaddr($netaddr,AF_INET); |
} |
} |
my $showstart = &Apache::lonlocal::locallocaltime($startblock); |
if ($name =~ /\Q$pattern\E$/i) { $allowed=$access{$acctype}; } |
my $showend = &Apache::lonlocal::locallocaltime($endblock); |
} elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) { |
$output = '<br />'.&mt('[_1] will be inaccessible between [_2] and [_3] because communication is being blocked.',$category,$showstart,$showend).'<br />'; |
#127.0.0.1 |
if (!($activity eq 'port' && !($ownitem) && !($is_course))) { |
if ($ip =~ /^\Q$pattern\E/) { $allowed=$access{$acctype}; } |
$output .= &build_block_table($startblock,$endblock,\%setters); |
} else { |
|
#some.name.com |
|
if (!defined($name)) { |
|
use Socket; |
|
my $netaddr=inet_aton($ip); |
|
($name)=gethostbyaddr($netaddr,AF_INET); |
} |
} |
|
if ($name =~ /\Q$pattern\E$/i) { $allowed=$access{$acctype}; } |
} |
} |
|
if ($allowed =~ /^(0|1)$/) { last; } |
} |
} |
if (wantarray) { |
if ($allowed eq '') { |
return ($blocked,$output); |
if ($numdenies && !$numallows) { |
} else { |
$allowed = 1; |
return $blocked; |
} else { |
|
$allowed = 0; |
|
} |
} |
} |
|
return $allowed; |
} |
} |
|
|
############################################### |
############################################### |
Line 3201 sub determinedomain {
|
Line 5671 sub determinedomain {
|
my $domain=shift; |
my $domain=shift; |
if (! $domain) { |
if (! $domain) { |
# Determine domain if we have not been given one |
# Determine domain if we have not been given one |
$domain = $Apache::lonnet::perlvar{'lonDefDomain'}; |
$domain = &Apache::lonnet::default_login_domain(); |
if ($env{'user.domain'}) { $domain=$env{'user.domain'}; } |
if ($env{'user.domain'}) { $domain=$env{'user.domain'}; } |
if ($env{'request.role.domain'}) { |
if ($env{'request.role.domain'}) { |
$domain=$env{'request.role.domain'}; |
$domain=$env{'request.role.domain'}; |
Line 3224 sub get_domainconf {
|
Line 5694 sub get_domainconf {
|
if (defined($cached)) { return %{$result}; } |
if (defined($cached)) { return %{$result}; } |
|
|
my %domconfig = &Apache::lonnet::get_dom('configuration', |
my %domconfig = &Apache::lonnet::get_dom('configuration', |
['login','rolecolors'],$udom); |
['login','rolecolors','autoenroll'],$udom); |
my %designhash; |
my (%designhash,%legacy); |
if (keys(%domconfig) > 0) { |
if (keys(%domconfig) > 0) { |
if (ref($domconfig{'login'}) eq 'HASH') { |
if (ref($domconfig{'login'}) eq 'HASH') { |
foreach my $key (keys(%{$domconfig{'login'}})) { |
if (keys(%{$domconfig{'login'}})) { |
$designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key}; |
foreach my $key (keys(%{$domconfig{'login'}})) { |
|
if (ref($domconfig{'login'}{$key}) eq 'HASH') { |
|
if (($key eq 'loginvia') || ($key eq 'headtag')) { |
|
if (ref($domconfig{'login'}{$key}) eq 'HASH') { |
|
foreach my $hostname (keys(%{$domconfig{'login'}{$key}})) { |
|
if (ref($domconfig{'login'}{$key}{$hostname}) eq 'HASH') { |
|
if ($key eq 'loginvia') { |
|
if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) { |
|
my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'}; |
|
$designhash{$udom.'.login.loginvia'} = $server; |
|
if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') { |
|
$designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'}; |
|
} else { |
|
$designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'}; |
|
} |
|
} |
|
} elsif ($key eq 'headtag') { |
|
if ($domconfig{'login'}{'headtag'}{$hostname}{'url'}) { |
|
$designhash{$udom.'.login.headtag_'.$hostname} = $domconfig{'login'}{'headtag'}{$hostname}{'url'}; |
|
} |
|
} |
|
if ($domconfig{'login'}{$key}{$hostname}{'exempt'}) { |
|
$designhash{$udom.'.login.'.$key.'_exempt_'.$hostname} = $domconfig{'login'}{$key}{$hostname}{'exempt'}; |
|
} |
|
} |
|
} |
|
} |
|
} elsif ($key eq 'saml') { |
|
if (ref($domconfig{'login'}{$key}) eq 'HASH') { |
|
foreach my $host (keys(%{$domconfig{'login'}{$key}})) { |
|
if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') { |
|
$designhash{$udom.'.login.'.$key.'_'.$host} = 1; |
|
foreach my $item ('text','img','alt','url','title','window','notsso') { |
|
$designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item}; |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
foreach my $img (keys(%{$domconfig{'login'}{$key}})) { |
|
$designhash{$udom.'.login.'.$key.'_'.$img} = |
|
$domconfig{'login'}{$key}{$img}; |
|
} |
|
} |
|
} else { |
|
$designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key}; |
|
} |
|
} |
|
} else { |
|
$legacy{'login'} = 1; |
} |
} |
|
} else { |
|
$legacy{'login'} = 1; |
} |
} |
if (ref($domconfig{'rolecolors'}) eq 'HASH') { |
if (ref($domconfig{'rolecolors'}) eq 'HASH') { |
foreach my $role (keys(%{$domconfig{'rolecolors'}})) { |
if (keys(%{$domconfig{'rolecolors'}})) { |
if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') { |
foreach my $role (keys(%{$domconfig{'rolecolors'}})) { |
foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) { |
if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') { |
$designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item}; |
foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) { |
|
$designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item}; |
|
} |
} |
} |
} |
} |
|
} else { |
|
$legacy{'rolecolors'} = 1; |
} |
} |
|
} else { |
|
$legacy{'rolecolors'} = 1; |
} |
} |
} else { |
if (ref($domconfig{'autoenroll'}) eq 'HASH') { |
my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; |
if ($domconfig{'autoenroll'}{'co-owners'}) { |
my $designfile = $designdir.'/'.$udom.'.tab'; |
$designhash{$udom.'.autoassign.co-owners'}=$domconfig{'autoenroll'}{'co-owners'}; |
if (-e $designfile) { |
|
if ( open (my $fh,"<$designfile") ) { |
|
while (my $line = <$fh>) { |
|
next if ($line =~ /^\#/); |
|
chomp($line); |
|
my ($key,$val)=(split(/\=/,$line)); |
|
if ($val) { $designhash{$udom.'.'.$key}=$val; } |
|
} |
|
close($fh); |
|
} |
} |
} |
} |
if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') { |
if (keys(%legacy) > 0) { |
$designhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif"; |
my %legacyhash = &get_legacy_domconf($udom); |
|
foreach my $item (keys(%legacyhash)) { |
|
if ($item =~ /^\Q$udom\E\.login/) { |
|
if ($legacy{'login'}) { |
|
$designhash{$item} = $legacyhash{$item}; |
|
} |
|
} else { |
|
if ($legacy{'rolecolors'}) { |
|
$designhash{$item} = $legacyhash{$item}; |
|
} |
|
} |
|
} |
} |
} |
|
} else { |
|
%designhash = &get_legacy_domconf($udom); |
} |
} |
&Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash, |
&Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash, |
$cachetime); |
$cachetime); |
return %designhash; |
return %designhash; |
} |
} |
|
|
|
sub get_legacy_domconf { |
|
my ($udom) = @_; |
|
my %legacyhash; |
|
my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; |
|
my $designfile = $designdir.'/'.$udom.'.tab'; |
|
if (-e $designfile) { |
|
if ( open (my $fh,'<',$designfile) ) { |
|
while (my $line = <$fh>) { |
|
next if ($line =~ /^\#/); |
|
chomp($line); |
|
my ($key,$val)=(split(/\=/,$line)); |
|
if ($val) { $legacyhash{$udom.'.'.$key}=$val; } |
|
} |
|
close($fh); |
|
} |
|
} |
|
if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/adm/lonDomLogos/'.$udom.'.gif') { |
|
$legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif"; |
|
} |
|
return %legacyhash; |
|
} |
|
|
=pod |
=pod |
|
|
=item * &domainlogo() |
=item * &domainlogo() |
Line 3288 sub domainlogo {
|
Line 5841 sub domainlogo {
|
&Apache::lonnet::repcopy($local_name); |
&Apache::lonnet::repcopy($local_name); |
} |
} |
$imgsrc = &lonhttpdurl($imgsrc); |
$imgsrc = &lonhttpdurl($imgsrc); |
} |
} |
return '<img src="'.$imgsrc.'" alt="'.$domain.'" />'; |
my $alttext = $domain; |
|
if ($designhash{$domain.'.login.alttext_domlogo'} ne '') { |
|
$alttext = $designhash{$domain.'.login.alttext_domlogo'}; |
|
} |
|
return '<img src="'.$imgsrc.'" alt="'.$alttext.'" id="lclogindomlogo" />'; |
} elsif (defined(&Apache::lonnet::domain($domain,'description'))) { |
} elsif (defined(&Apache::lonnet::domain($domain,'description'))) { |
return &Apache::lonnet::domain($domain,'description'); |
return &Apache::lonnet::domain($domain,'description'); |
} else { |
} else { |
Line 3312 Returns: value of designparamter $which
|
Line 5869 Returns: value of designparamter $which
|
############################################## |
############################################## |
sub designparm { |
sub designparm { |
my ($which,$domain)=@_; |
my ($which,$domain)=@_; |
if ($env{'browser.blackwhite'} eq 'on') { |
|
if ($which=~/\.(font|alink|vlink|link)$/) { |
|
return '#000000'; |
|
} |
|
if ($which=~/\.(pgbg|sidebg)$/) { |
|
return '#FFFFFF'; |
|
} |
|
if ($which=~/\.tabbg$/) { |
|
return '#CCCCCC'; |
|
} |
|
} |
|
if (exists($env{'environment.color.'.$which})) { |
if (exists($env{'environment.color.'.$which})) { |
return $env{'environment.color.'.$which}; |
return $env{'environment.color.'.$which}; |
} |
} |
$domain=&determinedomain($domain); |
$domain=&determinedomain($domain); |
my %domdesign = &get_domainconf($domain); |
my %domdesign; |
|
unless ($domain eq 'public') { |
|
%domdesign = &get_domainconf($domain); |
|
} |
my $output; |
my $output; |
if ($domdesign{$domain.'.'.$which} ne '') { |
if ($domdesign{$domain.'.'.$which} ne '') { |
$output = $domdesign{$domain.'.'.$which}; |
$output = $domdesign{$domain.'.'.$which}; |
} else { |
} else { |
$output = $defaultdesign{$which}; |
$output = $defaultdesign{$which}; |
} |
} |
if (($which =~ /^(student|coordinator|author|admin)\.img$/) || |
if (($which =~ /^(student|coordinator|author|admin)\.img$/) || |
($which =~ /login\.(img|logo|domlogo)/)) { |
($which =~ /login\.(img|logo|domlogo|login)/)) { |
if ($output =~ m{^/(adm|res)/}) { |
if ($output =~ m{^/(adm|res)/}) { |
if ($output =~ m{^/res/}) { |
if ($output =~ m{^/res/}) { |
my $local_name = &Apache::lonnet::filelocation('',$output); |
my $local_name = &Apache::lonnet::filelocation('',$output); |
&Apache::lonnet::repcopy($local_name); |
&Apache::lonnet::repcopy($local_name); |
} |
} |
$output = &lonhttpdurl($output); |
$output = &lonhttpdurl($output); |
} |
} |
} |
} |
return $output; |
return $output; |
} |
} |
|
|
|
############################################## |
|
=pod |
|
|
|
=item * &authorspace() |
|
|
|
Inputs: $url (usually will be undef). |
|
|
|
Returns: Path to Authoring Space containing the resource or |
|
directory being viewed (or for which action is being taken). |
|
If $url is provided, and begins /priv/<domain>/<uname> |
|
the path will be that portion of the $context argument. |
|
Otherwise the path will be for the author space of the current |
|
user when the current role is author, or for that of the |
|
co-author/assistant co-author space when the current role |
|
is co-author or assistant co-author. |
|
|
|
=cut |
|
|
|
sub authorspace { |
|
my ($url) = @_; |
|
if ($url ne '') { |
|
if ($url =~ m{^(/priv/$match_domain/$match_username/)}) { |
|
return $1; |
|
} |
|
} |
|
my $caname = ''; |
|
my $cadom = ''; |
|
if ($env{'request.role'} =~ /^(?:ca|aa)/) { |
|
($cadom,$caname) = |
|
($env{'request.role'}=~/($match_domain)\/($match_username)$/); |
|
} elsif ($env{'request.role'} =~ m{^au\./($match_domain)/}) { |
|
$caname = $env{'user.name'}; |
|
$cadom = $env{'user.domain'}; |
|
} |
|
if (($caname ne '') && ($cadom ne '')) { |
|
return "/priv/$cadom/$caname/"; |
|
} |
|
return; |
|
} |
|
|
|
############################################## |
|
=pod |
|
|
|
=item * &head_subbox() |
|
|
|
Inputs: $content (contains HTML code with page functions, etc.) |
|
|
|
Returns: HTML div with $content |
|
To be included in page header |
|
|
|
=cut |
|
|
|
sub head_subbox { |
|
my ($content)=@_; |
|
my $output = |
|
'<div class="LC_head_subbox">' |
|
.$content |
|
.'</div>' |
|
} |
|
|
|
############################################## |
|
=pod |
|
|
|
=item * &CSTR_pageheader() |
|
|
|
Input: (optional) filename from which breadcrumb trail is built. |
|
In most cases no input as needed, as $env{'request.filename'} |
|
is appropriate for use in building the breadcrumb trail. |
|
frameset flag |
|
If page header is being requested for use in a frameset, then |
|
the second (option) argument -- frameset will be true, and |
|
the target attribute set for links should be target="_parent". |
|
|
|
Returns: HTML div with CSTR path and recent box |
|
To be included on Authoring Space pages |
|
|
|
=cut |
|
|
|
sub CSTR_pageheader { |
|
my ($trailfile,$frameset) = @_; |
|
if ($trailfile eq '') { |
|
$trailfile = $env{'request.filename'}; |
|
} |
|
|
|
# this is for resources; directories have customtitle, and crumbs |
|
# and select recent are created in lonpubdir.pm |
|
|
|
my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; |
|
my ($udom,$uname,$thisdisfn)= |
|
($trailfile =~ m{^\Q$londocroot\E/priv/([^/]+)/([^/]+)(?:|/(.*))$}); |
|
my $formaction = "/priv/$udom/$uname/$thisdisfn"; |
|
$formaction =~ s{/+}{/}g; |
|
|
|
my $parentpath = ''; |
|
my $lastitem = ''; |
|
if ($thisdisfn =~ m-(.+/)([^/]*)$-) { |
|
$parentpath = $1; |
|
$lastitem = $2; |
|
} else { |
|
$lastitem = $thisdisfn; |
|
} |
|
|
|
my ($target,$crumbtarget) = (' target="_top"','_top'); |
|
if ($frameset) { |
|
$target = ' target="_parent"'; |
|
$crumbtarget = '_parent'; |
|
} elsif (($env{'request.lti.login'}) && ($env{'request.lti.target'} eq 'iframe')) { |
|
$target = ''; |
|
$crumbtarget = ''; |
|
} elsif (($env{'request.deeplink.login'}) && ($env{'request.deeplink.target'})) { |
|
$target = ' target="'.$env{'request.deeplink.target'}.'"'; |
|
$crumbtarget = $env{'request.deeplink.target'}; |
|
} |
|
|
|
my $output = |
|
'<div>' |
|
.&Apache::loncommon::help_open_menu('','',3,'Authoring') #FIXME: Broken? Where is it? |
|
.'<b>'.&mt('Authoring Space:').'</b> ' |
|
.'<form name="dirs" method="post" action="'.$formaction.'"'.$target.'>' |
|
.&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,$crumbtarget,'/priv/'.$udom,undef,undef); |
|
|
|
if ($lastitem) { |
|
$output .= |
|
'<span class="LC_filename">' |
|
.$lastitem |
|
.'</span>'; |
|
} |
|
$output .= |
|
'<br />' |
|
#FIXME lonpubdir: &Apache::lonhtmlcommon::crumbs($uname.$thisdisfn.'/',$crumbtarget,'/priv','','+1',1)."</b></tt><br />" |
|
.&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()') |
|
.'</form>' |
|
.&Apache::lonmenu::constspaceform($frameset) |
|
.'</div>'; |
|
|
|
return $output; |
|
} |
|
|
|
############################################## |
|
=pod |
|
|
|
=item * &nocodemirror() |
|
|
|
Input: None |
|
|
|
Returns: 1 if CodeMirror is deactivated based on |
|
user's preference, or domain default, |
|
if user indicated use of default. |
|
|
|
=cut |
|
|
|
sub nocodemirror { |
|
my $nocodem = $env{'environment.nocodemirror'}; |
|
unless ($nocodem) { |
|
my %domdefs = &Apache::lonnet::get_domain_defaults($env{'user.domain'}); |
|
if ($domdefs{'nocodemirror'}) { |
|
$nocodem = 'yes'; |
|
} |
|
} |
|
if ($nocodem eq 'yes') { |
|
return 1; |
|
} |
|
return; |
|
} |
|
|
|
############################################## |
|
=pod |
|
|
|
=item * &permitted_editors() |
|
|
|
Input: $uri (optional) |
|
|
|
Returns: %editors hash in which keys are editors |
|
permitted in current Authoring Space. |
|
Value for each key is 1. Possible keys |
|
are: edit, xml, and daxe. If no specific |
|
set of editors has been set for the Author |
|
who owns the Authoring Space, then the |
|
domain default will be used. If no domain |
|
default has been set, then the keys will be |
|
edit and xml. |
|
|
|
=cut |
|
|
|
sub permitted_editors { |
|
my ($uri) = @_; |
|
my ($is_author,$is_coauthor,$auname,$audom,%editors); |
|
if ($env{'request.role'} =~ m{^au\./}) { |
|
$is_author = 1; |
|
} elsif ($env{'request.role'} =~ m{^(?:ca|aa)\./($match_domain)/($match_username)}) { |
|
($audom,$auname) = ($1,$2); |
|
if (($audom ne '') && ($auname ne '')) { |
|
if (($env{'user.domain'} eq $audom) && |
|
($env{'user.name'} eq $auname)) { |
|
$is_author = 1; |
|
} else { |
|
$is_coauthor = 1; |
|
} |
|
} |
|
} elsif ($env{'request.course.id'}) { |
|
if ($env{'request.editurl'} =~ m{^/priv/($match_domain)/($match_username)/}) { |
|
($audom,$auname) = ($1,$2); |
|
} elsif ($env{'request.uri'} =~ m{^/priv/($match_domain)/($match_username)/}) { |
|
($audom,$auname) = ($1,$2); |
|
} elsif (($uri eq '/daxesave') && |
|
($env{'form.path'} =~ m{^/daxeopen/priv/($match_domain)/($match_username)/})) { |
|
($audom,$auname) = ($1,$2); |
|
} |
|
if (($audom ne '') && ($auname ne '')) { |
|
if (($env{'user.domain'} eq $audom) && |
|
($env{'user.name'} eq $auname)) { |
|
$is_author = 1; |
|
} else { |
|
$is_coauthor = 1; |
|
} |
|
} |
|
} |
|
if ($is_author) { |
|
if (exists($env{'environment.editors'})) { |
|
map { $editors{$_} = 1; } split(/,/,$env{'environment.editors'}); |
|
} else { |
|
%editors = ( edit => 1, |
|
xml => 1, |
|
); |
|
} |
|
} elsif ($is_coauthor) { |
|
if (exists($env{"environment.internal.editors./$audom/$auname"})) { |
|
map { $editors{$_} = 1; } split(/,/,$env{"environment.internal.editors./$audom/$auname"}); |
|
} else { |
|
%editors = ( edit => 1, |
|
xml => 1, |
|
); |
|
} |
|
} else { |
|
%editors = ( edit => 1, |
|
xml => 1, |
|
); |
|
} |
|
return %editors; |
|
} |
|
|
############################################### |
############################################### |
############################################### |
############################################### |
|
|
Line 3379 Inputs:
|
Line 6169 Inputs:
|
=item * $forcereg, if page should register as content page (relevant for |
=item * $forcereg, if page should register as content page (relevant for |
text interface only) |
text interface only) |
|
|
=item * $customtitle, alternate text to use instead of $title |
=item * $no_nav_bar, if true, keep the 'what is this' info but remove the |
in the title box that appears, this text |
navigational links |
is not auto translated like the $title is |
|
|
|
=item * $notopbar, if true, keep the 'what is this' info but remove the |
|
navigational links |
|
|
|
=item * $bgcolor, used to override the bgcolor on a webpage to a specific value |
=item * $bgcolor, used to override the bgcolor on a webpage to a specific value |
|
|
=item * $notitle, if true keep the nav controls, but remove the title bar |
=item * $no_inline_link, if true and in remote mode, don't show the |
|
|
=item * $no_inline_link, if true and in remote mode, don't show the |
|
'Switch To Inline Menu' link |
'Switch To Inline Menu' link |
|
|
=item * $args, optional argument valid values are |
=item * $args, optional argument valid values are |
no_auto_mt_title -> prevents &mt()ing the title arg |
no_auto_mt_title -> prevents &mt()ing the title arg |
|
use_absolute -> for external resource or syllabus, this will |
|
contain https://<hostname> if server uses |
|
https (as per hosts.tab), but request is for http |
|
hostname -> hostname, from $r->hostname(). |
|
|
|
=item * $advtoolsref, optional argument, ref to an array containing |
|
inlineremote items to be added in "Functions" menu below |
|
breadcrumbs. |
|
|
|
=item * $ltiscope, optional argument, will be one of: resource, map or |
|
course, if LON-CAPA is in LTI Provider context. Value is |
|
the scope of use, i.e., launch was for access to a single, a map |
|
or the entire course. |
|
|
|
=item * $ltiuri, optional argument, if LON-CAPA is in LTI Provider |
|
context, this will contain the URL for the landing item in |
|
the course, after launch from an LTI Consumer |
|
|
|
=item * $ltimenu, optional argument, if LON-CAPA is in LTI Provider |
|
context, this will contain a reference to hash of items |
|
to be included in the page header and/or inline menu. |
|
|
|
=item * $menucoll, optional argument, if specific menu collection is in |
|
effect, either set as the default for the course, or set for |
|
the deeplink paramater for $env{'request.deeplink.login'} |
|
then $menucoll will be the number of that collection. |
|
|
|
=item * $menuref, optional argument, reference to a hash, containing the |
|
menu options included for the menu in effect, based on the |
|
configuration for the numbered menu collection in use. |
|
|
|
=item * $showncrumbsref, reference to a scalar. Calls to lonmenu::innerregister |
|
within &bodytag() can result in calls to lonhtmlcommon::breadcrumbs(), |
|
if so, $showncrumbsref is set there to 1, and will propagate back |
|
via &bodytag() to &start_page(), to prevent lonhtmlcommon::breadcrumbs() |
|
being called a second time. |
|
|
=back |
=back |
|
|
Line 3406 other decorations will be returned.
|
Line 6226 other decorations will be returned.
|
=cut |
=cut |
|
|
sub bodytag { |
sub bodytag { |
my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle, |
my ($title,$function,$addentries,$bodyonly,$domain,$forcereg, |
$notopbar,$bgcolor,$notitle,$no_inline_link,$args)=@_; |
$no_nav_bar,$bgcolor,$no_inline_link,$args,$advtoolsref, |
|
$ltiscope,$ltiuri,$ltimenu,$menucoll,$menuref,$showncrumbsref)=@_; |
|
|
|
my $public; |
|
if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')) |
|
|| ($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) { |
|
$public = 1; |
|
} |
if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } |
if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } |
|
my $httphost = $args->{'use_absolute'}; |
|
my $hostname = $args->{'hostname'}; |
|
|
$function = &get_users_function() if (!$function); |
$function = &get_users_function() if (!$function); |
my $img = &designparm($function.'.img',$domain); |
my $img = &designparm($function.'.img',$domain); |
my $font = &designparm($function.'.font',$domain); |
my $font = &designparm($function.'.font',$domain); |
my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain); |
my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain); |
|
|
my %design = ( 'style' => 'margin-top: 0px', |
my %design = ( 'style' => 'margin-top: 0', |
'bgcolor' => $pgbg, |
'bgcolor' => $pgbg, |
'text' => $font, |
'text' => $font, |
'alink' => &designparm($function.'.alink',$domain), |
'alink' => &designparm($function.'.alink',$domain), |
Line 3425 sub bodytag {
|
Line 6253 sub bodytag {
|
@design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; |
@design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; |
|
|
# role and realm |
# role and realm |
my ($role,$realm) = split(/\./,$env{'request.role'},2); |
my ($role,$realm) = split(m{\./},$env{'request.role'},2); |
if ($role eq 'ca') { |
if ($realm) { |
|
$realm = '/'.$realm; |
|
} |
|
if ($role eq 'ca') { |
my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$}); |
my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$}); |
$realm = &plainname($rname,$rdom); |
$realm = &plainname($rname,$rdom); |
} |
} |
# realm |
# realm |
|
my ($cid,$sec); |
if ($env{'request.course.id'}) { |
if ($env{'request.course.id'}) { |
|
$cid = $env{'request.course.id'}; |
|
if ($env{'request.course.sec'}) { |
|
$sec = $env{'request.course.sec'}; |
|
} |
|
} elsif ($realm =~ m{^/($match_domain)/($match_courseid)(?:|/(\w+))$}) { |
|
if (&Apache::lonnet::is_course($1,$2)) { |
|
$cid = $1.'_'.$2; |
|
$sec = $3; |
|
} |
|
} |
|
if ($cid) { |
if ($env{'request.role'} !~ /^cr/) { |
if ($env{'request.role'} !~ /^cr/) { |
$role = &Apache::lonnet::plaintext($role,&course_type()); |
$role = &Apache::lonnet::plaintext($role,&course_type()); |
|
} elsif ($role =~ m{^cr/($match_domain)/\1-domainconfig/(\w+)$}) { |
|
if ($env{'request.role.desc'}) { |
|
$role = $env{'request.role.desc'}; |
|
} else { |
|
$role = &mt('Helpdesk[_1]',' '.$2); |
|
} |
|
} else { |
|
$role = (split(/\//,$role,4))[-1]; |
} |
} |
$realm = $env{'course.'.$env{'request.course.id'}.'.description'}; |
if ($sec) { |
|
$role .= (' 'x2).'- '.&mt('section:').' '.$sec; |
|
} |
|
$realm = $env{'course.'.$cid.'.description'}; |
} else { |
} else { |
$role = &Apache::lonnet::plaintext($role); |
$role = &Apache::lonnet::plaintext($role); |
} |
} |
|
|
if (!$realm) { $realm=' '; } |
if (!$realm) { $realm=' '; } |
# Set messages |
|
my $messages=&domainlogo($domain); |
|
# Port for miniserver |
|
my $lonhttpdPort=$Apache::lonnet::perlvar{'lonhttpdPort'}; |
|
if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; } |
|
|
|
my $extra_body_attr = &make_attr_string($forcereg,\%design); |
my $extra_body_attr = &make_attr_string($forcereg,\%design); |
|
|
Line 3453 sub bodytag {
|
Line 6302 sub bodytag {
|
my $bodytag = "<body $extra_body_attr>". |
my $bodytag = "<body $extra_body_attr>". |
&Apache::lontexconvert::init_math_support(); |
&Apache::lontexconvert::init_math_support(); |
|
|
if ($bodyonly) { |
&get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']); |
|
|
|
if (($bodyonly) || ($no_nav_bar) || ($env{'form.inhibitmenu'} eq 'yes')) { |
return $bodytag; |
return $bodytag; |
} elsif ($env{'browser.interface'} eq 'textual') { |
|
# Accessibility |
|
|
|
$bodytag.=&Apache::lonmenu::menubuttons($forcereg,$forcereg); |
|
if (!$notitle) { |
|
$bodytag.='<h1>LON-CAPA: '.$title.'</h1>'; |
|
} |
|
return $bodytag; |
|
} |
} |
|
|
my $name = &plainname($env{'user.name'},$env{'user.domain'}); |
if ($public) { |
if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { |
|
undef($role); |
undef($role); |
} else { |
|
$name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'}); |
|
} |
} |
|
|
my $roleinfo=(<<ENDROLE); |
|
<td class="LC_title_bar_who"> |
|
<div class="LC_title_bar_name"> |
|
$name |
|
|
|
</div> |
|
<div class="LC_title_bar_role"> |
|
$role |
|
</div> |
|
<div class="LC_title_bar_realm"> |
|
$realm |
|
</div> |
|
</td> |
|
ENDROLE |
|
|
|
my $titleinfo = '<span class="LC_title_bar_title">'.$title.'</span>'; |
my $showcrstitle = 1; |
if ($customtitle) { |
if (($cid) && ($env{'request.lti.login'})) { |
$titleinfo = $customtitle; |
if (ref($ltimenu) eq 'HASH') { |
|
unless ($ltimenu->{'role'}) { |
|
undef($role); |
|
} |
|
unless ($ltimenu->{'coursetitle'}) { |
|
$realm=' '; |
|
$showcrstitle = 0; |
|
} |
|
} |
|
} elsif (($cid) && ($menucoll)) { |
|
if (ref($menuref) eq 'HASH') { |
|
unless ($menuref->{'role'}) { |
|
undef($role); |
|
} |
|
unless ($menuref->{'crs'}) { |
|
$realm=' '; |
|
$showcrstitle = 0; |
|
} |
|
} |
} |
} |
|
|
|
my $titleinfo = '<h1>'.$title.'</h1>'; |
# |
# |
# Extra info if you are the DC |
# Extra info if you are the DC |
my $dc_info = ''; |
my $dc_info = ''; |
if ($env{'user.adv'} && exists($env{'user.role.dc./'. |
if (($env{'user.adv'}) && ($env{'request.course.id'}) && $showcrstitle && |
$env{'course.'.$env{'request.course.id'}. |
(exists($env{'user.role.dc./'.$env{'course.'.$cid.'.domain'}.'/'}))) { |
'.domain'}.'/'})) { |
$dc_info = $cid.' '.$env{'course.'.$cid.'.internal.coursecode'}; |
my $cid = $env{'request.course.id'}; |
|
$dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'}; |
|
$dc_info =~ s/\s+$//; |
$dc_info =~ s/\s+$//; |
$dc_info = '('.$dc_info.')'; |
|
} |
} |
|
|
if ($env{'environment.remote'} eq 'off') { |
my $crstype; |
# No Remote |
if ($cid) { |
if ($env{'request.state'} eq 'construct') { |
$crstype = $env{'course.'.$cid.'.type'}; |
$forcereg=1; |
} elsif ($args->{'crstype'}) { |
} |
$crstype = $args->{'crstype'}; |
|
} |
|
|
|
$role = '<span class="LC_nobreak">('.$role.')</span>' if ($role && !$env{'browser.mobile'}); |
|
|
|
if ($env{'request.state'} eq 'construct') { $forcereg=1; } |
|
|
if (!$customtitle && $env{'request.state'} eq 'construct') { |
|
# this is for resources; directories have customtitle, and crumbs |
|
# and select recent are created in lonpubdir.pm |
my $funclist; |
my ($uname,$thisdisfn)= |
if (($env{'environment.remote'} eq 'on') && ($env{'request.state'} ne 'construct')) { |
($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|); |
$bodytag .= Apache::lonhtmlcommon::scripttag(Apache::lonmenu::utilityfunctions($httphost), 'start')."\n". |
my $formaction='/priv/'.$uname.'/'.$thisdisfn; |
Apache::lonmenu::serverform(); |
$formaction=~s/\/+/\//g; |
my $forbodytag; |
|
&Apache::lonmenu::prepare_functions($env{'request.noversionuri'}, |
my $parentpath = ''; |
$forcereg,$args->{'group'}, |
my $lastitem = ''; |
$args->{'bread_crumbs'}, |
if ($thisdisfn =~ m-(.+/)([^/]*)$-) { |
$advtoolsref,'','',\$forbodytag); |
$parentpath = $1; |
unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') { |
$lastitem = $2; |
$funclist = $forbodytag; |
} else { |
} |
$lastitem = $thisdisfn; |
} else { |
} |
|
$titleinfo = |
# if ($env{'request.state'} eq 'construct') { |
&Apache::loncommon::help_open_menu('','',3,'Authoring'). |
# $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls |
'<b>Construction Space</b>: '. |
# } |
'<form name="dirs" method="post" action="'.$formaction |
|
.'" target="_top"><tt><b>' |
$bodytag .= Apache::lonhtmlcommon::scripttag( |
.&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."<font size=\"+1\">$lastitem</font></b></tt><br />" |
Apache::lonmenu::utilityfunctions($httphost), 'start'); |
.&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()') |
|
.'</form>' |
my $collapsible; |
.&Apache::lonmenu::constspaceform(); |
if ($args->{'collapsible_header'} ne '') { |
} |
$collapsible = 1; |
|
my ($menustate,$tiptext,$divclass); |
my $titletable; |
if ($args->{'start_collapsed'}) { |
if (!$notitle) { |
$menustate = 'collapsed'; |
$titletable = |
$tiptext = 'display'; |
'<table id="LC_title_bar">'. |
$divclass = 'hidden'; |
"<tr><td> $titleinfo $dc_info</td>".$roleinfo. |
|
'</tr></table>'; |
|
} |
|
if ($notopbar) { |
|
$bodytag .= $titletable; |
|
} else { |
|
if ($env{'request.state'} eq 'construct') { |
|
$bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg, |
|
$titletable); |
|
} else { |
} else { |
$bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg). |
$menustate = 'expanded'; |
$titletable; |
$tiptext = 'hide'; |
|
$divclass = 'shown'; |
|
} |
|
my $alttext = &mt('menu state: '.$menustate); |
|
my $tooltip = &mt($tiptext.' standard menus'); |
|
$bodytag .= <<"END"; |
|
<div id="LC_expandingContainer" style="display:inline;"> |
|
<div id="LC_collapsible" class="LC_collapse_trigger" style="position: absolute;top: -5px;left: 0px; z-index:101; display:inline;"> |
|
<a href="#" style="text-decoration:none;"><img class="LC_collapsible_indicator" alt="$alttext" title="$tooltip" src="/res/adm/pages/$menustate.png" style="border:0;margin:0;padding:0;max-width:100%;height:auto" /></a></div> |
|
<div class="LC_menus_content $divclass"> |
|
END |
|
} |
|
unless ($args->{'no_primary_menu'}) { |
|
my ($left,$right) = Apache::lonmenu::primary_menu($crstype,$ltimenu,$menucoll,$menuref, |
|
$args->{'links_disabled'}, |
|
$args->{'links_target'}, |
|
$collapsible); |
|
if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) { |
|
if ($dc_info) { |
|
$dc_info = qq|<span class="LC_cusr_subheading">$dc_info</span>|; |
|
} |
|
$bodytag .= qq|<div id="LC_nav_bar">$left $role<br /> |
|
<em>$realm</em> $dc_info</div>|; |
|
return $bodytag; |
|
} |
|
|
|
unless ($env{'request.symb'} =~ m/\.page___\d+___/) { |
|
$bodytag .= qq|<div id="LC_nav_bar">$left $role</div>|; |
|
} |
|
|
|
$bodytag .= $right; |
|
|
|
if ($dc_info) { |
|
$dc_info = &dc_courseid_toggle($dc_info); |
} |
} |
|
$bodytag .= qq|<div id="LC_realm">$realm $dc_info</div>|; |
|
} |
|
|
|
#if directed to not display the secondary menu, don't. |
|
if ($args->{'no_secondary_menu'}) { |
|
return $bodytag; |
|
} |
|
#don't show menus for public users |
|
if (!$public){ |
|
unless ($args->{'no_inline_menu'}) { |
|
$bodytag .= Apache::lonmenu::secondary_menu($httphost,$ltiscope,$ltimenu, |
|
$args->{'no_primary_menu'}, |
|
$menucoll,$menuref, |
|
$args->{'links_disabled'}, |
|
$args->{'links_target'}); |
|
} |
|
$bodytag .= Apache::lonmenu::serverform(); |
|
$bodytag .= Apache::lonhtmlcommon::scripttag('', 'end'); |
|
if ($env{'request.state'} eq 'construct') { |
|
$bodytag .= &Apache::lonmenu::innerregister($forcereg, |
|
$args->{'bread_crumbs'},'','',$hostname, |
|
$ltiscope,$ltiuri,$showncrumbsref); |
|
} elsif ($forcereg) { |
|
$bodytag .= &Apache::lonmenu::innerregister($forcereg,undef, |
|
$args->{'group'},$args->{'hide_buttons'}, |
|
$hostname,$ltiscope,$ltiuri,$showncrumbsref); |
|
} else { |
|
my $forbodytag; |
|
&Apache::lonmenu::prepare_functions($env{'request.noversionuri'}, |
|
$forcereg,$args->{'group'}, |
|
$args->{'bread_crumbs'}, |
|
$advtoolsref,'',$hostname, |
|
\$forbodytag); |
|
unless (ref($args->{'bread_crumbs'}) eq 'ARRAY') { |
|
$bodytag .= $forbodytag; |
|
} |
|
} |
|
}else{ |
|
# this is to seperate menu from content when there's no secondary |
|
# menu. Especially needed for public accessible ressources. |
|
$bodytag .= '<hr style="clear:both" />'; |
|
$bodytag .= Apache::lonhtmlcommon::scripttag('', 'end'); |
|
} |
|
if ($args->{'collapsible_header'} ne '') { |
|
$bodytag .= $args->{'collapsible_header'}. |
|
'<div id="LC_collapsible_separator"></div>'. |
|
'</div></div>'; |
} |
} |
return $bodytag; |
return $bodytag; |
} |
} |
Line 3563 ENDROLE
|
Line 6481 ENDROLE
|
|
|
my $imgsrc = $img; |
my $imgsrc = $img; |
if ($img =~ /^\/adm/) { |
if ($img =~ /^\/adm/) { |
$imgsrc = 'http://'.$ENV{'HTTP_HOST'}.':'.$lonhttpdPort.$img; |
$imgsrc = &lonhttpdurl($img); |
} |
} |
my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />'; |
my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />'; |
|
|
|
my $help=($no_inline_link?'' |
|
:&Apache::loncommon::top_nav_help('Help')); |
|
|
# Explicit link to get inline menu |
# Explicit link to get inline menu |
my $menu= ($no_inline_link?'' |
my $menu= ($no_inline_link?'' |
:'<br /><a href="/adm/remote?action=collapse">'.&mt('Switch to Inline Menu Mode').'</a>'); |
:'<a href="/adm/remote?action=collapse" target="_top">'.&mt('Switch to Inline Menu Mode').'</a>'); |
# |
|
if ($notitle) { |
if ($dc_info) { |
return $bodytag; |
$dc_info = qq|<span class="LC_cusr_subheading">($dc_info)</span>|; |
|
} |
|
|
|
my $name = &plainname($env{'user.name'},$env{'user.domain'}); |
|
unless ($public) { |
|
$name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'}, |
|
undef,'LC_menubuttons_link'); |
|
} |
|
|
|
unless ($env{'form.inhibitmenu'}) { |
|
$bodytag .= qq|<div id="LC_nav_bar">$name $role</div> |
|
<ol class="LC_primary_menu LC_floatright LC_right"> |
|
<li>$help</li> |
|
<li>$menu</li> |
|
</ol><div id="LC_realm"> $realm $dc_info</div>|; |
|
} |
|
if ($env{'request.state'} eq 'construct') { |
|
if (!$public){ |
|
if ($env{'request.state'} eq 'construct') { |
|
$funclist = &Apache::lonhtmlcommon::scripttag( |
|
&Apache::lonmenu::utilityfunctions($httphost), 'start'). |
|
&Apache::lonhtmlcommon::scripttag('','end'). |
|
&Apache::lonmenu::innerregister($forcereg, |
|
$args->{'bread_crumbs'}); |
|
} |
|
} |
} |
} |
return(<<ENDBODY); |
return $bodytag."\n".$funclist; |
$bodytag |
} |
<table id="LC_title_bar" class="LC_with_remote"> |
|
<tr><td class="LC_title_bar_role_logo">$upperleft</td> |
sub dc_courseid_toggle { |
<td class="LC_title_bar_domain_logo">$messages </td> |
my ($dc_info) = @_; |
</tr> |
return ' <span id="dccidtext" class="LC_cusr_subheading LC_nobreak">'. |
<tr><td>$titleinfo $dc_info $menu</td> |
'<a href="javascript:showCourseID();" class="LC_menubuttons_link">'. |
$roleinfo |
&mt('(More ...)').'</a></span>'. |
</tr> |
'<div id="dccid" class="LC_dccid">'.$dc_info.'</div>'; |
</table> |
|
ENDBODY |
|
} |
} |
|
|
sub make_attr_string { |
sub make_attr_string { |
Line 3608 sub make_attr_string {
|
Line 6552 sub make_attr_string {
|
delete($attr_ref->{$key}); |
delete($attr_ref->{$key}); |
} |
} |
} |
} |
$attr_ref->{'onload'} = |
if ($env{'environment.remote'} eq 'on') { |
&Apache::lonmenu::loadevents(). $on_load; |
$attr_ref->{'onload'} = |
$attr_ref->{'onunload'}= |
&Apache::lonmenu::loadevents(). $on_load; |
&Apache::lonmenu::unloadevents().$on_unload; |
$attr_ref->{'onunload'}= |
} |
&Apache::lonmenu::unloadevents().$on_unload; |
|
} else { |
# Accessibility font enhance |
$attr_ref->{'onload'} = $on_load; |
if ($env{'browser.fontenhance'} eq 'on') { |
$attr_ref->{'onunload'}= $on_unload; |
my $style; |
} |
foreach my $key (keys(%{$attr_ref})) { |
|
if (lc($key) eq 'style') { |
|
$style.=$attr_ref->{$key}.';'; |
|
delete($attr_ref->{$key}); |
|
} |
|
} |
|
$attr_ref->{'style'}=$style.'; font-size: x-large;'; |
|
} |
|
|
|
if ($env{'browser.blackwhite'} eq 'on') { |
|
delete($attr_ref->{'font'}); |
|
delete($attr_ref->{'link'}); |
|
delete($attr_ref->{'alink'}); |
|
delete($attr_ref->{'vlink'}); |
|
delete($attr_ref->{'bgcolor'}); |
|
delete($attr_ref->{'background'}); |
|
} |
} |
|
|
my $attr_string; |
my $attr_string; |
foreach my $attr (keys(%$attr_ref)) { |
foreach my $attr (sort(keys(%$attr_ref))) { |
$attr_string .= " $attr=\"".$attr_ref->{$attr}.'" '; |
$attr_string .= " $attr=\"".$attr_ref->{$attr}.'" '; |
} |
} |
return $attr_string; |
return $attr_string; |
Line 3652 sub make_attr_string {
|
Line 6580 sub make_attr_string {
|
|
|
Returns a uniform footer for LON-CAPA web pages. |
Returns a uniform footer for LON-CAPA web pages. |
|
|
Inputs: none |
Inputs: 1 - optional reference to an args hash |
|
If in the hash, key for noredirectlink has a value which evaluates to true, |
|
a 'Continue' link is not displayed if the page contains an |
|
internal redirect in the <head></head> section, |
|
i.e., $env{'internal.head.redirect'} exists |
|
|
=cut |
=cut |
|
|
sub endbodytag { |
sub endbodytag { |
my $endbodytag='</body>'; |
my ($args) = @_; |
$endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag; |
my $endbodytag; |
|
unless ((ref($args) eq 'HASH') && ($args->{'notbody'})) { |
|
$endbodytag='</body>'; |
|
} |
if ( exists( $env{'internal.head.redirect'} ) ) { |
if ( exists( $env{'internal.head.redirect'} ) ) { |
$endbodytag= |
if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) { |
"<br /><a href=\"$env{'internal.head.redirect'}\">". |
my ($endbodyjs,$idattr); |
&mt('Continue').'</a>'. |
if ($env{'internal.head.to_opener'}) { |
$endbodytag; |
my $linkid = 'LC_continue_link'; |
|
$idattr = ' id="'.$linkid.'"'; |
|
my $redirect_for_js = &js_escape($env{'internal.head.redirect'}); |
|
$endbodyjs=<<ENDJS; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
function ebFunction(evt) { |
|
evt.preventDefault(); |
|
var dest = '$redirect_for_js'; |
|
if (window.opener != null && !window.opener.closed) { |
|
window.opener.location.href=dest; |
|
window.close(); |
|
} else { |
|
window.location.href=dest; |
|
} |
|
return false; |
|
} |
|
|
|
\$(document).ready(function () { |
|
if (document.getElementById('$linkid')) { |
|
var clickelem = document.getElementById('$linkid'); |
|
clickelem.addEventListener('click',ebFunction,false); |
|
} |
|
}); |
|
// ]]> |
|
</script> |
|
ENDJS |
|
} |
|
$endbodytag= |
|
"$endbodyjs<br /><a href=\"$env{'internal.head.redirect'}\"$idattr>". |
|
&mt('Continue').'</a>'. |
|
$endbodytag; |
|
} |
|
} |
|
if ((ref($args) eq 'HASH') && ($args->{'dashjs'})) { |
|
$endbodytag = &Apache::lonhtmlcommon::dash_to_minus_js().$endbodytag; |
} |
} |
return $endbodytag; |
return $endbodytag; |
} |
} |
Line 3688 sub standard_css {
|
Line 6658 sub standard_css {
|
my $img = &designparm($function.'.img', $domain); |
my $img = &designparm($function.'.img', $domain); |
my $tabbg = &designparm($function.'.tabbg', $domain); |
my $tabbg = &designparm($function.'.tabbg', $domain); |
my $font = &designparm($function.'.font', $domain); |
my $font = &designparm($function.'.font', $domain); |
|
my $fontmenu = &designparm($function.'.fontmenu', $domain); |
|
#second colour for later usage |
my $sidebg = &designparm($function.'.sidebg',$domain); |
my $sidebg = &designparm($function.'.sidebg',$domain); |
my $pgbg_or_bgcolor = |
my $pgbg_or_bgcolor = |
$bgcolor || |
$bgcolor || |
Line 3697 sub standard_css {
|
Line 6669 sub standard_css {
|
my $vlink = &designparm($function.'.vlink', $domain); |
my $vlink = &designparm($function.'.vlink', $domain); |
my $link = &designparm($function.'.link', $domain); |
my $link = &designparm($function.'.link', $domain); |
|
|
my $sans = 'Arial,Helvetica,sans-serif'; |
my $sans = 'Verdana,Arial,Helvetica,sans-serif'; |
my $mono = 'monospace'; |
my $mono = 'monospace'; |
my $data_table_head = $tabbg; |
my $data_table_head = $sidebg; |
my $data_table_light = '#EEEEEE'; |
my $data_table_light = '#FAFAFA'; |
my $data_table_dark = '#DDDDDD'; |
my $data_table_dark = '#E0E0E0'; |
my $data_table_darker = '#CCCCCC'; |
my $data_table_darker = '#CCCCCC'; |
my $data_table_highlight = '#FFFF00'; |
my $data_table_highlight = '#FFFF00'; |
my $mail_new = '#FFBB77'; |
my $mail_new = '#FFBB77'; |
Line 3714 sub standard_css {
|
Line 6686 sub standard_css {
|
my $mail_other_hover = '#669999'; |
my $mail_other_hover = '#669999'; |
my $table_header = '#DDDDDD'; |
my $table_header = '#DDDDDD'; |
my $feedback_link_bg = '#BBBBBB'; |
my $feedback_link_bg = '#BBBBBB'; |
|
my $lg_border_color = '#C8C8C8'; |
|
my $button_hover = '#BF2317'; |
|
|
my $border = ($env{'browser.type'} eq 'explorer') ? '0px 2px 0px 2px' |
my $border = ($env{'browser.type'} eq 'explorer' || |
: '0px 3px 0px 4px'; |
$env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px' |
|
: '0 3px 0 4px'; |
|
|
|
|
return <<END; |
return <<END; |
h1, h2, h3, th { font-family: $sans } |
|
a:focus { color: red; background: yellow } |
|
table.thinborder, |
|
|
|
table.thinborder tr th { |
/* needed for iframe to allow 100% height in FF */ |
border-style: solid; |
body, html { |
border-width: 1px; |
margin: 0; |
background: $tabbg; |
padding: 0 0.5%; |
|
height: 99%; /* to avoid scrollbars */ |
} |
} |
table.thinborder tr td { |
|
border-style: solid; |
body { |
border-width: 1px |
font-family: $sans; |
|
line-height:130%; |
|
font-size:0.83em; |
|
color:$font; |
|
} |
|
|
|
a:focus, |
|
a:focus img { |
|
color: red; |
|
} |
|
|
|
form, .inline { |
|
display: inline; |
|
} |
|
|
|
.LC_menus_content.shown{ |
|
display: block; |
|
} |
|
|
|
.LC_menus_content.hidden { |
|
display: none; |
|
} |
|
|
|
.LC_right { |
|
text-align:right; |
|
} |
|
|
|
.LC_middle { |
|
vertical-align:middle; |
|
} |
|
|
|
.LC_floatleft { |
|
float: left; |
|
} |
|
|
|
.LC_floatright { |
|
float: right; |
|
} |
|
|
|
.LC_400Box { |
|
width:400px; |
|
} |
|
|
|
#LC_collapsible_separator { |
|
border: 1px solid black; |
|
width: 99.9%; |
|
height: 0px; |
|
} |
|
|
|
.LC_iframecontainer { |
|
width: 98%; |
|
margin: 0; |
|
position: fixed; |
|
top: 8.5em; |
|
bottom: 0; |
|
} |
|
|
|
.LC_iframecontainer iframe{ |
|
border: none; |
|
width: 100%; |
|
height: 100%; |
|
} |
|
|
|
.LC_filename { |
|
font-family: $mono; |
|
white-space:pre; |
|
font-size: 120%; |
|
} |
|
|
|
.LC_fileicon { |
|
border: none; |
|
height: 1.3em; |
|
vertical-align: text-bottom; |
|
margin-right: 0.3em; |
|
text-decoration:none; |
|
} |
|
|
|
.LC_setting { |
|
text-decoration:underline; |
} |
} |
|
|
form, .inline { display: inline; } |
|
.center { text-align: center; } |
|
.LC_filename {font-family: $mono;} |
|
.LC_error { |
.LC_error { |
color: red; |
color: red; |
font-size: larger; |
|
} |
} |
.LC_warning, |
|
|
.LC_warning { |
|
color: darkorange; |
|
} |
|
|
.LC_diff_removed { |
.LC_diff_removed { |
color: red; |
color: red; |
} |
} |
Line 3751 form, .inline { display: inline; }
|
Line 6802 form, .inline { display: inline; }
|
.LC_diff_added { |
.LC_diff_added { |
color: green; |
color: green; |
} |
} |
.LC_unknown { |
|
color: yellow; |
div.LC_confirm_box { |
|
background-color: #FAFAFA; |
|
border: 1px solid $lg_border_color; |
|
margin-right: 0; |
|
padding: 5px; |
} |
} |
|
|
.LC_icon { |
div.LC_confirm_box .LC_error img, |
border: 0px; |
div.LC_confirm_box .LC_success img { |
|
vertical-align: middle; |
} |
} |
.LC_indexer_icon { |
|
border: 0px; |
.LC_maxwidth { |
height: 22px; |
max-width: 100%; |
|
height: auto; |
|
} |
|
|
|
.LC_textsize_mobile { |
|
\@media only screen and (max-device-width: 480px) { |
|
-webkit-text-size-adjust:100%; -moz-text-size-adjust:100%; -ms-text-size-adjust:100%; |
|
} |
|
} |
|
|
|
.LC_icon { |
|
border: none; |
|
vertical-align: middle; |
} |
} |
|
|
.LC_docs_spacer { |
.LC_docs_spacer { |
width: 25px; |
width: 25px; |
height: 1px; |
height: 1px; |
border: 0px; |
border: none; |
} |
} |
|
|
.LC_internal_info { |
.LC_internal_info { |
color: #999; |
color: #999999; |
|
} |
|
|
|
.LC_discussion { |
|
background: $data_table_dark; |
|
border: 1px solid black; |
|
margin: 2px; |
|
} |
|
|
|
.LC_disc_action_left { |
|
background: $sidebg; |
|
text-align: left; |
|
padding: 4px; |
|
margin: 2px; |
|
} |
|
|
|
.LC_disc_action_right { |
|
background: $sidebg; |
|
text-align: right; |
|
padding: 4px; |
|
margin: 2px; |
|
} |
|
|
|
.LC_disc_new_item { |
|
background: white; |
|
border: 2px solid red; |
|
margin: 4px; |
|
padding: 4px; |
|
} |
|
|
|
.LC_disc_old_item { |
|
background: white; |
|
margin: 4px; |
|
padding: 4px; |
} |
} |
|
|
table.LC_pastsubmission { |
table.LC_pastsubmission { |
Line 3777 table.LC_pastsubmission {
|
Line 6879 table.LC_pastsubmission {
|
margin: 2px; |
margin: 2px; |
} |
} |
|
|
table#LC_top_nav, table#LC_menubuttons { |
table#LC_menubuttons { |
width: 100%; |
width: 100%; |
background: $pgbg; |
background: $pgbg; |
border: 2px; |
border: 2px; |
border-collapse: separate; |
border-collapse: separate; |
padding: 0px; |
padding: 0; |
|
} |
|
|
|
table#LC_title_bar a { |
|
color: $fontmenu; |
} |
} |
|
|
table#LC_title_bar, table.LC_breadcrumbs, table#LC_nav_location, |
table#LC_title_bar { |
|
clear: both; |
|
display: none; |
|
} |
|
|
|
table#LC_title_bar, |
|
table.LC_breadcrumbs, /* obsolete? */ |
table#LC_title_bar.LC_with_remote { |
table#LC_title_bar.LC_with_remote { |
width: 100%; |
width: 100%; |
border-color: $pgbg; |
border-color: $pgbg; |
border-style: solid; |
border-style: solid; |
border-width: $border; |
border-width: $border; |
|
|
background: $pgbg; |
background: $pgbg; |
font-family: $sans; |
color: $fontmenu; |
border-collapse: collapse; |
border-collapse: collapse; |
padding: 0px; |
padding: 0; |
|
margin: 0; |
} |
} |
|
|
table.LC_docs_path { |
ul.LC_breadcrumb_tools_outerlist { |
width: 100%; |
margin: 0; |
border: 0; |
padding: 0; |
background: $pgbg; |
position: relative; |
font-family: $sans; |
list-style: none; |
border-collapse: collapse; |
} |
padding: 0px; |
ul.LC_breadcrumb_tools_outerlist li { |
|
display: inline; |
} |
} |
|
|
table#LC_title_bar td { |
.LC_breadcrumb_tools_navigation { |
background: $tabbg; |
padding: 0; |
|
margin: 0; |
|
float: left; |
} |
} |
table#LC_title_bar td.LC_title_bar_who { |
.LC_breadcrumb_tools_tools { |
|
padding: 0; |
|
margin: 0; |
|
float: right; |
|
} |
|
|
|
table#LC_title_bar td { |
background: $tabbg; |
background: $tabbg; |
color: $font; |
|
font: small $sans; |
|
text-align: right; |
|
} |
} |
span.LC_metadata { |
|
font-family: $sans; |
table#LC_menubuttons img { |
|
border: none; |
} |
} |
span.LC_title_bar_title { |
|
font: bold x-large $sans; |
.LC_breadcrumbs_component { |
|
float: right; |
|
margin: 0 1em; |
} |
} |
table#LC_title_bar td.LC_title_bar_domain_logo { |
.LC_breadcrumbs_component img { |
background: $sidebg; |
vertical-align: middle; |
text-align: right; |
|
padding: 0px; |
|
} |
} |
table#LC_title_bar td.LC_title_bar_role_logo { |
|
|
.LC_breadcrumbs_hoverable { |
background: $sidebg; |
background: $sidebg; |
padding: 0px; |
|
} |
} |
|
|
table#LC_menubuttons_mainmenu { |
td.LC_table_cell_checkbox { |
width: 100%; |
text-align: center; |
border: 0px; |
|
border-spacing: 1px; |
|
padding: 0px 1px; |
|
margin: 0px; |
|
border-collapse: separate; |
|
} |
|
table#LC_menubuttons img, table#LC_menubuttons_mainmenu img { |
|
border: 0px; |
|
} |
|
table#LC_top_nav td { |
|
background: $tabbg; |
|
border: 0px; |
|
font-size: small; |
|
} |
} |
table#LC_top_nav td a, div#LC_top_nav a { |
|
color: $font; |
.LC_fontsize_small { |
font-family: $sans; |
font-size: 70%; |
} |
} |
table#LC_top_nav td.LC_top_nav_logo { |
|
background: $tabbg; |
#LC_breadcrumbs { |
|
clear:both; |
|
background: $sidebg; |
|
border-bottom: 1px solid $lg_border_color; |
|
line-height: 2.5em; |
|
overflow: hidden; |
|
margin: 0; |
|
padding: 0; |
text-align: left; |
text-align: left; |
white-space: nowrap; |
|
width: 31px; |
|
} |
} |
table#LC_top_nav td.LC_top_nav_logo img { |
|
border: 0px; |
.LC_head_subbox, .LC_actionbox { |
vertical-align: bottom; |
clear:both; |
} |
background: #F8F8F8; /* $sidebg; */ |
table#LC_top_nav td.LC_top_nav_exit, |
border: 1px solid $sidebg; |
table#LC_top_nav td.LC_top_nav_help { |
margin: 0 0 10px 0; |
width: 2.0em; |
padding: 3px; |
|
text-align: left; |
} |
} |
table#LC_top_nav td.LC_top_nav_login { |
|
width: 4.0em; |
.LC_fontsize_medium { |
text-align: center; |
font-size: 85%; |
} |
} |
table.LC_breadcrumbs td, table.LC_docs_path td { |
|
background: $tabbg; |
.LC_fontsize_large { |
color: $font; |
font-size: 120%; |
font-family: $sans; |
|
font-size: smaller; |
|
} |
} |
table.LC_breadcrumbs td.LC_breadcrumbs_component, |
|
table.LC_docs_path td.LC_docs_path_component { |
.LC_menubuttons_inline_text { |
background: $tabbg; |
|
color: $font; |
color: $font; |
font-family: $sans; |
font-size: 90%; |
font-size: larger; |
padding-left:3px; |
text-align: right; |
|
} |
|
td.LC_table_cell_checkbox { |
|
text-align: center; |
|
} |
} |
|
|
table#LC_mainmenu td.LC_mainmenu_column { |
.LC_menubuttons_inline_text img{ |
vertical-align: top; |
vertical-align: middle; |
} |
} |
|
|
.LC_menubuttons_inline_text { |
li.LC_menubuttons_inline_text img { |
color: $font; |
cursor:pointer; |
font-family: $sans; |
text-decoration: none; |
font-size: smaller; |
|
} |
} |
|
|
.LC_menubuttons_link { |
.LC_menubuttons_link { |
Line 3905 table#LC_mainmenu td.LC_mainmenu_column
|
Line 7009 table#LC_mainmenu td.LC_mainmenu_column
|
.LC_menubuttons_category { |
.LC_menubuttons_category { |
color: $font; |
color: $font; |
background: $pgbg; |
background: $pgbg; |
font-family: $sans; |
|
font-size: larger; |
font-size: larger; |
font-weight: bold; |
font-weight: bold; |
} |
} |
|
|
td.LC_menubuttons_text { |
td.LC_menubuttons_text { |
width: 90%; |
|
color: $font; |
color: $font; |
font-family: $sans; |
|
} |
|
|
|
td.LC_menubuttons_img { |
|
} |
} |
|
|
.LC_current_location { |
.LC_current_location { |
font-family: $sans; |
|
background: $tabbg; |
background: $tabbg; |
} |
} |
.LC_new_mail { |
|
font-family: $sans; |
|
font-weight: bold; |
|
} |
|
|
|
.LC_rolesmenu_is { |
|
font-family: $sans; |
|
} |
|
|
|
.LC_rolesmenu_selected { |
td.LC_zero_height { |
font-family: $sans; |
line-height: 0; |
|
cellpadding: 0; |
} |
} |
|
|
.LC_rolesmenu_future { |
table.LC_data_table { |
font-family: $sans; |
|
} |
|
|
|
|
|
.LC_rolesmenu_will { |
|
font-family: $sans; |
|
} |
|
|
|
.LC_rolesmenu_will_not { |
|
font-family: $sans; |
|
} |
|
|
|
.LC_rolesmenu_expired { |
|
font-family: $sans; |
|
} |
|
|
|
.LC_rolesinfo { |
|
font-family: $sans; |
|
} |
|
|
|
.LC_dropadd_labeltext { |
|
font-family: $sans; |
|
text-align: right; |
|
} |
|
|
|
.LC_preferences_labeltext { |
|
font-family: $sans; |
|
text-align: right; |
|
} |
|
|
|
table.LC_aboutme_port { |
|
border: 0px; |
|
border-collapse: collapse; |
|
border-spacing: 0px; |
|
} |
|
table.LC_data_table, table.LC_mail_list { |
|
border: 1px solid #000000; |
border: 1px solid #000000; |
border-collapse: separate; |
border-collapse: separate; |
border-spacing: 1px; |
border-spacing: 1px; |
|
background: $pgbg; |
} |
} |
|
|
.LC_data_table_dense { |
.LC_data_table_dense { |
font-size: small; |
font-size: small; |
} |
} |
|
|
table.LC_nested_outer { |
table.LC_nested_outer { |
border: 1px solid #000000; |
border: 1px solid #000000; |
border-collapse: separate; |
border-collapse: collapse; |
border-spacing: 0px; |
border-spacing: 0; |
width: 100%; |
width: 100%; |
} |
} |
|
|
|
table.LC_innerpickbox, |
table.LC_nested { |
table.LC_nested { |
border: 0px; |
border: none; |
border-collapse: separate; |
border-collapse: collapse; |
border-spacing: 0px; |
border-spacing: 0; |
width: 100%; |
width: 100%; |
} |
} |
table.LC_data_table tr th, table.LC_calendar tr th, table.LC_mail_list tr th, |
|
table.LC_prior_tries tr th { |
table.LC_data_table tr th, |
|
table.LC_calendar tr th, |
|
table.LC_prior_tries tr th, |
|
table.LC_innerpickbox tr th { |
font-weight: bold; |
font-weight: bold; |
background-color: $data_table_head; |
background-color: $data_table_head; |
font-size: smaller; |
color:$fontmenu; |
|
font-size:90%; |
|
} |
|
|
|
table.LC_innerpickbox tr th, |
|
table.LC_innerpickbox tr td { |
|
vertical-align: top; |
|
} |
|
|
|
table.LC_data_table tr.LC_info_row > td { |
|
background-color: #CCCCCC; |
|
font-weight: bold; |
|
text-align: left; |
} |
} |
table.LC_data_table tr td, |
|
table.LC_aboutme_port tr td { |
table.LC_data_table tr.LC_odd_row > td { |
background-color: $data_table_light; |
background-color: $data_table_light; |
padding: 2px; |
padding: 2px; |
|
vertical-align: top; |
|
} |
|
|
|
table.LC_pick_box tr > td.LC_odd_row { |
|
background-color: $data_table_light; |
|
vertical-align: top; |
} |
} |
table.LC_data_table tr.LC_even_row td, |
|
table.LC_aboutme_port tr.LC_even_row td { |
table.LC_data_table tr.LC_even_row > td { |
background-color: $data_table_dark; |
background-color: $data_table_dark; |
|
padding: 2px; |
|
vertical-align: top; |
|
} |
|
|
|
table.LC_pick_box tr > td.LC_even_row { |
|
background-color: $data_table_dark; |
|
vertical-align: top; |
} |
} |
|
|
table.LC_data_table tr.LC_data_table_highlight td { |
table.LC_data_table tr.LC_data_table_highlight td { |
background-color: $data_table_darker; |
background-color: $data_table_darker; |
} |
} |
|
|
|
table.LC_data_table tr td.LC_leftcol_header { |
|
background-color: $data_table_head; |
|
font-weight: bold; |
|
} |
|
|
table.LC_data_table tr.LC_empty_row td, |
table.LC_data_table tr.LC_empty_row td, |
table.LC_nested tr.LC_empty_row td { |
table.LC_nested tr.LC_empty_row td { |
background-color: #FFFFFF; |
|
font-weight: bold; |
font-weight: bold; |
font-style: italic; |
font-style: italic; |
text-align: center; |
text-align: center; |
padding: 8px; |
padding: 8px; |
} |
} |
|
|
|
table.LC_data_table tr.LC_empty_row td, |
|
table.LC_data_table tr.LC_footer_row td { |
|
background-color: $sidebg; |
|
} |
|
|
|
table.LC_nested tr.LC_empty_row td { |
|
background-color: #FFFFFF; |
|
} |
|
|
|
table.LC_caption { |
|
} |
|
|
table.LC_nested tr.LC_empty_row td { |
table.LC_nested tr.LC_empty_row td { |
padding: 4ex |
padding: 4ex |
} |
} |
|
|
table.LC_nested_outer tr th { |
table.LC_nested_outer tr th { |
font-weight: bold; |
font-weight: bold; |
|
color:$fontmenu; |
background-color: $data_table_head; |
background-color: $data_table_head; |
font-size: smaller; |
font-size: small; |
border-bottom: 1px solid #000000; |
border-bottom: 1px solid #000000; |
} |
} |
|
|
table.LC_nested_outer tr td.LC_subheader { |
table.LC_nested_outer tr td.LC_subheader { |
background-color: $data_table_head; |
background-color: $data_table_head; |
font-weight: bold; |
font-weight: bold; |
Line 4034 table.LC_nested_outer tr td.LC_subheader
|
Line 7143 table.LC_nested_outer tr td.LC_subheader
|
border-bottom: 1px solid #000000; |
border-bottom: 1px solid #000000; |
text-align: right; |
text-align: right; |
} |
} |
|
|
table.LC_nested tr.LC_info_row td { |
table.LC_nested tr.LC_info_row td { |
background-color: #CCC; |
background-color: #CCCCCC; |
font-weight: bold; |
font-weight: bold; |
font-size: small; |
font-size: small; |
text-align: center; |
text-align: center; |
} |
} |
table.LC_nested tr.LC_info_row td.LC_left_item { |
|
|
table.LC_nested tr.LC_info_row td.LC_left_item, |
|
table.LC_nested_outer tr th.LC_left_item { |
text-align: left; |
text-align: left; |
} |
} |
|
|
table.LC_nested td { |
table.LC_nested td { |
background-color: #FFF; |
background-color: #FFFFFF; |
font-size: small; |
font-size: small; |
} |
} |
|
|
table.LC_nested_outer tr th.LC_right_item, |
table.LC_nested_outer tr th.LC_right_item, |
table.LC_nested tr.LC_info_row td.LC_right_item, |
table.LC_nested tr.LC_info_row td.LC_right_item, |
table.LC_nested tr.LC_odd_row td.LC_right_item, |
table.LC_nested tr.LC_odd_row td.LC_right_item, |
Line 4055 table.LC_nested tr td.LC_right_item {
|
Line 7169 table.LC_nested tr td.LC_right_item {
|
} |
} |
|
|
table.LC_nested tr.LC_odd_row td { |
table.LC_nested tr.LC_odd_row td { |
background-color: #EEE; |
background-color: #EEEEEE; |
} |
} |
|
|
table.LC_createuser { |
table.LC_createuser { |
} |
} |
|
|
table.LC_createuser tr.LC_section_row td { |
table.LC_createuser tr.LC_section_row td { |
font-size: smaller; |
font-size: small; |
} |
} |
|
|
table.LC_createuser tr.LC_info_row td { |
table.LC_createuser tr.LC_info_row td { |
background-color: #CCC; |
background-color: #CCCCCC; |
font-weight: bold; |
font-weight: bold; |
text-align: center; |
text-align: center; |
} |
} |
Line 4074 table.LC_createuser tr.LC_info_row td {
|
Line 7188 table.LC_createuser tr.LC_info_row td {
|
table.LC_calendar { |
table.LC_calendar { |
border: 1px solid #000000; |
border: 1px solid #000000; |
border-collapse: collapse; |
border-collapse: collapse; |
|
width: 98%; |
} |
} |
|
|
table.LC_calendar_pickdate { |
table.LC_calendar_pickdate { |
font-size: xx-small; |
font-size: xx-small; |
} |
} |
|
|
table.LC_calendar tr td { |
table.LC_calendar tr td { |
border: 1px solid #000000; |
border: 1px solid #000000; |
vertical-align: top; |
vertical-align: top; |
|
width: 14%; |
} |
} |
|
|
table.LC_calendar tr td.LC_calendar_day_empty { |
table.LC_calendar tr td.LC_calendar_day_empty { |
background-color: $data_table_dark; |
background-color: $data_table_dark; |
} |
} |
|
|
table.LC_calendar tr td.LC_calendar_day_current { |
table.LC_calendar tr td.LC_calendar_day_current { |
background-color: $data_table_highlight; |
background-color: $data_table_highlight; |
} |
} |
|
|
table.LC_mail_list tr.LC_mail_new { |
table.LC_data_table tr td.LC_mail_new { |
background-color: $mail_new; |
background-color: $mail_new; |
} |
} |
table.LC_mail_list tr.LC_mail_new:hover { |
|
|
table.LC_data_table tr.LC_mail_new:hover { |
background-color: $mail_new_hover; |
background-color: $mail_new_hover; |
} |
} |
table.LC_mail_list tr.LC_mail_read { |
|
|
table.LC_data_table tr td.LC_mail_read { |
background-color: $mail_read; |
background-color: $mail_read; |
} |
} |
table.LC_mail_list tr.LC_mail_read:hover { |
|
|
/* |
|
table.LC_data_table tr.LC_mail_read:hover { |
background-color: $mail_read_hover; |
background-color: $mail_read_hover; |
} |
} |
table.LC_mail_list tr.LC_mail_replied { |
*/ |
|
|
|
table.LC_data_table tr td.LC_mail_replied { |
background-color: $mail_replied; |
background-color: $mail_replied; |
} |
} |
table.LC_mail_list tr.LC_mail_replied:hover { |
|
|
/* |
|
table.LC_data_table tr.LC_mail_replied:hover { |
background-color: $mail_replied_hover; |
background-color: $mail_replied_hover; |
} |
} |
table.LC_mail_list tr.LC_mail_other { |
*/ |
|
|
|
table.LC_data_table tr td.LC_mail_other { |
background-color: $mail_other; |
background-color: $mail_other; |
} |
} |
table.LC_mail_list tr.LC_mail_other:hover { |
|
|
/* |
|
table.LC_data_table tr.LC_mail_other:hover { |
background-color: $mail_other_hover; |
background-color: $mail_other_hover; |
} |
} |
table.LC_mail_list tr.LC_mail_even { |
*/ |
} |
|
table.LC_mail_list tr.LC_mail_odd { |
|
} |
|
|
|
|
table.LC_data_table tr > td.LC_browser_file, |
table#LC_portfolio_actions { |
table.LC_data_table tr > td.LC_browser_file_published { |
width: auto; |
background: #AAEE77; |
background: $pgbg; |
|
border: 0px; |
|
border-spacing: 2px 2px; |
|
padding: 0px; |
|
margin: 0px; |
|
border-collapse: separate; |
|
} |
|
table#LC_portfolio_actions td.LC_label { |
|
background: $tabbg; |
|
text-align: right; |
|
} |
|
table#LC_portfolio_actions td.LC_value { |
|
background: $tabbg; |
|
} |
} |
|
|
table#LC_cstr_controls { |
table.LC_data_table tr > td.LC_browser_file_locked, |
width: 100%; |
table.LC_data_table tr > td.LC_browser_file_unpublished { |
border-collapse: collapse; |
background: #FFAA99; |
} |
|
table#LC_cstr_controls tr td { |
|
border: 4px solid $pgbg; |
|
padding: 4px; |
|
text-align: center; |
|
background: $tabbg; |
|
} |
} |
table#LC_cstr_controls tr th { |
|
border: 4px solid $pgbg; |
table.LC_data_table tr > td.LC_browser_file_obsolete { |
background: $table_header; |
background: #888888; |
text-align: center; |
|
font-family: $sans; |
|
font-size: smaller; |
|
} |
} |
|
|
table#LC_browser { |
table.LC_data_table tr > td.LC_browser_file_modified, |
|
table.LC_data_table tr > td.LC_browser_file_metamodified { |
|
background: #F8F866; |
} |
} |
table#LC_browser tr th { |
|
background: $table_header; |
table.LC_data_table tr.LC_browser_folder > td { |
|
background: #E0E8FF; |
} |
} |
table#LC_browser tr td { |
|
padding: 2px; |
table.LC_data_table tr > td.LC_roles_is { |
|
/* background: #77FF77; */ |
} |
} |
table#LC_browser tr.LC_browser_file, |
|
table#LC_browser tr.LC_browser_file_published { |
table.LC_data_table tr > td.LC_roles_future { |
background: #CCFF88; |
border-right: 8px solid #FFFF77; |
} |
} |
table#LC_browser tr.LC_browser_file_locked, |
|
table#LC_browser tr.LC_browser_file_unpublished { |
table.LC_data_table tr > td.LC_roles_will { |
background: #FFAA99; |
border-right: 8px solid #FFAA77; |
} |
} |
table#LC_browser tr.LC_browser_file_obsolete { |
|
background: #AAAAAA; |
table.LC_data_table tr > td.LC_roles_expired { |
|
border-right: 8px solid #FF7777; |
} |
} |
table#LC_browser tr.LC_browser_file_modified, |
|
table#LC_browser tr.LC_browser_file_metamodified { |
table.LC_data_table tr > td.LC_roles_will_not { |
background: #FFFF77; |
border-right: 8px solid #AAFF77; |
} |
} |
table#LC_browser tr.LC_browser_folder { |
|
background: #CCCCFF; |
table.LC_data_table tr > td.LC_roles_selected { |
|
border-right: 8px solid #11CC55; |
} |
} |
|
|
span.LC_current_location { |
span.LC_current_location { |
font-size: x-large; |
font-size:larger; |
background: $pgbg; |
background: $pgbg; |
} |
} |
|
|
|
span.LC_current_nav_location { |
|
font-weight:bold; |
|
background: $sidebg; |
|
} |
|
|
span.LC_parm_menu_item { |
span.LC_parm_menu_item { |
font-size: larger; |
font-size: larger; |
font-family: $sans; |
|
} |
} |
|
|
span.LC_parm_scope_all { |
span.LC_parm_scope_all { |
color: red; |
color: red; |
} |
} |
|
|
span.LC_parm_scope_folder { |
span.LC_parm_scope_folder { |
color: green; |
color: green; |
} |
} |
|
|
span.LC_parm_scope_resource { |
span.LC_parm_scope_resource { |
color: orange; |
color: orange; |
} |
} |
|
|
span.LC_parm_part { |
span.LC_parm_part { |
color: blue; |
color: blue; |
} |
} |
span.LC_parm_folder, span.LC_parm_symb { |
|
|
span.LC_parm_folder, |
|
span.LC_parm_symb { |
font-size: x-small; |
font-size: x-small; |
font-family: $mono; |
font-family: $mono; |
color: #AAAAAA; |
color: #AAAAAA; |
} |
} |
|
|
td.LC_parm_overview_level_menu, td.LC_parm_overview_map_menu, |
ul.LC_parm_parmlist li { |
td.LC_parm_overview_parm_selectors, td.LC_parm_overview_parm_restrictions { |
display: inline-block; |
|
padding: 0.3em 0.8em; |
|
vertical-align: top; |
|
width: 150px; |
|
border-top:1px solid $lg_border_color; |
|
} |
|
|
|
td.LC_parm_overview_level_menu, |
|
td.LC_parm_overview_map_menu, |
|
td.LC_parm_overview_parm_selectors, |
|
td.LC_parm_overview_restrictions { |
border: 1px solid black; |
border: 1px solid black; |
border-collapse: collapse; |
border-collapse: collapse; |
} |
} |
|
|
table.LC_parm_overview_restrictions td { |
table.LC_parm_overview_restrictions td { |
border-width: 1px 4px 1px 4px; |
border-width: 1px 4px 1px 4px; |
border-style: solid; |
border-style: solid; |
border-color: $pgbg; |
border-color: $pgbg; |
text-align: center; |
text-align: center; |
} |
} |
|
|
table.LC_parm_overview_restrictions th { |
table.LC_parm_overview_restrictions th { |
background: $tabbg; |
background: $tabbg; |
border-width: 1px 4px 1px 4px; |
border-width: 1px 4px 1px 4px; |
border-style: solid; |
border-style: solid; |
border-color: $pgbg; |
border-color: $pgbg; |
} |
} |
|
|
table#LC_helpmenu { |
table#LC_helpmenu { |
border: 0px; |
border: none; |
height: 55px; |
height: 55px; |
border-spacing: 0px; |
border-spacing: 0; |
} |
} |
|
|
table#LC_helpmenu fieldset legend { |
table#LC_helpmenu fieldset legend { |
font-size: larger; |
font-size: larger; |
font-weight: bold; |
|
} |
} |
|
|
table#LC_helpmenu_links { |
table#LC_helpmenu_links { |
width: 100%; |
width: 100%; |
border: 1px solid black; |
border: 1px solid black; |
background: $pgbg; |
background: $pgbg; |
padding: 0px; |
padding: 0; |
border-spacing: 1px; |
border-spacing: 1px; |
} |
} |
|
|
table#LC_helpmenu_links tr td { |
table#LC_helpmenu_links tr td { |
padding: 1px; |
padding: 1px; |
background: $tabbg; |
background: $tabbg; |
Line 4249 table#LC_helpmenu_links tr td {
|
Line 7386 table#LC_helpmenu_links tr td {
|
font-weight: bold; |
font-weight: bold; |
} |
} |
|
|
table#LC_helpmenu_links a:link, table#LC_helpmenu_links a:visited, |
table#LC_helpmenu_links a:link, |
|
table#LC_helpmenu_links a:visited, |
table#LC_helpmenu_links a:active { |
table#LC_helpmenu_links a:active { |
text-decoration: none; |
text-decoration: none; |
color: $font; |
color: $font; |
} |
} |
|
|
table#LC_helpmenu_links a:hover { |
table#LC_helpmenu_links a:hover { |
text-decoration: underline; |
text-decoration: underline; |
color: $vlink; |
color: $vlink; |
Line 4263 table#LC_helpmenu_links a:hover {
|
Line 7402 table#LC_helpmenu_links a:hover {
|
border: 1px solid #339933; |
border: 1px solid #339933; |
margin: -1px; |
margin: -1px; |
} |
} |
|
|
.LC_chrt_popup_up { |
.LC_chrt_popup_up { |
border: 1px solid yellow; |
border: 1px solid yellow; |
margin: -1px; |
margin: -1px; |
} |
} |
|
|
.LC_chrt_popup { |
.LC_chrt_popup { |
border: 1px solid #8888FF; |
border: 1px solid #8888FF; |
background: #CCCCFF; |
background: #CCCCFF; |
} |
} |
|
|
table.LC_pick_box { |
table.LC_pick_box { |
width: 100%; |
|
border-collapse: separate; |
border-collapse: separate; |
background: white; |
background: white; |
border: 1px solid black; |
border: 1px solid black; |
border-spacing: 1px; |
border-spacing: 1px; |
} |
} |
|
|
table.LC_pick_box td.LC_pick_box_title { |
table.LC_pick_box td.LC_pick_box_title { |
background: $tabbg; |
background: $sidebg; |
font-weight: bold; |
font-weight: bold; |
text-align: right; |
text-align: left; |
|
vertical-align: top; |
width: 184px; |
width: 184px; |
padding: 8px; |
padding: 8px; |
} |
} |
|
|
|
table.LC_pick_box td.LC_pick_box_value { |
|
text-align: left; |
|
padding: 8px; |
|
} |
|
|
|
table.LC_pick_box td.LC_pick_box_select { |
|
text-align: left; |
|
padding: 8px; |
|
} |
|
|
table.LC_pick_box td.LC_pick_box_separator { |
table.LC_pick_box td.LC_pick_box_separator { |
padding: 0px; |
padding: 0; |
height: 1px; |
height: 1px; |
background: black; |
background: black; |
} |
} |
|
|
table.LC_pick_box td.LC_pick_box_submit { |
table.LC_pick_box td.LC_pick_box_submit { |
text-align: right; |
text-align: right; |
} |
} |
|
|
|
table.LC_pick_box td.LC_evenrow_value { |
|
text-align: left; |
|
padding: 8px; |
|
background-color: $data_table_light; |
|
} |
|
|
|
table.LC_pick_box td.LC_oddrow_value { |
|
text-align: left; |
|
padding: 8px; |
|
background-color: $data_table_light; |
|
} |
|
|
|
span.LC_helpform_receipt_cat { |
|
font-weight: bold; |
|
} |
|
|
table.LC_group_priv_box { |
table.LC_group_priv_box { |
background: white; |
background: white; |
border: 1px solid black; |
border: 1px solid black; |
border-spacing: 1px; |
border-spacing: 1px; |
} |
} |
|
|
table.LC_group_priv_box td.LC_pick_box_title { |
table.LC_group_priv_box td.LC_pick_box_title { |
background: $tabbg; |
background: $tabbg; |
font-weight: bold; |
font-weight: bold; |
text-align: right; |
text-align: right; |
width: 184px; |
width: 184px; |
} |
} |
|
|
table.LC_group_priv_box td.LC_groups_fixed { |
table.LC_group_priv_box td.LC_groups_fixed { |
background: $data_table_light; |
background: $data_table_light; |
text-align: center; |
text-align: center; |
} |
} |
|
|
table.LC_group_priv_box td.LC_groups_optional { |
table.LC_group_priv_box td.LC_groups_optional { |
background: $data_table_dark; |
background: $data_table_dark; |
text-align: center; |
text-align: center; |
} |
} |
|
|
table.LC_group_priv_box td.LC_groups_functionality { |
table.LC_group_priv_box td.LC_groups_functionality { |
background: $data_table_darker; |
background: $data_table_darker; |
text-align: center; |
text-align: center; |
font-weight: bold; |
font-weight: bold; |
} |
} |
|
|
table.LC_group_priv td { |
table.LC_group_priv td { |
text-align: left; |
text-align: left; |
padding: 0px; |
padding: 0; |
} |
} |
|
|
table.LC_notify_front_page { |
|
background: white; |
|
border: 1px solid black; |
|
padding: 8px; |
|
} |
|
table.LC_notify_front_page td { |
|
padding: 8px; |
|
} |
|
.LC_navbuttons { |
.LC_navbuttons { |
margin: 2ex 0ex 2ex 0ex; |
margin: 2ex 0ex 2ex 0ex; |
} |
} |
|
|
.LC_topic_bar { |
.LC_topic_bar { |
font-family: $sans; |
|
font-weight: bold; |
font-weight: bold; |
width: 100%; |
|
background: $tabbg; |
background: $tabbg; |
vertical-align: middle; |
margin: 1em 0em 1em 2em; |
margin: 2ex 0ex 2ex 0ex; |
padding: 3px; |
|
font-size: 1.2em; |
} |
} |
|
|
.LC_topic_bar span { |
.LC_topic_bar span { |
|
left: 0.5em; |
|
position: absolute; |
vertical-align: middle; |
vertical-align: middle; |
|
font-size: 1.2em; |
} |
} |
.LC_topic_bar img { |
|
vertical-align: bottom; |
|
} |
|
table.LC_course_group_status { |
table.LC_course_group_status { |
margin: 20px; |
margin: 20px; |
} |
} |
|
|
table.LC_status_selector td { |
table.LC_status_selector td { |
vertical-align: top; |
vertical-align: top; |
text-align: center; |
text-align: center; |
padding: 4px; |
padding: 4px; |
} |
} |
table.LC_descriptive_input td.LC_description { |
|
vertical-align: top; |
div.LC_feedback_link { |
text-align: right; |
clear: both; |
font-weight: bold; |
background: $sidebg; |
|
width: 100%; |
|
padding-bottom: 10px; |
|
border: 1px $tabbg solid; |
|
height: 22px; |
|
line-height: 22px; |
|
padding-top: 5px; |
|
} |
|
|
|
div.LC_feedback_link img { |
|
height: 22px; |
|
vertical-align:middle; |
|
} |
|
|
|
div.LC_feedback_link a { |
|
text-decoration: none; |
|
} |
|
|
|
div.LC_comblock { |
|
display:inline; |
|
color:$font; |
|
font-size:90%; |
} |
} |
table.LC_feedback_link { |
|
background: $feedback_link_bg; |
div.LC_feedback_link div.LC_comblock { |
|
padding-left:5px; |
|
} |
|
|
|
div.LC_feedback_link div.LC_comblock a { |
|
color:$font; |
} |
} |
|
|
span.LC_feedback_link { |
span.LC_feedback_link { |
background: $feedback_link_bg; |
/* background: $feedback_link_bg; */ |
font-size: larger; |
font-size: larger; |
|
} |
|
|
|
span.LC_message_link { |
|
/* background: $feedback_link_bg; */ |
|
font-size: larger; |
|
position: absolute; |
|
right: 1em; |
} |
} |
|
|
table.LC_prior_tries { |
table.LC_prior_tries { |
Line 4381 table.LC_prior_tries td {
|
Line 7585 table.LC_prior_tries td {
|
} |
} |
|
|
.LC_answer_correct { |
.LC_answer_correct { |
background: #AAFFAA; |
background: lightgreen; |
color: black; |
color: darkgreen; |
|
padding: 6px; |
} |
} |
|
|
.LC_answer_charged_try { |
.LC_answer_charged_try { |
background: #FFAAAA ! important; |
background: #FFAAAA; |
color: black; |
color: darkred; |
|
padding: 6px; |
} |
} |
.LC_answer_not_charged_try, |
|
|
.LC_answer_not_charged_try, |
.LC_answer_no_grade, |
.LC_answer_no_grade, |
.LC_answer_late { |
.LC_answer_late { |
background: #FFFFAA; |
background: lightyellow; |
color: black; |
color: black; |
|
padding: 6px; |
} |
} |
|
|
.LC_answer_previous { |
.LC_answer_previous { |
background: #AAAAFF; |
background: lightblue; |
color: black; |
color: darkblue; |
|
padding: 6px; |
} |
} |
|
|
.LC_answer_no_message { |
.LC_answer_no_message { |
background: #FFFFFF; |
background: #FFFFFF; |
color: black; |
color: black; |
|
padding: 6px; |
} |
} |
.LC_answer_unknown { |
|
|
.LC_answer_unknown, |
|
.LC_answer_warning { |
background: orange; |
background: orange; |
color: black; |
color: black; |
|
padding: 6px; |
} |
} |
|
|
|
|
span.LC_prior_numerical, |
span.LC_prior_numerical, |
span.LC_prior_string, |
span.LC_prior_string, |
span.LC_prior_custom, |
span.LC_prior_custom, |
span.LC_prior_reaction, |
span.LC_prior_reaction, |
span.LC_prior_math { |
span.LC_prior_math { |
font-family: monospace; |
font-family: $mono; |
white-space: pre; |
white-space: pre; |
} |
} |
|
|
span.LC_prior_string { |
span.LC_prior_string { |
font-family: monospace; |
font-family: $mono; |
white-space: pre; |
white-space: pre; |
} |
} |
|
|
Line 4426 table.LC_prior_option {
|
Line 7641 table.LC_prior_option {
|
width: 100%; |
width: 100%; |
border-collapse: collapse; |
border-collapse: collapse; |
} |
} |
table.LC_prior_rank, table.LC_prior_match { |
|
|
table.LC_prior_rank, |
|
table.LC_prior_match { |
border-collapse: collapse; |
border-collapse: collapse; |
} |
} |
|
|
table.LC_prior_option tr td, |
table.LC_prior_option tr td, |
table.LC_prior_rank tr td, |
table.LC_prior_rank tr td, |
table.LC_prior_match tr td { |
table.LC_prior_match tr td { |
border: 1px solid #000000; |
border: 1px solid #000000; |
} |
} |
|
|
span.LC_nobreak { |
.LC_nobreak { |
white-space: nowrap; |
white-space: nowrap; |
} |
} |
|
|
table.LC_docs_documents { |
span.LC_cusr_emph { |
background: #BBBBBB; |
font-style: italic; |
border-width: 0px; |
|
border-collapse: collapse; |
|
} |
} |
|
|
table.LC_docs_documents td.LC_docs_document { |
span.LC_cusr_subheading { |
border: 2px solid black; |
font-weight: normal; |
padding: 4px; |
font-size: 85%; |
} |
} |
|
|
.LC_docs_course_commands div { |
div.LC_docs_entry_move { |
float: left; |
border: 1px solid #BBBBBB; |
border: 4px solid #AAAAAA; |
background: #DDDDDD; |
padding: 4px; |
width: 22px; |
background: #DDDDCC; |
padding: 1px; |
|
margin: 0; |
} |
} |
|
|
.LC_docs_entry_move { |
table.LC_data_table tr > td.LC_docs_entry_commands, |
border: 0px; |
table.LC_data_table tr > td.LC_docs_entry_parameter { |
border-collapse: collapse; |
font-size: x-small; |
} |
} |
|
|
.LC_docs_entry_move td { |
.LC_docs_entry_parameter { |
border: 2px solid #BBBBBB; |
white-space: nowrap; |
background: #DDDDDD; |
|
} |
} |
|
|
.LC_docs_editor td.LC_docs_entry_commands { |
|
background: #DDDDDD; |
|
font-size: x-small; |
|
} |
|
.LC_docs_copy { |
.LC_docs_copy { |
color: #000099; |
color: #000099; |
} |
} |
|
|
.LC_docs_cut { |
.LC_docs_cut { |
color: #550044; |
color: #550044; |
} |
} |
|
|
.LC_docs_rename { |
.LC_docs_rename { |
color: #009900; |
color: #009900; |
} |
} |
|
|
.LC_docs_remove { |
.LC_docs_remove { |
color: #990000; |
color: #990000; |
} |
} |
|
|
|
.LC_domprefs_email, |
.LC_docs_reinit_warn, |
.LC_docs_reinit_warn, |
.LC_docs_ext_edit { |
.LC_docs_ext_edit { |
font-size: x-small; |
font-size: x-small; |
} |
} |
|
|
.LC_docs_editor td.LC_docs_entry_title, |
|
.LC_docs_editor td.LC_docs_entry_icon { |
|
background: #FFFFBB; |
|
} |
|
.LC_docs_editor td.LC_docs_entry_parameter { |
|
background: #BBBBFF; |
|
font-size: x-small; |
|
white-space: nowrap; |
|
} |
|
|
|
table.LC_docs_adddocs td, |
table.LC_docs_adddocs td, |
table.LC_docs_adddocs th { |
table.LC_docs_adddocs th { |
border: 1px solid #BBBBBB; |
border: 1px solid #BBBBBB; |
Line 4506 table.LC_docs_adddocs th {
|
Line 7712 table.LC_docs_adddocs th {
|
background: #DDDDDD; |
background: #DDDDDD; |
} |
} |
|
|
|
table.LC_sty_begin { |
|
background: #BBFFBB; |
|
} |
|
|
|
table.LC_sty_end { |
|
background: #FFBBBB; |
|
} |
|
|
|
table.LC_double_column { |
|
border-width: 0; |
|
border-collapse: collapse; |
|
width: 100%; |
|
padding: 2px; |
|
} |
|
|
|
table.LC_double_column tr td.LC_left_col { |
|
top: 2px; |
|
left: 2px; |
|
width: 47%; |
|
vertical-align: top; |
|
} |
|
|
|
table.LC_double_column tr td.LC_right_col { |
|
top: 2px; |
|
right: 2px; |
|
width: 47%; |
|
vertical-align: top; |
|
} |
|
|
|
div.LC_left_float { |
|
float: left; |
|
padding-right: 5%; |
|
padding-bottom: 4px; |
|
} |
|
|
|
div.LC_clear_float_header { |
|
padding-bottom: 2px; |
|
} |
|
|
|
div.LC_clear_float_footer { |
|
padding-top: 10px; |
|
clear: both; |
|
} |
|
|
|
div.LC_grade_show_user { |
|
/* border-left: 5px solid $sidebg; */ |
|
border-top: 5px solid #000000; |
|
margin: 50px 0 0 0; |
|
padding: 15px 0 5px 10px; |
|
} |
|
|
|
div.LC_grade_show_user_odd_row { |
|
/* border-left: 5px solid #000000; */ |
|
} |
|
|
|
div.LC_grade_show_user div.LC_Box { |
|
margin-right: 50px; |
|
} |
|
|
|
div.LC_grade_submissions, |
|
div.LC_grade_message_center, |
|
div.LC_grade_info_links { |
|
margin: 5px; |
|
width: 99%; |
|
background: #FFFFFF; |
|
} |
|
|
|
div.LC_grade_submissions_header, |
|
div.LC_grade_message_center_header { |
|
font-weight: bold; |
|
font-size: large; |
|
} |
|
|
|
div.LC_grade_submissions_body, |
|
div.LC_grade_message_center_body { |
|
border: 1px solid black; |
|
width: 99%; |
|
background: #FFFFFF; |
|
} |
|
|
|
table.LC_scantron_action { |
|
width: 100%; |
|
} |
|
|
|
table.LC_scantron_action tr th { |
|
font-weight:bold; |
|
font-style:normal; |
|
} |
|
|
|
.LC_edit_problem_header, |
|
div.LC_edit_problem_footer { |
|
font-weight: normal; |
|
font-size: medium; |
|
margin: 2px; |
|
background-color: $sidebg; |
|
} |
|
|
|
div.LC_edit_problem_header, |
|
div.LC_edit_problem_header div, |
|
div.LC_edit_problem_footer, |
|
div.LC_edit_problem_footer div, |
|
div.LC_edit_problem_editxml_header, |
|
div.LC_edit_problem_editxml_header div { |
|
z-index: 100; |
|
} |
|
|
|
div.LC_edit_problem_header_title { |
|
font-weight: bold; |
|
font-size: larger; |
|
background: $tabbg; |
|
padding: 3px; |
|
margin: 0 0 5px 0; |
|
} |
|
|
|
table.LC_edit_problem_header_title { |
|
width: 100%; |
|
background: $tabbg; |
|
} |
|
|
|
div.LC_edit_actionbar { |
|
background-color: $sidebg; |
|
margin: 0; |
|
padding: 0; |
|
line-height: 200%; |
|
} |
|
|
|
div.LC_edit_actionbar div{ |
|
padding: 0; |
|
margin: 0; |
|
display: inline-block; |
|
} |
|
|
|
.LC_edit_opt { |
|
padding-left: 1em; |
|
white-space: nowrap; |
|
} |
|
|
|
.LC_edit_problem_latexhelper{ |
|
text-align: right; |
|
} |
|
|
|
#LC_edit_problem_colorful div{ |
|
margin-left: 40px; |
|
} |
|
|
|
#LC_edit_problem_codemirror div{ |
|
margin-left: 0px; |
|
} |
|
|
|
img.stift { |
|
border-width: 0; |
|
vertical-align: middle; |
|
} |
|
|
|
table td.LC_mainmenu_col_fieldset { |
|
vertical-align: top; |
|
} |
|
|
|
div.LC_createcourse { |
|
margin: 10px 10px 10px 10px; |
|
} |
|
|
|
.LC_dccid { |
|
float: right; |
|
margin: 0.2em 0 0 0; |
|
padding: 0; |
|
font-size: 90%; |
|
display:none; |
|
} |
|
|
|
ol.LC_primary_menu a:hover, |
|
ol#LC_MenuBreadcrumbs a:hover, |
|
ol#LC_PathBreadcrumbs a:hover, |
|
ul#LC_secondary_menu a:hover, |
|
.LC_FormSectionClearButton input:hover |
|
ul.LC_TabContent li:hover a { |
|
color:$button_hover; |
|
text-decoration:none; |
|
} |
|
|
|
h1 { |
|
padding: 0; |
|
line-height:130%; |
|
} |
|
|
|
h2, |
|
h3, |
|
h4, |
|
h5, |
|
h6 { |
|
margin: 5px 0 5px 0; |
|
padding: 0; |
|
line-height:130%; |
|
} |
|
|
|
.LC_hcell { |
|
padding:3px 15px 3px 15px; |
|
margin: 0; |
|
background-color:$tabbg; |
|
color:$fontmenu; |
|
border-bottom:solid 1px $lg_border_color; |
|
} |
|
|
|
.LC_Box > .LC_hcell { |
|
margin: 0 -10px 10px -10px; |
|
} |
|
|
|
.LC_noBorder { |
|
border: 0; |
|
} |
|
|
|
.LC_FormSectionClearButton input { |
|
background-color:transparent; |
|
border: none; |
|
cursor:pointer; |
|
text-decoration:underline; |
|
} |
|
|
|
.LC_help_open_topic { |
|
color: #FFFFFF; |
|
background-color: #EEEEFF; |
|
margin: 1px; |
|
padding: 4px; |
|
border: 1px solid #000033; |
|
white-space: nowrap; |
|
/* vertical-align: middle; */ |
|
} |
|
|
|
dl, |
|
ul, |
|
div, |
|
fieldset { |
|
margin: 10px 10px 10px 0; |
|
/* overflow: hidden; */ |
|
} |
|
|
|
fieldset#LC_selectuser { |
|
margin: 0; |
|
padding: 0; |
|
} |
|
|
|
article.geogebraweb div { |
|
margin: 0; |
|
} |
|
|
|
fieldset > legend { |
|
font-weight: bold; |
|
padding: 0 5px 0 5px; |
|
} |
|
|
|
#LC_nav_bar { |
|
float: left; |
|
background-color: $pgbg_or_bgcolor; |
|
margin: 0 0 2px 0; |
|
} |
|
|
|
#LC_realm { |
|
margin: 0.2em 0 0 0; |
|
padding: 0; |
|
font-weight: bold; |
|
text-align: center; |
|
background-color: $pgbg_or_bgcolor; |
|
} |
|
|
|
#LC_nav_bar em { |
|
font-weight: bold; |
|
font-style: normal; |
|
} |
|
|
|
ol.LC_primary_menu { |
|
margin: 0; |
|
padding: 0; |
|
} |
|
|
|
ol#LC_PathBreadcrumbs { |
|
margin: 0; |
|
} |
|
|
|
ol.LC_primary_menu li { |
|
color: RGB(80, 80, 80); |
|
vertical-align: middle; |
|
text-align: left; |
|
list-style: none; |
|
position: relative; |
|
float: left; |
|
z-index: 100; /* will be displayed above codemirror and underneath the help-layer */ |
|
line-height: 1.5em; |
|
} |
|
|
|
ol.LC_primary_menu li a, |
|
ol.LC_primary_menu li p { |
|
display: block; |
|
margin: 0; |
|
padding: 0 5px 0 10px; |
|
text-decoration: none; |
|
} |
|
|
|
ol.LC_primary_menu li p span.LC_primary_menu_innertitle { |
|
display: inline-block; |
|
width: 95%; |
|
text-align: left; |
|
} |
|
|
|
ol.LC_primary_menu li p span.LC_primary_menu_innerarrow { |
|
display: inline-block; |
|
width: 5%; |
|
float: right; |
|
text-align: right; |
|
font-size: 70%; |
|
} |
|
|
|
ol.LC_primary_menu ul { |
|
display: none; |
|
width: 15em; |
|
background-color: $data_table_light; |
|
position: absolute; |
|
top: 100%; |
|
} |
|
|
|
ol.LC_primary_menu ul ul { |
|
left: 100%; |
|
top: 0; |
|
} |
|
|
|
ol.LC_primary_menu li:hover > ul, ol.LC_primary_menu li.hover > ul { |
|
display: block; |
|
position: absolute; |
|
margin: 0; |
|
padding: 0; |
|
z-index: 2; |
|
} |
|
|
|
ol.LC_primary_menu li:hover li, ol.LC_primary_menu li.hover li { |
|
/* First Submenu -> size should be smaller than the menu title of the whole menu */ |
|
font-size: 90%; |
|
vertical-align: top; |
|
float: none; |
|
border-left: 1px solid black; |
|
border-right: 1px solid black; |
|
/* A dark bottom border to visualize different menu options; |
|
overwritten in the create_submenu routine for the last border-bottom of the menu */ |
|
border-bottom: 1px solid $data_table_dark; |
|
} |
|
|
|
ol.LC_primary_menu li li p:hover { |
|
color:$button_hover; |
|
text-decoration:none; |
|
background-color:$data_table_dark; |
|
} |
|
|
|
ol.LC_primary_menu li li a:hover { |
|
color:$button_hover; |
|
background-color:$data_table_dark; |
|
} |
|
|
|
/* Font-size equal to the size of the predecessors*/ |
|
ol.LC_primary_menu li:hover li li { |
|
font-size: 100%; |
|
} |
|
|
|
ol.LC_primary_menu li img { |
|
vertical-align: bottom; |
|
height: 1.1em; |
|
margin: 0.2em 0 0 0; |
|
} |
|
|
|
ol.LC_primary_menu a { |
|
color: RGB(80, 80, 80); |
|
text-decoration: none; |
|
} |
|
|
|
ol.LC_primary_menu a.LC_new_message { |
|
font-weight:bold; |
|
color: darkred; |
|
} |
|
|
|
ol.LC_docs_parameters { |
|
margin-left: 0; |
|
padding: 0; |
|
list-style: none; |
|
} |
|
|
|
ol.LC_docs_parameters li { |
|
margin: 0; |
|
padding-right: 20px; |
|
display: inline; |
|
} |
|
|
|
ol.LC_docs_parameters li:before { |
|
content: "\\002022 \\0020"; |
|
} |
|
|
|
li.LC_docs_parameters_title { |
|
font-weight: bold; |
|
} |
|
|
|
ol.LC_docs_parameters li.LC_docs_parameters_title:before { |
|
content: ""; |
|
} |
|
|
|
ul#LC_secondary_menu { |
|
clear: right; |
|
color: $fontmenu; |
|
background: $tabbg; |
|
list-style: none; |
|
padding: 0; |
|
margin: 0; |
|
width: 100%; |
|
text-align: left; |
|
float: left; |
|
} |
|
|
|
ul#LC_secondary_menu li { |
|
font-weight: bold; |
|
line-height: 1.8em; |
|
border-right: 1px solid black; |
|
float: left; |
|
} |
|
|
|
ul#LC_secondary_menu li.LC_hoverable:hover, ul#LC_secondary_menu li.hover { |
|
background-color: $data_table_light; |
|
} |
|
|
|
ul#LC_secondary_menu li a { |
|
padding: 0 0.8em; |
|
} |
|
|
|
ul#LC_secondary_menu li ul { |
|
display: none; |
|
} |
|
|
|
ul#LC_secondary_menu li:hover ul, ul#LC_secondary_menu li.hover ul { |
|
display: block; |
|
position: absolute; |
|
margin: 0; |
|
padding: 0; |
|
list-style:none; |
|
float: none; |
|
background-color: $data_table_light; |
|
z-index: 2; |
|
margin-left: -1px; |
|
} |
|
|
|
ul#LC_secondary_menu li ul li { |
|
font-size: 90%; |
|
vertical-align: top; |
|
border-left: 1px solid black; |
|
border-right: 1px solid black; |
|
background-color: $data_table_light; |
|
list-style:none; |
|
float: none; |
|
} |
|
|
|
ul#LC_secondary_menu li ul li:hover, ul#LC_secondary_menu li ul li.hover { |
|
background-color: $data_table_dark; |
|
} |
|
|
|
ul.LC_TabContent { |
|
display:block; |
|
background: $sidebg; |
|
border-bottom: solid 1px $lg_border_color; |
|
list-style:none; |
|
margin: -1px -10px 0 -10px; |
|
padding: 0; |
|
} |
|
|
|
ul.LC_TabContent li, |
|
ul.LC_TabContentBigger li { |
|
float:left; |
|
} |
|
|
|
ul#LC_secondary_menu li a { |
|
color: $fontmenu; |
|
text-decoration: none; |
|
} |
|
|
|
ul.LC_TabContent { |
|
min-height:20px; |
|
} |
|
|
|
ul.LC_TabContent li { |
|
vertical-align:middle; |
|
padding: 0 16px 0 10px; |
|
background-color:$tabbg; |
|
border-bottom:solid 1px $lg_border_color; |
|
border-left: solid 1px $font; |
|
} |
|
|
|
ul.LC_TabContent .right { |
|
float:right; |
|
} |
|
|
|
ul.LC_TabContent li a, |
|
ul.LC_TabContent li { |
|
color:rgb(47,47,47); |
|
text-decoration:none; |
|
font-size:95%; |
|
font-weight:bold; |
|
min-height:20px; |
|
} |
|
|
|
ul.LC_TabContent li a:hover, |
|
ul.LC_TabContent li a:focus { |
|
color: $button_hover; |
|
background:none; |
|
outline:none; |
|
} |
|
|
|
ul.LC_TabContent li:hover { |
|
color: $button_hover; |
|
cursor:pointer; |
|
} |
|
|
|
ul.LC_TabContent li.active { |
|
color: $font; |
|
background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center; |
|
border-bottom:solid 1px #FFFFFF; |
|
cursor: default; |
|
} |
|
|
|
ul.LC_TabContent li.active a { |
|
color:$font; |
|
background:#FFFFFF; |
|
outline: none; |
|
} |
|
|
|
ul.LC_TabContent li.goback { |
|
float: left; |
|
border-left: none; |
|
} |
|
|
|
#maincoursedoc { |
|
clear:both; |
|
} |
|
|
|
ul.LC_TabContentBigger { |
|
display:block; |
|
list-style:none; |
|
padding: 0; |
|
} |
|
|
|
ul.LC_TabContentBigger li { |
|
vertical-align:bottom; |
|
height: 30px; |
|
font-size:110%; |
|
font-weight:bold; |
|
color: #737373; |
|
} |
|
|
|
ul.LC_TabContentBigger li.active { |
|
position: relative; |
|
top: 1px; |
|
} |
|
|
|
ul.LC_TabContentBigger li a { |
|
background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat; |
|
height: 30px; |
|
line-height: 30px; |
|
text-align: center; |
|
display: block; |
|
text-decoration: none; |
|
outline: none; |
|
} |
|
|
|
ul.LC_TabContentBigger li.active a { |
|
background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat; |
|
color:$font; |
|
} |
|
|
|
ul.LC_TabContentBigger li b { |
|
background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom; |
|
display: block; |
|
float: left; |
|
padding: 0 30px; |
|
border-bottom: 1px solid $lg_border_color; |
|
} |
|
|
|
ul.LC_TabContentBigger li:hover b { |
|
color:$button_hover; |
|
} |
|
|
|
ul.LC_TabContentBigger li.active b { |
|
background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat; |
|
color:$font; |
|
border: 0; |
|
} |
|
|
|
|
|
ul.LC_CourseBreadcrumbs { |
|
background: $sidebg; |
|
height: 2em; |
|
padding-left: 10px; |
|
margin: 0; |
|
list-style-position: inside; |
|
} |
|
|
|
ol#LC_MenuBreadcrumbs, |
|
ol#LC_PathBreadcrumbs { |
|
padding-left: 10px; |
|
margin: 0; |
|
height: 2.5em; /* equal to #LC_breadcrumbs line-height */ |
|
} |
|
|
|
ol#LC_MenuBreadcrumbs li, |
|
ol#LC_PathBreadcrumbs li, |
|
ul.LC_CourseBreadcrumbs li { |
|
display: inline; |
|
white-space: normal; |
|
} |
|
|
|
ol#LC_MenuBreadcrumbs li a, |
|
ul.LC_CourseBreadcrumbs li a { |
|
text-decoration: none; |
|
font-size:90%; |
|
} |
|
|
|
ol#LC_MenuBreadcrumbs h1 { |
|
display: inline; |
|
font-size: 90%; |
|
line-height: 2.5em; |
|
margin: 0; |
|
padding: 0; |
|
} |
|
|
|
ol#LC_PathBreadcrumbs li a { |
|
text-decoration:none; |
|
font-size:100%; |
|
font-weight:bold; |
|
} |
|
|
|
.LC_Box { |
|
border: solid 1px $lg_border_color; |
|
padding: 0 10px 10px 10px; |
|
} |
|
|
|
.LC_DocsBox { |
|
border: solid 1px $lg_border_color; |
|
padding: 0 0 10px 10px; |
|
} |
|
|
|
.LC_AboutMe_Image { |
|
float:left; |
|
margin-right:10px; |
|
} |
|
|
|
.LC_Clear_AboutMe_Image { |
|
clear:left; |
|
} |
|
|
|
dl.LC_ListStyleClean dt { |
|
padding-right: 5px; |
|
display: table-header-group; |
|
} |
|
|
|
dl.LC_ListStyleClean dd { |
|
display: table-row; |
|
} |
|
|
|
.LC_ListStyleClean, |
|
.LC_ListStyleSimple, |
|
.LC_ListStyleNormal, |
|
.LC_ListStyleSpecial { |
|
/* display:block; */ |
|
list-style-position: inside; |
|
list-style-type: none; |
|
overflow: hidden; |
|
padding: 0; |
|
} |
|
|
|
.LC_ListStyleSimple li, |
|
.LC_ListStyleSimple dd, |
|
.LC_ListStyleNormal li, |
|
.LC_ListStyleNormal dd, |
|
.LC_ListStyleSpecial li, |
|
.LC_ListStyleSpecial dd { |
|
margin: 0; |
|
padding: 5px 5px 5px 10px; |
|
clear: both; |
|
} |
|
|
|
.LC_ListStyleClean li, |
|
.LC_ListStyleClean dd { |
|
padding-top: 0; |
|
padding-bottom: 0; |
|
} |
|
|
|
.LC_ListStyleSimple dd, |
|
.LC_ListStyleSimple li { |
|
border-bottom: solid 1px $lg_border_color; |
|
} |
|
|
|
.LC_ListStyleSpecial li, |
|
.LC_ListStyleSpecial dd { |
|
list-style-type: none; |
|
background-color: RGB(220, 220, 220); |
|
margin-bottom: 4px; |
|
} |
|
|
|
table.LC_SimpleTable { |
|
margin:5px; |
|
border:solid 1px $lg_border_color; |
|
} |
|
|
|
table.LC_SimpleTable tr { |
|
padding: 0; |
|
border:solid 1px $lg_border_color; |
|
} |
|
|
|
table.LC_SimpleTable thead { |
|
background:rgb(220,220,220); |
|
} |
|
|
|
div.LC_columnSection { |
|
display: block; |
|
clear: both; |
|
overflow: hidden; |
|
margin: 0; |
|
} |
|
|
|
div.LC_columnSection>* { |
|
float: left; |
|
margin: 10px 20px 10px 0; |
|
overflow:hidden; |
|
} |
|
|
|
table em { |
|
font-weight: bold; |
|
font-style: normal; |
|
} |
|
|
|
table.LC_tableBrowseRes, |
|
table.LC_tableOfContent { |
|
border:none; |
|
border-spacing: 1px; |
|
padding: 3px; |
|
background-color: #FFFFFF; |
|
font-size: 90%; |
|
} |
|
|
|
table.LC_tableOfContent { |
|
border-collapse: collapse; |
|
} |
|
|
|
table.LC_tableBrowseRes a, |
|
table.LC_tableOfContent a { |
|
background-color: transparent; |
|
text-decoration: none; |
|
} |
|
|
|
table.LC_tableOfContent img { |
|
border: none; |
|
height: 1.3em; |
|
vertical-align: text-bottom; |
|
margin-right: 0.3em; |
|
} |
|
|
|
a#LC_content_toolbar_firsthomework { |
|
background-image:url(/res/adm/pages/open-first-problem.gif); |
|
} |
|
|
|
a#LC_content_toolbar_everything { |
|
background-image:url(/res/adm/pages/show-all.gif); |
|
} |
|
|
|
a#LC_content_toolbar_uncompleted { |
|
background-image:url(/res/adm/pages/show-incomplete-problems.gif); |
|
} |
|
|
|
#LC_content_toolbar_clearbubbles { |
|
background-image:url(/res/adm/pages/mark-discussionentries-read.gif); |
|
} |
|
|
|
a#LC_content_toolbar_changefolder { |
|
background : url(/res/adm/pages/close-all-folders.gif) top center ; |
|
} |
|
|
|
a#LC_content_toolbar_changefolder_toggled { |
|
background-image:url(/res/adm/pages/open-all-folders.gif); |
|
} |
|
|
|
a#LC_content_toolbar_edittoplevel { |
|
background-image:url(/res/adm/pages/edittoplevel.gif); |
|
} |
|
|
|
a#LC_content_toolbar_printout { |
|
background-image:url(/res/adm/pages/printout.gif); |
|
} |
|
|
|
ul#LC_toolbar li a:hover { |
|
background-position: bottom center; |
|
} |
|
|
|
ul#LC_toolbar { |
|
padding: 0; |
|
margin: 2px; |
|
list-style:none; |
|
position:relative; |
|
background-color:white; |
|
overflow: auto; |
|
} |
|
|
|
ul#LC_toolbar li { |
|
border:1px solid white; |
|
padding: 0; |
|
margin: 0; |
|
float: left; |
|
display:inline; |
|
vertical-align:middle; |
|
white-space: nowrap; |
|
} |
|
|
|
|
|
a.LC_toolbarItem { |
|
display:block; |
|
padding: 0; |
|
margin: 0; |
|
height: 32px; |
|
width: 32px; |
|
color:white; |
|
border: none; |
|
background-repeat:no-repeat; |
|
background-color:transparent; |
|
} |
|
|
|
ul.LC_funclist { |
|
margin: 0; |
|
padding: 0.5em 1em 0.5em 0; |
|
} |
|
|
|
ul.LC_funclist > li:first-child { |
|
font-weight:bold; |
|
margin-left:0.8em; |
|
} |
|
|
|
ul.LC_funclist + ul.LC_funclist { |
|
/* |
|
left border as a seperator if we have more than |
|
one list |
|
*/ |
|
border-left: 1px solid $sidebg; |
|
/* |
|
this hides the left border behind the border of the |
|
outer box if element is wrapped to the next 'line' |
|
*/ |
|
margin-left: -1px; |
|
} |
|
|
|
ul.LC_funclist li { |
|
display: inline; |
|
white-space: nowrap; |
|
margin: 0 0 0 25px; |
|
line-height: 150%; |
|
} |
|
|
|
.LC_hidden { |
|
display: none; |
|
} |
|
|
|
.LCmodal-overlay { |
|
position:fixed; |
|
top:0; |
|
right:0; |
|
bottom:0; |
|
left:0; |
|
height:100%; |
|
width:100%; |
|
margin:0; |
|
padding:0; |
|
background:#999; |
|
opacity:.75; |
|
filter: alpha(opacity=75); |
|
-moz-opacity: 0.75; |
|
z-index:101; |
|
} |
|
|
|
* html .LCmodal-overlay { |
|
position: absolute; |
|
height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px'); |
|
} |
|
|
|
.LCmodal-window { |
|
position:fixed; |
|
top:50%; |
|
left:50%; |
|
margin:0; |
|
padding:0; |
|
z-index:102; |
|
} |
|
|
|
* html .LCmodal-window { |
|
position:absolute; |
|
} |
|
|
|
.LCclose-window { |
|
position:absolute; |
|
width:32px; |
|
height:32px; |
|
right:8px; |
|
top:8px; |
|
background:transparent url('/res/adm/pages/process-stop.png') no-repeat scroll right top; |
|
text-indent:-99999px; |
|
overflow:hidden; |
|
cursor:pointer; |
|
} |
|
|
|
.LCisDisabled { |
|
cursor: not-allowed; |
|
opacity: 0.5; |
|
} |
|
|
|
a[aria-disabled="true"] { |
|
color: currentColor; |
|
display: inline-block; /* For IE11/ MS Edge bug */ |
|
pointer-events: none; |
|
text-decoration: none; |
|
} |
|
|
|
pre.LC_wordwrap { |
|
white-space: pre-wrap; |
|
white-space: -moz-pre-wrap; |
|
white-space: -pre-wrap; |
|
white-space: -o-pre-wrap; |
|
word-wrap: break-word; |
|
} |
|
|
|
/* |
|
styles used for response display |
|
*/ |
|
div.LC_radiofoil, div.LC_rankfoil { |
|
margin: .5em 0em .5em 0em; |
|
} |
|
table.LC_itemgroup { |
|
margin-top: 1em; |
|
} |
|
|
|
/* |
|
styles used by TTH when "Default set of options to pass to tth/m |
|
when converting TeX" in course settings has been set |
|
|
|
option passed: -t |
|
|
|
*/ |
|
|
|
td div.comp { margin-top: -0.6ex; margin-bottom: -1ex;} |
|
td div.comb { margin-top: -0.6ex; margin-bottom: -.6ex;} |
|
td div.hrcomp { line-height: 0.9; margin-top: -0.8ex; margin-bottom: -1ex;} |
|
td div.norm {line-height:normal;} |
|
|
|
/* |
|
option passed -y3 |
|
*/ |
|
|
|
span.roman {font-family: serif; font-style: normal; font-weight: normal;} |
|
span.overacc2 {position: relative; left: .8em; top: -1.2ex;} |
|
span.overacc1 {position: relative; left: .6em; top: -1.2ex;} |
|
|
|
/* |
|
sections with roles, for content only |
|
*/ |
|
section[class^="role-"] { |
|
padding-left: 10px; |
|
padding-right: 5px; |
|
margin-top: 8px; |
|
margin-bottom: 8px; |
|
border: 1px solid #2A4; |
|
border-radius: 5px; |
|
box-shadow: 0px 1px 1px #BBB; |
|
} |
|
section[class^="role-"]>h1 { |
|
position: relative; |
|
margin: 0px; |
|
padding-top: 10px; |
|
padding-left: 40px; |
|
} |
|
section[class^="role-"]>h1:before { |
|
position: absolute; |
|
left: -5px; |
|
top: 5px; |
|
} |
|
section.role-activity>h1:before { |
|
content:url('/adm/daxe/images/section_icons/activity.png'); |
|
} |
|
section.role-advice>h1:before { |
|
content:url('/adm/daxe/images/section_icons/advice.png'); |
|
} |
|
section.role-bibliography>h1:before { |
|
content:url('/adm/daxe/images/section_icons/bibliography.png'); |
|
} |
|
section.role-citation>h1:before { |
|
content:url('/adm/daxe/images/section_icons/citation.png'); |
|
} |
|
section.role-conclusion>h1:before { |
|
content:url('/adm/daxe/images/section_icons/conclusion.png'); |
|
} |
|
section.role-definition>h1:before { |
|
content:url('/adm/daxe/images/section_icons/definition.png'); |
|
} |
|
section.role-demonstration>h1:before { |
|
content:url('/adm/daxe/images/section_icons/demonstration.png'); |
|
} |
|
section.role-example>h1:before { |
|
content:url('/adm/daxe/images/section_icons/example.png'); |
|
} |
|
section.role-explanation>h1:before { |
|
content:url('/adm/daxe/images/section_icons/explanation.png'); |
|
} |
|
section.role-introduction>h1:before { |
|
content:url('/adm/daxe/images/section_icons/introduction.png'); |
|
} |
|
section.role-method>h1:before { |
|
content:url('/adm/daxe/images/section_icons/method.png'); |
|
} |
|
section.role-more_information>h1:before { |
|
content:url('/adm/daxe/images/section_icons/more_information.png'); |
|
} |
|
section.role-objectives>h1:before { |
|
content:url('/adm/daxe/images/section_icons/objectives.png'); |
|
} |
|
section.role-prerequisites>h1:before { |
|
content:url('/adm/daxe/images/section_icons/prerequisites.png'); |
|
} |
|
section.role-remark>h1:before { |
|
content:url('/adm/daxe/images/section_icons/remark.png'); |
|
} |
|
section.role-reminder>h1:before { |
|
content:url('/adm/daxe/images/section_icons/reminder.png'); |
|
} |
|
section.role-summary>h1:before { |
|
content:url('/adm/daxe/images/section_icons/summary.png'); |
|
} |
|
section.role-syntax>h1:before { |
|
content:url('/adm/daxe/images/section_icons/syntax.png'); |
|
} |
|
section.role-warning>h1:before { |
|
content:url('/adm/daxe/images/section_icons/warning.png'); |
|
} |
|
|
|
#LC_minitab_header { |
|
float:left; |
|
width:100%; |
|
background:#DAE0D2 url("/res/adm/pages/minitabmenu_bg.gif") repeat-x bottom; |
|
font-size:93%; |
|
line-height:normal; |
|
margin: 0.5em 0 0.5em 0; |
|
} |
|
#LC_minitab_header ul { |
|
margin:0; |
|
padding:10px 10px 0; |
|
list-style:none; |
|
} |
|
#LC_minitab_header li { |
|
float:left; |
|
background:url("/res/adm/pages/minitabmenu_left.gif") no-repeat left top; |
|
margin:0; |
|
padding:0 0 0 9px; |
|
} |
|
#LC_minitab_header a { |
|
display:block; |
|
background:url("/res/adm/pages/minitabmenu_right.gif") no-repeat right top; |
|
padding:5px 15px 4px 6px; |
|
} |
|
#LC_minitab_header #LC_current_minitab { |
|
background-image:url("/res/adm/pages/minitabmenu_left_on.gif"); |
|
} |
|
#LC_minitab_header #LC_current_minitab a { |
|
background-image:url("/res/adm/pages/minitabmenu_right_on.gif"); |
|
padding-bottom:5px; |
|
} |
|
|
|
|
END |
END |
} |
} |
|
|
Line 4526 Inputs: $title - optional title for the
|
Line 8802 Inputs: $title - optional title for the
|
3- whether the side effect should occur |
3- whether the side effect should occur |
(side effect of setting |
(side effect of setting |
$env{'internal.head.redirect'} to the url |
$env{'internal.head.redirect'} to the url |
redirected too) |
redirected to) |
|
4- whether the redirect target should be |
|
the opener of the current (pop-up) |
|
window (side effect of setting |
|
$env{'internal.head.to_opener'} to |
|
1, if true. |
|
5- whether encrypt check should be skipped |
domain -> force to color decorate a page for a specific |
domain -> force to color decorate a page for a specific |
domain |
domain |
function -> force usage of a specific rolish color scheme |
function -> force usage of a specific rolish color scheme |
Line 4542 sub headtag {
|
Line 8824 sub headtag {
|
my $function = $args->{'function'} || &get_users_function(); |
my $function = $args->{'function'} || &get_users_function(); |
my $domain = $args->{'domain'} || &determinedomain(); |
my $domain = $args->{'domain'} || &determinedomain(); |
my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain); |
my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain); |
|
my $httphost = $args->{'use_absolute'}; |
my $url = join(':',$env{'user.name'},$env{'user.domain'}, |
my $url = join(':',$env{'user.name'},$env{'user.domain'}, |
$Apache::lonnet::perlvar{'lonVersion'}, |
$Apache::lonnet::perlvar{'lonVersion'}, |
#time(), |
#time(), |
Line 4552 sub headtag {
|
Line 8835 sub headtag {
|
|
|
my $result = |
my $result = |
'<head>'. |
'<head>'. |
&font_settings(); |
&font_settings($args); |
|
|
|
my $inhibitprint; |
|
if ($args->{'print_suppress'}) { |
|
$inhibitprint = &print_suppression(); |
|
} |
|
|
if (!$args->{'frameset'}) { |
if (!$args->{'frameset'}) { |
$result .= &Apache::lonhtmlcommon::htmlareaheaders(); |
$result .= &Apache::lonhtmlcommon::htmlareaheaders(); |
} |
} |
if ($args->{'force_register'}) { |
if ($args->{'force_register'}) { |
$result .= &Apache::lonmenu::registerurl(1); |
$result .= &Apache::lonmenu::registerurl(1); |
} |
} |
if (!$args->{'no_nav_bar'} |
if (!$args->{'no_nav_bar'} |
&& !$args->{'only_body'} |
&& !$args->{'only_body'} |
&& !$args->{'frameset'}) { |
&& !$args->{'frameset'}) { |
$result .= &help_menu_js(); |
$result .= &help_menu_js($httphost); |
|
$result.=&modal_window(); |
|
$result.=&togglebox_script(); |
|
$result.=&wishlist_window(); |
|
$result.=&LCprogressbarUpdate_script(); |
|
} else { |
|
if ($args->{'add_modal'}) { |
|
$result.=&modal_window(); |
|
} |
|
if ($args->{'add_wishlist'}) { |
|
$result.=&wishlist_window(); |
|
} |
|
if ($args->{'add_togglebox'}) { |
|
$result.=&togglebox_script(); |
|
} |
|
if ($args->{'add_progressbar'}) { |
|
$result.=&LCprogressbarUpdate_script(); |
|
} |
} |
} |
|
|
if (ref($args->{'redirect'})) { |
if (ref($args->{'redirect'})) { |
my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}}; |
my ($time,$url,$inhibit_continue,$to_opener,$skip_enc_check) = @{$args->{'redirect'}}; |
$url = &Apache::lonenc::check_encrypt($url); |
if (!$skip_enc_check) { |
|
$url = &Apache::lonenc::check_encrypt($url); |
|
} |
if (!$inhibit_continue) { |
if (!$inhibit_continue) { |
$env{'internal.head.redirect'} = $url; |
$env{'internal.head.redirect'} = $url; |
} |
} |
$result.=<<ADDMETA |
$result.=<<"ADDMETA"; |
<meta http-equiv="pragma" content="no-cache" /> |
<meta http-equiv="pragma" content="no-cache" /> |
|
ADDMETA |
|
if ($to_opener) { |
|
$env{'internal.head.to_opener'} = 1; |
|
my $dest = &js_escape($url); |
|
my $timeout = int($time * 1000); |
|
$result .=<<"ENDJS"; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
function LC_To_Opener() { |
|
var dest = '$dest'; |
|
if (dest != '') { |
|
if (window.opener != null && !window.opener.closed) { |
|
window.opener.location.href=dest; |
|
window.close(); |
|
} else { |
|
window.location.href=dest; |
|
} |
|
} |
|
} |
|
\$(document).ready(function () { |
|
setTimeout('LC_To_Opener()',$timeout); |
|
}); |
|
// ]]> |
|
</script> |
|
ENDJS |
|
} else { |
|
$result.=<<"ADDMETA"; |
<meta http-equiv="Refresh" content="$time; url=$url" /> |
<meta http-equiv="Refresh" content="$time; url=$url" /> |
ADDMETA |
ADDMETA |
|
} |
|
} else { |
|
unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) { |
|
my $requrl = $env{'request.uri'}; |
|
if ($requrl eq '') { |
|
$requrl = $ENV{'REQUEST_URI'}; |
|
$requrl =~ s/\?.+$//; |
|
} |
|
unless (($requrl =~ m{^/adm/(?:switchserver|login|authenticate|logout|groupsort|cleanup|helper|slotrequest|grades)(\?|$)}) || |
|
(($requrl =~ m{^/res/}) && (($env{'form.submitted'} eq 'scantron') || |
|
($env{'form.grade_symb'}) || ($Apache::lonhomework::scantronmode)))) { |
|
my $dom_in_use = $Apache::lonnet::perlvar{'lonDefDomain'}; |
|
unless (&Apache::lonnet::allowed('mau',$dom_in_use)) { |
|
my %domdefs = &Apache::lonnet::get_domain_defaults($dom_in_use); |
|
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; |
|
my ($offload,$offloadoth); |
|
if (ref($domdefs{'offloadnow'}) eq 'HASH') { |
|
if ($domdefs{'offloadnow'}{$lonhost}) { |
|
$offload = 1; |
|
if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) && |
|
(!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) { |
|
unless (&Apache::lonnet::shared_institution($env{'user.domain'})) { |
|
$offloadoth = 1; |
|
$dom_in_use = $env{'user.domain'}; |
|
} |
|
} |
|
} |
|
} |
|
unless ($offload) { |
|
if (ref($domdefs{'offloadoth'}) eq 'HASH') { |
|
if ($domdefs{'offloadoth'}{$lonhost}) { |
|
if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne $dom_in_use) && |
|
(!(($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')))) { |
|
unless (&Apache::lonnet::shared_institution($env{'user.domain'})) { |
|
$offload = 1; |
|
$offloadoth = 1; |
|
$dom_in_use = $env{'user.domain'}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ($offload) { |
|
my $newserver = &Apache::lonnet::spareserver(undef,30000,undef,1,$dom_in_use); |
|
if (($newserver eq '') && ($offloadoth)) { |
|
my @domains = &Apache::lonnet::current_machine_domains(); |
|
if (($dom_in_use ne '') && (!grep(/^\Q$dom_in_use\E$/,@domains))) { |
|
($newserver) = &Apache::lonnet::choose_server($dom_in_use); |
|
} |
|
} |
|
if (($newserver) && ($newserver ne $lonhost)) { |
|
my $numsec = 5; |
|
my $timeout = $numsec * 1000; |
|
my ($newurl,$locknum,%locks,$msg); |
|
if ($env{'request.role.adv'}) { |
|
($locknum,%locks) = &Apache::lonnet::get_locks(); |
|
} |
|
my $disable_submit = 0; |
|
if ($requrl =~ /$LONCAPA::assess_re/) { |
|
$disable_submit = 1; |
|
} |
|
if ($locknum) { |
|
my @lockinfo = sort(values(%locks)); |
|
$msg = &mt('Once the following tasks are complete:')." \n". |
|
join(", ",sort(values(%locks)))."\n"; |
|
if (&show_course()) { |
|
$msg .= &mt('your session will be transferred to a different server, after you click "Courses".'); |
|
} else { |
|
$msg .= &mt('your session will be transferred to a different server, after you click "Roles".'); |
|
} |
|
} else { |
|
if (($requrl =~ m{^/res/}) && ($env{'form.submitted'} =~ /^part_/)) { |
|
$msg = &mt('Your LON-CAPA submission has been recorded')."\n"; |
|
} |
|
$msg .= &mt('Your current LON-CAPA session will be transferred to a different server in [quant,_1,second].',$numsec); |
|
$newurl = '/adm/switchserver?otherserver='.$newserver; |
|
if (($env{'request.role'}) && ($env{'request.role'} ne 'cm')) { |
|
$newurl .= '&role='.$env{'request.role'}; |
|
} |
|
if ($env{'request.symb'}) { |
|
my $shownsymb = &Apache::lonenc::check_encrypt($env{'request.symb'}); |
|
if ($shownsymb =~ m{^/enc/}) { |
|
my $reqdmajor = 2; |
|
my $reqdminor = 11; |
|
my $reqdsubminor = 3; |
|
my $newserverrev = &Apache::lonnet::get_server_loncaparev('',$newserver); |
|
my $remoterev = &Apache::lonnet::get_server_loncaparev(undef,$newserver); |
|
my ($major,$minor,$subminor) = ($remoterev =~ /^\'?(\d+)\.(\d+)\.(\d+|)[\w.\-]+\'?$/); |
|
if (($major eq '' && $minor eq '') || |
|
(($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)) || |
|
(($reqdmajor == $major) && ($reqdminor == $minor) && (($subminor eq '') || |
|
($reqdsubminor > $subminor))))) { |
|
undef($shownsymb); |
|
} |
|
} |
|
if ($shownsymb) { |
|
&js_escape(\$shownsymb); |
|
$newurl .= '&symb='.$shownsymb; |
|
} |
|
} else { |
|
my $shownurl = &Apache::lonenc::check_encrypt($requrl); |
|
&js_escape(\$shownurl); |
|
$newurl .= '&origurl='.$shownurl; |
|
} |
|
} |
|
&js_escape(\$msg); |
|
$result.=<<OFFLOAD |
|
<meta http-equiv="pragma" content="no-cache" /> |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
function LC_Offload_Now() { |
|
var dest = "$newurl"; |
|
if (dest != '') { |
|
window.location.href="$newurl"; |
|
} |
|
} |
|
\$(document).ready(function () { |
|
window.alert('$msg'); |
|
if ($disable_submit) { |
|
\$(".LC_hwk_submit").prop("disabled", true); |
|
\$( ".LC_textline" ).prop( "readonly", "readonly"); |
|
} |
|
setTimeout('LC_Offload_Now()', $timeout); |
|
}); |
|
// ]]> |
|
</script> |
|
OFFLOAD |
|
} |
|
} |
|
} |
|
} |
|
} |
} |
} |
if (!defined($title)) { |
if (!defined($title)) { |
$title = 'The LearningOnline Network with CAPA'; |
$title = 'The LearningOnline Network with CAPA'; |
} |
} |
if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } |
if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } |
$result .= '<title> LON-CAPA '.$title.'</title>' |
$result .= '<title> LON-CAPA '.$title.'</title>' |
.'<link rel="stylesheet" type="text/css" href="'.$url.'" />' |
.'<link rel="stylesheet" type="text/css" href="'.$url.'"'; |
|
if (!$args->{'frameset'}) { |
|
$result .= ' /'; |
|
} |
|
$result .= '>' |
|
.$inhibitprint |
.$head_extra; |
.$head_extra; |
return $result; |
my $clientmobile; |
|
if (($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) { |
|
(undef,undef,undef,undef,undef,undef,$clientmobile) = &decode_user_agent(); |
|
} else { |
|
$clientmobile = $env{'browser.mobile'}; |
|
} |
|
if ($clientmobile) { |
|
$result .= ' |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0"> |
|
<meta name="apple-mobile-web-app-capable" content="yes" />'; |
|
} |
|
$result .= '<meta name="google" content="notranslate" />'."\n"; |
|
return $result.'</head>'; |
} |
} |
|
|
=pod |
=pod |
Line 4593 ADDMETA
|
Line 9075 ADDMETA
|
|
|
Returns neccessary <meta> to set the proper encoding |
Returns neccessary <meta> to set the proper encoding |
|
|
Inputs: none |
Inputs: optional reference to HASH -- $args passed to &headtag() |
|
|
=cut |
=cut |
|
|
sub font_settings { |
sub font_settings { |
|
my ($args) = @_; |
my $headerstring=''; |
my $headerstring=''; |
if (($env{'browser.os'} eq 'mac') && (!$env{'browser.mathml'})) { |
if ((!$env{'browser.mathml'} && $env{'browser.unicode'}) || |
$headerstring.= |
((ref($args) eq 'HASH') && ($args->{'browser.unicode'}))) { |
'<meta Content-Type="text/html; charset=x-mac-roman" />'; |
|
} elsif (!$env{'browser.mathml'} && $env{'browser.unicode'}) { |
|
$headerstring.= |
$headerstring.= |
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />'; |
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8"'; |
|
if (!$args->{'frameset'}) { |
|
$headerstring.= ' /'; |
|
} |
|
$headerstring .= '>'."\n"; |
} |
} |
return $headerstring; |
return $headerstring; |
} |
} |
|
|
=pod |
=pod |
|
|
|
=item * &print_suppression() |
|
|
|
In course context returns css which causes the body to be blank when media="print", |
|
if printout generation is unavailable for the current resource. |
|
|
|
This could be because: |
|
|
|
(a) printstartdate is in the future |
|
|
|
(b) printenddate is in the past |
|
|
|
(c) there is an active exam block with "printout" |
|
functionality blocked |
|
|
|
Users with pav, pfo or evb privileges are exempt. |
|
|
|
Inputs: none |
|
|
|
=cut |
|
|
|
|
|
sub print_suppression { |
|
my $noprint; |
|
if ($env{'request.course.id'}) { |
|
my $scope = $env{'request.course.id'}; |
|
if ((&Apache::lonnet::allowed('pav',$scope)) || |
|
(&Apache::lonnet::allowed('pfo',$scope))) { |
|
return; |
|
} |
|
if ($env{'request.course.sec'} ne '') { |
|
$scope .= "/$env{'request.course.sec'}"; |
|
if ((&Apache::lonnet::allowed('pav',$scope)) || |
|
(&Apache::lonnet::allowed('pfo',$scope))) { |
|
return; |
|
} |
|
} |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $clientip = &Apache::lonnet::get_requestor_ip(); |
|
my $blocked = &blocking_status('printout',$clientip,$cnum,$cdom,undef,1); |
|
if ($blocked) { |
|
my $checkrole = "cm./$cdom/$cnum"; |
|
if ($env{'request.course.sec'} ne '') { |
|
$checkrole .= "/$env{'request.course.sec'}"; |
|
} |
|
unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && |
|
($env{'request.role'} !~ m{^st\./$cdom/$cnum})) { |
|
$noprint = 1; |
|
} |
|
} |
|
unless ($noprint) { |
|
my $symb = &Apache::lonnet::symbread(); |
|
if ($symb ne '') { |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (ref($navmap)) { |
|
my $res = $navmap->getBySymb($symb); |
|
if (ref($res)) { |
|
if (!$res->resprintable()) { |
|
$noprint = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ($noprint) { |
|
return <<"ENDSTYLE"; |
|
<style type="text/css" media="print"> |
|
body { display:none } |
|
</style> |
|
ENDSTYLE |
|
} |
|
} |
|
return; |
|
} |
|
|
|
=pod |
|
|
=item * &xml_begin() |
=item * &xml_begin() |
|
|
Returns the needed doctype and <html> |
Returns the needed doctype and <html> |
Line 4620 Inputs: none
|
Line 9182 Inputs: none
|
=cut |
=cut |
|
|
sub xml_begin { |
sub xml_begin { |
|
my ($is_frameset) = @_; |
my $output=''; |
my $output=''; |
|
|
&Apache::lonhtmlcommon::init_htmlareafields(); |
|
|
|
if ($env{'browser.mathml'}) { |
if ($env{'browser.mathml'}) { |
$output='<?xml version="1.0"?>' |
$output='<?xml version="1.0"?>' |
#.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n" |
#.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n" |
Line 4633 sub xml_begin {
|
Line 9194 sub xml_begin {
|
.'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">' |
.'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">' |
.'<html xmlns:math="http://www.w3.org/1998/Math/MathML" ' |
.'<html xmlns:math="http://www.w3.org/1998/Math/MathML" ' |
.'xmlns="http://www.w3.org/1999/xhtml">'; |
.'xmlns="http://www.w3.org/1999/xhtml">'; |
|
} elsif ($is_frameset) { |
|
$output='<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'."\n". |
|
'<html>'."\n"; |
} else { |
} else { |
$output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>'; |
$output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n". |
|
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">'."\n"; |
} |
} |
return $output; |
return $output; |
} |
} |
|
|
=pod |
=pod |
|
|
=item * &endheadtag() |
=item * &start_page() |
|
|
Returns a uniform </head> for LON-CAPA web pages. |
|
|
|
Inputs: none |
|
|
|
=cut |
|
|
|
sub endheadtag { |
|
return '</head>'; |
|
} |
|
|
|
=pod |
|
|
|
=item * &head() |
|
|
|
Returns a uniform complete <head>..</head> section for LON-CAPA web pages. |
Returns a complete <html> .. <body> section for LON-CAPA web pages. |
|
|
Inputs: $title - optional title for the page |
Inputs: |
$head_extra - optional extra HTML to put inside the <head> |
|
|
|
=cut |
=over 4 |
|
|
sub head { |
$title - optional title for the page |
my ($title,$head_extra,$args) = @_; |
|
return &headtag($title,$head_extra,$args).&endheadtag(); |
|
} |
|
|
|
=pod |
$head_extra - optional extra HTML to incude inside the <head> |
|
|
=item * &start_page() |
$args - additional optional args supported are: |
|
|
Returns a complete <html> .. <body> section for LON-CAPA web pages. |
=over 8 |
|
|
Inputs: $title - optional title for the page |
only_body -> is true will set &bodytag() onlybodytag |
$head_extra - optional extra HTML to incude inside the <head> |
|
$args - additional optional args supported are: |
|
only_body -> is true will set &bodytag() onlybodytag |
|
arg on |
arg on |
no_nav_bar -> is true will set &bodytag() notopbar arg on |
no_nav_bar -> is true will set &bodytag() no_nav_bar arg on |
add_entries -> additional attributes to add to the <body> |
add_entries -> additional attributes to add to the <body> |
domain -> force to color decorate a page for a |
domain -> force to color decorate a page for a |
specific domain |
specific domain |
function -> force usage of a specific rolish color |
function -> force usage of a specific rolish color |
scheme |
scheme |
redirect -> see &headtag() |
redirect -> see &headtag() |
bgcolor -> override the default page bg color |
bgcolor -> override the default page bg color |
js_ready -> return a string ready for being used in |
js_ready -> return a string ready for being used in |
a javascript writeln |
a javascript writeln |
html_encode -> return a string ready for being used in |
html_encode -> return a string ready for being used in |
a html attribute |
a html attribute |
force_register -> if is true will turn on the &bodytag() |
force_register -> if is true will turn on the &bodytag() |
$forcereg arg |
$forcereg arg |
body_title -> alternate text to use instead of $title |
frameset -> if true will start with a <frameset> |
in the title box that appears, this text |
|
is not auto translated like the $title is |
|
frameset -> if true will start with a <frameset> |
|
rather than <body> |
rather than <body> |
no_title -> if true the title bar won't be shown |
skip_phases -> hash ref of |
skip_phases -> hash ref of |
|
head -> skip the <html><head> generation |
head -> skip the <html><head> generation |
body -> skip all <body> generation |
body -> skip all <body> generation |
|
no_inline_link -> if true and in remote mode, don't show the |
no_inline_link -> if true and in remote mode, don't show the |
|
'Switch To Inline Menu' link |
'Switch To Inline Menu' link |
|
no_auto_mt_title -> prevent &mt()ing the title arg |
|
bread_crumbs -> Array containing breadcrumbs |
|
bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs |
|
bread_crumbs_nomenu -> if true will pass false as the value of $menulink |
|
to lonhtmlcommon::breadcrumbs |
|
group -> includes the current group, if page is for a |
|
specific group |
|
use_absolute -> for request for external resource or syllabus, this |
|
will contain https://<hostname> if server uses |
|
https (as per hosts.tab), but request is for http |
|
hostname -> hostname, originally from $r->hostname(), (optional). |
|
links_disabled -> Links in primary and secondary menus are disabled |
|
(Can enable them once page has loaded - see lonroles.pm |
|
for an example). |
|
links_target -> Target for links, e.g., _parent (optional). |
|
|
no_auto_mt_title -> prevent &mt()ing the title arg |
=back |
|
|
|
=back |
|
|
=cut |
=cut |
|
|
sub start_page { |
sub start_page { |
my ($title,$head_extra,$args) = @_; |
my ($title,$head_extra,$args) = @_; |
#&Apache::lonnet::logthis("start_page ".join(':',caller(0))); |
#&Apache::lonnet::logthis("start_page ".join(':',caller(0))); |
my %head_args; |
|
foreach my $arg ('redirect','force_register','domain','function', |
|
'bgcolor','frameset','no_nav_bar','only_body', |
|
'no_auto_mt_title') { |
|
if (defined($args->{$arg})) { |
|
$head_args{$arg} = $args->{$arg}; |
|
} |
|
} |
|
|
|
$env{'internal.start_page'}++; |
$env{'internal.start_page'}++; |
my $result; |
my ($result,@advtools,$ltiscope,$ltiuri,%ltimenu,$menucoll,%menu); |
|
|
if (! exists($args->{'skip_phases'}{'head'}) ) { |
if (! exists($args->{'skip_phases'}{'head'}) ) { |
$result.= |
$result .= &xml_begin($args->{'frameset'}) . &headtag($title, $head_extra, $args); |
&xml_begin(). |
|
&headtag($title,$head_extra,\%head_args).&endheadtag(); |
|
} |
} |
|
|
|
if (($env{'request.course.id'}) && ($env{'request.lti.login'})) { |
|
if ($env{'course.'.$env{'request.course.id'}.'.lti.override'}) { |
|
unless ($env{'course.'.$env{'request.course.id'}.'.lti.topmenu'}) { |
|
$args->{'no_primary_menu'} = 1; |
|
} |
|
unless ($env{'course.'.$env{'request.course.id'}.'.lti.inlinemenu'}) { |
|
$args->{'no_inline_menu'} = 1; |
|
} |
|
if ($env{'course.'.$env{'request.course.id'}.'.lti.lcmenu'}) { |
|
map { $ltimenu{$_} = 1; } split(/,/,$env{'course.'.$env{'request.course.id'}.'.lti.lcmenu'}); |
|
} |
|
} else { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider'); |
|
if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') { |
|
unless ($lti{$env{'request.lti.login'}}{'topmenu'}) { |
|
$args->{'no_primary_menu'} = 1; |
|
} |
|
unless ($lti{$env{'request.lti.login'}}{'inlinemenu'}) { |
|
$args->{'no_inline_menu'} = 1; |
|
} |
|
if (ref($lti{$env{'request.lti.login'}}{'lcmenu'}) eq 'ARRAY') { |
|
map { $ltimenu{$_} = 1; } @{$lti{$env{'request.lti.login'}}{'lcmenu'}}; |
|
} |
|
} |
|
} |
|
($ltiscope,$ltiuri) = &LONCAPA::ltiutils::lti_provider_scope($env{'request.lti.uri'}, |
|
$env{'course.'.$env{'request.course.id'}.'.domain'}, |
|
$env{'course.'.$env{'request.course.id'}.'.num'}); |
|
} elsif ($env{'request.course.id'}) { |
|
my $expiretime=600; |
|
if ((time-$env{'course.'.$env{'request.course.id'}.'.last_cache'}) > $expiretime) { |
|
&Apache::lonnet::coursedescription($env{'request.course.id'},{'freshen_cache' => 1}); |
|
} |
|
my ($deeplinkmenu,$menuref); |
|
($menucoll,$deeplinkmenu,$menuref) = &menucoll_in_effect(); |
|
if ($menucoll) { |
|
if (ref($menuref) eq 'HASH') { |
|
%menu = %{$menuref}; |
|
} |
|
if ($menu{'top'} eq 'n') { |
|
$args->{'no_primary_menu'} = 1; |
|
} |
|
if ($menu{'inline'} eq 'n') { |
|
unless (&Apache::lonnet::allowed('opa')) { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $crstype = &course_type(); |
|
my $now = time; |
|
my $ccrole; |
|
if ($crstype eq 'Community') { |
|
$ccrole = 'co'; |
|
} else { |
|
$ccrole = 'cc'; |
|
} |
|
if ($env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum}) { |
|
my ($start,$end) = split(/\./,$env{'user.role.'.$ccrole.'./'.$cdom.'/'.$cnum}); |
|
if ((($start) && ($start<0)) || |
|
(($end) && ($end<$now)) || |
|
(($start) && ($now<$start))) { |
|
$args->{'no_inline_menu'} = 1; |
|
} |
|
} else { |
|
$args->{'no_inline_menu'} = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
my $showncrumbs; |
if (! exists($args->{'skip_phases'}{'body'}) ) { |
if (! exists($args->{'skip_phases'}{'body'}) ) { |
if ($args->{'frameset'}) { |
if ($args->{'frameset'}) { |
my $attr_string = &make_attr_string($args->{'force_register'}, |
my $attr_string = &make_attr_string($args->{'force_register'}, |
$args->{'add_entries'}); |
$args->{'add_entries'}); |
$result .= "\n<frameset $attr_string>\n"; |
$result .= "\n<frameset $attr_string>\n"; |
} else { |
} else { |
$result .= |
$result .= |
&bodytag($title, |
&bodytag($title, |
$args->{'function'}, $args->{'add_entries'}, |
$args->{'function'}, $args->{'add_entries'}, |
$args->{'only_body'}, $args->{'domain'}, |
$args->{'only_body'}, $args->{'domain'}, |
$args->{'force_register'}, $args->{'body_title'}, |
$args->{'force_register'}, $args->{'no_nav_bar'}, |
$args->{'no_nav_bar'}, $args->{'bgcolor'}, |
$args->{'bgcolor'}, $args->{'no_inline_link'}, |
$args->{'no_title'}, $args->{'no_inline_link'}, |
$args, \@advtools, |
$args); |
$ltiscope,$ltiuri,\%ltimenu,$menucoll,\%menu,\$showncrumbs); |
} |
} |
} |
} |
|
|
if ($args->{'js_ready'}) { |
if ($args->{'js_ready'}) { |
$result = &js_ready($result); |
$result = &js_ready($result); |
} |
} |
if ($args->{'html_encode'}) { |
if ($args->{'html_encode'}) { |
$result = &html_encode($result); |
$result = &html_encode($result); |
} |
} |
return $result; |
|
} |
|
|
|
|
# Preparation for new and consistent functionlist at top of screen |
|
# if ($args->{'functionlist'}) { |
|
# $result .= &build_functionlist(); |
|
#} |
|
|
=pod |
# Don't add anything more if only_body wanted or in const space |
|
return $result if $args->{'only_body'} |
=item * &head() |
|| $env{'request.state'} eq 'construct'; |
|
|
Returns a complete </body></html> section for LON-CAPA web pages. |
#Breadcrumbs |
|
if (exists($args->{'bread_crumbs'}) or exists($args->{'bread_crumbs_component'})) { |
Inputs: $args - additional optional args supported are: |
unless ($showncrumbs) { |
js_ready -> return a string ready for being used in |
&Apache::lonhtmlcommon::clear_breadcrumbs(); |
a javascript writeln |
#if any br links exists, add them to the breadcrumbs |
html_encode -> return a string ready for being used in |
if (exists($args->{'bread_crumbs'}) and ref($args->{'bread_crumbs'}) eq 'ARRAY') { |
a html attribute |
foreach my $crumb (@{$args->{'bread_crumbs'}}){ |
frameset -> if true will start with a <frameset> |
&Apache::lonhtmlcommon::add_breadcrumb($crumb); |
rather than <body> |
} |
dicsussion -> if true will get discussion from |
} |
lonxml::xmlend |
# if @advtools array contains items add then to the breadcrumbs |
(you can pass the target and parser arguments |
if (@advtools > 0) { |
through optional 'target' and 'parser' args |
&Apache::lonmenu::advtools_crumbs(@advtools); |
to this routine) |
} |
|
my $menulink; |
=cut |
# if arg: bread_crumbs_nomenu is true pass 0 as $menulink item. |
|
if ((exists($args->{'bread_crumbs_nomenu'})) || |
|
($ltiscope eq 'map') || ($ltiscope eq 'resource')) { |
|
$menulink = 0; |
|
} else { |
|
undef($menulink); |
|
} |
|
my $linkprotout; |
|
if ($env{'request.deeplink.login'}) { |
|
my $linkprotout = &Apache::lonmenu::linkprot_exit(); |
|
if ($linkprotout) { |
|
&Apache::lonhtmlcommon::add_breadcrumb_tool('tools',$linkprotout); |
|
} |
|
} |
|
#if bread_crumbs_component exists show it as headline else show only the breadcrumbs |
|
if(exists($args->{'bread_crumbs_component'})){ |
|
$result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'},'',$menulink); |
|
} else { |
|
$result .= &Apache::lonhtmlcommon::breadcrumbs('','',$menulink); |
|
} |
|
} |
|
} elsif (($env{'environment.remote'} eq 'on') && |
|
($env{'form.inhibitmenu'} ne 'yes') && |
|
($env{'request.noversionuri'} =~ m{^/res/}) && |
|
($env{'request.noversionuri'} !~ m{^/res/adm/pages/})) { |
|
$result .= '<div style="padding:0;margin:0;clear:both"><hr /></div>'; |
|
} |
|
return $result; |
|
} |
|
|
sub end_page { |
sub end_page { |
my ($args) = @_; |
my ($args) = @_; |
Line 4791 sub end_page {
|
Line 9439 sub end_page {
|
} |
} |
$result .= &Apache::lonxml::xmlend($target,$parser); |
$result .= &Apache::lonxml::xmlend($target,$parser); |
} |
} |
|
|
if ($args->{'frameset'}) { |
if ($args->{'frameset'}) { |
$result .= '</frameset>'; |
$result .= '</frameset>'; |
} else { |
} else { |
$result .= &endbodytag(); |
$result .= &endbodytag($args); |
|
} |
|
unless ($args->{'notbody'}) { |
|
$result .= "\n</html>"; |
} |
} |
$result .= "\n</html>"; |
|
|
|
if ($args->{'js_ready'}) { |
if ($args->{'js_ready'}) { |
$result = &js_ready($result); |
$result = &js_ready($result); |
Line 4810 sub end_page {
|
Line 9459 sub end_page {
|
return $result; |
return $result; |
} |
} |
|
|
|
sub menucoll_in_effect { |
|
my ($menucoll,$deeplinkmenu,%menu); |
|
if ($env{'request.course.id'}) { |
|
$menucoll = $env{'course.'.$env{'request.course.id'}.'.menudefault'}; |
|
if ($env{'request.deeplink.login'}) { |
|
my ($deeplink_symb,$deeplink,$check_login_symb); |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
if ($env{'request.noversionuri'} =~ m{^/(res|uploaded)/}) { |
|
if ($env{'request.noversionuri'} =~ /\.(page|sequence)$/) { |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (ref($navmap)) { |
|
$deeplink = $navmap->get_mapparam(undef, |
|
&Apache::lonnet::declutter($env{'request.noversionuri'}), |
|
'0.deeplink'); |
|
} else { |
|
$check_login_symb = 1; |
|
} |
|
} else { |
|
my $symb=&Apache::lonnet::symbread(); |
|
if ($symb) { |
|
$deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$symb); |
|
} else { |
|
$check_login_symb = 1; |
|
} |
|
} |
|
} else { |
|
$check_login_symb = 1; |
|
} |
|
if ($check_login_symb) { |
|
$deeplink_symb = &deeplink_login_symb($cnum,$cdom); |
|
if ($deeplink_symb =~ /\.(page|sequence)$/) { |
|
my $mapname = &Apache::lonnet::deversion((&Apache::lonnet::decode_symb($deeplink_symb))[2]); |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (ref($navmap)) { |
|
$deeplink = $navmap->get_mapparam(undef,$mapname,'0.deeplink'); |
|
} |
|
} else { |
|
$deeplink = &Apache::lonnet::EXT('resource.0.deeplink',$deeplink_symb); |
|
} |
|
} |
|
if ($deeplink ne '') { |
|
my ($state,$others,$listed,$scope,$protect,$display,$target) = split(/,/,$deeplink); |
|
if ($display =~ /^\d+$/) { |
|
$deeplinkmenu = 1; |
|
$menucoll = $display; |
|
} |
|
} |
|
} |
|
if ($menucoll) { |
|
%menu = &page_menu($env{'course.'.$env{'request.course.id'}.'.menucollections'},$menucoll); |
|
} |
|
} |
|
return ($menucoll,$deeplinkmenu,\%menu); |
|
} |
|
|
|
sub deeplink_login_symb { |
|
my ($cnum,$cdom) = @_; |
|
my $login_symb; |
|
if ($env{'request.deeplink.login'}) { |
|
$login_symb = &symb_from_tinyurl($env{'request.deeplink.login'},$cnum,$cdom); |
|
} |
|
return $login_symb; |
|
} |
|
|
|
sub symb_from_tinyurl { |
|
my ($url,$cnum,$cdom) = @_; |
|
if ($url =~ m{^\Q/tiny/$cdom/\E(\w+)$}) { |
|
my $key = $1; |
|
my ($tinyurl,$login); |
|
my ($result,$cached)=&Apache::lonnet::is_cached_new('tiny',$cdom."\0".$key); |
|
if (defined($cached)) { |
|
$tinyurl = $result; |
|
} else { |
|
my $configuname = &Apache::lonnet::get_domainconfiguser($cdom); |
|
my %currtiny = &Apache::lonnet::get('tiny',[$key],$cdom,$configuname); |
|
if ($currtiny{$key} ne '') { |
|
$tinyurl = $currtiny{$key}; |
|
&Apache::lonnet::do_cache_new('tiny',$cdom."\0".$key,$currtiny{$key},600); |
|
} |
|
} |
|
if ($tinyurl ne '') { |
|
my ($cnumreq,$symb) = split(/\&/,$tinyurl); |
|
if (wantarray) { |
|
return ($cnumreq,$symb); |
|
} elsif ($cnumreq eq $cnum) { |
|
return $symb; |
|
} |
|
} |
|
} |
|
if (wantarray) { |
|
return (); |
|
} else { |
|
return; |
|
} |
|
} |
|
|
|
sub usable_exttools { |
|
my %tooltypes; |
|
if ($env{'request.course.id'}) { |
|
if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'}) { |
|
if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'both') { |
|
%tooltypes = ( |
|
crs => 1, |
|
dom => 1, |
|
); |
|
} elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'crs') { |
|
$tooltypes{'crs'} = 1; |
|
} elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'dom') { |
|
$tooltypes{'dom'} = 1; |
|
} |
|
} else { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $crstype = lc($env{'course.'.$env{'request.course.id'}.'.type'}); |
|
if ($crstype eq '') { |
|
$crstype = 'course'; |
|
} |
|
if ($crstype eq 'course') { |
|
if ($env{'course.'.$env{'request.course.id'}.'internal.coursecode'}) { |
|
$crstype = 'official'; |
|
} elsif ($env{'course.'.$env{'request.course.id'}.'.internal.textbook'}) { |
|
$crstype = 'textbook'; |
|
} elsif ($env{'course.'.$env{'request.course.id'}.'.internal.lti'}) { |
|
$crstype = 'lti'; |
|
} else { |
|
$crstype = 'unofficial'; |
|
} |
|
} |
|
my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom); |
|
if ($domdefaults{$crstype.'domexttool'}) { |
|
$tooltypes{'dom'} = 1; |
|
} |
|
if ($domdefaults{$crstype.'exttool'}) { |
|
$tooltypes{'crs'} = 1; |
|
} |
|
} |
|
} |
|
return %tooltypes; |
|
} |
|
|
|
sub wishlist_window { |
|
return(<<'ENDWISHLIST'); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
// <!-- BEGIN LON-CAPA Internal |
|
function set_wishlistlink(title, path) { |
|
if (!title) { |
|
title = document.title; |
|
title = title.replace(/^LON-CAPA /,''); |
|
} |
|
title = encodeURIComponent(title); |
|
title = title.replace("'","\\\'"); |
|
if (!path) { |
|
path = location.pathname; |
|
} |
|
path = encodeURIComponent(path); |
|
path = path.replace("'","\\\'"); |
|
Win = window.open('/adm/wishlist?mode=newLink&setTitle='+title+'&setPath='+path, |
|
'wishlistNewLink','width=560,height=350,scrollbars=0'); |
|
} |
|
// END LON-CAPA Internal --> |
|
// ]]> |
|
</script> |
|
ENDWISHLIST |
|
} |
|
|
|
sub modal_window { |
|
return(<<'ENDMODAL'); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
// <!-- BEGIN LON-CAPA Internal |
|
var modalWindow = { |
|
parent:"body", |
|
windowId:null, |
|
content:null, |
|
width:null, |
|
height:null, |
|
close:function() |
|
{ |
|
$(".LCmodal-window").remove(); |
|
$(".LCmodal-overlay").remove(); |
|
}, |
|
open:function() |
|
{ |
|
var modal = ""; |
|
modal += "<div class=\"LCmodal-overlay\"></div>"; |
|
modal += "<div id=\"" + this.windowId + "\" class=\"LCmodal-window\" style=\"width:" + this.width + "px; height:" + this.height + "px; margin-top:-" + (this.height / 2) + "px; margin-left:-" + (this.width / 2) + "px;\">"; |
|
modal += this.content; |
|
modal += "</div>"; |
|
|
|
$(this.parent).append(modal); |
|
|
|
$(".LCmodal-window").append("<a class=\"LCclose-window\"></a>"); |
|
$(".LCclose-window").click(function(){modalWindow.close();}); |
|
$(".LCmodal-overlay").click(function(){modalWindow.close();}); |
|
} |
|
}; |
|
var openMyModal = function(source,width,height,scrolling,transparency,style) |
|
{ |
|
source = source.replace(/'/g,"'"); |
|
modalWindow.windowId = "myModal"; |
|
modalWindow.width = width; |
|
modalWindow.height = height; |
|
modalWindow.content = "<iframe width='"+width+"' height='"+height+"' frameborder='0' scrolling='"+scrolling+"' allowtransparency='"+transparency+"' src='" + source + "' style='"+style+"'></iframe>"; |
|
modalWindow.open(); |
|
}; |
|
// END LON-CAPA Internal --> |
|
// ]]> |
|
</script> |
|
ENDMODAL |
|
} |
|
|
|
sub modal_link { |
|
my ($link,$linktext,$width,$height,$target,$scrolling,$title,$transparency,$style)=@_; |
|
unless ($width) { $width=480; } |
|
unless ($height) { $height=400; } |
|
unless ($scrolling) { $scrolling='yes'; } |
|
unless ($transparency) { $transparency='true'; } |
|
|
|
my $target_attr; |
|
if (defined($target)) { |
|
$target_attr = 'target="'.$target.'"'; |
|
} |
|
return <<"ENDLINK"; |
|
<a href="$link" $target_attr title="$title" onclick="javascript:openMyModal('$link',$width,$height,'$scrolling','$transparency','$style'); return false;">$linktext</a> |
|
ENDLINK |
|
} |
|
|
|
sub modal_adhoc_script { |
|
my ($funcname,$width,$height,$content,$possmathjax)=@_; |
|
my $mathjax; |
|
if ($possmathjax) { |
|
$mathjax = <<'ENDJAX'; |
|
if (typeof MathJax == 'object') { |
|
MathJax.Hub.Queue(["Typeset",MathJax.Hub]); |
|
} |
|
ENDJAX |
|
} |
|
return (<<ENDADHOC); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
var $funcname = function() |
|
{ |
|
modalWindow.windowId = "myModal"; |
|
modalWindow.width = $width; |
|
modalWindow.height = $height; |
|
modalWindow.content = '$content'; |
|
modalWindow.open(); |
|
$mathjax |
|
}; |
|
// ]]> |
|
</script> |
|
ENDADHOC |
|
} |
|
|
|
sub modal_adhoc_inner { |
|
my ($funcname,$width,$height,$content,$possmathjax)=@_; |
|
my $innerwidth=$width-20; |
|
$content=&js_ready( |
|
&start_page('Dialog',undef,{'only_body'=>1,'bgcolor'=>'#FFFFFF'}). |
|
&start_scrollbox($width.'px',$innerwidth.'px',$height.'px','myModal','#FFFFFF',undef,1). |
|
$content. |
|
&end_scrollbox(). |
|
&end_page() |
|
); |
|
return &modal_adhoc_script($funcname,$width,$height,$content,$possmathjax); |
|
} |
|
|
|
sub modal_adhoc_window { |
|
my ($funcname,$width,$height,$content,$linktext,$possmathjax)=@_; |
|
return &modal_adhoc_inner($funcname,$width,$height,$content,$possmathjax). |
|
"<a href=\"javascript:$funcname();void(0);\">".$linktext."</a>"; |
|
} |
|
|
|
sub modal_adhoc_launch { |
|
my ($funcname,$width,$height,$content)=@_; |
|
return &modal_adhoc_inner($funcname,$width,$height,$content).(<<ENDLAUNCH); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
$funcname(); |
|
// ]]> |
|
</script> |
|
ENDLAUNCH |
|
} |
|
|
|
sub modal_adhoc_close { |
|
return (<<ENDCLOSE); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
modalWindow.close(); |
|
// ]]> |
|
</script> |
|
ENDCLOSE |
|
} |
|
|
|
sub togglebox_script { |
|
return(<<ENDTOGGLE); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
function LCtoggleDisplay(id,hidetext,showtext) { |
|
link = document.getElementById(id + "link").childNodes[0]; |
|
with (document.getElementById(id).style) { |
|
if (display == "none" ) { |
|
display = "inline"; |
|
link.nodeValue = hidetext; |
|
} else { |
|
display = "none"; |
|
link.nodeValue = showtext; |
|
} |
|
} |
|
} |
|
// ]]> |
|
</script> |
|
ENDTOGGLE |
|
} |
|
|
|
sub start_togglebox { |
|
my ($id,$heading,$headerbg,$hidetext,$showtext)=@_; |
|
unless ($heading) { $heading=''; } else { $heading.=' '; } |
|
unless ($showtext) { $showtext=&mt('show'); } |
|
unless ($hidetext) { $hidetext=&mt('hide'); } |
|
unless ($headerbg) { $headerbg='#FFFFFF'; } |
|
return &start_data_table(). |
|
&start_data_table_header_row(). |
|
'<td bgcolor="'.$headerbg.'">'.$heading. |
|
'[<a id="'.$id.'link" href="javascript:LCtoggleDisplay(\''.$id.'\',\''.$hidetext.'\',\''. |
|
$showtext.'\')">'.$showtext.'</a>]</td>'. |
|
&end_data_table_header_row(). |
|
'<tr id="'.$id.'" style="display:none""><td>'; |
|
} |
|
|
|
sub end_togglebox { |
|
return '</td></tr>'.&end_data_table(); |
|
} |
|
|
|
sub LCprogressbar_script { |
|
my ($id,$number_to_do)=@_; |
|
if ($number_to_do) { |
|
return(<<ENDPROGRESS); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
\$('#progressbar$id').progressbar({ |
|
value: 0, |
|
change: function(event, ui) { |
|
var newVal = \$(this).progressbar('option', 'value'); |
|
\$('.pblabel', this).text(LCprogressTxt); |
|
} |
|
}); |
|
// ]]> |
|
</script> |
|
ENDPROGRESS |
|
} else { |
|
return(<<ENDPROGRESS); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
\$('#progressbar$id').progressbar({ |
|
value: false, |
|
create: function(event, ui) { |
|
\$('.ui-widget-header', this).css({'background':'#F0F0F0'}); |
|
\$('.ui-progressbar-overlay', this).css({'margin':'0'}); |
|
} |
|
}); |
|
// ]]> |
|
</script> |
|
ENDPROGRESS |
|
} |
|
} |
|
|
|
sub LCprogressbarUpdate_script { |
|
return(<<ENDPROGRESSUPDATE); |
|
<style type="text/css"> |
|
.ui-progressbar { position:relative; } |
|
.progress-label {position: absolute; width: 100%; text-align: center; top: 1px; font-weight: bold; text-shadow: 1px 1px 0 #fff;margin: 0; line-height: 200%; } |
|
.pblabel { position: absolute; width: 100%; text-align: center; line-height: 1.9em; } |
|
</style> |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
var LCprogressTxt='---'; |
|
|
|
function LCupdateProgress(percent,progresstext,id,maxnum) { |
|
LCprogressTxt=progresstext; |
|
if ((maxnum == '') || (maxnum == undefined) || (maxnum == null)) { |
|
\$('#progressbar'+id).find('.progress-label').text(LCprogressTxt); |
|
} else if (percent === \$('#progressbar'+id).progressbar( "value" )) { |
|
\$('#progressbar'+id).find('.pblabel').text(LCprogressTxt); |
|
} else { |
|
\$('#progressbar'+id).progressbar('value',percent); |
|
} |
|
} |
|
// ]]> |
|
</script> |
|
ENDPROGRESSUPDATE |
|
} |
|
|
|
my $LClastpercent; |
|
my $LCidcnt; |
|
my $LCcurrentid; |
|
|
|
sub LCprogressbar { |
|
my ($r,$number_to_do,$preamble)=@_; |
|
$LClastpercent=0; |
|
$LCidcnt++; |
|
$LCcurrentid=$$.'_'.$LCidcnt; |
|
my ($starting,$content); |
|
if ($number_to_do) { |
|
$starting=&mt('Starting'); |
|
$content=(<<ENDPROGBAR); |
|
$preamble |
|
<div id="progressbar$LCcurrentid"> |
|
<span class="pblabel">$starting</span> |
|
</div> |
|
ENDPROGBAR |
|
} else { |
|
$starting=&mt('Loading...'); |
|
$LClastpercent='false'; |
|
$content=(<<ENDPROGBAR); |
|
$preamble |
|
<div id="progressbar$LCcurrentid"> |
|
<div class="progress-label">$starting</div> |
|
</div> |
|
ENDPROGBAR |
|
} |
|
&r_print($r,$content.&LCprogressbar_script($LCcurrentid,$number_to_do)); |
|
} |
|
|
|
sub LCprogressbarUpdate { |
|
my ($r,$val,$text,$number_to_do)=@_; |
|
if ($number_to_do) { |
|
unless ($val) { |
|
if ($LClastpercent) { |
|
$val=$LClastpercent; |
|
} else { |
|
$val=0; |
|
} |
|
} |
|
if ($val<0) { $val=0; } |
|
if ($val>100) { $val=0; } |
|
$LClastpercent=$val; |
|
unless ($text) { $text=$val.'%'; } |
|
} else { |
|
$val = 'false'; |
|
} |
|
$text=&js_ready($text); |
|
&r_print($r,<<ENDUPDATE); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
LCupdateProgress($val,'$text','$LCcurrentid','$number_to_do'); |
|
// ]]> |
|
</script> |
|
ENDUPDATE |
|
} |
|
|
|
sub LCprogressbarClose { |
|
my ($r)=@_; |
|
$LClastpercent=0; |
|
&r_print($r,<<ENDCLOSE); |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
\$("#progressbar$LCcurrentid").hide('slow'); |
|
// ]]> |
|
</script> |
|
ENDCLOSE |
|
} |
|
|
|
sub r_print { |
|
my ($r,$to_print)=@_; |
|
if ($r) { |
|
$r->print($to_print); |
|
$r->rflush(); |
|
} else { |
|
print($to_print); |
|
} |
|
} |
|
|
sub html_encode { |
sub html_encode { |
my ($result) = @_; |
my ($result) = @_; |
|
|
Line 4817 sub html_encode {
|
Line 9941 sub html_encode {
|
|
|
return $result; |
return $result; |
} |
} |
|
|
sub js_ready { |
sub js_ready { |
my ($result) = @_; |
my ($result) = @_; |
|
|
Line 4853 sub validate_page {
|
Line 9978 sub validate_page {
|
} |
} |
} |
} |
|
|
|
|
|
sub start_scrollbox { |
|
my ($outerwidth,$width,$height,$id,$bgcolor,$cursor,$needjsready) = @_; |
|
unless ($outerwidth) { $outerwidth='520px'; } |
|
unless ($width) { $width='500px'; } |
|
unless ($height) { $height='200px'; } |
|
my ($table_id,$div_id,$tdcol); |
|
if ($id ne '') { |
|
$table_id = ' id="table_'.$id.'"'; |
|
$div_id = ' id="div_'.$id.'"'; |
|
} |
|
if ($bgcolor ne '') { |
|
$tdcol = "background-color: $bgcolor;"; |
|
} |
|
my $nicescroll_js; |
|
if ($env{'browser.mobile'}) { |
|
$nicescroll_js = &nicescroll_javascript('div_'.$id,$cursor,$needjsready); |
|
} |
|
return <<"END"; |
|
$nicescroll_js |
|
|
|
<table style="width: $outerwidth; border: 1px solid none;"$table_id><tr><td style="width: $width;$tdcol"> |
|
<div style="overflow:auto; width:$width; height:$height;"$div_id> |
|
END |
|
} |
|
|
|
sub end_scrollbox { |
|
return '</div></td></tr></table>'; |
|
} |
|
|
|
sub nicescroll_javascript { |
|
my ($id,$cursor,$needjsready,$framecheck,$location) = @_; |
|
my %options; |
|
if (ref($cursor) eq 'HASH') { |
|
%options = %{$cursor}; |
|
} |
|
unless ($options{'railalign'} =~ /^left|right$/) { |
|
$options{'railalign'} = 'left'; |
|
} |
|
unless ($options{'cursorcolor'} =~ /^\#\w+$/) { |
|
my $function = &get_users_function(); |
|
$options{'cursorcolor'} = &designparm($function.'.sidebg',$env{'request.role.domain'}); |
|
unless ($options{'cursorcolor'} =~ /^\#\w+$/) { |
|
$options{'cursorcolor'} = '#00F'; |
|
} |
|
} |
|
if ($options{'cursoropacity'} =~ /^[\d.]+$/) { |
|
unless ($options{'cursoropacity'} >= 0.0 && $options{'cursoropacity'} <=1.0) { |
|
$options{'cursoropacity'}='1.0'; |
|
} |
|
} else { |
|
$options{'cursoropacity'}='1.0'; |
|
} |
|
if ($options{'cursorfixedheight'} eq 'none') { |
|
delete($options{'cursorfixedheight'}); |
|
} else { |
|
unless ($options{'cursorfixedheight'} =~ /^\d+$/) { $options{'cursorfixedheight'}='50'; } |
|
} |
|
unless ($options{'railoffset'} =~ /^{[\w\:\d\-,]+}$/) { |
|
delete($options{'railoffset'}); |
|
} |
|
my @niceoptions; |
|
while (my($key,$value) = each(%options)) { |
|
if ($value =~ /^\{.+\}$/) { |
|
push(@niceoptions,$key.':'.$value); |
|
} else { |
|
push(@niceoptions,$key.':"'.$value.'"'); |
|
} |
|
} |
|
my $nicescroll_js = ' |
|
$(document).ready( |
|
function() { |
|
$("#'.$id.'").niceScroll({'.join(',',@niceoptions).'}); |
|
} |
|
); |
|
'; |
|
if ($framecheck) { |
|
$nicescroll_js .= ' |
|
function expand_div(caller) { |
|
if (top === self) { |
|
document.getElementById("'.$id.'").style.width = "auto"; |
|
document.getElementById("'.$id.'").style.height = "auto"; |
|
} else { |
|
try { |
|
if (parent.frames) { |
|
if (parent.frames.length > 1) { |
|
var framesrc = parent.frames[1].location.href; |
|
var currsrc = framesrc.replace(/\#.*$/,""); |
|
if ((caller == "search") || (currsrc == "'.$location.'")) { |
|
document.getElementById("'.$id.'").style.width = "auto"; |
|
document.getElementById("'.$id.'").style.height = "auto"; |
|
} |
|
} |
|
} |
|
} catch (e) { |
|
return; |
|
} |
|
} |
|
return; |
|
} |
|
'; |
|
} |
|
if ($needjsready) { |
|
$nicescroll_js = ' |
|
<script type="text/javascript">'."\n".$nicescroll_js."\n</script>\n"; |
|
} else { |
|
$nicescroll_js = &Apache::lonhtmlcommon::scripttag($nicescroll_js); |
|
} |
|
return $nicescroll_js; |
|
} |
|
|
sub simple_error_page { |
sub simple_error_page { |
my ($r,$title,$msg) = @_; |
my ($r,$title,$msg,$args) = @_; |
|
my %displayargs; |
|
if (ref($args) eq 'HASH') { |
|
if (!$args->{'no_auto_mt_msg'}) { $msg = &mt($msg); } |
|
if ($args->{'only_body'}) { |
|
$displayargs{'only_body'} = 1; |
|
} |
|
if ($args->{'no_nav_bar'}) { |
|
$displayargs{'no_nav_bar'} = 1; |
|
} |
|
} else { |
|
$msg = &mt($msg); |
|
} |
|
|
my $page = |
my $page = |
&Apache::loncommon::start_page($title). |
&Apache::loncommon::start_page($title,'',\%displayargs). |
&mt($msg). |
'<p class="LC_error">'.$msg.'</p>'. |
&Apache::loncommon::end_page(); |
&Apache::loncommon::end_page(); |
if (ref($r)) { |
if (ref($r)) { |
$r->print($page); |
$r->print($page); |
Line 4867 sub simple_error_page {
|
Line 10116 sub simple_error_page {
|
} |
} |
|
|
{ |
{ |
my $row_count; |
my @row_count; |
|
|
|
sub start_data_table_count { |
|
unshift(@row_count, 0); |
|
return; |
|
} |
|
|
|
sub end_data_table_count { |
|
shift(@row_count); |
|
return; |
|
} |
|
|
sub start_data_table { |
sub start_data_table { |
my ($add_class) = @_; |
my ($add_class,$id) = @_; |
my $css_class = (join(' ','LC_data_table',$add_class)); |
my $css_class = (join(' ','LC_data_table',$add_class)); |
undef($row_count); |
my $table_id; |
return '<table class="'.$css_class.'">'."\n"; |
if (defined($id)) { |
|
$table_id = ' id="'.$id.'"'; |
|
} |
|
&start_data_table_count(); |
|
return '<table class="'.$css_class.'"'.$table_id.'>'."\n"; |
} |
} |
|
|
sub end_data_table { |
sub end_data_table { |
undef($row_count); |
&end_data_table_count(); |
return '</table>'."\n";; |
return '</table>'."\n";; |
} |
} |
|
|
sub start_data_table_row { |
sub start_data_table_row { |
my ($add_class) = @_; |
my ($add_class, $id) = @_; |
$row_count++; |
$row_count[0]++; |
my $css_class = ($row_count % 2)?'':'LC_even_row'; |
my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row'; |
$css_class = (join(' ',$css_class,$add_class)); |
$css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); |
return '<tr class="'.$css_class.'">'."\n";; |
$id = (' id="'.$id.'"') unless ($id eq ''); |
|
return '<tr class="'.$css_class.'"'.$id.'>'."\n"; |
} |
} |
|
|
sub continue_data_table_row { |
sub continue_data_table_row { |
my ($add_class) = @_; |
my ($add_class, $id) = @_; |
my $css_class = ($row_count % 2)?'':'LC_even_row'; |
my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row'; |
$css_class = (join(' ',$css_class,$add_class)); |
$css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); |
return '<tr class="'.$css_class.'">'."\n";; |
$id = (' id="'.$id.'"') unless ($id eq ''); |
|
return '<tr class="'.$css_class.'"'.$id.'>'."\n"; |
} |
} |
|
|
sub end_data_table_row { |
sub end_data_table_row { |
Line 4900 sub simple_error_page {
|
Line 10166 sub simple_error_page {
|
} |
} |
|
|
sub start_data_table_empty_row { |
sub start_data_table_empty_row { |
$row_count++; |
# $row_count[0]++; |
return '<tr class="LC_empty_row" >'."\n";; |
return '<tr class="LC_empty_row" >'."\n";; |
} |
} |
|
|
Line 4915 sub simple_error_page {
|
Line 10181 sub simple_error_page {
|
sub end_data_table_header_row { |
sub end_data_table_header_row { |
return '</tr>'."\n";; |
return '</tr>'."\n";; |
} |
} |
|
|
|
sub data_table_caption { |
|
my $caption = shift; |
|
return "<caption class=\"LC_caption\">$caption</caption>"; |
|
} |
} |
} |
|
|
=pod |
=pod |
Line 4981 Returns either 'student','coordinator','
|
Line 10252 Returns either 'student','coordinator','
|
|
|
############################################### |
############################################### |
sub get_users_function { |
sub get_users_function { |
my $function = 'student'; |
my $function = 'norole'; |
if ($env{'request.role'}=~/^(cc|in|ta|ep)/) { |
if ($env{'request.role'}=~/^(st)/) { |
|
$function='student'; |
|
} |
|
if ($env{'request.role'}=~/^(cc|co|in|ta|ep)/) { |
$function='coordinator'; |
$function='coordinator'; |
} |
} |
if ($env{'request.role'}=~/^(su|dc|ad|li)/) { |
if ($env{'request.role'}=~/^(su|dc|ad|li)/) { |
$function='admin'; |
$function='admin'; |
} |
} |
if (($env{'request.role'}=~/^(au|ca)/) || |
if (($env{'request.role'}=~/^(au|ca|aa)/) || |
($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) { |
($ENV{'REQUEST_URI'}=~ m{/^(/priv)})) { |
$function='author'; |
$function='author'; |
} |
} |
return $function; |
return $function; |
Line 4999 sub get_users_function {
|
Line 10273 sub get_users_function {
|
|
|
=pod |
=pod |
|
|
|
=item * &show_course() |
|
|
|
Used by lonmenu.pm and lonroles.pm to determine whether to use the word |
|
'Courses' or 'Roles' in inline navigation and on screen displaying user's roles. |
|
|
|
Inputs: |
|
None |
|
|
|
Outputs: |
|
Scalar: 1 if 'Course' to be used, 0 otherwise. |
|
|
|
=cut |
|
|
|
############################################### |
|
sub show_course { |
|
my $course = !$env{'user.adv'}; |
|
if (!$env{'user.adv'}) { |
|
foreach my $env (keys(%env)) { |
|
next if ($env !~ m/^user\.priv\./); |
|
if ($env !~ m/^user\.priv\.(?:st|cm)/) { |
|
$course = 0; |
|
last; |
|
} |
|
} |
|
} |
|
return $course; |
|
} |
|
|
|
############################################### |
|
|
|
=pod |
|
|
=item * &check_user_status() |
=item * &check_user_status() |
|
|
Determines current status of supplied role for a |
Determines current status of supplied role for a |
Line 5016 role status: active, previous or future.
|
Line 10322 role status: active, previous or future.
|
sub check_user_status { |
sub check_user_status { |
my ($udom,$uname,$cdom,$crs,$role,$sec) = @_; |
my ($udom,$uname,$cdom,$crs,$role,$sec) = @_; |
my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname); |
my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname); |
my @uroles = keys %userinfo; |
my @uroles = keys(%userinfo); |
my $srchstr; |
my $srchstr; |
my $active_chk = 'none'; |
my $active_chk = 'none'; |
my $now = time; |
my $now = time; |
if (@uroles > 0) { |
if (@uroles > 0) { |
if (($role eq 'cc') || ($sec eq '') || (!defined($sec))) { |
if (($role eq 'cc') || ($role eq 'co') || ($sec eq '') || (!defined($sec))) { |
$srchstr = '/'.$cdom.'/'.$crs.'_'.$role; |
$srchstr = '/'.$cdom.'/'.$crs.'_'.$role; |
} else { |
} else { |
$srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role; |
$srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role; |
Line 5093 sub get_sections {
|
Line 10399 sub get_sections {
|
my %sectioncount; |
my %sectioncount; |
my $now = time; |
my $now = time; |
|
|
if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) { |
my $check_students = 1; |
|
my $only_students = 0; |
|
if (ref($possible_roles) eq 'ARRAY') { |
|
if (grep(/^st$/,@{$possible_roles})) { |
|
if (@{$possible_roles} == 1) { |
|
$only_students = 1; |
|
} |
|
} else { |
|
$check_students = 0; |
|
} |
|
} |
|
|
|
if ($check_students) { |
my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum); |
my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum); |
my $sec_index = &Apache::loncoursedata::CL_SECTION(); |
my $sec_index = &Apache::loncoursedata::CL_SECTION(); |
my $status_index = &Apache::loncoursedata::CL_STATUS(); |
my $status_index = &Apache::loncoursedata::CL_STATUS(); |
Line 5120 sub get_sections {
|
Line 10438 sub get_sections {
|
} |
} |
} |
} |
} |
} |
|
if ($only_students) { |
|
return %sectioncount; |
|
} |
my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); |
my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); |
foreach my $user (sort(keys(%courseroles))) { |
foreach my $user (sort(keys(%courseroles))) { |
if ($user !~ /^(\w{2})/) { next; } |
if ($user !~ /^(\w{2})/) { next; } |
Line 5172 previous, future, or all.
|
Line 10493 previous, future, or all.
|
5. reference to array of section restrictions (optional) |
5. reference to array of section restrictions (optional) |
6. reference to results object (hash of hashes). |
6. reference to results object (hash of hashes). |
7. reference to optional userdata hash |
7. reference to optional userdata hash |
Keys of top level hash are roles. |
8. reference to optional statushash |
|
9. flag if privileged users (except those set to unhide in |
|
course settings) should be excluded |
|
Keys of top level results hash are roles. |
Keys of inner hashes are username:domain, with |
Keys of inner hashes are username:domain, with |
values set to access type. |
values set to access type. |
Optional userdata hash returns an array with arguments in the |
Optional userdata hash returns an array with arguments in the |
same order as loncoursedata::get_classlist() for student data. |
same order as loncoursedata::get_classlist() for student data. |
|
|
|
Optional statushash returns |
|
|
Entries for end, start, section and status are blank because |
Entries for end, start, section and status are blank because |
of the possibility of multiple values for non-student roles. |
of the possibility of multiple values for non-student roles. |
|
|
Line 5186 of the possibility of multiple values fo
|
Line 10512 of the possibility of multiple values fo
|
############################################### |
############################################### |
|
|
sub get_course_users { |
sub get_course_users { |
my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_; |
my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata,$statushash,$hidepriv) = @_; |
my %idx = (); |
my %idx = (); |
my %seclists; |
my %seclists; |
|
|
Line 5206 sub get_course_users {
|
Line 10532 sub get_course_users {
|
my $match = 0; |
my $match = 0; |
my $secmatch = 0; |
my $secmatch = 0; |
my $section = $$classlist{$student}[$idx{section}]; |
my $section = $$classlist{$student}[$idx{section}]; |
|
my $status = $$classlist{$student}[$idx{status}]; |
if ($section eq '') { |
if ($section eq '') { |
$section = 'none'; |
$section = 'none'; |
} |
} |
Line 5225 sub get_course_users {
|
Line 10552 sub get_course_users {
|
next; |
next; |
} |
} |
} |
} |
push(@{$seclists{$student}},$section); |
|
if (defined($$types{'active'})) { |
if (defined($$types{'active'})) { |
if ($$classlist{$student}[$idx{status}] eq 'Active') { |
if ($$classlist{$student}[$idx{status}] eq 'Active') { |
push(@{$$users{st}{$student}},'active'); |
push(@{$$users{st}{$student}},'active'); |
Line 5233 sub get_course_users {
|
Line 10559 sub get_course_users {
|
} |
} |
} |
} |
if (defined($$types{'previous'})) { |
if (defined($$types{'previous'})) { |
if ($$classlist{$student}[$idx{end}] <= $now) { |
if ($$classlist{$student}[$idx{status}] eq 'Expired') { |
push(@{$$users{st}{$student}},'previous'); |
push(@{$$users{st}{$student}},'previous'); |
$match = 1; |
$match = 1; |
} |
} |
} |
} |
if (defined($$types{'future'})) { |
if (defined($$types{'future'})) { |
if (($$classlist{$student}[$idx{start}] > $now) && ($$classlist{$student}[$idx{end}] > $now) || ($$classlist{$student}[$idx{end}] == 0) || ($$classlist{$student}[$idx{end}] eq '')) { |
if ($$classlist{$student}[$idx{status}] eq 'Future') { |
push(@{$$users{st}{$student}},'future'); |
push(@{$$users{st}{$student}},'future'); |
$match = 1; |
$match = 1; |
} |
} |
} |
} |
if ($match && ref($userdata) eq 'HASH') { |
if ($match) { |
$$userdata{$student} = $$classlist{$student}; |
push(@{$seclists{$student}},$section); |
|
if (ref($userdata) eq 'HASH') { |
|
$$userdata{$student} = $$classlist{$student}; |
|
} |
|
if (ref($statushash) eq 'HASH') { |
|
$statushash->{$student}{'st'}{$section} = $status; |
|
} |
} |
} |
} |
} |
} |
} |
if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) { |
if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) { |
my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); |
my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); |
my $now = time; |
my $now = time; |
|
my %displaystatus = ( previous => 'Expired', |
|
active => 'Active', |
|
future => 'Future', |
|
); |
|
my (%nothide,@possdoms); |
|
if ($hidepriv) { |
|
my %coursehash=&Apache::lonnet::coursedescription($cdom.'_'.$cnum); |
|
foreach my $user (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) { |
|
if ($user !~ /:/) { |
|
$nothide{join(':',split(/[\@]/,$user))}=1; |
|
} else { |
|
$nothide{$user} = 1; |
|
} |
|
} |
|
my @possdoms = ($cdom); |
|
if ($coursehash{'checkforpriv'}) { |
|
push(@possdoms,split(/,/,$coursehash{'checkforpriv'})); |
|
} |
|
} |
foreach my $person (sort(keys(%coursepersonnel))) { |
foreach my $person (sort(keys(%coursepersonnel))) { |
my $match = 0; |
my $match = 0; |
my $secmatch = 0; |
my $secmatch = 0; |
Line 5285 sub get_course_users {
|
Line 10636 sub get_course_users {
|
$usec = 'none'; |
$usec = 'none'; |
} |
} |
if ($uname ne '' && $udom ne '') { |
if ($uname ne '' && $udom ne '') { |
|
if ($hidepriv) { |
|
if ((&Apache::lonnet::privileged($uname,$udom,\@possdoms)) && |
|
(!$nothide{$uname.':'.$udom})) { |
|
next; |
|
} |
|
} |
if ($end > 0 && $end < $now) { |
if ($end > 0 && $end < $now) { |
$status = 'previous'; |
$status = 'previous'; |
} elsif ($start > $now) { |
} elsif ($start > $now) { |
Line 5307 sub get_course_users {
|
Line 10664 sub get_course_users {
|
if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) { |
if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) { |
push(@{$seclists{$uname.':'.$udom}},$usec); |
push(@{$seclists{$uname.':'.$udom}},$usec); |
} |
} |
|
if (ref($statushash) eq 'HASH') { |
|
$statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status}; |
|
} |
} |
} |
} |
} |
} |
} |
Line 5316 sub get_course_users {
|
Line 10676 sub get_course_users {
|
my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum); |
my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum); |
if ( defined($csettings{'internal.courseowner'}) ) { |
if ( defined($csettings{'internal.courseowner'}) ) { |
my $owner = $csettings{'internal.courseowner'}; |
my $owner = $csettings{'internal.courseowner'}; |
if ($owner !~ /^[^:]+:[^:]+$/) { |
next if ($owner eq ''); |
$owner = $owner.':'.$cdom; |
my ($ownername,$ownerdom); |
|
if ($owner =~ /^([^:]+):([^:]+)$/) { |
|
$ownername = $1; |
|
$ownerdom = $2; |
|
} else { |
|
$ownername = $owner; |
|
$ownerdom = $cdom; |
|
$owner = $ownername.':'.$ownerdom; |
} |
} |
@{$$users{'ow'}{$owner}} = 'any'; |
@{$$users{'ow'}{$owner}} = 'any'; |
if (defined($userdata) && |
if (defined($userdata) && |
!exists($$userdata{$owner.':'.$cdom})) { |
!exists($$userdata{$owner})) { |
&get_user_info($cdom,$owner,\%idx,$userdata); |
&get_user_info($ownerdom,$ownername,\%idx,$userdata); |
if (!grep(/^none$/,@{$seclists{$owner.':'.$cdom}})) { |
if (!grep(/^none$/,@{$seclists{$owner}})) { |
push(@{$seclists{$owner.':'.$cdom}},'none'); |
push(@{$seclists{$owner}},'none'); |
|
} |
|
if (ref($statushash) eq 'HASH') { |
|
$statushash->{$owner}{'ow'}{'none'} = 'Any'; |
} |
} |
} |
} |
} |
} |
Line 5344 sub get_user_info {
|
Line 10714 sub get_user_info {
|
&plainname($uname,$udom,'lastname'); |
&plainname($uname,$udom,'lastname'); |
$$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname; |
$$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname; |
$$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom; |
$$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom; |
|
my %idhash = &Apache::lonnet::idrget($udom,($uname)); |
|
$$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname}; |
return; |
return; |
} |
} |
|
|
Line 5353 sub get_user_info {
|
Line 10725 sub get_user_info {
|
|
|
=item * &get_user_quota() |
=item * &get_user_quota() |
|
|
Retrieves quota assigned for storage of portfolio files for a user |
Retrieves quota assigned for storage of user files. |
|
Default is to report quota for portfolio files. |
|
|
Incoming parameters: |
Incoming parameters: |
1. user's username |
1. user's username |
2. user's domain |
2. user's domain |
|
3. quota name - portfolio, author, or course |
|
(if no quota name provided, defaults to portfolio). |
|
4. crstype - official, unofficial, textbook or community, if quota name is |
|
course |
|
|
Returns: |
Returns: |
1. Disk quota (in Mb) assigned to student. |
1. Disk quota (in MB) assigned to student. |
2. (Optional) Type of setting: custom or default |
2. (Optional) Type of setting: custom or default |
(individually assigned or default for user's |
(individually assigned or default for user's |
institutional status). |
institutional status). |
Line 5371 Returns:
|
Line 10748 Returns:
|
|
|
If a value has been stored in the user's environment, |
If a value has been stored in the user's environment, |
it will return that, otherwise it returns the maximal default |
it will return that, otherwise it returns the maximal default |
defined for the user's instituional status(es) in the domain. |
defined for the user's institutional status(es) in the domain. |
|
|
=cut |
=cut |
|
|
Line 5379 defined for the user's instituional stat
|
Line 10756 defined for the user's instituional stat
|
|
|
|
|
sub get_user_quota { |
sub get_user_quota { |
my ($uname,$udom) = @_; |
my ($uname,$udom,$quotaname,$crstype) = @_; |
my ($quota,$quotatype,$settingstatus,$defquota); |
my ($quota,$quotatype,$settingstatus,$defquota); |
if (!defined($udom)) { |
if (!defined($udom)) { |
$udom = $env{'user.domain'}; |
$udom = $env{'user.domain'}; |
Line 5394 sub get_user_quota {
|
Line 10771 sub get_user_quota {
|
$defquota = 0; |
$defquota = 0; |
} else { |
} else { |
my $inststatus; |
my $inststatus; |
if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) { |
if ($quotaname eq 'course') { |
$quota = $env{'environment.portfolioquota'}; |
if (($env{'course.'.$udom.'_'.$uname.'.num'} eq $uname) && |
$inststatus = $env{'environment.inststatus'}; |
($env{'course.'.$udom.'_'.$uname.'.domain'} eq $udom)) { |
} else { |
$quota = $env{'course.'.$udom.'_'.$uname.'.internal.uploadquota'}; |
my %userenv = |
} else { |
&Apache::lonnet::get('environment',['portfolioquota', |
my %cenv = &Apache::lonnet::coursedescription("$udom/$uname"); |
'inststatus'],$udom,$uname); |
$quota = $cenv{'internal.uploadquota'}; |
my ($tmp) = keys(%userenv); |
} |
if ($tmp !~ /^(con_lost|error|no_such_host)/i) { |
|
$quota = $userenv{'portfolioquota'}; |
|
$inststatus = $userenv{'inststatus'}; |
|
} else { |
|
undef(%userenv); |
|
} |
|
} |
|
($defquota,$settingstatus) = &default_quota($udom,$inststatus); |
|
if ($quota eq '') { |
|
$quota = $defquota; |
|
$quotatype = 'default'; |
|
} else { |
} else { |
$quotatype = 'custom'; |
if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) { |
|
if ($quotaname eq 'author') { |
|
$quota = $env{'environment.authorquota'}; |
|
} else { |
|
$quota = $env{'environment.portfolioquota'}; |
|
} |
|
$inststatus = $env{'environment.inststatus'}; |
|
} else { |
|
my %userenv = |
|
&Apache::lonnet::get('environment',['portfolioquota', |
|
'authorquota','inststatus'],$udom,$uname); |
|
my ($tmp) = keys(%userenv); |
|
if ($tmp !~ /^(con_lost|error|no_such_host)/i) { |
|
if ($quotaname eq 'author') { |
|
$quota = $userenv{'authorquota'}; |
|
} else { |
|
$quota = $userenv{'portfolioquota'}; |
|
} |
|
$inststatus = $userenv{'inststatus'}; |
|
} else { |
|
undef(%userenv); |
|
} |
|
} |
|
} |
|
if ($quota eq '' || wantarray) { |
|
if ($quotaname eq 'course') { |
|
my %domdefs = &Apache::lonnet::get_domain_defaults($udom); |
|
if (($crstype eq 'official') || ($crstype eq 'unofficial') || |
|
($crstype eq 'community') || ($crstype eq 'textbook')) { |
|
$defquota = $domdefs{$crstype.'quota'}; |
|
} |
|
if ($defquota eq '') { |
|
$defquota = 500; |
|
} |
|
} else { |
|
($defquota,$settingstatus) = &default_quota($udom,$inststatus,$quotaname); |
|
} |
|
if ($quota eq '') { |
|
$quota = $defquota; |
|
$quotatype = 'default'; |
|
} else { |
|
$quotatype = 'custom'; |
|
} |
} |
} |
} |
} |
if (wantarray) { |
if (wantarray) { |
Line 5434 Retrieves default quota assigned for sto
|
Line 10842 Retrieves default quota assigned for sto
|
given an (optional) user's institutional status. |
given an (optional) user's institutional status. |
|
|
Incoming parameters: |
Incoming parameters: |
|
|
1. domain |
1. domain |
2. (Optional) institutional status(es). This is a : separated list of |
2. (Optional) institutional status(es). This is a : separated list of |
status types (e.g., faculty, staff, student etc.) |
status types (e.g., faculty, staff, student etc.) |
which apply to the user for whom the default is being retrieved. |
which apply to the user for whom the default is being retrieved. |
If the institutional status string in undefined, the domain |
If the institutional status string in undefined, the domain |
default quota will be returned. |
default quota will be returned. |
|
3. quota name - portfolio, author, or course |
|
(if no quota name provided, defaults to portfolio). |
|
|
Returns: |
Returns: |
1. Default disk quota (in Mb) for user portfolios in the domain. |
|
|
1. Default disk quota (in MB) for user portfolios in the domain. |
2. (Optional) institutional type which determined the value of the |
2. (Optional) institutional type which determined the value of the |
default quota. |
default quota. |
|
|
If a value has been stored in the domain's configuration db, |
If a value has been stored in the domain's configuration db, |
it will return that, otherwise it returns 20 (for backwards |
it will return that, otherwise it returns 20 (for backwards |
compatibility with domains which have not set up a configuration |
compatibility with domains which have not set up a configuration |
db file; the original statically defined portfolio quota was 20 Mb). |
db file; the original statically defined portfolio quota was 20 MB). |
|
|
If the user's status includes multiple types (e.g., staff and student), |
If the user's status includes multiple types (e.g., staff and student), |
the largest default quota which applies to the user determines the |
the largest default quota which applies to the user determines the |
Line 5461 default quota returned.
|
Line 10873 default quota returned.
|
|
|
|
|
sub default_quota { |
sub default_quota { |
my ($udom,$inststatus) = @_; |
my ($udom,$inststatus,$quotaname) = @_; |
my ($defquota,$settingstatus); |
my ($defquota,$settingstatus); |
my %quotahash = &Apache::lonnet::get_dom('configuration', |
my %quotahash = &Apache::lonnet::get_dom('configuration', |
['quota'],$udom); |
['quotas'],$udom); |
if (ref($quotahash{'quota'}) eq 'HASH') { |
my $key = 'defaultquota'; |
|
if ($quotaname eq 'author') { |
|
$key = 'authorquota'; |
|
} |
|
if (ref($quotahash{'quotas'}) eq 'HASH') { |
if ($inststatus ne '') { |
if ($inststatus ne '') { |
my @statuses = split(/:/,$inststatus); |
my @statuses = map { &unescape($_); } split(/:/,$inststatus); |
foreach my $item (@statuses) { |
foreach my $item (@statuses) { |
if ($quotahash{'quota'}{$item} ne '') { |
if (ref($quotahash{'quotas'}{$key}) eq 'HASH') { |
if ($defquota eq '') { |
if ($quotahash{'quotas'}{$key}{$item} ne '') { |
$defquota = $quotahash{'quota'}{$item}; |
if ($defquota eq '') { |
$settingstatus = $item; |
$defquota = $quotahash{'quotas'}{$key}{$item}; |
} elsif ($quotahash{'quota'}{$item} > $defquota) { |
$settingstatus = $item; |
$defquota = $quotahash{'quota'}{$item}; |
} elsif ($quotahash{'quotas'}{$key}{$item} > $defquota) { |
$settingstatus = $item; |
$defquota = $quotahash{'quotas'}{$key}{$item}; |
|
$settingstatus = $item; |
|
} |
|
} |
|
} elsif ($key eq 'defaultquota') { |
|
if ($quotahash{'quotas'}{$item} ne '') { |
|
if ($defquota eq '') { |
|
$defquota = $quotahash{'quotas'}{$item}; |
|
$settingstatus = $item; |
|
} elsif ($quotahash{'quotas'}{$item} > $defquota) { |
|
$defquota = $quotahash{'quotas'}{$item}; |
|
$settingstatus = $item; |
|
} |
} |
} |
} |
} |
} |
} |
} |
} |
if ($defquota eq '') { |
if ($defquota eq '') { |
$defquota = $quotahash{'quota'}{'default'}; |
if (ref($quotahash{'quotas'}{$key}) eq 'HASH') { |
|
$defquota = $quotahash{'quotas'}{$key}{'default'}; |
|
} elsif ($key eq 'defaultquota') { |
|
$defquota = $quotahash{'quotas'}{'default'}; |
|
} |
$settingstatus = 'default'; |
$settingstatus = 'default'; |
|
if ($defquota eq '') { |
|
if ($quotaname eq 'author') { |
|
$defquota = 500; |
|
} |
|
} |
} |
} |
} else { |
} else { |
$settingstatus = 'default'; |
$settingstatus = 'default'; |
$defquota = 20; |
if ($quotaname eq 'author') { |
|
$defquota = 500; |
|
} else { |
|
$defquota = 20; |
|
} |
} |
} |
if (wantarray) { |
if (wantarray) { |
return ($defquota,$settingstatus); |
return ($defquota,$settingstatus); |
Line 5495 sub default_quota {
|
Line 10936 sub default_quota {
|
} |
} |
} |
} |
|
|
|
############################################### |
|
|
|
=pod |
|
|
|
=item * &excess_filesize_warning() |
|
|
|
Returns warning message if upload of file to authoring space, or copying |
|
of existing file within authoring space will cause quota for the authoring |
|
space to be exceeded. |
|
|
|
Same, if upload of a file directly to a course/community via Course Editor |
|
will cause quota for uploaded content for the course to be exceeded. |
|
|
|
Inputs: 7 |
|
1. username or coursenum |
|
2. domain |
|
3. context ('author' or 'course') |
|
4. filename of file for which action is being requested |
|
5. filesize (kB) of file |
|
6. action being taken: copy or upload. |
|
7. quotatype (in course context -- official, unofficial, community or textbook). |
|
|
|
Returns: 1 scalar: HTML to display containing warning if quota would be exceeded, |
|
otherwise return null. |
|
|
|
=back |
|
|
|
=cut |
|
|
|
sub excess_filesize_warning { |
|
my ($uname,$udom,$context,$filename,$filesize,$action,$quotatype) = @_; |
|
my $current_disk_usage = 0; |
|
my $disk_quota = &get_user_quota($uname,$udom,$context,$quotatype); #expressed in MB |
|
if ($context eq 'author') { |
|
my $authorspace = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname"; |
|
$current_disk_usage = &Apache::lonnet::diskusage($udom,$uname,$authorspace); |
|
} else { |
|
foreach my $subdir ('docs','supplemental') { |
|
$current_disk_usage += &Apache::lonnet::diskusage($udom,$uname,"userfiles/$subdir",1); |
|
} |
|
} |
|
$disk_quota = int($disk_quota * 1000); |
|
if (($current_disk_usage + $filesize) > $disk_quota) { |
|
return '<p class="LC_warning">'. |
|
&mt("Unable to $action [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.", |
|
'<span class="LC_filename">'.$filename.'</span>',$filesize).'</p>'. |
|
'<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', |
|
$disk_quota,$current_disk_usage). |
|
'</p>'; |
|
} |
|
return; |
|
} |
|
|
|
############################################### |
|
|
|
|
sub get_secgrprole_info { |
sub get_secgrprole_info { |
my ($cdom,$cnum,$needroles,$type) = @_; |
my ($cdom,$cnum,$needroles,$type) = @_; |
my %sections_count = &get_sections($cdom,$cnum); |
my %sections_count = &get_sections($cdom,$cnum); |
Line 5532 sub get_secgrprole_info {
|
Line 11029 sub get_secgrprole_info {
|
return (\@sections,\@groups,$allroles,$rolehash,$accesshash); |
return (\@sections,\@groups,$allroles,$rolehash,$accesshash); |
} |
} |
|
|
|
sub user_picker { |
|
my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context,$fixeddom,$noinstd) = @_; |
|
my $currdom = $dom; |
|
my @alldoms = &Apache::lonnet::all_domains(); |
|
if (@alldoms == 1) { |
|
my %domsrch = &Apache::lonnet::get_dom('configuration', |
|
['directorysrch'],$alldoms[0]); |
|
my $domdesc = &Apache::lonnet::domain($alldoms[0],'description'); |
|
my $showdom = $domdesc; |
|
if ($showdom eq '') { |
|
$showdom = $dom; |
|
} |
|
if (ref($domsrch{'directorysrch'}) eq 'HASH') { |
|
if ((!$domsrch{'directorysrch'}{'available'}) && |
|
($domsrch{'directorysrch'}{'lcavailable'} eq '0')) { |
|
return (&mt('LON-CAPA directory search is not available in domain: [_1]',$showdom),0); |
|
} |
|
} |
|
} |
|
my %curr_selected = ( |
|
srchin => 'dom', |
|
srchby => 'lastname', |
|
); |
|
my $srchterm; |
|
if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) { |
|
if ($srch->{'srchby'} ne '') { |
|
$curr_selected{'srchby'} = $srch->{'srchby'}; |
|
} |
|
if ($srch->{'srchin'} ne '') { |
|
$curr_selected{'srchin'} = $srch->{'srchin'}; |
|
} |
|
if ($srch->{'srchtype'} ne '') { |
|
$curr_selected{'srchtype'} = $srch->{'srchtype'}; |
|
} |
|
if ($srch->{'srchdomain'} ne '') { |
|
$currdom = $srch->{'srchdomain'}; |
|
} |
|
$srchterm = $srch->{'srchterm'}; |
|
} |
|
my %html_lt=&Apache::lonlocal::texthash( |
|
'usr' => 'Search criteria', |
|
'doma' => 'Domain/institution to search', |
|
'uname' => 'username', |
|
'lastname' => 'last name', |
|
'lastfirst' => 'last name, first name', |
|
'crs' => 'in this course', |
|
'dom' => 'in selected LON-CAPA domain', |
|
'alc' => 'all LON-CAPA', |
|
'instd' => 'in institutional directory for selected domain', |
|
'exact' => 'is', |
|
'contains' => 'contains', |
|
'begins' => 'begins with', |
|
); |
|
my %js_lt=&Apache::lonlocal::texthash( |
|
'youm' => "You must include some text to search for.", |
|
'thte' => "The text you are searching for must contain at least two characters when using a 'begins' type search.", |
|
'thet' => "The text you are searching for must contain at least three characters when using a 'contains' type search.", |
|
'yomc' => "You must choose a domain when using an institutional directory search.", |
|
'ymcd' => "You must choose a domain when using a domain search.", |
|
'whus' => "When using searching by last,first you must include a comma as separator between last name and first name.", |
|
'whse' => "When searching by last,first you must include at least one character in the first name.", |
|
'thfo' => "The following need to be corrected before the search can be run:", |
|
); |
|
&html_escape(\%html_lt); |
|
&js_escape(\%js_lt); |
|
my $domform; |
|
my $allow_blank = 1; |
|
if ($fixeddom) { |
|
$allow_blank = 0; |
|
$domform = &select_dom_form($currdom,'srchdomain',$allow_blank,1,undef,[$currdom]); |
|
} else { |
|
$domform = &select_dom_form($currdom,'srchdomain',$allow_blank,1); |
|
} |
|
my $srchinsel = ' <select name="srchin">'; |
|
|
|
my @srchins = ('crs','dom','alc','instd'); |
|
|
|
foreach my $option (@srchins) { |
|
# FIXME 'alc' option unavailable until |
|
# loncreateuser::print_user_query_page() |
|
# has been completed. |
|
next if ($option eq 'alc'); |
|
next if (($option eq 'crs') && ($env{'form.form'} eq 'requestcrs')); |
|
next if ($option eq 'crs' && !$env{'request.course.id'}); |
|
next if (($option eq 'instd') && ($noinstd)); |
|
if ($curr_selected{'srchin'} eq $option) { |
|
$srchinsel .= ' |
|
<option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>'; |
|
} else { |
|
$srchinsel .= ' |
|
<option value="'.$option.'">'.$html_lt{$option}.'</option>'; |
|
} |
|
} |
|
$srchinsel .= "\n </select>\n"; |
|
|
|
my $srchbysel = ' <select name="srchby">'; |
|
foreach my $option ('lastname','lastfirst','uname') { |
|
if ($curr_selected{'srchby'} eq $option) { |
|
$srchbysel .= ' |
|
<option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>'; |
|
} else { |
|
$srchbysel .= ' |
|
<option value="'.$option.'">'.$html_lt{$option}.'</option>'; |
|
} |
|
} |
|
$srchbysel .= "\n </select>\n"; |
|
|
|
my $srchtypesel = ' <select name="srchtype">'; |
|
foreach my $option ('begins','contains','exact') { |
|
if ($curr_selected{'srchtype'} eq $option) { |
|
$srchtypesel .= ' |
|
<option value="'.$option.'" selected="selected">'.$html_lt{$option}.'</option>'; |
|
} else { |
|
$srchtypesel .= ' |
|
<option value="'.$option.'">'.$html_lt{$option}.'</option>'; |
|
} |
|
} |
|
$srchtypesel .= "\n </select>\n"; |
|
|
|
my ($newuserscript,$new_user_create); |
|
my $context_dom = $env{'request.role.domain'}; |
|
if ($context eq 'requestcrs') { |
|
if ($env{'form.coursedom'} ne '') { |
|
$context_dom = $env{'form.coursedom'}; |
|
} |
|
} |
|
if ($forcenewuser) { |
|
if (ref($srch) eq 'HASH') { |
|
if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $context_dom) { |
|
if ($cancreate) { |
|
$new_user_create = '<p> <input type="submit" name="forcenew" value="'.&HTML::Entities::encode(&mt('Make new user "[_1]"',$srchterm),'<>&"').'" onclick="javascript:setSearch(\'1\','.$caller.');" /> </p>'; |
|
} else { |
|
my $helplink = 'javascript:helpMenu('."'display'".')'; |
|
my %usertypetext = ( |
|
official => 'institutional', |
|
unofficial => 'non-institutional', |
|
); |
|
$new_user_create = '<p class="LC_warning">' |
|
.&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.") |
|
.' ' |
|
.&mt('Please contact the [_1]helpdesk[_2] for assistance.' |
|
,'<a href="'.$helplink.'">','</a>') |
|
.'</p><br />'; |
|
} |
|
} |
|
} |
|
|
|
$newuserscript = <<"ENDSCRIPT"; |
|
|
|
function setSearch(createnew,callingForm) { |
|
if (createnew == 1) { |
|
for (var i=0; i<callingForm.srchby.length; i++) { |
|
if (callingForm.srchby.options[i].value == 'uname') { |
|
callingForm.srchby.selectedIndex = i; |
|
} |
|
} |
|
for (var i=0; i<callingForm.srchin.length; i++) { |
|
if ( callingForm.srchin.options[i].value == 'dom') { |
|
callingForm.srchin.selectedIndex = i; |
|
} |
|
} |
|
for (var i=0; i<callingForm.srchtype.length; i++) { |
|
if (callingForm.srchtype.options[i].value == 'exact') { |
|
callingForm.srchtype.selectedIndex = i; |
|
} |
|
} |
|
for (var i=0; i<callingForm.srchdomain.length; i++) { |
|
if (callingForm.srchdomain.options[i].value == '$context_dom') { |
|
callingForm.srchdomain.selectedIndex = i; |
|
} |
|
} |
|
} |
|
} |
|
ENDSCRIPT |
|
|
|
} |
|
|
|
my $output = <<"END_BLOCK"; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
function validateEntry(callingForm) { |
|
|
|
var checkok = 1; |
|
var srchin; |
|
for (var i=0; i<callingForm.srchin.length; i++) { |
|
if ( callingForm.srchin[i].checked ) { |
|
srchin = callingForm.srchin[i].value; |
|
} |
|
} |
|
|
|
var srchtype = callingForm.srchtype.options[callingForm.srchtype.selectedIndex].value; |
|
var srchby = callingForm.srchby.options[callingForm.srchby.selectedIndex].value; |
|
var srchdomain = callingForm.srchdomain.options[callingForm.srchdomain.selectedIndex].value; |
|
var srchterm = callingForm.srchterm.value; |
|
var srchin = callingForm.srchin.options[callingForm.srchin.selectedIndex].value; |
|
var msg = ""; |
|
|
|
if (srchterm == "") { |
|
checkok = 0; |
|
msg += "$js_lt{'youm'}\\n"; |
|
} |
|
|
|
if (srchtype== 'begins') { |
|
if (srchterm.length < 2) { |
|
checkok = 0; |
|
msg += "$js_lt{'thte'}\\n"; |
|
} |
|
} |
|
|
|
if (srchtype== 'contains') { |
|
if (srchterm.length < 3) { |
|
checkok = 0; |
|
msg += "$js_lt{'thet'}\\n"; |
|
} |
|
} |
|
if (srchin == 'instd') { |
|
if (srchdomain == '') { |
|
checkok = 0; |
|
msg += "$js_lt{'yomc'}\\n"; |
|
} |
|
} |
|
if (srchin == 'dom') { |
|
if (srchdomain == '') { |
|
checkok = 0; |
|
msg += "$js_lt{'ymcd'}\\n"; |
|
} |
|
} |
|
if (srchby == 'lastfirst') { |
|
if (srchterm.indexOf(",") == -1) { |
|
checkok = 0; |
|
msg += "$js_lt{'whus'}\\n"; |
|
} |
|
if (srchterm.indexOf(",") == srchterm.length -1) { |
|
checkok = 0; |
|
msg += "$js_lt{'whse'}\\n"; |
|
} |
|
} |
|
if (checkok == 0) { |
|
alert("$js_lt{'thfo'}\\n"+msg); |
|
return; |
|
} |
|
if (checkok == 1) { |
|
callingForm.submit(); |
|
} |
|
} |
|
|
|
$newuserscript |
|
|
|
// ]]> |
|
</script> |
|
|
|
$new_user_create |
|
|
|
END_BLOCK |
|
|
|
$output .= &Apache::lonhtmlcommon::start_pick_box(). |
|
&Apache::lonhtmlcommon::row_title($html_lt{'doma'}). |
|
$domform. |
|
&Apache::lonhtmlcommon::row_closure(). |
|
&Apache::lonhtmlcommon::row_title($html_lt{'usr'}). |
|
$srchbysel. |
|
$srchtypesel. |
|
'<input type="text" size="15" name="srchterm" value="'.$srchterm.'" />'. |
|
$srchinsel. |
|
&Apache::lonhtmlcommon::row_closure(1). |
|
&Apache::lonhtmlcommon::end_pick_box(). |
|
'<br />'; |
|
return ($output,1); |
|
} |
|
|
|
sub user_rule_check { |
|
my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_; |
|
my ($response,%inst_response); |
|
if (ref($usershash) eq 'HASH') { |
|
if (keys(%{$usershash}) > 1) { |
|
my (%by_username,%by_id,%userdoms); |
|
my $checkid; |
|
if (ref($checks) eq 'HASH') { |
|
if ((!defined($checks->{'username'})) && (defined($checks->{'id'}))) { |
|
$checkid = 1; |
|
} |
|
} |
|
foreach my $user (keys(%{$usershash})) { |
|
my ($uname,$udom) = split(/:/,$user); |
|
if ($checkid) { |
|
if (ref($usershash->{$user}) eq 'HASH') { |
|
if ($usershash->{$user}->{'id'} ne '') { |
|
$by_id{$udom}{$usershash->{$user}->{'id'}} = $uname; |
|
$userdoms{$udom} = 1; |
|
if (ref($inst_results) eq 'HASH') { |
|
$inst_results->{$uname.':'.$udom} = {}; |
|
} |
|
} |
|
} |
|
} else { |
|
$by_username{$udom}{$uname} = 1; |
|
$userdoms{$udom} = 1; |
|
if (ref($inst_results) eq 'HASH') { |
|
$inst_results->{$uname.':'.$udom} = {}; |
|
} |
|
} |
|
} |
|
foreach my $udom (keys(%userdoms)) { |
|
if (!$got_rules->{$udom}) { |
|
my %domconfig = &Apache::lonnet::get_dom('configuration', |
|
['usercreation'],$udom); |
|
if (ref($domconfig{'usercreation'}) eq 'HASH') { |
|
foreach my $item ('username','id') { |
|
if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { |
|
$$curr_rules{$udom}{$item} = |
|
$domconfig{'usercreation'}{$item.'_rule'}; |
|
} |
|
} |
|
} |
|
$got_rules->{$udom} = 1; |
|
} |
|
} |
|
if ($checkid) { |
|
foreach my $udom (keys(%by_id)) { |
|
my ($outcome,$results) = &Apache::lonnet::get_multiple_instusers($udom,$by_id{$udom},'id'); |
|
if ($outcome eq 'ok') { |
|
foreach my $id (keys(%{$by_id{$udom}})) { |
|
my $uname = $by_id{$udom}{$id}; |
|
$inst_response{$uname.':'.$udom} = $outcome; |
|
} |
|
if (ref($results) eq 'HASH') { |
|
foreach my $uname (keys(%{$results})) { |
|
if (exists($inst_response{$uname.':'.$udom})) { |
|
$inst_response{$uname.':'.$udom} = $outcome; |
|
$inst_results->{$uname.':'.$udom} = $results->{$uname}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
foreach my $udom (keys(%by_username)) { |
|
my ($outcome,$results) = &Apache::lonnet::get_multiple_instusers($udom,$by_username{$udom}); |
|
if ($outcome eq 'ok') { |
|
foreach my $uname (keys(%{$by_username{$udom}})) { |
|
$inst_response{$uname.':'.$udom} = $outcome; |
|
} |
|
if (ref($results) eq 'HASH') { |
|
foreach my $uname (keys(%{$results})) { |
|
$inst_results->{$uname.':'.$udom} = $results->{$uname}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} elsif (keys(%{$usershash}) == 1) { |
|
my $user = (keys(%{$usershash}))[0]; |
|
my ($uname,$udom) = split(/:/,$user); |
|
if (($udom ne '') && ($uname ne '')) { |
|
if (ref($usershash->{$user}) eq 'HASH') { |
|
if (ref($checks) eq 'HASH') { |
|
if (defined($checks->{'username'})) { |
|
($inst_response{$user},%{$inst_results->{$user}}) = |
|
&Apache::lonnet::get_instuser($udom,$uname); |
|
} elsif (defined($checks->{'id'})) { |
|
if ($usershash->{$user}->{'id'} ne '') { |
|
($inst_response{$user},%{$inst_results->{$user}}) = |
|
&Apache::lonnet::get_instuser($udom,undef, |
|
$usershash->{$user}->{'id'}); |
|
} else { |
|
($inst_response{$user},%{$inst_results->{$user}}) = |
|
&Apache::lonnet::get_instuser($udom,$uname); |
|
} |
|
} |
|
} else { |
|
($inst_response{$user},%{$inst_results->{$user}}) = |
|
&Apache::lonnet::get_instuser($udom,$uname); |
|
return; |
|
} |
|
if (!$got_rules->{$udom}) { |
|
my %domconfig = &Apache::lonnet::get_dom('configuration', |
|
['usercreation'],$udom); |
|
if (ref($domconfig{'usercreation'}) eq 'HASH') { |
|
foreach my $item ('username','id') { |
|
if (ref($domconfig{'usercreation'}{$item.'_rule'}) eq 'ARRAY') { |
|
$$curr_rules{$udom}{$item} = |
|
$domconfig{'usercreation'}{$item.'_rule'}; |
|
} |
|
} |
|
} |
|
$got_rules->{$udom} = 1; |
|
} |
|
} |
|
} else { |
|
return; |
|
} |
|
} else { |
|
return; |
|
} |
|
foreach my $user (keys(%{$usershash})) { |
|
my ($uname,$udom) = split(/:/,$user); |
|
next if (($udom eq '') || ($uname eq '')); |
|
my $id; |
|
if (ref($inst_results) eq 'HASH') { |
|
if (ref($inst_results->{$user}) eq 'HASH') { |
|
$id = $inst_results->{$user}->{'id'}; |
|
} |
|
} |
|
if ($id eq '') { |
|
if (ref($usershash->{$user})) { |
|
$id = $usershash->{$user}->{'id'}; |
|
} |
|
} |
|
foreach my $item (keys(%{$checks})) { |
|
if (ref($$curr_rules{$udom}) eq 'HASH') { |
|
if (ref($$curr_rules{$udom}{$item}) eq 'ARRAY') { |
|
if (@{$$curr_rules{$udom}{$item}} > 0) { |
|
my %rule_check = &Apache::lonnet::inst_rulecheck($udom,$uname,$id,$item, |
|
$$curr_rules{$udom}{$item}); |
|
foreach my $rule (@{$$curr_rules{$udom}{$item}}) { |
|
if ($rule_check{$rule}) { |
|
$$rulematch{$user}{$item} = $rule; |
|
if ($inst_response{$user} eq 'ok') { |
|
if (ref($inst_results) eq 'HASH') { |
|
if (ref($inst_results->{$user}) eq 'HASH') { |
|
if (keys(%{$inst_results->{$user}}) == 0) { |
|
$$alerts{$item}{$udom}{$uname} = 1; |
|
} elsif ($item eq 'id') { |
|
if ($inst_results->{$user}->{'id'} eq '') { |
|
$$alerts{$item}{$udom}{$uname} = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
sub user_rule_formats { |
|
my ($domain,$domdesc,$curr_rules,$check) = @_; |
|
my %text = ( |
|
'username' => 'Usernames', |
|
'id' => 'IDs', |
|
); |
|
my $output; |
|
my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($domain,$check); |
|
if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) { |
|
if (@{$ruleorder} > 0) { |
|
$output = '<br />'. |
|
&mt($text{$check}.' with the following format(s) may [_1]only[_2] be used for verified users at [_3]:', |
|
'<span class="LC_cusr_emph">','</span>',$domdesc). |
|
' <ul>'; |
|
foreach my $rule (@{$ruleorder}) { |
|
if (ref($curr_rules) eq 'ARRAY') { |
|
if (grep(/^\Q$rule\E$/,@{$curr_rules})) { |
|
if (ref($rules->{$rule}) eq 'HASH') { |
|
$output .= '<li>'.$rules->{$rule}{'name'}.': '. |
|
$rules->{$rule}{'desc'}.'</li>'; |
|
} |
|
} |
|
} |
|
} |
|
$output .= '</ul>'; |
|
} |
|
} |
|
return $output; |
|
} |
|
|
|
sub instrule_disallow_msg { |
|
my ($checkitem,$domdesc,$count,$mode) = @_; |
|
my $response; |
|
my %text = ( |
|
item => 'username', |
|
items => 'usernames', |
|
match => 'matches', |
|
do => 'does', |
|
action => 'a username', |
|
one => 'one', |
|
); |
|
if ($count > 1) { |
|
$text{'item'} = 'usernames'; |
|
$text{'match'} ='match'; |
|
$text{'do'} = 'do'; |
|
$text{'action'} = 'usernames', |
|
$text{'one'} = 'ones'; |
|
} |
|
if ($checkitem eq 'id') { |
|
$text{'items'} = 'IDs'; |
|
$text{'item'} = 'ID'; |
|
$text{'action'} = 'an ID'; |
|
if ($count > 1) { |
|
$text{'item'} = 'IDs'; |
|
$text{'action'} = 'IDs'; |
|
} |
|
} |
|
$response = &mt("The $text{'item'} you chose $text{'match'} the format of $text{'items'} defined for [_1], but the $text{'item'} $text{'do'} not exist in the institutional directory.",'<span class="LC_cusr_emph">'.$domdesc.'</span>').'<br />'; |
|
if ($mode eq 'upload') { |
|
if ($checkitem eq 'username') { |
|
$response .= &mt("You will need to modify your upload file so it will include $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}."); |
|
} elsif ($checkitem eq 'id') { |
|
$response .= &mt("Either upload a file which includes $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or when associating fields with data columns, omit an association for the Student/Employee ID field."); |
|
} |
|
} elsif ($mode eq 'selfcreate') { |
|
if ($checkitem eq 'id') { |
|
$response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank."); |
|
} |
|
} else { |
|
if ($checkitem eq 'username') { |
|
$response .= &mt("You must choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}."); |
|
} elsif ($checkitem eq 'id') { |
|
$response .= &mt("You must either choose $text{'action'} with a different format -- $text{'one'} that will not conflict with 'official' institutional $text{'items'}, or leave the ID field blank."); |
|
} |
|
} |
|
return $response; |
|
} |
|
|
|
sub personal_data_fieldtitles { |
|
my %fieldtitles = &Apache::lonlocal::texthash ( |
|
id => 'Student/Employee ID', |
|
permanentemail => 'E-mail address', |
|
lastname => 'Last Name', |
|
firstname => 'First Name', |
|
middlename => 'Middle Name', |
|
generation => 'Generation', |
|
gen => 'Generation', |
|
inststatus => 'Affiliation', |
|
); |
|
return %fieldtitles; |
|
} |
|
|
|
sub sorted_inst_types { |
|
my ($dom) = @_; |
|
my ($usertypes,$order); |
|
my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); |
|
if (ref($domdefaults{'inststatus'}) eq 'HASH') { |
|
$usertypes = $domdefaults{'inststatus'}{'inststatustypes'}; |
|
$order = $domdefaults{'inststatus'}{'inststatusorder'}; |
|
} else { |
|
($usertypes,$order) = &Apache::lonnet::retrieve_inst_usertypes($dom); |
|
} |
|
my $othertitle = &mt('All users'); |
|
if ($env{'request.course.id'}) { |
|
$othertitle = &mt('Any users'); |
|
} |
|
my @types; |
|
if (ref($order) eq 'ARRAY') { |
|
@types = @{$order}; |
|
} |
|
if (@types == 0) { |
|
if (ref($usertypes) eq 'HASH') { |
|
@types = sort(keys(%{$usertypes})); |
|
} |
|
} |
|
if (keys(%{$usertypes}) > 0) { |
|
$othertitle = &mt('Other users'); |
|
} |
|
return ($othertitle,$usertypes,\@types); |
|
} |
|
|
|
sub get_institutional_codes { |
|
my ($cdom,$crs,$settings,$allcourses,$LC_code) = @_; |
|
# Get complete list of course sections to update |
|
my @currsections = (); |
|
my @currxlists = (); |
|
my (%unclutteredsec,%unclutteredlcsec); |
|
my $coursecode = $$settings{'internal.coursecode'}; |
|
my $crskey = $crs.':'.$coursecode; |
|
@{$unclutteredsec{$crskey}} = (); |
|
@{$unclutteredlcsec{$crskey}} = (); |
|
|
|
if ($$settings{'internal.sectionnums'} ne '') { |
|
@currsections = split(/,/,$$settings{'internal.sectionnums'}); |
|
} |
|
|
|
if ($$settings{'internal.crosslistings'} ne '') { |
|
@currxlists = split(/,/,$$settings{'internal.crosslistings'}); |
|
} |
|
|
|
if (@currxlists > 0) { |
|
foreach my $xl (@currxlists) { |
|
if ($xl =~ /^([^:]+):(\w*)$/) { |
|
unless (grep/^$1$/,@{$allcourses}) { |
|
push(@{$allcourses},$1); |
|
$$LC_code{$1} = $2; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (@currsections > 0) { |
|
foreach my $sec (@currsections) { |
|
if ($sec =~ m/^(\w+):(\w*)$/ ) { |
|
my $instsec = $1; |
|
my $lc_sec = $2; |
|
unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) { |
|
push(@{$unclutteredsec{$crskey}},$instsec); |
|
push(@{$unclutteredlcsec{$crskey}},$lc_sec); |
|
} |
|
} |
|
} |
|
} |
|
|
|
if (@{$unclutteredsec{$crskey}} > 0) { |
|
my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',\%unclutteredsec); |
|
if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) { |
|
for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) { |
|
my $sec = $coursecode.$formattedsec{$crskey}[$i]; |
|
unless (grep/^\Q$sec\E$/,@{$allcourses}) { |
|
push(@{$allcourses},$sec); |
|
$$LC_code{$sec} = $unclutteredlcsec{$crskey}[$i]; |
|
} |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
sub get_standard_codeitems { |
|
return ('Year','Semester','Department','Number','Section'); |
|
} |
|
|
|
=pod |
|
|
|
=head1 Slot Helpers |
|
|
|
=over 4 |
|
|
|
=item * sorted_slots() |
|
|
|
Sorts an array of slot names in order of an optional sort key, |
|
default sort is by slot start time (earliest first). |
|
|
|
Inputs: |
|
|
|
=over 4 |
|
|
|
slotsarr - Reference to array of unsorted slot names. |
|
|
|
slots - Reference to hash of hash, where outer hash keys are slot names. |
|
|
|
sortkey - Name of key in inner hash to be sorted on (e.g., starttime). |
|
|
|
=back |
|
|
|
Returns: |
|
|
|
=over 4 |
|
|
|
sorted - An array of slot names sorted by a specified sort key |
|
(default sort key is start time of the slot). |
|
|
|
=back |
|
|
|
=cut |
|
|
|
|
|
sub sorted_slots { |
|
my ($slotsarr,$slots,$sortkey) = @_; |
|
if ($sortkey eq '') { |
|
$sortkey = 'starttime'; |
|
} |
|
my @sorted; |
|
if ((ref($slotsarr) eq 'ARRAY') && (ref($slots) eq 'HASH')) { |
|
@sorted = |
|
sort { |
|
if (ref($slots->{$a}) && ref($slots->{$b})) { |
|
return $slots->{$a}{$sortkey} <=> $slots->{$b}{$sortkey} |
|
} |
|
if (ref($slots->{$a})) { return -1;} |
|
if (ref($slots->{$b})) { return 1;} |
|
return 0; |
|
} @{$slotsarr}; |
|
} |
|
return @sorted; |
|
} |
|
|
|
=pod |
|
|
|
=item * get_future_slots() |
|
|
|
Inputs: |
|
|
|
=over 4 |
|
|
|
cnum - course number |
|
|
|
cdom - course domain |
|
|
|
now - current UNIX time |
|
|
|
symb - optional symb |
|
|
|
=back |
|
|
|
Returns: |
|
|
|
=over 4 |
|
|
|
sorted_reservable - ref to array of student_schedulable slots currently |
|
reservable, ordered by end date of reservation period. |
|
|
|
reservable_now - ref to hash of student_schedulable slots currently |
|
reservable. |
|
|
|
Keys in inner hash are: |
|
(a) symb: either blank or symb to which slot use is restricted. |
|
(b) endreserve: end date of reservation period. |
|
(c) uniqueperiod: start,end dates when slot is to be uniquely |
|
selected. |
|
|
|
sorted_future - ref to array of student_schedulable slots reservable in |
|
the future, ordered by start date of reservation period. |
|
|
|
future_reservable - ref to hash of student_schedulable slots reservable |
|
in the future. |
|
|
|
Keys in inner hash are: |
|
(a) symb: either blank or symb to which slot use is restricted. |
|
(b) startreserve: start date of reservation period. |
|
(c) uniqueperiod: start,end dates when slot is to be uniquely |
|
selected. |
|
|
|
=back |
|
|
|
=cut |
|
|
|
sub get_future_slots { |
|
my ($cnum,$cdom,$now,$symb) = @_; |
|
my (%reservable_now,%future_reservable,@sorted_reservable,@sorted_future); |
|
my %slots = &Apache::lonnet::get_course_slots($cnum,$cdom); |
|
foreach my $slot (keys(%slots)) { |
|
next unless($slots{$slot}->{'type'} eq 'schedulable_student'); |
|
if ($symb) { |
|
next if (($slots{$slot}->{'symb'} ne '') && |
|
($slots{$slot}->{'symb'} ne $symb)); |
|
} |
|
if (($slots{$slot}->{'starttime'} > $now) && |
|
($slots{$slot}->{'endtime'} > $now)) { |
|
if (($slots{$slot}->{'allowedsections'}) || ($slots{$slot}->{'allowedusers'})) { |
|
my $userallowed = 0; |
|
if ($slots{$slot}->{'allowedsections'}) { |
|
my @allowed_sec = split(',',$slots{$slot}->{'allowedsections'}); |
|
if (!defined($env{'request.role.sec'}) |
|
&& grep(/^No section assigned$/,@allowed_sec)) { |
|
$userallowed=1; |
|
} else { |
|
if (grep(/^\Q$env{'request.role.sec'}\E$/,@allowed_sec)) { |
|
$userallowed=1; |
|
} |
|
} |
|
unless ($userallowed) { |
|
if (defined($env{'request.course.groups'})) { |
|
my @groups = split(/:/,$env{'request.course.groups'}); |
|
foreach my $group (@groups) { |
|
if (grep(/^\Q$group\E$/,@allowed_sec)) { |
|
$userallowed=1; |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ($slots{$slot}->{'allowedusers'}) { |
|
my @allowed_users = split(',',$slots{$slot}->{'allowedusers'}); |
|
my $user = $env{'user.name'}.':'.$env{'user.domain'}; |
|
if (grep(/^\Q$user\E$/,@allowed_users)) { |
|
$userallowed = 1; |
|
} |
|
} |
|
next unless($userallowed); |
|
} |
|
my $startreserve = $slots{$slot}->{'startreserve'}; |
|
my $endreserve = $slots{$slot}->{'endreserve'}; |
|
my $symb = $slots{$slot}->{'symb'}; |
|
my $uniqueperiod; |
|
if (ref($slots{$slot}->{'uniqueperiod'}) eq 'ARRAY') { |
|
$uniqueperiod = join(',',@{$slots{$slot}->{'uniqueperiod'}}); |
|
} |
|
if (($startreserve < $now) && |
|
(!$endreserve || $endreserve > $now)) { |
|
my $lastres = $endreserve; |
|
if (!$lastres) { |
|
$lastres = $slots{$slot}->{'starttime'}; |
|
} |
|
$reservable_now{$slot} = { |
|
symb => $symb, |
|
endreserve => $lastres, |
|
uniqueperiod => $uniqueperiod, |
|
}; |
|
} elsif (($startreserve > $now) && |
|
(!$endreserve || $endreserve > $startreserve)) { |
|
$future_reservable{$slot} = { |
|
symb => $symb, |
|
startreserve => $startreserve, |
|
uniqueperiod => $uniqueperiod, |
|
}; |
|
} |
|
} |
|
} |
|
my @unsorted_reservable = keys(%reservable_now); |
|
if (@unsorted_reservable > 0) { |
|
@sorted_reservable = |
|
&sorted_slots(\@unsorted_reservable,\%reservable_now,'endreserve'); |
|
} |
|
my @unsorted_future = keys(%future_reservable); |
|
if (@unsorted_future > 0) { |
|
@sorted_future = |
|
&sorted_slots(\@unsorted_future,\%future_reservable,'startreserve'); |
|
} |
|
return (\@sorted_reservable,\%reservable_now,\@sorted_future,\%future_reservable); |
|
} |
|
|
=pod |
=pod |
|
|
=back |
=back |
Line 5540 sub get_secgrprole_info {
|
Line 11853 sub get_secgrprole_info {
|
|
|
=over 4 |
=over 4 |
|
|
=item * get_unprocessed_cgi($query,$possible_names) |
=item * &get_unprocessed_cgi($query,$possible_names) |
|
|
Modify the %env hash to contain unprocessed CGI form parameters held in |
Modify the %env hash to contain unprocessed CGI form parameters held in |
$query. The parameters listed in $possible_names (an array reference), |
$query. The parameters listed in $possible_names (an array reference), |
Line 5569 sub get_unprocessed_cgi {
|
Line 11882 sub get_unprocessed_cgi {
|
|
|
=pod |
=pod |
|
|
=item * cacheheader() |
=item * &cacheheader() |
|
|
returns cache-controlling header code |
returns cache-controlling header code |
|
|
Line 5586 sub cacheheader {
|
Line 11899 sub cacheheader {
|
|
|
=pod |
=pod |
|
|
=item * no_cache($r) |
=item * &no_cache($r) |
|
|
specifies header code to not have cache |
specifies header code to not have cache |
|
|
Line 5622 sub content_type {
|
Line 11935 sub content_type {
|
|
|
=pod |
=pod |
|
|
=item * add_to_env($name,$value) |
=item * &add_to_env($name,$value) |
|
|
adds $name to the %env hash with value |
adds $name to the %env hash with value |
$value, if $name already exists, the entry is converted to an array |
$value, if $name already exists, the entry is converted to an array |
Line 5649 sub add_to_env {
|
Line 11962 sub add_to_env {
|
|
|
=pod |
=pod |
|
|
=item * get_env_multiple($name) |
=item * &get_env_multiple($name) |
|
|
gets $name from the %env hash, it seemlessly handles the cases where multiple |
gets $name from the %env hash, it seemlessly handles the cases where multiple |
values may be defined and end up as an array ref. |
values may be defined and end up as an array ref. |
Line 5672 sub get_env_multiple {
|
Line 11985 sub get_env_multiple {
|
return(@values); |
return(@values); |
} |
} |
|
|
|
sub ask_for_embedded_content { |
|
my ($actionurl,$state,$allfiles,$codebase,$args)=@_; |
|
my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges, |
|
%currsubfile,%unused,$rem); |
|
my $counter = 0; |
|
my $numnew = 0; |
|
my $numremref = 0; |
|
my $numinvalid = 0; |
|
my $numpathchg = 0; |
|
my $numexisting = 0; |
|
my $numunused = 0; |
|
my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath,$cdom,$cnum, |
|
$fileloc,$filename,$delete_output,$modify_output,$title,$symb,$path,$navmap); |
|
my $heading = &mt('Upload embedded files'); |
|
my $buttontext = &mt('Upload'); |
|
|
|
if ($env{'request.course.id'}) { |
|
if ($actionurl eq '/adm/dependencies') { |
|
$navmap = Apache::lonnavmaps::navmap->new(); |
|
} |
|
$cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
$cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
} |
|
if (($actionurl eq '/adm/portfolio') || |
|
($actionurl eq '/adm/coursegrp_portfolio')) { |
|
my $current_path='/'; |
|
if ($env{'form.currentpath'}) { |
|
$current_path = $env{'form.currentpath'}; |
|
} |
|
if ($actionurl eq '/adm/coursegrp_portfolio') { |
|
$udom = $cdom; |
|
$uname = $cnum; |
|
$url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio'; |
|
} else { |
|
$udom = $env{'user.domain'}; |
|
$uname = $env{'user.name'}; |
|
$url = '/userfiles/portfolio'; |
|
} |
|
$toplevel = $url.'/'; |
|
$url .= $current_path; |
|
$getpropath = 1; |
|
} elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || |
|
($actionurl eq '/adm/imsimport')) { |
|
my ($udom,$uname,$rest) = ($args->{'current_path'} =~ m{/priv/($match_domain)/($match_username)/?(.*)$}); |
|
$url = $Apache::lonnet::perlvar{'lonDocRoot'}."/priv/$udom/$uname/"; |
|
$toplevel = $url; |
|
if ($rest ne '') { |
|
$url .= $rest; |
|
} |
|
} elsif ($actionurl eq '/adm/coursedocs') { |
|
if (ref($args) eq 'HASH') { |
|
$url = $args->{'docs_url'}; |
|
$toplevel = $url; |
|
if ($args->{'context'} eq 'paste') { |
|
($cdom,$cnum) = ($url =~ m{^\Q/uploaded/\E($match_domain)/($match_courseid)/}); |
|
($path) = |
|
($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/}); |
|
$fileloc = &Apache::lonnet::filelocation('',$toplevel); |
|
$fileloc =~ s{^/}{}; |
|
} |
|
} |
|
} elsif ($actionurl eq '/adm/dependencies') { |
|
if ($env{'request.course.id'} ne '') { |
|
if (ref($args) eq 'HASH') { |
|
$url = $args->{'docs_url'}; |
|
$title = $args->{'docs_title'}; |
|
$toplevel = $url; |
|
unless ($toplevel =~ m{^/}) { |
|
$toplevel = "/$url"; |
|
} |
|
($rem) = ($toplevel =~ m{^(.+/)[^/]+$}); |
|
if ($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E)}) { |
|
$path = $1; |
|
} else { |
|
($path) = |
|
($toplevel =~ m{^(\Q/uploaded/$cdom/$cnum/\E(?:docs|supplemental)/(?:default|\d+)/\d+)/}); |
|
} |
|
if ($toplevel=~/^\/*(uploaded|editupload)/) { |
|
$fileloc = $toplevel; |
|
$fileloc=~ s/^\s*(\S+)\s*$/$1/; |
|
my ($udom,$uname,$fname) = |
|
($fileloc=~ m{^/+(?:uploaded|editupload)/+($match_domain)/+($match_name)/+(.*)$}); |
|
$fileloc = propath($udom,$uname).'/userfiles/'.$fname; |
|
} else { |
|
$fileloc = &Apache::lonnet::filelocation('',$toplevel); |
|
} |
|
$fileloc =~ s{^/}{}; |
|
($filename) = ($fileloc =~ m{.+/([^/]+)$}); |
|
$heading = &mt('Status of dependencies in [_1]',"$title ($filename)"); |
|
} |
|
} |
|
} elsif ($actionurl eq "/public/$cdom/$cnum/syllabus") { |
|
$udom = $cdom; |
|
$uname = $cnum; |
|
$url = "/uploaded/$cdom/$cnum/portfolio/syllabus"; |
|
$toplevel = $url; |
|
$path = $url; |
|
$fileloc = &Apache::lonnet::filelocation('',$toplevel).'/'; |
|
$fileloc =~ s{^/}{}; |
|
} |
|
foreach my $file (keys(%{$allfiles})) { |
|
my $embed_file; |
|
if (($path eq "/uploaded/$cdom/$cnum/portfolio/syllabus") && ($file =~ m{^\Q$path/\E(.+)$})) { |
|
$embed_file = $1; |
|
} else { |
|
$embed_file = $file; |
|
} |
|
my ($absolutepath,$cleaned_file); |
|
if ($embed_file =~ m{^\w+://}) { |
|
$cleaned_file = $embed_file; |
|
$newfiles{$cleaned_file} = 1; |
|
$mapping{$cleaned_file} = $embed_file; |
|
} else { |
|
$cleaned_file = &clean_path($embed_file); |
|
if ($embed_file =~ m{^/}) { |
|
$absolutepath = $embed_file; |
|
} |
|
if ($cleaned_file =~ m{/}) { |
|
my ($path,$fname) = ($cleaned_file =~ m{^(.+)/([^/]*)$}); |
|
$path = &check_for_traversal($path,$url,$toplevel); |
|
my $item = $fname; |
|
if ($path ne '') { |
|
$item = $path.'/'.$fname; |
|
$subdependencies{$path}{$fname} = 1; |
|
} else { |
|
$dependencies{$item} = 1; |
|
} |
|
if ($absolutepath) { |
|
$mapping{$item} = $absolutepath; |
|
} else { |
|
$mapping{$item} = $embed_file; |
|
} |
|
} else { |
|
$dependencies{$embed_file} = 1; |
|
if ($absolutepath) { |
|
$mapping{$cleaned_file} = $absolutepath; |
|
} else { |
|
$mapping{$cleaned_file} = $embed_file; |
|
} |
|
} |
|
} |
|
} |
|
my $dirptr = 16384; |
|
foreach my $path (keys(%subdependencies)) { |
|
$currsubfile{$path} = {}; |
|
if (($actionurl eq '/adm/portfolio') || |
|
($actionurl eq '/adm/coursegrp_portfolio')) { |
|
my ($sublistref,$listerror) = |
|
&Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath); |
|
if (ref($sublistref) eq 'ARRAY') { |
|
foreach my $line (@{$sublistref}) { |
|
my ($file_name,$rest) = split(/\&/,$line,2); |
|
$currsubfile{$path}{$file_name} = 1; |
|
} |
|
} |
|
} elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { |
|
if (opendir(my $dir,$url.'/'.$path)) { |
|
my @subdir_list = grep(!/^\./,readdir($dir)); |
|
map {$currsubfile{$path}{$_} = 1;} @subdir_list; |
|
} |
|
} elsif (($actionurl eq '/adm/dependencies') || |
|
(($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') && |
|
($args->{'context'} eq 'paste')) || |
|
($actionurl eq "/public/$cdom/$cnum/syllabus")) { |
|
if ($env{'request.course.id'} ne '') { |
|
my $dir; |
|
if ($actionurl eq "/public/$cdom/$cnum/syllabus") { |
|
$dir = $fileloc; |
|
} else { |
|
($dir) = ($fileloc =~ m{^(.+/)[^/]+$}); |
|
} |
|
if ($dir ne '') { |
|
my ($sublistref,$listerror) = |
|
&Apache::lonnet::dirlist($dir.$path,$cdom,$cnum,$getpropath,undef,'/'); |
|
if (ref($sublistref) eq 'ARRAY') { |
|
foreach my $line (@{$sublistref}) { |
|
my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef,$size, |
|
undef,$mtime)=split(/\&/,$line,12); |
|
unless (($testdir&$dirptr) || |
|
($file_name =~ /^\.\.?$/)) { |
|
$currsubfile{$path}{$file_name} = [$size,$mtime]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
foreach my $file (keys(%{$subdependencies{$path}})) { |
|
if (exists($currsubfile{$path}{$file})) { |
|
my $item = $path.'/'.$file; |
|
unless ($mapping{$item} eq $item) { |
|
$pathchanges{$item} = 1; |
|
} |
|
$existing{$item} = 1; |
|
$numexisting ++; |
|
} else { |
|
$newfiles{$path.'/'.$file} = 1; |
|
} |
|
} |
|
if ($actionurl eq '/adm/dependencies') { |
|
foreach my $path (keys(%currsubfile)) { |
|
if (ref($currsubfile{$path}) eq 'HASH') { |
|
foreach my $file (keys(%{$currsubfile{$path}})) { |
|
unless ($subdependencies{$path}{$file}) { |
|
next if (($rem ne '') && |
|
(($env{"httpref.$rem"."$path/$file"} ne '') || |
|
(ref($navmap) && |
|
(($navmap->getResourceByUrl($rem."$path/$file") ne '') || |
|
(($file =~ /^(.*\.s?html?)\.bak$/i) && |
|
($navmap->getResourceByUrl($rem."$path/$1"))))))); |
|
$unused{$path.'/'.$file} = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
my %currfile; |
|
if (($actionurl eq '/adm/portfolio') || |
|
($actionurl eq '/adm/coursegrp_portfolio')) { |
|
my ($dirlistref,$listerror) = |
|
&Apache::lonnet::dirlist($url,$udom,$uname,$getpropath); |
|
if (ref($dirlistref) eq 'ARRAY') { |
|
foreach my $line (@{$dirlistref}) { |
|
my ($file_name,$rest) = split(/\&/,$line,2); |
|
$currfile{$file_name} = 1; |
|
} |
|
} |
|
} elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { |
|
if (opendir(my $dir,$url)) { |
|
my @dir_list = grep(!/^\./,readdir($dir)); |
|
map {$currfile{$_} = 1;} @dir_list; |
|
} |
|
} elsif (($actionurl eq '/adm/dependencies') || |
|
(($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') && |
|
($args->{'context'} eq 'paste')) || |
|
($actionurl eq "/public/$cdom/$cnum/syllabus")) { |
|
if ($env{'request.course.id'} ne '') { |
|
my ($dir) = ($fileloc =~ m{^(.+/)[^/]+$}); |
|
if ($dir ne '') { |
|
my ($dirlistref,$listerror) = |
|
&Apache::lonnet::dirlist($dir,$cdom,$cnum,$getpropath,undef,'/'); |
|
if (ref($dirlistref) eq 'ARRAY') { |
|
foreach my $line (@{$dirlistref}) { |
|
my ($file_name,$dom,undef,$testdir,undef,undef,undef,undef, |
|
$size,undef,$mtime)=split(/\&/,$line,12); |
|
unless (($testdir&$dirptr) || |
|
($file_name =~ /^\.\.?$/)) { |
|
$currfile{$file_name} = [$size,$mtime]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
foreach my $file (keys(%dependencies)) { |
|
if (exists($currfile{$file})) { |
|
unless ($mapping{$file} eq $file) { |
|
$pathchanges{$file} = 1; |
|
} |
|
$existing{$file} = 1; |
|
$numexisting ++; |
|
} else { |
|
$newfiles{$file} = 1; |
|
} |
|
} |
|
foreach my $file (keys(%currfile)) { |
|
unless (($file eq $filename) || |
|
($file eq $filename.'.bak') || |
|
($dependencies{$file})) { |
|
if ($actionurl eq '/adm/dependencies') { |
|
unless ($toplevel =~ m{^\Q/uploaded/$cdom/$cnum/portfolio/syllabus\E}) { |
|
next if (($rem ne '') && |
|
(($env{"httpref.$rem".$file} ne '') || |
|
(ref($navmap) && |
|
(($navmap->getResourceByUrl($rem.$file) ne '') || |
|
(($file =~ /^(.*\.s?html?)\.bak$/i) && |
|
($navmap->getResourceByUrl($rem.$1))))))); |
|
} |
|
} |
|
$unused{$file} = 1; |
|
} |
|
} |
|
if (($actionurl eq '/adm/coursedocs') && (ref($args) eq 'HASH') && |
|
($args->{'context'} eq 'paste')) { |
|
$counter = scalar(keys(%existing)); |
|
$numpathchg = scalar(keys(%pathchanges)); |
|
return ($output,$counter,$numpathchg,\%existing); |
|
} elsif (($actionurl eq "/public/$cdom/$cnum/syllabus") && |
|
(ref($args) eq 'HASH') && ($args->{'context'} eq 'rewrites')) { |
|
$counter = scalar(keys(%existing)); |
|
$numpathchg = scalar(keys(%pathchanges)); |
|
return ($output,$counter,$numpathchg,\%existing,\%mapping); |
|
} |
|
foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) { |
|
if ($actionurl eq '/adm/dependencies') { |
|
next if ($embed_file =~ m{^\w+://}); |
|
} |
|
$upload_output .= &start_data_table_row(). |
|
'<td valign="top"><img src="'.&icon($embed_file).'" /> '. |
|
'<span class="LC_filename">'.$embed_file.'</span>'; |
|
unless ($mapping{$embed_file} eq $embed_file) { |
|
$upload_output .= '<br /><span class="LC_info" style="font-size:smaller;">'. |
|
&mt('changed from: [_1]',$mapping{$embed_file}).'</span>'; |
|
} |
|
$upload_output .= '</td>'; |
|
if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { |
|
$upload_output.='<td align="right">'. |
|
'<span class="LC_info LC_fontsize_medium">'. |
|
&mt("URL points to web address").'</span>'; |
|
$numremref++; |
|
} elsif ($args->{'error_on_invalid_names'} |
|
&& $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) { |
|
$upload_output.='<td align="right"><span class="LC_warning">'. |
|
&mt('Invalid characters').'</span>'; |
|
$numinvalid++; |
|
} else { |
|
$upload_output .= '<td>'. |
|
&embedded_file_element('upload_embedded',$counter, |
|
$embed_file,\%mapping, |
|
$allfiles,$codebase,'upload'); |
|
$counter ++; |
|
$numnew ++; |
|
} |
|
$upload_output .= '</td>'.&Apache::loncommon::end_data_table_row()."\n"; |
|
} |
|
foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) { |
|
if ($actionurl eq '/adm/dependencies') { |
|
my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$embed_file); |
|
$modify_output .= &start_data_table_row(). |
|
'<td><a href="'.$path.'/'.$embed_file.'" style="text-decoration:none;">'. |
|
'<img src="'.&icon($embed_file).'" border="0" />'. |
|
' <span class="LC_filename">'.$embed_file.'</span></a></td>'. |
|
'<td>'.$size.'</td>'. |
|
'<td>'.$mtime.'</td>'. |
|
'<td><label><input type="checkbox" name="mod_upload_dep" '. |
|
'onclick="toggleBrowse('."'$counter'".')" id="mod_upload_dep_'. |
|
$counter.'" value="'.$counter.'" />'.&mt('Yes').'</label>'. |
|
'<div id="moduploaddep_'.$counter.'" style="display:none;">'. |
|
&embedded_file_element('upload_embedded',$counter, |
|
$embed_file,\%mapping, |
|
$allfiles,$codebase,'modify'). |
|
'</div></td>'. |
|
&end_data_table_row()."\n"; |
|
$counter ++; |
|
} else { |
|
$upload_output .= &start_data_table_row(). |
|
'<td valign="top"><img src="'.&icon($embed_file).'" /> '. |
|
'<span class="LC_filename">'.$embed_file.'</span></td>'. |
|
'<td align="right"><span class="LC_info LC_fontsize_medium">'.&mt('Already exists').'</span></td>'. |
|
&Apache::loncommon::end_data_table_row()."\n"; |
|
} |
|
} |
|
my $delidx = $counter; |
|
foreach my $oldfile (sort {lc($a) cmp lc($b)} keys(%unused)) { |
|
my ($size,$mtime) = &get_dependency_details(\%currfile,\%currsubfile,$oldfile); |
|
$delete_output .= &start_data_table_row(). |
|
'<td><img src="'.&icon($oldfile).'" />'. |
|
' <span class="LC_filename">'.$oldfile.'</span></td>'. |
|
'<td>'.$size.'</td>'. |
|
'<td>'.$mtime.'</td>'. |
|
'<td><label><input type="checkbox" name="del_upload_dep" '. |
|
' value="'.$delidx.'" />'.&mt('Yes').'</label>'. |
|
&embedded_file_element('upload_embedded',$delidx, |
|
$oldfile,\%mapping,$allfiles, |
|
$codebase,'delete').'</td>'. |
|
&end_data_table_row()."\n"; |
|
$numunused ++; |
|
$delidx ++; |
|
} |
|
if ($upload_output) { |
|
$upload_output = &start_data_table(). |
|
$upload_output. |
|
&end_data_table()."\n"; |
|
} |
|
if ($modify_output) { |
|
$modify_output = &start_data_table(). |
|
&start_data_table_header_row(). |
|
'<th>'.&mt('File').'</th>'. |
|
'<th>'.&mt('Size (KB)').'</th>'. |
|
'<th>'.&mt('Modified').'</th>'. |
|
'<th>'.&mt('Upload replacement?').'</th>'. |
|
&end_data_table_header_row(). |
|
$modify_output. |
|
&end_data_table()."\n"; |
|
} |
|
if ($delete_output) { |
|
$delete_output = &start_data_table(). |
|
&start_data_table_header_row(). |
|
'<th>'.&mt('File').'</th>'. |
|
'<th>'.&mt('Size (KB)').'</th>'. |
|
'<th>'.&mt('Modified').'</th>'. |
|
'<th>'.&mt('Delete?').'</th>'. |
|
&end_data_table_header_row(). |
|
$delete_output. |
|
&end_data_table()."\n"; |
|
} |
|
my $applies = 0; |
|
if ($numremref) { |
|
$applies ++; |
|
} |
|
if ($numinvalid) { |
|
$applies ++; |
|
} |
|
if ($numexisting) { |
|
$applies ++; |
|
} |
|
if ($counter || $numunused) { |
|
$output = '<form name="upload_embedded" action="'.$actionurl.'"'. |
|
' method="post" enctype="multipart/form-data">'."\n". |
|
$state.'<h3>'.$heading.'</h3>'; |
|
if ($actionurl eq '/adm/dependencies') { |
|
if ($numnew) { |
|
$output .= '<h4>'.&mt('Missing dependencies').'</h4>'. |
|
'<p>'.&mt('The following files need to be uploaded.').'</p>'."\n". |
|
$upload_output.'<br />'."\n"; |
|
} |
|
if ($numexisting) { |
|
$output .= '<h4>'.&mt('Uploaded dependencies (in use)').'</h4>'. |
|
'<p>'.&mt('Upload a new file to replace the one currently in use.').'</p>'."\n". |
|
$modify_output.'<br />'."\n"; |
|
$buttontext = &mt('Save changes'); |
|
} |
|
if ($numunused) { |
|
$output .= '<h4>'.&mt('Unused files').'</h4>'. |
|
'<p>'.&mt('The following uploaded files are no longer used.').'</p>'."\n". |
|
$delete_output.'<br />'."\n"; |
|
$buttontext = &mt('Save changes'); |
|
} |
|
} else { |
|
$output .= $upload_output.'<br />'."\n"; |
|
} |
|
$output .= '<input type ="hidden" name="number_embedded_items" value="'. |
|
$counter.'" />'."\n"; |
|
if ($actionurl eq '/adm/dependencies') { |
|
$output .= '<input type ="hidden" name="number_newemb_items" value="'. |
|
$numnew.'" />'."\n"; |
|
} elsif ($actionurl eq '') { |
|
$output .= '<input type="hidden" name="phase" value="three" />'; |
|
} |
|
} elsif ($applies) { |
|
$output = '<b>'.&mt('Referenced files').'</b>:<br />'; |
|
if ($applies > 1) { |
|
$output .= |
|
&mt('No dependencies need to be uploaded, as one of the following applies to each reference:').'<ul>'; |
|
if ($numremref) { |
|
$output .= '<li>'.&mt('reference is to a URL which points to another server').'</li>'."\n"; |
|
} |
|
if ($numinvalid) { |
|
$output .= '<li>'.&mt('reference is to file with a name containing invalid characters').'</li>'."\n"; |
|
} |
|
if ($numexisting) { |
|
$output .= '<li>'.&mt('reference is to an existing file at the specified location').'</li>'."\n"; |
|
} |
|
$output .= '</ul><br />'; |
|
} elsif ($numremref) { |
|
$output .= '<p>'.&mt('None to upload, as all references are to URLs pointing to another server.').'</p>'; |
|
} elsif ($numinvalid) { |
|
$output .= '<p>'.&mt('None to upload, as all references are to files with names containing invalid characters.').'</p>'; |
|
} elsif ($numexisting) { |
|
$output .= '<p>'.&mt('None to upload, as all references are to existing files.').'</p>'; |
|
} |
|
$output .= $upload_output.'<br />'; |
|
} |
|
my ($pathchange_output,$chgcount); |
|
$chgcount = $counter; |
|
if (keys(%pathchanges) > 0) { |
|
foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) { |
|
if ($counter) { |
|
$output .= &embedded_file_element('pathchange',$chgcount, |
|
$embed_file,\%mapping, |
|
$allfiles,$codebase,'change'); |
|
} else { |
|
$pathchange_output .= |
|
&start_data_table_row(). |
|
'<td><input type ="checkbox" name="namechange" value="'. |
|
$chgcount.'" checked="checked" /></td>'. |
|
'<td>'.$mapping{$embed_file}.'</td>'. |
|
'<td>'.$embed_file. |
|
&embedded_file_element('pathchange',$numpathchg,$embed_file, |
|
\%mapping,$allfiles,$codebase,'change'). |
|
'</td>'.&end_data_table_row(); |
|
} |
|
$numpathchg ++; |
|
$chgcount ++; |
|
} |
|
} |
|
if (($counter) || ($numunused)) { |
|
if ($numpathchg) { |
|
$output .= '<input type ="hidden" name="number_pathchange_items" value="'. |
|
$numpathchg.'" />'."\n"; |
|
} |
|
if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || |
|
($actionurl eq '/adm/imsimport')) { |
|
$output .= '<input type="hidden" name="phase" value="three" />'."\n"; |
|
} elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') { |
|
$output .= '<input type="hidden" name="action" value="upload_embedded" />'; |
|
} elsif ($actionurl eq '/adm/dependencies') { |
|
$output .= '<input type="hidden" name="action" value="process_changes" />'; |
|
} |
|
$output .= '<input type ="submit" value="'.$buttontext.'" />'."\n".'</form>'."\n"; |
|
} elsif ($numpathchg) { |
|
my %pathchange = (); |
|
$output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output); |
|
if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { |
|
$output .= '<p>'.&mt('or').'</p>'; |
|
} |
|
} |
|
return ($output,$counter,$numpathchg); |
|
} |
|
|
|
=pod |
|
|
|
=item * clean_path($name) |
|
|
|
Performs clean-up of directories, subdirectories and filename in an |
|
embedded object, referenced in an HTML file which is being uploaded |
|
to a course or portfolio, where |
|
"Upload embedded images/multimedia files if HTML file" checkbox was |
|
checked. |
|
|
|
Clean-up is similar to replacements in lonnet::clean_filename() |
|
except each / between sub-directory and next level is preserved. |
|
|
|
=cut |
|
|
|
sub clean_path { |
|
my ($embed_file) = @_; |
|
$embed_file =~s{^/+}{}; |
|
my @contents; |
|
if ($embed_file =~ m{/}) { |
|
@contents = split(/\//,$embed_file); |
|
} else { |
|
@contents = ($embed_file); |
|
} |
|
my $lastidx = scalar(@contents)-1; |
|
for (my $i=0; $i<=$lastidx; $i++) { |
|
$contents[$i]=~s{\\}{/}g; |
|
$contents[$i]=~s/\s+/\_/g; |
|
$contents[$i]=~s{[^/\w\.\-]}{}g; |
|
if ($i == $lastidx) { |
|
$contents[$i]=~s/\.(\d+)(?=\.)/_$1/g; |
|
} |
|
} |
|
if ($lastidx > 0) { |
|
return join('/',@contents); |
|
} else { |
|
return $contents[0]; |
|
} |
|
} |
|
|
|
sub embedded_file_element { |
|
my ($context,$num,$embed_file,$mapping,$allfiles,$codebase,$type) = @_; |
|
return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') && |
|
(ref($codebase) eq 'HASH')); |
|
my $output; |
|
if (($context eq 'upload_embedded') && ($type ne 'delete')) { |
|
$output = '<input name="embedded_item_'.$num.'" type="file" value="" />'."\n"; |
|
} |
|
$output .= '<input name="embedded_orig_'.$num.'" type="hidden" value="'. |
|
&escape($embed_file).'" />'; |
|
unless (($context eq 'upload_embedded') && |
|
($mapping->{$embed_file} eq $embed_file)) { |
|
$output .=' |
|
<input name="embedded_ref_'.$num.'" type="hidden" value="'.&escape($mapping->{$embed_file}).'" />'; |
|
} |
|
my $attrib; |
|
if (ref($allfiles->{$mapping->{$embed_file}}) eq 'ARRAY') { |
|
$attrib = &escape(join(':',@{$allfiles->{$mapping->{$embed_file}}})); |
|
} |
|
$output .= |
|
"\n\t\t". |
|
'<input name="embedded_attrib_'.$num.'" type="hidden" value="'. |
|
$attrib.'" />'; |
|
if (exists($codebase->{$mapping->{$embed_file}})) { |
|
$output .= |
|
"\n\t\t". |
|
'<input name="codebase_'.$num.'" type="hidden" value="'. |
|
&escape($codebase->{$mapping->{$embed_file}}).'" />'; |
|
} |
|
return $output; |
|
} |
|
|
|
sub get_dependency_details { |
|
my ($currfile,$currsubfile,$embed_file) = @_; |
|
my ($size,$mtime,$showsize,$showmtime); |
|
if ((ref($currfile) eq 'HASH') && (ref($currsubfile))) { |
|
if ($embed_file =~ m{/}) { |
|
my ($path,$fname) = split(/\//,$embed_file); |
|
if (ref($currsubfile->{$path}{$fname}) eq 'ARRAY') { |
|
($size,$mtime) = @{$currsubfile->{$path}{$fname}}; |
|
} |
|
} else { |
|
if (ref($currfile->{$embed_file}) eq 'ARRAY') { |
|
($size,$mtime) = @{$currfile->{$embed_file}}; |
|
} |
|
} |
|
$showsize = $size/1024.0; |
|
$showsize = sprintf("%.1f",$showsize); |
|
if ($mtime > 0) { |
|
$showmtime = &Apache::lonlocal::locallocaltime($mtime); |
|
} |
|
} |
|
return ($showsize,$showmtime); |
|
} |
|
|
|
sub ask_embedded_js { |
|
return <<"END"; |
|
<script type="text/javascript""> |
|
// <![CDATA[ |
|
function toggleBrowse(counter) { |
|
var chkboxid = document.getElementById('mod_upload_dep_'+counter); |
|
var fileid = document.getElementById('embedded_item_'+counter); |
|
var uploaddivid = document.getElementById('moduploaddep_'+counter); |
|
if (chkboxid.checked == true) { |
|
uploaddivid.style.display='block'; |
|
} else { |
|
uploaddivid.style.display='none'; |
|
fileid.value = ''; |
|
} |
|
} |
|
// ]]> |
|
</script> |
|
|
|
END |
|
} |
|
|
|
sub upload_embedded { |
|
my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota, |
|
$current_disk_usage,$hiddenstate,$actionurl) = @_; |
|
my (%pathchange,$output,$modifyform,$footer,$returnflag); |
|
for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) { |
|
next if (!exists($env{'form.embedded_item_'.$i.'.filename'})); |
|
my $orig_uploaded_filename = |
|
$env{'form.embedded_item_'.$i.'.filename'}; |
|
foreach my $type ('orig','ref','attrib','codebase') { |
|
if ($env{'form.embedded_'.$type.'_'.$i} ne '') { |
|
$env{'form.embedded_'.$type.'_'.$i} = |
|
&unescape($env{'form.embedded_'.$type.'_'.$i}); |
|
} |
|
} |
|
my ($path,$fname) = |
|
($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)}); |
|
# no path, whole string is fname |
|
if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} }; |
|
$fname = &Apache::lonnet::clean_filename($fname); |
|
# See if there is anything left |
|
next if ($fname eq ''); |
|
|
|
# Check if file already exists as a file or directory. |
|
my ($state,$msg); |
|
if ($context eq 'portfolio') { |
|
my $port_path = $dirpath; |
|
if ($group ne '') { |
|
$port_path = "groups/$group/$port_path"; |
|
} |
|
($state,$msg) = &check_for_upload($env{'form.currentpath'}.$path, |
|
$fname,$group,'embedded_item_'.$i, |
|
$dir_root,$port_path,$disk_quota, |
|
$current_disk_usage,$uname,$udom); |
|
if ($state eq 'will_exceed_quota' |
|
|| $state eq 'file_locked') { |
|
$output .= $msg; |
|
next; |
|
} |
|
} elsif (($context eq 'author') || ($context eq 'testbank')) { |
|
($state,$msg) = &check_for_existing($path,$fname,'embedded_item_'.$i); |
|
if ($state eq 'exists') { |
|
$output .= $msg; |
|
next; |
|
} |
|
} |
|
# Check if extension is valid |
|
if (($fname =~ /\.(\w+)$/) && |
|
(&Apache::loncommon::fileembstyle($1) eq 'hdn')) { |
|
$output .= &mt('Invalid file extension ([_1]) - reserved for internal use.',$1) |
|
.' '.&mt('Rename the file with a different extension and re-upload.').'<br />'; |
|
next; |
|
} elsif (($fname =~ /\.(\w+)$/) && |
|
(!defined(&Apache::loncommon::fileembstyle($1)))) { |
|
$output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'<br />'; |
|
next; |
|
} elsif ($fname=~/\.(\d+)\.(\w+)$/) { |
|
$output .= &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'<br />'; |
|
next; |
|
} |
|
$env{'form.embedded_item_'.$i.'.filename'}=$fname; |
|
my $subdir = $path; |
|
$subdir =~ s{/+$}{}; |
|
if ($context eq 'portfolio') { |
|
my $result; |
|
if ($state eq 'existingfile') { |
|
$result= |
|
&Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile', |
|
$dirpath.$env{'form.currentpath'}.$subdir); |
|
} else { |
|
$result= |
|
&Apache::lonnet::userfileupload('embedded_item_'.$i,'', |
|
$dirpath. |
|
$env{'form.currentpath'}.$subdir); |
|
if ($result !~ m|^/uploaded/|) { |
|
$output .= '<span class="LC_error">' |
|
.&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' |
|
,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}) |
|
.'</span><br />'; |
|
next; |
|
} else { |
|
$output .= &mt('Uploaded [_1]','<span class="LC_filename">'. |
|
$path.$fname.'</span>').'<br />'; |
|
} |
|
} |
|
} elsif (($context eq 'coursedoc') || ($context eq 'syllabus')) { |
|
my $extendedsubdir = $dirpath.'/'.$subdir; |
|
$extendedsubdir =~ s{/+$}{}; |
|
my $result = |
|
&Apache::lonnet::userfileupload('embedded_item_'.$i,$context,$extendedsubdir); |
|
if ($result !~ m|^/uploaded/|) { |
|
$output .= '<span class="LC_error">' |
|
.&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' |
|
,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}) |
|
.'</span><br />'; |
|
next; |
|
} else { |
|
$output .= &mt('Uploaded [_1]','<span class="LC_filename">'. |
|
$path.$fname.'</span>').'<br />'; |
|
if ($context eq 'syllabus') { |
|
&Apache::lonnet::make_public_indefinitely($result); |
|
} |
|
} |
|
} else { |
|
# Save the file |
|
my $target = $env{'form.embedded_item_'.$i}; |
|
my $fullpath = $dir_root.$dirpath.'/'.$path; |
|
my $dest = $fullpath.$fname; |
|
my $url = $url_root.$dirpath.'/'.$path.$fname; |
|
my @parts=split(/\//,"$dirpath/$path"); |
|
my $count; |
|
my $filepath = $dir_root; |
|
foreach my $subdir (@parts) { |
|
$filepath .= "/$subdir"; |
|
if (!-e $filepath) { |
|
mkdir($filepath,0770); |
|
} |
|
} |
|
my $fh; |
|
if (!open($fh,'>'.$dest)) { |
|
&Apache::lonnet::logthis('Failed to create '.$dest); |
|
$output .= '<span class="LC_error">'. |
|
&mt('An error occurred while trying to upload [_1] for embedded element [_2].', |
|
$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}). |
|
'</span><br />'; |
|
} else { |
|
if (!print $fh $env{'form.embedded_item_'.$i}) { |
|
&Apache::lonnet::logthis('Failed to write to '.$dest); |
|
$output .= '<span class="LC_error">'. |
|
&mt('An error occurred while writing the file [_1] for embedded element [_2].', |
|
$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}). |
|
'</span><br />'; |
|
} else { |
|
$output .= &mt('Uploaded [_1]','<span class="LC_filename">'. |
|
$url.'</span>').'<br />'; |
|
unless ($context eq 'testbank') { |
|
$footer .= &mt('View embedded file: [_1]', |
|
'<a href="'.$url.'">'.$fname.'</a>').'<br />'; |
|
} |
|
} |
|
close($fh); |
|
} |
|
} |
|
if ($env{'form.embedded_ref_'.$i}) { |
|
$pathchange{$i} = 1; |
|
} |
|
} |
|
if ($output) { |
|
$output = '<p>'.$output.'</p>'; |
|
} |
|
$output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange); |
|
$returnflag = 'ok'; |
|
my $numpathchgs = scalar(keys(%pathchange)); |
|
if ($numpathchgs > 0) { |
|
if ($context eq 'portfolio') { |
|
$output .= '<p>'.&mt('or').'</p>'; |
|
} elsif ($context eq 'testbank') { |
|
$output .= '<p>'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).', |
|
'<a href="javascript:document.testbankForm.submit();">','</a>').'</p>'; |
|
$returnflag = 'modify_orightml'; |
|
} |
|
} |
|
return ($output.$footer,$returnflag,$numpathchgs); |
|
} |
|
|
|
sub modify_html_form { |
|
my ($context,$actionurl,$hiddenstate,$pathchange,$pathchgtable) = @_; |
|
my $end = 0; |
|
my $modifyform; |
|
if ($context eq 'upload_embedded') { |
|
return unless (ref($pathchange) eq 'HASH'); |
|
if ($env{'form.number_embedded_items'}) { |
|
$end += $env{'form.number_embedded_items'}; |
|
} |
|
if ($env{'form.number_pathchange_items'}) { |
|
$end += $env{'form.number_pathchange_items'}; |
|
} |
|
if ($end) { |
|
for (my $i=0; $i<$end; $i++) { |
|
if ($i < $env{'form.number_embedded_items'}) { |
|
next unless($pathchange->{$i}); |
|
} |
|
$modifyform .= |
|
&start_data_table_row(). |
|
'<td><input type ="checkbox" name="namechange" value="'.$i.'" '. |
|
'checked="checked" /></td>'. |
|
'<td>'.$env{'form.embedded_ref_'.$i}. |
|
'<input type="hidden" name="embedded_ref_'.$i.'" value="'. |
|
&escape($env{'form.embedded_ref_'.$i}).'" />'. |
|
'<input type="hidden" name="embedded_codebase_'.$i.'" value="'. |
|
&escape($env{'form.embedded_codebase_'.$i}).'" />'. |
|
'<input type="hidden" name="embedded_attrib_'.$i.'" value="'. |
|
&escape($env{'form.embedded_attrib_'.$i}).'" /></td>'. |
|
'<td>'.$env{'form.embedded_orig_'.$i}. |
|
'<input type="hidden" name="embedded_orig_'.$i.'" value="'. |
|
&escape($env{'form.embedded_orig_'.$i}).'" /></td>'. |
|
&end_data_table_row(); |
|
} |
|
} |
|
} else { |
|
$modifyform = $pathchgtable; |
|
if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { |
|
$hiddenstate .= '<input type="hidden" name="phase" value="four" />'; |
|
} elsif (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { |
|
$hiddenstate .= '<input type="hidden" name="action" value="modify_orightml" />'; |
|
} |
|
} |
|
if ($modifyform) { |
|
if ($actionurl eq '/adm/dependencies') { |
|
$hiddenstate .= '<input type="hidden" name="action" value="modifyhrefs" />'; |
|
} |
|
return '<h3>'.&mt('Changes in content of HTML file required').'</h3>'."\n". |
|
'<p>'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'<ol>'."\n". |
|
'<li>'.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'</li>'."\n". |
|
'<li>'.&mt('To change absolute paths to relative paths, or replace directory traversal via "../" within the original reference.').'</li>'."\n". |
|
'</ol></p>'."\n".'<p>'. |
|
&mt('LON-CAPA can make the required changes to your HTML file.').'</p>'."\n". |
|
'<form method="post" name="refchanger" action="'.$actionurl.'">'. |
|
&start_data_table()."\n". |
|
&start_data_table_header_row(). |
|
'<th>'.&mt('Change?').'</th>'. |
|
'<th>'.&mt('Current reference').'</th>'. |
|
'<th>'.&mt('Required reference').'</th>'. |
|
&end_data_table_header_row()."\n". |
|
$modifyform. |
|
&end_data_table().'<br />'."\n".$hiddenstate. |
|
'<input type="submit" name="pathchanges" value="'.&mt('Modify HTML file').'" />'. |
|
'</form>'."\n"; |
|
} |
|
return; |
|
} |
|
|
|
sub modify_html_refs { |
|
my ($context,$dirpath,$uname,$udom,$dir_root,$url) = @_; |
|
my $container; |
|
if ($context eq 'portfolio') { |
|
$container = $env{'form.container'}; |
|
} elsif ($context eq 'coursedoc') { |
|
$container = $env{'form.primaryurl'}; |
|
} elsif ($context eq 'manage_dependencies') { |
|
(undef,undef,$container) = &Apache::lonnet::decode_symb($env{'form.symb'}); |
|
$container = "/$container"; |
|
} elsif ($context eq 'syllabus') { |
|
$container = $url; |
|
} else { |
|
$container = $Apache::lonnet::perlvar{'lonDocRoot'}.$env{'form.filename'}; |
|
} |
|
my (%allfiles,%codebase,$output,$content); |
|
my @changes = &get_env_multiple('form.namechange'); |
|
unless ((@changes > 0) || ($context eq 'syllabus')) { |
|
if (wantarray) { |
|
return ('',0,0); |
|
} else { |
|
return; |
|
} |
|
} |
|
if (($context eq 'portfolio') || ($context eq 'coursedoc') || |
|
($context eq 'manage_dependencies') || ($context eq 'syllabus')) { |
|
unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}) { |
|
if (wantarray) { |
|
return ('',0,0); |
|
} else { |
|
return; |
|
} |
|
} |
|
$content = &Apache::lonnet::getfile($container); |
|
if ($content eq '-1') { |
|
if (wantarray) { |
|
return ('',0,0); |
|
} else { |
|
return; |
|
} |
|
} |
|
} else { |
|
unless ($container =~ /^\Q$dir_root\E/) { |
|
if (wantarray) { |
|
return ('',0,0); |
|
} else { |
|
return; |
|
} |
|
} |
|
if (open(my $fh,'<',$container)) { |
|
$content = join('', <$fh>); |
|
close($fh); |
|
} else { |
|
if (wantarray) { |
|
return ('',0,0); |
|
} else { |
|
return; |
|
} |
|
} |
|
} |
|
my ($count,$codebasecount) = (0,0); |
|
my $mm = new File::MMagic; |
|
my $mime_type = $mm->checktype_contents($content); |
|
if ($mime_type eq 'text/html') { |
|
my $parse_result = |
|
&Apache::lonnet::extract_embedded_items($container,\%allfiles, |
|
\%codebase,\$content); |
|
if ($parse_result eq 'ok') { |
|
foreach my $i (@changes) { |
|
my $orig = &unescape($env{'form.embedded_orig_'.$i}); |
|
my $ref = &unescape($env{'form.embedded_ref_'.$i}); |
|
if ($allfiles{$ref}) { |
|
my $newname = $orig; |
|
my ($attrib_regexp,$codebase); |
|
$attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i}); |
|
if ($attrib_regexp =~ /:/) { |
|
$attrib_regexp =~ s/\:/|/g; |
|
} |
|
if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) { |
|
my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi); |
|
$count += $numchg; |
|
$allfiles{$newname} = $allfiles{$ref}; |
|
delete($allfiles{$ref}); |
|
} |
|
if ($env{'form.embedded_codebase_'.$i} ne '') { |
|
$codebase = &unescape($env{'form.embedded_codebase_'.$i}); |
|
my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs |
|
$codebasecount ++; |
|
} |
|
} |
|
} |
|
my $skiprewrites; |
|
if ($count || $codebasecount) { |
|
my $saveresult; |
|
if (($context eq 'portfolio') || ($context eq 'coursedoc') || |
|
($context eq 'manage_dependencies') || ($context eq 'syllabus')) { |
|
my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult); |
|
if ($url eq $container) { |
|
my ($fname) = ($container =~ m{/([^/]+)$}); |
|
$output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].', |
|
$count,'<span class="LC_filename">'. |
|
$fname.'</span>').'</p>'; |
|
} else { |
|
$output = '<p class="LC_error">'. |
|
&mt('Error: update failed for: [_1].', |
|
'<span class="LC_filename">'. |
|
$container.'</span>').'</p>'; |
|
} |
|
if ($context eq 'syllabus') { |
|
unless ($saveresult eq 'ok') { |
|
$skiprewrites = 1; |
|
} |
|
} |
|
} else { |
|
if (open(my $fh,'>',$container)) { |
|
print $fh $content; |
|
close($fh); |
|
$output = '<p>'.&mt('Updated [quant,_1,reference] in [_2].', |
|
$count,'<span class="LC_filename">'. |
|
$container.'</span>').'</p>'; |
|
} else { |
|
$output = '<p class="LC_error">'. |
|
&mt('Error: could not update [_1].', |
|
'<span class="LC_filename">'. |
|
$container.'</span>').'</p>'; |
|
} |
|
} |
|
} |
|
if (($context eq 'syllabus') && (!$skiprewrites)) { |
|
my ($actionurl,$state); |
|
$actionurl = "/public/$udom/$uname/syllabus"; |
|
my ($ignore,$num,$numpathchanges,$existing,$mapping) = |
|
&ask_for_embedded_content($actionurl,$state,\%allfiles, |
|
\%codebase, |
|
{'context' => 'rewrites', |
|
'ignore_remote_references' => 1,}); |
|
if (ref($mapping) eq 'HASH') { |
|
my $rewrites = 0; |
|
foreach my $key (keys(%{$mapping})) { |
|
next if ($key =~ m{^https?://}); |
|
my $ref = $mapping->{$key}; |
|
my $newname = "/uploaded/$udom/$uname/portfolio/syllabus/$key"; |
|
my $attrib; |
|
if (ref($allfiles{$mapping->{$key}}) eq 'ARRAY') { |
|
$attrib = join('|',@{$allfiles{$mapping->{$key}}}); |
|
} |
|
if ($content =~ m{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}) { |
|
my $numchg = ($content =~ s{($attrib\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi); |
|
$rewrites += $numchg; |
|
} |
|
} |
|
if ($rewrites) { |
|
my $saveresult; |
|
my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult); |
|
if ($url eq $container) { |
|
my ($fname) = ($container =~ m{/([^/]+)$}); |
|
$output .= '<p>'.&mt('Rewrote [quant,_1,link] as [quant,_1,absolute link] in [_2].', |
|
$count,'<span class="LC_filename">'. |
|
$fname.'</span>').'</p>'; |
|
} else { |
|
$output .= '<p class="LC_error">'. |
|
&mt('Error: could not update links in [_1].', |
|
'<span class="LC_filename">'. |
|
$container.'</span>').'</p>'; |
|
|
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
&logthis('Failed to parse '.$container. |
|
' to modify references: '.$parse_result); |
|
} |
|
} |
|
if (wantarray) { |
|
return ($output,$count,$codebasecount); |
|
} else { |
|
return $output; |
|
} |
|
} |
|
|
|
sub check_for_existing { |
|
my ($path,$fname,$element) = @_; |
|
my ($state,$msg); |
|
if (-d $path.'/'.$fname) { |
|
$state = 'exists'; |
|
$msg = &mt('Unable to upload [_1]. A directory by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path); |
|
} elsif (-e $path.'/'.$fname) { |
|
$state = 'exists'; |
|
$msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$path); |
|
} |
|
if ($state eq 'exists') { |
|
$msg = '<span class="LC_error">'.$msg.'</span><br />'; |
|
} |
|
return ($state,$msg); |
|
} |
|
|
|
sub check_for_upload { |
|
my ($path,$fname,$group,$element,$portfolio_root,$port_path, |
|
$disk_quota,$current_disk_usage,$uname,$udom) = @_; |
|
my $filesize = length($env{'form.'.$element}); |
|
if (!$filesize) { |
|
my $msg = '<span class="LC_error">'. |
|
&mt('Unable to upload [_1]. (size = [_2] bytes)', |
|
'<span class="LC_filename">'.$fname.'</span>', |
|
$filesize).'<br />'. |
|
&mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'<br />'. |
|
'</span>'; |
|
return ('zero_bytes',$msg); |
|
} |
|
$filesize = $filesize/1000; #express in k (1024?) |
|
my $getpropath = 1; |
|
my ($dirlistref,$listerror) = |
|
&Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,$getpropath); |
|
my $found_file = 0; |
|
my $locked_file = 0; |
|
my @lockers; |
|
my $navmap; |
|
if ($env{'request.course.id'}) { |
|
$navmap = Apache::lonnavmaps::navmap->new(); |
|
} |
|
if (ref($dirlistref) eq 'ARRAY') { |
|
foreach my $line (@{$dirlistref}) { |
|
my ($file_name,$rest)=split(/\&/,$line,2); |
|
if ($file_name eq $fname){ |
|
$file_name = $path.$file_name; |
|
if ($group ne '') { |
|
$file_name = $group.$file_name; |
|
} |
|
$found_file = 1; |
|
if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') { |
|
foreach my $lock (@lockers) { |
|
if (ref($lock) eq 'ARRAY') { |
|
my ($symb,$crsid) = @{$lock}; |
|
if ($crsid eq $env{'request.course.id'}) { |
|
if (ref($navmap)) { |
|
my $res = $navmap->getBySymb($symb); |
|
foreach my $part (@{$res->parts()}) { |
|
my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part); |
|
unless (($slot_status == $res->RESERVED) || |
|
($slot_status == $res->RESERVED_LOCATION)) { |
|
$locked_file = 1; |
|
} |
|
} |
|
} else { |
|
$locked_file = 1; |
|
} |
|
} else { |
|
$locked_file = 1; |
|
} |
|
} |
|
} |
|
} else { |
|
my @info = split(/\&/,$rest); |
|
my $currsize = $info[6]/1000; |
|
if ($currsize < $filesize) { |
|
my $extra = $filesize - $currsize; |
|
if (($current_disk_usage + $extra) > $disk_quota) { |
|
my $msg = '<p class="LC_warning">'. |
|
&mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.', |
|
'<span class="LC_filename">'.$fname.'</span>',$filesize,$currsize).'</p>'. |
|
'<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', |
|
$disk_quota,$current_disk_usage).'</p>'; |
|
return ('will_exceed_quota',$msg); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if (($current_disk_usage + $filesize) > $disk_quota){ |
|
my $msg = '<p class="LC_warning">'. |
|
&mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.','<span class="LC_filename">'.$fname.'</span>',$filesize).'</p>'. |
|
'<p>'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage).'</p>'; |
|
return ('will_exceed_quota',$msg); |
|
} elsif ($found_file) { |
|
if ($locked_file) { |
|
my $msg = '<p class="LC_warning">'; |
|
$msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].','<span class="LC_filename">'.$fname.'</span>','<span class="LC_filename">'.$port_path.$env{'form.currentpath'}.'</span>'); |
|
$msg .= '</p>'; |
|
$msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.','<span class="LC_filename">'.$fname.'</span>'); |
|
return ('file_locked',$msg); |
|
} else { |
|
my $msg = '<p class="LC_error">'; |
|
$msg .= &mt(' A file by that name: [_1] was found in [_2].','<span class="LC_filename">'.$fname.'</span>',$port_path.$env{'form.currentpath'}); |
|
$msg .= '</p>'; |
|
return ('existingfile',$msg); |
|
} |
|
} |
|
} |
|
|
|
sub check_for_traversal { |
|
my ($path,$url,$toplevel) = @_; |
|
my @parts=split(/\//,$path); |
|
my $cleanpath; |
|
my $fullpath = $url; |
|
for (my $i=0;$i<@parts;$i++) { |
|
next if ($parts[$i] eq '.'); |
|
if ($parts[$i] eq '..') { |
|
$fullpath =~ s{([^/]+/)$}{}; |
|
} else { |
|
$fullpath .= $parts[$i].'/'; |
|
} |
|
} |
|
if ($fullpath =~ /^\Q$url\E(.*)$/) { |
|
$cleanpath = $1; |
|
} elsif ($fullpath =~ /^\Q$toplevel\E(.*)$/) { |
|
my $curr_toprel = $1; |
|
my @parts = split(/\//,$curr_toprel); |
|
my ($url_toprel) = ($url =~ /^\Q$toplevel\E(.*)$/); |
|
my @urlparts = split(/\//,$url_toprel); |
|
my $doubledots; |
|
my $startdiff = -1; |
|
for (my $i=0; $i<@urlparts; $i++) { |
|
if ($startdiff == -1) { |
|
unless ($urlparts[$i] eq $parts[$i]) { |
|
$startdiff = $i; |
|
$doubledots .= '../'; |
|
} |
|
} else { |
|
$doubledots .= '../'; |
|
} |
|
} |
|
if ($startdiff > -1) { |
|
$cleanpath = $doubledots; |
|
for (my $i=$startdiff; $i<@parts; $i++) { |
|
$cleanpath .= $parts[$i].'/'; |
|
} |
|
} |
|
} |
|
$cleanpath =~ s{(/)$}{}; |
|
return $cleanpath; |
|
} |
|
|
|
sub is_archive_file { |
|
my ($mimetype) = @_; |
|
if (($mimetype eq 'application/octet-stream') || |
|
($mimetype eq 'application/x-stuffit') || |
|
($mimetype =~ m{^application/(x\-)?(compressed|tar|zip|tgz|gz|gtar|gzip|gunzip|bz|bz2|bzip2)})) { |
|
return 1; |
|
} |
|
return; |
|
} |
|
|
|
sub decompress_form { |
|
my ($mimetype,$archiveurl,$action,$noextract,$hiddenelements,$dirlist) = @_; |
|
my %lt = &Apache::lonlocal::texthash ( |
|
this => 'This file is an archive file.', |
|
camt => 'This file is a Camtasia archive file.', |
|
itsc => 'Its contents are as follows:', |
|
youm => 'You may wish to extract its contents.', |
|
extr => 'Extract contents', |
|
auto => 'LON-CAPA can process the files automatically, or you can decide how each should be handled.', |
|
proa => 'Process automatically?', |
|
yes => 'Yes', |
|
no => 'No', |
|
fold => 'Title for folder containing movie', |
|
movi => 'Title for page containing embedded movie', |
|
); |
|
my $fileloc = &Apache::lonnet::filelocation(undef,$archiveurl); |
|
my ($is_camtasia,$topdir,%toplevel,@paths); |
|
my $info = &list_archive_contents($fileloc,\@paths); |
|
if (@paths) { |
|
foreach my $path (@paths) { |
|
$path =~ s{^/}{}; |
|
if ($path =~ m{^([^/]+)/$}) { |
|
$topdir = $1; |
|
} |
|
if ($path =~ m{^([^/]+)/}) { |
|
$toplevel{$1} = $path; |
|
} else { |
|
$toplevel{$path} = $path; |
|
} |
|
} |
|
} |
|
if ($mimetype =~ m{^application/(x\-)?(compressed|zip)}) { |
|
my @camtasia6 = ("$topdir/","$topdir/index.html", |
|
"$topdir/media/", |
|
"$topdir/media/$topdir.mp4", |
|
"$topdir/media/FirstFrame.png", |
|
"$topdir/media/player.swf", |
|
"$topdir/media/swfobject.js", |
|
"$topdir/media/expressInstall.swf"); |
|
my @camtasia8_1 = ("$topdir/","$topdir/$topdir.html", |
|
"$topdir/$topdir.mp4", |
|
"$topdir/$topdir\_config.xml", |
|
"$topdir/$topdir\_controller.swf", |
|
"$topdir/$topdir\_embed.css", |
|
"$topdir/$topdir\_First_Frame.png", |
|
"$topdir/$topdir\_player.html", |
|
"$topdir/$topdir\_Thumbnails.png", |
|
"$topdir/playerProductInstall.swf", |
|
"$topdir/scripts/", |
|
"$topdir/scripts/config_xml.js", |
|
"$topdir/scripts/handlebars.js", |
|
"$topdir/scripts/jquery-1.7.1.min.js", |
|
"$topdir/scripts/jquery-ui-1.8.15.custom.min.js", |
|
"$topdir/scripts/modernizr.js", |
|
"$topdir/scripts/player-min.js", |
|
"$topdir/scripts/swfobject.js", |
|
"$topdir/skins/", |
|
"$topdir/skins/configuration_express.xml", |
|
"$topdir/skins/express_show/", |
|
"$topdir/skins/express_show/player-min.css", |
|
"$topdir/skins/express_show/spritesheet.png"); |
|
my @camtasia8_4 = ("$topdir/","$topdir/$topdir.html", |
|
"$topdir/$topdir.mp4", |
|
"$topdir/$topdir\_config.xml", |
|
"$topdir/$topdir\_controller.swf", |
|
"$topdir/$topdir\_embed.css", |
|
"$topdir/$topdir\_First_Frame.png", |
|
"$topdir/$topdir\_player.html", |
|
"$topdir/$topdir\_Thumbnails.png", |
|
"$topdir/playerProductInstall.swf", |
|
"$topdir/scripts/", |
|
"$topdir/scripts/config_xml.js", |
|
"$topdir/scripts/techsmith-smart-player.min.js", |
|
"$topdir/skins/", |
|
"$topdir/skins/configuration_express.xml", |
|
"$topdir/skins/express_show/", |
|
"$topdir/skins/express_show/spritesheet.min.css", |
|
"$topdir/skins/express_show/spritesheet.png", |
|
"$topdir/skins/express_show/techsmith-smart-player.min.css"); |
|
my @diffs = &compare_arrays(\@paths,\@camtasia6); |
|
if (@diffs == 0) { |
|
$is_camtasia = 6; |
|
} else { |
|
@diffs = &compare_arrays(\@paths,\@camtasia8_1); |
|
if (@diffs == 0) { |
|
$is_camtasia = 8; |
|
} else { |
|
@diffs = &compare_arrays(\@paths,\@camtasia8_4); |
|
if (@diffs == 0) { |
|
$is_camtasia = 8; |
|
} |
|
} |
|
} |
|
} |
|
my $output; |
|
if ($is_camtasia) { |
|
$output = <<"ENDCAM"; |
|
<script type="text/javascript" language="Javascript"> |
|
// <![CDATA[ |
|
|
|
function camtasiaToggle() { |
|
for (var i=0; i<document.uploaded_decompress.autoextract_camtasia.length; i++) { |
|
if (document.uploaded_decompress.autoextract_camtasia[i].checked) { |
|
if (document.uploaded_decompress.autoextract_camtasia[i].value == $is_camtasia) { |
|
document.getElementById('camtasia_titles').style.display='block'; |
|
} else { |
|
document.getElementById('camtasia_titles').style.display='none'; |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
// ]]> |
|
</script> |
|
<p>$lt{'camt'}</p> |
|
ENDCAM |
|
} else { |
|
$output = '<p>'.$lt{'this'}; |
|
if ($info eq '') { |
|
$output .= ' '.$lt{'youm'}.'</p>'."\n"; |
|
} else { |
|
$output .= ' '.$lt{'itsc'}.'</p>'."\n". |
|
'<div><pre>'.$info.'</pre></div>'; |
|
} |
|
} |
|
$output .= '<form name="uploaded_decompress" action="'.$action.'" method="post">'."\n"; |
|
my $duplicates; |
|
my $num = 0; |
|
if (ref($dirlist) eq 'ARRAY') { |
|
foreach my $item (@{$dirlist}) { |
|
if (ref($item) eq 'ARRAY') { |
|
if (exists($toplevel{$item->[0]})) { |
|
$duplicates .= |
|
&start_data_table_row(). |
|
'<td><label><input type="radio" name="archive_overwrite_'.$num.'" '. |
|
'value="0" checked="checked" />'.&mt('No').'</label>'. |
|
' <label><input type="radio" name="archive_overwrite_'.$num.'" '. |
|
'value="1" />'.&mt('Yes').'</label>'. |
|
'<input type="hidden" name="archive_overwrite_name_'.$num.'" value="'.$item->[0].'" /></td>'."\n". |
|
'<td>'.$item->[0].'</td>'; |
|
if ($item->[2]) { |
|
$duplicates .= '<td>'.&mt('Directory').'</td>'; |
|
} else { |
|
$duplicates .= '<td>'.&mt('File').'</td>'; |
|
} |
|
$duplicates .= '<td>'.$item->[3].'</td>'. |
|
'<td>'. |
|
&Apache::lonlocal::locallocaltime($item->[4]). |
|
'</td>'. |
|
&end_data_table_row(); |
|
$num ++; |
|
} |
|
} |
|
} |
|
} |
|
my $itemcount; |
|
if (@paths > 0) { |
|
$itemcount = scalar(@paths); |
|
} else { |
|
$itemcount = 1; |
|
} |
|
if ($is_camtasia) { |
|
$output .= $lt{'auto'}.'<br />'. |
|
'<span class="LC_nobreak">'.$lt{'proa'}.'<label>'. |
|
'<input type="radio" name="autoextract_camtasia" value="'.$is_camtasia.'" onclick="javascript:camtasiaToggle();" checked="checked" />'. |
|
$lt{'yes'}.'</label> <label>'. |
|
'<input type="radio" name="autoextract_camtasia" value="0" onclick="javascript:camtasiaToggle();" />'. |
|
$lt{'no'}.'</label></span><br />'. |
|
'<div id="camtasia_titles" style="display:block">'. |
|
&Apache::lonhtmlcommon::start_pick_box(). |
|
&Apache::lonhtmlcommon::row_title($lt{'fold'}). |
|
'<input type="textbox" name="camtasia_foldername" value="'.$env{'form.comment'}.'" />'."\n". |
|
&Apache::lonhtmlcommon::row_closure(). |
|
&Apache::lonhtmlcommon::row_title($lt{'movi'}). |
|
'<input type="textbox" name="camtasia_moviename" value="" />'."\n". |
|
&Apache::lonhtmlcommon::row_closure(1). |
|
&Apache::lonhtmlcommon::end_pick_box(). |
|
'</div>'; |
|
} |
|
$output .= |
|
'<input type="hidden" name="archive_overwrite_total" value="'.$num.'" />'. |
|
'<input type="hidden" name="archive_itemcount" value="'.$itemcount.'" />'. |
|
"\n"; |
|
if ($duplicates ne '') { |
|
$output .= '<p><span class="LC_warning">'. |
|
&mt('Warning: decompression of the archive will overwrite the following items which already exist:').'</span><br />'. |
|
&start_data_table(). |
|
&start_data_table_header_row(). |
|
'<th>'.&mt('Overwrite?').'</th>'. |
|
'<th>'.&mt('Name').'</th>'. |
|
'<th>'.&mt('Type').'</th>'. |
|
'<th>'.&mt('Size').'</th>'. |
|
'<th>'.&mt('Last modified').'</th>'. |
|
&end_data_table_header_row(). |
|
$duplicates. |
|
&end_data_table(). |
|
'</p>'; |
|
} |
|
$output .= '<input type="hidden" name="archiveurl" value="'.$archiveurl.'" />'."\n"; |
|
if (ref($hiddenelements) eq 'HASH') { |
|
foreach my $hidden (sort(keys(%{$hiddenelements}))) { |
|
$output .= '<input type="hidden" name="'.$hidden.'" value="'.$hiddenelements->{$hidden}.'" />'."\n"; |
|
} |
|
} |
|
$output .= <<"END"; |
|
<br /> |
|
<input type="submit" name="decompress" value="$lt{'extr'}" /> |
|
</form> |
|
$noextract |
|
END |
|
return $output; |
|
} |
|
|
|
sub decompression_utility { |
|
my ($program) = @_; |
|
my @utilities = ('tar','gunzip','bunzip2','unzip'); |
|
my $location; |
|
if (grep(/^\Q$program\E$/,@utilities)) { |
|
foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/', |
|
'/usr/sbin/') { |
|
if (-x $dir.$program) { |
|
$location = $dir.$program; |
|
last; |
|
} |
|
} |
|
} |
|
return $location; |
|
} |
|
|
|
sub list_archive_contents { |
|
my ($file,$pathsref) = @_; |
|
my (@cmd,$output); |
|
my $needsregexp; |
|
if ($file =~ /\.zip$/) { |
|
@cmd = (&decompression_utility('unzip'),"-l"); |
|
$needsregexp = 1; |
|
} elsif (($file =~ m/\.tar\.gz$/) || |
|
($file =~ /\.tgz$/)) { |
|
@cmd = (&decompression_utility('tar'),"-ztf"); |
|
} elsif ($file =~ /\.tar\.bz2$/) { |
|
@cmd = (&decompression_utility('tar'),"-jtf"); |
|
} elsif ($file =~ m|\.tar$|) { |
|
@cmd = (&decompression_utility('tar'),"-tf"); |
|
} |
|
if (@cmd) { |
|
undef($!); |
|
undef($@); |
|
if (open(my $fh,"-|", @cmd, $file)) { |
|
while (my $line = <$fh>) { |
|
$output .= $line; |
|
chomp($line); |
|
my $item; |
|
if ($needsregexp) { |
|
($item) = ($line =~ /^\s*\d+\s+[\d\-]+\s+[\d:]+\s*(.+)$/); |
|
} else { |
|
$item = $line; |
|
} |
|
if ($item ne '') { |
|
unless (grep(/^\Q$item\E$/,@{$pathsref})) { |
|
push(@{$pathsref},$item); |
|
} |
|
} |
|
} |
|
close($fh); |
|
} |
|
} |
|
return $output; |
|
} |
|
|
|
sub decompress_uploaded_file { |
|
my ($file,$dir) = @_; |
|
&Apache::lonnet::appenv({'cgi.file' => $file}); |
|
&Apache::lonnet::appenv({'cgi.dir' => $dir}); |
|
my $result = &Apache::lonnet::ssi_body('/cgi-bin/decompress.pl'); |
|
my ($handle) = ($env{'user.environment'} =~m{/([^/]+)\.id$}); |
|
my $lonidsdir = $Apache::lonnet::perlvar{'lonIDsDir'}; |
|
&Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle,1); |
|
my $decompressed = $env{'cgi.decompressed'}; |
|
&Apache::lonnet::delenv('cgi.file'); |
|
&Apache::lonnet::delenv('cgi.dir'); |
|
&Apache::lonnet::delenv('cgi.decompressed'); |
|
return ($decompressed,$result); |
|
} |
|
|
|
sub process_decompression { |
|
my ($docudom,$docuname,$file,$destination,$dir_root,$hiddenelem) = @_; |
|
unless (($dir_root eq '/userfiles') && ($destination =~ m{^(docs|supplemental)/(default|\d+)/\d+$})) { |
|
return '<p class="LC_error">'.&mt('Not extracted.').'<br />'. |
|
&mt('Unexpected file path.').'</p>'."\n"; |
|
} |
|
unless (($docudom =~ /^$match_domain$/) && ($docuname =~ /^$match_courseid$/)) { |
|
return '<p class="LC_error">'.&mt('Not extracted.').'<br />'. |
|
&mt('Unexpected course context.').'</p>'."\n"; |
|
} |
|
unless ($file eq &Apache::lonnet::clean_filename($file)) { |
|
return '<p class="LC_error">'.&mt('Not extracted.').'<br />'. |
|
&mt('Filename contained unexpected characters.').'</p>'."\n"; |
|
} |
|
my ($dir,$error,$warning,$output); |
|
if ($file !~ /\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/i) { |
|
$error = &mt('Filename not a supported archive file type.'). |
|
'<br />'.&mt('Filename should end with one of: [_1].', |
|
'.zip, .tar, .bz2, .gz, .tar.gz, .tar.bz2, .tgz'); |
|
} else { |
|
my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom); |
|
if ($docuhome eq 'no_host') { |
|
$error = &mt('Could not determine home server for course.'); |
|
} else { |
|
my @ids=&Apache::lonnet::current_machine_ids(); |
|
my $currdir = "$dir_root/$destination"; |
|
if (grep(/^\Q$docuhome\E$/,@ids)) { |
|
$dir = &LONCAPA::propath($docudom,$docuname). |
|
"$dir_root/$destination"; |
|
} else { |
|
$dir = $Apache::lonnet::perlvar{'lonDocRoot'}. |
|
"$dir_root/$docudom/$docuname/$destination"; |
|
unless (&Apache::lonnet::repcopy_userfile("$dir/$file") eq 'ok') { |
|
$error = &mt('Archive file not found.'); |
|
} |
|
} |
|
my (@to_overwrite,@to_skip); |
|
if ($env{'form.archive_overwrite_total'} > 0) { |
|
my $total = $env{'form.archive_overwrite_total'}; |
|
for (my $i=0; $i<$total; $i++) { |
|
if ($env{'form.archive_overwrite_'.$i} == 1) { |
|
push(@to_overwrite,$env{'form.archive_overwrite_name_'.$i}); |
|
} elsif ($env{'form.archive_overwrite_'.$i} == 0) { |
|
push(@to_skip,$env{'form.archive_overwrite_name_'.$i}); |
|
} |
|
} |
|
} |
|
my $numskip = scalar(@to_skip); |
|
my $numoverwrite = scalar(@to_overwrite); |
|
if (($numskip) && (!$numoverwrite)) { |
|
$warning = &mt('All items in the archive file already exist, and no overwriting of existing files has been requested.'); |
|
} elsif ($dir eq '') { |
|
$error = &mt('Directory containing archive file unavailable.'); |
|
} elsif (!$error) { |
|
my ($decompressed,$display); |
|
if (($numskip) || ($numoverwrite)) { |
|
my $tempdir = time.'_'.$$.int(rand(10000)); |
|
mkdir("$dir/$tempdir",0755); |
|
if (&File::Copy::move("$dir/$file","$dir/$tempdir/$file")) { |
|
($decompressed,$display) = |
|
&decompress_uploaded_file($file,"$dir/$tempdir"); |
|
foreach my $item (@to_skip) { |
|
if (($item ne '') && ($item !~ /\.\./)) { |
|
if (-f "$dir/$tempdir/$item") { |
|
unlink("$dir/$tempdir/$item"); |
|
} elsif (-d "$dir/$tempdir/$item") { |
|
&File::Path::remove_tree("$dir/$tempdir/$item",{ safe => 1 }); |
|
} |
|
} |
|
} |
|
foreach my $item (@to_overwrite) { |
|
if ((-e "$dir/$tempdir/$item") && (-e "$dir/$item")) { |
|
if (($item ne '') && ($item !~ /\.\./)) { |
|
if (-f "$dir/$item") { |
|
unlink("$dir/$item"); |
|
} elsif (-d "$dir/$item") { |
|
&File::Path::remove_tree("$dir/$item",{ safe => 1 }); |
|
} |
|
&File::Copy::move("$dir/$tempdir/$item","$dir/$item"); |
|
} |
|
} |
|
} |
|
if (&File::Copy::move("$dir/$tempdir/$file","$dir/$file")) { |
|
&File::Path::remove_tree("$dir/$tempdir",{ safe => 1 }); |
|
} |
|
} |
|
} else { |
|
($decompressed,$display) = |
|
&decompress_uploaded_file($file,$dir); |
|
} |
|
if ($decompressed eq 'ok') { |
|
$output = '<p class="LC_info">'. |
|
&mt('Files extracted successfully from archive.'). |
|
'</p>'."\n"; |
|
my ($warning,$result,@contents); |
|
my ($newdirlistref,$newlisterror) = |
|
&Apache::lonnet::dirlist($currdir,$docudom, |
|
$docuname,1); |
|
my (%is_dir,%changes,@newitems); |
|
my $dirptr = 16384; |
|
if (ref($newdirlistref) eq 'ARRAY') { |
|
foreach my $dir_line (@{$newdirlistref}) { |
|
my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5); |
|
unless (($item =~ /^\.+$/) || ($item eq $file)) { |
|
push(@newitems,$item); |
|
if ($dirptr&$testdir) { |
|
$is_dir{$item} = 1; |
|
} |
|
$changes{$item} = 1; |
|
} |
|
} |
|
} |
|
if (keys(%changes) > 0) { |
|
foreach my $item (sort(@newitems)) { |
|
if ($changes{$item}) { |
|
push(@contents,$item); |
|
} |
|
} |
|
} |
|
if (@contents > 0) { |
|
my $wantform; |
|
unless ($env{'form.autoextract_camtasia'}) { |
|
$wantform = 1; |
|
} |
|
my (%children,%parent,%dirorder,%titles); |
|
my ($count,$datatable) = &get_extracted($docudom,$docuname, |
|
$currdir,\%is_dir, |
|
\%children,\%parent, |
|
\@contents,\%dirorder, |
|
\%titles,$wantform); |
|
if ($datatable ne '') { |
|
$output .= &archive_options_form('decompressed',$datatable, |
|
$count,$hiddenelem); |
|
my $startcount = 6; |
|
$output .= &archive_javascript($startcount,$count, |
|
\%titles,\%children); |
|
} |
|
if ($env{'form.autoextract_camtasia'}) { |
|
my $version = $env{'form.autoextract_camtasia'}; |
|
my %displayed; |
|
my $total = 1; |
|
$env{'form.archive_directory'} = []; |
|
foreach my $i (sort { $a <=> $b } keys(%dirorder)) { |
|
my $path = join('/',map { $titles{$_}; } @{$dirorder{$i}}); |
|
$path =~ s{/$}{}; |
|
my $item; |
|
if ($path ne '') { |
|
$item = "$path/$titles{$i}"; |
|
} else { |
|
$item = $titles{$i}; |
|
} |
|
$env{'form.archive_content_'.$i} = "$dir_root/$destination/$item"; |
|
if ($item eq $contents[0]) { |
|
push(@{$env{'form.archive_directory'}},$i); |
|
$env{'form.archive_'.$i} = 'display'; |
|
$env{'form.archive_title_'.$i} = $env{'form.camtasia_foldername'}; |
|
$displayed{'folder'} = $i; |
|
} elsif ((($item eq "$contents[0]/index.html") && ($version == 6)) || |
|
(($item eq "$contents[0]/$contents[0]".'.html') && ($version == 8))) { |
|
$env{'form.archive_'.$i} = 'display'; |
|
$env{'form.archive_title_'.$i} = $env{'form.camtasia_moviename'}; |
|
$displayed{'web'} = $i; |
|
} else { |
|
if ((($item eq "$contents[0]/media") && ($version == 6)) || |
|
((($item eq "$contents[0]/scripts") || ($item eq "$contents[0]/skins") || |
|
($item eq "$contents[0]/skins/express_show")) && ($version == 8))) { |
|
push(@{$env{'form.archive_directory'}},$i); |
|
} |
|
$env{'form.archive_'.$i} = 'dependency'; |
|
} |
|
$total ++; |
|
} |
|
for (my $i=1; $i<$total; $i++) { |
|
next if ($i == $displayed{'web'}); |
|
next if ($i == $displayed{'folder'}); |
|
$env{'form.archive_dependent_on_'.$i} = $displayed{'web'}; |
|
} |
|
$env{'form.phase'} = 'decompress_cleanup'; |
|
$env{'form.archivedelete'} = 1; |
|
$env{'form.archive_count'} = $total-1; |
|
$output .= |
|
&process_extracted_files('coursedocs',$docudom, |
|
$docuname,$destination, |
|
$dir_root,$hiddenelem); |
|
} |
|
} else { |
|
$warning = &mt('No new items extracted from archive file.'); |
|
} |
|
} else { |
|
$output = $display; |
|
$error = &mt('An error occurred during extraction from the archive file.'); |
|
} |
|
} |
|
} |
|
} |
|
if ($error) { |
|
$output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'. |
|
$error.'</p>'."\n"; |
|
} |
|
if ($warning) { |
|
$output .= '<p class="LC_warning">'.$warning.'</p>'."\n"; |
|
} |
|
return $output; |
|
} |
|
|
|
sub get_extracted { |
|
my ($docudom,$docuname,$currdir,$is_dir,$children,$parent,$contents,$dirorder, |
|
$titles,$wantform) = @_; |
|
my $count = 0; |
|
my $depth = 0; |
|
my $datatable; |
|
my @hierarchy; |
|
return unless ((ref($is_dir) eq 'HASH') && (ref($children) eq 'HASH') && |
|
(ref($parent) eq 'HASH') && (ref($contents) eq 'ARRAY') && |
|
(ref($dirorder) eq 'HASH') && (ref($titles) eq 'HASH')); |
|
foreach my $item (@{$contents}) { |
|
$count ++; |
|
@{$dirorder->{$count}} = @hierarchy; |
|
$titles->{$count} = $item; |
|
&archive_hierarchy($depth,$count,$parent,$children); |
|
if ($wantform) { |
|
$datatable .= &archive_row($is_dir->{$item},$item, |
|
$currdir,$depth,$count); |
|
} |
|
if ($is_dir->{$item}) { |
|
$depth ++; |
|
push(@hierarchy,$count); |
|
$parent->{$depth} = $count; |
|
$datatable .= |
|
&recurse_extracted_archive("$currdir/$item",$docudom,$docuname, |
|
\$depth,\$count,\@hierarchy,$dirorder, |
|
$children,$parent,$titles,$wantform); |
|
$depth --; |
|
pop(@hierarchy); |
|
} |
|
} |
|
return ($count,$datatable); |
|
} |
|
|
|
sub recurse_extracted_archive { |
|
my ($currdir,$docudom,$docuname,$depth,$count,$hierarchy,$dirorder, |
|
$children,$parent,$titles,$wantform) = @_; |
|
my $result=''; |
|
unless ((ref($depth)) && (ref($count)) && (ref($hierarchy) eq 'ARRAY') && |
|
(ref($children) eq 'HASH') && (ref($parent) eq 'HASH') && |
|
(ref($dirorder) eq 'HASH')) { |
|
return $result; |
|
} |
|
my $dirptr = 16384; |
|
my ($newdirlistref,$newlisterror) = |
|
&Apache::lonnet::dirlist($currdir,$docudom,$docuname,1); |
|
if (ref($newdirlistref) eq 'ARRAY') { |
|
foreach my $dir_line (@{$newdirlistref}) { |
|
my ($item,undef,undef,$testdir)=split(/\&/,$dir_line,5); |
|
unless ($item =~ /^\.+$/) { |
|
$$count ++; |
|
@{$dirorder->{$$count}} = @{$hierarchy}; |
|
$titles->{$$count} = $item; |
|
&archive_hierarchy($$depth,$$count,$parent,$children); |
|
|
|
my $is_dir; |
|
if ($dirptr&$testdir) { |
|
$is_dir = 1; |
|
} |
|
if ($wantform) { |
|
$result .= &archive_row($is_dir,$item,$currdir,$$depth,$$count); |
|
} |
|
if ($is_dir) { |
|
$$depth ++; |
|
push(@{$hierarchy},$$count); |
|
$parent->{$$depth} = $$count; |
|
$result .= |
|
&recurse_extracted_archive("$currdir/$item",$docudom, |
|
$docuname,$depth,$count, |
|
$hierarchy,$dirorder,$children, |
|
$parent,$titles,$wantform); |
|
$$depth --; |
|
pop(@{$hierarchy}); |
|
} |
|
} |
|
} |
|
} |
|
return $result; |
|
} |
|
|
|
sub archive_hierarchy { |
|
my ($depth,$count,$parent,$children) =@_; |
|
if ((ref($parent) eq 'HASH') && (ref($children) eq 'HASH')) { |
|
if (exists($parent->{$depth})) { |
|
$children->{$parent->{$depth}} .= $count.':'; |
|
} |
|
} |
|
return; |
|
} |
|
|
|
sub archive_row { |
|
my ($is_dir,$item,$currdir,$depth,$count) = @_; |
|
my ($name) = ($item =~ m{([^/]+)$}); |
|
my %choices = &Apache::lonlocal::texthash ( |
|
'display' => 'Add as file', |
|
'dependency' => 'Include as dependency', |
|
'discard' => 'Discard', |
|
); |
|
if ($is_dir) { |
|
$choices{'display'} = &mt('Add as folder'); |
|
} |
|
my $output = &start_data_table_row().'<td align="right">'.$count.'</td>'."\n"; |
|
my $offset = 0; |
|
foreach my $action ('display','dependency','discard') { |
|
$offset ++; |
|
if ($action ne 'display') { |
|
$offset ++; |
|
} |
|
$output .= '<td><span class="LC_nobreak">'. |
|
'<label><input type="radio" name="archive_'.$count. |
|
'" id="archive_'.$action.'_'.$count.'" value="'.$action.'"'; |
|
my $text = $choices{$action}; |
|
if ($is_dir) { |
|
$output .= ' onclick="javascript:propagateCheck(this.form,'."'$count'".');"'; |
|
if ($action eq 'display') { |
|
$text = &mt('Add as folder'); |
|
} |
|
} else { |
|
$output .= ' onclick="javascript:dependencyCheck(this.form,'."$count,$offset".');"'; |
|
|
|
} |
|
$output .= ' /> '.$choices{$action}.'</label></span>'; |
|
if ($action eq 'dependency') { |
|
$output .= '<div id="arc_depon_'.$count.'" style="display:none;">'."\n". |
|
&mt('Used by:').' <select name="archive_dependent_on_'.$count.'" '. |
|
'onchange="propagateSelect(this.form,'."$count,$offset".')">'."\n". |
|
'<option value=""></option>'."\n". |
|
'</select>'."\n". |
|
'</div>'; |
|
} elsif ($action eq 'display') { |
|
$output .= '<div id="arc_title_'.$count.'" style="display:none;">'."\n". |
|
&mt('Title:').' <input type="text" name="archive_title_'.$count.'" id="archive_title_'.$count.'" />'."\n". |
|
'</div>'; |
|
} |
|
$output .= '</td>'; |
|
} |
|
$output .= '<td><input type="hidden" name="archive_content_'.$count.'" value="'. |
|
&HTML::Entities::encode("$currdir/$item",'"<>&').'" />'.(' ' x 2); |
|
for (my $i=0; $i<$depth; $i++) { |
|
$output .= ('<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" alt="" />' x2)."\n"; |
|
} |
|
if ($is_dir) { |
|
$output .= '<img src="/adm/lonIcons/navmap.folder.open.gif" alt="" /> '."\n". |
|
'<input type="hidden" name="archive_directory" value="'.$count.'" />'."\n"; |
|
} else { |
|
$output .= '<input type="hidden" name="archive_file" value="'.$count.'" />'."\n"; |
|
} |
|
$output .= ' '.$name.'</td>'."\n". |
|
&end_data_table_row(); |
|
return $output; |
|
} |
|
|
|
sub archive_options_form { |
|
my ($form,$display,$count,$hiddenelem) = @_; |
|
my %lt = &Apache::lonlocal::texthash( |
|
perm => 'Permanently remove archive file?', |
|
hows => 'How should each extracted item be incorporated in the course?', |
|
cont => 'Content actions for all', |
|
addf => 'Add as folder/file', |
|
incd => 'Include as dependency for a displayed file', |
|
disc => 'Discard', |
|
no => 'No', |
|
yes => 'Yes', |
|
save => 'Save', |
|
); |
|
my $output = <<"END"; |
|
<form name="$form" method="post" action=""> |
|
<p><span class="LC_nobreak">$lt{'perm'} |
|
<label> |
|
<input type="radio" name="archivedelete" value="0" checked="checked" />$lt{'no'} |
|
</label> |
|
|
|
<label> |
|
<input type="radio" name="archivedelete" value="1" />$lt{'yes'}</label> |
|
</span> |
|
</p> |
|
<input type="hidden" name="phase" value="decompress_cleanup" /> |
|
<br />$lt{'hows'} |
|
<div class="LC_columnSection"> |
|
<fieldset> |
|
<legend>$lt{'cont'}</legend> |
|
<input type="button" value="$lt{'addf'}" onclick="javascript:checkAll(document.$form,'display');" /> |
|
<input type="button" value="$lt{'incd'}" onclick="javascript:checkAll(document.$form,'dependency');" /> |
|
<input type="button" value="$lt{'disc'}" onclick="javascript:checkAll(document.$form,'discard');" /> |
|
</fieldset> |
|
</div> |
|
END |
|
return $output. |
|
&start_data_table()."\n". |
|
$display."\n". |
|
&end_data_table()."\n". |
|
'<input type="hidden" name="archive_count" value="'.$count.'" />'. |
|
$hiddenelem. |
|
'<br /><input type="submit" name="archive_submit" value="'.$lt{'save'}.'" />'. |
|
'</form>'; |
|
} |
|
|
|
sub archive_javascript { |
|
my ($startcount,$numitems,$titles,$children) = @_; |
|
return unless ((ref($titles) eq 'HASH') && (ref($children) eq 'HASH')); |
|
my $maintitle = $env{'form.comment'}; |
|
my $scripttag = <<START; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
|
|
function checkAll(form,prefix) { |
|
var idstr = new RegExp("^archive_"+prefix+"_\\\\d+\$"); |
|
for (var i=0; i < form.elements.length; i++) { |
|
var id = form.elements[i].id; |
|
if ((id != '') && (id != undefined)) { |
|
if (idstr.test(id)) { |
|
if (form.elements[i].type == 'radio') { |
|
form.elements[i].checked = true; |
|
var nostart = i-$startcount; |
|
var offset = nostart%7; |
|
var count = (nostart-offset)/7; |
|
dependencyCheck(form,count,offset); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
function propagateCheck(form,count) { |
|
if (count > 0) { |
|
var startelement = $startcount + ((count-1) * 7); |
|
for (var j=1; j<6; j++) { |
|
if ((j != 2) && (j != 4)) { |
|
var item = startelement + j; |
|
if (form.elements[item].type == 'radio') { |
|
if (form.elements[item].checked) { |
|
containerCheck(form,count,j); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
numitems = $numitems |
|
var titles = new Array(numitems); |
|
var parents = new Array(numitems); |
|
for (var i=0; i<numitems; i++) { |
|
parents[i] = new Array; |
|
} |
|
var maintitle = '$maintitle'; |
|
|
|
START |
|
|
|
foreach my $container (sort { $a <=> $b } (keys(%{$children}))) { |
|
my @contents = split(/:/,$children->{$container}); |
|
for (my $i=0; $i<@contents; $i ++) { |
|
$scripttag .= 'parents['.$container.']['.$i.'] = '.$contents[$i]."\n"; |
|
} |
|
} |
|
|
|
foreach my $key (sort { $a <=> $b } (keys(%{$titles}))) { |
|
$scripttag .= "titles[$key] = '".$titles->{$key}."';\n"; |
|
} |
|
|
|
$scripttag .= <<END; |
|
|
|
function containerCheck(form,count,offset) { |
|
if (count > 0) { |
|
dependencyCheck(form,count,offset); |
|
var item = (offset+$startcount)+7*(count-1); |
|
form.elements[item].checked = true; |
|
if(Object.prototype.toString.call(parents[count]) === '[object Array]') { |
|
if (parents[count].length > 0) { |
|
for (var j=0; j<parents[count].length; j++) { |
|
containerCheck(form,parents[count][j],offset); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
function dependencyCheck(form,count,offset) { |
|
if (count > 0) { |
|
var chosen = (offset+$startcount)+7*(count-1); |
|
var depitem = $startcount + ((count-1) * 7) + 4; |
|
var currtype = form.elements[depitem].type; |
|
if (form.elements[chosen].value == 'dependency') { |
|
document.getElementById('arc_depon_'+count).style.display='block'; |
|
form.elements[depitem].options.length = 0; |
|
form.elements[depitem].options[0] = new Option('Select','',true,true); |
|
for (var i=1; i<=numitems; i++) { |
|
if (i == count) { |
|
continue; |
|
} |
|
var startelement = $startcount + (i-1) * 7; |
|
for (var j=1; j<6; j++) { |
|
if ((j != 2) && (j!= 4)) { |
|
var item = startelement + j; |
|
if (form.elements[item].type == 'radio') { |
|
if (form.elements[item].checked) { |
|
if (form.elements[item].value == 'display') { |
|
var n = form.elements[depitem].options.length; |
|
form.elements[depitem].options[n] = new Option(titles[i],i,false,false); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
document.getElementById('arc_depon_'+count).style.display='none'; |
|
form.elements[depitem].options.length = 0; |
|
form.elements[depitem].options[0] = new Option('Select','',true,true); |
|
} |
|
titleCheck(form,count,offset); |
|
} |
|
} |
|
|
|
function propagateSelect(form,count,offset) { |
|
if (count > 0) { |
|
var item = (1+offset+$startcount)+7*(count-1); |
|
var picked = form.elements[item].options[form.elements[item].selectedIndex].value; |
|
if (Object.prototype.toString.call(parents[count]) === '[object Array]') { |
|
if (parents[count].length > 0) { |
|
for (var j=0; j<parents[count].length; j++) { |
|
containerSelect(form,parents[count][j],offset,picked); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
function containerSelect(form,count,offset,picked) { |
|
if (count > 0) { |
|
var item = (offset+$startcount)+7*(count-1); |
|
if (form.elements[item].type == 'radio') { |
|
if (form.elements[item].value == 'dependency') { |
|
if (form.elements[item+1].type == 'select-one') { |
|
for (var i=0; i<form.elements[item+1].options.length; i++) { |
|
if (form.elements[item+1].options[i].value == picked) { |
|
form.elements[item+1].selectedIndex = i; |
|
break; |
|
} |
|
} |
|
} |
|
if (Object.prototype.toString.call(parents[count]) === '[object Array]') { |
|
if (parents[count].length > 0) { |
|
for (var j=0; j<parents[count].length; j++) { |
|
containerSelect(form,parents[count][j],offset,picked); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
function titleCheck(form,count,offset) { |
|
if (count > 0) { |
|
var chosen = (offset+$startcount)+7*(count-1); |
|
var depitem = $startcount + ((count-1) * 7) + 2; |
|
var currtype = form.elements[depitem].type; |
|
if (form.elements[chosen].value == 'display') { |
|
document.getElementById('arc_title_'+count).style.display='block'; |
|
if ((count==1) && ((parents[count].length > 0) || (numitems == 1))) { |
|
document.getElementById('archive_title_'+count).value=maintitle; |
|
} |
|
} else { |
|
document.getElementById('arc_title_'+count).style.display='none'; |
|
if (currtype == 'text') { |
|
document.getElementById('archive_title_'+count).value=''; |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
// ]]> |
|
</script> |
|
END |
|
return $scripttag; |
|
} |
|
|
|
sub process_extracted_files { |
|
my ($context,$docudom,$docuname,$destination,$dir_root,$hiddenelem) = @_; |
|
my $numitems = $env{'form.archive_count'}; |
|
return if ((!$numitems) || ($numitems =~ /\D/)); |
|
my @ids=&Apache::lonnet::current_machine_ids(); |
|
my ($prefix,$pathtocheck,$dir,$ishome,$error,$warning,%toplevelitems,%is_dir, |
|
%folders,%containers,%mapinner,%prompttofetch); |
|
my $docuhome = &Apache::lonnet::homeserver($docuname,$docudom); |
|
if (grep(/^\Q$docuhome\E$/,@ids)) { |
|
$prefix = &LONCAPA::propath($docudom,$docuname); |
|
$pathtocheck = "$dir_root/$destination"; |
|
$dir = $dir_root; |
|
$ishome = 1; |
|
} else { |
|
$prefix = $Apache::lonnet::perlvar{'lonDocRoot'}; |
|
$pathtocheck = "$dir_root/$docudom/$docuname/$destination"; |
|
$dir = "$dir_root/$docudom/$docuname"; |
|
} |
|
my $currdir = "$dir_root/$destination"; |
|
(my $docstype,$mapinner{'0'}) = ($destination =~ m{^(docs|supplemental)/(\w+)/}); |
|
if ($env{'form.folderpath'}) { |
|
my @items = split('&',$env{'form.folderpath'}); |
|
$folders{'0'} = $items[-2]; |
|
if ($env{'form.folderpath'} =~ /\:1$/) { |
|
$containers{'0'}='page'; |
|
} else { |
|
$containers{'0'}='sequence'; |
|
} |
|
} |
|
my @archdirs = &get_env_multiple('form.archive_directory'); |
|
if ($numitems) { |
|
for (my $i=1; $i<=$numitems; $i++) { |
|
my $path = $env{'form.archive_content_'.$i}; |
|
if ($path =~ m{^\Q$pathtocheck\E/([^/]+)$}) { |
|
my $item = $1; |
|
$toplevelitems{$item} = $i; |
|
if (grep(/^\Q$i\E$/,@archdirs)) { |
|
$is_dir{$item} = 1; |
|
} |
|
} |
|
} |
|
} |
|
my ($output,%children,%parent,%titles,%dirorder,$result); |
|
if (keys(%toplevelitems) > 0) { |
|
my @contents = sort(keys(%toplevelitems)); |
|
(my $count,undef) = &get_extracted($docudom,$docuname,$currdir,\%is_dir,\%children, |
|
\%parent,\@contents,\%dirorder,\%titles); |
|
} |
|
my (%referrer,%orphaned,%todelete,%todeletedir,%newdest,%newseqid); |
|
if ($numitems) { |
|
for (my $i=1; $i<=$numitems; $i++) { |
|
next if ($env{'form.archive_'.$i} eq 'dependency'); |
|
my $path = $env{'form.archive_content_'.$i}; |
|
if ($path =~ /^\Q$pathtocheck\E/) { |
|
if ($env{'form.archive_'.$i} eq 'discard') { |
|
if ($prefix ne '' && $path ne '') { |
|
if (-e $prefix.$path) { |
|
if ((@archdirs > 0) && |
|
(grep(/^\Q$i\E$/,@archdirs))) { |
|
$todeletedir{$prefix.$path} = 1; |
|
} else { |
|
$todelete{$prefix.$path} = 1; |
|
} |
|
} |
|
} |
|
} elsif ($env{'form.archive_'.$i} eq 'display') { |
|
my ($docstitle,$title,$url,$outer); |
|
($title) = ($path =~ m{/([^/]+)$}); |
|
$docstitle = $env{'form.archive_title_'.$i}; |
|
if ($docstitle eq '') { |
|
$docstitle = $title; |
|
} |
|
$outer = 0; |
|
if (ref($dirorder{$i}) eq 'ARRAY') { |
|
if (@{$dirorder{$i}} > 0) { |
|
foreach my $item (reverse(@{$dirorder{$i}})) { |
|
if ($env{'form.archive_'.$item} eq 'display') { |
|
$outer = $item; |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
my ($errtext,$fatal) = |
|
&LONCAPA::map::mapread('/uploaded/'.$docudom.'/'.$docuname. |
|
'/'.$folders{$outer}.'.'. |
|
$containers{$outer}); |
|
next if ($fatal); |
|
if ((@archdirs > 0) && (grep(/^\Q$i\E$/,@archdirs))) { |
|
if ($context eq 'coursedocs') { |
|
$mapinner{$i} = time; |
|
$folders{$i} = 'default_'.$mapinner{$i}; |
|
$containers{$i} = 'sequence'; |
|
my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'. |
|
$folders{$i}.'.'.$containers{$i}; |
|
my $newidx = &LONCAPA::map::getresidx(); |
|
$LONCAPA::map::resources[$newidx]= |
|
$docstitle.':'.$url.':false:normal:res'; |
|
push(@LONCAPA::map::order,$newidx); |
|
my ($outtext,$errtext) = |
|
&LONCAPA::map::storemap('/uploaded/'.$docudom.'/'. |
|
$docuname.'/'.$folders{$outer}. |
|
'.'.$containers{$outer},1,1); |
|
$newseqid{$i} = $newidx; |
|
unless ($errtext) { |
|
$result .= '<li>'.&mt('Folder: [_1] added to course', |
|
&HTML::Entities::encode($docstitle,'<>&"')).. |
|
'</li>'."\n"; |
|
} |
|
} |
|
} else { |
|
if ($context eq 'coursedocs') { |
|
my $newidx=&LONCAPA::map::getresidx(); |
|
my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'. |
|
$docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'. |
|
$title; |
|
if (($outer !~ /\D/) && |
|
(($mapinner{$outer} eq 'default') || ($mapinner{$outer} !~ /\D/)) && |
|
($newidx !~ /\D/)) { |
|
if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") { |
|
mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755); |
|
} |
|
if (!-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") { |
|
mkdir("$prefix$dir/$docstype/$mapinner{$outer}/$newidx"); |
|
} |
|
if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx") { |
|
if (rename("$prefix$path","$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title")) { |
|
$newdest{$i} = "$prefix$dir/$docstype/$mapinner{$outer}/$newidx"; |
|
unless ($ishome) { |
|
my $fetch = "$newdest{$i}/$title"; |
|
$fetch =~ s/^\Q$prefix$dir\E//; |
|
$prompttofetch{$fetch} = 1; |
|
} |
|
} |
|
} |
|
$LONCAPA::map::resources[$newidx]= |
|
$docstitle.':'.$url.':false:normal:res'; |
|
push(@LONCAPA::map::order, $newidx); |
|
my ($outtext,$errtext)= |
|
&LONCAPA::map::storemap('/uploaded/'.$docudom.'/'. |
|
$docuname.'/'.$folders{$outer}. |
|
'.'.$containers{$outer},1,1); |
|
unless ($errtext) { |
|
if (-e "$prefix$dir/$docstype/$mapinner{$outer}/$newidx/$title") { |
|
$result .= '<li>'.&mt('File: [_1] added to course', |
|
&HTML::Entities::encode($docstitle,'<>&"')). |
|
'</li>'."\n"; |
|
} |
|
} |
|
} else { |
|
$warning .= &mt('Item extracted from archive: [_1] has unexpected path.', |
|
&HTML::Entities::encode($path,'<>&"')).'<br />'; |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
$warning .= &mt('Item extracted from archive: [_1] has unexpected path.', |
|
&HTML::Entities::encode($path,'<>&"')).'<br />'; |
|
} |
|
} |
|
for (my $i=1; $i<=$numitems; $i++) { |
|
next unless ($env{'form.archive_'.$i} eq 'dependency'); |
|
my $path = $env{'form.archive_content_'.$i}; |
|
if ($path =~ /^\Q$pathtocheck\E/) { |
|
my ($title) = ($path =~ m{/([^/]+)$}); |
|
$referrer{$i} = $env{'form.archive_dependent_on_'.$i}; |
|
if ($env{'form.archive_'.$referrer{$i}} eq 'display') { |
|
if (ref($dirorder{$i}) eq 'ARRAY') { |
|
my ($itemidx,$fullpath,$relpath); |
|
if (ref($dirorder{$referrer{$i}}) eq 'ARRAY') { |
|
my $container = $dirorder{$referrer{$i}}->[-1]; |
|
for (my $j=0; $j<@{$dirorder{$i}}; $j++) { |
|
if ($dirorder{$i}->[$j] eq $container) { |
|
$itemidx = $j; |
|
} |
|
} |
|
} |
|
if ($itemidx eq '') { |
|
$itemidx = 0; |
|
} |
|
if (grep(/^\Q$referrer{$i}\E$/,@archdirs)) { |
|
if ($mapinner{$referrer{$i}}) { |
|
$fullpath = "$prefix$dir/$docstype/$mapinner{$referrer{$i}}"; |
|
for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) { |
|
if (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) { |
|
unless (defined($newseqid{$dirorder{$i}->[$j]})) { |
|
$fullpath .= '/'.$titles{$dirorder{$i}->[$j]}; |
|
$relpath .= '/'.$titles{$dirorder{$i}->[$j]}; |
|
if (!-e $fullpath) { |
|
mkdir($fullpath,0755); |
|
} |
|
} |
|
} else { |
|
last; |
|
} |
|
} |
|
} |
|
} elsif ($newdest{$referrer{$i}}) { |
|
$fullpath = $newdest{$referrer{$i}}; |
|
for (my $j=$itemidx; $j<@{$dirorder{$i}}; $j++) { |
|
if ($env{'form.archive_'.$dirorder{$i}->[$j]} eq 'discard') { |
|
$orphaned{$i} = $env{'form.archive_'.$dirorder{$i}->[$j]}; |
|
last; |
|
} elsif (grep(/^\Q$dirorder{$i}->[$j]\E$/,@archdirs)) { |
|
unless (defined($newseqid{$dirorder{$i}->[$j]})) { |
|
$fullpath .= '/'.$titles{$dirorder{$i}->[$j]}; |
|
$relpath .= '/'.$titles{$dirorder{$i}->[$j]}; |
|
if (!-e $fullpath) { |
|
mkdir($fullpath,0755); |
|
} |
|
} |
|
} else { |
|
last; |
|
} |
|
} |
|
} |
|
if ($fullpath ne '') { |
|
if (-e "$prefix$path") { |
|
unless (rename("$prefix$path","$fullpath/$title")) { |
|
$warning .= &mt('Failed to rename dependency').'<br />'; |
|
} |
|
} |
|
if (-e "$fullpath/$title") { |
|
my $showpath; |
|
if ($relpath ne '') { |
|
$showpath = "$relpath/$title"; |
|
} else { |
|
$showpath = "/$title"; |
|
} |
|
$result .= '<li>'.&mt('[_1] included as a dependency', |
|
&HTML::Entities::encode($showpath,'<>&"')). |
|
'</li>'."\n"; |
|
unless ($ishome) { |
|
my $fetch = "$fullpath/$title"; |
|
$fetch =~ s/^\Q$prefix$dir\E//; |
|
$prompttofetch{$fetch} = 1; |
|
} |
|
} |
|
} |
|
} |
|
} elsif ($env{'form.archive_'.$referrer{$i}} eq 'discard') { |
|
$warning .= &mt('[_1] is a dependency of [_2], which was discarded.', |
|
&HTML::Entities::encode($path,'<>&"'), |
|
&HTML::Entities::encode($env{'form.archive_content_'.$referrer{$i}},'<>&"')). |
|
'<br />'; |
|
} |
|
} else { |
|
$warning .= &mt('Item extracted from archive: [_1] has unexpected path.', |
|
&HTML::Entities::encode($path)).'<br />'; |
|
} |
|
} |
|
if (keys(%todelete)) { |
|
foreach my $key (keys(%todelete)) { |
|
unlink($key); |
|
} |
|
} |
|
if (keys(%todeletedir)) { |
|
foreach my $key (keys(%todeletedir)) { |
|
rmdir($key); |
|
} |
|
} |
|
foreach my $dir (sort(keys(%is_dir))) { |
|
if (($pathtocheck ne '') && ($dir ne '')) { |
|
&cleanup_empty_dirs($prefix."$pathtocheck/$dir"); |
|
} |
|
} |
|
if ($result ne '') { |
|
$output .= '<ul>'."\n". |
|
$result."\n". |
|
'</ul>'; |
|
} |
|
unless ($ishome) { |
|
my $replicationfail; |
|
foreach my $item (keys(%prompttofetch)) { |
|
my $fetchresult= &Apache::lonnet::reply('fetchuserfile:'.$item,$docuhome); |
|
unless ($fetchresult eq 'ok') { |
|
$replicationfail .= '<li>'.$item.'</li>'."\n"; |
|
} |
|
} |
|
if ($replicationfail) { |
|
$output .= '<p class="LC_error">'. |
|
&mt('Course home server failed to retrieve:').'<ul>'. |
|
$replicationfail. |
|
'</ul></p>'; |
|
} |
|
} |
|
} else { |
|
$warning = &mt('No items found in archive.'); |
|
} |
|
if ($error) { |
|
$output .= '<p class="LC_error">'.&mt('Not extracted.').'<br />'. |
|
$error.'</p>'."\n"; |
|
} |
|
if ($warning) { |
|
$output .= '<p class="LC_warning">'.$warning.'</p>'."\n"; |
|
} |
|
return $output; |
|
} |
|
|
|
sub cleanup_empty_dirs { |
|
my ($path) = @_; |
|
if (($path ne '') && (-d $path)) { |
|
if (opendir(my $dirh,$path)) { |
|
my @dircontents = grep(!/^\./,readdir($dirh)); |
|
my $numitems = 0; |
|
foreach my $item (@dircontents) { |
|
if (-d "$path/$item") { |
|
&cleanup_empty_dirs("$path/$item"); |
|
if (-e "$path/$item") { |
|
$numitems ++; |
|
} |
|
} else { |
|
$numitems ++; |
|
} |
|
} |
|
if ($numitems == 0) { |
|
rmdir($path); |
|
} |
|
closedir($dirh); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
=pod |
|
|
|
=item * &get_folder_hierarchy() |
|
|
|
Provides hierarchy of names of folders/sub-folders containing the current |
|
item, |
|
|
|
Inputs: 3 |
|
- $navmap - navmaps object |
|
|
|
- $map - url for map (either the trigger itself, or map containing |
|
the resource, which is the trigger). |
|
|
|
- $showitem - 1 => show title for map itself; 0 => do not show. |
|
|
|
Outputs: 1 @pathitems - array of folder/subfolder names. |
|
|
|
=cut |
|
|
|
sub get_folder_hierarchy { |
|
my ($navmap,$map,$showitem) = @_; |
|
my @pathitems; |
|
if (ref($navmap)) { |
|
my $mapres = $navmap->getResourceByUrl($map); |
|
if (ref($mapres)) { |
|
my $pcslist = $mapres->map_hierarchy(); |
|
if ($pcslist ne '') { |
|
my @pcs = split(/,/,$pcslist); |
|
foreach my $pc (@pcs) { |
|
if ($pc == 1) { |
|
push(@pathitems,&mt('Main Content')); |
|
} else { |
|
my $res = $navmap->getByMapPc($pc); |
|
if (ref($res)) { |
|
my $title = $res->compTitle(); |
|
$title =~ s/\W+/_/g; |
|
if ($title ne '') { |
|
push(@pathitems,$title); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ($showitem) { |
|
if ($mapres->{ID} eq '0.0') { |
|
push(@pathitems,&mt('Main Content')); |
|
} else { |
|
my $maptitle = $mapres->compTitle(); |
|
$maptitle =~ s/\W+/_/g; |
|
if ($maptitle ne '') { |
|
push(@pathitems,$maptitle); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return @pathitems; |
|
} |
|
|
|
=pod |
|
|
|
=item * &get_turnedin_filepath() |
|
|
|
Determines path in a user's portfolio file for storage of files uploaded |
|
to a specific essayresponse or dropbox item. |
|
|
|
Inputs: 3 required + 1 optional. |
|
$symb is symb for resource, $uname and $udom are for current user (required). |
|
$caller is optional (can be "submission", if routine is called when storing |
|
an upoaded file when "Submit Answer" button was pressed). |
|
|
|
Returns array containing $path and $multiresp. |
|
$path is path in portfolio. $multiresp is 1 if this resource contains more |
|
than one file upload item. Callers of routine should append partid as a |
|
subdirectory to $path in cases where $multiresp is 1. |
|
|
|
Called by: homework/essayresponse.pm and homework/structuretags.pm |
|
|
|
=cut |
|
|
|
sub get_turnedin_filepath { |
|
my ($symb,$uname,$udom,$caller) = @_; |
|
my ($map,$resid,$resurl)=&Apache::lonnet::decode_symb($symb); |
|
my $turnindir; |
|
my %userhash = &Apache::lonnet::userenvironment($udom,$uname,'turnindir'); |
|
$turnindir = $userhash{'turnindir'}; |
|
my ($path,$multiresp); |
|
if ($turnindir eq '') { |
|
if ($caller eq 'submission') { |
|
$turnindir = &mt('turned in'); |
|
$turnindir =~ s/\W+/_/g; |
|
my %newhash = ( |
|
'turnindir' => $turnindir, |
|
); |
|
&Apache::lonnet::put('environment',\%newhash,$udom,$uname); |
|
} |
|
} |
|
if ($turnindir ne '') { |
|
$path = '/'.$turnindir.'/'; |
|
my ($multipart,$turnin,@pathitems); |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (defined($navmap)) { |
|
my $mapres = $navmap->getResourceByUrl($map); |
|
if (ref($mapres)) { |
|
my $pcslist = $mapres->map_hierarchy(); |
|
if ($pcslist ne '') { |
|
foreach my $pc (split(/,/,$pcslist)) { |
|
my $res = $navmap->getByMapPc($pc); |
|
if (ref($res)) { |
|
my $title = $res->compTitle(); |
|
$title =~ s/\W+/_/g; |
|
if ($title ne '') { |
|
if (($pc > 1) && (length($title) > 12)) { |
|
$title = substr($title,0,12); |
|
} |
|
push(@pathitems,$title); |
|
} |
|
} |
|
} |
|
} |
|
my $maptitle = $mapres->compTitle(); |
|
$maptitle =~ s/\W+/_/g; |
|
if ($maptitle ne '') { |
|
if (length($maptitle) > 12) { |
|
$maptitle = substr($maptitle,0,12); |
|
} |
|
push(@pathitems,$maptitle); |
|
} |
|
unless ($env{'request.state'} eq 'construct') { |
|
my $res = $navmap->getBySymb($symb); |
|
if (ref($res)) { |
|
my $partlist = $res->parts(); |
|
my $totaluploads = 0; |
|
if (ref($partlist) eq 'ARRAY') { |
|
foreach my $part (@{$partlist}) { |
|
my @types = $res->responseType($part); |
|
my @ids = $res->responseIds($part); |
|
for (my $i=0; $i < scalar(@ids); $i++) { |
|
if ($types[$i] eq 'essay') { |
|
my $partid = $part.'_'.$ids[$i]; |
|
if (&Apache::lonnet::EXT("resource.$partid.uploadedfiletypes") ne '') { |
|
$totaluploads ++; |
|
} |
|
} |
|
} |
|
} |
|
if ($totaluploads > 1) { |
|
$multiresp = 1; |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
return; |
|
} |
|
} else { |
|
return; |
|
} |
|
my $restitle=&Apache::lonnet::gettitle($symb); |
|
$restitle =~ s/\W+/_/g; |
|
if ($restitle eq '') { |
|
$restitle = ($resurl =~ m{/[^/]+$}); |
|
if ($restitle eq '') { |
|
$restitle = time; |
|
} |
|
} |
|
if (length($restitle) > 12) { |
|
$restitle = substr($restitle,0,12); |
|
} |
|
push(@pathitems,$restitle); |
|
$path .= join('/',@pathitems); |
|
} |
|
return ($path,$multiresp); |
|
} |
|
|
=pod |
=pod |
|
|
Line 5681 sub get_env_multiple {
|
Line 14565 sub get_env_multiple {
|
|
|
=over 4 |
=over 4 |
|
|
=item * upfile_store($r) |
=item * &upfile_store($r) |
|
|
Store uploaded file, $r should be the HTTP Request object, |
Store uploaded file, $r should be the HTTP Request object, |
needs $env{'form.upfile'} |
needs $env{'form.upfile'} |
Line 5696 sub upfile_store {
|
Line 14580 sub upfile_store {
|
$env{'form.upfile'}=~s/\n+/\n/gs; |
$env{'form.upfile'}=~s/\n+/\n/gs; |
$env{'form.upfile'}=~s/\n+$//gs; |
$env{'form.upfile'}=~s/\n+$//gs; |
|
|
my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}. |
my $datatoken = &valid_datatoken($env{'user.name'}.'_'.$env{'user.domain'}. |
'_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$; |
'_enroll_'.$env{'request.course.id'}.'_'. |
|
time.'_'.$$); |
|
return if ($datatoken eq ''); |
|
|
{ |
{ |
my $datafile = $r->dir_config('lonDaemons'). |
my $datafile = $r->dir_config('lonDaemons'). |
'/tmp/'.$datatoken.'.tmp'; |
'/tmp/'.$datatoken.'.tmp'; |
if ( open(my $fh,">$datafile") ) { |
if ( open(my $fh,'>',$datafile) ) { |
print $fh $env{'form.upfile'}; |
print $fh $env{'form.upfile'}; |
close($fh); |
close($fh); |
} |
} |
Line 5711 sub upfile_store {
|
Line 14598 sub upfile_store {
|
|
|
=pod |
=pod |
|
|
=item * load_tmp_file($r) |
=item * &load_tmp_file($r,$datatoken) |
|
|
Load uploaded file from tmp, $r should be the HTTP Request object, |
Load uploaded file from tmp, $r should be the HTTP Request object, |
needs $env{'form.datatoken'}, |
$datatoken is the name to assign to the temporary file. |
sets $env{'form.upfile'} to the contents of the file |
sets $env{'form.upfile'} to the contents of the file |
|
|
=cut |
=cut |
|
|
sub load_tmp_file { |
sub load_tmp_file { |
my $r=shift; |
my ($r,$datatoken) = @_; |
|
return if ($datatoken eq ''); |
my @studentdata=(); |
my @studentdata=(); |
{ |
{ |
my $studentfile = $r->dir_config('lonDaemons'). |
my $studentfile = $r->dir_config('lonDaemons'). |
'/tmp/'.$env{'form.datatoken'}.'.tmp'; |
'/tmp/'.$datatoken.'.tmp'; |
if ( open(my $fh,"<$studentfile") ) { |
if ( open(my $fh,'<',$studentfile) ) { |
@studentdata=<$fh>; |
@studentdata=<$fh>; |
close($fh); |
close($fh); |
} |
} |
Line 5733 sub load_tmp_file {
|
Line 14621 sub load_tmp_file {
|
$env{'form.upfile'}=join('',@studentdata); |
$env{'form.upfile'}=join('',@studentdata); |
} |
} |
|
|
|
sub valid_datatoken { |
|
my ($datatoken) = @_; |
|
if ($datatoken =~ /^$match_username\_$match_domain\_enroll_(|$match_domain\_$match_courseid)\_\d+_\d+$/) { |
|
return $datatoken; |
|
} |
|
return; |
|
} |
|
|
=pod |
=pod |
|
|
=item * upfile_record_sep() |
=item * &upfile_record_sep() |
|
|
Separate uploaded file into records |
Separate uploaded file into records |
returns array of records, |
returns array of records, |
Line 5757 sub upfile_record_sep {
|
Line 14653 sub upfile_record_sep {
|
|
|
=pod |
=pod |
|
|
=item * record_sep($record) |
=item * &record_sep($record) |
|
|
Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'} |
Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'} |
|
|
Line 5789 sub record_sep {
|
Line 14685 sub record_sep {
|
$i++; |
$i++; |
} |
} |
} else { |
} else { |
my @allfields; |
my $separator=','; |
if ($env{'form.upfiletype'} eq 'semisv') { |
if ($env{'form.upfiletype'} eq 'semisv') { |
@allfields=split(/;/,$record,-1); |
$separator=';'; |
} else { |
|
@allfields=split(/\,/,$record,-1); |
|
} |
} |
my $i=0; |
my $i=0; |
my $j; |
# the character we are looking for to indicate the end of a quote or a record |
for ($j=0;$j<=$#allfields;$j++) { |
my $looking_for=$separator; |
my $field=$allfields[$j]; |
# do not add the characters to the fields |
if ($field=~/^\s*(\"|\')/) { |
my $ignore=0; |
my $delimiter=$1; |
# we just encountered a separator (or the beginning of the record) |
while (($field!~/$delimiter$/) && ($j<$#allfields)) { |
my $just_found_separator=1; |
$j++; |
# store the field we are working on here |
$field.=','.$allfields[$j]; |
my $field=''; |
} |
# work our way through all characters in record |
$field=~s/^\s*$delimiter//; |
foreach my $character ($record=~/(.)/g) { |
$field=~s/$delimiter\s*$//; |
if ($character eq $looking_for) { |
|
if ($character ne $separator) { |
|
# Found the end of a quote, again looking for separator |
|
$looking_for=$separator; |
|
$ignore=1; |
|
} else { |
|
# Found a separator, store away what we got |
|
$components{&takeleft($i)}=$field; |
|
$i++; |
|
$just_found_separator=1; |
|
$ignore=0; |
|
$field=''; |
|
} |
|
next; |
} |
} |
$components{&takeleft($i)}=$field; |
# single or double quotation marks after a separator indicate beginning of a quote |
$i++; |
# we are now looking for the end of the quote and need to ignore separators |
|
if ((($character eq '"') || ($character eq "'")) && ($just_found_separator)) { |
|
$looking_for=$character; |
|
next; |
|
} |
|
# ignore would be true after we reached the end of a quote |
|
if ($ignore) { next; } |
|
if (($just_found_separator) && ($character=~/\s/)) { next; } |
|
$field.=$character; |
|
$just_found_separator=0; |
} |
} |
|
# catch the very last entry, since we never encountered the separator |
|
$components{&takeleft($i)}=$field; |
} |
} |
return %components; |
return %components; |
} |
} |
Line 5820 sub record_sep {
|
Line 14738 sub record_sep {
|
|
|
=pod |
=pod |
|
|
=item * upfile_select_html() |
=item * &upfile_select_html() |
|
|
Return HTML code to select a file from the users machine and specify |
Return HTML code to select a file from the users machine and specify |
the file type. |
the file type. |
Line 5838 sub upfile_select_html {
|
Line 14756 sub upfile_select_html {
|
# xml => &mt('HTML/XML'), |
# xml => &mt('HTML/XML'), |
); |
); |
my $Str = '<input type="file" name="upfile" size="50" />'. |
my $Str = '<input type="file" name="upfile" size="50" />'. |
'<br />Type: <select name="upfiletype">'; |
'<br />'.&mt('Type').': <select name="upfiletype">'; |
foreach my $type (sort(keys(%Types))) { |
foreach my $type (sort(keys(%Types))) { |
$Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n"; |
$Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n"; |
} |
} |
Line 5867 sub get_samples {
|
Line 14785 sub get_samples {
|
|
|
=pod |
=pod |
|
|
=item * csv_print_samples($r,$records) |
=item * &csv_print_samples($r,$records) |
|
|
Prints a table of sample values from each column uploaded $r is an |
Prints a table of sample values from each column uploaded $r is an |
Apache Request ref, $records is an arrayref from |
Apache Request ref, $records is an arrayref from |
Line 5879 Apache Request ref, $records is an array
|
Line 14797 Apache Request ref, $records is an array
|
###################################################### |
###################################################### |
sub csv_print_samples { |
sub csv_print_samples { |
my ($r,$records) = @_; |
my ($r,$records) = @_; |
my $samples = &get_samples($records,3); |
my $samples = &get_samples($records,5); |
|
|
$r->print(&mt('Samples').'<br /><table border="2"><tr>'); |
$r->print(&mt('Samples').'<br />'.&start_data_table(). |
|
&start_data_table_header_row()); |
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { |
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { |
$r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); } |
$r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); } |
$r->print('</tr>'); |
$r->print(&end_data_table_header_row()); |
foreach my $hash (@$samples) { |
foreach my $hash (@$samples) { |
$r->print('<tr>'); |
$r->print(&start_data_table_row()); |
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { |
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { |
$r->print('<td>'); |
$r->print('<td>'); |
if (defined($$hash{$sample})) { $r->print($$hash{$sample}); } |
if (defined($$hash{$sample})) { $r->print($$hash{$sample}); } |
$r->print('</td>'); |
$r->print('</td>'); |
} |
} |
$r->print('</tr>'); |
$r->print(&end_data_table_row()); |
} |
} |
$r->print('</tr></table><br />'."\n"); |
$r->print(&end_data_table().'<br />'."\n"); |
} |
} |
|
|
###################################################### |
###################################################### |
Line 5902 sub csv_print_samples {
|
Line 14821 sub csv_print_samples {
|
|
|
=pod |
=pod |
|
|
=item * csv_print_select_table($r,$records,$d) |
=item * &csv_print_select_table($r,$records,$d) |
|
|
Prints a table to create associations between values and table columns. |
Prints a table to create associations between values and table columns. |
|
|
Line 5919 sub csv_print_select_table {
|
Line 14838 sub csv_print_select_table {
|
my $i=0; |
my $i=0; |
my $samples = &get_samples($records,1); |
my $samples = &get_samples($records,1); |
$r->print(&mt('Associate columns with student attributes.')."\n". |
$r->print(&mt('Associate columns with student attributes.')."\n". |
'<table border="2"><tr>'. |
&start_data_table().&start_data_table_header_row(). |
'<th>'.&mt('Attribute').'</th>'. |
'<th>'.&mt('Attribute').'</th>'. |
'<th>'.&mt('Column').'</th></tr>'."\n"); |
'<th>'.&mt('Column').'</th>'. |
|
&end_data_table_header_row()."\n"); |
foreach my $array_ref (@$d) { |
foreach my $array_ref (@$d) { |
my ($value,$display,$defaultcol)=@{ $array_ref }; |
my ($value,$display,$defaultcol)=@{ $array_ref }; |
$r->print('<tr><td>'.$display.'</td>'); |
$r->print(&start_data_table_row().'<td>'.$display.'</td>'); |
|
|
$r->print('<td><select name=f'.$i. |
$r->print('<td><select name="f'.$i.'"'. |
' onchange="javascript:flip(this.form,'.$i.');">'); |
' onchange="javascript:flip(this.form,'.$i.');">'); |
$r->print('<option value="none"></option>'); |
$r->print('<option value="none"></option>'); |
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { |
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) { |
$r->print('<option value="'.$sample.'"'. |
$r->print('<option value="'.$sample.'"'. |
($sample eq $defaultcol ? ' selected="selected" ' : ''). |
($sample eq $defaultcol ? ' selected="selected" ' : ''). |
'>Column '.($sample+1).'</option>'); |
'>'.&mt('Column [_1]',($sample+1)).'</option>'); |
} |
} |
$r->print('</select></td></tr>'."\n"); |
$r->print('</select></td>'.&end_data_table_row()."\n"); |
$i++; |
$i++; |
} |
} |
|
$r->print(&end_data_table()); |
$i--; |
$i--; |
return $i; |
return $i; |
} |
} |
Line 5946 sub csv_print_select_table {
|
Line 14867 sub csv_print_select_table {
|
|
|
=pod |
=pod |
|
|
=item * csv_samples_select_table($r,$records,$d) |
=item * &csv_samples_select_table($r,$records,$d) |
|
|
Prints a table of sample values from the upload and can make associate samples to internal names. |
Prints a table of sample values from the upload and can make associate samples to internal names. |
|
|
Line 5962 sub csv_samples_select_table {
|
Line 14883 sub csv_samples_select_table {
|
my ($r,$records,$d) = @_; |
my ($r,$records,$d) = @_; |
my $i=0; |
my $i=0; |
# |
# |
my $samples = &get_samples($records,3); |
my $max_samples = 5; |
$r->print('<table border=2><tr><th>'. |
my $samples = &get_samples($records,$max_samples); |
&mt('Field').'</th><th>'.&mt('Samples').'</th></tr>'); |
$r->print(&start_data_table(). |
|
&start_data_table_header_row().'<th>'. |
|
&mt('Field').'</th><th>'.&mt('Samples').'</th>'. |
|
&end_data_table_header_row()); |
|
|
foreach my $key (sort(keys(%{ $samples->[0] }))) { |
foreach my $key (sort(keys(%{ $samples->[0] }))) { |
$r->print('<tr><td><select name="f'.$i.'"'. |
$r->print(&start_data_table_row().'<td><select name="f'.$i.'"'. |
' onchange="javascript:flip(this.form,'.$i.');">'); |
' onchange="javascript:flip(this.form,'.$i.');">'); |
foreach my $option (@$d) { |
foreach my $option (@$d) { |
my ($value,$display,$defaultcol)=@{ $option }; |
my ($value,$display,$defaultcol)=@{ $option }; |
Line 5976 sub csv_samples_select_table {
|
Line 14900 sub csv_samples_select_table {
|
$display.'</option>'); |
$display.'</option>'); |
} |
} |
$r->print('</select></td><td>'); |
$r->print('</select></td><td>'); |
foreach my $line (0..2) { |
foreach my $line (0..($max_samples-1)) { |
if (defined($samples->[$line]{$key})) { |
if (defined($samples->[$line]{$key})) { |
$r->print($samples->[$line]{$key}."<br />\n"); |
$r->print($samples->[$line]{$key}."<br />\n"); |
} |
} |
} |
} |
$r->print('</td></tr>'); |
$r->print('</td>'.&end_data_table_row()); |
$i++; |
$i++; |
} |
} |
|
$r->print(&end_data_table()); |
$i--; |
$i--; |
return($i); |
return($i); |
} |
} |
Line 5993 sub csv_samples_select_table {
|
Line 14918 sub csv_samples_select_table {
|
|
|
=pod |
=pod |
|
|
=item clean_excel_name($name) |
=item * &clean_excel_name($name) |
|
|
Returns a replacement for $name which does not contain any illegal characters. |
Returns a replacement for $name which does not contain any illegal characters. |
|
|
Line 6012 sub clean_excel_name {
|
Line 14937 sub clean_excel_name {
|
|
|
=pod |
=pod |
|
|
=item * check_if_partid_hidden($id,$symb,$udom,$uname) |
=item * &check_if_partid_hidden($id,$symb,$udom,$uname) |
|
|
Returns either 1 or undef |
Returns either 1 or undef |
|
|
Line 6053 sub check_if_partid_hidden {
|
Line 14978 sub check_if_partid_hidden {
|
|
|
=over 4 |
=over 4 |
|
|
=item get_cgi_id |
=item * &get_cgi_id() |
|
|
Inputs: none |
Inputs: none |
|
|
Line 6077 sub get_cgi_id {
|
Line 15002 sub get_cgi_id {
|
|
|
=pod |
=pod |
|
|
=item DrawBarGraph |
=item * &DrawBarGraph() |
|
|
Facilitates the plotting of data in a (stacked) bar graph. |
Facilitates the plotting of data in a (stacked) bar graph. |
Puts plot definition data into the users environment in order for |
Puts plot definition data into the users environment in order for |
Line 6144 sub DrawBarGraph {
|
Line 15069 sub DrawBarGraph {
|
@Labels = @$labels; |
@Labels = @$labels; |
} else { |
} else { |
for (my $i=0;$i<@{$Values[0]};$i++) { |
for (my $i=0;$i<@{$Values[0]};$i++) { |
push (@Labels,$i+1); |
push(@Labels,$i+1); |
} |
} |
} |
} |
# |
# |
Line 6212 sub DrawBarGraph {
|
Line 15137 sub DrawBarGraph {
|
$ValuesHash{$id.'.'.$key} = $value; |
$ValuesHash{$id.'.'.$key} = $value; |
} |
} |
# |
# |
&Apache::lonnet::appenv(%ValuesHash); |
&Apache::lonnet::appenv(\%ValuesHash); |
return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; |
return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; |
} |
} |
|
|
Line 6221 sub DrawBarGraph {
|
Line 15146 sub DrawBarGraph {
|
|
|
=pod |
=pod |
|
|
=item DrawXYGraph |
=item * &DrawXYGraph() |
|
|
Facilitates the plotting of data in an XY graph. |
Facilitates the plotting of data in an XY graph. |
Puts plot definition data into the users environment in order for |
Puts plot definition data into the users environment in order for |
Line 6302 sub DrawXYGraph {
|
Line 15227 sub DrawXYGraph {
|
$ValuesHash{$id.'.'.$key} = $value; |
$ValuesHash{$id.'.'.$key} = $value; |
} |
} |
# |
# |
&Apache::lonnet::appenv(%ValuesHash); |
&Apache::lonnet::appenv(\%ValuesHash); |
return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; |
return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; |
} |
} |
|
|
Line 6311 sub DrawXYGraph {
|
Line 15236 sub DrawXYGraph {
|
|
|
=pod |
=pod |
|
|
=item DrawXYYGraph |
=item * &DrawXYYGraph() |
|
|
Facilitates the plotting of data in an XY graph with two Y axes. |
Facilitates the plotting of data in an XY graph with two Y axes. |
Puts plot definition data into the users environment in order for |
Puts plot definition data into the users environment in order for |
Line 6404 sub DrawXYYGraph {
|
Line 15329 sub DrawXYYGraph {
|
$ValuesHash{$id.'.'.$key} = $value; |
$ValuesHash{$id.'.'.$key} = $value; |
} |
} |
# |
# |
&Apache::lonnet::appenv(%ValuesHash); |
&Apache::lonnet::appenv(\%ValuesHash); |
return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; |
return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />'; |
} |
} |
|
|
Line 6421 Bad place for them but what the hell.
|
Line 15346 Bad place for them but what the hell.
|
|
|
=over 4 |
=over 4 |
|
|
=item &chartlink |
=item * &chartlink() |
|
|
Returns a link to the chart for a specific student. |
Returns a link to the chart for a specific student. |
|
|
Line 6460 sub chartlink {
|
Line 15385 sub chartlink {
|
|
|
=over 4 |
=over 4 |
|
|
=item &restore_course_settings |
=item * &restore_course_settings() |
|
|
=item &store_course_settings |
=item * &store_course_settings() |
|
|
Restores/Store indicated form parameters from the course environment. |
Restores/Store indicated form parameters from the course environment. |
Will not overwrite existing values of the form parameters. |
Will not overwrite existing values of the form parameters. |
Line 6482 a hash ref describing the data to be sto
|
Line 15407 a hash ref describing the data to be sto
|
|
|
Returns: both routines return nothing |
Returns: both routines return nothing |
|
|
|
=back |
|
|
=cut |
=cut |
|
|
####################################################### |
####################################################### |
Line 6534 sub store_settings {
|
Line 15461 sub store_settings {
|
'got error:'.$put_result); |
'got error:'.$put_result); |
} |
} |
# Make sure these settings stick around in this session, too |
# Make sure these settings stick around in this session, too |
&Apache::lonnet::appenv(%AppHash); |
&Apache::lonnet::appenv(\%AppHash); |
return; |
return; |
} |
} |
|
|
Line 6562 sub restore_settings {
|
Line 15489 sub restore_settings {
|
} |
} |
} |
} |
|
|
|
####################################################### |
|
####################################################### |
|
|
|
=pod |
|
|
|
=head1 Domain E-mail Routines |
|
|
|
=over 4 |
|
|
|
=item * &build_recipient_list() |
|
|
|
Build recipient lists for following types of e-mail: |
|
(a) Error Reports, (b) Package Updates, (c) lonstatus warnings/errors |
|
(d) Help requests, (e) Course requests needing approval, (f) loncapa |
|
module change checking, student/employee ID conflict checks, as |
|
generated by lonerrorhandler.pm, CHECKRPMS, loncron, |
|
lonsupportreq.pm, loncoursequeueadmin.pm, searchcat.pl respectively. |
|
|
|
Inputs: |
|
defmail (scalar - email address of default recipient), |
|
mailing type (scalar: errormail, packagesmail, helpdeskmail, |
|
requestsmail, updatesmail, or idconflictsmail). |
|
|
|
defdom (domain for which to retrieve configuration settings), |
|
|
|
origmail (scalar - email address of recipient from loncapa.conf, |
|
i.e., predates configuration by DC via domainprefs.pm |
|
|
|
$requname username of requester (if mailing type is helpdeskmail) |
|
|
|
$requdom domain of requester (if mailing type is helpdeskmail) |
|
|
|
$reqemail e-mail address of requester (if mailing type is helpdeskmail) |
|
|
|
Returns: comma separated list of addresses to which to send e-mail. |
|
|
|
=back |
|
|
|
=cut |
|
|
|
############################################################ |
|
############################################################ |
|
sub build_recipient_list { |
|
my ($defmail,$mailing,$defdom,$origmail,$requname,$requdom,$reqemail) = @_; |
|
my @recipients; |
|
my ($otheremails,$lastresort,$allbcc,$addtext); |
|
my %domconfig = |
|
&Apache::lonnet::get_dom('configuration',['contacts'],$defdom); |
|
if (ref($domconfig{'contacts'}) eq 'HASH') { |
|
if (exists($domconfig{'contacts'}{$mailing})) { |
|
if (ref($domconfig{'contacts'}{$mailing}) eq 'HASH') { |
|
my @contacts = ('adminemail','supportemail'); |
|
foreach my $item (@contacts) { |
|
if ($domconfig{'contacts'}{$mailing}{$item}) { |
|
my $addr = $domconfig{'contacts'}{$item}; |
|
if (!grep(/^\Q$addr\E$/,@recipients)) { |
|
push(@recipients,$addr); |
|
} |
|
} |
|
} |
|
$otheremails = $domconfig{'contacts'}{$mailing}{'others'}; |
|
if ($mailing eq 'helpdeskmail') { |
|
if ($domconfig{'contacts'}{$mailing}{'bcc'}) { |
|
my @bccs = split(/,/,$domconfig{'contacts'}{$mailing}{'bcc'}); |
|
my @ok_bccs; |
|
foreach my $bcc (@bccs) { |
|
$bcc =~ s/^\s+//g; |
|
$bcc =~ s/\s+$//g; |
|
if ($bcc =~ m/^[^\@]+\@[^\@]+$/) { |
|
if (!(grep(/^\Q$bcc\E$/,@ok_bccs))) { |
|
push(@ok_bccs,$bcc); |
|
} |
|
} |
|
} |
|
if (@ok_bccs > 0) { |
|
$allbcc = join(', ',@ok_bccs); |
|
} |
|
} |
|
$addtext = $domconfig{'contacts'}{$mailing}{'include'}; |
|
} |
|
} |
|
} elsif ($origmail ne '') { |
|
$lastresort = $origmail; |
|
} |
|
if ($mailing eq 'helpdeskmail') { |
|
if ((ref($domconfig{'contacts'}{'overrides'}) eq 'HASH') && |
|
(keys(%{$domconfig{'contacts'}{'overrides'}}))) { |
|
my ($inststatus,$inststatus_checked); |
|
if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '') && |
|
($env{'user.domain'} ne 'public')) { |
|
$inststatus_checked = 1; |
|
$inststatus = $env{'environment.inststatus'}; |
|
} |
|
unless ($inststatus_checked) { |
|
if (($requname ne '') && ($requdom ne '')) { |
|
if (($requname =~ /^$match_username$/) && |
|
($requdom =~ /^$match_domain$/) && |
|
(&Apache::lonnet::domain($requdom))) { |
|
my $requhome = &Apache::lonnet::homeserver($requname, |
|
$requdom); |
|
unless ($requhome eq 'no_host') { |
|
my %userenv = &Apache::lonnet::userenvironment($requdom,$requname,'inststatus'); |
|
$inststatus = $userenv{'inststatus'}; |
|
$inststatus_checked = 1; |
|
} |
|
} |
|
} |
|
} |
|
unless ($inststatus_checked) { |
|
if ($reqemail =~ /^[^\@]+\@[^\@]+$/) { |
|
my %srch = (srchby => 'email', |
|
srchdomain => $defdom, |
|
srchterm => $reqemail, |
|
srchtype => 'exact'); |
|
my %srch_results = &Apache::lonnet::usersearch(\%srch); |
|
foreach my $uname (keys(%srch_results)) { |
|
if (ref($srch_results{$uname}{'inststatus'}) eq 'ARRAY') { |
|
$inststatus = join(',',@{$srch_results{$uname}{'inststatus'}}); |
|
$inststatus_checked = 1; |
|
last; |
|
} |
|
} |
|
unless ($inststatus_checked) { |
|
my ($dirsrchres,%srch_results) = &Apache::lonnet::inst_directory_query(\%srch); |
|
if ($dirsrchres eq 'ok') { |
|
foreach my $uname (keys(%srch_results)) { |
|
if (ref($srch_results{$uname}{'inststatus'}) eq 'ARRAY') { |
|
$inststatus = join(',',@{$srch_results{$uname}{'inststatus'}}); |
|
$inststatus_checked = 1; |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ($inststatus ne '') { |
|
foreach my $status (split(/\:/,$inststatus)) { |
|
if (ref($domconfig{'contacts'}{'overrides'}{$status}) eq 'HASH') { |
|
my @contacts = ('adminemail','supportemail'); |
|
foreach my $item (@contacts) { |
|
if ($domconfig{'contacts'}{'overrides'}{$status}{$item}) { |
|
my $addr = $domconfig{'contacts'}{'overrides'}{$status}; |
|
if (!grep(/^\Q$addr\E$/,@recipients)) { |
|
push(@recipients,$addr); |
|
} |
|
} |
|
} |
|
$otheremails = $domconfig{'contacts'}{'overrides'}{$status}{'others'}; |
|
if ($domconfig{'contacts'}{'overrides'}{$status}{'bcc'}) { |
|
my @bccs = split(/,/,$domconfig{'contacts'}{'overrides'}{$status}{'bcc'}); |
|
my @ok_bccs; |
|
foreach my $bcc (@bccs) { |
|
$bcc =~ s/^\s+//g; |
|
$bcc =~ s/\s+$//g; |
|
if ($bcc =~ m/^[^\@]+\@[^\@]+$/) { |
|
if (!(grep(/^\Q$bcc\E$/,@ok_bccs))) { |
|
push(@ok_bccs,$bcc); |
|
} |
|
} |
|
} |
|
if (@ok_bccs > 0) { |
|
$allbcc = join(', ',@ok_bccs); |
|
} |
|
} |
|
$addtext = $domconfig{'contacts'}{'overrides'}{$status}{'include'}; |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} elsif ($origmail ne '') { |
|
$lastresort = $origmail; |
|
} |
|
if (($mailing eq 'helpdeskmail') && ($lastresort ne '')) { |
|
unless (grep(/^\Q$defdom\E$/,&Apache::lonnet::current_machine_domains())) { |
|
my $lonhost = $Apache::lonnet::perlvar{'lonHostID'}; |
|
my $machinedom = $Apache::lonnet::perlvar{'lonDefDomain'}; |
|
my %what = ( |
|
perlvar => 1, |
|
); |
|
my $primary = &Apache::lonnet::domain($defdom,'primary'); |
|
if ($primary) { |
|
my $gotaddr; |
|
my ($result,$returnhash) = |
|
&Apache::lonnet::get_remote_globals($primary,{ perlvar => 1 }); |
|
if (($result eq 'ok') && (ref($returnhash) eq 'HASH')) { |
|
if ($returnhash->{'lonSupportEMail'} =~ /^[^\@]+\@[^\@]+$/) { |
|
$lastresort = $returnhash->{'lonSupportEMail'}; |
|
$gotaddr = 1; |
|
} |
|
} |
|
unless ($gotaddr) { |
|
my $uintdom = &Apache::lonnet::internet_dom($primary); |
|
my $intdom = &Apache::lonnet::internet_dom($lonhost); |
|
unless ($uintdom eq $intdom) { |
|
my %domconfig = |
|
&Apache::lonnet::get_dom('configuration',['contacts'],$machinedom); |
|
if (ref($domconfig{'contacts'}) eq 'HASH') { |
|
if (ref($domconfig{'contacts'}{'otherdomsmail'}) eq 'HASH') { |
|
my @contacts = ('adminemail','supportemail'); |
|
foreach my $item (@contacts) { |
|
if ($domconfig{'contacts'}{'otherdomsmail'}{$item}) { |
|
my $addr = $domconfig{'contacts'}{$item}; |
|
if (!grep(/^\Q$addr\E$/,@recipients)) { |
|
push(@recipients,$addr); |
|
} |
|
} |
|
} |
|
if ($domconfig{'contacts'}{'otherdomsmail'}{'others'}) { |
|
$otheremails = $domconfig{'contacts'}{'otherdomsmail'}{'others'}; |
|
} |
|
if ($domconfig{'contacts'}{'otherdomsmail'}{'bcc'}) { |
|
my @bccs = split(/,/,$domconfig{'contacts'}{'otherdomsmail'}{'bcc'}); |
|
my @ok_bccs; |
|
foreach my $bcc (@bccs) { |
|
$bcc =~ s/^\s+//g; |
|
$bcc =~ s/\s+$//g; |
|
if ($bcc =~ m/^[^\@]+\@[^\@]+$/) { |
|
if (!(grep(/^\Q$bcc\E$/,@ok_bccs))) { |
|
push(@ok_bccs,$bcc); |
|
} |
|
} |
|
} |
|
if (@ok_bccs > 0) { |
|
$allbcc = join(', ',@ok_bccs); |
|
} |
|
} |
|
$addtext = $domconfig{'contacts'}{'otherdomsmail'}{'include'}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if (defined($defmail)) { |
|
if ($defmail ne '') { |
|
push(@recipients,$defmail); |
|
} |
|
} |
|
if ($otheremails) { |
|
my @others; |
|
if ($otheremails =~ /,/) { |
|
@others = split(/,/,$otheremails); |
|
} else { |
|
push(@others,$otheremails); |
|
} |
|
foreach my $addr (@others) { |
|
if (!grep(/^\Q$addr\E$/,@recipients)) { |
|
push(@recipients,$addr); |
|
} |
|
} |
|
} |
|
if ($mailing eq 'helpdeskmail') { |
|
if ((!@recipients) && ($lastresort ne '')) { |
|
push(@recipients,$lastresort); |
|
} |
|
} elsif ($lastresort ne '') { |
|
if (!grep(/^\Q$lastresort\E$/,@recipients)) { |
|
push(@recipients,$lastresort); |
|
} |
|
} |
|
my $recipientlist = join(',',@recipients); |
|
if (wantarray) { |
|
return ($recipientlist,$allbcc,$addtext); |
|
} else { |
|
return $recipientlist; |
|
} |
|
} |
|
|
############################################################ |
############################################################ |
############################################################ |
############################################################ |
|
|
|
=pod |
|
|
|
=head1 Course Catalog Routines |
|
|
|
=over 4 |
|
|
|
=item * &gather_categories() |
|
|
|
Converts category definitions - keys of categories hash stored in |
|
coursecategories in configuration.db on the primary library server in a |
|
domain - to an array. Also generates javascript and idx hash used to |
|
generate Domain Coordinator interface for editing Course Categories. |
|
|
|
Inputs: |
|
|
|
categories (reference to hash of category definitions). |
|
|
|
cats (reference to array of arrays/hashes which encapsulates hierarchy of |
|
categories and subcategories). |
|
|
|
idx (reference to hash of counters used in Domain Coordinator interface for |
|
editing Course Categories). |
|
|
|
jsarray (reference to array of categories used to create Javascript arrays for |
|
Domain Coordinator interface for editing Course Categories). |
|
|
|
Returns: nothing |
|
|
|
Side effects: populates cats, idx and jsarray. |
|
|
|
=cut |
|
|
|
sub gather_categories { |
|
my ($categories,$cats,$idx,$jsarray) = @_; |
|
my %counters; |
|
my $num = 0; |
|
foreach my $item (keys(%{$categories})) { |
|
my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item); |
|
if ($container eq '' && $depth == 0) { |
|
$cats->[$depth][$categories->{$item}] = $cat; |
|
} else { |
|
$cats->[$depth]{$container}[$categories->{$item}] = $cat; |
|
} |
|
my ($escitem,$tail) = split(/:/,$item,2); |
|
if ($counters{$tail} eq '') { |
|
$counters{$tail} = $num; |
|
$num ++; |
|
} |
|
if (ref($idx) eq 'HASH') { |
|
$idx->{$item} = $counters{$tail}; |
|
} |
|
if (ref($jsarray) eq 'ARRAY') { |
|
push(@{$jsarray->[$counters{$tail}]},$item); |
|
} |
|
} |
|
return; |
|
} |
|
|
|
=pod |
|
|
|
=item * &extract_categories() |
|
|
|
Used to generate breadcrumb trails for course categories. |
|
|
|
Inputs: |
|
|
|
categories (reference to hash of category definitions). |
|
|
|
cats (reference to array of arrays/hashes which encapsulates hierarchy of |
|
categories and subcategories). |
|
|
|
trails (reference to array of breacrumb trails for each category). |
|
|
|
allitems (reference to hash - key is category key |
|
(format: escaped(name):escaped(parent category):depth in hierarchy). |
|
|
|
idx (reference to hash of counters used in Domain Coordinator interface for |
|
editing Course Categories). |
|
|
|
jsarray (reference to array of categories used to create Javascript arrays for |
|
Domain Coordinator interface for editing Course Categories). |
|
|
|
subcats (reference to hash of arrays containing all subcategories within each |
|
category, -recursive) |
|
|
|
maxd (reference to hash used to hold max depth for all top-level categories). |
|
|
|
Returns: nothing |
|
|
|
Side effects: populates trails and allitems hash references. |
|
|
|
=cut |
|
|
|
sub extract_categories { |
|
my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats,$maxd) = @_; |
|
if (ref($categories) eq 'HASH') { |
|
&gather_categories($categories,$cats,$idx,$jsarray); |
|
if (ref($cats->[0]) eq 'ARRAY') { |
|
for (my $i=0; $i<@{$cats->[0]}; $i++) { |
|
my $name = $cats->[0][$i]; |
|
my $item = &escape($name).'::0'; |
|
my $trailstr; |
|
if ($name eq 'instcode') { |
|
$trailstr = &mt('Official courses (with institutional codes)'); |
|
} elsif ($name eq 'communities') { |
|
$trailstr = &mt('Communities'); |
|
} else { |
|
$trailstr = $name; |
|
} |
|
if ($allitems->{$item} eq '') { |
|
push(@{$trails},$trailstr); |
|
$allitems->{$item} = scalar(@{$trails})-1; |
|
} |
|
my @parents = ($name); |
|
if (ref($cats->[1]{$name}) eq 'ARRAY') { |
|
for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) { |
|
my $category = $cats->[1]{$name}[$j]; |
|
if (ref($subcats) eq 'HASH') { |
|
push(@{$subcats->{$item}},&escape($category).':'.&escape($name).':1'); |
|
} |
|
&recurse_categories($cats,2,$category,$trails,$allitems,\@parents,$subcats,$maxd); |
|
} |
|
} else { |
|
if (ref($subcats) eq 'HASH') { |
|
$subcats->{$item} = []; |
|
} |
|
if (ref($maxd) eq 'HASH') { |
|
$maxd->{$name} = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
=pod |
|
|
|
=item * &recurse_categories() |
|
|
|
Recursively used to generate breadcrumb trails for course categories. |
|
|
|
Inputs: |
|
|
|
cats (reference to array of arrays/hashes which encapsulates hierarchy of |
|
categories and subcategories). |
|
|
|
depth (current depth in hierarchy of categories and sub-categories - 0 indexed). |
|
|
|
category (current course category, for which breadcrumb trail is being generated). |
|
|
|
trails (reference to array of breadcrumb trails for each category). |
|
|
|
allitems (reference to hash - key is category key |
|
(format: escaped(name):escaped(parent category):depth in hierarchy). |
|
|
|
parents (array containing containers directories for current category, |
|
back to top level). |
|
|
|
Returns: nothing |
|
|
|
Side effects: populates trails and allitems hash references |
|
|
|
=cut |
|
|
|
sub recurse_categories { |
|
my ($cats,$depth,$category,$trails,$allitems,$parents,$subcats,$maxd) = @_; |
|
my $shallower = $depth - 1; |
|
if (ref($cats->[$depth]{$category}) eq 'ARRAY') { |
|
for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) { |
|
my $name = $cats->[$depth]{$category}[$k]; |
|
my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower; |
|
my $trailstr = join(' » ',(@{$parents},$category)); |
|
if ($allitems->{$item} eq '') { |
|
push(@{$trails},$trailstr); |
|
$allitems->{$item} = scalar(@{$trails})-1; |
|
} |
|
my $deeper = $depth+1; |
|
push(@{$parents},$category); |
|
if (ref($subcats) eq 'HASH') { |
|
my $subcat = &escape($name).':'.$category.':'.$depth; |
|
for (my $j=@{$parents}; $j>=0; $j--) { |
|
my $higher; |
|
if ($j > 0) { |
|
$higher = &escape($parents->[$j]).':'. |
|
&escape($parents->[$j-1]).':'.$j; |
|
} else { |
|
$higher = &escape($parents->[$j]).'::'.$j; |
|
} |
|
push(@{$subcats->{$higher}},$subcat); |
|
} |
|
} |
|
&recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents, |
|
$subcats,$maxd); |
|
pop(@{$parents}); |
|
} |
|
} else { |
|
my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower; |
|
my $trailstr = join(' » ',(@{$parents},$category)); |
|
if ($allitems->{$item} eq '') { |
|
push(@{$trails},$trailstr); |
|
$allitems->{$item} = scalar(@{$trails})-1; |
|
} |
|
if (ref($maxd) eq 'HASH') { |
|
if ($depth > $maxd->{$parents->[0]}) { |
|
$maxd->{$parents->[0]} = $depth; |
|
} |
|
} |
|
} |
|
return; |
|
} |
|
|
|
=pod |
|
|
|
=item * &assign_categories_table() |
|
|
|
Create a datatable for display of hierarchical categories in a domain, |
|
with checkboxes to allow a course to be categorized. |
|
|
|
Inputs: |
|
|
|
cathash - reference to hash of categories defined for the domain (from |
|
configuration.db) |
|
|
|
currcat - scalar with an & separated list of categories assigned to a course. |
|
|
|
type - scalar contains course type (Course or Community). |
|
|
|
disabled - scalar (optional) contains disabled="disabled" if input elements are |
|
to be readonly (e.g., Domain Helpdesk role viewing course settings). |
|
|
|
Returns: $output (markup to be displayed) |
|
|
|
=cut |
|
|
|
sub assign_categories_table { |
|
my ($cathash,$currcat,$type,$disabled) = @_; |
|
my $output; |
|
if (ref($cathash) eq 'HASH') { |
|
my (@cats,@trails,%allitems,%idx,@jsarray,%maxd,@path,$maxdepth); |
|
&extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray,\%maxd); |
|
$maxdepth = scalar(@cats); |
|
if (@cats > 0) { |
|
my $itemcount = 0; |
|
if (ref($cats[0]) eq 'ARRAY') { |
|
my @currcategories; |
|
if ($currcat ne '') { |
|
@currcategories = split('&',$currcat); |
|
} |
|
my $table; |
|
for (my $i=0; $i<@{$cats[0]}; $i++) { |
|
my $parent = $cats[0][$i]; |
|
next if ($parent eq 'instcode'); |
|
if ($type eq 'Community') { |
|
next unless ($parent eq 'communities'); |
|
} else { |
|
next if ($parent eq 'communities'); |
|
} |
|
my $css_class = $itemcount%2?' class="LC_odd_row"':''; |
|
my $item = &escape($parent).'::0'; |
|
my $checked = ''; |
|
if (@currcategories > 0) { |
|
if (grep(/^\Q$item\E$/,@currcategories)) { |
|
$checked = ' checked="checked"'; |
|
} |
|
} |
|
my $parent_title = $parent; |
|
if ($parent eq 'communities') { |
|
$parent_title = &mt('Communities'); |
|
} |
|
$table .= '<tr '.$css_class.'><td><span class="LC_nobreak">'. |
|
'<input type="checkbox" name="usecategory" value="'. |
|
$item.'"'.$checked.$disabled.' />'.$parent_title.'</span>'. |
|
'<input type="hidden" name="catname" value="'.$parent.'" /></td>'; |
|
my $depth = 1; |
|
push(@path,$parent); |
|
$table .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories,$disabled); |
|
pop(@path); |
|
$table .= '</tr><tr><td colspan="'.$maxdepth.'" class="LC_row_separator"></td></tr>'; |
|
$itemcount ++; |
|
} |
|
if ($itemcount) { |
|
$output = &Apache::loncommon::start_data_table(). |
|
$table. |
|
&Apache::loncommon::end_data_table(); |
|
} |
|
} |
|
} |
|
} |
|
return $output; |
|
} |
|
|
|
=pod |
|
|
|
=item * &assign_category_rows() |
|
|
|
Create a datatable row for display of nested categories in a domain, |
|
with checkboxes to allow a course to be categorized,called recursively. |
|
|
|
Inputs: |
|
|
|
itemcount - track row number for alternating colors |
|
|
|
cats - reference to array of arrays/hashes which encapsulates hierarchy of |
|
categories and subcategories. |
|
|
|
depth - current depth in hierarchy of categories and sub-categories - 0 indexed. |
|
|
|
parent - parent of current category item |
|
|
|
path - Array containing all categories back up through the hierarchy from the |
|
current category to the top level. |
|
|
|
currcategories - reference to array of current categories assigned to the course |
|
|
|
disabled - scalar (optional) contains disabled="disabled" if input elements are |
|
to be readonly (e.g., Domain Helpdesk role viewing course settings). |
|
|
|
Returns: $output (markup to be displayed). |
|
|
|
=cut |
|
|
|
sub assign_category_rows { |
|
my ($itemcount,$cats,$depth,$parent,$path,$currcategories,$disabled) = @_; |
|
my ($text,$name,$item,$chgstr); |
|
if (ref($cats) eq 'ARRAY') { |
|
my $maxdepth = scalar(@{$cats}); |
|
if (ref($cats->[$depth]) eq 'HASH') { |
|
if (ref($cats->[$depth]{$parent}) eq 'ARRAY') { |
|
my $numchildren = @{$cats->[$depth]{$parent}}; |
|
my $css_class = $itemcount%2?' class="LC_odd_row"':''; |
|
$text .= '<td><table class="LC_data_table">'; |
|
for (my $j=0; $j<$numchildren; $j++) { |
|
$name = $cats->[$depth]{$parent}[$j]; |
|
$item = &escape($name).':'.&escape($parent).':'.$depth; |
|
my $deeper = $depth+1; |
|
my $checked = ''; |
|
if (ref($currcategories) eq 'ARRAY') { |
|
if (@{$currcategories} > 0) { |
|
if (grep(/^\Q$item\E$/,@{$currcategories})) { |
|
$checked = ' checked="checked"'; |
|
} |
|
} |
|
} |
|
$text .= '<tr><td><span class="LC_nobreak"><label>'. |
|
'<input type="checkbox" name="usecategory" value="'. |
|
$item.'"'.$checked.$disabled.' />'.$name.'</label></span>'. |
|
'<input type="hidden" name="catname" value="'.$name.'" />'. |
|
'</td><td>'; |
|
if (ref($path) eq 'ARRAY') { |
|
push(@{$path},$name); |
|
$text .= &assign_category_rows($itemcount,$cats,$deeper,$name,$path,$currcategories,$disabled); |
|
pop(@{$path}); |
|
} |
|
$text .= '</td></tr>'; |
|
} |
|
$text .= '</table></td>'; |
|
} |
|
} |
|
} |
|
return $text; |
|
} |
|
|
|
=pod |
|
|
|
=back |
|
|
|
=cut |
|
|
|
############################################################ |
|
############################################################ |
|
|
|
|
sub commit_customrole { |
sub commit_customrole { |
my ($udom,$uname,$url,$three,$four,$five,$start,$end) = @_; |
my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_; |
my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.'@'.$three.' in '.$url. |
my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url. |
($start?', '.&mt('starting').' '.localtime($start):''). |
($start?', '.&mt('starting').' '.localtime($start):''). |
($end?', ending '.localtime($end):'').': <b>'. |
($end?', ending '.localtime($end):'').': <b>'. |
&Apache::lonnet::assigncustomrole( |
&Apache::lonnet::assigncustomrole( |
$udom,$uname,$url,$three,$four,$five,$end,$start). |
$udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context). |
'</b><br />'; |
'</b><br />'; |
return $output; |
return $output; |
} |
} |
|
|
sub commit_standardrole { |
sub commit_standardrole { |
my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_; |
my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits) = @_; |
my ($output,$logmsg,$linefeed); |
my ($output,$logmsg,$linefeed); |
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$linefeed = "\n"; |
$linefeed = "\n"; |
Line 6586 sub commit_standardrole {
|
Line 16158 sub commit_standardrole {
|
} |
} |
if ($three eq 'st') { |
if ($three eq 'st') { |
my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end, |
my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end, |
$one,$two,$sec,$context); |
$one,$two,$sec,$context,$credits); |
if (($result =~ /^error/) || ($result eq 'not_in_class') || |
if (($result =~ /^error/) || ($result eq 'not_in_class') || |
($result eq 'unknown_course')) { |
($result eq 'unknown_course') || ($result eq 'refused')) { |
$output = "Error: $result\n"; |
$output = $logmsg.' '.&mt('Error: ').$result."\n"; |
} else { |
} else { |
$output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url. |
$output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url. |
($start?', '.&mt('starting').' '.localtime($start):''). |
($start?', '.&mt('starting').' '.localtime($start):''). |
Line 6606 sub commit_standardrole {
|
Line 16178 sub commit_standardrole {
|
$output = &mt('Assigning').' '.$three.' in '.$url. |
$output = &mt('Assigning').' '.$three.' in '.$url. |
($start?', '.&mt('starting').' '.localtime($start):''). |
($start?', '.&mt('starting').' '.localtime($start):''). |
($end?', '.&mt('ending').' '.localtime($end):'').': '; |
($end?', '.&mt('ending').' '.localtime($end):'').': '; |
my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start); |
my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context); |
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$output .= $result.$linefeed; |
$output .= $result.$linefeed; |
} else { |
} else { |
Line 6617 sub commit_standardrole {
|
Line 16189 sub commit_standardrole {
|
} |
} |
|
|
sub commit_studentrole { |
sub commit_studentrole { |
my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_; |
my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context, |
my ($result,$linefeed); |
$credits) = @_; |
|
my ($result,$linefeed,$oldsecurl,$newsecurl); |
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$linefeed = "\n"; |
$linefeed = "\n"; |
} else { |
} else { |
Line 6630 sub commit_studentrole {
|
Line 16203 sub commit_studentrole {
|
my $secchange = 0; |
my $secchange = 0; |
my $expire_role_result; |
my $expire_role_result; |
my $modify_section_result; |
my $modify_section_result; |
unless ($oldsec eq '-1') { |
if ($oldsec ne '-1') { |
unless ($sec eq $oldsec) { |
if ($oldsec ne $sec) { |
$secchange = 1; |
$secchange = 1; |
|
my $now = time; |
my $uurl='/'.$cid; |
my $uurl='/'.$cid; |
$uurl=~s/\_/\//g; |
$uurl=~s/\_/\//g; |
if ($oldsec) { |
if ($oldsec) { |
$uurl.='/'.$oldsec; |
$uurl.='/'.$oldsec; |
} |
} |
$expire_role_result = &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',time); |
$oldsecurl = $uurl; |
|
$expire_role_result = |
|
&Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','','',$context); |
|
if ($env{'request.course.sec'} ne '') { |
|
if ($expire_role_result eq 'refused') { |
|
my @roles = ('st'); |
|
my @statuses = ('previous'); |
|
my @roledoms = ($one); |
|
my $withsec = 1; |
|
my %roleshash = |
|
&Apache::lonnet::get_my_roles($uname,$udom,'userroles', |
|
\@statuses,\@roles,\@roledoms,$withsec); |
|
if (defined ($roleshash{$two.':'.$one.':st:'.$oldsec})) { |
|
my ($oldstart,$oldend) = |
|
split(':',$roleshash{$two.':'.$one.':st:'.$oldsec}); |
|
if ($oldend > 0 && $oldend <= $now) { |
|
$expire_role_result = 'ok'; |
|
} |
|
} |
|
} |
|
} |
$result = $expire_role_result; |
$result = $expire_role_result; |
} |
} |
} |
} |
if (($expire_role_result eq 'ok') || ($secchange == 0)) { |
if (($expire_role_result eq 'ok') || ($secchange == 0)) { |
$modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid); |
$modify_section_result = |
|
&Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef, |
|
undef,undef,undef,$sec, |
|
$end,$start,'','',$cid, |
|
'',$context,$credits); |
if ($modify_section_result =~ /^ok/) { |
if ($modify_section_result =~ /^ok/) { |
if ($secchange == 1) { |
if ($secchange == 1) { |
$$logmsg .= "Section for $uname switched from old section: $oldsec to new section: $sec".$linefeed; |
if ($sec eq '') { |
|
$$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to student role without a section.',$uname,$oldsec).$linefeed; |
|
} else { |
|
$$logmsg .= &mt('Section for [_1] switched from (possibly expired) old section: [_2] to new section: [_3].',$uname,$oldsec,$sec).$linefeed; |
|
} |
} elsif ($oldsec eq '-1') { |
} elsif ($oldsec eq '-1') { |
$$logmsg .= "New student role for $uname in section $sec in course $cid".$linefeed; |
if ($sec eq '') { |
|
$$logmsg .= &mt('New student role without a section for [_1] in course [_2].',$uname,$cid).$linefeed; |
|
} else { |
|
$$logmsg .= &mt('New student role for [_1] in section [_2] in course [_3].',$uname,$sec,$cid).$linefeed; |
|
} |
} else { |
} else { |
$$logmsg .= "Student $uname assigned to unchanged section $sec in course $cid".$linefeed; |
if ($sec eq '') { |
|
$$logmsg .= &mt('Student [_1] assigned to course [_2] without a section.',$uname,$cid).$linefeed; |
|
} else { |
|
$$logmsg .= &mt('Student [_1] assigned to section [_2] in course [_3].',$uname,$sec,$cid).$linefeed; |
|
} |
} |
} |
} else { |
} else { |
$$logmsg .= "Error when attempting section change for $uname from old section $oldsec to new section: $sec in course $cid -error: $modify_section_result".$linefeed; |
if ($secchange) { |
|
$$logmsg .= &mt('Error when attempting section change for [_1] from old section "[_2]" to new section: "[_3]" in course [_4] -error:',$uname,$oldsec,$sec,$cid).' '.$modify_section_result.$linefeed; |
|
} else { |
|
$$logmsg .= &mt('Error when attempting to modify role for [_1] for section: "[_2]" in course [_3] -error:',$uname,$sec,$cid).' '.$modify_section_result.$linefeed; |
|
} |
} |
} |
$result = $modify_section_result; |
$result = $modify_section_result; |
} elsif ($secchange == 1) { |
} elsif ($secchange == 1) { |
$$logmsg .= "Error when attempting to expire role for $uname in old section $oldsec in course $cid -error: $expire_role_result".$linefeed; |
if ($oldsec eq '') { |
|
$$logmsg .= &mt('Error when attempting to expire existing role without a section for [_1] in course [_2] -error: ',$uname,$cid).' '.$expire_role_result.$linefeed; |
|
} else { |
|
$$logmsg .= &mt('Error when attempting to expire existing role for [_1] in section [_2] in course [_3] -error: ',$uname,$oldsec,$cid).' '.$expire_role_result.$linefeed; |
|
} |
|
if ($expire_role_result eq 'refused') { |
|
my $newsecurl = '/'.$cid; |
|
$newsecurl =~ s/\_/\//g; |
|
if ($sec ne '') { |
|
$newsecurl.='/'.$sec; |
|
} |
|
if (&Apache::lonnet::allowed('cst',$newsecurl) && !(&Apache::lonnet::allowed('cst',$oldsecurl))) { |
|
if ($sec eq '') { |
|
$$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments unaffiliated with any section.',$sec).$linefeed; |
|
} else { |
|
$$logmsg .= &mt('Although your current role has privileges to add students to section "[_1]", you do not have privileges to modify existing enrollments in other sections.',$sec).$linefeed; |
|
} |
|
} |
|
} |
} |
} |
} else { |
} else { |
$$logmsg .= "Incomplete course id defined. Addition of user $uname from domain $udom to course $one\_$two, section $sec not completed.$linefeed"; |
$$logmsg .= &mt('Incomplete course id defined.').$linefeed.&mt('Addition of user [_1] from domain [_2] to course [_3], section [_4] not completed.',$uname,$udom,$one.'_'.$two,$sec).$linefeed; |
$result = "error: incomplete course id\n"; |
$result = "error: incomplete course id\n"; |
} |
} |
return $result; |
return $result; |
} |
} |
|
|
|
sub show_role_extent { |
|
my ($scope,$context,$role) = @_; |
|
$scope =~ s{^/}{}; |
|
my @courseroles = &Apache::lonuserutils::roles_by_context('course',1); |
|
push(@courseroles,'co'); |
|
my @authorroles = &Apache::lonuserutils::roles_by_context('author'); |
|
if (($context eq 'course') || (grep(/^\Q$role\E/,@courseroles))) { |
|
$scope =~ s{/}{_}; |
|
return '<span class="LC_cusr_emph">'.$env{'course.'.$scope.'.description'}.'</span>'; |
|
} elsif (($context eq 'author') || (grep(/^\Q$role\E/,@authorroles))) { |
|
my ($audom,$auname) = split(/\//,$scope); |
|
return &mt('[_1] Author Space','<span class="LC_cusr_emph">'. |
|
&Apache::loncommon::plainname($auname,$audom).'</span>'); |
|
} else { |
|
$scope =~ s{/$}{}; |
|
return &mt('Domain: [_1]','<span class="LC_cusr_emph">'. |
|
&Apache::lonnet::domain($scope,'description').'</span>'); |
|
} |
|
} |
|
|
############################################################ |
############################################################ |
############################################################ |
############################################################ |
|
|
|
sub check_clone { |
|
my ($args,$linefeed) = @_; |
|
my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; |
|
my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); |
|
my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); |
|
my $clonetitle; |
|
my @clonemsg; |
|
my $can_clone = 0; |
|
my $lctype = lc($args->{'crstype'}); |
|
if ($lctype ne 'community') { |
|
$lctype = 'course'; |
|
} |
|
if ($clonehome eq 'no_host') { |
|
if ($args->{'crstype'} eq 'Community') { |
|
push(@clonemsg,({ |
|
mt => 'No new community created.', |
|
args => [], |
|
}, |
|
{ |
|
mt => 'A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.', |
|
args => [$args->{'clonedomain'}.':'.$args->{'clonedomain'}], |
|
})); |
|
} else { |
|
push(@clonemsg,({ |
|
mt => 'No new course created.', |
|
args => [], |
|
}, |
|
{ |
|
mt => 'A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.', |
|
args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}], |
|
})); |
|
} |
|
} else { |
|
my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); |
|
$clonetitle = $clonedesc{'description'}; |
|
if ($args->{'crstype'} eq 'Community') { |
|
if ($clonedesc{'type'} ne 'Community') { |
|
push(@clonemsg,({ |
|
mt => 'No new community created.', |
|
args => [], |
|
}, |
|
{ |
|
mt => 'A new community could not be cloned from the specified original - [_1] - because it is a course not a community.', |
|
args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}], |
|
})); |
|
return ($can_clone,\@clonemsg,$cloneid,$clonehome); |
|
} |
|
} |
|
if (($env{'request.role.domain'} eq $args->{'clonedomain'}) && |
|
(&Apache::lonnet::allowed('ccc',$env{'request.role.domain'}))) { |
|
$can_clone = 1; |
|
} else { |
|
my %clonehash = &Apache::lonnet::get('environment',['cloners','internal.coursecode'], |
|
$args->{'clonedomain'},$args->{'clonecourse'}); |
|
if ($clonehash{'cloners'} eq '') { |
|
my %domdefs = &Apache::lonnet::get_domain_defaults($args->{'course_domain'}); |
|
if ($domdefs{'canclone'}) { |
|
unless ($domdefs{'canclone'} eq 'none') { |
|
if ($domdefs{'canclone'} eq 'domain') { |
|
if ($args->{'ccdomain'} eq $args->{'clonedomain'}) { |
|
$can_clone = 1; |
|
} |
|
} elsif (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && |
|
($args->{'clonedomain'} eq $args->{'course_domain'})) { |
|
if (&Apache::lonnet::default_instcode_cloning($args->{'clonedomain'},$domdefs{'canclone'}, |
|
$clonehash{'internal.coursecode'},$args->{'crscode'})) { |
|
$can_clone = 1; |
|
} |
|
} |
|
} |
|
} |
|
} else { |
|
my @cloners = split(/,/,$clonehash{'cloners'}); |
|
if (grep(/^\*$/,@cloners)) { |
|
$can_clone = 1; |
|
} elsif (grep(/^\*\:\Q$args->{'ccdomain'}\E$/,@cloners)) { |
|
$can_clone = 1; |
|
} elsif (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners)) { |
|
$can_clone = 1; |
|
} |
|
unless ($can_clone) { |
|
if (($clonehash{'internal.coursecode'}) && ($args->{'crscode'}) && |
|
($args->{'clonedomain'} eq $args->{'course_domain'})) { |
|
my (%gotdomdefaults,%gotcodedefaults); |
|
foreach my $cloner (@cloners) { |
|
if (($cloner ne '*') && ($cloner !~ /^\*\:$match_domain$/) && |
|
($cloner !~ /^$match_username\:$match_domain$/) && ($cloner ne '')) { |
|
my (%codedefaults,@code_order); |
|
if (ref($gotcodedefaults{$args->{'clonedomain'}}) eq 'HASH') { |
|
if (ref($gotcodedefaults{$args->{'clonedomain'}}{'defaults'}) eq 'HASH') { |
|
%codedefaults = %{$gotcodedefaults{$args->{'clonedomain'}}{'defaults'}}; |
|
} |
|
if (ref($gotcodedefaults{$args->{'clonedomain'}}{'order'}) eq 'ARRAY') { |
|
@code_order = @{$gotcodedefaults{$args->{'clonedomain'}}{'order'}}; |
|
} |
|
} else { |
|
&Apache::lonnet::auto_instcode_defaults($args->{'clonedomain'}, |
|
\%codedefaults, |
|
\@code_order); |
|
$gotcodedefaults{$args->{'clonedomain'}}{'defaults'} = \%codedefaults; |
|
$gotcodedefaults{$args->{'clonedomain'}}{'order'} = \@code_order; |
|
} |
|
if (@code_order > 0) { |
|
if (&Apache::lonnet::check_instcode_cloning(\%codedefaults,\@code_order, |
|
$cloner,$clonehash{'internal.coursecode'}, |
|
$args->{'crscode'})) { |
|
$can_clone = 1; |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
unless ($can_clone) { |
|
my $ccrole = 'cc'; |
|
if ($args->{'crstype'} eq 'Community') { |
|
$ccrole = 'co'; |
|
} |
|
my %roleshash = |
|
&Apache::lonnet::get_my_roles($args->{'ccuname'}, |
|
$args->{'ccdomain'}, |
|
'userroles',['active'],[$ccrole], |
|
[$args->{'clonedomain'}]); |
|
if ($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) { |
|
$can_clone = 1; |
|
} elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'}, |
|
$args->{'ccuname'},$args->{'ccdomain'})) { |
|
$can_clone = 1; |
|
} |
|
} |
|
unless ($can_clone) { |
|
if ($args->{'crstype'} eq 'Community') { |
|
push(@clonemsg,({ |
|
mt => 'No new community created.', |
|
args => [], |
|
}, |
|
{ |
|
mt => 'The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).', |
|
args => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}], |
|
})); |
|
} else { |
|
push(@clonemsg,({ |
|
mt => 'No new course created.', |
|
args => [], |
|
}, |
|
{ |
|
mt => 'The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).', |
|
args => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}], |
|
})); |
|
} |
|
} |
|
} |
|
} |
|
return ($can_clone,\@clonemsg,$cloneid,$clonehome,$clonetitle); |
|
} |
|
|
sub construct_course { |
sub construct_course { |
my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context) = @_; |
my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context, |
my $outcome; |
$cnum,$category,$coderef,$callercontext,$user_lh) = @_; |
|
my ($outcome,$msgref,$clonemsgref); |
my $linefeed = '<br />'."\n"; |
my $linefeed = '<br />'."\n"; |
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$linefeed = "\n"; |
$linefeed = "\n"; |
} |
} |
|
|
|
# |
|
# Are we cloning? |
|
# |
|
my ($can_clone,$cloneid,$clonehome,$clonetitle); |
|
if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { |
|
($can_clone,$clonemsgref,$cloneid,$clonehome,$clonetitle) = &check_clone($args,$linefeed); |
|
if (!$can_clone) { |
|
return (0,$outcome,$clonemsgref); |
|
} |
|
} |
|
|
# |
# |
# Open course |
# Open course |
# |
# |
Line 6689 sub construct_course {
|
Line 16512 sub construct_course {
|
$args->{'crscode'}, |
$args->{'crscode'}, |
$args->{'ccuname'}.':'. |
$args->{'ccuname'}.':'. |
$args->{'ccdomain'}, |
$args->{'ccdomain'}, |
$args->{'crstype'}); |
$args->{'crstype'}, |
|
$cnum,$context,$category, |
|
$callercontext); |
|
|
# Note: The testing routines depend on this being output; see |
# Note: The testing routines depend on this being output; see |
# Utils::Course. This needs to at least be output as a comment |
# Utils::Course. This needs to at least be output as a comment |
# if anyone ever decides to not show this, and Utils::Course::new |
# if anyone ever decides to not show this, and Utils::Course::new |
# will need to be suitably modified. |
# will need to be suitably modified. |
$outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; |
if (($callercontext eq 'auto') && ($user_lh ne '')) { |
|
$outcome .= &mt_user($user_lh,'New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; |
|
} else { |
|
$outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; |
|
} |
|
if ($$courseid =~ /^error:/) { |
|
return (0,$outcome,$clonemsgref); |
|
} |
|
|
# |
# |
# Check if created correctly |
# Check if created correctly |
# |
# |
($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid); |
($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid); |
my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom); |
my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom); |
|
if ($crsuhome eq 'no_host') { |
|
if (($callercontext eq 'auto') && ($user_lh ne '')) { |
|
$outcome .= &mt_user($user_lh, |
|
'Course creation failed, unrecognized course home server.'); |
|
} else { |
|
$outcome .= &mt('Course creation failed, unrecognized course home server.'); |
|
} |
|
$outcome .= $linefeed; |
|
return (0,$outcome,$clonemsgref); |
|
} |
$outcome .= &mt('Created on').': '.$crsuhome.$linefeed; |
$outcome .= &mt('Created on').': '.$crsuhome.$linefeed; |
|
|
# |
# |
# Are we cloning? |
# Do the cloning |
# |
# |
my $cloneid=''; |
my @clonemsg; |
if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) { |
if ($can_clone && $cloneid) { |
my $can_clone = 0; |
push(@clonemsg, |
$cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'}; |
{ |
my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid); |
mt => 'Created [_1] by cloning from [_2]', |
my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom); |
args => [$crstype,$clonetitle], |
my $clonemsg; |
}); |
if ($clonehome eq 'no_host') { |
my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); |
$clonemsg = &mt('Attempting to clone non-existing [_1]',$crstype); |
|
if ($context eq 'auto') { |
|
$outcome .= $clonemsg; |
|
} else { |
|
$outcome .= '<font color="red">'.$clonemsg.'</font>'; |
|
} |
|
$outcome .= $linefeed; |
|
} else { |
|
my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1}); |
|
if ($env{'request.role.domain'} eq $args->{'form.clonedomain'}) { |
|
$can_clone = 1; |
|
} else { |
|
my %clonehash = &Apache::lonnet::get('environment',['cloners'], |
|
$args->{'clonedomain'},$args->{'clonecourse'}); |
|
my @cloners = split(/,/,$clonehash{'cloners'}); |
|
my %roleshash = |
|
&Apache::lonnet::get_my_roles($args->{'ccuname'}, |
|
$args->{'ccdomain'},'userroles',['active'],['cc'], |
|
[$args->{'clonedomain'}]); |
|
if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { |
|
$can_clone = 1; |
|
} else { |
|
$clonemsg = &mt('The new course was not cloned from an existing course because the course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); |
|
if ($context eq 'auto') { |
|
$outcome .= $clonemsg; |
|
} else { |
|
$outcome .= '<font color="red">'.$clonemsg.'</font>'; |
|
} |
|
$outcome .= $linefeed; |
|
} |
|
} |
|
} |
|
if ($can_clone) { |
|
$clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome); |
|
if ($context eq 'auto') { |
|
$outcome = $clonemsg; |
|
} else { |
|
$outcome .= '<font color="green">'.$clonemsg.'</font>'; |
|
} |
|
$outcome .= $linefeed; |
|
my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum); |
|
# Copy all files |
# Copy all files |
&Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid); |
my @info = |
|
&Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'}, |
|
$args->{'dateshift'},$args->{'crscode'}, |
|
$args->{'ccuname'}.':'.$args->{'ccdomain'}, |
|
$args->{'tinyurls'}); |
|
if (@info) { |
|
push(@clonemsg,@info); |
|
} |
# Restore URL |
# Restore URL |
$cenv{'url'}=$oldcenv{'url'}; |
$cenv{'url'}=$oldcenv{'url'}; |
# Restore title |
# Restore title |
$cenv{'description'}=$oldcenv{'description'}; |
$cenv{'description'}=$oldcenv{'description'}; |
# restore grading mode |
# Restore creation date, creator and creation context. |
if (defined($oldcenv{'grading'})) { |
$cenv{'internal.created'}=$oldcenv{'internal.created'}; |
$cenv{'grading'}=$oldcenv{'grading'}; |
$cenv{'internal.creator'}=$oldcenv{'internal.creator'}; |
} |
$cenv{'internal.creationcontext'}=$oldcenv{'internal.creationcontext'}; |
# Mark as cloned |
# Mark as cloned |
$cenv{'clonedfrom'}=$cloneid; |
$cenv{'clonedfrom'}=$cloneid; |
delete($cenv{'default_enrollment_start_date'}); |
# Need to clone grading mode |
delete($cenv{'default_enrollment_end_date'}); |
my %newenv=&Apache::lonnet::get('environment',['grading'],$$crsudom,$$crsunum); |
} |
$cenv{'grading'}=$newenv{'grading'}; |
|
# Do not clone these environment entries |
|
&Apache::lonnet::del('environment', |
|
['default_enrollment_start_date', |
|
'default_enrollment_end_date', |
|
'question.email', |
|
'policy.email', |
|
'comment.email', |
|
'pch.users.denied', |
|
'plc.users.denied', |
|
'hidefromcat', |
|
'checkforpriv', |
|
'categories'], |
|
$$crsudom,$$crsunum); |
|
if ($args->{'textbook'}) { |
|
$cenv{'internal.textbook'} = $args->{'textbook'}; |
|
} |
} |
} |
|
|
# |
# |
# Set environment (will override cloned, if existing) |
# Set environment (will override cloned, if existing) |
# |
# |
Line 6779 sub construct_course {
|
Line 16605 sub construct_course {
|
if ($args->{'crstype'}) { |
if ($args->{'crstype'}) { |
$cenv{'type'}=$args->{'crstype'}; |
$cenv{'type'}=$args->{'crstype'}; |
} |
} |
|
if ($args->{'lti'}) { |
|
$cenv{'internal.lti'}=$args->{'lti'}; |
|
} |
if ($args->{'crsid'}) { |
if ($args->{'crsid'}) { |
$cenv{'courseid'}=$args->{'crsid'}; |
$cenv{'courseid'}=$args->{'crsid'}; |
} |
} |
Line 6796 sub construct_course {
|
Line 16625 sub construct_course {
|
} else { |
} else { |
$cenv{'internal.courseowner'} = $args->{'curruser'}; |
$cenv{'internal.courseowner'} = $args->{'curruser'}; |
} |
} |
|
if ($args->{'defaultcredits'}) { |
|
$cenv{'internal.defaultcredits'} = $args->{'defaultcredits'}; |
|
} |
my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner. |
my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner. |
|
my @oklcsecs = (); # Used to accumulate LON-CAPA sections for validated institutional sections. |
if ($args->{'crssections'}) { |
if ($args->{'crssections'}) { |
$cenv{'internal.sectionnums'} = ''; |
$cenv{'internal.sectionnums'} = ''; |
if ($args->{'crssections'} =~ m/,/) { |
if ($args->{'crssections'} =~ m/,/) { |
Line 6811 sub construct_course {
|
Line 16643 sub construct_course {
|
my $class = $args->{'crscode'}.$sec; |
my $class = $args->{'crscode'}.$sec; |
my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'}); |
my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'}); |
$cenv{'internal.sectionnums'} .= $item.','; |
$cenv{'internal.sectionnums'} .= $item.','; |
unless ($addcheck eq 'ok') { |
if ($addcheck eq 'ok') { |
push @badclasses, $class; |
unless (grep(/^\Q$gp\E$/,@oklcsecs)) { |
|
push(@oklcsecs,$gp); |
|
} |
|
} else { |
|
push(@badclasses,$class); |
} |
} |
} |
} |
$cenv{'internal.sectionnums'} =~ s/,$//; |
$cenv{'internal.sectionnums'} =~ s/,$//; |
Line 6821 sub construct_course {
|
Line 16657 sub construct_course {
|
# do not hide course coordinator from staff listing, |
# do not hide course coordinator from staff listing, |
# even if privileged |
# even if privileged |
$cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; |
$cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; |
|
# add course coordinator's domain to domains to check for privileged users |
|
# if different to course domain |
|
if ($$crsudom ne $args->{'ccdomain'}) { |
|
$cenv{'checkforpriv'} = $args->{'ccdomain'}; |
|
} |
# add crosslistings |
# add crosslistings |
if ($args->{'crsxlist'}) { |
if ($args->{'crsxlist'}) { |
$cenv{'internal.crosslistings'}=''; |
$cenv{'internal.crosslistings'}=''; |
Line 6834 sub construct_course {
|
Line 16675 sub construct_course {
|
my ($xl,$gp) = split/:/,$item; |
my ($xl,$gp) = split/:/,$item; |
my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'}); |
my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'}); |
$cenv{'internal.crosslistings'} .= $item.','; |
$cenv{'internal.crosslistings'} .= $item.','; |
unless ($addcheck eq 'ok') { |
if ($addcheck eq 'ok') { |
push @badclasses, $xl; |
unless (grep(/^\Q$gp\E$/,@oklcsecs)) { |
|
push(@oklcsecs,$gp); |
|
} |
|
} else { |
|
push(@badclasses,$xl); |
} |
} |
} |
} |
$cenv{'internal.crosslistings'} =~ s/,$//; |
$cenv{'internal.crosslistings'} =~ s/,$//; |
Line 6856 sub construct_course {
|
Line 16701 sub construct_course {
|
} |
} |
if ($args->{'notify_dc'}) { |
if ($args->{'notify_dc'}) { |
if ($uname ne '') { |
if ($uname ne '') { |
push(@notified,$uname.'@'.$udom); |
push(@notified,$uname.':'.$udom); |
} |
} |
} |
} |
if (@notified > 0) { |
if (@notified > 0) { |
Line 6870 sub construct_course {
|
Line 16715 sub construct_course {
|
} |
} |
if (@badclasses > 0) { |
if (@badclasses > 0) { |
my %lt=&Apache::lonlocal::texthash( |
my %lt=&Apache::lonlocal::texthash( |
'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course. However, if automated course roster updates are enabled for this class, these particular sections/crosslistings will not contribute towards enrollment, because the user identified as the course owner for this LON-CAPA course', |
'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course.', |
'dnhr' => 'does not have rights to access enrollment in these classes', |
'howi' => 'However, if automated course roster updates are enabled for this class, these particular sections/crosslistings are not guaranteed to contribute towards enrollment.', |
'adby' => 'as determined by the policies of your institution on access to official classlists' |
'itis' => 'It is possible that rights to access enrollment for these classes will be available through assignment of co-owners.', |
); |
); |
my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}. |
my $badclass_msg = $lt{'tclb'}.$linefeed.$lt{'howi'}.$linefeed. |
' ('.$lt{'adby'}.')'; |
&mt('That is because the user identified as the course owner ([_1]) does not have rights to access enrollment in these classes, as determined by the policies of your institution on access to official classlists',$cenv{'internal.courseowner'}).$linefeed.$lt{'itis'}; |
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$outcome .= $badclass_msg.$linefeed; |
$outcome .= $badclass_msg.$linefeed; |
$outcome .= '<font color="red">'.$badclass_msg.$linefeed.'<ul>'."\n"; |
} else { |
foreach my $item (@badclasses) { |
$outcome .= '<div class="LC_warning">'.$badclass_msg.$linefeed.'<ul>'."\n"; |
if ($context eq 'auto') { |
} |
$outcome .= " - $item\n"; |
foreach my $item (@badclasses) { |
} else { |
|
$outcome .= "<li>$item</li>\n"; |
|
} |
|
} |
|
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$outcome .= $linefeed; |
$outcome .= " - $item\n"; |
} else { |
} else { |
$outcome .= "</ul><br /><br /></font>\n"; |
$outcome .= "<li>$item</li>\n"; |
} |
} |
} |
} |
|
if ($context eq 'auto') { |
|
$outcome .= $linefeed; |
|
} else { |
|
$outcome .= "</ul><br /><br /></div>\n"; |
|
} |
} |
} |
if ($args->{'no_end_date'}) { |
if ($args->{'no_end_date'}) { |
$args->{'endaccess'} = 0; |
$args->{'endaccess'} = 0; |
} |
} |
|
# If an official course with institutional sections is created by cloning |
|
# an existing course, section-specific hiding of course totals in student's |
|
# view of grades as copied from cloned course, will be checked for valid |
|
# sections. |
|
if (($can_clone && $cloneid) && |
|
($cenv{'internal.coursecode'} ne '') && |
|
($cenv{'grading'} eq 'standard') && |
|
($cenv{'hidetotals'} ne '') && |
|
($cenv{'hidetotals'} ne 'all')) { |
|
my @hidesecs; |
|
my $deletehidetotals; |
|
if (@oklcsecs) { |
|
foreach my $sec (split(/,/,$cenv{'hidetotals'})) { |
|
if (grep(/^\Q$sec$/,@oklcsecs)) { |
|
push(@hidesecs,$sec); |
|
} |
|
} |
|
if (@hidesecs) { |
|
$cenv{'hidetotals'} = join(',',@hidesecs); |
|
} else { |
|
$deletehidetotals = 1; |
|
} |
|
} else { |
|
$deletehidetotals = 1; |
|
} |
|
if ($deletehidetotals) { |
|
delete($cenv{'hidetotals'}); |
|
&Apache::lonnet::del('environment',['hidetotals'],$$crsudom,$$crsunum); |
|
} |
|
} |
$cenv{'internal.autostart'}=$args->{'enrollstart'}; |
$cenv{'internal.autostart'}=$args->{'enrollstart'}; |
$cenv{'internal.autoend'}=$args->{'enrollend'}; |
$cenv{'internal.autoend'}=$args->{'enrollend'}; |
$cenv{'default_enrollment_start_date'}=$args->{'startaccess'}; |
$cenv{'default_enrollment_start_date'}=$args->{'startaccess'}; |
Line 6911 sub construct_course {
|
Line 16787 sub construct_course {
|
if ($context eq 'auto') { |
if ($context eq 'auto') { |
$outcome .= $krb_msg; |
$outcome .= $krb_msg; |
} else { |
} else { |
$outcome .= '<font color="red" size="+1">'.$krb_msg.'</font>'; |
$outcome .= '<span class="LC_error">'.$krb_msg.'</span>'; |
} |
} |
$outcome .= $linefeed; |
$outcome .= $linefeed; |
} |
} |
Line 6923 sub construct_course {
|
Line 16799 sub construct_course {
|
if ($args->{'setcontent'}) { |
if ($args->{'setcontent'}) { |
$cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; |
$cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; |
} |
} |
|
if ($args->{'setcomment'}) { |
|
$cenv{'comment.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'}; |
|
} |
} |
} |
if ($args->{'reshome'}) { |
if ($args->{'reshome'}) { |
$cenv{'reshome'}=$args->{'reshome'}.'/'; |
$cenv{'reshome'}=$args->{'reshome'}.'/'; |
Line 6945 sub construct_course {
|
Line 16824 sub construct_course {
|
} |
} |
} |
} |
|
|
|
# |
|
# generate and store uniquecode (available to course requester), if course should have one. |
|
# |
|
if ($args->{'uniquecode'}) { |
|
my ($code,$error) = &make_unique_code($$crsudom,$$crsunum); |
|
if ($code) { |
|
$cenv{'internal.uniquecode'} = $code; |
|
my %crsinfo = |
|
&Apache::lonnet::courseiddump($$crsudom,'.',1,'.','.',$$crsunum,undef,undef,'.'); |
|
if (ref($crsinfo{$$crsudom.'_'.$$crsunum}) eq 'HASH') { |
|
$crsinfo{$$crsudom.'_'.$$crsunum}{'uniquecode'} = $code; |
|
my $putres = &Apache::lonnet::courseidput($$crsudom,\%crsinfo,$crsuhome,'notime'); |
|
} |
|
if (ref($coderef)) { |
|
$$coderef = $code; |
|
} |
|
} |
|
} |
|
|
if ($args->{'disresdis'}) { |
if ($args->{'disresdis'}) { |
$cenv{'pch.roles.denied'}='st'; |
$cenv{'pch.roles.denied'}='st'; |
} |
} |
Line 6975 sub construct_course {
|
Line 16873 sub construct_course {
|
# Open all assignments |
# Open all assignments |
# |
# |
if ($args->{'openall'}) { |
if ($args->{'openall'}) { |
|
my $opendate = time; |
|
if ($args->{'openallfrom'} =~ /^\d+$/) { |
|
$opendate = $args->{'openallfrom'}; |
|
} |
my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate'; |
my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate'; |
my %storecontent = ($storeunder => time, |
my %storecontent = ($storeunder => $opendate, |
$storeunder.'.type' => 'date_start'); |
$storeunder.'.type' => 'date_start'); |
|
$outcome .= &mt('All assignments open starting [_1]', |
$outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput |
&Apache::lonlocal::locallocaltime($opendate)).': '. |
('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed; |
&Apache::lonnet::cput |
|
('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed; |
} |
} |
# |
# |
# Set first page |
# Set first page |
# |
# |
unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank') |
unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank') |
|| ($cloneid)) { |
|| ($cloneid)) { |
use LONCAPA::map; |
|
$outcome .= &mt('Setting first resource').': '; |
$outcome .= &mt('Setting first resource').': '; |
|
|
my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence'; |
my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence'; |
Line 6996 sub construct_course {
|
Line 16898 sub construct_course {
|
$outcome .= ($fatal?$errtext:'read ok').' - '; |
$outcome .= ($fatal?$errtext:'read ok').' - '; |
my $title; my $url; |
my $title; my $url; |
if ($args->{'firstres'} eq 'syl') { |
if ($args->{'firstres'} eq 'syl') { |
$title='Syllabus'; |
$title=&mt('Syllabus'); |
$url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus'; |
$url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus'; |
} else { |
} else { |
$title='Navigate Contents'; |
$title=&mt('Table of Contents'); |
$url='/adm/navmaps'; |
$url='/adm/navmaps'; |
} |
} |
|
|
Line 7009 sub construct_course {
|
Line 16911 sub construct_course {
|
if ($errtext) { $fatal=2; } |
if ($errtext) { $fatal=2; } |
$outcome .= ($fatal?$errtext:'write ok').$linefeed; |
$outcome .= ($fatal?$errtext:'write ok').$linefeed; |
} |
} |
return $outcome; |
|
|
return (1,$outcome,\@clonemsg); |
|
} |
|
|
|
sub make_unique_code { |
|
my ($cdom,$cnum) = @_; |
|
# get lock on uniquecodes db |
|
my $lockhash = { |
|
$cnum."\0".'uniquecodes' => $env{'user.name'}. |
|
':'.$env{'user.domain'}, |
|
}; |
|
my $tries = 0; |
|
my $gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom); |
|
my ($code,$error); |
|
|
|
while (($gotlock ne 'ok') && ($tries<3)) { |
|
$tries ++; |
|
sleep 1; |
|
$gotlock = &Apache::lonnet::newput_dom('uniquecodes',$lockhash,$cdom); |
|
} |
|
if ($gotlock eq 'ok') { |
|
my %currcodes = &Apache::lonnet::dump_dom('uniquecodes',$cdom); |
|
my $gotcode; |
|
my $attempts = 0; |
|
while ((!$gotcode) && ($attempts < 100)) { |
|
$code = &generate_code(); |
|
if (!exists($currcodes{$code})) { |
|
$gotcode = 1; |
|
unless (&Apache::lonnet::newput_dom('uniquecodes',{ $code => $cnum },$cdom) eq 'ok') { |
|
$error = 'nostore'; |
|
} |
|
} |
|
$attempts ++; |
|
} |
|
my @del_lock = ($cnum."\0".'uniquecodes'); |
|
my $dellockoutcome = &Apache::lonnet::del_dom('uniquecodes',\@del_lock,$cdom); |
|
} else { |
|
$error = 'nolock'; |
|
} |
|
return ($code,$error); |
|
} |
|
|
|
sub generate_code { |
|
my $code; |
|
my @letts = qw(B C D G H J K M N P Q R S T V W X Z); |
|
for (my $i=0; $i<6; $i++) { |
|
my $lettnum = int (rand 2); |
|
my $item = ''; |
|
if ($lettnum) { |
|
$item = $letts[int( rand(18) )]; |
|
} else { |
|
$item = 1+int( rand(8) ); |
|
} |
|
$code .= $item; |
|
} |
|
return $code; |
} |
} |
|
|
############################################################ |
############################################################ |
############################################################ |
############################################################ |
|
|
|
#SD |
|
# only Community and Course, or anything else? |
sub course_type { |
sub course_type { |
my ($cid) = @_; |
my ($cid) = @_; |
if (!defined($cid)) { |
if (!defined($cid)) { |
Line 7031 sub group_term {
|
Line 16990 sub group_term {
|
my $crstype = &course_type(); |
my $crstype = &course_type(); |
my %names = ( |
my %names = ( |
'Course' => 'group', |
'Course' => 'group', |
'Group' => 'team', |
'Community' => 'group', |
); |
); |
return $names{$crstype}; |
return $names{$crstype}; |
} |
} |
|
|
|
sub course_types { |
|
my @types = ('official','unofficial','community','textbook','lti'); |
|
my %typename = ( |
|
official => 'Official course', |
|
unofficial => 'Unofficial course', |
|
community => 'Community', |
|
textbook => 'Textbook course', |
|
lti => 'LTI provider', |
|
); |
|
return (\@types,\%typename); |
|
} |
|
|
sub icon { |
sub icon { |
my ($file)=@_; |
my ($file)=@_; |
my $curfext = lc((split(/\./,$file))[-1]); |
my $curfext = lc((split(/\./,$file))[-1]); |
Line 7053 sub icon {
|
Line 17024 sub icon {
|
} |
} |
|
|
sub lonhttpdurl { |
sub lonhttpdurl { |
|
# |
|
# Had been used for "small fry" static images on separate port 8080. |
|
# Modify here if lightweight http functionality desired again. |
|
# Currently eliminated due to increasing firewall issues. |
|
# |
my ($url)=@_; |
my ($url)=@_; |
my $lonhttpd_port=$Apache::lonnet::perlvar{'lonhttpdPort'}; |
return $url; |
if (!defined($lonhttpd_port)) { $lonhttpd_port='8080'; } |
|
return 'http://'.$ENV{'SERVER_NAME'}.':'.$lonhttpd_port.$url; |
|
} |
} |
|
|
sub connection_aborted { |
sub connection_aborted { |
Line 7089 sub escape_url {
|
Line 17063 sub escape_url {
|
my ($url) = @_; |
my ($url) = @_; |
my @urlslices = split(/\//, $url,-1); |
my @urlslices = split(/\//, $url,-1); |
my $lastitem = &escape(pop(@urlslices)); |
my $lastitem = &escape(pop(@urlslices)); |
return join('/',@urlslices).'/'.$lastitem; |
return &HTML::Entities::encode(join('/',@urlslices),"'").'/'.$lastitem; |
|
} |
|
|
|
sub compare_arrays { |
|
my ($arrayref1,$arrayref2) = @_; |
|
my (@difference,%count); |
|
@difference = (); |
|
%count = (); |
|
if ((ref($arrayref1) eq 'ARRAY') && (ref($arrayref2) eq 'ARRAY')) { |
|
foreach my $element (@{$arrayref1}, @{$arrayref2}) { $count{$element}++; } |
|
foreach my $element (keys(%count)) { |
|
if ($count{$element} == 1) { |
|
push(@difference,$element); |
|
} |
|
} |
|
} |
|
return @difference; |
|
} |
|
|
|
sub lon_status_items { |
|
my %defaults = ( |
|
E => 100, |
|
W => 4, |
|
N => 1, |
|
U => 5, |
|
threshold => 200, |
|
sysmail => 2500, |
|
); |
|
my %names = ( |
|
E => 'Errors', |
|
W => 'Warnings', |
|
N => 'Notices', |
|
U => 'Unsent', |
|
); |
|
return (\%defaults,\%names); |
} |
} |
|
|
# -------------------------------------------------------- Initliaze user login |
# -------------------------------------------------------- Initialize user login |
sub init_user_environment { |
sub init_user_environment { |
my ($r, $username, $domain, $authhost, $form, $args) = @_; |
my ($r, $username, $domain, $authhost, $form, $args) = @_; |
my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'}; |
my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'}; |
Line 7101 sub init_user_environment {
|
Line 17109 sub init_user_environment {
|
|
|
# See if old ID present, if so, remove |
# See if old ID present, if so, remove |
|
|
my ($filename,$cookie,$userroles); |
my ($filename,$cookie,$userroles,$firstaccenv,$timerintenv, |
|
$coauthorenv); |
my $now=time; |
my $now=time; |
|
|
if ($public) { |
if ($public) { |
Line 7127 sub init_user_environment {
|
Line 17136 sub init_user_environment {
|
opendir(DIR,$lonids); |
opendir(DIR,$lonids); |
while ($filename=readdir(DIR)) { |
while ($filename=readdir(DIR)) { |
if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) { |
if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) { |
unlink($lonids.'/'.$filename); |
if (tie(my %oldenv,'GDBM_File',"$lonids/$filename", |
|
&GDBM_READER(),0640)) { |
|
my $linkedfile; |
|
if (exists($oldenv{'user.linkedenv'})) { |
|
$linkedfile = $oldenv{'user.linkedenv'}; |
|
} |
|
untie(%oldenv); |
|
if (unlink("$lonids/$filename")) { |
|
if ($linkedfile =~ /^[a-f0-9]+_linked$/) { |
|
if (-l "$lonids/$linkedfile.id") { |
|
unlink("$lonids/$linkedfile.id"); |
|
} |
|
} |
|
} |
|
} else { |
|
unlink($lonids.'/'.$filename); |
|
} |
} |
} |
} |
} |
closedir(DIR); |
closedir(DIR); |
|
# If there is a undeleted lockfile for the user's paste buffer remove it. |
|
my $namespace = 'nohist_courseeditor'; |
|
my $lockingkey = 'paste'."\0".'locked_num'; |
|
my %lockhash = &Apache::lonnet::get($namespace,[$lockingkey], |
|
$domain,$username); |
|
if (exists($lockhash{$lockingkey})) { |
|
my $delresult = &Apache::lonnet::del($namespace,[$lockingkey],$domain,$username); |
|
unless ($delresult eq 'ok') { |
|
&Apache::lonnet::logthis("Failed to delete paste buffer locking key in $namespace for ".$username.":".$domain." Result was: $delresult"); |
|
} |
|
} |
} |
} |
# Give them a new cookie |
# Give them a new cookie |
my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'} |
my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'} |
: $now); |
: $now.$$.int(rand(10000))); |
$cookie="$username\_$id\_$domain\_$authhost"; |
$cookie="$username\_$id\_$domain\_$authhost"; |
|
|
# Initialize roles |
# Initialize roles |
|
|
$userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost); |
($userroles,$firstaccenv,$timerintenv,$coauthorenv) = |
|
&Apache::lonnet::rolesinit($domain,$username,$authhost); |
} |
} |
# ------------------------------------ Check browser type and MathML capability |
# ------------------------------------ Check browser type and MathML capability |
|
|
my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml, |
my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,$clientunicode, |
$clientunicode,$clientos) = &decode_user_agent($r); |
$clientos,$clientmobile,$clientinfo,$clientosversion) = &decode_user_agent($r); |
|
|
# -------------------------------------- Any accessibility options to remember? |
|
if (($form->{'interface'}) && ($form->{'remember'} eq 'true')) { |
|
foreach my $option ('imagesuppress','appletsuppress', |
|
'embedsuppress','fontenhance','blackwhite') { |
|
if ($form->{$option} eq 'true') { |
|
&Apache::lonnet::put('environment',{$option => 'on'}, |
|
$domain,$username); |
|
} else { |
|
&Apache::lonnet::del('environment',[$option], |
|
$domain,$username); |
|
} |
|
} |
|
} |
|
# ------------------------------------------------------------- Get environment |
# ------------------------------------------------------------- Get environment |
|
|
my %userenv = &Apache::lonnet::dump('environment',$domain,$username); |
my %userenv = &Apache::lonnet::dump('environment',$domain,$username); |
my ($tmp) = keys(%userenv); |
my ($tmp) = keys(%userenv); |
if ($tmp !~ /^(con_lost|error|no_such_host)/i) { |
if ($tmp !~ /^(con_lost|error|no_such_host)/i) { |
# default remote control to off |
|
if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; } |
|
} else { |
} else { |
undef(%userenv); |
undef(%userenv); |
} |
} |
if (($userenv{'interface'}) && (!$form->{'interface'})) { |
if (($userenv{'interface'}) && (!$form->{'interface'})) { |
$form->{'interface'}=$userenv{'interface'}; |
$form->{'interface'}=$userenv{'interface'}; |
} |
} |
$env{'environment.remote'}=$userenv{'remote'}; |
|
if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; } |
if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; } |
|
|
# --------------- Do not trust query string to be put directly into environment |
# --------------- Do not trust query string to be put directly into environment |
foreach my $option ('imagesuppress','appletsuppress', |
foreach my $option ('interface','localpath','localres') { |
'embedsuppress','fontenhance','blackwhite', |
$form->{$option}=~s/[\n\r\=]//gs; |
'interface','localpath','localres') { |
|
$form->{$option}=~s/[\n\r\=]//gs; |
|
} |
} |
# --------------------------------------------------------- Write first profile |
# --------------------------------------------------------- Write first profile |
|
|
{ |
{ |
|
my $ip = &Apache::lonnet::get_requestor_ip(); |
my %initial_env = |
my %initial_env = |
("user.name" => $username, |
("user.name" => $username, |
"user.domain" => $domain, |
"user.domain" => $domain, |
Line 7193 sub init_user_environment {
|
Line 17213 sub init_user_environment {
|
"browser.mathml" => $clientmathml, |
"browser.mathml" => $clientmathml, |
"browser.unicode" => $clientunicode, |
"browser.unicode" => $clientunicode, |
"browser.os" => $clientos, |
"browser.os" => $clientos, |
|
"browser.mobile" => $clientmobile, |
|
"browser.info" => $clientinfo, |
|
"browser.osversion" => $clientosversion, |
"server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'}, |
"server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'}, |
"request.course.fn" => '', |
"request.course.fn" => '', |
"request.course.uri" => '', |
"request.course.uri" => '', |
"request.course.sec" => '', |
"request.course.sec" => '', |
"request.role" => 'cm', |
"request.role" => 'cm', |
"request.role.adv" => $env{'user.adv'}, |
"request.role.adv" => $env{'user.adv'}, |
"request.host" => $ENV{'REMOTE_ADDR'},); |
"request.host" => $ip,); |
|
|
if ($form->{'localpath'}) { |
if ($form->{'localpath'}) { |
$initial_env{"browser.localpath"} = $form->{'localpath'}; |
$initial_env{"browser.localpath"} = $form->{'localpath'}; |
$initial_env{"browser.localres"} = $form->{'localres'}; |
$initial_env{"browser.localres"} = $form->{'localres'}; |
} |
} |
|
|
if ($public) { |
|
$initial_env{"environment.remote"} = "off"; |
|
} |
|
if ($form->{'interface'}) { |
if ($form->{'interface'}) { |
$form->{'interface'}=~s/\W//gs; |
$form->{'interface'}=~s/\W//gs; |
$initial_env{"browser.interface"} = $form->{'interface'}; |
$initial_env{"browser.interface"} = $form->{'interface'}; |
$env{'browser.interface'}=$form->{'interface'}; |
$env{'browser.interface'}=$form->{'interface'}; |
foreach my $option ('imagesuppress','appletsuppress', |
|
'embedsuppress','fontenhance','blackwhite') { |
|
if (($form->{$option} eq 'true') || |
|
($userenv{$option} eq 'on')) { |
|
$initial_env{"browser.$option"} = "on"; |
|
} |
|
} |
|
} |
} |
|
|
|
if ($form->{'iptoken'}) { |
|
my $lonhost = $r->dir_config('lonHostID'); |
|
$initial_env{"user.noloadbalance"} = $lonhost; |
|
$env{'user.noloadbalance'} = $lonhost; |
|
} |
|
|
|
if ($form->{'noloadbalance'}) { |
|
my @hosts = &Apache::lonnet::current_machine_ids(); |
|
my $hosthere = $form->{'noloadbalance'}; |
|
if (grep(/^\Q$hosthere\E$/,@hosts)) { |
|
$initial_env{"user.noloadbalance"} = $hosthere; |
|
$env{'user.noloadbalance'} = $hosthere; |
|
} |
|
} |
|
|
|
unless ($domain eq 'public') { |
|
my %is_adv = ( is_adv => $env{'user.adv'} ); |
|
my %domdef = &Apache::lonnet::get_domain_defaults($domain); |
|
|
|
foreach my $tool ('aboutme','blog','webdav','portfolio','timezone') { |
|
$userenv{'availabletools.'.$tool} = |
|
&Apache::lonnet::usertools_access($username,$domain,$tool,'reload', |
|
undef,\%userenv,\%domdef,\%is_adv); |
|
} |
|
|
|
foreach my $crstype ('official','unofficial','community','textbook','lti') { |
|
$userenv{'canrequest.'.$crstype} = |
|
&Apache::lonnet::usertools_access($username,$domain,$crstype, |
|
'reload','requestcourses', |
|
\%userenv,\%domdef,\%is_adv); |
|
} |
|
|
|
if ((ref($userroles) eq 'HASH') && ($userroles->{'user.author'}) && |
|
(exists($userroles->{"user.role.au./$domain/"}))) { |
|
if ($userenv{'authoreditors'}) { |
|
$userenv{'editors'} = $userenv{'authoreditors'}; |
|
} elsif ($domdef{'editors'} ne '') { |
|
$userenv{'editors'} = $domdef{'editors'}; |
|
} else { |
|
$userenv{'editors'} = 'edit,xml'; |
|
} |
|
} |
|
|
|
$userenv{'canrequest.author'} = |
|
&Apache::lonnet::usertools_access($username,$domain,'requestauthor', |
|
'reload','requestauthor', |
|
\%userenv,\%domdef,\%is_adv); |
|
my %reqauthor = &Apache::lonnet::get('requestauthor',['author_status','author'], |
|
$domain,$username); |
|
my $reqstatus = $reqauthor{'author_status'}; |
|
if ($reqstatus eq 'approval' || $reqstatus eq 'approved') { |
|
if (ref($reqauthor{'author'}) eq 'HASH') { |
|
$userenv{'requestauthorqueued'} = $reqstatus.':'. |
|
$reqauthor{'author'}{'timestamp'}; |
|
} |
|
} |
|
} |
|
|
$env{'user.environment'} = "$lonids/$cookie.id"; |
$env{'user.environment'} = "$lonids/$cookie.id"; |
|
|
if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id", |
if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id", |
&GDBM_WRCREAT(),0640)) { |
&GDBM_WRCREAT(),0640)) { |
&_add_to_env(\%disk_env,\%initial_env); |
&_add_to_env(\%disk_env,\%initial_env); |
&_add_to_env(\%disk_env,\%userenv,'environment.'); |
&_add_to_env(\%disk_env,\%userenv,'environment.'); |
&_add_to_env(\%disk_env,$userroles); |
&_add_to_env(\%disk_env,$userroles); |
|
if (ref($firstaccenv) eq 'HASH') { |
|
&_add_to_env(\%disk_env,$firstaccenv); |
|
} |
|
if (ref($timerintenv) eq 'HASH') { |
|
&_add_to_env(\%disk_env,$timerintenv); |
|
} |
|
if (ref($coauthorenv) eq 'HASH') { |
|
if (keys(%{$coauthorenv})) { |
|
&_add_to_env(\%disk_env,$coauthorenv); |
|
} |
|
} |
if (ref($args->{'extra_env'})) { |
if (ref($args->{'extra_env'})) { |
&_add_to_env(\%disk_env,$args->{'extra_env'}); |
&_add_to_env(\%disk_env,$args->{'extra_env'}); |
} |
} |
untie(%disk_env); |
untie(%disk_env); |
} else { |
} else { |
&Apache::lonnet::logthis("<font color=\"blue\">WARNING: ". |
&Apache::lonnet::logthis("<span style=\"color:blue;\">WARNING: ". |
'Could not create environment storage in lonauth: '.$!.'</font>'); |
'Could not create environment storage in lonauth: '.$!.'</span>'); |
return 'error: '.$!; |
return 'error: '.$!; |
} |
} |
} |
} |
Line 7249 sub init_user_environment {
|
Line 17331 sub init_user_environment {
|
|
|
sub _add_to_env { |
sub _add_to_env { |
my ($idf,$env_data,$prefix) = @_; |
my ($idf,$env_data,$prefix) = @_; |
while (my ($key,$value) = each(%$env_data)) { |
if (ref($env_data) eq 'HASH') { |
$idf->{$prefix.$key} = $value; |
while (my ($key,$value) = each(%$env_data)) { |
$env{$prefix.$key} = $value; |
$idf->{$prefix.$key} = $value; |
|
$env{$prefix.$key} = $value; |
|
} |
|
} |
|
} |
|
|
|
# --- Get the symbolic name of a problem and the url |
|
sub get_symb { |
|
my ($request,$silent) = @_; |
|
(my $url=$env{'form.url'}) =~ s-^https?\://($ENV{'SERVER_NAME'}|$ENV{'HTTP_HOST'})--; |
|
my $symb=($env{'form.symb'} ne '' ? $env{'form.symb'} : (&Apache::lonnet::symbread($url))); |
|
if ($symb eq '') { |
|
if (!$silent) { |
|
if (ref($request)) { |
|
$request->print("Unable to handle ambiguous references:$url:."); |
|
} |
|
return (); |
|
} |
|
} |
|
&Apache::lonenc::check_decrypt(\$symb); |
|
return ($symb); |
|
} |
|
|
|
# --------------------------------------------------------------Get annotation |
|
|
|
sub get_annotation { |
|
my ($symb,$enc) = @_; |
|
|
|
my $key = $symb; |
|
if (!$enc) { |
|
$key = |
|
&Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]); |
|
} |
|
my %annotation=&Apache::lonnet::get('nohist_annotations',[$key]); |
|
return $annotation{$key}; |
|
} |
|
|
|
sub clean_symb { |
|
my ($symb,$delete_enc) = @_; |
|
|
|
&Apache::lonenc::check_decrypt(\$symb); |
|
my $enc = $env{'request.enc'}; |
|
if ($delete_enc) { |
|
delete($env{'request.enc'}); |
|
} |
|
|
|
return ($symb,$enc); |
|
} |
|
|
|
############################################################ |
|
############################################################ |
|
|
|
=pod |
|
|
|
=head1 Routines for building display used to search for courses |
|
|
|
|
|
=over 4 |
|
|
|
=item * &build_filters() |
|
|
|
Create markup for a table used to set filters to use when selecting |
|
courses in a domain. Used by lonpickcourse.pm, lonmodifycourse.pm |
|
and quotacheck.pl |
|
|
|
|
|
Inputs: |
|
|
|
filterlist - anonymous array of fields to include as potential filters |
|
|
|
crstype - course type |
|
|
|
roleelement - fifth arg in selectcourse_link() populates fifth arg in javascript: opencrsbrowser() function, used |
|
to pop-open a course selector (will contain "extra element"). |
|
|
|
multelement - if multiple course selections will be allowed, this will be a hidden form element: name: multiple; value: 1 |
|
|
|
filter - anonymous hash of criteria and their values |
|
|
|
action - form action |
|
|
|
numfiltersref - ref to scalar (count of number of elements in institutional codes -- e.g., 4 for year, semester, department, and number) |
|
|
|
caller - caller context (e.g., set to 'modifycourse' when routine is called from lonmodifycourse.pm) |
|
|
|
cloneruname - username of owner of new course who wants to clone |
|
|
|
clonerudom - domain of owner of new course who wants to clone |
|
|
|
typeelem - text to use for left column in row containing course type (i.e., Course, Community or Course/Community) |
|
|
|
codetitlesref - reference to array of titles of components in institutional codes (official courses) |
|
|
|
codedom - domain |
|
|
|
formname - value of form element named "form". |
|
|
|
fixeddom - domain, if fixed. |
|
|
|
prevphase - value to assign to form element named "phase" when going back to the previous screen |
|
|
|
cnameelement - name of form element in form on opener page which will receive title of selected course |
|
|
|
cnumelement - name of form element in form on opener page which will receive courseID of selected course |
|
|
|
cdomelement - name of form element in form on opener page which will receive domain of selected course |
|
|
|
setroles - includes access constraint identifier when setting a roles-based condition for acces to a portfolio file |
|
|
|
clonetext - hidden form elements containing list of courses cloneable by intended course owner when DC creates a course |
|
|
|
clonewarning - warning message about missing information for intended course owner when DC creates a course |
|
|
|
|
|
Returns: $output - HTML for display of search criteria, and hidden form elements. |
|
|
|
|
|
Side Effects: None |
|
|
|
=cut |
|
|
|
# ---------------------------------------------- search for courses based on last activity etc. |
|
|
|
sub build_filters { |
|
my ($filterlist,$crstype,$roleelement,$multelement,$filter,$action, |
|
$numtitlesref,$caller,$cloneruname,$clonerudom,$typeelement, |
|
$codetitlesref,$codedom,$formname,$fixeddom,$prevphase, |
|
$cnameelement,$cnumelement,$cdomelement,$setroles, |
|
$clonetext,$clonewarning) = @_; |
|
my ($list,$jscript); |
|
my $onchange = 'javascript:updateFilters(this)'; |
|
my ($domainselectform,$sincefilterform,$createdfilterform, |
|
$ownerdomselectform,$persondomselectform,$instcodeform, |
|
$typeselectform,$instcodetitle); |
|
if ($formname eq '') { |
|
$formname = $caller; |
|
} |
|
foreach my $item (@{$filterlist}) { |
|
unless (($item eq 'descriptfilter') || ($item eq 'instcodefilter') || |
|
($item eq 'sincefilter') || ($item eq 'createdfilter')) { |
|
if ($item eq 'domainfilter') { |
|
$filter->{$item} = &LONCAPA::clean_domain($filter->{$item}); |
|
} elsif ($item eq 'coursefilter') { |
|
$filter->{$item} = &LONCAPA::clean_courseid($filter->{$item}); |
|
} elsif ($item eq 'ownerfilter') { |
|
$filter->{$item} = &LONCAPA::clean_username($filter->{$item}); |
|
} elsif ($item eq 'ownerdomfilter') { |
|
$filter->{'ownerdomfilter'} = |
|
&LONCAPA::clean_domain($filter->{$item}); |
|
$ownerdomselectform = &select_dom_form($filter->{'ownerdomfilter'}, |
|
'ownerdomfilter',1); |
|
} elsif ($item eq 'personfilter') { |
|
$filter->{$item} = &LONCAPA::clean_username($filter->{$item}); |
|
} elsif ($item eq 'persondomfilter') { |
|
$persondomselectform = &select_dom_form($filter->{'persondomfilter'}, |
|
'persondomfilter',1); |
|
} else { |
|
$filter->{$item} =~ s/\W//g; |
|
} |
|
if (!$filter->{$item}) { |
|
$filter->{$item} = ''; |
|
} |
|
} |
|
if ($item eq 'domainfilter') { |
|
my $allow_blank = 1; |
|
if ($formname eq 'portform') { |
|
$allow_blank=0; |
|
} elsif ($formname eq 'studentform') { |
|
$allow_blank=0; |
|
} |
|
if ($fixeddom) { |
|
$domainselectform = '<input type="hidden" name="domainfilter"'. |
|
' value="'.$codedom.'" />'. |
|
&Apache::lonnet::domain($codedom,'description'); |
|
} else { |
|
$domainselectform = &select_dom_form($filter->{$item}, |
|
'domainfilter', |
|
$allow_blank,'',$onchange); |
|
} |
|
} else { |
|
$list->{$item} = &HTML::Entities::encode($filter->{$item},'<>&"'); |
|
} |
|
} |
|
|
|
# last course activity filter and selection |
|
$sincefilterform = &timebased_select_form('sincefilter',$filter); |
|
|
|
# course created filter and selection |
|
if (exists($filter->{'createdfilter'})) { |
|
$createdfilterform = &timebased_select_form('createdfilter',$filter); |
|
} |
|
|
|
my %lt = &Apache::lonlocal::texthash( |
|
'cac' => "$crstype Activity", |
|
'ccr' => "$crstype Created", |
|
'cde' => "$crstype Title", |
|
'cdo' => "$crstype Domain", |
|
'ins' => 'Institutional Code', |
|
'inc' => 'Institutional Categorization', |
|
'cow' => "$crstype Owner/Co-owner", |
|
'cop' => "$crstype Personnel Includes", |
|
'cog' => 'Type', |
|
); |
|
|
|
if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) { |
|
my $typeval = 'Course'; |
|
if ($crstype eq 'Community') { |
|
$typeval = 'Community'; |
|
} |
|
$typeselectform = '<input type="hidden" name="type" value="'.$typeval.'" />'; |
|
} else { |
|
$typeselectform = '<select name="type" size="1"'; |
|
if ($onchange) { |
|
$typeselectform .= ' onchange="'.$onchange.'"'; |
|
} |
|
$typeselectform .= '>'."\n"; |
|
foreach my $posstype ('Course','Community') { |
|
$typeselectform.='<option value="'.$posstype.'"'. |
|
($posstype eq $crstype ? ' selected="selected" ' : ''). ">".&mt($posstype)."</option>\n"; |
|
} |
|
$typeselectform.="</select>"; |
|
} |
|
|
|
my ($cloneableonlyform,$cloneabletitle); |
|
if (exists($filter->{'cloneableonly'})) { |
|
my $cloneableon = ''; |
|
my $cloneableoff = ' checked="checked"'; |
|
if ($filter->{'cloneableonly'}) { |
|
$cloneableon = $cloneableoff; |
|
$cloneableoff = ''; |
|
} |
|
$cloneableonlyform = '<span class="LC_nobreak"><label><input type="radio" name="cloneableonly" value="1" '.$cloneableon.'/> '.&mt('Required').'</label>'.(' 'x3).'<label><input type="radio" name="cloneableonly" value="" '.$cloneableoff.' /> '.&mt('No restriction').'</label></span>'; |
|
if ($formname eq 'ccrs') { |
|
$cloneabletitle = &mt('Cloneable for [_1]',$cloneruname.':'.$clonerudom); |
|
} else { |
|
$cloneabletitle = &mt('Cloneable by you'); |
|
} |
|
} |
|
my $officialjs; |
|
if ($crstype eq 'Course') { |
|
if (exists($filter->{'instcodefilter'})) { |
|
# if (($fixeddom) || ($formname eq 'requestcrs') || |
|
# ($formname eq 'modifycourse') || ($formname eq 'filterpicker')) { |
|
if ($codedom) { |
|
$officialjs = 1; |
|
($instcodeform,$jscript,$$numtitlesref) = |
|
&Apache::courseclassifier::instcode_selectors($codedom,'filterpicker', |
|
$officialjs,$codetitlesref); |
|
if ($jscript) { |
|
$jscript = '<script type="text/javascript">'."\n". |
|
'// <![CDATA['."\n". |
|
$jscript."\n". |
|
'// ]]>'."\n". |
|
'</script>'."\n"; |
|
} |
|
} |
|
if ($instcodeform eq '') { |
|
$instcodeform = |
|
'<input type="text" name="instcodefilter" size="10" value="'. |
|
$list->{'instcodefilter'}.'" />'; |
|
$instcodetitle = $lt{'ins'}; |
|
} else { |
|
$instcodetitle = $lt{'inc'}; |
|
} |
|
if ($fixeddom) { |
|
$instcodetitle .= '<br />('.$codedom.')'; |
|
} |
|
} |
|
} |
|
my $output = qq| |
|
<form method="post" name="filterpicker" action="$action"> |
|
<input type="hidden" name="form" value="$formname" /> |
|
|; |
|
if ($formname eq 'modifycourse') { |
|
$output .= '<input type="hidden" name="phase" value="courselist" />'."\n". |
|
'<input type="hidden" name="prevphase" value="'. |
|
$prevphase.'" />'."\n"; |
|
} elsif ($formname eq 'quotacheck') { |
|
$output .= qq| |
|
<input type="hidden" name="sortby" value="" /> |
|
<input type="hidden" name="sortorder" value="" /> |
|
|; |
|
} else { |
|
my $name_input; |
|
if ($cnameelement ne '') { |
|
$name_input = '<input type="hidden" name="cnameelement" value="'. |
|
$cnameelement.'" />'; |
|
} |
|
$output .= qq| |
|
<input type="hidden" name="cnumelement" value="$cnumelement" /> |
|
<input type="hidden" name="cdomelement" value="$cdomelement" /> |
|
$name_input |
|
$roleelement |
|
$multelement |
|
$typeelement |
|
|; |
|
if ($formname eq 'portform') { |
|
$output .= '<input type="hidden" name="setroles" value="'.$setroles.'" />'."\n"; |
|
} |
|
} |
|
if ($fixeddom) { |
|
$output .= '<input type="hidden" name="fixeddom" value="'.$fixeddom.'" />'."\n"; |
|
} |
|
$output .= "<br />\n".&Apache::lonhtmlcommon::start_pick_box(); |
|
if ($sincefilterform) { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'cac'}) |
|
.$sincefilterform |
|
.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if ($createdfilterform) { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'ccr'}) |
|
.$createdfilterform |
|
.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if ($domainselectform) { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'cdo'}) |
|
.$domainselectform |
|
.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if ($typeselectform) { |
|
if (($formname eq 'ccrs') || ($formname eq 'requestcrs')) { |
|
$output .= $typeselectform; |
|
} else { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'cog'}) |
|
.$typeselectform |
|
.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
} |
|
if ($instcodeform) { |
|
$output .= &Apache::lonhtmlcommon::row_title($instcodetitle) |
|
.$instcodeform |
|
.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if (exists($filter->{'ownerfilter'})) { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'cow'}). |
|
'<table><tr><td>'.&mt('Username').'<br />'. |
|
'<input type="text" name="ownerfilter" size="20" value="'. |
|
$list->{'ownerfilter'}.'" /></td><td>'.&mt('Domain').'<br />'. |
|
$ownerdomselectform.'</td></tr></table>'. |
|
&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if (exists($filter->{'personfilter'})) { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'cop'}). |
|
'<table><tr><td>'.&mt('Username').'<br />'. |
|
'<input type="text" name="personfilter" size="20" value="'. |
|
$list->{'personfilter'}.'" /></td><td>'.&mt('Domain').'<br />'. |
|
$persondomselectform.'</td></tr></table>'. |
|
&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if (exists($filter->{'coursefilter'})) { |
|
$output .= &Apache::lonhtmlcommon::row_title(&mt('LON-CAPA course ID')) |
|
.'<input type="text" name="coursefilter" size="25" value="' |
|
.$list->{'coursefilter'}.'" />' |
|
.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if ($cloneableonlyform) { |
|
$output .= &Apache::lonhtmlcommon::row_title($cloneabletitle). |
|
$cloneableonlyform.&Apache::lonhtmlcommon::row_closure(); |
|
} |
|
if (exists($filter->{'descriptfilter'})) { |
|
$output .= &Apache::lonhtmlcommon::row_title($lt{'cde'}) |
|
.'<input type="text" name="descriptfilter" size="40" value="' |
|
.$list->{'descriptfilter'}.'" />' |
|
.&Apache::lonhtmlcommon::row_closure(1); |
|
} |
|
$output .= &Apache::lonhtmlcommon::end_pick_box().'<p>'.$clonetext."\n". |
|
'<input type="hidden" name="updater" value="" />'."\n". |
|
'<input type="submit" name="gosearch" value="'. |
|
&mt('Search').'" /></p>'."\n".'</form>'."\n".'<hr />'."\n"; |
|
return $jscript.$clonewarning.$output; |
|
} |
|
|
|
=pod |
|
|
|
=item * &timebased_select_form() |
|
|
|
Create markup for a dropdown list used to select a time-based |
|
filter e.g., Course Activity, Course Created, when searching for courses |
|
or communities |
|
|
|
Inputs: |
|
|
|
item - name of form element (sincefilter or createdfilter) |
|
|
|
filter - anonymous hash of criteria and their values |
|
|
|
Returns: HTML for a select box contained a blank, then six time selections, |
|
with value set in incoming form variables currently selected. |
|
|
|
Side Effects: None |
|
|
|
=cut |
|
|
|
sub timebased_select_form { |
|
my ($item,$filter) = @_; |
|
if (ref($filter) eq 'HASH') { |
|
$filter->{$item} =~ s/[^\d-]//g; |
|
if (!$filter->{$item}) { $filter->{$item}=-1; } |
|
return &select_form( |
|
$filter->{$item}, |
|
$item, |
|
{ '-1' => '', |
|
'86400' => &mt('today'), |
|
'604800' => &mt('last week'), |
|
'2592000' => &mt('last month'), |
|
'7776000' => &mt('last three months'), |
|
'15552000' => &mt('last six months'), |
|
'31104000' => &mt('last year'), |
|
'select_form_order' => |
|
['-1','86400','604800','2592000','7776000', |
|
'15552000','31104000']}); |
|
} |
|
} |
|
|
|
=pod |
|
|
|
=item * &js_changer() |
|
|
|
Create script tag containing Javascript used to submit course search form |
|
when course type or domain is changed, and also to hide 'Searching ...' on |
|
page load completion for page showing search result. |
|
|
|
Inputs: None |
|
|
|
Returns: markup containing updateFilters() and hideSearching() javascript functions. |
|
|
|
Side Effects: None |
|
|
|
=cut |
|
|
|
sub js_changer { |
|
return <<ENDJS; |
|
<script type="text/javascript"> |
|
// <![CDATA[ |
|
function updateFilters(caller) { |
|
if (typeof(caller) != "undefined") { |
|
document.filterpicker.updater.value = caller.name; |
|
} |
|
document.filterpicker.submit(); |
|
} |
|
|
|
function hideSearching() { |
|
if (document.getElementById('searching')) { |
|
document.getElementById('searching').style.display = 'none'; |
|
} |
|
return; |
|
} |
|
|
|
// ]]> |
|
</script> |
|
|
|
ENDJS |
|
} |
|
|
|
=pod |
|
|
|
=item * &search_courses() |
|
|
|
Process selected filters form course search form and pass to lonnet::courseiddump |
|
to retrieve a hash for which keys are courseIDs which match the selected filters. |
|
|
|
Inputs: |
|
|
|
dom - domain being searched |
|
|
|
type - course type ('Course' or 'Community' or '.' if any). |
|
|
|
filter - anonymous hash of criteria and their values |
|
|
|
numtitles - for institutional codes - number of categories |
|
|
|
cloneruname - optional username of new course owner |
|
|
|
clonerudom - optional domain of new course owner |
|
|
|
domcloner - optional "domcloner" flag; has value=1 if user has ccc priv in domain being filtered by, |
|
(used when DC is using course creation form) |
|
|
|
codetitles - reference to array of titles of components in institutional codes (official courses). |
|
|
|
cc_clone - escaped comma separated list of courses for which course cloner has active CC role |
|
(and so can clone automatically) |
|
|
|
reqcrsdom - domain of new course, where search_courses is used to identify potential courses to clone |
|
|
|
reqinstcode - institutional code of new course, where search_courses is used to identify potential |
|
courses to clone |
|
|
|
Returns: %courses - hash of courses satisfying search criteria, keys = course IDs, values are corresponding colon-separated escaped description, institutional code, owner and type. |
|
|
|
|
|
Side Effects: None |
|
|
|
=cut |
|
|
|
|
|
sub search_courses { |
|
my ($dom,$type,$filter,$numtitles,$cloneruname,$clonerudom,$domcloner,$codetitles, |
|
$cc_clone,$reqcrsdom,$reqinstcode) = @_; |
|
my (%courses,%showcourses,$cloner); |
|
if (($filter->{'ownerfilter'} ne '') || |
|
($filter->{'ownerdomfilter'} ne '')) { |
|
$filter->{'combownerfilter'} = $filter->{'ownerfilter'}.':'. |
|
$filter->{'ownerdomfilter'}; |
|
} |
|
foreach my $item ('descriptfilter','coursefilter','combownerfilter') { |
|
if (!$filter->{$item}) { |
|
$filter->{$item}='.'; |
|
} |
} |
} |
|
my $now = time; |
|
my $timefilter = |
|
($filter->{'sincefilter'}==-1?1:$now-$filter->{'sincefilter'}); |
|
my ($createdbefore,$createdafter); |
|
if (($filter->{'createdfilter'} ne '') && ($filter->{'createdfilter'} !=-1)) { |
|
$createdbefore = $now; |
|
$createdafter = $now-$filter->{'createdfilter'}; |
|
} |
|
my ($instcodefilter,$regexpok); |
|
if ($numtitles) { |
|
if ($env{'form.official'} eq 'on') { |
|
$instcodefilter = |
|
&Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles); |
|
$regexpok = 1; |
|
} elsif ($env{'form.official'} eq 'off') { |
|
$instcodefilter = &Apache::courseclassifier::instcode_search_str($dom,$numtitles,$codetitles); |
|
unless ($instcodefilter eq '') { |
|
$regexpok = -1; |
|
} |
|
} |
|
} else { |
|
$instcodefilter = $filter->{'instcodefilter'}; |
|
} |
|
if ($instcodefilter eq '') { $instcodefilter = '.'; } |
|
if ($type eq '') { $type = '.'; } |
|
|
|
if (($clonerudom ne '') && ($cloneruname ne '')) { |
|
$cloner = $cloneruname.':'.$clonerudom; |
|
} |
|
%courses = &Apache::lonnet::courseiddump($dom, |
|
$filter->{'descriptfilter'}, |
|
$timefilter, |
|
$instcodefilter, |
|
$filter->{'combownerfilter'}, |
|
$filter->{'coursefilter'}, |
|
undef,undef,$type,$regexpok,undef,undef, |
|
undef,undef,$cloner,$cc_clone, |
|
$filter->{'cloneableonly'}, |
|
$createdbefore,$createdafter,undef, |
|
$domcloner,undef,$reqcrsdom,$reqinstcode); |
|
if (($filter->{'personfilter'} ne '') && ($filter->{'persondomfilter'} ne '')) { |
|
my $ccrole; |
|
if ($type eq 'Community') { |
|
$ccrole = 'co'; |
|
} else { |
|
$ccrole = 'cc'; |
|
} |
|
my %rolehash = &Apache::lonnet::get_my_roles($filter->{'personfilter'}, |
|
$filter->{'persondomfilter'}, |
|
'userroles',undef, |
|
[$ccrole,'in','ad','ep','ta','cr'], |
|
$dom); |
|
foreach my $role (keys(%rolehash)) { |
|
my ($cnum,$cdom,$courserole) = split(':',$role); |
|
my $cid = $cdom.'_'.$cnum; |
|
if (exists($courses{$cid})) { |
|
if (ref($courses{$cid}) eq 'HASH') { |
|
if (ref($courses{$cid}{roles}) eq 'ARRAY') { |
|
if (!grep(/^\Q$courserole\E$/,@{$courses{$cid}{roles}})) { |
|
push(@{$courses{$cid}{roles}},$courserole); |
|
} |
|
} else { |
|
$courses{$cid}{roles} = [$courserole]; |
|
} |
|
$showcourses{$cid} = $courses{$cid}; |
|
} |
|
} |
|
} |
|
%courses = %showcourses; |
|
} |
|
return %courses; |
} |
} |
|
|
|
=pod |
|
|
|
=back |
|
|
|
=head1 Routines for version requirements for current course. |
|
|
|
=over 4 |
|
|
|
=item * &check_release_required() |
|
|
|
Compares required LON-CAPA version with version on server, and |
|
if required version is newer looks for a server with the required version. |
|
|
|
Looks first at servers in user's owen domain; if none suitable, looks at |
|
servers in course's domain are permitted to host sessions for user's domain. |
|
|
|
Inputs: |
|
|
|
$loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp) |
|
|
|
$courseid - Course ID of current course |
|
|
|
$rolecode - User's current role in course (for switchserver query string). |
|
|
|
$required - LON-CAPA version needed by course (format: Major.Minor). |
|
|
|
|
|
Returns: |
|
|
|
$switchserver - query string tp append to /adm/switchserver call (if |
|
current server's LON-CAPA version is too old. |
|
|
|
$warning - Message is displayed if no suitable server could be found. |
|
|
|
=cut |
|
|
|
sub check_release_required { |
|
my ($loncaparev,$courseid,$rolecode,$required) = @_; |
|
my ($switchserver,$warning); |
|
if ($required ne '') { |
|
my ($reqdmajor,$reqdminor) = ($required =~ /^(\d+)\.(\d+)$/); |
|
my ($major,$minor) = ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); |
|
if ($reqdmajor ne '' && $reqdminor ne '') { |
|
my $otherserver; |
|
if (($major eq '' && $minor eq '') || |
|
(($reqdmajor > $major) || (($reqdmajor == $major) && ($reqdminor > $minor)))) { |
|
my ($userdomserver) = &Apache::lonnet::choose_server($env{'user.domain'},undef,$required,1); |
|
my $switchlcrev = |
|
&Apache::lonnet::get_server_loncaparev($env{'user.domain'}, |
|
$userdomserver); |
|
my ($swmajor,$swminor) = ($switchlcrev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?$/); |
|
if (($swmajor eq '' && $swminor eq '') || ($reqdmajor > $swmajor) || |
|
(($reqdmajor == $swmajor) && ($reqdminor > $swminor))) { |
|
my $cdom = $env{'course.'.$courseid.'.domain'}; |
|
if ($cdom ne $env{'user.domain'}) { |
|
my ($coursedomserver,$coursehostname) = &Apache::lonnet::choose_server($cdom,undef,$required,1); |
|
my $serverhomeID = &Apache::lonnet::get_server_homeID($coursehostname); |
|
my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID); |
|
my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom); |
|
my %udomdefaults = &Apache::lonnet::get_domain_defaults($env{'user.domain'}); |
|
my $remoterev = &Apache::lonnet::get_server_loncaparev($serverhomedom,$coursedomserver); |
|
my $canhost = |
|
&Apache::lonnet::can_host_session($env{'user.domain'}, |
|
$coursedomserver, |
|
$remoterev, |
|
$udomdefaults{'remotesessions'}, |
|
$defdomdefaults{'hostedsessions'}); |
|
|
|
if ($canhost) { |
|
$otherserver = $coursedomserver; |
|
} else { |
|
$warning = &mt('Requires LON-CAPA version [_1].',$env{'course.'.$courseid.'.internal.releaserequired'}).'<br />'. &mt("No suitable server could be found amongst servers in either your own domain or in the course's domain."); |
|
} |
|
} else { |
|
$warning = &mt('Requires LON-CAPA version [_1].',$env{'course.'.$courseid.'.internal.releaserequired'}).'<br />'.&mt("No suitable server could be found amongst servers in your own domain (which is also the course's domain)."); |
|
} |
|
} else { |
|
$otherserver = $userdomserver; |
|
} |
|
} |
|
if ($otherserver ne '') { |
|
$switchserver = 'otherserver='.$otherserver.'&role='.$rolecode; |
|
} |
|
} |
|
} |
|
return ($switchserver,$warning); |
|
} |
|
|
|
=pod |
|
|
|
=item * &check_release_result() |
|
|
|
Inputs: |
|
|
|
$switchwarning - Warning message if no suitable server found to host session. |
|
|
|
$switchserver - query string to append to /adm/switchserver containing lonHostID |
|
and current role. |
|
|
|
Returns: HTML to display with information about requirement to switch server. |
|
Either displaying warning with link to Roles/Courses screen or |
|
display link to switchserver. |
|
|
|
=cut |
|
|
|
sub check_release_result { |
|
my ($switchwarning,$switchserver) = @_; |
|
my $output = &start_page('Selected course unavailable on this server'). |
|
'<p class="LC_warning">'; |
|
if ($switchwarning) { |
|
$output .= $switchwarning.'<br /><a href="/adm/roles">'; |
|
if (&show_course()) { |
|
$output .= &mt('Display courses'); |
|
} else { |
|
$output .= &mt('Display roles'); |
|
} |
|
$output .= '</a>'; |
|
} elsif ($switchserver) { |
|
$output .= &mt('This course requires a newer version of LON-CAPA than is installed on this server.'). |
|
'<br />'. |
|
'<a href="/adm/switchserver?'.$switchserver.'">'. |
|
&mt('Switch Server'). |
|
'</a>'; |
|
} |
|
$output .= '</p>'.&end_page(); |
|
return $output; |
|
} |
|
|
=pod |
=pod |
|
|
|
=item * &needs_coursereinit() |
|
|
|
Determine if course contents stored for user's session needs to be |
|
refreshed, because content has changed since "Big Hash" last tied. |
|
|
|
Check for change is made if time last checked is more than 10 minutes ago |
|
(by default). |
|
|
|
Inputs: |
|
|
|
$loncaparev - Version on current server (format: Major.Minor.Subrelease-datestamp) |
|
|
|
$interval (optional) - Time which may elapse (in s) between last check for content |
|
change in current course. (default: 600 s). |
|
|
|
Returns: an array; first element is: |
|
|
|
=over 4 |
|
|
|
'switch' - if content updates mean user's session |
|
needs to be switched to a server running a newer LON-CAPA version |
|
|
|
'update' - if course session needs to be refreshed (i.e., Big Hash needs to be reloaded) |
|
on current server hosting user's session |
|
|
|
'' - if no action required. |
|
|
|
=back |
|
|
|
If first item element is 'switch': |
|
|
|
second item is $switchwarning - Warning message if no suitable server found to host session. |
|
|
|
third item is $switchserver - query string to append to /adm/switchserver containing lonHostID |
|
and current role. |
|
|
|
otherwise: no other elements returned. |
|
|
=back |
=back |
|
|
=cut |
=cut |
|
|
|
sub needs_coursereinit { |
|
my ($loncaparev,$interval) = @_; |
|
return() unless ($env{'request.course.id'} && $env{'request.course.tied'}); |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $now = time; |
|
if ($interval eq '') { |
|
$interval = 600; |
|
} |
|
if (($now-$env{'request.course.timechecked'})>$interval) { |
|
&Apache::lonnet::appenv({'request.course.timechecked'=>$now}); |
|
my $blocked = &blocking_status('reinit',undef,$cnum,$cdom,undef,1); |
|
if ($blocked) { |
|
return (); |
|
} |
|
my $update; |
|
my $lastmainchange = &Apache::lonnet::get_coursechange($cdom,$cnum); |
|
my $lastsuppchange = &Apache::lonnet::get_suppchange($cdom,$cnum); |
|
if ($lastmainchange > $env{'request.course.tied'}) { |
|
my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum); |
|
if ($needswitch) { |
|
return ('switch',$switchwarning,$switchserver); |
|
} |
|
$update = 'main'; |
|
} |
|
if ($lastsuppchange > $env{'request.course.suppupdated'}) { |
|
if ($update) { |
|
$update = 'both'; |
|
} else { |
|
my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum); |
|
if ($needswitch) { |
|
return ('switch',$switchwarning,$switchserver); |
|
} else { |
|
$update = 'supp'; |
|
} |
|
} |
|
return ($update); |
|
} |
|
} |
|
return (); |
|
} |
|
|
|
sub switch_for_update { |
|
my ($loncaparev,$cdom,$cnum) = @_; |
|
my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired'); |
|
if ($curr_reqd_hash{'internal.releaserequired'} ne '') { |
|
my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'}; |
|
if ($curr_reqd_hash{'internal.releaserequired'} ne $required) { |
|
&Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' => |
|
$curr_reqd_hash{'internal.releaserequired'}}); |
|
my ($switchserver,$switchwarning) = |
|
&check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'}, |
|
$curr_reqd_hash{'internal.releaserequired'}); |
|
if ($switchwarning ne '' || $switchserver ne '') { |
|
return ('switch',$switchwarning,$switchserver); |
|
} |
|
} |
|
} |
|
return (); |
|
} |
|
|
|
sub update_content_constraints { |
|
my ($cdom,$cnum,$chome,$cid) = @_; |
|
my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired'); |
|
my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'}); |
|
my %checkresponsetypes; |
|
foreach my $key (keys(%Apache::lonnet::needsrelease)) { |
|
my ($item,$name,$value) = split(/:/,$key); |
|
if ($item eq 'resourcetag') { |
|
if ($name eq 'responsetype') { |
|
$checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key} |
|
} |
|
} |
|
} |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (defined($navmap)) { |
|
my %allresponses; |
|
foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() },1,0)) { |
|
my %responses = $res->responseTypes(); |
|
foreach my $key (keys(%responses)) { |
|
next unless(exists($checkresponsetypes{$key})); |
|
$allresponses{$key} += $responses{$key}; |
|
} |
|
} |
|
foreach my $key (keys(%allresponses)) { |
|
my ($major,$minor) = split(/\./,$checkresponsetypes{$key}); |
|
if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) { |
|
($reqdmajor,$reqdminor) = ($major,$minor); |
|
} |
|
} |
|
undef($navmap); |
|
} |
|
unless (($reqdmajor eq '') && ($reqdminor eq '')) { |
|
&Apache::lonnet::update_released_required($reqdmajor.'.'.$reqdminor,$cdom,$cnum,$chome,$cid); |
|
} |
|
return; |
|
} |
|
|
|
sub allmaps_incourse { |
|
my ($cdom,$cnum,$chome,$cid) = @_; |
|
if ($cdom eq '' || $cnum eq '' || $chome eq '' || $cid eq '') { |
|
$cid = $env{'request.course.id'}; |
|
$cdom = $env{'course.'.$cid.'.domain'}; |
|
$cnum = $env{'course.'.$cid.'.num'}; |
|
$chome = $env{'course.'.$cid.'.home'}; |
|
} |
|
my %allmaps = (); |
|
my $lastchange = |
|
&Apache::lonnet::get_coursechange($cdom,$cnum); |
|
if ($lastchange > $env{'request.course.tied'}) { |
|
my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum"); |
|
unless ($ferr) { |
|
&update_content_constraints($cdom,$cnum,$chome,$cid); |
|
} |
|
} |
|
my $navmap = Apache::lonnavmaps::navmap->new(); |
|
if (defined($navmap)) { |
|
foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_map() },1,0,1)) { |
|
$allmaps{$res->src()} = 1; |
|
} |
|
} |
|
return \%allmaps; |
|
} |
|
|
|
sub parse_supplemental_title { |
|
my ($title) = @_; |
|
|
|
my ($foldertitle,$renametitle); |
|
if ($title =~ /&&&/) { |
|
$title = &HTML::Entites::decode($title); |
|
} |
|
if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) { |
|
$renametitle=$4; |
|
my ($time,$uname,$udom) = ($1,$2,$3); |
|
$foldertitle=&Apache::lontexconvert::msgtexconverted($4); |
|
my $name = &plainname($uname,$udom); |
|
$name = &HTML::Entities::encode($name,'"<>&\''); |
|
$renametitle = &HTML::Entities::encode($renametitle,'"<>&\''); |
|
$title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.$name; |
|
if ($foldertitle ne '') { |
|
$title .= ': <br />'.$foldertitle; |
|
} |
|
} |
|
if (wantarray) { |
|
return ($title,$foldertitle,$renametitle); |
|
} |
|
return $title; |
|
} |
|
|
|
sub get_supplemental { |
|
my ($cnum,$cdom,$ignorecache,$possdel)=@_; |
|
my $hashid=$cnum.':'.$cdom; |
|
my ($supplemental,$cached,$set_httprefs); |
|
unless ($ignorecache) { |
|
($supplemental,$cached) = &Apache::lonnet::is_cached_new('supplemental',$hashid); |
|
} |
|
unless (defined($cached)) { |
|
my $chome=&Apache::lonnet::homeserver($cnum,$cdom); |
|
unless ($chome eq 'no_host') { |
|
my @order = @LONCAPA::map::order; |
|
my @resources = @LONCAPA::map::resources; |
|
my @resparms = @LONCAPA::map::resparms; |
|
my @zombies = @LONCAPA::map::zombies; |
|
my ($errors,%ids,%hidden); |
|
$errors = |
|
&recurse_supplemental($cnum,$cdom,'supplemental.sequence', |
|
$errors,$possdel,\%ids,\%hidden); |
|
@LONCAPA::map::order = @order; |
|
@LONCAPA::map::resources = @resources; |
|
@LONCAPA::map::resparms = @resparms; |
|
@LONCAPA::map::zombies = @zombies; |
|
$set_httprefs = 1; |
|
if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { |
|
&Apache::lonnet::appenv({'request.course.suppupdated' => time}); |
|
} |
|
$supplemental = { |
|
ids => \%ids, |
|
hidden => \%hidden, |
|
}; |
|
&Apache::lonnet::do_cache_new('supplemental',$hashid,$supplemental,600); |
|
} |
|
} |
|
return ($supplemental,$set_httprefs); |
|
} |
|
|
|
sub recurse_supplemental { |
|
my ($cnum,$cdom,$suppmap,$errors,$possdel,$suppids,$hiddensupp,$hidden) = @_; |
|
if (($suppmap) && (ref($suppids) eq 'HASH') && (ref($hiddensupp) eq 'HASH')) { |
|
my $mapnum; |
|
if ($suppmap eq 'supplemental.sequence') { |
|
$mapnum = 0; |
|
} else { |
|
($mapnum) = ($suppmap =~ /^supplemental_(\d+)\.sequence$/); |
|
} |
|
my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap); |
|
if ($fatal) { |
|
$errors ++; |
|
} else { |
|
my @order = @LONCAPA::map::order; |
|
if (@order > 0) { |
|
my @resources = @LONCAPA::map::resources; |
|
my @resparms = @LONCAPA::map::resparms; |
|
foreach my $idx (@order) { |
|
my ($title,$src,$ext,$type,$status)=split(/\:/,$resources[$idx]); |
|
if (($src ne '') && ($status eq 'res')) { |
|
my $id = $mapnum.':'.$idx; |
|
push(@{$suppids->{$src}},$id); |
|
if (($hidden) || (&get_supp_parameter($resparms[$idx],'parameter_hiddenresource') =~ /^yes/i)) { |
|
$hiddensupp->{$id} = 1; |
|
} |
|
if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) { |
|
$errors = &recurse_supplemental($cnum,$cdom,$1,$errors,$possdel,$suppids, |
|
$hiddensupp,$hiddensupp->{$id}); |
|
} else { |
|
my $allowed; |
|
if (($env{'request.role.adv'}) || (!$hiddensupp->{$id})) { |
|
$allowed = 1; |
|
} elsif ($possdel) { |
|
foreach my $item (@{$suppids->{$src}}) { |
|
next if ($item eq $id); |
|
unless ($hiddensupp->{$item}) { |
|
$allowed = 1; |
|
last; |
|
} |
|
} |
|
if ((!$allowed) && (exists($env{'httpref.'.$src}))) { |
|
&Apache::lonnet::delenv('httpref.'.$src); |
|
} |
|
} |
|
if ($allowed && (!exists($env{'httpref.'.$src}))) { |
|
&Apache::lonnet::allowuploaded('/adm/coursedoc',$src); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return $errors; |
|
} |
|
|
|
sub set_supp_httprefs { |
|
my ($cnum,$cdom,$supplemental,$possdel) = @_; |
|
if (ref($supplemental) eq 'HASH') { |
|
if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) { |
|
foreach my $src (keys(%{$supplemental->{'ids'}})) { |
|
next if ($src =~ /\.sequence$/); |
|
if (ref($supplemental->{'ids'}->{$src}) eq 'ARRAY') { |
|
my $allowed; |
|
if ($env{'request.role.adv'}) { |
|
$allowed = 1; |
|
} else { |
|
foreach my $id (@{$supplemental->{'ids'}->{$src}}) { |
|
unless ($supplemental->{'hidden'}->{$id}) { |
|
$allowed = 1; |
|
last; |
|
} |
|
} |
|
} |
|
if (exists($env{'httpref.'.$src})) { |
|
if ($possdel) { |
|
unless ($allowed) { |
|
&Apache::lonnet::delenv('httpref.'.$src); |
|
} |
|
} |
|
} elsif ($allowed) { |
|
&Apache::lonnet::allowuploaded('/adm/coursedoc',$src); |
|
} |
|
} |
|
} |
|
if ($env{'request.course.id'} eq $cdom.'_'.$cnum) { |
|
&Apache::lonnet::appenv({'request.course.suppupdated' => time}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
sub get_supp_parameter { |
|
my ($resparm,$name)=@_; |
|
return if ($resparm eq ''); |
|
my $value=undef; |
|
my $ptype=undef; |
|
foreach (split('&&&',$resparm)) { |
|
my ($thistype,$thisname,$thisvalue)=split('___',$_); |
|
if ($thisname eq $name) { |
|
$value=$thisvalue; |
|
$ptype=$thistype; |
|
} |
|
} |
|
return $value; |
|
} |
|
|
|
sub symb_to_docspath { |
|
my ($symb,$navmapref) = @_; |
|
return unless ($symb && ref($navmapref)); |
|
my ($mapurl,$id,$resurl) = &Apache::lonnet::decode_symb($symb); |
|
if ($resurl=~/\.(sequence|page)$/) { |
|
$mapurl=$resurl; |
|
} elsif ($resurl eq 'adm/navmaps') { |
|
$mapurl=$env{'course.'.$env{'request.course.id'}.'.url'}; |
|
} |
|
my $mapresobj; |
|
unless (ref($$navmapref)) { |
|
$$navmapref = Apache::lonnavmaps::navmap->new(); |
|
} |
|
if (ref($$navmapref)) { |
|
$mapresobj = $$navmapref->getResourceByUrl($mapurl); |
|
} |
|
$mapurl=~s{^.*/([^/]+)\.(\w+)$}{$1}; |
|
my $type=$2; |
|
my $path; |
|
if (ref($mapresobj)) { |
|
my $pcslist = $mapresobj->map_hierarchy(); |
|
if ($pcslist ne '') { |
|
foreach my $pc (split(/,/,$pcslist)) { |
|
next if ($pc <= 1); |
|
my $res = $$navmapref->getByMapPc($pc); |
|
if (ref($res)) { |
|
my $thisurl = $res->src(); |
|
$thisurl=~s{^.*/([^/]+)\.\w+$}{$1}; |
|
my $thistitle = $res->title(); |
|
$path .= '&'. |
|
&Apache::lonhtmlcommon::entity_encode($thisurl).'&'. |
|
&escape($thistitle). |
|
':'.$res->randompick(). |
|
':'.$res->randomout(). |
|
':'.$res->encrypted(). |
|
':'.$res->randomorder(). |
|
':'.$res->is_page(); |
|
} |
|
} |
|
} |
|
$path =~ s/^\&//; |
|
my $maptitle = $mapresobj->title(); |
|
if ($mapurl eq 'default') { |
|
$maptitle = 'Main Content'; |
|
} |
|
$path .= (($path ne '')? '&' : ''). |
|
&Apache::lonhtmlcommon::entity_encode($mapurl).'&'. |
|
&escape($maptitle). |
|
':'.$mapresobj->randompick(). |
|
':'.$mapresobj->randomout(). |
|
':'.$mapresobj->encrypted(). |
|
':'.$mapresobj->randomorder(). |
|
':'.$mapresobj->is_page(); |
|
} else { |
|
my $maptitle = &Apache::lonnet::gettitle($mapurl); |
|
my $ispage = (($type eq 'page')? 1 : ''); |
|
if ($mapurl eq 'default') { |
|
$maptitle = 'Main Content'; |
|
} |
|
$path = &Apache::lonhtmlcommon::entity_encode($mapurl).'&'. |
|
&escape($maptitle).':::::'.$ispage; |
|
} |
|
unless ($mapurl eq 'default') { |
|
$path = 'default&'. |
|
&escape('Main Content'). |
|
':::::&'.$path; |
|
} |
|
return $path; |
|
} |
|
|
|
sub validate_folderpath { |
|
my ($supplementalflag,$allowed,$coursenum,$coursedom) = @_; |
|
if ($env{'form.folderpath'} ne '') { |
|
my @items = split(/\&/,$env{'form.folderpath'}); |
|
my ($badpath,$changed,$got_supp,$supppath,%supphidden,%suppids); |
|
for (my $i=0; $i<@items; $i++) { |
|
my $odd = $i%2; |
|
if (($odd) && (!$supplementalflag) && ($items[$i] !~ /^[^:]*:(|\d+):(|1):(|1):(|1):(|1)$/)) { |
|
$badpath = 1; |
|
} elsif ($odd && $supplementalflag) { |
|
my $idx = $i-1; |
|
if ($items[$i] =~ /^([^:]*)::(|1):::$/) { |
|
my $esc_name = $1; |
|
if ((!$allowed) || ($items[$idx] eq 'supplemental')) { |
|
$supppath .= '&'.$esc_name; |
|
$changed = 1; |
|
} else { |
|
$supppath .= '&'.$items[$i]; |
|
} |
|
} elsif (($allowed) && ($items[$idx] ne 'supplemental')) { |
|
$changed = 1; |
|
my $is_hidden; |
|
unless ($got_supp) { |
|
my ($supplemental) = &get_supplemental($coursenum,$coursedom); |
|
if (ref($supplemental) eq 'HASH') { |
|
if (ref($supplemental->{'hidden'}) eq 'HASH') { |
|
%supphidden = %{$supplemental->{'hidden'}}; |
|
} |
|
if (ref($supplemental->{'ids'}) eq 'HASH') { |
|
%suppids = %{$supplemental->{'ids'}}; |
|
} |
|
} |
|
$got_supp = 1; |
|
} |
|
if (ref($suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}) eq 'ARRAY') { |
|
my $mapid = $suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}->[0]; |
|
if ($supphidden{$mapid}) { |
|
$is_hidden = 1; |
|
} |
|
} |
|
$supppath .= '&'.$items[$i].'::'.$is_hidden.':::'; |
|
} else { |
|
$supppath .= '&'.$items[$i]; |
|
} |
|
} elsif ((!$odd) && ($items[$i] !~ /^(default|supplemental)(|_\d+)$/)) { |
|
$badpath = 1; |
|
} elsif ($supplementalflag) { |
|
$supppath .= '&'.$items[$i]; |
|
} |
|
last if ($badpath); |
|
} |
|
if ($badpath) { |
|
delete($env{'form.folderpath'}); |
|
} elsif ($changed && $supplementalflag) { |
|
$supppath =~ s/^\&//; |
|
$env{'form.folderpath'} = $supppath; |
|
} |
|
} |
|
return; |
|
} |
|
|
|
sub captcha_display { |
|
my ($context,$lonhost,$defdom) = @_; |
|
my ($output,$error); |
|
my ($captcha,$pubkey,$privkey,$version) = |
|
&get_captcha_config($context,$lonhost,$defdom); |
|
if ($captcha eq 'original') { |
|
$output = &create_captcha(); |
|
unless ($output) { |
|
$error = 'captcha'; |
|
} |
|
} elsif ($captcha eq 'recaptcha') { |
|
$output = &create_recaptcha($pubkey,$version); |
|
unless ($output) { |
|
$error = 'recaptcha'; |
|
} |
|
} |
|
return ($output,$error,$captcha,$version); |
|
} |
|
|
|
sub captcha_response { |
|
my ($context,$lonhost,$defdom) = @_; |
|
my ($captcha_chk,$captcha_error); |
|
my ($captcha,$pubkey,$privkey,$version) = &get_captcha_config($context,$lonhost,$defdom); |
|
if ($captcha eq 'original') { |
|
($captcha_chk,$captcha_error) = &check_captcha(); |
|
} elsif ($captcha eq 'recaptcha') { |
|
$captcha_chk = &check_recaptcha($privkey,$version); |
|
} else { |
|
$captcha_chk = 1; |
|
} |
|
return ($captcha_chk,$captcha_error); |
|
} |
|
|
|
sub get_captcha_config { |
|
my ($context,$lonhost,$dom_in_effect) = @_; |
|
my ($captcha,$pubkey,$privkey,$version,$hashtocheck); |
|
my $hostname = &Apache::lonnet::hostname($lonhost); |
|
my $serverhomeID = &Apache::lonnet::get_server_homeID($hostname); |
|
my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID); |
|
if ($context eq 'usercreation') { |
|
my %domconfig = &Apache::lonnet::get_dom('configuration',[$context],$serverhomedom); |
|
if (ref($domconfig{$context}) eq 'HASH') { |
|
$hashtocheck = $domconfig{$context}{'cancreate'}; |
|
if (ref($hashtocheck) eq 'HASH') { |
|
if ($hashtocheck->{'captcha'} eq 'recaptcha') { |
|
if (ref($hashtocheck->{'recaptchakeys'}) eq 'HASH') { |
|
$pubkey = $hashtocheck->{'recaptchakeys'}{'public'}; |
|
$privkey = $hashtocheck->{'recaptchakeys'}{'private'}; |
|
} |
|
if ($privkey && $pubkey) { |
|
$captcha = 'recaptcha'; |
|
$version = $hashtocheck->{'recaptchaversion'}; |
|
if ($version ne '2') { |
|
$version = 1; |
|
} |
|
} else { |
|
$captcha = 'original'; |
|
} |
|
} elsif ($hashtocheck->{'captcha'} ne 'notused') { |
|
$captcha = 'original'; |
|
} |
|
} |
|
} else { |
|
$captcha = 'captcha'; |
|
} |
|
} elsif ($context eq 'login') { |
|
my %domconfhash = &Apache::loncommon::get_domainconf($serverhomedom); |
|
if ($domconfhash{$serverhomedom.'.login.captcha'} eq 'recaptcha') { |
|
$pubkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_public'}; |
|
$privkey = $domconfhash{$serverhomedom.'.login.recaptchakeys_private'}; |
|
if ($privkey && $pubkey) { |
|
$captcha = 'recaptcha'; |
|
$version = $domconfhash{$serverhomedom.'.login.recaptchaversion'}; |
|
if ($version ne '2') { |
|
$version = 1; |
|
} |
|
} else { |
|
$captcha = 'original'; |
|
} |
|
} elsif ($domconfhash{$serverhomedom.'.login.captcha'} eq 'original') { |
|
$captcha = 'original'; |
|
} |
|
} elsif ($context eq 'passwords') { |
|
if ($dom_in_effect) { |
|
my %passwdconf = &Apache::lonnet::get_passwdconf($dom_in_effect); |
|
if ($passwdconf{'captcha'} eq 'recaptcha') { |
|
if (ref($passwdconf{'recaptchakeys'}) eq 'HASH') { |
|
$pubkey = $passwdconf{'recaptchakeys'}{'public'}; |
|
$privkey = $passwdconf{'recaptchakeys'}{'private'}; |
|
} |
|
if ($privkey && $pubkey) { |
|
$captcha = 'recaptcha'; |
|
$version = $passwdconf{'recaptchaversion'}; |
|
if ($version ne '2') { |
|
$version = 1; |
|
} |
|
} else { |
|
$captcha = 'original'; |
|
} |
|
} elsif ($passwdconf{'captcha'} ne 'notused') { |
|
$captcha = 'original'; |
|
} |
|
} |
|
} |
|
return ($captcha,$pubkey,$privkey,$version); |
|
} |
|
|
|
sub create_captcha { |
|
my %captcha_params = &captcha_settings(); |
|
my ($output,$maxtries,$tries) = ('',10,0); |
|
while ($tries < $maxtries) { |
|
$tries ++; |
|
my $captcha = Authen::Captcha->new ( |
|
output_folder => $captcha_params{'output_dir'}, |
|
data_folder => $captcha_params{'db_dir'}, |
|
); |
|
my $md5sum = $captcha->generate_code($captcha_params{'numchars'}); |
|
|
|
if (-e $Apache::lonnet::perlvar{'lonCaptchaDir'}.'/'.$md5sum.'.png') { |
|
$output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n". |
|
'<span class="LC_nobreak">'. |
|
&mt('Type in the letters/numbers shown below').' '. |
|
'<input type="text" size="5" name="code" value="" autocomplete="new-password" />'. |
|
'</span><br />'. |
|
'<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />'; |
|
last; |
|
} |
|
} |
|
if ($output eq '') { |
|
&Apache::lonnet::logthis("Failed to create Captcha code after $tries attempts."); |
|
} |
|
return $output; |
|
} |
|
|
|
sub captcha_settings { |
|
my %captcha_params = ( |
|
output_dir => $Apache::lonnet::perlvar{'lonCaptchaDir'}, |
|
www_output_dir => "/captchaspool", |
|
db_dir => $Apache::lonnet::perlvar{'lonCaptchaDb'}, |
|
numchars => '5', |
|
); |
|
return %captcha_params; |
|
} |
|
|
|
sub check_captcha { |
|
my ($captcha_chk,$captcha_error); |
|
my $code = $env{'form.code'}; |
|
my $md5sum = $env{'form.crypt'}; |
|
my %captcha_params = &captcha_settings(); |
|
my $captcha = Authen::Captcha->new( |
|
output_folder => $captcha_params{'output_dir'}, |
|
data_folder => $captcha_params{'db_dir'}, |
|
); |
|
$captcha_chk = $captcha->check_code($code,$md5sum); |
|
my %captcha_hash = ( |
|
0 => 'Code not checked (file error)', |
|
-1 => 'Failed: code expired', |
|
-2 => 'Failed: invalid code (not in database)', |
|
-3 => 'Failed: invalid code (code does not match crypt)', |
|
); |
|
if ($captcha_chk != 1) { |
|
$captcha_error = $captcha_hash{$captcha_chk} |
|
} |
|
return ($captcha_chk,$captcha_error); |
|
} |
|
|
|
sub create_recaptcha { |
|
my ($pubkey,$version) = @_; |
|
if ($version >= 2) { |
|
return '<div class="g-recaptcha" data-sitekey="'.$pubkey.'"></div>'. |
|
'<div style="padding:0;clear:both;margin:0;border:0"></div>'; |
|
} else { |
|
my $use_ssl; |
|
if ($ENV{'SERVER_PORT'} == 443) { |
|
$use_ssl = 1; |
|
} |
|
my $captcha = Captcha::reCAPTCHA->new; |
|
return $captcha->get_options_setter({theme => 'white'})."\n". |
|
$captcha->get_html($pubkey,undef,$use_ssl). |
|
&mt('If the text is hard to read, [_1] will replace them.', |
|
'<img src="/res/adm/pages/refresh.gif" alt="reCAPTCHA refresh" />'). |
|
'<br /><br />'; |
|
} |
|
} |
|
|
|
sub check_recaptcha { |
|
my ($privkey,$version) = @_; |
|
my $captcha_chk; |
|
my $ip = &Apache::lonnet::get_requestor_ip(); |
|
if ($version >= 2) { |
|
my $ua = LWP::UserAgent->new; |
|
$ua->timeout(10); |
|
my %info = ( |
|
secret => $privkey, |
|
response => $env{'form.g-recaptcha-response'}, |
|
remoteip => $ip, |
|
); |
|
my $response = $ua->post('https://www.google.com/recaptcha/api/siteverify',\%info); |
|
if ($response->is_success) { |
|
my $data = JSON::DWIW->from_json($response->decoded_content); |
|
if (ref($data) eq 'HASH') { |
|
if ($data->{'success'}) { |
|
$captcha_chk = 1; |
|
} |
|
} |
|
} |
|
} else { |
|
my $captcha = Captcha::reCAPTCHA->new; |
|
my $captcha_result = |
|
$captcha->check_answer( |
|
$privkey, |
|
$ip, |
|
$env{'form.recaptcha_challenge_field'}, |
|
$env{'form.recaptcha_response_field'}, |
|
); |
|
if ($captcha_result->{is_valid}) { |
|
$captcha_chk = 1; |
|
} |
|
} |
|
return $captcha_chk; |
|
} |
|
|
|
sub emailusername_info { |
|
my @fields = ('firstname','lastname','institution','web','location','officialemail','id'); |
|
my %titles = &Apache::lonlocal::texthash ( |
|
lastname => 'Last Name', |
|
firstname => 'First Name', |
|
institution => 'School/college/university', |
|
location => "School's city, state/province, country", |
|
web => "School's web address", |
|
officialemail => 'E-mail address at institution (if different)', |
|
id => 'Student/Employee ID', |
|
); |
|
return (\@fields,\%titles); |
|
} |
|
|
|
sub cleanup_html { |
|
my ($incoming) = @_; |
|
my $outgoing; |
|
if ($incoming ne '') { |
|
$outgoing = $incoming; |
|
$outgoing =~ s/;/;/g; |
|
$outgoing =~ s/\#/#/g; |
|
$outgoing =~ s/\&/&/g; |
|
$outgoing =~ s/</</g; |
|
$outgoing =~ s/>/>/g; |
|
$outgoing =~ s/\(/(/g; |
|
$outgoing =~ s/\)/)/g; |
|
$outgoing =~ s/"/"/g; |
|
$outgoing =~ s/'/'/g; |
|
$outgoing =~ s/\$/$/g; |
|
$outgoing =~ s{/}{/}g; |
|
$outgoing =~ s/=/=/g; |
|
$outgoing =~ s/\\/\/g |
|
} |
|
return $outgoing; |
|
} |
|
|
|
# Checks for critical messages and returns a redirect url if one exists. |
|
# $interval indicates how often to check for messages. |
|
# $context is the calling context -- roles, grades, contents, menu or flip. |
|
sub critical_redirect { |
|
my ($interval,$context) = @_; |
|
unless (($env{'user.domain'} ne '') && ($env{'user.name'} ne '')) { |
|
return (); |
|
} |
|
if ((time-$env{'user.criticalcheck.time'})>$interval) { |
|
if (($env{'request.course.id'}) && (($context eq 'flip') || ($context eq 'contents'))) { |
|
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; |
|
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; |
|
my $blocked = &blocking_status('alert',undef,$cnum,$cdom,undef,1); |
|
if ($blocked) { |
|
my $checkrole = "cm./$cdom/$cnum"; |
|
if ($env{'request.course.sec'} ne '') { |
|
$checkrole .= "/$env{'request.course.sec'}"; |
|
} |
|
unless ((&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) && |
|
($env{'request.role'} !~ m{^st\./$cdom/$cnum})) { |
|
return; |
|
} |
|
} |
|
} |
|
my @what=&Apache::lonnet::dump('critical', $env{'user.domain'}, |
|
$env{'user.name'}); |
|
&Apache::lonnet::appenv({'user.criticalcheck.time'=>time}); |
|
my $redirecturl; |
|
if ($what[0]) { |
|
if (($what[0] ne 'con_lost') && ($what[0] ne 'no_such_host') && ($what[0]!~/^error\:/)) { |
|
$redirecturl='/adm/email?critical=display'; |
|
my $url=&Apache::lonnet::absolute_url().$redirecturl; |
|
return (1, $url); |
|
} |
|
} |
|
} |
|
return (); |
|
} |
|
|
|
# Use: |
|
# my $answer=reply("encrypt:passwd:$udom:$uname:$upass",$tryserver); |
|
# |
|
################################################## |
|
# password associated functions # |
|
################################################## |
|
sub des_keys { |
|
# Make a new key for DES encryption. |
|
# Each key has two parts which are returned separately. |
|
# Please note: Each key must be passed through the &hex function |
|
# before it is output to the web browser. The hex versions cannot |
|
# be used to decrypt. |
|
my @hexstr=('0','1','2','3','4','5','6','7', |
|
'8','9','a','b','c','d','e','f'); |
|
my $lkey=''; |
|
for (0..7) { |
|
$lkey.=$hexstr[rand(15)]; |
|
} |
|
my $ukey=''; |
|
for (0..7) { |
|
$ukey.=$hexstr[rand(15)]; |
|
} |
|
return ($lkey,$ukey); |
|
} |
|
|
|
sub des_decrypt { |
|
my ($key,$cyphertext) = @_; |
|
my $keybin=pack("H16",$key); |
|
my $cypher; |
|
if ($Crypt::DES::VERSION>=2.03) { |
|
$cypher=new Crypt::DES $keybin; |
|
} else { |
|
$cypher=new DES $keybin; |
|
} |
|
my $plaintext=''; |
|
my $cypherlength = length($cyphertext); |
|
my $numchunks = int($cypherlength/32); |
|
for (my $j=0; $j<$numchunks; $j++) { |
|
my $start = $j*32; |
|
my $cypherblock = substr($cyphertext,$start,32); |
|
my $chunk = |
|
$cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,0,16)))); |
|
$chunk .= |
|
$cypher->decrypt(unpack("a8",pack("H16",substr($cypherblock,16,16)))); |
|
$chunk=substr($chunk,1,ord(substr($chunk,0,1)) ); |
|
$plaintext .= $chunk; |
|
} |
|
return $plaintext; |
|
} |
|
|
|
sub get_requested_shorturls { |
|
my ($cdom,$cnum,$navmap) = @_; |
|
return unless (ref($navmap)); |
|
my ($numnew,$errors); |
|
my @toshorten = &Apache::loncommon::get_env_multiple('form.addtiny'); |
|
if (@toshorten) { |
|
my (%maps,%resources,%titles); |
|
&Apache::loncourserespicker::enumerate_course_contents($navmap,\%maps,\%resources,\%titles, |
|
'shorturls',$cdom,$cnum); |
|
if (keys(%resources)) { |
|
my %tocreate; |
|
foreach my $item (sort {$a <=> $b} (@toshorten)) { |
|
my $symb = $resources{$item}; |
|
if ($symb) { |
|
$tocreate{$cnum.'&'.$symb} = 1; |
|
} |
|
} |
|
if (keys(%tocreate)) { |
|
($numnew,$errors) = &make_short_symbs($cdom,$cnum, |
|
\%tocreate); |
|
} |
|
} |
|
} |
|
return ($numnew,$errors); |
|
} |
|
|
|
sub make_short_symbs { |
|
my ($cdom,$cnum,$tocreateref,$lockuser) = @_; |
|
my ($numnew,@errors); |
|
if (ref($tocreateref) eq 'HASH') { |
|
my %tocreate = %{$tocreateref}; |
|
if (keys(%tocreate)) { |
|
my %coursetiny = &Apache::lonnet::dump('tiny',$cdom,$cnum); |
|
my $su = Short::URL->new(no_vowels => 1); |
|
my $init = ''; |
|
my (%newunique,%addcourse,%courseonly,%failed); |
|
# get lock on tiny db |
|
my $now = time; |
|
if ($lockuser eq '') { |
|
$lockuser = $env{'user.name'}.':'.$env{'user.domain'}; |
|
} |
|
my $lockhash = { |
|
"lock\0$now" => $lockuser, |
|
}; |
|
my $tries = 0; |
|
my $gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom); |
|
my ($code,$error); |
|
while (($gotlock ne 'ok') && ($tries<3)) { |
|
$tries ++; |
|
sleep 1; |
|
$gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom); |
|
} |
|
if ($gotlock eq 'ok') { |
|
$init = &shorten_symbs($cdom,$init,$su,\%coursetiny,\%tocreate,\%newunique, |
|
\%addcourse,\%courseonly,\%failed); |
|
if (keys(%failed)) { |
|
my $numfailed = scalar(keys(%failed)); |
|
push(@errors,&mt('error: could not obtain unique six character URL for [quant,_1,resource]',$numfailed)); |
|
} |
|
if (keys(%newunique)) { |
|
my $putres = &Apache::lonnet::newput_dom('tiny',\%newunique,$cdom); |
|
if ($putres eq 'ok') { |
|
$numnew = scalar(keys(%newunique)); |
|
my $newputres = &Apache::lonnet::newput('tiny',\%addcourse,$cdom,$cnum); |
|
unless ($newputres eq 'ok') { |
|
push(@errors,&mt('error: could not store course look-up of short URLs')); |
|
} |
|
} else { |
|
push(@errors,&mt('error: could not store unique six character URLs')); |
|
} |
|
} |
|
my $dellockres = &Apache::lonnet::del_dom('tiny',["lock\0$now"],$cdom); |
|
unless ($dellockres eq 'ok') { |
|
push(@errors,&mt('error: could not release lockfile')); |
|
} |
|
} else { |
|
push(@errors,&mt('error: could not obtain lockfile')); |
|
} |
|
if (keys(%courseonly)) { |
|
my $result = &Apache::lonnet::newput('tiny',\%courseonly,$cdom,$cnum); |
|
if ($result ne 'ok') { |
|
push(@errors,&mt('error: could not update course look-up of short URLs')); |
|
} |
|
} |
|
} |
|
} |
|
return ($numnew,\@errors); |
|
} |
|
|
|
sub shorten_symbs { |
|
my ($cdom,$init,$su,$coursetiny,$tocreate,$newunique,$addcourse,$courseonly,$failed) = @_; |
|
return unless ((ref($su)) && (ref($coursetiny) eq 'HASH') && (ref($tocreate) eq 'HASH') && |
|
(ref($newunique) eq 'HASH') && (ref($addcourse) eq 'HASH') && |
|
(ref($courseonly) eq 'HASH') && (ref($failed) eq 'HASH')); |
|
my (%possibles,%collisions); |
|
foreach my $key (keys(%{$tocreate})) { |
|
my $num = String::CRC32::crc32($key); |
|
my $tiny = $su->encode($num,$init); |
|
if ($tiny) { |
|
$possibles{$tiny} = $key; |
|
} |
|
} |
|
if (!$init) { |
|
$init = 1; |
|
} else { |
|
$init ++; |
|
} |
|
if (keys(%possibles)) { |
|
my @posstiny = keys(%possibles); |
|
my $configuname = &Apache::lonnet::get_domainconfiguser($cdom); |
|
my %currtiny = &Apache::lonnet::get('tiny',\@posstiny,$cdom,$configuname); |
|
if (keys(%currtiny)) { |
|
foreach my $key (keys(%currtiny)) { |
|
next if ($currtiny{$key} eq ''); |
|
if ($currtiny{$key} eq $possibles{$key}) { |
|
my ($tcnum,$tsymb) = split(/\&/,$currtiny{$key}); |
|
unless (($coursetiny->{$tsymb} eq $key) || ($addcourse->{$tsymb} eq $key) || ($courseonly->{$tsymb} eq $key)) { |
|
$courseonly->{$tsymb} = $key; |
|
} |
|
} else { |
|
$collisions{$possibles{$key}} = 1; |
|
} |
|
delete($possibles{$key}); |
|
} |
|
} |
|
foreach my $key (keys(%possibles)) { |
|
$newunique->{$key} = $possibles{$key}; |
|
my ($tcnum,$tsymb) = split(/\&/,$possibles{$key}); |
|
unless (($coursetiny->{$tsymb} eq $key) || ($addcourse->{$tsymb} eq $key) || ($courseonly->{$tsymb} eq $key)) { |
|
$addcourse->{$tsymb} = $key; |
|
} |
|
} |
|
} |
|
if (keys(%collisions)) { |
|
if ($init <5) { |
|
if (!$init) { |
|
$init = 1; |
|
} else { |
|
$init ++; |
|
} |
|
$init = &shorten_symbs($cdom,$init,$su,$coursetiny,\%collisions, |
|
$newunique,$addcourse,$courseonly,$failed); |
|
} else { |
|
foreach my $key (keys(%collisions)) { |
|
$failed->{$key} = 1; |
|
$failed->{$key} = 1; |
|
} |
|
} |
|
} |
|
return $init; |
|
} |
|
|
|
sub is_nonframeable { |
|
my ($url,$absolute,$hostname,$ip,$nocache) = @_; |
|
my ($remprotocol,$remhost) = ($url =~ m{^(https?)\://(([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,})}i); |
|
return if (($remprotocol eq '') || ($remhost eq '')); |
|
|
|
$remprotocol = lc($remprotocol); |
|
$remhost = lc($remhost); |
|
my $remport = 80; |
|
if ($remprotocol eq 'https') { |
|
$remport = 443; |
|
} |
|
my ($result,$cached) = &Apache::lonnet::is_cached_new('noiframe',$remhost.':'.$remport); |
|
if ($cached) { |
|
unless ($nocache) { |
|
if ($result) { |
|
return 1; |
|
} else { |
|
return 0; |
|
} |
|
} |
|
} |
|
my $uselink; |
|
my $request = new HTTP::Request('HEAD',$url); |
|
my $ua = LWP::UserAgent->new; |
|
$ua->timeout(5); |
|
my $response=$ua->request($request); |
|
if ($response->is_success()) { |
|
my $secpolicy = lc($response->header('content-security-policy')); |
|
my $xframeop = lc($response->header('x-frame-options')); |
|
$secpolicy =~ s/^\s+|\s+$//g; |
|
$xframeop =~ s/^\s+|\s+$//g; |
|
if (($secpolicy ne '') || ($xframeop ne '')) { |
|
my $remotehost = $remprotocol.'://'.$remhost; |
|
my ($origin,$protocol,$port); |
|
if ($ENV{'SERVER_PORT'} =~/^\d+$/) { |
|
$port = $ENV{'SERVER_PORT'}; |
|
} else { |
|
$port = 80; |
|
} |
|
if ($absolute eq '') { |
|
$protocol = 'http:'; |
|
if ($port == 443) { |
|
$protocol = 'https:'; |
|
} |
|
$origin = $protocol.'//'.lc($hostname); |
|
} else { |
|
$origin = lc($absolute); |
|
($protocol,$hostname) = ($absolute =~ m{^(https?:)//([^/]+)$}); |
|
} |
|
if (($secpolicy) && ($secpolicy =~ /\Qframe-ancestors\E([^;]*)(;|$)/)) { |
|
my $framepolicy = $1; |
|
$framepolicy =~ s/^\s+|\s+$//g; |
|
my @policies = split(/\s+/,$framepolicy); |
|
if (@policies) { |
|
if (grep(/^\Q'none'\E$/,@policies)) { |
|
$uselink = 1; |
|
} else { |
|
$uselink = 1; |
|
if ((grep(/^\Q*\E$/,@policies)) || (grep(/^\Q$protocol\E$/,@policies)) || |
|
(($origin ne '') && (grep(/^\Q$origin\E$/,@policies))) || |
|
(($ip ne '') && (grep(/^\Q$ip\E$/,@policies)))) { |
|
undef($uselink); |
|
} |
|
if ($uselink) { |
|
if (grep(/^\Q'self'\E$/,@policies)) { |
|
if (($origin ne '') && ($remotehost eq $origin)) { |
|
undef($uselink); |
|
} |
|
} |
|
} |
|
if ($uselink) { |
|
my @possok; |
|
if ($ip ne '') { |
|
push(@possok,$ip); |
|
} |
|
my $hoststr = ''; |
|
foreach my $part (reverse(split(/\./,$hostname))) { |
|
if ($hoststr eq '') { |
|
$hoststr = $part; |
|
} else { |
|
$hoststr = "$part.$hoststr"; |
|
} |
|
if ($hoststr eq $hostname) { |
|
push(@possok,$hostname); |
|
} else { |
|
push(@possok,"*.$hoststr"); |
|
} |
|
} |
|
if (@possok) { |
|
foreach my $poss (@possok) { |
|
last if (!$uselink); |
|
foreach my $policy (@policies) { |
|
if ($policy =~ m{^(\Q$protocol\E//|)\Q$poss\E(\Q:$port\E|)$}) { |
|
undef($uselink); |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} elsif ($xframeop ne '') { |
|
$uselink = 1; |
|
my @policies = split(/\s*,\s*/,$xframeop); |
|
if (@policies) { |
|
unless (grep(/^deny$/,@policies)) { |
|
if ($origin ne '') { |
|
if (grep(/^sameorigin$/,@policies)) { |
|
if ($remotehost eq $origin) { |
|
undef($uselink); |
|
} |
|
} |
|
if ($uselink) { |
|
foreach my $policy (@policies) { |
|
if ($policy =~ /^allow-from\s*(.+)$/) { |
|
my $allowfrom = $1; |
|
if (($allowfrom ne '') && ($allowfrom eq $origin)) { |
|
undef($uselink); |
|
last; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
if ($nocache) { |
|
if ($cached) { |
|
my $devalidate; |
|
if ($uselink && !$result) { |
|
$devalidate = 1; |
|
} elsif (!$uselink && $result) { |
|
$devalidate = 1; |
|
} |
|
if ($devalidate) { |
|
&Apache::lonnet::devalidate_cache_new('noiframe',$remhost.':'.$remport); |
|
} |
|
} |
|
} else { |
|
if ($uselink) { |
|
$result = 1; |
|
} else { |
|
$result = 0; |
|
} |
|
&Apache::lonnet::do_cache_new('noiframe',$remhost.':'.$remport,$result,3600); |
|
} |
|
return $uselink; |
|
} |
|
|
|
sub page_menu { |
|
my ($menucolls,$menunum) = @_; |
|
my %menu; |
|
foreach my $item (split(/;/,$menucolls)) { |
|
my ($num,$value) = split(/\%/,$item); |
|
if ($num eq $menunum) { |
|
my @entries = split(/\&/,$value); |
|
foreach my $entry (@entries) { |
|
my ($name,$fields) = split(/=/,$entry); |
|
if (($name eq 'top') || ($name eq 'inline') || ($name eq 'foot') || ($name eq 'main')) { |
|
$menu{$name} = $fields; |
|
} else { |
|
my @shown; |
|
if ($fields =~ /,/) { |
|
@shown = split(/,/,$fields); |
|
} else { |
|
@shown = ($fields); |
|
} |
|
if (@shown) { |
|
foreach my $field (@shown) { |
|
next if ($field eq ''); |
|
$menu{$field} = 1; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return %menu; |
|
} |
|
|
1; |
1; |
__END__; |
__END__; |
|
|