".
- "$text ";
+ "".
+ "$text ";
}
# Add the graphic
+ my $title = &mt('View the FAQ');
+ my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
$template .= <<"ENDTEMPLATE";
-
+
ENDTEMPLATE
if ($text ne '') { $template.='
' };
return $template;
}
+###############################################################
+###############################################################
+
+=pod
+
+=item * &change_content_javascript():
+
+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
+Javascript, even in Netscape 4.
+
+The Javascript fragment returned by this function (no EscriptE tag)
+must be written to the HTML page once. It will prove the Javascript
+function "change(name, content)". Calling the change function with the
+name of the section
+you want to update, matching the name passed to C, and
+the new content you want to put in there, will put the content into
+that area.
+
+B: Netscape 4 only reserves enough space for the changable area
+to contain room for the original contents. You need to "make space"
+for whatever changes you wish to make, and be B to check your
+code in Netscape 4. This feature in Netscape 4 is B powerful;
+it's adequate for updating a one-line status display, but little more.
+This script will set the space to 100% width, so you only need to
+worry about height in Netscape 4.
+
+Modern browsers are much less limiting, and if you can commit to the
+user not using Netscape 4, this feature may be used freely with
+pretty much any HTML.
+
+=cut
+
+sub change_content_javascript {
+ # If we're on Netscape 4, we need to use Layer-based code
+ if ($env{'browser.type'} eq 'netscape' &&
+ $env{'browser.version'} =~ /^4\./) {
+ return (<. $name is
+the name you will use to reference the area later; do not repeat the
+same name on a given HTML page more then once. $origContent is what
+the area will originally contain, which can be left blank.
+
+=cut
+
+sub changable_area {
+ my ($name, $origContent) = @_;
+
+ if ($env{'browser.type'} eq 'netscape' &&
+ $env{'browser.version'} =~ /^4\./) {
+ # If this is netscape 4, we need to use the Layer tag
+ return "$origContent ";
+ } else {
+ return "$origContent ";
+ }
+}
+
+=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 csv_translate($text)
+=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 for the onload and onresize events.
+
+=back
+
+=cut
+
+sub resize_textarea_js {
+ my $geometry = &viewport_geometry_js();
+ return <<"RESIZE";
+
+RESIZE
-Translate $text to allow it to be output as a 'comma seperated values'
+}
+
+=pod
+
+=head1 Excel and CSV file utility routines
+
+=over 4
+
+=cut
+
+###############################################################
+###############################################################
+
+=pod
+
+=item * &csv_translate($text)
+
+Translate $text to allow it to be output as a 'comma separated values'
format.
=cut
+###############################################################
+###############################################################
sub csv_translate {
my $text = shift;
$text =~ s/\"/\"\"/g;
- $text =~ s/\n//g;
+ $text =~ s/\n/ /g;
return $text;
}
###############################################################
+###############################################################
+
+=pod
+
+=item * &define_excel_formats()
+
+Define some commonly used Excel cell formats.
+
+Currently supported formats:
+
+=over 4
+
+=item header
+
+=item bold
+
+=item h1
+
+=item h2
+
+=item h3
+
+=item h4
+
+=item i
+
+=item date
+
+=back
+
+Inputs: $workbook
+
+Returns: $format, a hash reference.
+
+=cut
+
+###############################################################
+###############################################################
+sub define_excel_formats {
+ my ($workbook) = @_;
+ my $format;
+ $format->{'header'} = $workbook->add_format(bold => 1,
+ bottom => 1,
+ align => 'center');
+ $format->{'bold'} = $workbook->add_format(bold=>1);
+ $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
+ $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
+ $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
+ $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
+ $format->{'i'} = $workbook->add_format(italic=>1);
+ $format->{'date'} = $workbook->add_format(num_format=>
+ 'mm/dd/yyyy hh:mm:ss');
+ return $format;
+}
+
+###############################################################
+###############################################################
+
+=pod
+
+=item * &create_workbook()
+
+Create an Excel worksheet. If it fails, output message on the
+request object and return undefs.
+
+Inputs: Apache request object
+
+Returns (undef) on failure,
+ Excel worksheet object, scalar with filename, and formats
+ from &Apache::loncommon::define_excel_formats on success
+
+=cut
+
+###############################################################
+###############################################################
+sub create_workbook {
+ my ($r) = @_;
+ #
+ # Create the excel spreadsheet
+ my $filename = '/prtspool/'.
+ $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
+ time.'_'.rand(1000000000).'.xls';
+ my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
+ if (! defined($workbook)) {
+ $r->log_error("Error creating excel spreadsheet $filename: $!");
+ $r->print(''.&mt("Unable to create new Excel file. ".
+ "This error has been logged. ".
+ "Please alert your LON-CAPA administrator").
+ '
');
+ return (undef);
+ }
+ #
+ $workbook->set_tempdir('/home/httpd/perl/tmp');
+ #
+ my $format = &Apache::loncommon::define_excel_formats($workbook);
+ return ($workbook,$filename,$format);
+}
+
+###############################################################
+###############################################################
+
+=pod
+
+=item * &create_text_file()
+
+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
+return undefs.
+
+Inputs: Apache request object, and file suffix
+
+Returns (undef) on failure,
+ Filehandle and filename on success.
+
+=cut
+
+###############################################################
+###############################################################
+sub create_text_file {
+ my ($r,$suffix) = @_;
+ if (! defined($suffix)) { $suffix = 'txt'; };
+ my $fh;
+ my $filename = '/prtspool/'.
+ $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
+ time.'_'.rand(1000000000).'.'.$suffix;
+ $fh = Apache::File->new('>/home/httpd'.$filename);
+ if (! defined($fh)) {
+ $r->log_error("Couldn't open $filename for output $!");
+ $r->print("Problems occured in creating the output file. ".
+ "This error has been logged. ".
+ "Please alert your LON-CAPA administrator.");
+ }
+ return ($fh,$filename)
+}
+
+
+=pod
+
+=back
+
+=cut
+
+###############################################################
## Home server list generating code ##
###############################################################
+
+# ------------------------------------------
+
+sub domain_select {
+ my ($name,$value,$multiple)=@_;
+ my %domains=map {
+ $_ => $_.' '. &Apache::lonnet::domain($_,'description')
+ } &Apache::lonnet::all_domains();
+ if ($multiple) {
+ $domains{''}=&mt('Any domain');
+ $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
+ return &multiple_select_form($name,$value,4,\%domains);
+ } else {
+ $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
+ return &select_form($name,$value,%domains);
+ }
+}
+
+#-------------------------------------------
+
+=pod
+
+=head1 Routines for form select boxes
+
+=over 4
+
+=item * &multiple_select_form($name,$value,$size,$hash,$order)
+
+Returns a string containing a element int multiple mode
+
+
+Args:
+ $name - name of the element
+ $value - scalar or array ref of values that should already be selected
+ $size - number of rows long the select element is
+ $hash - the elements should be 'option' => 'shown text'
+ (shown text should already have been &mt())
+ $order - (optional) array ref of the order to show the elements in
+
+=cut
+
+#-------------------------------------------
+sub multiple_select_form {
+ my ($name,$value,$size,$hash,$order)=@_;
+ my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
+ my $output='';
+ if (! defined($size)) {
+ $size = 4;
+ if (scalar(keys(%$hash))<4) {
+ $size = scalar(keys(%$hash));
+ }
+ }
+ $output.="\n";
+ my @order;
+ if (ref($order) eq 'ARRAY') {
+ @order = @{$order};
+ } else {
+ @order = sort(keys(%$hash));
+ }
+ if (exists($$hash{'select_form_order'})) {
+ @order = @{$$hash{'select_form_order'}};
+ }
+
+ foreach my $key (@order) {
+ $output.='&').'" ';
+ $output.='selected="selected" ' if ($selected{$key});
+ $output.='>'.$hash->{$key}." \n";
+ }
+ $output.=" \n";
+ return $output;
+}
+
#-------------------------------------------
=pod
-=item get_domains()
+=item * &select_form($defdom,$name,%hash)
-Returns an array containing each of the domains listed in the hosts.tab
-file.
+Returns a string containing a form to
+allow a user to select options from a hash option_name => displayed text.
+See lonrights.pm for an example invocation and use.
=cut
#-------------------------------------------
-sub get_domains {
- # The code below was stolen from "The Perl Cookbook", p 102, 1st ed.
- my @domains;
- my %seen;
- foreach (sort values(%Apache::lonnet::hostdom)) {
- push (@domains,$_) unless $seen{$_}++;
+sub select_form {
+ my ($def,$name,%hash) = @_;
+ my $selectform = "\n";
+ my @keys;
+ if (exists($hash{'select_form_order'})) {
+ @keys=@{$hash{'select_form_order'}};
+ } else {
+ @keys=sort(keys(%hash));
+ }
+ foreach my $key (@keys) {
+ $selectform.=
+ '&').'" '.
+ ($key eq $def ? 'selected="selected" ' : '').
+ ">".&mt($hash{$key})." \n";
+ }
+ $selectform.=" ";
+ return $selectform;
+}
+
+# For display filters
+
+sub display_filter {
+ if (!$env{'form.show'}) { $env{'form.show'}=10; }
+ if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
+ return ''.&mt('Records [_1]',
+ &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
+ (&mt('all'),10,20,50,100,1000,10000))).
+ ' '.
+ &mt('Filter [_1]',
+ &select_form($env{'form.displayfilter'},
+ 'displayfilter',
+ ('currentfolder' => 'Current folder/page',
+ 'containing' => 'Containing phrase',
+ 'none' => 'None'))).
+ ' ';
+}
+
+sub gradeleveldescription {
+ my $gradelevel=shift;
+ my %gradelevels=(0 => 'Not specified',
+ 1 => 'Grade 1',
+ 2 => 'Grade 2',
+ 3 => 'Grade 3',
+ 4 => 'Grade 4',
+ 5 => 'Grade 5',
+ 6 => 'Grade 6',
+ 7 => 'Grade 7',
+ 8 => 'Grade 8',
+ 9 => 'Grade 9',
+ 10 => 'Grade 10',
+ 11 => 'Grade 11',
+ 12 => 'Grade 12',
+ 13 => 'Grade 13',
+ 14 => '100 Level',
+ 15 => '200 Level',
+ 16 => '300 Level',
+ 17 => '400 Level',
+ 18 => 'Graduate Level');
+ return &mt($gradelevels{$gradelevel});
+}
+
+sub select_level_form {
+ my ($deflevel,$name)=@_;
+ unless ($deflevel) { $deflevel=0; }
+ my $selectform = "\n";
+ for (my $i=0; $i<=18; $i++) {
+ $selectform.="".&gradeleveldescription($i)." \n";
}
- return @domains;
+ $selectform.=" ";
+ return $selectform;
}
#-------------------------------------------
=pod
-=item select_dom_form($defdom,$name)
+=item * &select_dom_form($defdom,$name,$includeempty,$showdomdesc)
Returns a string containing a form to
allow a user to select the domain to preform an operation in.
See loncreateuser.pm for an example invocation and use.
+If the $includeempty flag is set, it also includes an empty choice ("no domain
+selected");
+
+If the $showdomdesc flag is set, the domain name is followed by the domain description.
+
=cut
#-------------------------------------------
sub select_dom_form {
- my ($defdom,$name) = @_;
- my @domains = get_domains();
+ my ($defdom,$name,$includeempty,$showdomdesc) = @_;
+ my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
+ if ($includeempty) { @domains=('',@domains); }
my $selectdomain = "\n";
- foreach (@domains) {
- $selectdomain.="$_ \n";
+ foreach my $dom (@domains) {
+ $selectdomain.="'.$dom;
+ if ($showdomdesc) {
+ if ($dom ne '') {
+ my $domdesc = &Apache::lonnet::domain($dom,'description');
+ if ($domdesc ne '') {
+ $selectdomain .= ' ('.$domdesc.')';
+ }
+ }
+ }
+ $selectdomain .= " \n";
}
$selectdomain.=" ";
return $selectdomain;
@@ -626,51 +1727,149 @@ sub select_dom_form {
=pod
-=item get_library_servers($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)
+ $hostid $servers{$hostid}
+ $hostid $servers{$hostid}
+
+ form item if there are multiple library servers in $domain, or
+ (ii) an form item
+ if there is only one library server in $domain.
+
+(b) number of library servers found.
-Returns a hash which contains keys like '103l3' and values like
-'kirk.lite.msu.edu'. All of the keys will be for machines in the
-given $domain.
+See loncreateuser.pm for example of use.
=cut
#-------------------------------------------
-sub get_library_servers {
- my $domain = shift;
- my %library_servers;
- foreach (keys(%Apache::lonnet::libserv)) {
- if ($Apache::lonnet::hostdom{$_} eq $domain) {
- $library_servers{$_} = $Apache::lonnet::hostname{$_};
+sub home_server_form_item {
+ my ($domain,$name,$default,$hide) = @_;
+ my %servers = &Apache::lonnet::get_servers($domain,'library');
+ my $result;
+ my $numlib = keys(%servers);
+ if ($numlib > 1) {
+ $result .= ' '."\n";
+ if ($default) {
+ $result .= ''.&mt('default').
+ ' '."\n";
+ }
+ foreach my $hostid (sort(keys(%servers))) {
+ $result.= ''.
+ $hostid.' '.$servers{$hostid}." \n";
+ }
+ $result .= ' '."\n";
+ } elsif ($numlib == 1) {
+ my $hostid;
+ foreach my $item (keys(%servers)) {
+ $hostid = $item;
}
+ $result .= ' ';
+ if (!$hide) {
+ $result .= $hostid.' '.$servers{$hostid};
+ }
+ $result .= "\n";
+ } elsif ($default) {
+ $result .= ' ';
+ if (!$hide) {
+ $result .= &mt('default');
+ }
+ $result .= "\n";
}
- return %library_servers;
+ return ($result,$numlib);
}
-#-------------------------------------------
+=pod
+
+=back
+
+=cut
+
+###############################################################
+## Decoding User Agent ##
+###############################################################
=pod
-=item home_server_option_list($domain)
+=head1 Decoding the User Agent
-returns a string which contains an list to be used in a
- form input. See loncreateuser.pm for an example.
+=over 4
+
+=item * &decode_user_agent()
+
+Inputs: $r
+
+Outputs:
+
+=over 4
+
+=item * $httpbrowser
+
+=item * $clientbrowser
+
+=item * $clientversion
+
+=item * $clientmathml
+
+=item * $clientunicode
+
+=item * $clientos
+
+=back
+
+=back
=cut
-#-------------------------------------------
-sub home_server_option_list {
- my $domain = shift;
- my %servers = &get_library_servers($domain);
- my $result = '';
- foreach (sort keys(%servers)) {
- $result.=
- ''.$_.' '.$servers{$_}." \n";
- }
- return $result;
-}
###############################################################
-## End of home server list generating code ##
###############################################################
+sub decode_user_agent {
+ my ($r)=@_;
+ my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
+ my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
+ my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
+ if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
+ my $clientbrowser='unknown';
+ my $clientversion='0';
+ my $clientmathml='';
+ my $clientunicode='0';
+ for (my $i=0;$i<=$#browsertype;$i++) {
+ my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
+ if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
+ $clientbrowser=$bname;
+ $httpbrowser=~/$vreg/i;
+ $clientversion=$1;
+ $clientmathml=($clientversion>=$minv);
+ $clientunicode=($clientversion>=$univ);
+ }
+ }
+ my $clientos='unknown';
+ if (($httpbrowser=~/linux/i) ||
+ ($httpbrowser=~/unix/i) ||
+ ($httpbrowser=~/ux/i) ||
+ ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
+ if (($httpbrowser=~/vax/i) ||
+ ($httpbrowser=~/vms/i)) { $clientos='vms'; }
+ if ($httpbrowser=~/next/i) { $clientos='next'; }
+ if (($httpbrowser=~/mac/i) ||
+ ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
+ if ($httpbrowser=~/win/i) { $clientos='win'; }
+ if ($httpbrowser=~/embed/i) { $clientos='pda'; }
+ return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
+ $clientunicode,$clientos,);
+}
###############################################################
## Authentication changing form generation subroutines ##
@@ -684,30 +1883,34 @@ sub home_server_option_list {
=pod
-=item authform_xxxxxx
+=head1 Authentication Routines
+
+=over 4
+
+=item * &authform_xxxxxx()
The authform_xxxxxx subroutines provide javascript and html forms which
handle some of the conveniences required for authentication forms.
This is not an optimal method, but it works.
-See loncreateuser.pm for invocation and use examples.
-
=over 4
-=item authform_header
+=item * authform_header
-=item authform_authorwarning
+=item * authform_authorwarning
-=item authform_nochange
+=item * authform_nochange
-=item authform_kerberos
+=item * authform_kerberos
-=item authform_internal
+=item * authform_internal
-=item authform_filesystem
+=item * authform_filesystem
=back
+See loncreateuser.pm for invocation and use examples.
+
=cut
#-------------------------------------------
@@ -735,10 +1938,27 @@ END
$Javascript_toUpperCase = "";
}
+ my $radioval = "'nochange'";
+ if (defined($in{'curr_authtype'})) {
+ if ($in{'curr_authtype'} ne '') {
+ $radioval = "'".$in{'curr_authtype'}."arg'";
+ }
+ }
+ my $argfield = 'null';
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifycourse') {
+ if (defined($in{'curr_autharg'})) {
+ if ($in{'curr_autharg'} ne '') {
+ $argfield = "'$in{'curr_autharg'}'";
+ }
+ }
+ }
+ }
+
$result.=<<"END";
var current = new Object();
-current.radiovalue = 'nochange';
-current.argfield = null;
+current.radiovalue = $radioval;
+current.argfield = $argfield;
function changed_radio(choice,currentform) {
var choicearg = choice + 'arg';
@@ -798,10 +2018,10 @@ END
sub authform_authorwarning{
my $result='';
- $result=<<"END";
-As a general rule, only authors or co-authors should be filesystem
-authenticated (which allows access to the server filesystem).
-END
+ $result=''.
+ &mt('As a general rule, only authors or co-authors should be '.
+ 'filesystem authenticated '.
+ '(which allows access to the server filesystem).')." \n";
return $result;
}
@@ -811,58 +2031,181 @@ sub authform_nochange{
kerb_def_dom => 'MSU.EDU',
@_,
);
- my $result='';
- $result.=<<"END";
-
-Do not change login data
-END
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ my $result;
+ if (keys(%can_assign) == 0) {
+ $result = &mt('Under you current role you are not permitted to change login settings for this user');
+ } else {
+ $result = ''.&mt('[_1] Do not change login data',
+ ' ').
+ ' ';
+ }
return $result;
}
-sub authform_kerberos{
+sub authform_kerberos {
my %in = (
formname => 'document.cu',
kerb_def_dom => 'MSU.EDU',
kerb_def_auth => 'krb4',
@_,
);
- my $result='';
- my $check4;
- my $check5;
+ my ($check4,$check5,$krbcheck,$krbarg,$krbver,$result,$authtype,
+ $autharg,$jscall);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
if ($in{'kerb_def_auth'} eq 'krb5') {
- $check5 = " checked=\"on\"";
+ $check5 = ' checked="on"';
} else {
- $check4 = " checked=\"on\"";
+ $check4 = ' checked="on"';
+ }
+ $krbarg = $in{'kerb_def_dom'};
+ if (defined($in{'curr_authtype'})) {
+ if ($in{'curr_authtype'} eq 'krb') {
+ $krbcheck = ' checked="on"';
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifyuser') {
+ $krbcheck = '';
+ }
+ }
+ if (defined($in{'curr_kerb_ver'})) {
+ if ($in{'curr_krb_ver'} eq '5') {
+ $check5 = ' checked="on"';
+ $check4 = '';
+ } else {
+ $check4 = ' checked="on"';
+ $check5 = '';
+ }
+ }
+ if (defined($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 = ' ';
+ }
+ }
+ if (!$can_assign{'krb4'} && !$can_assign{'krb5'}) {
+ return;
+ } elsif ($authtype eq '') {
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifycourse') {
+ if ($authnum == 1) {
+ $authtype = ' ';
+ }
+ }
+ }
+ }
+ $jscall = "javascript:changed_radio('krb',$in{'formname'});";
+ if ($authtype eq '') {
+ $authtype = ' ';
+ }
+ 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] '.
+ '[_3] Version 4 [_4] Version 5 [_5]',
+ ''.$authtype,
+ ' ',
+ ' ',
+ ' ',
+ ' ');
+ } elsif ($can_assign{'krb4'}) {
+ $result .= &mt
+ ('[_1] Kerberos authenticated with domain [_2] '.
+ '[_3] Version 4 [_4]',
+ ''.$authtype,
+ ' ',
+ ' ',
+ ' ');
+ } elsif ($can_assign{'krb5'}) {
+ $result .= &mt
+ ('[_1] Kerberos authenticated with domain [_2] '.
+ '[_3] Version 5 [_4]',
+ ''.$authtype,
+ ' ',
+ ' ',
+ ' ');
}
- $result.=<<"END";
-
-Kerberos authenticated with domain
-
- Version 4
- Version 5
-END
return $result;
}
sub authform_internal{
- my %args = (
+ my %in = (
formname => 'document.cu',
kerb_def_dom => 'MSU.EDU',
@_,
);
- my $result='';
- $result.=<<"END";
-
-Internally authenticated (with initial password
- )
-END
+ my ($intcheck,$intarg,$result,$authtype,$autharg,$jscall);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ if (defined($in{'curr_authtype'})) {
+ if ($in{'curr_authtype'} eq 'int') {
+ if ($can_assign{'int'}) {
+ $intcheck = 'checked="on" ';
+ 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 = ' ';
+ }
+ }
+ if (!$can_assign{'int'}) {
+ return;
+ } elsif ($authtype eq '') {
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifycourse') {
+ if ($authnum == 1) {
+ $authtype = ' ';
+ }
+ }
+ }
+ }
+ $jscall = "javascript:changed_radio('int',$in{'formname'});";
+ if ($authtype eq '') {
+ $authtype = ' ';
+ }
+ $autharg = ' ';
+ $result = &mt
+ ('[_1] Internally authenticated (with initial password [_2])',
+ ''.$authtype,' '.$autharg);
+ $result.=" ".&mt('Visible input').' ';
return $result;
}
@@ -872,15 +2215,51 @@ sub authform_local{
kerb_def_dom => 'MSU.EDU',
@_,
);
- my $result='';
- $result.=<<"END";
-
-Local Authentication with argument
-
-END
+ my ($loccheck,$locarg,$result,$authtype,$autharg,$jscall);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ if (defined($in{'curr_authtype'})) {
+ if ($in{'curr_authtype'} eq 'loc') {
+ if ($can_assign{'loc'}) {
+ $loccheck = 'checked="on" ';
+ 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 = ' ';
+ }
+ }
+ if (!$can_assign{'loc'}) {
+ return;
+ } elsif ($authtype eq '') {
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifycourse') {
+ if ($authnum == 1) {
+ $authtype = ' ';
+ }
+ }
+ }
+ }
+ $jscall = "javascript:changed_radio('loc',$in{'formname'});";
+ if ($authtype eq '') {
+ $authtype = ' ';
+ }
+ $autharg = ' ';
+ $result = &mt('[_1] Local Authentication with argument [_2]',
+ ''.$authtype,' '.$autharg);
return $result;
}
@@ -890,59 +2269,96 @@ sub authform_filesystem{
kerb_def_dom => 'MSU.EDU',
@_,
);
- my $result='';
- $result.=<<"END";
-
-Filesystem authenticated (with initial password
- )
-END
+ my ($fsyscheck,$result,$authtype,$autharg,$jscall);
+ my ($authnum,%can_assign) = &get_assignable_auth($in{'domain'});
+ if (defined($in{'curr_authtype'})) {
+ if ($in{'curr_authtype'} eq 'fsys') {
+ if ($can_assign{'fsys'}) {
+ $fsyscheck = 'checked="on" ';
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifyuser') {
+ $fsyscheck = '';
+ }
+ }
+ } else {
+ $result = &mt('Currently Filesystem Authenticated.');
+ return $result;
+ }
+ }
+ } else {
+ if ($authnum == 1) {
+ $authtype = ' ';
+ }
+ }
+ if (!$can_assign{'fsys'}) {
+ return;
+ } elsif ($authtype eq '') {
+ if (defined($in{'mode'})) {
+ if ($in{'mode'} eq 'modifycourse') {
+ if ($authnum == 1) {
+ $authtype = ' ';
+ }
+ }
+ }
+ }
+ $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
+ if ($authtype eq '') {
+ $authtype = ' ';
+ }
+ $autharg = ' ';
+ $result = &mt
+ ('[_1] Filesystem Authenticated (with initial password [_2])',
+ ' ',
+ ' ');
return $result;
}
-###############################################################
-## End Authentication changing form generation functions ##
-###############################################################
-
-###############################################################
-## Get Authentication Defaults for Domain ##
-###############################################################
-##
-## Returns default authentication type and an associated argument
-## as listed in file domain.tab
-##
-#-------------------------------------------
-
-=pod
-
-=item get_auth_defaults
-
-get_auth_defaults($target_domain) returns the default authentication
-type and an associated argument (initial password or a kerberos domain).
-These values are stored in lonTabs/domain.tab
-
-($def_auth, $def_arg) = &get_auth_defaults($target_domain);
-
-If target_domain is not found in domain.tab, returns nothing ('').
-
-=over 4
-
-=item get_auth_defaults
-
-=back
-
-=cut
-
-#-------------------------------------------
-sub get_auth_defaults {
- my $domain=shift;
- return ($Apache::lonnet::domain_auth_def{$domain},$Apache::lonnet::domain_auth_arg_def{$domain});
+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/) {
+ $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);
}
-###############################################################
-## End Get Authentication Defaults for Domain ##
-###############################################################
###############################################################
## Get Kerberos Defaults for Domain ##
@@ -956,17 +2372,17 @@ sub get_auth_defaults {
=pod
-=item get_kerberos_defaults
+=item * &get_kerberos_defaults()
get_kerberos_defaults($target_domain) returns the default kerberos
-version and domain. If not found in domain.tabs, it defaults to
-version 4 and the domain of the server.
-
-($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
+version and domain. If not found, it defaults to version 4 and the
+domain of the server.
=over 4
-=item get_kerberos_defaults
+($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
+
+=back
=back
@@ -975,9 +2391,12 @@ version 4 and the domain of the server.
#-------------------------------------------
sub get_kerberos_defaults {
my $domain=shift;
- my ($krbdef,$krbdefdom) =
- &Apache::loncommon::get_auth_defaults($domain);
- unless ($krbdef =~/^krb/ && $krbdefdom) {
+ my ($krbdef,$krbdefdom);
+ my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
+ 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+)$/;
my $krbdefdom=$1;
$krbdefdom=~tr/a-z/A-Z/;
@@ -985,9 +2404,7 @@ sub get_kerberos_defaults {
}
return ($krbdef,$krbdefdom);
}
-###############################################################
-## End Get Kerberos Defaults for Domain ##
-###############################################################
+
###############################################################
## Thesaurus Functions ##
@@ -995,7 +2412,11 @@ sub get_kerberos_defaults {
=pod
-=item initialize_keywords
+=head1 Thesaurus Functions
+
+=over 4
+
+=item * &initialize_keywords()
Initializes the package variable %Keywords if it is empty. Uses the
package variable $thesaurus_db_file.
@@ -1030,9 +2451,9 @@ sub initialize_keywords {
}
untie %thesaurus_db;
# Remove special values from %Keywords.
- foreach ('total.count','average.count') {
- delete($Keywords{$_}) if (exists($Keywords{$_}));
- }
+ foreach my $value ('total.count','average.count') {
+ delete($Keywords{$value}) if (exists($Keywords{$value}));
+ }
return 1;
}
@@ -1040,7 +2461,7 @@ sub initialize_keywords {
=pod
-=item keyword($word)
+=item * &keyword($word)
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
@@ -1061,9 +2482,9 @@ sub keyword {
=pod
-=item get_related_words
+=item * &get_related_words()
-Look up a word in the thesaurus. Takes a scalar arguement 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
will be returned. The order of the words returned is determined by the
database which holds them.
@@ -1086,43 +2507,86 @@ sub get_related_words {
return ();
}
my @Words=();
+ my $count=0;
if (exists($thesaurus_db{$keyword})) {
- $_ = $thesaurus_db{$keyword};
- (undef,@Words) = split/:/; # The first element is the number of times
- # the word appears. We do not need it now.
- for (my $i=0;$i<=$#Words;$i++) {
- ($Words[$i],undef)= split/\,/,$Words[$i];
+ # The first element is the number of times
+ # the word appears. We do not need it now.
+ my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
+ my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
+ my $threshold=$mostfrequentcount/10;
+ foreach my $possibleword (@RelatedWords) {
+ my ($word,$wordcount)=split(/\,/,$possibleword);
+ if ($wordcount>$threshold) {
+ push(@Words,$word);
+ $count++;
+ if ($count>10) { last; }
+ }
}
}
untie %thesaurus_db;
return @Words;
}
-###############################################################
-## End Thesaurus Functions ##
-###############################################################
+=pod
+
+=back
+
+=cut
# -------------------------------------------------------------- Plaintext name
+=pod
+=head1 User Name Functions
+
+=over 4
+
+=item * &plainname($uname,$udom,$first)
+
+Takes a users logon name and returns it as a string in
+"first middle last generation" form
+if $first is set to 'lastname' then it returns it as
+'lastname generation, firstname middlename' if their is a lastname
+
+=cut
+
+
+###############################################################
sub plainname {
- my ($uname,$udom)=@_;
- my %names=&Apache::lonnet::get('environment',
- ['firstname','middlename','lastname','generation'],
- $udom,$uname);
- my $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
- $names{'lastname'}.' '.$names{'generation'};
+ my ($uname,$udom,$first)=@_;
+ return if (!defined($uname) || !defined($udom));
+ my %names=&getnames($uname,$udom);
+ my $name=&Apache::lonnet::format_name($names{'firstname'},
+ $names{'middlename'},
+ $names{'lastname'},
+ $names{'generation'},$first);
+ $name=~s/^\s+//;
$name=~s/\s+$//;
$name=~s/\s+/ /g;
+ if ($name !~ /\S/) { $name=$uname.':'.$udom; }
return $name;
}
# -------------------------------------------------------------------- Nickname
+=pod
+=item * &nickname($uname,$udom)
+
+Gets a users name and returns it as a string as
+
+""nickname""
+
+if the user has a nickname or
+
+"first middle last generation"
+
+if the user does not
+
+=cut
sub nickname {
my ($uname,$udom)=@_;
- my %names=&Apache::lonnet::get('environment',
- ['nickname','firstname','middlename','lastname','generation'],$udom,$uname);
+ return if (!defined($uname) || !defined($udom));
+ my %names=&getnames($uname,$udom);
my $name=$names{'nickname'};
if ($name) {
$name='"'.$name.'"';
@@ -1135,22 +2599,99 @@ sub nickname {
return $name;
}
+sub getnames {
+ my ($uname,$udom)=@_;
+ return if (!defined($uname) || !defined($udom));
+ if ($udom eq 'public' && $uname eq 'public') {
+ return ('lastname' => &mt('Public'));
+ }
+ my $id=$uname.':'.$udom;
+ my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
+ if ($cached) {
+ return %{$names};
+ } else {
+ my %loadnames=&Apache::lonnet::get('environment',
+ ['firstname','middlename','lastname','generation','nickname'],
+ $udom,$uname);
+ &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
+ return %loadnames;
+ }
+}
+
+# -------------------------------------------------------------------- getemails
+
+=pod
+
+=item * &getemails($uname,$udom)
+
+Gets a user's email information and returns it as a hash with keys:
+notification, critnotification, permanentemail
+
+For notification and critnotification, values are comma-separated lists
+of e-mail addresses; for permanentemail, value is a single e-mail address.
+
+
+=cut
+
+
+sub getemails {
+ my ($uname,$udom)=@_;
+ if ($udom eq 'public' && $uname eq 'public') {
+ return;
+ }
+ if (!$udom) { $udom=$env{'user.domain'}; }
+ if (!$uname) { $uname=$env{'user.name'}; }
+ my $id=$uname.':'.$udom;
+ my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
+ if ($cached) {
+ return %{$names};
+ } else {
+ my %loadnames=&Apache::lonnet::get('environment',
+ ['notification','critnotification',
+ 'permanentemail'],
+ $udom,$uname);
+ &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
+ return %loadnames;
+ }
+}
+
+sub flush_email_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('emailscache',$id);
+}
# ------------------------------------------------------------------ Screenname
+=pod
+
+=item * &screenname($uname,$udom)
+
+Gets a users screenname and returns it as a string
+
+=cut
+
sub screenname {
my ($uname,$udom)=@_;
- my %names=
- &Apache::lonnet::get('environment',['screenname'],$udom,$uname);
+ if ($uname eq $env{'user.name'} &&
+ $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
+ my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
return $names{'screenname'};
}
+
# ------------------------------------------------------------- Message Wrapper
sub messagewrapper {
- my ($link,$un,$do)=@_;
+ my ($link,$username,$domain,$subject,$text)=@_;
return
-"$link ";
+ ''.$link.' ';
}
# --------------------------------------------------------------- Notes Wrapper
@@ -1162,82 +2703,367 @@ sub noteswrapper {
# ------------------------------------------------------------- Aboutme Wrapper
sub aboutmewrapper {
- my ($link,$username,$domain)=@_;
- return "$link ";
+ my ($link,$username,$domain,$target)=@_;
+ if (!defined($username) && !defined($domain)) {
+ return;
+ }
+ return ''.$link.' ';
}
# ------------------------------------------------------------ Syllabus Wrapper
sub syllabuswrapper {
- my ($link,$un,$do,$tf)=@_;
- if ($tf) { $link=''.$link.' '; }
- return "$link ";
+ my ($linktext,$coursedir,$domain,$fontcolor)=@_;
+ if ($fontcolor) {
+ $linktext=''.$linktext.' ';
+ }
+ return qq{$linktext };
+}
+
+sub track_student_link {
+ my ($linktext,$sname,$sdom,$target,$start) = @_;
+ my $link ="/adm/trackstudent?";
+ my $title = 'View recent activity';
+ if (defined($sname) && $sname !~ /^\s*$/ &&
+ defined($sdom) && $sdom !~ /^\s*$/) {
+ $link .= "selected_student=$sname:$sdom";
+ $title .= ' of this student';
+ }
+ if (defined($target) && $target !~ /^\s*$/) {
+ $target = qq{target="$target"};
+ } else {
+ $target = '';
+ }
+ if ($start) { $link.='&start='.$start; }
+ $title = &mt($title);
+ $linktext = &mt($linktext);
+ return qq{$linktext }.
+ &help_open_topic('View_recent_activity');
+}
+
+# ===================================================== Display a student photo
+
+
+sub student_image_tag {
+ my ($domain,$user)=@_;
+ my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
+ if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
+ return ' ';
+ } else {
+ return '';
+ }
}
-# ---------------------------------------------------------------- Language IDs
+=pod
+
+=back
+
+=head1 Access .tab File Data
+
+=over 4
+
+=item * &languageids()
+
+returns list of all language ids
+
+=cut
+
sub languageids {
return sort(keys(%language));
}
-# -------------------------------------------------------- Language Description
+=pod
+
+=item * &languagedescription()
+
+returns description of a specified language id
+
+=cut
+
sub languagedescription {
- return $language{shift(@_)};
+ my $code=shift;
+ return ($supported_language{$code}?'* ':'').
+ $language{$code}.
+ ($supported_language{$code}?' ('.&mt('interface available').')':'');
+}
+
+sub plainlanguagedescription {
+ my $code=shift;
+ return $language{$code};
}
-# --------------------------------------------------------------- Copyright IDs
+sub supportedlanguagecode {
+ my $code=shift;
+ return $supported_language{$code};
+}
+
+=pod
+
+=item * ©rightids()
+
+returns list of all copyrights
+
+=cut
+
sub copyrightids {
return sort(keys(%cprtag));
}
-# ------------------------------------------------------- Copyright Description
+=pod
+
+=item * ©rightdescription()
+
+returns description of a specified copyright id
+
+=cut
+
sub copyrightdescription {
- return $cprtag{shift(@_)};
+ return &mt($cprtag{shift(@_)});
+}
+
+=pod
+
+=item * &source_copyrightids()
+
+returns list of all source copyrights
+
+=cut
+
+sub source_copyrightids {
+ return sort(keys(%scprtag));
}
-# ------------------------------------------------------------- File Categories
+=pod
+
+=item * &source_copyrightdescription()
+
+returns description of a specified source copyright id
+
+=cut
+
+sub source_copyrightdescription {
+ return &mt($scprtag{shift(@_)});
+}
+
+=pod
+
+=item * &filecategories()
+
+returns list of all file categories
+
+=cut
+
sub filecategories {
return sort(keys(%category_extensions));
}
-# -------------------------------------- File Types within a specified category
+=pod
+
+=item * &filecategorytypes()
+
+returns list of file types belonging to a given file
+category
+
+=cut
+
sub filecategorytypes {
- return @{$category_extensions{lc($_[0])}};
+ my ($cat) = @_;
+ return @{$category_extensions{lc($cat)}};
}
-# ------------------------------------------------------------------ File Types
-sub fileextensions {
- return sort(keys(%fe));
-}
+=pod
+
+=item * &fileembstyle()
+
+returns embedding style for a specified file type
+
+=cut
-# ------------------------------------------------------------- Embedding Style
sub fileembstyle {
return $fe{lc(shift(@_))};
}
-# ------------------------------------------------------------ Description Text
+sub filemimetype {
+ return $fm{lc(shift(@_))};
+}
+
+
+sub filecategoryselect {
+ my ($name,$value)=@_;
+ return &select_form($value,$name,
+ '' => &mt('Any category'),
+ map { $_,$_ } sort(keys(%category_extensions)));
+}
+
+=pod
+
+=item * &filedescription()
+
+returns description for a specified file type
+
+=cut
+
sub filedescription {
- return $fd{lc(shift(@_))};
+ my $file_description = $fd{lc(shift())};
+ $file_description =~ s:([\[\]]):~$1:g;
+ return &mt($file_description);
}
-# ------------------------------------------------------------ Description Text
+=pod
+
+=item * &filedescriptionex()
+
+returns description for a specified file type with
+extra formatting
+
+=cut
+
sub filedescriptionex {
my $ex=shift;
- return '.'.$ex.' '.$fd{lc($ex)};
+ my $file_description = $fd{lc($ex)};
+ $file_description =~ s:([\[\]]):~$1:g;
+ return '.'.$ex.' '.&mt($file_description);
+}
+
+# End of .tab access
+=pod
+
+=back
+
+=cut
+
+# ------------------------------------------------------------------ File Types
+sub fileextensions {
+ return sort(keys(%fe));
}
-# ---- Retrieve attempts by students
-# input
-# $symb - problem including path
-# $username,$domain - that of the student
-# $course - course name
-# $getattempt - leave blank if want all attempts, else put something.
-# $regexp - regular expression. If string matches regexp send to
-# $gradesub - routine that process the string if it matches regexp
-#
-# output
-# formatted as a table all the attempts, if any.
+# ----------------------------------------------------------- Display Languages
+# returns a hash with all desired display languages
#
+
+sub display_languages {
+ my %languages=();
+ foreach my $lang (&preferred_languages()) {
+ $languages{$lang}=1;
+ }
+ &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
+ if ($env{'form.displaylanguage'}) {
+ foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
+ $languages{$lang}=1;
+ }
+ }
+ return %languages;
+}
+
+sub preferred_languages {
+ my @languages=();
+ if (($env{'request.role.adv'}) && ($env{'form.languages'})) {
+ @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$env{'form.languages'}));
+ }
+ if ($env{'course.'.$env{'request.course.id'}.'.languages'}) {
+ @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,
+ $env{'course.'.$env{'request.course.id'}.'.languages'}));
+ }
+
+ if ($env{'environment.languages'}) {
+ @languages=(@languages,
+ split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'}));
+ }
+ my $browser=$ENV{'HTTP_ACCEPT_LANGUAGE'};
+ if ($browser) {
+ my @browser =
+ map { (split(/\s*;\s*/,$_))[0] } (split(/\s*,\s*/,$browser));
+ push(@languages,@browser);
+ }
+
+ foreach my $domtype ($env{'user.domain'},$env{'request.role.domain'},
+ $Apache::lonnet::perlvar{'lonDefDomain'}) {
+ if ($domtype ne '') {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($domtype);
+ if ($domdefs{'lang_def'} ne '') {
+ push(@languages,$domdefs{'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]);
+ }
+ }
+ #uniqueify the languages list
+ my %count;
+ @genlanguages = map { $count{$_}++ == 0 ? $_ : () } @genlanguages;
+ return @genlanguages;
+}
+
+sub languages {
+ my ($possible_langs) = @_;
+ my @preferred_langs = &preferred_languages();
+ if (!ref($possible_langs)) {
+ if( wantarray ) {
+ return @preferred_langs;
+ } else {
+ return $preferred_langs[0];
+ }
+ }
+ my %possibilities = map { $_ => 1 } (@$possible_langs);
+ my @preferred_possibilities;
+ foreach my $preferred_lang (@preferred_langs) {
+ if (exists($possibilities{$preferred_lang})) {
+ push(@preferred_possibilities, $preferred_lang);
+ }
+ }
+ if( wantarray ) {
+ return @preferred_possibilities;
+ }
+ return $preferred_possibilities[0];
+}
+
+###############################################################
+## Student Answer Attempts ##
+###############################################################
+
+=pod
+
+=head1 Alternate Problem Views
+
+=over 4
+
+=item * &get_previous_attempt($symb, $username, $domain, $course,
+ $getattempt, $regexp, $gradesub)
+
+Return string with previous attempt on problem. Arguments:
+
+=over 4
+
+=item * $symb: Problem, including path
+
+=item * $username: username of the desired student
+
+=item * $domain: domain of the desired student
+
+=item * $course: Course ID
+
+=item * $getattempt: Leave blank for all attempts, otherwise put
+ something
+
+=item * $regexp: if string matches this regexp, the string will be
+ sent to $gradesub
+
+=item * $gradesub: routine that processes the string if it matches $regexp
+
+=back
+
+The output string is a table containing all desired attempts, if any.
+
+=cut
+
sub get_previous_attempt {
my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
my $prevattempts='';
@@ -1249,18 +3075,18 @@ sub get_previous_attempt {
my %lasthash=();
my $version;
for ($version=1;$version<=$returnhash{'version'};$version++) {
- foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
- $lasthash{$_}=$returnhash{$version.':'.$_};
+ foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
+ $lasthash{$key}=$returnhash{$version.':'.$key};
}
}
- $prevattempts='';
- $prevattempts.='History ';
- foreach (sort(keys %lasthash)) {
- my ($ign,@parts) = split(/\./,$_);
+ $prevattempts=&start_data_table().&start_data_table_header_row();
+ $prevattempts.=''.&mt('History').' ';
+ foreach my $key (sort(keys(%lasthash))) {
+ my ($ign,@parts) = split(/\./,$key);
if ($#parts > 0) {
my $data=$parts[-1];
pop(@parts);
- $prevattempts.='Part '.join('.',@parts).' '.$data.' ';
+ $prevattempts.=''.&mt('Part ').join('.',@parts).' '.$data.' ';
} else {
if ($#parts == 0) {
$prevattempts.=''.$parts[0].' ';
@@ -1269,56 +3095,110 @@ sub get_previous_attempt {
}
}
}
+ $prevattempts.=&end_data_table_header_row();
if ($getattempt eq '') {
for ($version=1;$version<=$returnhash{'version'};$version++) {
- $prevattempts.='Transaction '.$version.' ';
- foreach (sort(keys %lasthash)) {
- my $value;
- if ($_ =~ /timestamp/) {
- $value=scalar(localtime($returnhash{$version.':'.$_}));
- } else {
- $value=$returnhash{$version.':'.$_};
- }
- $prevattempts.=''.$value.' ';
+ $prevattempts.=&start_data_table_row().
+ ''.&mt('Transaction [_1]',$version).' ';
+ foreach my $key (sort(keys(%lasthash))) {
+ my $value = &format_previous_attempt_value($key,
+ $returnhash{$version.':'.$key});
+ $prevattempts.=''.$value.' ';
}
+ $prevattempts.=&end_data_table_row();
}
}
- $prevattempts.='Current ';
- foreach (sort(keys %lasthash)) {
- my $value;
- if ($_ =~ /timestamp/) {
- $value=scalar(localtime($lasthash{$_}));
- } else {
- $value=$lasthash{$_};
- }
- if ($_ =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
+ $prevattempts.=&start_data_table_row().''.&mt('Current').' ';
+ foreach my $key (sort(keys(%lasthash))) {
+ my $value = &format_previous_attempt_value($key,$lasthash{$key});
+ if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
$prevattempts.=''.$value.' ';
}
- $prevattempts.='
';
+ $prevattempts.= &end_data_table_row().&end_data_table();
} else {
- $prevattempts='Nothing submitted - no attempts.';
+ $prevattempts=
+ &start_data_table().&start_data_table_row().
+ ''.&mt('Nothing submitted - no attempts.').' '.
+ &end_data_table_row().&end_data_table();
}
} else {
- $prevattempts='No data.';
+ $prevattempts=
+ &start_data_table().&start_data_table_row().
+ ''.&mt('No data.').' '.
+ &end_data_table_row().&end_data_table();
}
}
+sub format_previous_attempt_value {
+ my ($key,$value) = @_;
+ if ($key =~ /timestamp/) {
+ $value = &Apache::lonlocal::locallocaltime($value);
+ } elsif (ref($value) eq 'ARRAY') {
+ $value = '('.join(', ', @{ $value }).')';
+ } else {
+ $value = &unescape($value);
+ }
+ return $value;
+}
+
+
+sub relative_to_absolute {
+ my ($url,$output)=@_;
+ my $parser=HTML::TokeParser->new(\$output);
+ my $token;
+ my $thisdir=$url;
+ my @rlinks=();
+ while ($token=$parser->get_token) {
+ if ($token->[0] eq 'S') {
+ if ($token->[1] eq 'a') {
+ if ($token->[2]->{'href'}) {
+ $rlinks[$#rlinks+1]=$token->[2]->{'href'};
+ }
+ } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
+ $rlinks[$#rlinks+1]=$token->[2]->{'src'};
+ } elsif ($token->[1] eq 'base') {
+ $thisdir=$token->[2]->{'href'};
+ }
+ }
+ }
+ $thisdir=~s-/[^/]*$--;
+ foreach my $link (@rlinks) {
+ unless (($link=~/^http:\/\//i) ||
+ ($link=~/^\//) ||
+ ($link=~/^javascript:/i) ||
+ ($link=~/^mailto:/i) ||
+ ($link=~/^\#/)) {
+ my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
+ $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
+ }
+ }
+# -------------------------------------------------- Deal with Applet codebases
+ $output=~s/(\]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
+ return $output;
+}
+
+=pod
+
+=item * &get_student_view()
+
+show a snapshot of what student was looking at
+
+=cut
+
sub get_student_view {
- my ($symb,$username,$domain,$courseid,$target) = @_;
- my ($map,$id,$feedurl) = split(/___/,$symb);
- my (%old,%moreenv);
+ my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
+ my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
+ my (%form);
my @elements=('symb','courseid','domain','username');
foreach my $element (@elements) {
- $old{$element}=$ENV{'form.grade_'.$element};
- $moreenv{'form.grade_'.$element}=eval '$'.$element #'
+ $form{'grade_'.$element}=eval '$'.$element #'
}
- if ($target eq 'tex') {$moreenv{'form.grade_target'} = 'tex';}
- &Apache::lonnet::appenv(%moreenv);
- my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
- &Apache::lonnet::delenv('form.grade_');
- foreach my $element (@elements) {
- $ENV{'form.grade_'.$element}=$old{$element};
+ if (defined($moreenv)) {
+ %form=(%form,%{$moreenv});
}
+ if (defined($target)) { $form{'grade_target'} = $target; }
+ $feedurl=&Apache::lonnet::clutter($feedurl);
+ my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
$userview=~s/\]*\>//gi;
$userview=~s/\<\/body\>//gi;
$userview=~s/\//gi;
@@ -1326,28 +3206,144 @@ sub get_student_view {
$userview=~s/\//gi;
$userview=~s/\<\/head\>//gi;
$userview=~s/action\s*\=/would_be_action\=/gi;
- return $userview;
+ $userview=&relative_to_absolute($feedurl,$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;
+ }
}
+=pod
+
+=item * &get_student_answers()
+
+show a snapshot of how student was answering problem
+
+=cut
+
sub get_student_answers {
- my ($symb,$username,$domain,$courseid) = @_;
- my ($map,$id,$feedurl) = split(/___/,$symb);
- my (%old,%moreenv);
+ my ($symb,$username,$domain,$courseid,%form) = @_;
+ my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
+ my (%moreenv);
my @elements=('symb','courseid','domain','username');
foreach my $element (@elements) {
- $old{$element}=$ENV{'form.grade_'.$element};
- $moreenv{'form.grade_'.$element}=eval '$'.$element #'
- }
- $moreenv{'form.grade_target'}='answer';
- &Apache::lonnet::appenv(%moreenv);
- my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
- &Apache::lonnet::delenv('form.grade_');
- foreach my $element (@elements) {
- $ENV{'form.grade_'.$element}=$old{$element};
+ $moreenv{'grade_'.$element}=eval '$'.$element #'
}
+ $moreenv{'grade_target'}='answer';
+ %moreenv=(%form,%moreenv);
+ $feedurl = &Apache::lonnet::clutter($feedurl);
+ my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
return $userview;
}
+=pod
+
+=item * &submlink()
+
+Inputs: $text $uname $udom $symb $target
+
+Returns: A link to grades.pm such as to see the SUBM view of a student
+
+=cut
+
+###############################################
+sub submlink {
+ my ($text,$uname,$udom,$symb,$target)=@_;
+ if (!($uname && $udom)) {
+ (my $cursymb, my $courseid,$udom,$uname)=
+ &Apache::lonnet::whichuser($symb);
+ if (!$symb) { $symb=$cursymb; }
+ }
+ if (!$symb) { $symb=&Apache::lonnet::symbread(); }
+ $symb=&escape($symb);
+ if ($target) { $target="target=\"$target\""; }
+ return ''.$text.' ';
+}
+##############################################
+
+=pod
+
+=item * &pgrdlink()
+
+Inputs: $text $uname $udom $symb $target
+
+Returns: A link to grades.pm such as to see the PGRD view of a student
+
+=cut
+
+###############################################
+sub pgrdlink {
+ my $link=&submlink(@_);
+ $link=~s/(&command=submission)/$1&showgrading=yes/;
+ return $link;
+}
+##############################################
+
+=pod
+
+=item * &pprmlink()
+
+Inputs: $text $uname $udom $symb $target
+
+Returns: A link to parmset.pm such as to see the PPRM view of a
+student and a specific resource
+
+=cut
+
+###############################################
+sub pprmlink {
+ my ($text,$uname,$udom,$symb,$target)=@_;
+ if (!($uname && $udom)) {
+ (my $cursymb, my $courseid,$udom,$uname)=
+ &Apache::lonnet::whichuser($symb);
+ if (!$symb) { $symb=$cursymb; }
+ }
+ if (!$symb) { $symb=&Apache::lonnet::symbread(); }
+ $symb=&escape($symb);
+ if ($target) { $target="target=\"$target\""; }
+ return ''.$text.' ';
+}
+##############################################
+
+=pod
+
+=back
+
+=cut
+
###############################################
@@ -1364,55 +3360,400 @@ sub timehash {
'dlsav' => $ltime[8] );
}
+sub utc_string {
+ my ($date)=@_;
+ return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
+}
+
sub maketime {
my %th=@_;
return POSIX::mktime(
($th{'seconds'},$th{'minutes'},$th{'hours'},
- $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,$th{'dlsav'}));
+ $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
}
-
#########################################
-#
-# Retro-fixing of un-backward-compatible time format
-sub unsqltime {
- my $timestamp=shift;
- if ($timestamp=~/^(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)$/) {
- $timestamp=&maketime(
- 'year'=>$1,'month'=>$2,'day'=>$3,
- 'hours'=>$4,'minutes'=>$5,'seconds'=>$6);
+sub findallcourses {
+ my ($roles,$uname,$udom) = @_;
+ my %roles;
+ if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
+ my %courses;
+ my $now=time;
+ if (!defined($uname)) {
+ $uname = $env{'user.name'};
+ }
+ if (!defined($udom)) {
+ $udom = $env{'user.domain'};
+ }
+ if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
+ my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
+ if (!%roles) {
+ %roles = (
+ cc => 1,
+ in => 1,
+ ep => 1,
+ ta => 1,
+ cr => 1,
+ st => 1,
+ );
+ }
+ foreach my $entry (keys(%roleshash)) {
+ my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
+ if ($trole =~ /^cr/) {
+ next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
+ } else {
+ next if (!exists($roles{$trole}));
+ }
+ if ($tend) {
+ next if ($tend < $now);
+ }
+ if ($tstart) {
+ next if ($tstart > $now);
+ }
+ my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
+ (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
+ if ($secpart eq '') {
+ ($cnum,$role) = split(/_/,$cnumpart);
+ $sec = 'none';
+ $realsec = '';
+ } else {
+ $cnum = $cnumpart;
+ ($sec,$role) = split(/_/,$secpart);
+ $realsec = $sec;
+ }
+ $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
+ }
+ } else {
+ foreach my $key (keys(%env)) {
+ if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
+ $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
+ my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
+ next if ($role eq 'ca' || $role eq 'aa');
+ next if (%roles && !exists($roles{$role}));
+ my ($starttime,$endtime)=split(/\./,$env{$key});
+ my $active=1;
+ if ($starttime) {
+ if ($now<$starttime) { $active=0; }
+ }
+ if ($endtime) {
+ if ($now>$endtime) { $active=0; }
+ }
+ if ($active) {
+ if ($sec eq '') {
+ $sec = 'none';
+ }
+ $courses{$cdom.'_'.$cnum}{$sec} =
+ $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
+ }
+ }
+ }
}
- return $timestamp;
+ return %courses;
}
-#########################################
+###############################################
-sub findallcourses {
- my %courses=();
- my $now=time;
- foreach (keys %ENV) {
- if ($_=~/^user\.role\.\w+\.\/(\w+)\/(\w+)/) {
- my ($starttime,$endtime)=$ENV{$_};
- my $active=1;
- if ($starttime) {
- if ($now<$starttime) { $active=0; }
+sub blockcheck {
+ my ($setters,$activity,$uname,$udom) = @_;
+
+ if (!defined($udom)) {
+ $udom = $env{'user.domain'};
+ }
+ if (!defined($uname)) {
+ $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 $endblock = 0;
+ my %live_courses = &findallcourses(undef,$uname,$udom);
+
+ # If uname is for a user, and activity is course-specific, i.e.,
+ # boards, chat or groups, check for blocking in current course only.
+
+ if (($activity eq 'boards' || $activity eq 'chat' ||
+ $activity eq 'groups') && ($env{'request.course.id'})) {
+ foreach my $key (keys(%live_courses)) {
+ if ($key ne $env{'request.course.id'}) {
+ delete($live_courses{$key});
}
- if ($endtime) {
- if ($now>$endtime) { $active=0; }
+ }
+ }
+
+ my $otheruser = 0;
+ my %own_courses;
+ if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
+ # Resource belongs to user other than current user.
+ $otheruser = 1;
+ # Gather courses for current user
+ %own_courses =
+ &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
+ }
+
+ # Gather active course roles - course coordinator, instructor,
+ # exam proctor, ta, student, or custom role.
+
+ foreach my $course (keys(%live_courses)) {
+ my ($cdom,$cnum);
+ if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
+ $cdom = $env{'course.'.$course.'.domain'};
+ $cnum = $env{'course.'.$course.'.num'};
+ } else {
+ ($cdom,$cnum) = split(/_/,$course);
+ }
+ my $no_ownblock = 0;
+ my $no_userblock = 0;
+ if ($otheruser && $activity ne 'com') {
+ # Check if current user has 'evb' priv for this
+ if (defined($own_courses{$course})) {
+ foreach my $sec (keys(%{$own_courses{$course}})) {
+ my $checkrole = 'cm./'.$cdom.'/'.$cnum;
+ if ($sec ne 'none') {
+ $checkrole .= '/'.$sec;
+ }
+ if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
+ $no_ownblock = 1;
+ last;
+ }
+ }
+ }
+ # if they have 'evb' priv and are currently not playing student
+ next if (($no_ownblock) &&
+ ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
+ }
+ foreach my $sec (keys(%{$live_courses{$course}})) {
+ my $checkrole = 'cm./'.$cdom.'/'.$cnum;
+ if ($sec ne 'none') {
+ $checkrole .= '/'.$sec;
+ }
+ if ($otheruser) {
+ # Resource belongs to user other than current user.
+ # Assemble privs for that user, and check for 'evb' priv.
+ my ($trole,$tdom,$tnum,$tsec);
+ my $entry = $live_courses{$course}{$sec};
+ if ($entry =~ /^cr/) {
+ ($trole,$tdom,$tnum,$tsec) =
+ ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
+ } else {
+ ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
+ }
+ my ($spec,$area,$trest,%allroles,%userroles);
+ $area = '/'.$tdom.'/'.$tnum;
+ $trest = $tnum;
+ if ($tsec ne '') {
+ $area .= '/'.$tsec;
+ $trest .= '/'.$tsec;
+ }
+ $spec = $trole.'.'.$area;
+ if ($trole =~ /^cr/) {
+ &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
+ $tdom,$spec,$trest,$area);
+ } else {
+ &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
+ $tdom,$spec,$trest,$area);
+ }
+ my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
+ if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
+ if ($1) {
+ $no_userblock = 1;
+ last;
+ }
+ }
+ } else {
+ # Resource belongs to current user
+ # Check for 'evb' priv via lonnet::allowed().
+ if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
+ $no_ownblock = 1;
+ last;
+ }
}
- if ($active) { $courses{$1.'_'.$2}=1; }
+ }
+ # if they have the evb priv and are currently not playing student
+ next if (($no_ownblock) &&
+ ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
+ next if ($no_userblock);
+
+ # Retrieve blocking times and identity of blocker for course
+ # of specified user, unless user has 'evb' privilege.
+
+ my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
+ if (($start != 0) &&
+ (($startblock == 0) || ($startblock > $start))) {
+ $startblock = $start;
+ }
+ if (($end != 0) &&
+ (($endblock == 0) || ($endblock < $end))) {
+ $endblock = $end;
}
}
- return keys %courses;
+ return ($startblock,$endblock);
+}
+
+sub get_blocks {
+ my ($setters,$activity,$cdom,$cnum) = @_;
+ my $startblock = 0;
+ my $endblock = 0;
+ my $course = $cdom.'_'.$cnum;
+ $setters->{$course} = {};
+ $setters->{$course}{'staff'} = [];
+ $setters->{$course}{'times'} = [];
+ my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
+ foreach my $record (keys(%records)) {
+ my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
+ if ($start <= time && $end >= time) {
+ my ($staff_name,$staff_dom,$title,$blocks) =
+ &parse_block_record($records{$record});
+ if ($blocks->{$activity} eq 'on') {
+ push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
+ push(@{$$setters{$course}{'times'}}, [$start,$end]);
+ if ( ($startblock == 0) || ($startblock > $start) ) {
+ $startblock = $start;
+ }
+ if ( ($endblock == 0) || ($endblock < $end) ) {
+ $endblock = $end;
+ }
+ }
+ }
+ }
+ return ($startblock,$endblock);
+}
+
+sub parse_block_record {
+ my ($record) = @_;
+ my ($setuname,$setudom,$title,$blocks);
+ if (ref($record) eq 'HASH') {
+ ($setuname,$setudom) = split(/:/,$record->{'setter'});
+ $title = &unescape($record->{'event'});
+ $blocks = $record->{'blocks'};
+ } else {
+ my @data = split(/:/,$record,3);
+ if (scalar(@data) eq 2) {
+ $title = $data[1];
+ ($setuname,$setudom) = split(/@/,$data[0]);
+ } else {
+ ($setuname,$setudom,$title) = @data;
+ }
+ $blocks = { 'com' => 'on' };
+ }
+ return ($setuname,$setudom,$title,$blocks);
+}
+
+sub build_block_table {
+ my ($startblock,$endblock,$setters) = @_;
+ my %lt = &Apache::lonlocal::texthash(
+ 'cacb' => 'Currently active communication blocks',
+ 'cour' => 'Course',
+ 'dura' => 'Duration',
+ 'blse' => 'Block set by'
+ );
+ my $output;
+ $output = ' '.$lt{'cacb'}.': ';
+ $output .= &start_data_table();
+ $output .= '
+
+ '.$lt{'cour'}.'
+ '.$lt{'dura'}.'
+ '.$lt{'blse'}.'
+
+';
+ foreach my $course (keys(%{$setters})) {
+ my %courseinfo=&Apache::lonnet::coursedescription($course);
+ for (my $i=0; $i<@{$$setters{$course}{staff}}; $i++) {
+ my ($uname,$udom) = @{$$setters{$course}{staff}[$i]};
+ my $fullname = &plainname($uname,$udom);
+ if (defined($env{'user.name'}) && defined($env{'user.domain'})
+ && $env{'user.name'} ne 'public'
+ && $env{'user.domain'} ne 'public') {
+ $fullname = &aboutmewrapper($fullname,$uname,$udom);
+ }
+ my ($openblock,$closeblock) = @{$$setters{$course}{times}[$i]};
+ $openblock = &Apache::lonlocal::locallocaltime($openblock);
+ $closeblock= &Apache::lonlocal::locallocaltime($closeblock);
+ $output .= &Apache::loncommon::start_data_table_row().
+ ''.$courseinfo{'description'}.' '.
+ ''.$openblock.' to '.$closeblock.' '.
+ ''.$fullname.' '.
+ &Apache::loncommon::end_data_table_row();
+ }
+ }
+ $output .= &end_data_table();
+}
+
+sub blocking_status {
+ my ($activity,$uname,$udom) = @_;
+ my %setters;
+ my ($blocked,$output,$ownitem,$is_course);
+ my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
+ if ($startblock && $endblock) {
+ $blocked = 1;
+ if (wantarray) {
+ my $category;
+ if ($activity eq 'boards') {
+ $category = 'Discussion posts in this course';
+ } elsif ($activity eq 'blogs') {
+ $category = 'Blogs';
+ } elsif ($activity eq 'port') {
+ if (defined($uname) && defined($udom)) {
+ if ($uname eq $env{'user.name'} &&
+ $udom eq $env{'user.domain'}) {
+ $ownitem = 1;
+ }
+ }
+ $is_course = &Apache::lonnet::is_course($udom,$uname);
+ if ($ownitem) {
+ $category = 'Your portfolio files';
+ } elsif ($is_course) {
+ my $coursedesc;
+ foreach my $course (keys(%setters)) {
+ my %courseinfo =
+ &Apache::lonnet::coursedescription($course);
+ $coursedesc = $courseinfo{'description'};
+ }
+ $category = "Group files in the course '$coursedesc'";
+ } else {
+ $category = 'Portfolio files belonging to ';
+ if ($env{'user.name'} eq 'public' &&
+ $env{'user.domain'} eq 'public') {
+ $category .= &plainname($uname,$udom);
+ } else {
+ $category .= &aboutmewrapper(&plainname($uname,$udom),$uname,$udom);
+ }
+ }
+ } elsif ($activity eq 'groups') {
+ $category = 'Groups in this course';
+ }
+ my $showstart = &Apache::lonlocal::locallocaltime($startblock);
+ my $showend = &Apache::lonlocal::locallocaltime($endblock);
+ $output = ' '.&mt('[_1] will be inaccessible between [_2] and [_3] because communication is being blocked.',$category,$showstart,$showend).' ';
+ if (!($activity eq 'port' && !($ownitem) && !($is_course))) {
+ $output .= &build_block_table($startblock,$endblock,\%setters);
+ }
+ }
+ }
+ if (wantarray) {
+ return ($blocked,$output);
+ } else {
+ return $blocked;
+ }
}
-###############################################
###############################################
=pod
-=item &determinedomain()
+=head1 Domain Template Functions
+
+=over 4
+
+=item * &determinedomain()
Inputs: $domain (usually will be undef)
@@ -1423,20 +3764,107 @@ Returns: Determines which domain should
###############################################
sub determinedomain {
my $domain=shift;
- if (! $domain) {
+ if (! $domain) {
# Determine domain if we have not been given one
$domain = $Apache::lonnet::perlvar{'lonDefDomain'};
- if ($ENV{'user.domain'}) { $domain=$ENV{'user.domain'}; }
- if ($ENV{'request.role.domain'}) {
- $domain=$ENV{'request.role.domain'};
+ if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
+ if ($env{'request.role.domain'}) {
+ $domain=$env{'request.role.domain'};
}
}
return $domain;
}
###############################################
+
+sub devalidate_domconfig_cache {
+ my ($udom)=@_;
+ &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
+}
+
+# ---------------------- Get domain configuration for a domain
+sub get_domainconf {
+ my ($udom) = @_;
+ my $cachetime=1800;
+ my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
+ if (defined($cached)) { return %{$result}; }
+
+ my %domconfig = &Apache::lonnet::get_dom('configuration',
+ ['login','rolecolors'],$udom);
+ my (%designhash,%legacy);
+ if (keys(%domconfig) > 0) {
+ if (ref($domconfig{'login'}) eq 'HASH') {
+ if (keys(%{$domconfig{'login'}})) {
+ foreach my $key (keys(%{$domconfig{'login'}})) {
+ $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
+ }
+ } else {
+ $legacy{'login'} = 1;
+ }
+ } else {
+ $legacy{'login'} = 1;
+ }
+ if (ref($domconfig{'rolecolors'}) eq 'HASH') {
+ if (keys(%{$domconfig{'rolecolors'}})) {
+ foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
+ if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
+ foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
+ $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
+ }
+ }
+ }
+ } else {
+ $legacy{'rolecolors'} = 1;
+ }
+ } else {
+ $legacy{'rolecolors'} = 1;
+ }
+ if (keys(%legacy) > 0) {
+ 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,
+ $cachetime);
+ 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 '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
+ $legacyhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
+ }
+ return %legacyhash;
+}
+
=pod
-=item &domainlogo()
+=item * &domainlogo()
Inputs: $domain (usually will be undef)
@@ -1444,15 +3872,24 @@ Returns: A link to a domain logo, if the
If the domain logo does not exist, a description of the domain.
=cut
+
###############################################
sub domainlogo {
- my $domain = &determinedomain(shift);
- # See if there is a logo
- if (-e '/home/httpd/html/adm/lonDomLogos/'.$domain.'.gif') {
- return ' ';
- } elsif(exists($Apache::lonnet::domaindescription{$domain})) {
- return $Apache::lonnet::domaindescription{$domain};
+ my $domain = &determinedomain(shift);
+ my %designhash = &get_domainconf($domain);
+ # See if there is a logo
+ if ($designhash{$domain.'.login.domlogo'} ne '') {
+ my $imgsrc = $designhash{$domain.'.login.domlogo'};
+ if ($imgsrc =~ m{^/(adm|res)/}) {
+ if ($imgsrc =~ m{^/res/}) {
+ my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
+ &Apache::lonnet::repcopy($local_name);
+ }
+ $imgsrc = &lonhttpdurl($imgsrc);
+ }
+ return ' ';
+ } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
+ return &Apache::lonnet::domain($domain,'description');
} else {
return '';
}
@@ -1461,22 +3898,51 @@ sub domainlogo {
=pod
-=item &designparm()
+=item * &designparm()
Inputs: $which parameter; $domain (usually will be undef)
Returns: value of designparamter $which
=cut
+
+
##############################################
sub designparm {
my ($which,$domain)=@_;
+ if ($env{'browser.blackwhite'} eq 'on') {
+ if ($which=~/\.(font|alink|vlink|link|textcol)$/) {
+ return '#000000';
+ }
+ if ($which=~/\.(pgbg|sidebg|bgcol)$/) {
+ return '#FFFFFF';
+ }
+ if ($which=~/\.tabbg$/) {
+ return '#CCCCCC';
+ }
+ }
+ if (exists($env{'environment.color.'.$which})) {
+ return $env{'environment.color.'.$which};
+ }
$domain=&determinedomain($domain);
- if ($designhash{$domain.'.'.$which}) {
- return $designhash{$domain.'.'.$which};
+ my %domdesign = &get_domainconf($domain);
+ my $output;
+ if ($domdesign{$domain.'.'.$which} ne '') {
+ $output = $domdesign{$domain.'.'.$which};
} else {
- return $designhash{'default.'.$which};
+ $output = $defaultdesign{$which};
+ }
+ if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
+ ($which =~ /login\.(img|logo|domlogo|login)/)) {
+ if ($output =~ m{^/(adm|res)/}) {
+ if ($output =~ m{^/res/}) {
+ my $local_name = &Apache::lonnet::filelocation('',$output);
+ &Apache::lonnet::repcopy($local_name);
+ }
+ $output = &lonhttpdurl($output);
+ }
}
+ return $output;
}
###############################################
@@ -1484,17 +3950,54 @@ sub designparm {
=pod
-=item &bodytag()
+=back
+
+=head1 HTML Helpers
+
+=over 4
+
+=item * &bodytag()
Returns a uniform header for LON-CAPA web pages.
Inputs:
- $title, A title to be displayed on the page.
- $function, the current role (can be undef).
- $addentries, extra parameters for the tag.
- $bodyonly, if defined, only return the tag.
- $domain, if defined, force a given domain.
+=over 4
+
+=item * $title, A title to be displayed on the page.
+
+=item * $function, the current role (can be undef).
+
+=item * $addentries, extra parameters for the tag.
+
+=item * $bodyonly, if defined, only return the tag.
+
+=item * $domain, if defined, force a given domain.
+
+=item * $forcereg, if page should register as content page (relevant for
+ text interface only)
+
+=item * $customtitle, alternate text to use instead of $title
+ in the title box that appears, this text
+ 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 * $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
+ 'Switch To Inline Menu' link
+
+=item * $args, optional argument valid values are
+ no_auto_mt_title -> prevents &mt()ing the title arg
+ inherit_jsmath -> when creating popup window in a page,
+ should it have jsmath forced on by the
+ current page
+
+=back
Returns: A uniform header for LON-CAPA web pages.
If $bodyonly is nonzero, a string containing a tag will be returned.
@@ -1503,176 +4006,3340 @@ other decorations will be returned.
=cut
-###############################################
+sub bodytag {
+ my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle,
+ $notopbar,$bgcolor,$notitle,$no_inline_link,$args)=@_;
+ if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
-###############################################
-sub bodytag {
- my ($title,$function,$addentries,$bodyonly,$domain)=@_;
- unless ($function) {
- $function='student';
- if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) {
- $function='coordinator';
- }
- if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) {
- $function='admin';
- }
- if (($ENV{'request.role'}=~/^(au|ca)/) ||
- ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
- $function='author';
- }
- }
- my $img=&designparm($function.'.img',$domain);
- my $pgbg=&designparm($function.'.pgbg',$domain);
- my $tabbg=&designparm($function.'.tabbg',$domain);
- my $font=&designparm($function.'.font',$domain);
- my $link=&designparm($function.'.link',$domain);
- my $alink=&designparm($function.'.alink',$domain);
- my $vlink=&designparm($function.'.vlink',$domain);
- my $sidebg=&designparm($function.'.sidebg',$domain);
+ $function = &get_users_function() if (!$function);
+ my $img = &designparm($function.'.img',$domain);
+ my $font = &designparm($function.'.font',$domain);
+ my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
+
+ my %design = ( 'style' => 'margin-top: 0px',
+ 'bgcolor' => $pgbg,
+ 'text' => $font,
+ 'alink' => &designparm($function.'.alink',$domain),
+ 'vlink' => &designparm($function.'.vlink',$domain),
+ 'link' => &designparm($function.'.link',$domain),);
+ @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
# role and realm
- my ($role,$realm)
- =&Apache::lonnet::plaintext((split(/\./,$ENV{'request.role'}))[0]);
+ my ($role,$realm) = split(/\./,$env{'request.role'},2);
+ if ($role eq 'ca') {
+ my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
+ $realm = &plainname($rname,$rdom);
+ }
# realm
- if ($ENV{'request.course.id'}) {
- $realm=
- $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
+ if ($env{'request.course.id'}) {
+ if ($env{'request.role'} !~ /^cr/) {
+ $role = &Apache::lonnet::plaintext($role,&course_type());
+ }
+ $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
+ } else {
+ $role = &Apache::lonnet::plaintext($role);
}
- unless ($realm) { $realm=' '; }
+
+ if (!$realm) { $realm=' '; }
# Set messages
my $messages=&domainlogo($domain);
-# Output
- my $bodytag = <
-END
+
+ my $extra_body_attr = &make_attr_string($forcereg,\%design);
+
+# construct main body tag
+ my $bodytag = "".
+ &Apache::lontexconvert::init_math_support($args->{'inherit_jsmath'});
+
if ($bodyonly) {
return $bodytag;
- } elsif ($ENV{'browser.interface'} eq 'textual') {
- return $bodytag.'LON-CAPA: '.$title.
- ' Main Menu ';
+ } elsif ($env{'browser.interface'} eq 'textual') {
+# Accessibility
+
+ $bodytag.=&Apache::lonmenu::menubuttons($forcereg,$forcereg);
+ if (!$notitle) {
+ $bodytag.='LON-CAPA: '.$title.' ';
+ }
+ return $bodytag;
+ }
+
+ my $name = &plainname($env{'user.name'},$env{'user.domain'});
+ if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
+ undef($role);
} else {
- return(<
+
+ $name
+
+
+
+$role
+
+
+$realm
+
+
+ENDROLE
+
+ my $titleinfo = ''.$title.' ';
+ if ($customtitle) {
+ $titleinfo = $customtitle;
+ }
+ #
+ # Extra info if you are the DC
+ my $dc_info = '';
+ if ($env{'user.adv'} && exists($env{'user.role.dc./'.
+ $env{'course.'.$env{'request.course.id'}.
+ '.domain'}.'/'})) {
+ my $cid = $env{'request.course.id'};
+ $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
+ $dc_info =~ s/\s+$//;
+ $dc_info = '('.$dc_info.')';
+ }
+
+ if (($env{'environment.remote'} eq 'off') || ($args->{'suppress_header_logos'})) {
+ # No Remote
+ 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 ($uname,$thisdisfn)=
+ ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
+ my $formaction='/priv/'.$uname.'/'.$thisdisfn;
+ $formaction=~s/\/+/\//g;
+
+ my $parentpath = '';
+ my $lastitem = '';
+ if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
+ $parentpath = $1;
+ $lastitem = $2;
+ } else {
+ $lastitem = $thisdisfn;
+ }
+ $titleinfo =
+ &Apache::loncommon::help_open_menu('','',3,'Authoring')
+ .''.&mt('Construction Space').' : '
+ .''
+ .&Apache::lonmenu::constspaceform();
+ }
+
+ my $titletable;
+ if (!$notitle) {
+ $titletable =
+ ''.
+ " $titleinfo $dc_info ".$roleinfo.
+ '
';
+ }
+ if ($notopbar) {
+ $bodytag .= $titletable;
+ } else {
+ if ($env{'request.state'} eq 'construct') {
+ $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg,
+ $titletable);
+ } else {
+ $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg).
+ $titletable;
+ }
+ }
+ return $bodytag;
+ }
+
+#
+# Top frame rendering, Remote is up
+#
+
+ my $imgsrc = $img;
+ if ($img =~ /^\/adm/) {
+ $imgsrc = &lonhttpdurl($img);
+ }
+ my $upperleft=' ';
+
+ # Explicit link to get inline menu
+ my $menu= ($no_inline_link?''
+ :''.&mt('Switch to Inline Menu Mode').' ');
+ #
+ if ($notitle) {
+ return $bodytag;
+ }
+ return(<
-
-
-$messages
+
+$upperleft
+ $messages
-
-
- $title
-
-
- $ENV{'environment.firstname'}
- $ENV{'environment.middlename'}
- $ENV{'environment.lastname'}
- $ENV{'environment.generation'}
-
-
+ $titleinfo $dc_info $menu
+$roleinfo
-
-$role
-
-
-$realm
-
+