".
- "$text ";
+ "$text ";
}
# Add the graphic
my $title = &mt('Online Help');
- my $helpicon=&lonhttpdurl("/adm/help/gif/smallHelp.gif");
+ my $helpicon=&lonhttpdurl("/adm/help/help.png");
$template .= <<"ENDTEMPLATE";
ENDTEMPLATE
@@ -751,21 +943,30 @@ ENDTEMPLATE
# This is a quicky function for Latex cheatsheet editing, since it
# appears in at least four places
sub helpLatexCheatsheet {
- my $other = shift;
+ my ($topic,$text,$not_author) = @_;
+ my $out;
my $addOther = '';
- if ($other) {
- $addOther = Apache::loncommon::help_open_topic($other, shift,
- undef, undef, 600) .
+ if ($topic) {
+ $addOther = &Apache::loncommon::help_open_topic($topic,$text,
+ undef, undef, 600).
'';
}
- return ''.
- $addOther .
- &Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols',
- undef,undef,600)
- .' '.
- &Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols',
- undef,undef,600)
- .'
';
+ $out = ''.
+ $addOther .
+ &Apache::loncommon::help_open_topic("Greek_Symbols",&mt('Greek Symbols'),
+ undef,undef,600).
+ ' '.
+ &Apache::loncommon::help_open_topic("Other_Symbols",&mt('Other Symbols'),
+ undef,undef,600).
+ ' ';
+ unless ($not_author) {
+ $out .= ''.
+ &Apache::loncommon::help_open_topic("Authoring_Output_Tags",&mt('Output Tags'),
+ undef,undef,600).
+ ' ';
+ }
+ $out .= '
';
+ return $out;
}
sub general_help {
@@ -774,6 +975,8 @@ sub general_help {
$helptopic='Authoring_Intro';
} elsif ($env{'request.role'}=~/^cc/) {
$helptopic='Course_Coordination_Intro';
+ } elsif ($env{'request.role'}=~/^dc/) {
+ $helptopic='Domain_Coordination_Intro';
}
return $helptopic;
}
@@ -931,7 +1134,7 @@ sub help_open_bug {
{
$template .=
"".
- "$text ";
+ "$text ";
}
# Add the graphic
@@ -976,7 +1179,7 @@ sub help_open_faq {
{
$template .=
"".
- "$text ";
+ "$text ";
}
# Add the graphic
@@ -995,7 +1198,7 @@ ENDTEMPLATE
=pod
-=item * change_content_javascript():
+=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
@@ -1050,7 +1253,7 @@ DOMBASED
=pod
-=item * changable_area($name, $origContent):
+=item * &changable_area($name,$origContent):
This provides a "changable area" that can be modified on the fly via
the Javascript code provided in C. $name is
@@ -1074,7 +1277,7 @@ sub changable_area {
=pod
-=item * viewport_geometry_js {
+=item * &viewport_geometry_js
Provides javascript object (Geometry) which can provide information about the viewport geometry for the client browser.
@@ -1121,7 +1324,7 @@ GEOMETRY
=pod
-=item * viewport_size_js {
+=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.
@@ -1145,7 +1348,7 @@ DIMS
=pod
-=item * resize_textarea_js
+=item * &resize_textarea_js()
emits the needed javascript to resize a textarea to be as big as possible
@@ -1154,6 +1357,7 @@ the id of the element to resize, second
surrounds everything that comes after the textarea, this routine needs
to be attached to the for the onload and onresize events.
+=back
=cut
@@ -1206,8 +1410,6 @@ RESIZE
=pod
-=back
-
=head1 Excel and CSV file utility routines
=over 4
@@ -1219,7 +1421,7 @@ RESIZE
=pod
-=item * csv_translate($text)
+=item * &csv_translate($text)
Translate $text to allow it to be output as a 'comma separated values'
format.
@@ -1240,7 +1442,7 @@ sub csv_translate {
=pod
-=item * define_excel_formats
+=item * &define_excel_formats()
Define some commonly used Excel cell formats.
@@ -1296,7 +1498,7 @@ sub define_excel_formats {
=pod
-=item * create_workbook
+=item * &create_workbook()
Create an Excel worksheet. If it fails, output message on the
request object and return undefs.
@@ -1339,7 +1541,7 @@ sub create_workbook {
=pod
-=item * create_text_file
+=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
@@ -1364,9 +1566,9 @@ sub create_text_file {
$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.");
+ $r->print(&mt('Problems occurred in creating the output file. '
+ .'This error has been logged. '
+ .'Please alert your LON-CAPA administrator.'));
}
return ($fh,$filename)
}
@@ -1407,7 +1609,7 @@ sub domain_select {
=over 4
-=item * multiple_select_form($name,$value,$size,$hash,$order)
+=item * &multiple_select_form($name,$value,$size,$hash,$order)
Returns a string containing a element int multiple mode
@@ -1457,7 +1659,7 @@ sub multiple_select_form {
=pod
-=item * select_form($defdom,$name,%hash)
+=item * &select_form($defdom,$name,%hash)
Returns a string containing a form to
allow a user to select options from a hash option_name => displayed text.
@@ -1490,17 +1692,17 @@ sub select_form {
sub display_filter {
if (!$env{'form.show'}) { $env{'form.show'}=10; }
if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
- return ''.&mt('Records [_1]',
+ 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 {
@@ -1544,7 +1746,7 @@ sub select_level_form {
=pod
-=item * select_dom_form($defdom,$name,$includeempty,$showdomdesc)
+=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.
@@ -1584,7 +1786,7 @@ sub select_dom_form {
=pod
-=item * home_server_form_item($domain,$name,$defaultflag)
+=item * &home_server_form_item($domain,$name,$defaultflag)
input: 4 arguments (two required, two optional) -
$domain - domain of new user
@@ -1744,14 +1946,12 @@ sub decode_user_agent {
=over 4
-=item * authform_xxxxxx
+=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
@@ -1768,7 +1968,7 @@ See loncreateuser.pm for invocation and
=back
-=back
+See loncreateuser.pm for invocation and use examples.
=cut
@@ -1923,6 +2123,11 @@ sub authform_kerberos {
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"';
@@ -2020,6 +2225,11 @@ sub authform_internal{
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'};
}
@@ -2049,11 +2259,12 @@ sub authform_internal{
$authtype = ' ';
}
- $autharg = ' ';
$result = &mt
('[_1] Internally authenticated (with initial password [_2])',
''.$authtype,' '.$autharg);
+ $result.=" ".&mt('Visible input').' ';
return $result;
}
@@ -2069,6 +2280,11 @@ sub authform_local{
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'};
}
@@ -2118,6 +2334,11 @@ sub authform_filesystem{
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;
@@ -2151,7 +2372,7 @@ sub authform_filesystem{
('[_1] Filesystem Authenticated (with initial password [_2])',
' ',
- ' ');
return $result;
}
@@ -2199,42 +2420,6 @@ sub get_assignable_auth {
}
###############################################################
-## Get Authentication Defaults for Domain ##
-###############################################################
-
-=pod
-
-=head1 Domains and Authentication
-
-Returns default authentication type and an associated argument as
-listed in file 'domain.tab'.
-
-=over 4
-
-=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 ('').
-
-=cut
-
-#-------------------------------------------
-sub get_auth_defaults {
- my $domain=shift;
- return (&Apache::lonnet::domain($domain,'auth_def'),
- &Apache::lonnet::domain($domain,'auth_arg_def'));
-
-}
-###############################################################
-## End Get Authentication Defaults for Domain ##
-###############################################################
-
-###############################################################
## Get Kerberos Defaults for Domain ##
###############################################################
##
@@ -2246,22 +2431,31 @@ 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.
+version and domain. If not found, it defaults to version 4 and the
+domain of the server.
+
+=over 4
($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
+=back
+
+=back
+
=cut
#-------------------------------------------
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/;
@@ -2270,11 +2464,6 @@ sub get_kerberos_defaults {
return ($krbdef,$krbdefdom);
}
-=pod
-
-=back
-
-=cut
###############################################################
## Thesaurus Functions ##
@@ -2286,7 +2475,7 @@ sub get_kerberos_defaults {
=over 4
-=item * initialize_keywords
+=item * &initialize_keywords()
Initializes the package variable %Keywords if it is empty. Uses the
package variable $thesaurus_db_file.
@@ -2331,7 +2520,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
@@ -2352,7 +2541,7 @@ sub keyword {
=pod
-=item * get_related_words
+=item * &get_related_words()
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
@@ -2410,7 +2599,7 @@ sub get_related_words {
=over 4
-=item * plainname($uname,$udom,$first)
+=item * &plainname($uname,$udom,$first)
Takes a users logon name and returns it as a string in
"first middle last generation" form
@@ -2439,7 +2628,7 @@ sub plainname {
# -------------------------------------------------------------------- Nickname
=pod
-=item * nickname($uname,$udom)
+=item * &nickname($uname,$udom)
Gets a users name and returns it as a string as
@@ -2489,18 +2678,21 @@ sub getnames {
}
# -------------------------------------------------------------------- getemails
+
=pod
-=item * getemails($uname,$udom)
+=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 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
+
sub getemails {
my ($uname,$udom)=@_;
if ($udom eq 'public' && $uname eq 'public') {
@@ -2531,11 +2723,48 @@ sub flush_email_cache {
&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
=pod
-=item * screenname($uname,$udom)
+=item * &screenname($uname,$udom)
Gets a users screenname and returns it as a string
@@ -2582,10 +2811,7 @@ sub aboutmewrapper {
sub syllabuswrapper {
- my ($linktext,$coursedir,$domain,$fontcolor)=@_;
- if ($fontcolor) {
- $linktext=''.$linktext.' ';
- }
+ my ($linktext,$coursedir,$domain)=@_;
return qq{$linktext };
}
@@ -2631,7 +2857,7 @@ sub student_image_tag {
=over 4
-=item * languageids()
+=item * &languageids()
returns list of all language ids
@@ -2643,7 +2869,7 @@ sub languageids {
=pod
-=item * languagedescription()
+=item * &languagedescription()
returns description of a specified language id
@@ -2668,7 +2894,7 @@ sub supportedlanguagecode {
=pod
-=item * copyrightids()
+=item * ©rightids()
returns list of all copyrights
@@ -2680,7 +2906,7 @@ sub copyrightids {
=pod
-=item * copyrightdescription()
+=item * ©rightdescription()
returns description of a specified copyright id
@@ -2692,7 +2918,7 @@ sub copyrightdescription {
=pod
-=item * source_copyrightids()
+=item * &source_copyrightids()
returns list of all source copyrights
@@ -2704,7 +2930,7 @@ sub source_copyrightids {
=pod
-=item * source_copyrightdescription()
+=item * &source_copyrightdescription()
returns description of a specified source copyright id
@@ -2716,7 +2942,7 @@ sub source_copyrightdescription {
=pod
-=item * filecategories()
+=item * &filecategories()
returns list of all file categories
@@ -2728,7 +2954,7 @@ sub filecategories {
=pod
-=item * filecategorytypes()
+=item * &filecategorytypes()
returns list of file types belonging to a given file
category
@@ -2742,7 +2968,7 @@ sub filecategorytypes {
=pod
-=item * fileembstyle()
+=item * &fileembstyle()
returns embedding style for a specified file type
@@ -2766,7 +2992,7 @@ sub filecategoryselect {
=pod
-=item * filedescription()
+=item * &filedescription()
returns description for a specified file type
@@ -2780,7 +3006,7 @@ sub filedescription {
=pod
-=item * filedescriptionex()
+=item * &filedescriptionex()
returns description for a specified file type with
extra formatting
@@ -2812,7 +3038,7 @@ sub fileextensions {
sub display_languages {
my %languages=();
- foreach my $lang (&preferred_languages()) {
+ foreach my $lang (&Apache::lonlocal::preferred_languages()) {
$languages{$lang}=1;
}
&get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
@@ -2824,56 +3050,9 @@ sub display_languages {
return %languages;
}
-sub preferred_languages {
- my @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);
- }
- if (&Apache::lonnet::domain($env{'user.domain'},'lang_def')) {
- @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]);
- }
- }
- #uniqueify the languages list
- my %count;
- @genlanguages = map { $count{$_}++ == 0 ? $_ : () } @genlanguages;
- return @genlanguages;
-}
-
sub languages {
my ($possible_langs) = @_;
- my @preferred_langs = &preferred_languages();
+ my @preferred_langs = &Apache::lonlocal::preferred_languages();
if (!ref($possible_langs)) {
if( wantarray ) {
return @preferred_langs;
@@ -2904,7 +3083,7 @@ sub languages {
=over 4
-=item * get_previous_attempt($symb, $username, $domain, $course,
+=item * &get_previous_attempt($symb, $username, $domain, $course,
$getattempt, $regexp, $gradesub)
Return string with previous attempt on problem. Arguments:
@@ -3032,7 +3211,7 @@ sub relative_to_absolute {
}
$thisdir=~s-/[^/]*$--;
foreach my $link (@rlinks) {
- unless (($link=~/^http:\/\//i) ||
+ unless (($link=~/^https?\:\/\//i) ||
($link=~/^\//) ||
($link=~/^javascript:/i) ||
($link=~/^mailto:/i) ||
@@ -3048,7 +3227,7 @@ sub relative_to_absolute {
=pod
-=item * get_student_view
+=item * &get_student_view()
show a snapshot of what student was looking at
@@ -3067,7 +3246,7 @@ sub get_student_view {
}
if (defined($target)) { $form{'grade_target'} = $target; }
$feedurl=&Apache::lonnet::clutter($feedurl);
- my $userview=&Apache::lonnet::ssi_body($feedurl,%form);
+ my ($userview,$response)=&Apache::lonnet::ssi_body($feedurl,%form);
$userview=~s/\]*\>//gi;
$userview=~s/\<\/body\>//gi;
$userview=~s/\//gi;
@@ -3076,12 +3255,44 @@ sub get_student_view {
$userview=~s/\<\/head\>//gi;
$userview=~s/action\s*\=/would_be_action\=/gi;
$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;
+ }
}
=pod
-=item * get_student_answers()
+=item * &get_student_answers()
show a snapshot of how student was answering problem
@@ -3185,16 +3396,21 @@ sub pprmlink {
sub timehash {
- my @ltime=localtime(shift);
- return ( 'seconds' => $ltime[0],
- 'minutes' => $ltime[1],
- 'hours' => $ltime[2],
- 'day' => $ltime[3],
- 'month' => $ltime[4]+1,
- 'year' => $ltime[5]+1900,
- 'weekday' => $ltime[6],
- 'dayyear' => $ltime[7]+1,
- 'dlsav' => $ltime[8] );
+ my ($thistime) = @_;
+ my $timezone = &Apache::lonlocal::gettimezone();
+ my $dt = DateTime->from_epoch(epoch => $thistime)
+ ->set_time_zone($timezone);
+ my $wday = $dt->day_of_week();
+ if ($wday == 7) { $wday = 0; }
+ return ( 'second' => $dt->second(),
+ 'minute' => $dt->minute(),
+ 'hour' => $dt->hour(),
+ '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 {
@@ -3204,6 +3420,24 @@ sub utc_string {
sub maketime {
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(
($th{'seconds'},$th{'minutes'},$th{'hours'},
$th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
@@ -3584,6 +3818,60 @@ sub blocking_status {
###############################################
+sub check_ip_acc {
+ my ($acc)=@_;
+ &Apache::lonxml::debug("acc is $acc");
+ if (!defined($acc) || $acc =~ /^\s*$/ || $acc =~/^\s*no\s*$/i) {
+ return 1;
+ }
+ my $allowed=0;
+ my $ip=$env{'request.host'} || $ENV{'REMOTE_ADDR'};
+
+ my $name;
+ foreach my $pattern (split(',',$acc)) {
+ $pattern =~ s/^\s*//;
+ $pattern =~ s/\s*$//;
+ if ($pattern =~ /\*$/) {
+ #35.8.*
+ $pattern=~s/\*//;
+ if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
+ } 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=1; }
+ }
+ } elsif ($pattern =~ /^\*/) {
+ #*.msu.edu
+ $pattern=~s/\*//;
+ if (!defined($name)) {
+ use Socket;
+ my $netaddr=inet_aton($ip);
+ ($name)=gethostbyaddr($netaddr,AF_INET);
+ }
+ if ($name =~ /\Q$pattern\E$/i) { $allowed=1; }
+ } elsif ($pattern =~ /\d+\.\d+\.\d+\.\d+/) {
+ #127.0.0.1
+ if ($ip =~ /^\Q$pattern\E/) { $allowed=1; }
+ } 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=1; }
+ }
+ if ($allowed) { last; }
+ }
+ return $allowed;
+}
+
+###############################################
+
=pod
=head1 Domain Template Functions
@@ -3627,45 +3915,85 @@ sub get_domainconf {
my %domconfig = &Apache::lonnet::get_dom('configuration',
['login','rolecolors'],$udom);
- my %designhash;
+ my (%designhash,%legacy);
if (keys(%domconfig) > 0) {
if (ref($domconfig{'login'}) eq 'HASH') {
- foreach my $key (keys(%{$domconfig{'login'}})) {
- $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
+ if (keys(%{$domconfig{'login'}})) {
+ foreach my $key (keys(%{$domconfig{'login'}})) {
+ if (ref($domconfig{'login'}{$key}) eq 'HASH') {
+ 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') {
- 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};
+ 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;
}
- } else {
- 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) { $designhash{$udom.'.'.$key}=$val; }
+ 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};
+ }
}
- close($fh);
}
}
- if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
- $designhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
- }
+ } 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()
@@ -3715,10 +4043,10 @@ Returns: value of designparamter $which
sub designparm {
my ($which,$domain)=@_;
if ($env{'browser.blackwhite'} eq 'on') {
- if ($which=~/\.(font|alink|vlink|link)$/) {
+ if ($which=~/\.(font|alink|vlink|link|textcol)$/) {
return '#000000';
}
- if ($which=~/\.(pgbg|sidebg)$/) {
+ if ($which=~/\.(pgbg|sidebg|bgcol)$/) {
return '#FFFFFF';
}
if ($which=~/\.tabbg$/) {
@@ -3737,7 +4065,7 @@ sub designparm {
$output = $defaultdesign{$which};
}
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{^/res/}) {
my $local_name = &Apache::lonnet::filelocation('',$output);
@@ -3905,7 +4233,7 @@ ENDROLE
$dc_info = '('.$dc_info.')';
}
- if ($env{'environment.remote'} eq 'off') {
+ if (($env{'environment.remote'} eq 'off') || ($args->{'suppress_header_logos'})) {
# No Remote
if ($env{'request.state'} eq 'construct') {
$forcereg=1;
@@ -3928,11 +4256,11 @@ ENDROLE
$lastitem = $thisdisfn;
}
$titleinfo =
- &Apache::loncommon::help_open_menu('','',3,'Authoring').
- 'Construction Space : '.
- ''
.&Apache::lonmenu::constspaceform();
@@ -4054,18 +4382,25 @@ sub make_attr_string {
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 section,
+i.e., $env{'internal.head.redirect'} exists
=cut
sub endbodytag {
+ my ($args) = @_;
my $endbodytag='';
$endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
if ( exists( $env{'internal.head.redirect'} ) ) {
- $endbodytag=
- "".
- &mt('Continue').' '.
- $endbodytag;
+ if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
+ $endbodytag=
+ "".
+ &mt('Continue').' '.
+ $endbodytag;
+ }
}
return $endbodytag;
}
@@ -4099,7 +4434,11 @@ sub standard_css {
my $vlink = &designparm($function.'.vlink', $domain);
my $link = &designparm($function.'.link', $domain);
- my $sans = 'Arial,Helvetica,sans-serif';
+ my $loginbg = &designparm('login.sidebg',$domain);
+ my $bgcol = &designparm('login.bgcol',$domain);
+ my $textcol = &designparm('login.textcol',$domain);
+
+ my $sans = 'Verdana,Arial,Helvetica,sans-serif';
my $mono = 'monospace';
my $data_table_head = $tabbg;
my $data_table_light = '#EEEEEE';
@@ -4116,28 +4455,52 @@ sub standard_css {
my $mail_other_hover = '#669999';
my $table_header = '#DDDDDD';
my $feedback_link_bg = '#BBBBBB';
+ my $lg_border_color = '#C8C8C8';
- my $border = ($env{'browser.type'} eq 'explorer') ? '0px 2px 0px 2px'
- : '0px 3px 0px 4px';
+ my $border = ($env{'browser.type'} eq 'explorer' ||
+ $env{'browser.type'} eq 'safari' ) ? '0px 2px 0px 2px'
+ : '0px 3px 0px 4px';
return < td {
+ background-color: #CCC;
+ font-weight: bold;
+ text-align: left;
}
-table.LC_data_table tr td,
+table.LC_data_table tr.LC_odd_row > td,
+table.LC_pick_box tr > td.LC_odd_row,
table.LC_aboutme_port tr td {
background-color: $data_table_light;
padding: 2px;
}
-table.LC_data_table tr.LC_even_row td,
+table.LC_data_table tr.LC_even_row > td,
+table.LC_pick_box tr > td.LC_even_row,
table.LC_aboutme_port tr.LC_even_row td {
background-color: $data_table_dark;
+ padding: 2px;
}
table.LC_data_table tr.LC_data_table_highlight td {
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_nested tr.LC_empty_row td {
background-color: #FFFFFF;
@@ -4426,7 +4793,7 @@ table.LC_nested tr.LC_empty_row td {
table.LC_nested_outer tr th {
font-weight: bold;
background-color: $data_table_head;
- font-size: smaller;
+ font-size: small;
border-bottom: 1px solid #000000;
}
table.LC_nested_outer tr td.LC_subheader {
@@ -4465,7 +4832,7 @@ table.LC_createuser {
}
table.LC_createuser tr.LC_section_row td {
- font-size: smaller;
+ font-size: small;
}
table.LC_createuser tr.LC_info_row td {
@@ -4521,71 +4888,46 @@ table.LC_mail_list tr.LC_mail_even {
table.LC_mail_list tr.LC_mail_odd {
}
-
-table#LC_portfolio_actions {
- width: auto;
- 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_data_table tr > td.LC_browser_file,
+table.LC_data_table tr > td.LC_browser_file_published {
+ background: #CCFF88;
}
-table#LC_portfolio_actions td.LC_value {
- background: $tabbg;
+table.LC_data_table tr > td.LC_browser_file_locked,
+table.LC_data_table tr > td.LC_browser_file_unpublished {
+ background: #FFAA99;
}
-
-table#LC_cstr_controls {
- width: 100%;
- border-collapse: collapse;
+table.LC_data_table tr > td.LC_browser_file_obsolete {
+ background: #AAAAAA;
}
-table#LC_cstr_controls tr td {
- border: 4px solid $pgbg;
- padding: 4px;
- text-align: center;
- background: $tabbg;
+table.LC_data_table tr > td.LC_browser_file_modified,
+table.LC_data_table tr > td.LC_browser_file_metamodified {
+ background: #FFFF77;
}
-table#LC_cstr_controls tr th {
- border: 4px solid $pgbg;
- background: $table_header;
- text-align: center;
- font-family: $sans;
- font-size: smaller;
+table.LC_data_table tr.LC_browser_folder > td {
+ background: #CCCCFF;
}
-table#LC_browser {
-
+table.LC_data_table tr > td.LC_roles_is {
+/* background: #77FF77; */
}
-table#LC_browser tr th {
- background: $table_header;
+table.LC_data_table tr > td.LC_roles_future {
+ background: #FFFF77;
}
-table#LC_browser tr td {
- padding: 2px;
+table.LC_data_table tr > td.LC_roles_will {
+ background: #FFAA77;
}
-table#LC_browser tr.LC_browser_file,
-table#LC_browser tr.LC_browser_file_published {
- background: #CCFF88;
+table.LC_data_table tr > td.LC_roles_expired {
+ background: #FF7777;
}
-table#LC_browser tr.LC_browser_file_locked,
-table#LC_browser tr.LC_browser_file_unpublished {
- background: #FFAA99;
+table.LC_data_table tr > td.LC_roles_will_not {
+ background: #AAFF77;
}
-table#LC_browser tr.LC_browser_file_obsolete {
- background: #AAAAAA;
-}
-table#LC_browser tr.LC_browser_file_modified,
-table#LC_browser tr.LC_browser_file_metamodified {
- background: #FFFF77;
-}
-table#LC_browser tr.LC_browser_folder {
- background: #CCCCFF;
+table.LC_data_table tr > td.LC_roles_selected {
+ background: #11CC55;
}
+
span.LC_current_location {
- font-size: x-large;
+ font-size:larger;
background: $pgbg;
}
@@ -4687,6 +5029,14 @@ table.LC_pick_box td.LC_pick_box_title {
width: 184px;
padding: 8px;
}
+table.LC_pick_box td.LC_selfenroll_pick_box_title {
+ background: $tabbg;
+ font-weight: bold;
+ text-align: right;
+ width: 350px;
+ padding: 8px;
+}
+
table.LC_pick_box td.LC_pick_box_value {
text-align: left;
padding: 8px;
@@ -4812,12 +5162,20 @@ table.LC_descriptive_input td.LC_descrip
text-align: right;
font-weight: bold;
}
-table.LC_feedback_link {
- background: $feedback_link_bg;
+div.LC_feedback_link {
+ clear: both;
+ background: white;
+ width: 100%;
}
span.LC_feedback_link {
- background: $feedback_link_bg;
- font-size: larger;
+ background: $feedback_link_bg;
+ font-size: larger;
+}
+span.LC_message_link {
+ background: $feedback_link_bg;
+ font-size: larger;
+ position: absolute;
+ right: 1em;
}
table.LC_prior_tries {
@@ -4893,6 +5251,11 @@ span.LC_cusr_emph {
font-style: italic;
}
+span.LC_cusr_subheading {
+ font-weight: normal;
+ font-size: 85%;
+}
+
table.LC_docs_documents {
background: #BBBBBB;
border-width: 0px;
@@ -5015,7 +5378,8 @@ div.LC_grade_show_user {
div.LC_grade_user_name {
background: #DDDDEE;
border-bottom: 1px solid black;
- font: bold large $sans;
+ font-weight: bold;
+ font-size: large;
}
div.LC_grade_show_user_odd_row div.LC_grade_user_name {
background: #DDEEDD;
@@ -5034,7 +5398,8 @@ div.LC_grade_show_problem_header,
div.LC_grade_submissions_header,
div.LC_grade_message_center_header,
div.LC_grade_assign_header {
- font: bold large $sans;
+ font-weight: bold;
+ font-size: large;
}
div.LC_grade_show_problem_problem,
div.LC_grade_submissions_body,
@@ -5044,6 +5409,456 @@ div.LC_grade_assign_body {
width: 99%;
background: #FFFFFF;
}
+span.LC_grade_check_note {
+ font-weight: normal;
+ font-size: medium;
+ display: inline;
+ position: absolute;
+ right: 1em;
+}
+
+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;
+}
+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 {
+ margin-top: 5px;
+}
+div.LC_edit_problem_header_edit_row {
+ background: $tabbg;
+ padding: 3px;
+ margin-bottom: 5px;
+}
+div.LC_edit_problem_header_title {
+ font-weight: bold;
+ font-size: larger;
+ background: $tabbg;
+ padding: 3px;
+}
+table.LC_edit_problem_header_title {
+ font-size: larger;
+ font-weight: bold;
+ width: 100%;
+ border-color: $pgbg;
+ border-style: solid;
+ border-width: $border;
+
+ background: $tabbg;
+ border-collapse: collapse;
+ padding: 0px
+}
+
+div.LC_edit_problem_discards {
+ float: left;
+ padding-bottom: 5px;
+}
+div.LC_edit_problem_saves {
+ float: right;
+ padding-bottom: 5px;
+}
+hr.LC_edit_problem_divide {
+ clear: both;
+ color: $tabbg;
+ background-color: $tabbg;
+ height: 3px;
+ border: 0px;
+}
+img.stift{
+ border-width:0;
+ vertical-align:middle;
+}
+
+table#LC_mainmenu{
+ margin-top:10px;
+ width:80%;
+
+}
+
+table#LC_mainmenu td.LC_mainmenu_col_fieldset{
+ vertical-align: top;
+ width: 45%;
+}
+.LC_mainmenu_fieldset_category {
+ color: $font;
+ background: $pgbg;
+ font-family: $sans;
+ font-size: small;
+ font-weight: bold;
+}
+
+div.LC_createcourse {
+ margin: 10px 10px 10px 10px;
+}
+
+/* ---- Remove when done ----
+# The following styles is part of the redesign of LON-CAPA and are
+# subject to change during this project.
+# Don't rely on their current functionality as they might be
+# changed or removed.
+# --------------------------*/
+
+a:hover,
+ol.LC_smallMenu a:hover,
+ol#LC_MenuBreadcrumbs a:hover,
+ol#LC_PathBreadcrumbs a:hover,
+ul#LC_TabMainMenuContent a:hover,
+.LC_FormSectionClearButton input:hover
+ul.LC_TabContent li:hover a{
+ color:#BF2317;
+ text-decoration:none;
+}
+
+h1 {
+ padding:5px 10px 5px 20px;
+ line-height:130%;
+}
+
+h2,h3,h4,h5,h6
+{
+ margin:5px 0px 5px 0px;
+ padding:0px;
+ line-height:130%;
+}
+.LC_hcell{
+ padding:3px 15px 3px 15px;
+ margin:0px;
+ background-color:$tabbg;
+ border-bottom:solid 1px $lg_border_color;
+}
+.LC_noBorder {
+ border:0px;
+}
+
+.LC_bgLightGrey{
+ background:URL(/adm/lonIcons/lightGreyBG.png) repeat-x left top;
+}
+.LC_bgLightGreyYellow {
+ background-color:#EFECE0;
+}
+
+/* Main Header with discription of Person, Course, etc. */
+.LC_HeadRight {
+ text-align: right;
+ float: right;
+ margin: 0px;
+ padding: 0px;
+ right:0;
+ position:absolute;
+ overflow:hidden;
+}
+
+p, .LC_ContentBox {
+ padding: 10px;
+
+}
+.LC_FormSectionClearButton input {
+
+ border:0px;
+ cursor:pointer;
+ text-decoration:underline;
+}
+
+
+dl,ul,div,fieldset {
+ margin: 10px 10px 10px 0px;
+ overflow:hidden;
+}
+ol.LC_smallMenu, ol#LC_PathBreadcrumbs {
+ margin: 0px;
+}
+
+ol.LC_smallMenu li {
+ display: inline;
+ padding: 5px 5px 0px 10px;
+ vertical-align: top;
+}
+
+ol.LC_smallMenu li img {
+ vertical-align: bottom;
+}
+
+ol.LC_smallMenu a {
+ font-size: 90%;
+ color: RGB(80, 80, 80);
+ text-decoration: none;
+}
+
+ol#LC_TabMainMenuContent {
+ display:block;
+ list-style:none;
+ margin: 0px 0px 10px 0px;
+ padding: 0px;
+}
+
+ol#LC_TabMainMenuContent li {
+ display: inline;
+ vertical-align: bottom;
+ border-bottom: solid 1px RGB(175, 175, 175);
+ border-right: solid 1px RGB(175, 175, 175);
+ padding: 5px 10px 5px 10px;
+ margin-right:3px;
+ line-height: 140%;
+ font-weight: bold;
+ white-space:nowrap;
+ background: url(/adm/lonIcons/lightGreyBG.png) repeat-x left top;
+}
+
+ol#LC_TabMainMenuContent li a{
+ color: RGB(47, 47, 47);
+ text-decoration: none;
+}
+ul.LC_TabContent {
+ margin:0px;
+ padding:0px;
+ display:block;
+ list-style:none;
+ min-height:1.5em;
+}
+ul.LC_TabContent li{
+ display:inline;
+ vertical-align:top;
+ border-bottom:solid 1px $lg_border_color;
+ border-right:solid 1px $lg_border_color;
+ padding:5px 10px 5px 10px;
+ margin-right:2px;
+ background: url(/adm/lonIcons/lightGreyBG.png) repeat-x left top;
+}
+ul.LC_TabContent li a, ul.LC_TabContent li{
+ color:rgb(47,47,47);
+ text-decoration:none;
+ font-size:95%;
+ font-weight:bold;
+ white-space:nowrap;
+}
+.LC_hideThis
+{
+ display:none;
+ visibility:hidden;
+}
+
+ol#LC_MenuBreadcrumbs, ol#LC_PathBreadcrumbs {
+ border-top: solid 1px RGB(255, 255, 255);
+ height: 20px;
+ line-height: 20px;
+ vertical-align: bottom;
+ margin: 0px 0px 30px 0px;
+ padding-left: 10px;
+ list-style-position: inside;
+ background: url(/adm/lonIcons/lightGreyBG.png) repeat-x left top;
+}
+
+ol#LC_MenuBreadcrumbs li, ol#LC_PathBreadcrumbs li {
+ background: url(/adm/lonIcons/arrow_white.png) no-repeat left center;
+ display: inline;
+ padding: 0px 0px 0px 10px;
+ vertical-align: bottom;
+ overflow:hidden;
+}
+
+ol#LC_MenuBreadcrumbs li a {
+ text-decoration: none;
+ font-size:90%;
+}
+ol#LC_PathBreadcrumbs li a{
+ text-decoration:none;
+ font-size:100%;
+ font-weight:bold;
+}
+.LC_ContentBoxSpecial
+{
+ border: solid 1px $lg_border_color;
+}
+.LC_PopUp
+{
+ padding:10px;
+ border-left:solid 1px $lg_border_color;
+ border-top:solid 1px $lg_border_color;
+ border-bottom:outset 1px $lg_border_color;
+ border-right:outset 1px $lg_border_color;
+ display:none;
+ position:absolute;
+ right:0;
+ background-color:white;
+ z-index:5;
+}
+
+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_ListStyleNormal_Border,
+.LC_ListStyleSpecial
+ {
+ /*display:block; */
+ list-style-position: inside;
+ list-style-type: none;
+ overflow: hidden;
+ padding: 0px;
+}
+
+.LC_ListStyleSimple li,
+.LC_ListStyleSimple dd,
+.LC_ListStyleNormal li,
+.LC_ListStyleNormal dd,
+.LC_ListStyleSpecial li,
+.LC_ListStyleSpecial dd
+ {
+ margin: 0px;
+ padding: 5px 5px 5px 10px;
+ clear: both;
+}
+
+.LC_ListStyleClean li,
+.LC_ListStyleClean dd {
+ padding-top: 0px;
+ padding-bottom: 0px;
+}
+
+.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:0px;
+ 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:0px;
+}
+
+div.LC_columnSection>* {
+ float: left;
+ margin: 10px 20px 10px 0px;
+ overflow:hidden;
+}
+div.LC_columnSection > .LC_ContentBox,
+div.LC_columnSection > .LC_ContentBoxSpecial
+ {
+ width: 400px;
+}
+
+.ContentBoxSpecialTemplate
+{
+ border: solid 1px $lg_border_color;
+}
+.ContentBoxTemplate {
+ padding:10px;
+}
+
+div.LC_columnSection > .ContentBoxTemplate,
+div.LC_columnSection > .ContentBoxSpecialTemplate
+ {
+ width: 600px;
+
+}
+
+.clear{
+ clear: both;
+ line-height: 0px;
+ font-size: 0px;
+ height: 0px;
+}
+
+.LC_loginpage_container {
+ text-align:left;
+ margin : 0 auto;
+ width:65%;
+ padding: 10px;
+ height: auto;
+ background-color:#FFFFFF;
+ border:1px solid #CCCCCC;
+}
+
+
+.LC_loginpage_loginContainer {
+ float:left;
+ width: 182px;
+ border:1px solid #CCCCCC;
+ background-color:$loginbg;
+}
+
+.LC_loginpage_loginContainer h2{
+ margin-top:0;
+ display:block;
+ background:$bgcol;
+ color:$textcol;
+ padding-left:5px;
+}
+.LC_loginpage_loginInfo {
+ margin-left:20px;
+ float:left;
+ width:30%;
+ border:1px solid #CCCCCC;
+ padding:10px;
+}
+
+.LC_loginpage_loginDomain {
+ margin-right:20px;
+ width:20%;
+ float:left;
+ padding:10px;
+}
+
+.LC_loginpage_space {
+ clear:both;
+ margin-bottom:20px;
+ border-bottom: 1px solid #CCCCCC;
+}
+
+.LC_loginpage_fieldset{
+ border: 1px solid #CCCCCC;
+ margin: 0 auto;
+}
+
+.LC_loginpage_legend{
+ padding: 2px;
+ margin: 0px;
+ font-size:14px;
+ font-weight:bold;
+}
+
END
}
@@ -5138,10 +5953,7 @@ Inputs: none
sub font_settings {
my $headerstring='';
- if (($env{'browser.os'} eq 'mac') && (!$env{'browser.mathml'})) {
- $headerstring.=
- ' ';
- } elsif (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
+ if (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
$headerstring.=
' ';
}
@@ -5200,8 +6012,15 @@ sub endheadtag {
Returns a uniform complete .. section for LON-CAPA web pages.
-Inputs: $title - optional title for the page
- $head_extra - optional extra HTML to put inside the
+Inputs:
+
+=over 4
+
+$title - optional title for the page
+
+$head_extra - optional extra HTML to put inside the
+
+=back
=cut
@@ -5216,44 +6035,54 @@ sub head {
Returns a complete .. section for LON-CAPA web pages.
-Inputs: $title - optional title for the page
- $head_extra - optional extra HTML to incude inside the
- $args - additional optional args supported are:
- only_body -> is true will set &bodytag() onlybodytag
+Inputs:
+
+=over 4
+
+$title - optional title for the page
+
+$head_extra - optional extra HTML to incude inside the
+
+$args - additional optional args supported are:
+
+=over 8
+
+ only_body -> is true will set &bodytag() onlybodytag
arg on
- no_nav_bar -> is true will set &bodytag() notopbar arg on
- add_entries -> additional attributes to add to the
- domain -> force to color decorate a page for a
+ no_nav_bar -> is true will set &bodytag() notopbar arg on
+ add_entries -> additional attributes to add to the
+ domain -> force to color decorate a page for a
specific domain
- function -> force usage of a specific rolish color
+ function -> force usage of a specific rolish color
scheme
- redirect -> see &headtag()
- bgcolor -> override the default page bg color
- js_ready -> return a string ready for being used in
+ redirect -> see &headtag()
+ bgcolor -> override the default page bg color
+ js_ready -> return a string ready for being used in
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
- force_register -> if is true will turn on the &bodytag()
+ force_register -> if is true will turn on the &bodytag()
$forcereg arg
- body_title -> alternate text to use instead of $title
+ body_title -> alternate text to use instead of $title
in the title box that appears, this text
is not auto translated like the $title is
- frameset -> if true will start with a
+ frameset -> if true will start with a
rather than
- no_title -> if true the title bar won't be shown
- skip_phases -> hash ref of
+ no_title -> if true the title bar won't be shown
+ skip_phases -> hash ref of
head -> skip the generation
body -> skip all 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
-
- no_auto_mt_title -> prevent &mt()ing the title arg
-
- inherit_jsmath -> when creating popup window in a page,
+ no_auto_mt_title -> prevent &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
+
+=back
+
=cut
sub start_page {
@@ -5294,11 +6123,22 @@ sub start_page {
}
if ($args->{'js_ready'}) {
- $result = &js_ready($result);
+ $result = &js_ready($result);
}
if ($args->{'html_encode'}) {
- $result = &html_encode($result);
+ $result = &html_encode($result);
}
+
+ if (exists($args->{'bread_crumbs'})) {
+ &Apache::lonhtmlcommon::clear_breadcrumbs();
+ if (ref($args->{'bread_crumbs'}) eq 'ARRAY') {
+ foreach my $crumb (@{$args->{'bread_crumbs'}}){
+ &Apache::lonhtmlcommon::add_breadcrumb($crumb);
+ }
+ }
+ $result .= &Apache::lonhtmlcommon::breadcrumbs();
+ }
+
return $result;
}
@@ -5340,7 +6180,7 @@ sub end_page {
if ($args->{'frameset'}) {
$result .= ' ';
} else {
- $result .= &endbodytag();
+ $result .= &endbodytag($args);
}
$result .= "\n";
@@ -5412,30 +6252,30 @@ sub simple_error_page {
}
{
- my $row_count;
+ my @row_count;
sub start_data_table {
my ($add_class) = @_;
my $css_class = (join(' ','LC_data_table',$add_class));
- undef($row_count);
+ unshift(@row_count,0);
return ''."\n";
}
sub end_data_table {
- undef($row_count);
+ shift(@row_count);
return '
'."\n";;
}
sub start_data_table_row {
my ($add_class) = @_;
- $row_count++;
- my $css_class = ($row_count % 2)?'':'LC_even_row';
+ $row_count[0]++;
+ my $css_class = ($row_count[0] % 2)?'LC_odd_row':'LC_even_row';
$css_class = (join(' ',$css_class,$add_class));
return ''."\n";;
}
sub continue_data_table_row {
my ($add_class) = @_;
- 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));
return ' '."\n";;
}
@@ -5445,7 +6285,7 @@ sub simple_error_page {
}
sub start_data_table_empty_row {
- $row_count++;
+# $row_count[0]++;
return ' '."\n";;
}
@@ -5717,12 +6557,17 @@ previous, future, or all.
5. reference to array of section restrictions (optional)
6. reference to results object (hash of hashes).
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
values set to access type.
Optional userdata hash returns an array with arguments in the
same order as loncoursedata::get_classlist() for student data.
+Optional statushash returns
+
Entries for end, start, section and status are blank because
of the possibility of multiple values for non-student roles.
@@ -5731,7 +6576,7 @@ of the possibility of multiple values fo
###############################################
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 %seclists;
@@ -5751,6 +6596,7 @@ sub get_course_users {
my $match = 0;
my $secmatch = 0;
my $section = $$classlist{$student}[$idx{section}];
+ my $status = $$classlist{$student}[$idx{status}];
if ($section eq '') {
$section = 'none';
}
@@ -5770,7 +6616,6 @@ sub get_course_users {
next;
}
}
- push(@{$seclists{$student}},$section);
if (defined($$types{'active'})) {
if ($$classlist{$student}[$idx{status}] eq 'Active') {
push(@{$$users{st}{$student}},'active');
@@ -5778,25 +6623,46 @@ sub get_course_users {
}
}
if (defined($$types{'previous'})) {
- if ($$classlist{$student}[$idx{end}] <= $now) {
+ if ($$classlist{$student}[$idx{status}] eq 'Expired') {
push(@{$$users{st}{$student}},'previous');
$match = 1;
}
}
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');
$match = 1;
}
}
- if ($match && ref($userdata) eq 'HASH') {
- $$userdata{$student} = $$classlist{$student};
+ if ($match) {
+ 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"))) {
my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
my $now = time;
+ my %displaystatus = ( previous => 'Expired',
+ active => 'Active',
+ future => 'Future',
+ );
+ my %nothide;
+ 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;
+ }
+ }
+ }
foreach my $person (sort(keys(%coursepersonnel))) {
my $match = 0;
my $secmatch = 0;
@@ -5830,6 +6696,12 @@ sub get_course_users {
$usec = 'none';
}
if ($uname ne '' && $udom ne '') {
+ if ($hidepriv) {
+ if ((&Apache::lonnet::privileged($uname,$udom)) &&
+ (!$nothide{$uname.':'.$udom})) {
+ next;
+ }
+ }
if ($end > 0 && $end < $now) {
$status = 'previous';
} elsif ($start > $now) {
@@ -5852,6 +6724,9 @@ sub get_course_users {
if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
push(@{$seclists{$uname.':'.$udom}},$usec);
}
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{$uname.':'.$udom}{$role}{$usec} = $displaystatus{$status};
+ }
}
}
}
@@ -5861,15 +6736,25 @@ sub get_course_users {
my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
if ( defined($csettings{'internal.courseowner'}) ) {
my $owner = $csettings{'internal.courseowner'};
- if ($owner !~ /^[^:]+:[^:]+$/) {
- $owner = $owner.':'.$cdom;
+ next if ($owner eq '');
+ my ($ownername,$ownerdom);
+ if ($owner =~ /^([^:]+):([^:]+)$/) {
+ $ownername = $1;
+ $ownerdom = $2;
+ } else {
+ $ownername = $owner;
+ $ownerdom = $cdom;
+ $owner = $ownername.':'.$ownerdom;
}
@{$$users{'ow'}{$owner}} = 'any';
if (defined($userdata) &&
- !exists($$userdata{$owner.':'.$cdom})) {
- &get_user_info($cdom,$owner,\%idx,$userdata);
- if (!grep(/^none$/,@{$seclists{$owner.':'.$cdom}})) {
- push(@{$seclists{$owner.':'.$cdom}},'none');
+ !exists($$userdata{$owner})) {
+ &get_user_info($ownerdom,$ownername,\%idx,$userdata);
+ if (!grep(/^none$/,@{$seclists{$owner}})) {
+ push(@{$seclists{$owner}},'none');
+ }
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{$owner}{'ow'}{'none'} = 'Any';
}
}
}
@@ -5889,6 +6774,8 @@ sub get_user_info {
&plainname($uname,$udom,'lastname');
$$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
$$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
+ my %idhash = &Apache::lonnet::idrget($udom,($uname));
+ $$userdata{$uname.':'.$udom}[$$idx{id}] = $idhash{$uname};
return;
}
@@ -6009,24 +6896,40 @@ sub default_quota {
my ($udom,$inststatus) = @_;
my ($defquota,$settingstatus);
my %quotahash = &Apache::lonnet::get_dom('configuration',
- ['quota'],$udom);
- if (ref($quotahash{'quota'}) eq 'HASH') {
+ ['quotas'],$udom);
+ if (ref($quotahash{'quotas'}) eq 'HASH') {
if ($inststatus ne '') {
my @statuses = split(/:/,$inststatus);
foreach my $item (@statuses) {
- if ($quotahash{'quota'}{$item} ne '') {
- if ($defquota eq '') {
- $defquota = $quotahash{'quota'}{$item};
- $settingstatus = $item;
- } elsif ($quotahash{'quota'}{$item} > $defquota) {
- $defquota = $quotahash{'quota'}{$item};
- $settingstatus = $item;
+ if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
+ if ($quotahash{'quotas'}{'defaultquota'}{$item} ne '') {
+ if ($defquota eq '') {
+ $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
+ $settingstatus = $item;
+ } elsif ($quotahash{'quotas'}{'defaultquota'}{$item} > $defquota) {
+ $defquota = $quotahash{'quotas'}{'defaultquota'}{$item};
+ $settingstatus = $item;
+ }
+ }
+ } else {
+ 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 '') {
- $defquota = $quotahash{'quota'}{'default'};
+ if (ref($quotahash{'quotas'}{'defaultquota'}) eq 'HASH') {
+ $defquota = $quotahash{'quotas'}{'defaultquota'}{'default'};
+ } else {
+ $defquota = $quotahash{'quotas'}{'default'};
+ }
$settingstatus = 'default';
}
} else {
@@ -6078,14 +6981,14 @@ sub get_secgrprole_info {
}
sub user_picker {
- my ($dom,$srch,$forcenewuser,$caller) = @_;
+ my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
my $currdom = $dom;
my %curr_selected = (
srchin => 'dom',
srchby => 'lastname',
);
my $srchterm;
- if (ref($srch) eq 'HASH') {
+ if ((ref($srch) eq 'HASH') && ($env{'form.origform'} ne 'crtusername')) {
if ($srch->{'srchby'} ne '') {
$curr_selected{'srchby'} = $srch->{'srchby'};
}
@@ -6172,7 +7075,16 @@ sub user_picker {
if ($forcenewuser) {
if (ref($srch) eq 'HASH') {
if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
- $new_user_create = ' &"').'" onclick="javascript:setSearch(\'1\','.$caller.');" />
';
+ if ($cancreate) {
+ $new_user_create = ' &"').'" onclick="javascript:setSearch(\'1\','.$caller.');" />
';
+ } else {
+ my $helplink = ' href="javascript:helpMenu('."'display'".')"';
+ my %usertypetext = (
+ official => 'institutional',
+ unofficial => 'non-institutional',
+ );
+ $new_user_create = ''.&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.").' '.&mt('Contact the helpdesk for assistance.',$helplink).' ';
+ }
}
}
@@ -6301,57 +7213,223 @@ END_BLOCK
return $output;
}
-sub username_rule_check {
- my ($srch,$caller) = @_;
- my ($response,@curr_rules,%inst_results,$rulematch);
- my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($srch->{'srchdomain'});
- if (ref($srch) eq 'HASH') {
- (my $inst_response,%inst_results) =
- &Apache::lonnet::get_instuser($srch->{'srchdomain'},
- $srch->{'srchterm'});
- my %domconfig = &Apache::lonnet::get_dom('configuration',
- ['usercreation'],$srch->{'srchdomain'});
- if (ref($domconfig{'usercreation'}) eq 'HASH') {
- if (ref($domconfig{'usercreation'}{'username_rule'}) eq 'ARRAY') {
- @curr_rules = @{$domconfig{'usercreation'}{'username_rule'}};
- }
- }
- if (@curr_rules > 0) {
- my $domdesc = &Apache::lonnet::domain($srch->{'srchdomain'},'description');
- my $instuser_reqd;
- my %rule_check = &Apache::lonnet::inst_rulecheck($srch->{'srchdomain'},$srch->{'srchterm'},\@curr_rules);
- foreach my $rule (@curr_rules) {
- if ($rule_check{$rule}) {
- $rulematch = $rule;
- if ($inst_response eq 'ok') {
- if (keys(%inst_results) == 0) {
- if ($caller eq 'new') {
- $response = &mt('The username you chose matches the format of usernames defined for [_1] , but the user does not exist in the institutional directory.',$domdesc).' '.&mt("You must choose a username with a different format -- one that will not conflict with 'official' institutional usernames.");
- }
+sub user_rule_check {
+ my ($usershash,$checks,$alerts,$rulematch,$inst_results,$curr_rules,$got_rules) = @_;
+ my $response;
+ if (ref($usershash) eq 'HASH') {
+ foreach my $user (keys(%{$usershash})) {
+ my ($uname,$udom) = split(/:/,$user);
+ next if ($udom eq '' || $uname eq '');
+ my ($id,$newuser);
+ if (ref($usershash->{$user}) eq 'HASH') {
+ $newuser = $usershash->{$user}->{'newuser'};
+ $id = $usershash->{$user}->{'id'};
+ }
+ my $inst_response;
+ if (ref($checks) eq 'HASH') {
+ if (defined($checks->{'username'})) {
+ ($inst_response,%{$inst_results->{$user}}) =
+ &Apache::lonnet::get_instuser($udom,$uname);
+ } elsif (defined($checks->{'id'})) {
+ ($inst_response,%{$inst_results->{$user}}) =
+ &Apache::lonnet::get_instuser($udom,undef,$id);
+ }
+ } else {
+ ($inst_response,%{$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'};
}
}
- last;
}
+ $got_rules->{$udom} = 1;
}
- if ($response) {
- if ((ref($rules) eq 'HASH') && (ref($ruleorder) eq 'ARRAY')) {
- if (@{$ruleorder} > 0) {
- $response .= ' '.&mt('Usernames with the following format(s) may only be used for verified users at [_1]:',$domdesc).' ';
- foreach my $rule (@{$ruleorder}) {
- if (grep(/^\Q$rule\E$/,@curr_rules)) {
- if (ref($rules->{$rule}) eq 'HASH') {
- $response .= ''.$rules->{$rule}{'name'}.': '.
- $rules->{$rule}{'desc'}.' ';
+ 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 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;
+ }
+ }
+ }
+ }
+ last;
}
}
}
}
- $response .= ' ';
}
}
}
}
- return ($response,$rulematch,$rules,%inst_results);
+ 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 = ' '.&mt("$text{$check} with the following format(s) may only be used for verified users at [_1]:",$domdesc).' ';
+ foreach my $rule (@{$ruleorder}) {
+ if (ref($curr_rules) eq 'ARRAY') {
+ if (grep(/^\Q$rule\E$/,@{$curr_rules})) {
+ if (ref($rules->{$rule}) eq 'HASH') {
+ $output .= ''.$rules->{$rule}{'name'}.': '.
+ $rules->{$rule}{'desc'}.' ';
+ }
+ }
+ }
+ }
+ $output .= ' ';
+ }
+ }
+ 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.",''.$domdesc.' ').' ';
+ 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',
+ );
+ return %fieldtitles;
+}
+
+sub sorted_inst_types {
+ my ($dom) = @_;
+ my ($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 ($settings,$allcourses,$LC_code) = @_;
+# Get complete list of course sections to update
+ my @currsections = ();
+ my @currxlists = ();
+ my $coursecode = $$settings{'internal.coursecode'};
+
+ if ($$settings{'internal.sectionnums'} ne '') {
+ @currsections = split(/,/,$$settings{'internal.sectionnums'});
+ }
+
+ if ($$settings{'internal.crosslistings'} ne '') {
+ @currxlists = split(/,/,$$settings{'internal.crosslistings'});
+ }
+
+ if (@currxlists > 0) {
+ foreach (@currxlists) {
+ if (m/^([^:]+):(\w*)$/) {
+ unless (grep/^$1$/,@{$allcourses}) {
+ push @{$allcourses},$1;
+ $$LC_code{$1} = $2;
+ }
+ }
+ }
+ }
+
+ if (@currsections > 0) {
+ foreach (@currsections) {
+ if (m/^(\w+):(\w*)$/) {
+ my $sec = $coursecode.$1;
+ my $lc_sec = $2;
+ unless (grep/^$sec$/,@{$allcourses}) {
+ push @{$allcourses},$sec;
+ $$LC_code{$sec} = $lc_sec;
+ }
+ }
+ }
+ }
+ return;
}
=pod
@@ -6362,7 +7440,7 @@ sub username_rule_check {
=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
$query. The parameters listed in $possible_names (an array reference),
@@ -6391,7 +7469,7 @@ sub get_unprocessed_cgi {
=pod
-=item * cacheheader()
+=item * &cacheheader()
returns cache-controlling header code
@@ -6408,7 +7486,7 @@ sub cacheheader {
=pod
-=item * no_cache($r)
+=item * &no_cache($r)
specifies header code to not have cache
@@ -6444,7 +7522,7 @@ sub content_type {
=pod
-=item * add_to_env($name,$value)
+=item * &add_to_env($name,$value)
adds $name to the %env hash with value
$value, if $name already exists, the entry is converted to an array
@@ -6471,7 +7549,7 @@ sub add_to_env {
=pod
-=item * get_env_multiple($name)
+=item * &get_env_multiple($name)
gets $name from the %env hash, it seemlessly handles the cases where multiple
values may be defined and end up as an array ref.
@@ -6494,6 +7572,232 @@ sub get_env_multiple {
return(@values);
}
+sub ask_for_embedded_content {
+ my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
+ my $upload_output = '
+ ';
+ return $upload_output;
+}
+
+sub upload_embedded {
+ my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota,
+ $current_disk_usage) = @_;
+ my $output;
+ 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'};
+
+ $env{'form.embedded_orig_'.$i} =
+ &unescape($env{'form.embedded_orig_'.$i});
+ my ($path,$fname) =
+ ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)});
+ # no path, whole string is fname
+ if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} };
+
+ $path = $env{'form.currentpath'}.$path;
+ $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($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'
+ || $state eq 'file_exists' ) {
+ $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 LONCAPA use - rename the file with a different extension and re-upload. ',$1);
+ 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);
+ next;
+ } elsif ($fname=~/\.(\d+)\.(\w+)$/) {
+ $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2);
+ next;
+ }
+
+ $env{'form.embedded_item_'.$i.'.filename'}=$fname;
+ if ($context eq 'portfolio') {
+ my $result=
+ &Apache::lonnet::userfileupload('embedded_item_'.$i,'',
+ $dirpath.$path);
+ if ($result !~ m|^/uploaded/|) {
+ $output .= ''
+ .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].'
+ ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i})
+ .' ';
+ next;
+ } else {
+ $output .= ''.&mt('Uploaded [_1]',''.
+ $path.$fname.' ').'
';
+ }
+ } 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(/\//,$fullpath);
+ my $count;
+ my $filepath = $dir_root;
+ for ($count=4;$count<=$#parts;$count++) {
+ $filepath .= "/$parts[$count]";
+ if ((-e $filepath)!=1) {
+ mkdir($filepath,0770);
+ }
+ }
+ my $fh;
+ if (!open($fh,'>'.$dest)) {
+ &Apache::lonnet::logthis('Failed to create '.$dest);
+ $output .= ''.
+ &mt('An error occurred while trying to upload [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
+ ' ';
+ } else {
+ if (!print $fh $env{'form.embedded_item_'.$i}) {
+ &Apache::lonnet::logthis('Failed to write to '.$dest);
+ $output .= ''.
+ &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}).
+ ' ';
+ } else {
+ if ($context eq 'testbank') {
+ $output .= &mt('Embedded file uploaded successfully:').
+ ' '.
+ $orig_uploaded_filename.' ';
+ } else {
+ $output .= ''.
+ &mt('View embedded file: [_1]',''.
+ $orig_uploaded_filename.' ').' ';
+ }
+ }
+ close($fh);
+ }
+ }
+ }
+ 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].',''.$fname.' ',$path);
+ } elsif (-e $path.'/'.$fname) {
+ $state = 'exists';
+ $msg = &mt('Unable to upload [_1]. A file by that name was found in [_2].',''.$fname.' ',$path);
+ }
+ if ($state eq 'exists') {
+ $msg = ''.$msg.' ';
+ }
+ 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})) / 1000; #express in k (1024?)
+ my $getpropath = 1;
+ my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname,
+ $getpropath);
+ my $found_file = 0;
+ my $locked_file = 0;
+ foreach my $line (@dir_list) {
+ my ($file_name)=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) eq 'true') {
+ $locked_file = 1;
+ }
+ }
+ }
+ if (($current_disk_usage + $filesize) > $disk_quota){
+ my $msg = ''.
+ &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded.',''.$fname.' ',$filesize).' '.
+ ' '.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.',$disk_quota,$current_disk_usage);
+ return ('will_exceed_quota',$msg);
+ } elsif ($found_file) {
+ if ($locked_file) {
+ my $msg = '';
+ $msg .= &mt('Unable to upload [_1]. A locked file by that name was found in [_2].',''.$fname.' ',''.$port_path.$env{'form.currentpath'}.' ');
+ $msg .= ' ';
+ $msg .= &mt('You will be able to rename or delete existing [_1] after a grade has been assigned.',''.$fname.' ');
+ return ('file_locked',$msg);
+ } else {
+ my $msg = '';
+ $msg .= &mt('Unable to upload [_1]. A file by that name was found in [_2].',''.$fname.' ',$port_path.$env{'form.currentpath'});
+ $msg .= ' ';
+ $msg .= ' ';
+ $msg .= &mt('To upload, rename or delete existing [_1] in [_2].',''.$fname.' ', $port_path.$env{'form.currentpath'});
+ return ('file_exists',$msg);
+ }
+ }
+}
+
=pod
@@ -6503,7 +7807,7 @@ sub get_env_multiple {
=over 4
-=item * upfile_store($r)
+=item * &upfile_store($r)
Store uploaded file, $r should be the HTTP Request object,
needs $env{'form.upfile'}
@@ -6533,7 +7837,7 @@ sub upfile_store {
=pod
-=item * load_tmp_file($r)
+=item * &load_tmp_file($r)
Load uploaded file from tmp, $r should be the HTTP Request object,
needs $env{'form.datatoken'},
@@ -6557,7 +7861,7 @@ sub load_tmp_file {
=pod
-=item * upfile_record_sep()
+=item * &upfile_record_sep()
Separate uploaded file into records
returns array of records,
@@ -6579,7 +7883,7 @@ sub upfile_record_sep {
=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'}
@@ -6664,7 +7968,7 @@ sub record_sep {
=pod
-=item * upfile_select_html()
+=item * &upfile_select_html()
Return HTML code to select a file from the users machine and specify
the file type.
@@ -6682,7 +7986,7 @@ sub upfile_select_html {
# xml => &mt('HTML/XML'),
);
my $Str = ' '.
- ' Type: ';
+ ' '.&mt('Type').': ';
foreach my $type (sort(keys(%Types))) {
$Str .= ''.$Types{$type}." \n";
}
@@ -6711,7 +8015,7 @@ sub get_samples {
=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
Apache Request ref, $records is an arrayref from
@@ -6723,7 +8027,7 @@ Apache Request ref, $records is an array
######################################################
sub csv_print_samples {
my ($r,$records) = @_;
- my $samples = &get_samples($records,3);
+ my $samples = &get_samples($records,5);
$r->print(&mt('Samples').' '.&start_data_table().
&start_data_table_header_row());
@@ -6747,7 +8051,7 @@ sub csv_print_samples {
=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.
@@ -6770,7 +8074,7 @@ sub csv_print_select_table {
&end_data_table_header_row()."\n");
foreach my $array_ref (@$d) {
my ($value,$display,$defaultcol)=@{ $array_ref };
- $r->print(&start_data_table_row().''.$display.' ');
+ $r->print(&start_data_table_row().''.$display.' ');
$r->print('');
@@ -6778,7 +8082,7 @@ sub csv_print_select_table {
foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
$r->print('Column '.($sample+1).' ');
+ '>'.&mt('Column [_1]',($sample+1)).'');
}
$r->print(' '.&end_data_table_row()."\n");
$i++;
@@ -6793,7 +8097,7 @@ sub csv_print_select_table {
=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.
@@ -6809,7 +8113,8 @@ sub csv_samples_select_table {
my ($r,$records,$d) = @_;
my $i=0;
#
- my $samples = &get_samples($records,3);
+ my $max_samples = 5;
+ my $samples = &get_samples($records,$max_samples);
$r->print(&start_data_table().
&start_data_table_header_row().''.
&mt('Field').' '.&mt('Samples').' '.
@@ -6825,7 +8130,7 @@ sub csv_samples_select_table {
$display.'');
}
$r->print('');
- foreach my $line (0..2) {
+ foreach my $line (0..($max_samples-1)) {
if (defined($samples->[$line]{$key})) {
$r->print($samples->[$line]{$key}." \n");
}
@@ -6843,7 +8148,7 @@ sub csv_samples_select_table {
=pod
-=item clean_excel_name($name)
+=item * &clean_excel_name($name)
Returns a replacement for $name which does not contain any illegal characters.
@@ -6862,7 +8167,7 @@ sub clean_excel_name {
=pod
-=item * check_if_partid_hidden($id,$symb,$udom,$uname)
+=item * &check_if_partid_hidden($id,$symb,$udom,$uname)
Returns either 1 or undef
@@ -6903,7 +8208,7 @@ sub check_if_partid_hidden {
=over 4
-=item get_cgi_id
+=item * &get_cgi_id()
Inputs: none
@@ -6927,7 +8232,7 @@ sub get_cgi_id {
=pod
-=item DrawBarGraph
+=item * &DrawBarGraph()
Facilitates the plotting of data in a (stacked) bar graph.
Puts plot definition data into the users environment in order for
@@ -7062,7 +8367,7 @@ sub DrawBarGraph {
$ValuesHash{$id.'.'.$key} = $value;
}
#
- &Apache::lonnet::appenv(%ValuesHash);
+ &Apache::lonnet::appenv(\%ValuesHash);
return ' ';
}
@@ -7071,7 +8376,7 @@ sub DrawBarGraph {
=pod
-=item DrawXYGraph
+=item * &DrawXYGraph()
Facilitates the plotting of data in an XY graph.
Puts plot definition data into the users environment in order for
@@ -7152,7 +8457,7 @@ sub DrawXYGraph {
$ValuesHash{$id.'.'.$key} = $value;
}
#
- &Apache::lonnet::appenv(%ValuesHash);
+ &Apache::lonnet::appenv(\%ValuesHash);
return ' ';
}
@@ -7161,7 +8466,7 @@ sub DrawXYGraph {
=pod
-=item DrawXYYGraph
+=item * &DrawXYYGraph()
Facilitates the plotting of data in an XY graph with two Y axes.
Puts plot definition data into the users environment in order for
@@ -7254,7 +8559,7 @@ sub DrawXYYGraph {
$ValuesHash{$id.'.'.$key} = $value;
}
#
- &Apache::lonnet::appenv(%ValuesHash);
+ &Apache::lonnet::appenv(\%ValuesHash);
return ' ';
}
@@ -7271,7 +8576,7 @@ Bad place for them but what the hell.
=over 4
-=item &chartlink
+=item * &chartlink()
Returns a link to the chart for a specific student.
@@ -7310,9 +8615,9 @@ sub chartlink {
=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.
Will not overwrite existing values of the form parameters.
@@ -7332,6 +8637,8 @@ a hash ref describing the data to be sto
Returns: both routines return nothing
+=back
+
=cut
#######################################################
@@ -7384,7 +8691,7 @@ sub store_settings {
'got error:'.$put_result);
}
# Make sure these settings stick around in this session, too
- &Apache::lonnet::appenv(%AppHash);
+ &Apache::lonnet::appenv(\%AppHash);
return;
}
@@ -7412,16 +8719,424 @@ sub restore_settings {
}
}
+#######################################################
+#######################################################
+
+=pod
+
+=head1 Domain E-mail Routines
+
+=over 4
+
+=item * &build_recipient_list()
+
+Build recipient lists for three types of e-mail:
+(a) Error Reports, (b) Package Updates, (c) Help requests, generated by
+lonerrorhandler.pm, CHECKRPMS and lonsupportreq.pm respectively.
+
+Inputs:
+defmail (scalar - email address of default recipient),
+mailing type (scalar - errormail, packagesmail, or helpdeskmail),
+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
+
+Returns: comma separated list of addresses to which to send e-mail.
+
+=back
+
+=cut
+
+############################################################
+############################################################
+sub build_recipient_list {
+ my ($defmail,$mailing,$defdom,$origmail) = @_;
+ my @recipients;
+ my $otheremails;
+ my %domconfig =
+ &Apache::lonnet::get_dom('configuration',['contacts'],$defdom);
+ if (ref($domconfig{'contacts'}) eq 'HASH') {
+ 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'};
+ }
+ }
+ } elsif ($origmail ne '') {
+ push(@recipients,$origmail);
+ }
+ 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);
+ }
+ }
+ }
+ my $recipientlist = join(',',@recipients);
+ 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)
+
+Returns: nothing
+
+Side effects: populates trails and allitems hash references.
+
+=cut
+
+sub extract_categories {
+ my ($categories,$cats,$trails,$allitems,$idx,$jsarray,$subcats) = @_;
+ 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)');
+ } 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);
+ }
+ } else {
+ if (ref($subcats) eq 'HASH') {
+ $subcats->{$item} = [];
+ }
+ }
+ }
+ }
+ }
+ 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) = @_;
+ 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);
+ 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;
+ }
+ }
+ 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.
+
+Returns: $output (markup to be displayed)
+
+=cut
+
+sub assign_categories_table {
+ my ($cathash,$currcat) = @_;
+ my $output;
+ if (ref($cathash) eq 'HASH') {
+ my (@cats,@trails,%allitems,%idx,@jsarray,@path,$maxdepth);
+ &extract_categories($cathash,\@cats,\@trails,\%allitems,\%idx,\@jsarray);
+ $maxdepth = scalar(@cats);
+ if (@cats > 0) {
+ my $itemcount = 0;
+ if (ref($cats[0]) eq 'ARRAY') {
+ $output = &Apache::loncommon::start_data_table();
+ my @currcategories;
+ if ($currcat ne '') {
+ @currcategories = split('&',$currcat);
+ }
+ for (my $i=0; $i<@{$cats[0]}; $i++) {
+ my $parent = $cats[0][$i];
+ my $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ next if ($parent eq 'instcode');
+ my $item = &escape($parent).'::0';
+ my $checked = '';
+ if (@currcategories > 0) {
+ if (grep(/^\Q$item\E$/,@currcategories)) {
+ $checked = ' checked="checked" ';
+ }
+ }
+ $output .= ' '.
+ ' '.$parent.' '.
+ ' ';
+ my $depth = 1;
+ push(@path,$parent);
+ $output .= &assign_category_rows($itemcount,\@cats,$depth,$parent,\@path,\@currcategories);
+ pop(@path);
+ $output .= ' ';
+ $itemcount ++;
+ }
+ $output .= &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
+
+Returns: $output (markup to be displayed).
+
+=cut
+
+sub assign_category_rows {
+ my ($itemcount,$cats,$depth,$parent,$path,$currcategories) = @_;
+ 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 .= ' ';
+ }
+ }
+ }
+ return $text;
+}
+
+############################################################
+############################################################
+
+
sub commit_customrole {
- my ($udom,$uname,$url,$three,$four,$five,$start,$end) = @_;
- my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.'@'.$three.' in '.$url.
+ my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;
+ my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
($start?', '.&mt('starting').' '.localtime($start):'').
($end?', ending '.localtime($end):'').': '.
&Apache::lonnet::assigncustomrole(
- $udom,$uname,$url,$three,$four,$five,$end,$start).
+ $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).
' ';
return $output;
}
@@ -7438,8 +9153,8 @@ sub commit_standardrole {
my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
$one,$two,$sec,$context);
if (($result =~ /^error/) || ($result eq 'not_in_class') ||
- ($result eq 'unknown_course')) {
- $output = "Error: $result\n";
+ ($result eq 'unknown_course') || ($result eq 'refused')) {
+ $output = $logmsg.' '.&mt('Error: ').$result."\n";
} else {
$output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
($start?', '.&mt('starting').' '.localtime($start):'').
@@ -7456,7 +9171,7 @@ sub commit_standardrole {
$output = &mt('Assigning').' '.$three.' in '.$url.
($start?', '.&mt('starting').' '.localtime($start):'').
($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') {
$output .= $result.$linefeed;
} else {
@@ -7468,7 +9183,7 @@ sub commit_standardrole {
sub commit_studentrole {
my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
- my ($result,$linefeed);
+ my ($result,$linefeed,$oldsecurl,$newsecurl);
if ($context eq 'auto') {
$linefeed = "\n";
} else {
@@ -7480,37 +9195,92 @@ sub commit_studentrole {
my $secchange = 0;
my $expire_role_result;
my $modify_section_result;
- unless ($oldsec eq '-1') {
- unless ($sec eq $oldsec) {
+ if ($oldsec ne '-1') {
+ if ($oldsec ne $sec) {
$secchange = 1;
+ my $now = time;
my $uurl='/'.$cid;
$uurl=~s/\_/\//g;
if ($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;
}
}
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);
if ($modify_section_result =~ /^ok/) {
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') {
- $$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 {
- $$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 {
- $$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;
} 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 [_3] -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 {
- $$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";
}
return $result;
@@ -7622,19 +9392,28 @@ sub construct_course {
$outcome .= $clonemsg.$linefeed;
my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
# Copy all files
- &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid);
+ &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},$args->{'dateshift'});
# Restore URL
$cenv{'url'}=$oldcenv{'url'};
# Restore title
$cenv{'description'}=$oldcenv{'description'};
-# restore grading mode
- if (defined($oldcenv{'grading'})) {
- $cenv{'grading'}=$oldcenv{'grading'};
- }
# Mark as cloned
$cenv{'clonedfrom'}=$cloneid;
- delete($cenv{'default_enrollment_start_date'});
- delete($cenv{'default_enrollment_end_date'});
+# Need to clone grading mode
+ 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',
+ 'categories'],
+ $$crsudom,$$crsunum);
}
#
@@ -7662,7 +9441,6 @@ sub construct_course {
} else {
$cenv{'internal.courseowner'} = $args->{'curruser'};
}
-
my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
if ($args->{'crssections'}) {
$cenv{'internal.sectionnums'} = '';
@@ -7722,7 +9500,7 @@ sub construct_course {
}
if ($args->{'notify_dc'}) {
if ($uname ne '') {
- push(@notified,$uname.'@'.$udom);
+ push(@notified,$uname.':'.$udom);
}
}
if (@notified > 0) {
@@ -7862,10 +9640,10 @@ sub construct_course {
$outcome .= ($fatal?$errtext:'read ok').' - ';
my $title; my $url;
if ($args->{'firstres'} eq 'syl') {
- $title='Syllabus';
+ $title=&mt('Syllabus');
$url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
} else {
- $title='Navigate Contents';
+ $title=&mt('Navigate Contents');
$url='/adm/navmaps';
}
@@ -7919,28 +9697,14 @@ sub icon {
return &lonhttpdurl($iconname);
}
-sub lonhttpd_port {
- my $lonhttpd_port=$Apache::lonnet::perlvar{'lonhttpdPort'};
- if (!defined($lonhttpd_port)) { $lonhttpd_port='8080'; }
- # IE doesn't like a secure page getting images from a non-secure
- # port (when logging we haven't parsed the browser type so default
- # back to secure
- if ((!exists($env{'browser.type'}) || $env{'browser.type'} eq 'explorer')
- && $ENV{'SERVER_PORT'} == 443) {
- return 443;
- }
- return $lonhttpd_port;
-
-}
-
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 $lonhttpd_port = &lonhttpd_port();
- if ($lonhttpd_port == 443) {
- return 'https://'.$ENV{'SERVER_NAME'}.$url;
- }
- return 'http://'.$ENV{'SERVER_NAME'}.':'.$lonhttpd_port.$url;
+ return $url;
}
sub connection_aborted {
@@ -8018,7 +9782,7 @@ sub init_user_environment {
}
# Give them a new cookie
my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
- : $now);
+ : $now.$$.int(rand(10000)));
$cookie="$username\_$id\_$domain\_$authhost";
# Initialize roles
@@ -8106,6 +9870,11 @@ sub init_user_environment {
}
}
+ foreach my $tool ('aboutme','blog','portfolio') {
+ $userenv{'availabletools.'.$tool} =
+ &Apache::lonnet::usertools_access($username,$domain,$tool,'reload');
+ }
+
$env{'user.environment'} = "$lonids/$cookie.id";
if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
@@ -8118,8 +9887,8 @@ sub init_user_environment {
}
untie(%disk_env);
} else {
- &Apache::lonnet::logthis("WARNING: ".
- 'Could not create environment storage in lonauth: '.$!.' ');
+ &Apache::lonnet::logthis("WARNING: ".
+ 'Could not create environment storage in lonauth: '.$!.' ');
return 'error: '.$!;
}
}
@@ -8133,12 +9902,54 @@ sub init_user_environment {
sub _add_to_env {
my ($idf,$env_data,$prefix) = @_;
- while (my ($key,$value) = each(%$env_data)) {
- $idf->{$prefix.$key} = $value;
- $env{$prefix.$key} = $value;
+ if (ref($env_data) eq 'HASH') {
+ while (my ($key,$value) = each(%$env_data)) {
+ $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) {
+ $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