--- loncom/interface/courseprefs.pm 2021/08/04 19:59:10 1.93
+++ loncom/interface/courseprefs.pm 2023/06/03 11:21:37 1.124
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler to set configuration settings for a course
#
-# $Id: courseprefs.pm,v 1.93 2021/08/04 19:59:10 raeburn Exp $
+# $Id: courseprefs.pm,v 1.124 2023/06/03 11:21:37 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -52,12 +52,16 @@ This module is used for configuration of
=item process_changes()
+=item process_linkprot()
+
=item get_sec_str()
=item check_clone()
=item store_changes()
+=item store_linkprot()
+
=item update_env()
=item display_disallowed()
@@ -112,7 +116,7 @@ This module is used for configuration of
=item item_table_row_end()
-=item yes_no_radio()
+=item yesno_radio()
=item select_from_options()
@@ -220,6 +224,8 @@ use Apache::lonparmset;
use Apache::courseclassifier;
use Apache::lonlocal;
use LONCAPA qw(:DEFAULT :match);
+use Crypt::CBC;
+use Time::HiRes qw( sleep );
my $registered_cleanup;
my $modified_courses;
@@ -288,7 +294,7 @@ sub handler {
excc => 'Exclude from community catalog',
clon => 'Users allowed to clone community',
rept => 'Replacement titles for standard community roles',
- time => 'Timezone where the community is located',
+ time => 'Time Zone where the community is located',
date => 'Locale used for community calendar',
coco => 'Community Content',
copo => 'Community Policy',
@@ -310,14 +316,14 @@ sub handler {
idnu => 'Course ID or number',
unco => 'Unique code',
desc => 'Course Description',
- cred => 'Student credits',
+ cred => 'Student credits',
ownr => 'Course Owner',
cown => 'Course Co-owners',
catg => 'Categorize course',
excc => 'Exclude from course catalog',
clon => 'Users allowed to clone course',
rept => 'Replacement titles for standard course roles',
- time => 'Timezone in which the course takes place',
+ time => 'Time Zone in which the course takes place',
date => 'Locale used for course calendar',
coco => 'Course Content',
copo => 'Course Policy',
@@ -365,16 +371,48 @@ sub handler {
}
my %values=&Apache::lonnet::dump('environment',$cdom,$cnum);
- my %courselti=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1);
- if ($courselti{'lock'}) {
- delete($courselti{'lock'});
+ my %linkprot=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1);
+ my %ltienc = &Apache::lonnet::dump('nohist_ltienc',$cdom,$cnum,undef,undef,undef,1);
+ my %ltitools = &Apache::lonnet::dump('ltitools',$cdom,$cnum,undef,undef,undef,1);
+ my %ltitoolsenc = &Apache::lonnet::dump('nohist_toolsenc',$cdom,$cnum,undef,undef,undef,1);
+ foreach my $id (keys(%linkprot)) {
+ if (ref($linkprot{$id}) eq 'HASH') {
+ if (ref($ltienc{$id}) eq 'HASH') {
+ $values{'linkprot'}{$id} = { %{$linkprot{$id}}, %{$ltienc{$id}} };
+ } else {
+ $values{'linkprot'}{$id} = $linkprot{$id};
+ }
+ }
+ unless ($phase eq 'process') {
+ if (ref($values{'linkprot'}{$id}) eq 'HASH') {
+ delete($values{'linkprot'}{$id}{'secret'});
+ }
+ }
+ }
+ if ($linkprot{'lock'}) {
+ delete($linkprot{'lock'});
+ }
+ foreach my $id (keys(%ltitools)) {
+ if (ref($ltitools{$id}) eq 'HASH') {
+ if (ref($ltitoolsenc{$id}) eq 'HASH') {
+ $values{'ltitools'}{$id} = { %{$ltitools{$id}}, %{$ltitoolsenc{$id}} };
+ } else {
+ $values{'ltitools'}{$id} = $ltitools{$id};
+ }
+ }
+ unless ($phase eq 'process') {
+ if (ref($values{'ltitools'}{$id}) eq 'HASH') {
+ delete($values{'ltitools'}{$id}{'secret'});
+ }
+ }
+ }
+ if ($ltitools{'lock'}) {
+ delete($ltitools{'lock'});
}
- $values{'linkprotection'} = \%courselti;
my @prefs_order = ('courseinfo','localization','feedback','discussion',
'classlists','appearance','grading','printouts',
- 'menuitems','linkprotection','spreadsheet','bridgetasks',
- 'lti','other');
-
+ 'menuitems','ltitools','linkprot','spreadsheet',
+ 'bridgetasks','lti','other');
my %prefs = (
'courseinfo' =>
{ text => $lt{'gens'},
@@ -473,7 +511,8 @@ sub handler {
help => 'Course_Prefs_Display',
ordered => ['default_xml_style','pageseparators',
'disable_receipt_display','texengine',
- 'tthoptions','uselcmath','usejsme'],
+ 'tthoptions','uselcmath','usejsme',
+ 'inline_chem','extresource'],
itemtext => {
default_xml_style => 'Default XML style file',
pageseparators => 'Visibly Separate Items on Pages',
@@ -482,6 +521,8 @@ sub handler {
tthoptions => 'Default set of options to pass to tth/m when converting TeX',
uselcmath => 'Student formula entry uses inline preview, not DragMath pop-up',
usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)',
+ inline_chem => 'Chemical reaction response uses inline preview, not pop-up',
+ extresource => 'Display of external resources',
},
},
'grading' =>
@@ -563,7 +604,7 @@ sub handler {
menucollections => 'Menu collections',
},
},
- 'linkprotection' =>
+ 'linkprot' =>
{
text => 'Link protection',
help => 'Course_Prefs_Linkprotection',
@@ -571,6 +612,14 @@ sub handler {
col2 => 'Settings',
}],
},
+ 'ltitools' =>
+ {
+ text => 'External tools',
+ help => 'Course_Prefs_ExternalTools',
+ header => [{col1 => 'Item',
+ col2 => 'Settings',
+ }],
+ },
'other' =>
{ text => 'Other settings',
help => 'Course_Prefs_Other',
@@ -581,10 +630,14 @@ sub handler {
);
if (($phase eq 'process') && ($parm_permission->{'process'})) {
my @allitems = &get_allitems(%prefs);
- &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context,
- \@prefs_order,\%prefs,\%values,
- $cnum,undef,\@allitems,
- 'coursepref',$parm_permission);
+ my $result = &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context,
+ \@prefs_order,\%prefs,\%values,
+ $cnum,undef,\@allitems,
+ 'coursepref',$parm_permission);
+ if ((ref($result) eq 'HASH') && (keys(%{$result}))) {
+ $r->rflush();
+ &devalidate_remote_courseprefs($cdom,$cnum,$result);
+ }
} elsif (($phase eq 'display') && ($parm_permission->{'display'})) {
my $noedit;
if (ref($parm_permission) eq 'HASH') {
@@ -595,7 +648,7 @@ sub handler {
my $jscript = &get_jscript($cid,$cdom,$phase,$crstype,\%values,$noedit);
my @allitems = &get_allitems(%prefs);
&Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context,
- \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype,
+ \@prefs_order,\%prefs,\%values,$cnum,$jscript,\@allitems,$crstype,
'coursepref',$parm_permission);
} else {
&Apache::lonconfigsettings::display_choices($r,$phase,$context,
@@ -648,7 +701,7 @@ sub get_allitems {
}
sub print_config_box {
- my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype,$parm_permission) = @_;
+ my ($r,$cdom,$cnum,$phase,$action,$item,$settings,$allitems,$crstype,$parm_permission) = @_;
my $ordered = $item->{'ordered'};
my $itemtext = $item->{'itemtext'};
my $noedit;
@@ -774,12 +827,18 @@ sub print_config_box {
$output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'bridgetasks') {
$output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
+ } elsif ($action eq 'ltitools') {
+ my $currtools = {};
+ if ((ref($settings) eq 'HASH') && (ref($settings->{'ltitools'}))) {
+ $currtools = $settings->{'ltitools'};
+ }
+ $output .= &print_ltitools($cdom,$cnum,$currtools,\$rowtotal,$crstype,$noedit,'course');
} elsif ($action eq 'lti') {
$output .= &print_lti($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit);
} elsif ($action eq 'menuitems') {
$output .= &print_menuitems('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit);
- } elsif ($action eq 'linkprotection') {
- $output .= &print_linkprotection($cdom,$settings,\$rowtotal,$crstype,$noedit);
+ } elsif ($action eq 'linkprot') {
+ $output .= &print_linkprotection($cdom,$cnum,$settings,\$rowtotal,$crstype,$noedit,'course');
} elsif ($action eq 'other') {
$output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype,$noedit);
}
@@ -792,8 +851,8 @@ sub print_config_box {
}
sub process_changes {
- my ($cdom,$cnum,$action,$values,$item,$changes,$allitems,$disallowed,$crstype) = @_;
- my (%newvalues,%courselti,$errors);
+ my ($cdom,$cnum,$action,$values,$item,$changes,$allitems,$disallowed,$crstype,$lastactref) = @_;
+ my (%newvalues,$errors);
if (ref($item) eq 'HASH') {
if (ref($changes) eq 'HASH') {
my @ordered;
@@ -810,20 +869,17 @@ sub process_changes {
}
}
}
- } elsif ($action eq 'linkprotection') {
- if (ref($values->{'linkprotection'}) eq 'HASH') {
- foreach my $id (keys(%{$values->{'linkprotection'}})) {
+ } elsif (($action eq 'linkprot') || ($action eq 'ltitools')) {
+ if (ref($values->{$action}) eq 'HASH') {
+ foreach my $id (keys(%{$values->{$action}})) {
if ($id =~ /^\d+$/) {
push(@ordered,$id);
- unless (ref($values->{'linkprotection'}->{$id}) eq 'HASH') {
- $courselti{$id} = '';
- }
}
}
}
@ordered = sort { $a <=> $b } @ordered;
- if (($env{'form.linkprot_add'}) && ($env{'form.linkprot_maxnum'} =~ /^\d+$/)) {
- push(@ordered,$env{'form.linkprot_maxnum'});
+ if (($env{'form.'.$action.'_add'}) && ($env{'form.'.$action.'_maxnum'} =~ /^\d+$/)) {
+ push(@ordered,$env{'form.'.$action.'_maxnum'});
}
} elsif (ref($item->{'ordered'}) eq 'ARRAY') {
if ($action eq 'courseinfo') {
@@ -962,77 +1018,15 @@ sub process_changes {
} elsif ($values->{'menucollections'}) {
$changes->{'menucollections'} = '';
}
- } elsif ($action eq 'linkprotection') {
- my %menutitles = <imenu_titles();
- my (@items,%deletions,%itemids,%haschanges);
- if ($env{'form.linkprot_add'}) {
- my $name = $env{'form.linkprot_name_add'};
- $name =~ s/(`)/'/g;
- my ($newid,$error) = &get_courselti_id($cdom,$cnum,$name);
- if ($newid) {
- $itemids{'add'} = $newid;
- push(@items,'add');
- $haschanges{$newid} = 1;
- } else {
- $errors .= ''.
- &mt('Failed to acquire unique ID for link protection').
- ' ';
- }
- }
- if (ref($values->{'linkprotection'}) eq 'HASH') {
- my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_del');
- my $maxnum = $env{'form.linkprot_maxnum'};
- for (my $i=0; $i<=$maxnum; $i++) {
- my $itemid = $env{'form.linkprot_id_'.$i};
- $itemid =~ s/\D+//g;
- if ($itemid) {
- if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') {
- push(@items,$i);
- $itemids{$i} = $itemid;
- if ((@todelete > 0) && (grep(/^$i$/,@todelete))) {
- $deletions{$itemid} = $values->{'linkprotection'}->{$itemid}->{'name'};
- }
- }
- }
- }
-
- }
- foreach my $idx (@items) {
- my $itemid = $itemids{$idx};
- next unless ($itemid);
- if (exists($deletions{$itemid})) {
- $courselti{$itemid} = $deletions{$itemid};
- $haschanges{$itemid} = 1;
- next;
- }
- my %current;
- if (ref($values->{'linkprotection'}) eq 'HASH') {
- if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') {
- foreach my $key (keys(%{$values->{'linkprotection'}->{$itemid}})) {
- $current{$key} = $values->{'linkprotection'}->{$itemid}->{$key};
- }
- }
- }
- foreach my $inner ('name','key','secret','lifetime','version') {
- my $formitem = 'form.linkprot_'.$inner.'_'.$idx;
- $env{$formitem} =~ s/(`)/'/g;
- if ($inner eq 'lifetime') {
- $env{$formitem} =~ s/[^\d.]//g;
- }
- unless ($idx eq 'add') {
- if ($current{$inner} ne $env{$formitem}) {
- $haschanges{$itemid} = 1;
- }
- }
- if ($env{$formitem} ne '') {
- $courselti{$itemid}{$inner} = $env{$formitem};
- }
- }
- }
- if (keys(%haschanges)) {
- foreach my $entry (keys(%haschanges)) {
- $changes->{$entry} = $courselti{$entry};
- }
+ } elsif ($action eq 'linkprot') {
+ if (ref($values) eq 'HASH') {
+ $errors = &process_linkprot($cdom,$cnum,$values->{$action},$changes,'course',$lastactref);
+ }
+ } elsif ($action eq 'ltitools') {
+ if (ref($values) eq 'HASH') {
+ my $switchserver = &check_switchserver($cdom,$cnum,'course','/adm/courseprefs');
+ $errors = &process_ltitools('',$cdom,$cnum,$values->{$action},$changes,'course',$lastactref,
+ 'ok','','ok');
}
} else {
foreach my $entry (@ordered) {
@@ -1163,7 +1157,9 @@ sub process_changes {
$autocoowner = $domconf{'autoenroll'}{'co-owners'};
}
}
- unless ($autocoowner) {
+ if ($autocoowner) {
+ $newvalues{'co-owners'} = $values->{'internal.co-owners'};
+ } else {
my @keepcoowners = &Apache::loncommon::get_env_multiple('form.coowners');
my @pendingcoowners = &Apache::loncommon::get_env_multiple('form.pendingcoowners');
my @invitecoowners = &Apache::loncommon::get_env_multiple('form.invitecoowners');
@@ -1208,6 +1204,8 @@ sub process_changes {
if ($pendingcoowners ne '') {
@newpending = @pendingcoown;
}
+ } else {
+ @newcoown = @currcoown;
}
$newvalues{'pendingco-owners'} = join(',',sort(@newpending));
$newvalues{'co-owners'} = join(',',sort(@newcoown));
@@ -1339,14 +1337,14 @@ sub process_changes {
my ($classorder,$classtitles) = &discussion_vote_classes();
my $fontchange = 0;
foreach my $class (@{$classorder}) {
- my $ext_entry = $entry.'_'.$class;
+ my $ext_entry = $entry.'_'.$class;
my $size = $env{'form.'.$ext_entry.'_size'};
my $unit = $env{'form.'.$ext_entry.'_unit'};
my $weight = $env{'form.'.$ext_entry.'_weight'};
my $style = $env{'form.'.$ext_entry.'_style'};
my $other = $env{'form.'.$ext_entry.'_other'};
$size =~ s/,//g;
- $unit =~ s/,//g;
+ $unit =~ s/,//g;
$weight =~ s/,//g;
$style =~ s/,//g;
$other =~ s/[^\w;:\s\-\%.]//g;
@@ -1354,7 +1352,7 @@ sub process_changes {
$newvalues{$ext_entry} = join(',',($size.$unit,$weight,$style,$other));
my $current = $values->{$ext_entry};
if ($values->{$ext_entry} eq '') {
- $current = ',,,';
+ $current = ',,,';
}
if ($newvalues{$ext_entry} ne $current) {
$changes->{$ext_entry} = $newvalues{$ext_entry};
@@ -1363,7 +1361,7 @@ sub process_changes {
}
if ($fontchange) {
$changes->{$entry} = 1;
- }
+ }
} elsif ($entry eq 'nothideprivileged') {
my @curr_nothide;
my @new_nothide;
@@ -1438,7 +1436,7 @@ sub process_changes {
my $newtext = $maxnum-1;
$newhdr[$env{'form.printfmthdr_pos_'.$newtext}] = $env{'form.printfmthdr_text_'.$newtext};
$newvalues{$entry} = join('',@newhdr);
- } elsif (($entry eq 'languages') ||
+ } elsif (($entry eq 'languages') ||
($entry eq 'checkforpriv')) {
my $settings;
my $total = $env{'form.'.$entry.'_total'};
@@ -1454,7 +1452,7 @@ sub process_changes {
}
if ($env{'form.'.$entry.'_'.$total} ne '') {
my $new = $env{'form.'.$entry.'_'.$total};
- if ($entry eq 'languages') {
+ if ($entry eq 'languages') {
my %langchoices = &get_lang_choices();
if ($langchoices{$new}) {
$settings .= $new;
@@ -1507,10 +1505,54 @@ sub process_changes {
$newvalues{$entry} = '';
}
}
+ } elsif ($entry eq 'extresource') {
+ if ($env{'form.'.$entry} =~ /^iframe|tab|window$/) {
+ $newvalues{$entry} = $env{'form.'.$entry};
+ if ($env{'form.'.$entry} ne 'iframe') {
+ if ($env{'form.extwintabreuse'}) {
+ $newvalues{$entry} .= ':1';
+ } else {
+ $newvalues{$entry} .= ':0';
+ }
+ if ($env{'form.'.$entry} eq 'window') {
+ foreach my $dim ('width','height') {
+ $env{'form.extreswin'.$dim} =~ s/^\s+|\s+$//g;
+ if ($env{'form.extreswin'.$dim} =~ /^\d+$/) {
+ $newvalues{$entry} .= ':'.$env{'form.extreswin'.$dim};
+ } else {
+ $newvalues{$entry} .= ':';
+ }
+ }
+ }
+ }
+ }
+ unless (($newvalues{$entry} eq 'iframe') && ($values->{$entry} eq '')) {
+ if ($newvalues{$entry} ne $values->{$entry}) {
+ $changes->{$entry} = $newvalues{$entry};
+ }
+ }
+ } elsif ($entry eq 'timezone') {
+ if ($env{'form.'.$entry}) {
+ $newvalues{$entry} = $env{'form.'.$entry};
+ if ($newvalues{$entry} ne $values->{$entry}) {
+ $changes->{$entry} = $newvalues{$entry};
+ }
+ if ($env{'form.tzover'}) {
+ $newvalues{'tzover'} = $env{'form.tzover'};
+ if ($newvalues{'tzover'} ne $values->{'tzover'}) {
+ $changes->{'tzover'} = $newvalues{'tzover'};
+ }
+ } elsif ($values->{'tzover'}) {
+ $changes->{'tzover'} = '';
+ }
+ } elsif ($values->{$entry}) {
+ $changes->{$entry} = '';
+ }
} else {
$newvalues{$entry} = $env{'form.'.$entry};
}
- unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts')) {
+ unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts') ||
+ ($entry eq 'extresource') || ($entry eq 'timezone')) {
if ($newvalues{$entry} ne $values->{$entry}) {
$changes->{$entry} = $newvalues{$entry};
}
@@ -1523,23 +1565,250 @@ sub process_changes {
return $errors;
}
-sub get_courselti_id {
- my ($cdom,$cnum,$name) = @_;
- # get lock on lti db in course
+sub process_linkprot {
+ my ($cdom,$cnum,$values,$changes,$context,$lastactref) = @_;
+ my ($dest,$ltiauth,$privnum,$cipher,$errors,%linkprot);
+ if (ref($values) eq 'HASH') {
+ foreach my $id (keys(%{$values})) {
+ if ($id =~ /^\d+$/) {
+ unless (ref($values->{$id}) eq 'HASH') {
+ $linkprot{$id} = '';
+ }
+ }
+ }
+ }
+ ($cipher,$privnum) = &get_credentials($cdom,$cnum,'lti',$context);
+ if ($context eq 'domain') {
+ $dest = '/adm/domainprefs';
+ $ltiauth = 1;
+ } else {
+ $dest = '/adm/courseprefs';
+ if (exists($env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'})) {
+ $ltiauth = $env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'};
+ } else {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
+ $ltiauth = $domdefs{'crsltiauth'};
+ }
+ }
+ my $switchserver = &check_switchserver($cdom,$cnum,$context,$dest);
+ my (@items,%deletions,%itemids,%haschanges);
+ if ($env{'form.linkprot_add'}) {
+ my $name = $env{'form.linkprot_name_add'};
+ $name =~ s/(`)/'/g;
+ my ($newid,$error) = &get_linkprot_id($cdom,$cnum,$name,$context);
+ if ($newid) {
+ $itemids{'add'} = $newid;
+ push(@items,'add');
+ $haschanges{$newid} = 1;
+ } else {
+ $errors .= ''.
+ &mt('Failed to acquire unique ID for link protection').
+ ' ';
+ }
+ }
+ if (ref($values) eq 'HASH') {
+ my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_del');
+ my $maxnum = $env{'form.linkprot_maxnum'};
+ for (my $i=0; $i<$maxnum; $i++) {
+ my $itemid = $env{'form.linkprot_id_'.$i};
+ $itemid =~ s/\D+//g;
+ if ($itemid) {
+ if (ref($values->{$itemid}) eq 'HASH') {
+ push(@items,$i);
+ $itemids{$i} = $itemid;
+ if ((@todelete > 0) && (grep(/^$i$/,@todelete))) {
+ $deletions{$itemid} = $values->{$itemid}->{'name'};
+ }
+ }
+ }
+ }
+ }
+ foreach my $idx (@items) {
+ my $itemid = $itemids{$idx};
+ next unless ($itemid);
+ if (exists($deletions{$itemid})) {
+ $linkprot{$itemid} = $deletions{$itemid};
+ $haschanges{$itemid} = 1;
+ next;
+ }
+ my %current;
+ if (ref($values) eq 'HASH') {
+ if (ref($values->{$itemid}) eq 'HASH') {
+ foreach my $key (keys(%{$values->{$itemid}})) {
+ $current{$key} = $values->{$itemid}->{$key};
+ }
+ }
+ }
+ foreach my $inner ('name','lifetime','version') {
+ my $formitem = 'form.linkprot_'.$inner.'_'.$idx;
+ $env{$formitem} =~ s/(`)/'/g;
+ if ($inner eq 'lifetime') {
+ $env{$formitem} =~ s/[^\d.]//g;
+ }
+ unless ($idx eq 'add') {
+ if ($current{$inner} ne $env{$formitem}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ if ($env{$formitem} ne '') {
+ $linkprot{$itemid}{$inner} = $env{$formitem};
+ }
+ }
+ my $urlitem = 'form.linkprot_returnurl_'.$idx;
+ my $urlparamname = 'form.linkprot_urlparam_'.$idx;
+ if ($env{$urlitem} == 1) {
+ $env{$urlparamname} =~ s/(`)/'/g;
+ } elsif (exists($env{$urlparamname})) {
+ $env{$urlparamname} = '';
+ }
+ my $passback = 'form.linkprot_passback_'.$idx;
+ my $passbackparamname = 'form.linkprot_passbackformat_'.$idx;
+ if ($env{$passback} == 1) {
+ unless ($env{$passbackparamname} =~ /^1\.(0|1)$/) {
+ $env{$passbackparamname} = '';
+ }
+ } elsif (exists($env{$passbackparamname})) {
+ $env{$passbackparamname} = '';
+ }
+ unless ($idx eq 'add') {
+ if ((!$current{'returnurl'} && ($env{$urlparamname} ne '')) ||
+ ($current{'returnurl'} && ($env{$urlparamname} eq ''))) {
+ $haschanges{$itemid} = 1;
+ }
+ if ((!$current{'passback'} && ($env{$passbackparamname} ne '')) ||
+ ($current{'passback'} && ($env{$passbackparamname} eq ''))) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ if ($env{$urlparamname} ne '') {
+ $linkprot{$itemid}{'returnurl'} = $env{$urlparamname};
+ }
+ if ($env{$passbackparamname} ne '') {
+ $linkprot{$itemid}{'passback'} = 1;
+ $linkprot{$itemid}{'passbackformat'} = $env{$passbackparamname};
+ }
+ if ($ltiauth) {
+ my $reqitem = 'form.linkprot_requser_'.$idx;
+ $env{$reqitem} =~ s/(`)/'/g;
+ unless ($idx eq 'add') {
+ if ((!$current{'requser'} && $env{$reqitem}) ||
+ ($current{'requser'} && !$env{$reqitem})) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ if ($env{$reqitem} == 1) {
+ $linkprot{$itemid}{'requser'} = $env{$reqitem};
+ foreach my $inner ('mapuser','notstudent') {
+ my $formitem = 'form.linkprot_'.$inner.'_'.$idx;
+ $env{$formitem} =~ s/(`)/'/g;
+ if ($inner eq 'mapuser') {
+ if ($env{$formitem} eq 'other') {
+ my $mapuser = $env{'form.linkprot_customuser_'.$idx};
+ $mapuser =~ s/(`)/'/g;
+ $mapuser =~ s/^\s+|\s+$//g;
+ if ($mapuser ne '') {
+ $linkprot{$itemid}{$inner} = $mapuser;
+ } else {
+ delete($linkprot{$itemid}{'requser'});
+ last;
+ }
+ } elsif ($env{$formitem} eq 'sourcedid') {
+ $linkprot{$itemid}{$inner} = 'lis_person_sourcedid';
+ } elsif ($env{$formitem} eq 'email') {
+ $linkprot{$itemid}{$inner} = 'lis_person_contact_email_primary';
+ }
+ } else {
+ $linkprot{$itemid}{$inner} = $env{$formitem};
+ }
+ unless ($idx eq 'add') {
+ if ($current{$inner} ne $linkprot{$itemid}{$inner}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ }
+ }
+ unless ($switchserver) {
+ my $keyitem = 'form.linkprot_key_'.$idx;
+ $env{$keyitem} =~ s/(`)/'/g;
+ unless ($idx eq 'add') {
+ if ($current{'key'} ne $env{$keyitem}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ if ($env{$keyitem} ne '') {
+ $linkprot{$itemid}{'key'} = $env{$keyitem};
+ }
+ my $secretitem = 'form.linkprot_secret_'.$idx;
+ $env{$secretitem} =~ s/(`)/'/g;
+ if ($current{'usable'}) {
+ if ($env{'form.linkprot_changesecret_'.$idx}) {
+ if ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $linkprot{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $linkprot{$itemid}{'cipher'} = $privnum;
+ } else {
+ $linkprot{$itemid}{'secret'} = $env{$secretitem};
+ }
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $linkprot{$itemid}{'secret'} = $current{'secret'};
+ $linkprot{$itemid}{'cipher'} = $current{'cipher'};
+ }
+ } elsif ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $linkprot{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $linkprot{$itemid}{'cipher'} = $privnum;
+ } else {
+ $linkprot{$itemid}{'secret'} = $env{$secretitem};
+ }
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ if (keys(%haschanges)) {
+ foreach my $entry (keys(%haschanges)) {
+ $changes->{$entry} = $linkprot{$entry};
+ }
+ if (ref($lastactref) eq 'HASH') {
+ $lastactref->{'courselti'} = 1;
+ }
+ }
+ return $errors;
+}
+
+sub get_linkprot_id {
+ my ($cdom,$cnum,$name,$context) = @_;
+ # get lock on lti db in course or linkprot db in domain
my $lockhash = {
lock => $env{'user.name'}.
':'.$env{'user.domain'},
};
my $tries = 0;
- my $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum);
+ my $gotlock;
+ if ($context eq 'domain') {
+ $gotlock = &Apache::lonnet::newput_dom('linkprot',$lockhash,$cdom);
+ } else {
+ $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum);
+ }
my ($id,$error);
while (($gotlock ne 'ok') && ($tries<10)) {
$tries ++;
sleep (0.1);
- $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum);
+ if ($context eq 'domain') {
+ $gotlock = &Apache::lonnet::newput_dom('linkprot',$lockhash,$cdom);
+ } else {
+ $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum);
+ }
}
if ($gotlock eq 'ok') {
- my %currids = &Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1);
+ my %currids;
+ if ($context eq 'domain') {
+ %currids = &Apache::lonnet::dump_dom('linkprot',$cdom);
+ } else {
+ %currids = &Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1);
+ }
if ($currids{'lock'}) {
delete($currids{'lock'});
if (keys(%currids)) {
@@ -1553,20 +1822,696 @@ sub get_courselti_id {
$id = 1;
}
if ($id) {
- unless (&Apache::lonnet::newput('lti',{ $id => $name },$cdom,$cnum) eq 'ok') {
- $error = 'nostore';
+ if ($context eq 'domain') {
+ unless (&Apache::lonnet::newput_dom('linkprot',{ $id => $name },$cdom) eq 'ok') {
+ $error = 'nostore';
+ }
+ } else {
+ unless (&Apache::lonnet::newput('lti',{ $id => $name },$cdom,$cnum) eq 'ok') {
+ $error = 'nostore';
+ }
}
} else {
$error = 'nonumber';
}
}
- my $dellockoutcome = &Apache::lonnet::del('lti',['lock'],$cdom,$cnum);
+ my $dellockoutcome;
+ if ($context eq 'domain') {
+ $dellockoutcome = &Apache::lonnet::del_dom('linkprot',['lock'],$cdom);
+ } else {
+ $dellockoutcome = &Apache::lonnet::del('lti',['lock'],$cdom,$cnum);
+ }
} else {
$error = 'nolock';
}
return ($id,$error);
}
+sub get_credentials {
+ my ($cdom,$cnum,$type,$context) = @_;
+ my ($cipher,$privnum,$home);
+ my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
+ my @ids=&Apache::lonnet::current_machine_ids();
+ if ($context eq 'domain') {
+ $home = &Apache::lonnet::domain($cdom,'primary');
+ } else {
+ $home = &Apache::lonnet::homeserver($cnum,$cdom);
+ }
+ my ($hostskey,$domkey,$crskey);
+ if ($type eq 'ltitools') {
+ $hostskey = 'toolprivhosts';
+ $domkey = 'toolenc_dom';
+ $crskey = 'toolenc_crs';
+ } else {
+ $hostskey = 'ltiprivhosts';
+ $domkey = 'linkprotenc_dom';
+ $crskey = 'linkprotenc_crs';
+ }
+ if ((($context eq 'domain') && ($domdefs{$domkey})) ||
+ (($context eq 'course') && ($domdefs{$crskey}))) {
+ unless (($home eq 'no_host') || ($home eq '')) {
+ if (grep(/^\Q$home\E$/,@ids)) {
+ if (ref($domdefs{$hostskey}) eq 'ARRAY') {
+ if (grep(/^\Q$home\E$/,@{$domdefs{$hostskey}})) {
+ my %privhash = &Apache::lonnet::restore_dom($type,'private',$cdom,$home,1);
+ my $privkey = $privhash{'key'};
+ $privnum = $privhash{'version'};
+ if (($privnum) && ($privkey ne '')) {
+ $cipher = Crypt::CBC->new({'key' => $privkey,
+ 'cipher' => 'DES'});
+ }
+ }
+ }
+ }
+ }
+ }
+ return ($cipher,$privnum);
+}
+
+sub process_ltitools {
+ my ($r,$cdom,$cnum,$values,$changes,$context,$lastactref,$configuserok,$lonhost,
+ $author_ok,$confname) = @_;
+ my (%currconfig,$newid,@allpos,%changes,%ltitools,$errors);
+
+ my (%posslti,%possfield);
+ my @courseroles = ('cc','in','ta','ep','st');
+ my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
+ map { $posslti{$_} = 1; } @ltiroles;
+ my @allfields = ('fullname','firstname','lastname','email','user','roles');
+ map { $possfield{$_} = 1; } @allfields;
+
+ my ($dest,$privnum,$cipher);
+
+ ($cipher,$privnum) = &get_credentials($cdom,$cnum,'ltitools',$context);
+ if ($context eq 'domain') {
+ $dest = '/adm/domainprefs';
+ } else {
+ $dest = '/adm/courseprefs';
+ }
+ my $switchserver = &check_switchserver($cdom,$cnum,$context,$dest);
+
+ my (@allpos,@items,%deletions,%itemids,%haschanges);
+ if ($env{'form.ltitools_add'}) {
+ my $title = $env{'form.ltitools_add_title'};
+ $title =~ s/(`)/'/g;
+ my ($newid,$error) = &get_ltitools_id($context,$cdom,$cnum,$title);
+ if ($newid) {
+ my $position = $env{'form.ltitools_add_pos'};
+ $position =~ s/\D+//g;
+ if ($position ne '') {
+ $allpos[$position] = $newid;
+ }
+ $haschanges{$newid} = 1;
+ foreach my $item ('title','url','lifetime') {
+ $env{'form.ltitools_add_'.$item} =~ s/(`)/'/g;
+ if ($item eq 'lifetime') {
+ $env{'form.ltitools_add_'.$item} =~ s/[^\d.]//g;
+ }
+ if ($env{'form.ltitools_add_'.$item}) {
+ $ltitools{$newid}{$item} = $env{'form.ltitools_add_'.$item};
+ }
+ }
+ if ($env{'form.ltitools_add_version'} eq 'LTI-1p0') {
+ $ltitools{$newid}{'version'} = $env{'form.ltitools_add_version'};
+ }
+ if ($env{'form.ltitools_add_msgtype'} eq 'basic-lti-launch-request') {
+ $ltitools{$newid}{'msgtype'} = $env{'form.ltitools_add_msgtype'};
+ }
+ if ($env{'form.ltitools_add_sigmethod'} eq 'HMAC-SHA256') {
+ $ltitools{$newid}{'sigmethod'} = $env{'form.ltitools_add_sigmethod'};
+ } else {
+ $ltitools{$newid}{'sigmethod'} = 'HMAC-SHA1';
+ }
+ foreach my $item ('width','height','linktext','explanation') {
+ $env{'form.ltitools_add_'.$item} =~ s/^\s+//;
+ $env{'form.ltitools_add_'.$item} =~ s/\s+$//;
+ if (($item eq 'width') || ($item eq 'height')) {
+ if ($env{'form.ltitools_add_'.$item} =~ /^\d+$/) {
+ $ltitools{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};
+ }
+ } else {
+ if ($env{'form.ltitools_add_'.$item} ne '') {
+ $ltitools{$newid}{'display'}{$item} = $env{'form.ltitools_add_'.$item};
+ }
+ }
+ }
+ if ($env{'form.ltitools_add_target'} eq 'window') {
+ $ltitools{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
+ } elsif ($env{'form.ltitools_add_target'} eq 'tab') {
+ $ltitools{$newid}{'display'}{'target'} = $env{'form.ltitools_add_target'};
+ } else {
+ $ltitools{$newid}{'display'}{'target'} = 'iframe';
+ }
+ foreach my $item ('passback','roster') {
+ if ($env{'form.ltitools_'.$item.'_add'}) {
+ $ltitools{$newid}{$item} = 1;
+ if ($env{'form.ltitools_'.$item.'valid_add'} ne '') {
+ my $lifetime = $env{'form.ltitools_'.$item.'valid_add'};
+ $lifetime =~ s/^\s+|\s+$//g;
+ if ($lifetime =~ /^\d+\.?\d*$/) {
+ $ltitools{$newid}{$item.'valid'} = $lifetime;
+ }
+ }
+ }
+ }
+ if ($env{'form.ltitools_add_image.filename'} ne '') {
+ my ($imageurl,$error) =
+ &process_ltitools_image($r,$context,$cdom,$cnum,$confname,'ltitools_add_image',
+ $newid,$configuserok,$lonhost,$author_ok);
+ if ($imageurl) {
+ $ltitools{$newid}{'image'} = $imageurl;
+ }
+ if ($error) {
+ &Apache::lonnet::logthis($error);
+ $errors .= '
'.$error.' ';
+ }
+ }
+ my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_add_fields');
+ foreach my $field (@fields) {
+ if ($possfield{$field}) {
+ if ($field eq 'roles') {
+ foreach my $role (@courseroles) {
+ my $choice = $env{'form.ltitools_add_roles_'.$role};
+ if (($choice ne '') && ($posslti{$choice})) {
+ $ltitools{$newid}{'roles'}{$role} = $choice;
+ if ($role eq 'cc') {
+ $ltitools{$newid}{'roles'}{'co'} = $choice;
+ }
+ }
+ }
+ } else {
+ $ltitools{$newid}{'fields'}{$field} = 1;
+ }
+ }
+ }
+ if (ref($ltitools{$newid}{'fields'}) eq 'HASH') {
+ if ($ltitools{$newid}{'fields'}{'user'}) {
+ if ($env{'form.ltitools_add_userincdom'}) {
+ $ltitools{$newid}{'incdom'} = 1;
+ }
+ }
+ }
+ my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_add_courseconfig');
+ foreach my $item (@courseconfig) {
+ $ltitools{$newid}{'crsconf'}{$item} = 1;
+ }
+ if ($env{'form.ltitools_add_custom'}) {
+ my $name = $env{'form.ltitools_add_custom_name'};
+ my $value = $env{'form.ltitools_add_custom_value'};
+ $value =~ s/(`)/'/g;
+ $name =~ s/(`)/'/g;
+ $ltitools{$newid}{'custom'}{$name} = $value;
+ }
+ unless ($switchserver) {
+ my $keyitem = 'form.ltitools_add_key';
+ $env{$keyitem} =~ s/(`)/'/g;
+ if ($env{$keyitem} ne '') {
+ $ltitools{$newid}{'key'} = $env{$keyitem};
+ }
+ my $secretitem = 'form.ltitools_secret_add';
+ $env{$secretitem} =~ s/(`)/'/g;
+ if ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $ltitools{$newid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $ltitools{$newid}{'cipher'} = $privnum;
+ } else {
+ $ltitools{$newid}{'secret'} = $env{$secretitem};
+ }
+ }
+ }
+ } else {
+ $errors .= ''.
+ &mt('Failed to acquire unique ID for new external tool').
+ ' ';
+ }
+ }
+ if (ref($values) eq 'HASH') {
+ my %deletions;
+ my @todelete = &Apache::loncommon::get_env_multiple('form.ltitools_del');
+ if (@todelete) {
+ map { $deletions{$_} = 1; } @todelete;
+ }
+ my %customadds;
+ my @newcustom = &Apache::loncommon::get_env_multiple('form.ltitools_customadd');
+ if (@newcustom) {
+ map { $customadds{$_} = 1; } @newcustom;
+ }
+ my %imgdeletions;
+ my @todeleteimages = &Apache::loncommon::get_env_multiple('form.ltitools_image_del');
+ if (@todeleteimages) {
+ map { $imgdeletions{$_} = 1; } @todeleteimages;
+ }
+ my $maxnum = $env{'form.ltitools_maxnum'};
+ for (my $i=0; $i<=$maxnum; $i++) {
+ my $itemid = $env{'form.ltitools_id_'.$i};
+ $itemid =~ s/\D+//g;
+ if (ref($values->{$itemid}) eq 'HASH') {
+ if ($deletions{$itemid}) {
+ if ($values->{$itemid}{'image'}) {
+ #FIXME need to obsolete item in RES space
+ }
+ $haschanges{$itemid} = $values->{$itemid}{'title'};
+ next;
+ } else {
+ my $newpos = $env{'form.ltitools_'.$itemid};
+ $newpos =~ s/\D+//g;
+ foreach my $item ('title','url','lifetime') {
+ $ltitools{$itemid}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
+ if ($values->{$itemid}{$item} ne $ltitools{$itemid}{$item}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ if ($env{'form.ltitools_version_'.$i} eq 'LTI-1p0') {
+ $ltitools{$itemid}{'version'} = $env{'form.ltitools_version_'.$i};
+ }
+ if ($env{'form.ltitools_msgtype_'.$i} eq 'basic-lti-launch-request') {
+ $ltitools{$itemid}{'msgtype'} = $env{'form.ltitools_msgtype_'.$i};
+ }
+ if ($env{'form.ltitools_sigmethod_'.$i} eq 'HMAC-SHA256') {
+ $ltitools{$itemid}{'sigmethod'} = $env{'form.ltitools_sigmethod_'.$i};
+ } else {
+ $ltitools{$itemid}{'sigmethod'} = 'HMAC-SHA1';
+ }
+ if ($values->{$itemid}{'sigmethod'} eq '') {
+ if ($ltitools{$itemid}{'sigmethod'} ne 'HMAC-SHA1') {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif ($values->{$itemid}{'sigmethod'} ne $ltitools{$itemid}{'sigmethod'}) {
+ $haschanges{$itemid} = 1;
+ }
+ foreach my $size ('width','height') {
+ $env{'form.ltitools_'.$size.'_'.$i} =~ s/^\s+//;
+ $env{'form.ltitools_'.$size.'_'.$i} =~ s/\s+$//;
+ if ($env{'form.ltitools_'.$size.'_'.$i} =~ /^\d+$/) {
+ $ltitools{$itemid}{'display'}{$size} = $env{'form.ltitools_'.$size.'_'.$i};
+ if (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$size} ne $ltitools{$itemid}{'display'}{$size}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$size} ne '') {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ foreach my $item ('linktext','explanation') {
+ $env{'form.ltitools_'.$item.'_'.$i} =~ s/^\s+//;
+ $env{'form.ltitools_'.$item.'_'.$i} =~ s/\s+$//;
+ if ($env{'form.ltitools_'.$item.'_'.$i} ne '') {
+ $ltitools{$itemid}{'display'}{$item} = $env{'form.ltitools_'.$item.'_'.$i};
+ if (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$item} ne $ltitools{$itemid}{'display'}{$item}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{$item} ne '') {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ if ($env{'form.ltitools_target_'.$i} eq 'window') {
+ $ltitools{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
+ } elsif ($env{'form.ltitools_target_'.$i} eq 'tab') {
+ $ltitools{$itemid}{'display'}{'target'} = $env{'form.ltitools_target_'.$i};
+ } else {
+ $ltitools{$itemid}{'display'}{'target'} = 'iframe';
+ }
+ if (ref($values->{$itemid}{'display'}) eq 'HASH') {
+ if ($values->{$itemid}{'display'}{'target'} ne $ltitools{$itemid}{'display'}{'target'}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ foreach my $extra ('passback','roster') {
+ if ($env{'form.ltitools_'.$extra.'_'.$i}) {
+ $ltitools{$itemid}{$extra} = 1;
+ if ($env{'form.ltitools_'.$extra.'valid_'.$i} ne '') {
+ my $lifetime = $env{'form.ltitools_'.$extra.'valid_'.$i};
+ $lifetime =~ s/^\s+|\s+$//g;
+ if ($lifetime =~ /^\d+\.?\d*$/) {
+ $ltitools{$itemid}{$extra.'valid'} = $lifetime;
+ }
+ }
+ }
+ if ($values->{$itemid}{$extra} ne $ltitools{$itemid}{$extra}) {
+ $haschanges{$itemid} = 1;
+ }
+ if ($values->{$itemid}{$extra.'valid'} ne $ltitools{$itemid}{$extra.'valid'}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ my @courseconfig = &Apache::loncommon::get_env_multiple('form.ltitools_courseconfig_'.$i);
+ foreach my $item ('label','title','target','linktext','explanation','append') {
+ if (grep(/^\Q$item\E$/,@courseconfig)) {
+ $ltitools{$itemid}{'crsconf'}{$item} = 1;
+ if (ref($values->{$itemid}{'crsconf'}) eq 'HASH') {
+ if ($values->{$itemid}{'crsconf'}{$item} ne $ltitools{$itemid}{'crsconf'}{$item}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ my @fields = &Apache::loncommon::get_env_multiple('form.ltitools_fields_'.$i);
+ foreach my $field (@fields) {
+ if ($possfield{$field}) {
+ if ($field eq 'roles') {
+ foreach my $role (@courseroles) {
+ my $choice = $env{'form.ltitools_roles_'.$role.'_'.$i};
+ if (($choice ne '') && ($posslti{$choice})) {
+ $ltitools{$itemid}{'roles'}{$role} = $choice;
+ if ($role eq 'cc') {
+ $ltitools{$itemid}{'roles'}{'co'} = $choice;
+ }
+ }
+ if (ref($values->{$itemid}{'roles'}) eq 'HASH') {
+ if ($values->{$itemid}{'roles'}{$role} ne $ltitools{$itemid}{'roles'}{$role}) {
+ $haschanges{$itemid} = 1;
+ }
+ } elsif ($ltitools{$itemid}{'roles'}{$role}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ } else {
+ $ltitools{$itemid}{'fields'}{$field} = 1;
+ if (ref($values->{$itemid}{'fields'}) eq 'HASH') {
+ if ($values->{$itemid}{'fields'}{$field} ne $ltitools{$itemid}{'fields'}{$field}) {
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ }
+ if (ref($ltitools{$itemid}{'fields'}) eq 'HASH') {
+ if ($ltitools{$itemid}{'fields'}{'user'}) {
+ if ($env{'form.ltitools_userincdom_'.$i}) {
+ $ltitools{$itemid}{'incdom'} = 1;
+ }
+ if ($values->{$itemid}{'incdom'} ne $ltitools{$itemid}{'incdom'}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ $allpos[$newpos] = $itemid;
+ }
+ if ($imgdeletions{$itemid}) {
+ $haschanges{$itemid} = 1;
+ if ($context eq 'course') {
+ my $currimgurl = $values->{$itemid}{'image'};
+ if ($currimgurl =~ m{^(\Q/uploaded/$cdom/$cnum/toollogo/$itemid\E)/([^/]+)$}) {
+ my ($path,$imagefile) = ($1,$2);
+ if ($imagefile =~ /^tn\-(.+)$/) {
+ my $origimg = $1;
+ &Apache::lonnet::removeuploadedurl("$path/$origimg");
+ }
+ &Apache::lonnet::removeuploadedurl($currimgurl);
+ }
+ }
+ #FIXME need to obsolete item in RES space
+ } elsif ($env{'form.ltitools_image_'.$i.'.filename'}) {
+ my $currimgurl = $values->{$itemid}{'image'};
+ my ($imgurl,$error) = &process_ltitools_image($r,$context,$cdom,$cnum,$confname,'ltitools_image_'.$i,
+ $itemid,$configuserok,$lonhost,$author_ok,$currimgurl);
+ if ($imgurl) {
+ $ltitools{$itemid}{'image'} = $imgurl;
+ $haschanges{$itemid} = 1;
+ }
+ if ($error) {
+ &Apache::lonnet::logthis($error);
+ $errors .= ''.$error.' ';
+ }
+ } elsif ($values->{$itemid}{'image'}) {
+ $ltitools{$itemid}{'image'} = $values->{$itemid}{'image'};
+ }
+ if ($customadds{$i}) {
+ my $name = $env{'form.ltitools_custom_name_'.$i};
+ $name =~ s/(`)/'/g;
+ $name =~ s/^\s+//;
+ $name =~ s/\s+$//;
+ my $value = $env{'form.ltitools_custom_value_'.$i};
+ $value =~ s/(`)/'/g;
+ $value =~ s/^\s+//;
+ $value =~ s/\s+$//;
+ if ($name ne '') {
+ $ltitools{$itemid}{'custom'}{$name} = $value;
+ $haschanges{$itemid} = 1;
+ }
+ }
+ my %customdels;
+ my @customdeletions = &Apache::loncommon::get_env_multiple('form.ltitools_customdel_'.$i);
+ if (@customdeletions) {
+ $haschanges{$itemid} = 1;
+ }
+ map { $customdels{$_} = 1; } @customdeletions;
+ if (ref($values->{$itemid}{'custom'}) eq 'HASH') {
+ foreach my $key (keys(%{$values->{$itemid}{'custom'}})) {
+ unless ($customdels{$key}) {
+ if ($env{'form.ltitools_customval_'.$key.'_'.$i} ne '') {
+ $ltitools{$itemid}{'custom'}{$key} = $env{'form.ltitools_customval_'.$key.'_'.$i};
+ }
+ if ($values->{$itemid}{'custom'}{$key} ne $env{'form.ltitools_customval_'.$key.'_'.$i}) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ }
+ unless ($switchserver) {
+ my $keyitem = 'form.ltitools_key_'.$i;
+ $env{$keyitem} =~ s/(`)/'/g;
+ if ($values->{$itemid}{'key'} ne $env{$keyitem}) {
+ $haschanges{$itemid} = 1;
+ }
+ if ($env{$keyitem} ne '') {
+ $ltitools{$itemid}{'key'} = $env{$keyitem};
+ }
+ my $secretitem = 'form.ltitools_secret_'.$i;
+ $env{$secretitem} =~ s/(`)/'/g;
+ if ($values->{$itemid}{'usable'}) {
+ if ($env{'form.ltitools_changesecret_'.$i}) {
+ if ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $ltitools{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $ltitools{$itemid}{'cipher'} = $privnum;
+ } else {
+ $ltitools{$itemid}{'secret'} = $env{$secretitem};
+ }
+ $haschanges{$itemid} = 1;
+ }
+ } else {
+ $ltitools{$itemid}{'secret'} = $values->{$itemid}{'secret'};
+ $ltitools{$itemid}{'cipher'} = $values->{$itemid}{'cipher'};
+ }
+ } elsif ($env{$secretitem} ne '') {
+ if ($privnum && $cipher) {
+ $ltitools{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem});
+ $ltitools{$itemid}{'cipher'} = $privnum;
+ } else {
+ $ltitools{$itemid}{'secret'} = $env{$secretitem};
+ }
+ $haschanges{$itemid} = 1;
+ }
+ }
+ unless ($haschanges{$itemid}) {
+ foreach my $key (keys(%{$values->{$itemid}})) {
+ if (ref($values->{$itemid}{$key}) eq 'HASH') {
+ if (ref($ltitools{$itemid}{$key}) eq 'HASH') {
+ foreach my $innerkey (keys(%{$values->{$itemid}{$key}})) {
+ unless (exists($ltitools{$itemid}{$key}{$innerkey})) {
+ $haschanges{$itemid} = 1;
+ last;
+ }
+ }
+ } elsif (keys(%{$values->{$itemid}{$key}}) > 0) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ last if ($haschanges{$itemid});
+ }
+ }
+ }
+ }
+ }
+ if (@allpos > 0) {
+ my $idx = 0;
+ foreach my $itemid (@allpos) {
+ if ($itemid ne '') {
+ $ltitools{$itemid}{'order'} = $idx;
+ if (ref($values) eq 'HASH') {
+ if (ref($values->{$itemid}) eq 'HASH') {
+ if ($values->{$itemid}{'order'} ne $idx) {
+ $haschanges{$itemid} = 1;
+ }
+ }
+ }
+ $idx ++;
+ }
+ }
+ }
+ if (keys(%haschanges)) {
+ foreach my $entry (keys(%haschanges)) {
+ $changes->{$entry} = $ltitools{$entry};
+ }
+ if (ref($lastactref) eq 'HASH') {
+ $lastactref->{'courseltitools'} = 1;
+ }
+ }
+ return $errors;
+}
+
+sub get_ltitools_id {
+ my ($context,$cdom,$cnum,$title) = @_;
+ my ($lockhash,$tries,$gotlock,$id,$error);
+
+ # get lock on ltitools db
+ $lockhash = {
+ lock => $env{'user.name'}.
+ ':'.$env{'user.domain'},
+ };
+ $tries = 0;
+ if ($context eq 'domain') {
+ $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
+ } else {
+ $gotlock = &Apache::lonnet::newput('ltitools',$lockhash,$cdom,$cnum);
+ }
+ while (($gotlock ne 'ok') && ($tries<10)) {
+ $tries ++;
+ sleep (0.1);
+ if ($context eq 'domain') {
+ $gotlock = &Apache::lonnet::newput_dom('ltitools',$lockhash,$cdom);
+ } else {
+ $gotlock = &Apache::lonnet::newput('ltitools',$lockhash,$cdom,$cnum);
+ }
+ }
+ if ($gotlock eq 'ok') {
+ my %currids;
+ if ($context eq 'domain') {
+ %currids = &Apache::lonnet::dump_dom('ltitools',$cdom);
+ } else {
+ %currids = &Apache::lonnet::dump('ltitools',$cdom,$cnum);
+ }
+ if ($currids{'lock'}) {
+ delete($currids{'lock'});
+ if (keys(%currids)) {
+ my @curr = sort { $a <=> $b } keys(%currids);
+ if ($curr[-1] =~ /^\d+$/) {
+ $id = 1 + $curr[-1];
+ }
+ } else {
+ $id = 1;
+ }
+ if ($id) {
+ if ($context eq 'domain') {
+ unless (&Apache::lonnet::newput_dom('ltitools',{ $id => $title },$cdom) eq 'ok') {
+ $error = 'nostore';
+ }
+ } else {
+ unless (&Apache::lonnet::newput('ltitools',{ $id => $title },$cdom,$cnum) eq 'ok') {
+ $error = 'nostore';
+ }
+ }
+ } else {
+ $error = 'nonumber';
+ }
+ }
+ my $dellockoutcome;
+ if ($context eq 'domain') {
+ $dellockoutcome = &Apache::lonnet::del_dom('ltitools',['lock'],$cdom);
+ } else {
+ $dellockoutcome = &Apache::lonnet::del('ltitools',['lock'],$cdom,$cnum);
+ }
+ } else {
+ $error = 'nolock';
+ }
+ return ($id,$error);
+}
+
+sub process_ltitools_image {
+ my ($r,$context,$dom,$cnum,$confname,$caller,$itemid,$configuserok,$switch,$author_ok,$currimg) = @_;
+ my $filename = $env{'form.'.$caller.'.filename'};
+ my ($error,$url);
+ my ($width,$height) = (21,21);
+ if ($configuserok eq 'ok') {
+ if ($switch) {
+ $error = &mt('Upload of Tool Provider (LTI) icon is not permitted to this server: [_1]',
+ $switch);
+ } elsif ($author_ok eq 'ok') {
+ my ($result,$imageurl,$madethumb);
+ if ($context eq 'domain') {
+ ($result,$imageurl,$madethumb) =
+ &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
+ "ltitools/$itemid/icon",$width,$height);
+ } else {
+ ($result,$imageurl,$madethumb) = &processlogo($dom,$cnum,$caller,$currimg,$itemid,$width,$height);
+ }
+ if ($result eq 'ok') {
+ if ($madethumb) {
+ my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
+ my $imagethumb = "$path/tn-".$imagefile;
+ $url = $imagethumb;
+ } else {
+ $url = $imageurl;
+ }
+ } else {
+ if ($context eq 'domain') {
+ $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
+ } else {
+ $error = &mt("Upload of [_1] failed because an error occurred. Error was: [_2].",$filename,$result);
+ }
+ }
+ } else {
+ $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$author_ok);
+ }
+ } else {
+ $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3]. Error was: [_4].",$filename,$confname,$dom,$configuserok);
+ }
+ return ($url,$error);
+}
+
+sub processlogo {
+ my ($dom,$cnum,$caller,$currimg,$itemid,$width,$height) = @_;
+ my ($result,$imageurl,$madethumb);
+ if ($env{"form.$caller.filename"} ne '') {
+ unless ($caller eq 'ltitools_add_image') {
+ if ($currimg =~ m{^(\Q/uploaded/$dom/$cnum/toollogo/$itemid\E)/([^/]+)$}) {
+ my ($path,$imagefile) = ($1,$2);
+ if ($imagefile =~ /^tn\-(.+)$/) {
+ my $origimg = $1;
+ &Apache::lonnet::removeuploadedurl("$path/$origimg");
+ }
+ &Apache::lonnet::removeuploadedurl($currimg);
+ }
+ }
+ $imageurl = &Apache::lonnet::userfileupload($caller,'toollogo',"toollogo/$itemid",
+ '','','',$cnum,$dom,$width,$height);
+ if ($imageurl =~ m{^(\Q/uploaded/$dom/$cnum/toollogo/$itemid\E)/([^/]+)$}) {
+ my ($path,$imagefile) = ($1,$2);
+ $result = 'ok';
+ my $thumburl = "$path/tn-".$imagefile;
+ my ($rtncode,$info);
+ my $res = &Apache::lonnet::getuploaded('HEAD',$thumburl,$dom,$cnum,\$info,\$rtncode);
+ if ($res eq 'ok') {
+ $madethumb = 1;
+ }
+ } elsif ($imageurl eq '/adm/notfound.html') {
+ undef($imageurl);
+ $result = 'store failed';
+ } elsif ($imageurl =~ /^error: (.+)$/) {
+ $result = $1;
+ }
+ }
+ return ($result,$imageurl,$madethumb);
+}
+
sub get_sec_str {
my ($entry,$num) = @_;
my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$num);
@@ -1609,12 +2554,15 @@ sub check_clone {
sub store_changes {
my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes,$crstype) = @_;
my ($chome,$output);
- my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot);
+ my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot,%oldltitools);
if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) {
- if (ref($values->{'linkprotection'}) eq 'HASH') {
- %oldlinkprot = %{$values->{'linkprotection'}};
+ if (ref($values->{'linkprot'}) eq 'HASH') {
+ %oldlinkprot = %{$values->{'linkprot'}};
+ }
+ delete($values->{'linkprot'});
+ if (ref($values->{'ltitools'}) eq 'HASH') {
+ %oldltitools = %{$values->{'ltitools'}};
}
- delete($values->{'linkprotection'});
%storehash = %{$values};
} else {
if ($crstype eq 'Community') {
@@ -1627,7 +2575,9 @@ sub store_changes {
my ($numchanges,$skipstore);
if (ref($changes) eq 'HASH') {
$numchanges = scalar(keys(%{$changes}));
- if (($numchanges == 1) && (exists($changes->{'linkprotection'}))) {
+ if (($numchanges == 1) && (exists($changes->{'linkprot'}))) {
+ $skipstore = 1;
+ } elsif (($numchanges == 1) && (exists($changes->{'ltitools'}))) {
$skipstore = 1;
} elsif (!$numchanges) {
if ($crstype eq 'Community') {
@@ -1650,7 +2600,7 @@ sub store_changes {
if (grep(/^\Q$item\E$/,@{$actions})) {
$output .= ''.&mt($prefs->{$item}{'text'}).' ';
if (ref($changes->{$item}) eq 'HASH') {
- if ((keys(%{$changes->{$item}}) > 0) || ($item eq 'linkprotection')) {
+ if (keys(%{$changes->{$item}}) > 0) {
$output .= &mt('Changes made:').'';
if ($item eq 'other') {
foreach my $key (sort(keys(%{$changes->{$item}}))) {
@@ -1663,41 +2613,10 @@ sub store_changes {
"'$storehash{$key}'")).'';
}
}
- } elsif ($item eq 'linkprotection') {
- if (&Apache::lonnet::put('lti',$changes->{'linkprotection'},$cdom,$cnum,1) eq 'ok') {
- my $hashid=$cdom.'_'.$cnum;
- &Apache::lonnet::devalidate_cache_new('courselti',$hashid);
- foreach my $itemid (sort { $a <=> $b } %{$changes->{'linkprotection'}}) {
- if (ref($changes->{'linkprotection'}->{$itemid}) eq 'HASH') {
- my %values = %{$changes->{'linkprotection'}->{$itemid}};
- my %desc = &linkprot_names();
- my $display;
- foreach my $title ('name','lifetime','version','key','secret') {
- if ($title eq 'secret') {
- my $length = length($values{$title});
- $display .= $desc{$title}.': '.('*' x $length);
- } elsif ($title eq 'version') {
- if ($values{$title} eq 'LTI-1p0') {
- $display .= $desc{$title}.': 1.1, ';
- }
- } else {
- $display .= $desc{$title}.': '.$values{$title}.', ';
- }
- }
- $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.$itemid.' ',
- "'$display'")).' ';
- } elsif (ref($oldlinkprot{$itemid}) eq 'HASH') {
- my $oldname = $oldlinkprot{$itemid}{'name'};
- $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',''."$itemid ($oldname)".' ')).' ';
- }
- }
- } else {
- $output .= ''.
- ''.
- &mt('An error occurred when saving changes to link protection settings, which remain unchanged.').
- ' '.
- ' ';
- }
+ } elsif ($item eq 'linkprot') {
+ $output .= &store_linkprot($cdom,$cnum,'course',$changes->{$item},\%oldlinkprot);
+ } elsif ($item eq 'ltitools') {
+ $output .= &store_ltitools($cdom,$cnum,'course',$changes->{$item},\%oldltitools);
} else {
if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') {
my @settings = @{$prefs->{$item}->{'ordered'}};
@@ -1729,12 +2648,52 @@ sub store_changes {
if ($msg ne '') {
$output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt($displayname)).' ';
}
+ } elsif ($key eq 'timezone') {
+ next unless ((exists($changes->{$item}{$key})) || (exists($changes->{$item}{'tzover'})));
+ my ($displayname,$text);
+ $text = $prefs->{$item}->{'itemtext'}{$key};
+ my $displayval;
+ if (exists($changes->{$item}{$key})) {
+ $displayname = &mt($text);
+ $storehash{$key} = $changes->{$item}{$key};
+ if ($changes->{$item}{$key} ne '') {
+ $displayval = ''.$changes->{$item}{$key}.' ';
+ } else {
+ push(@delkeys,$key);
+ if (exists($values->{'tzover'})) {
+ push(@delkeys,'tzover');
+ }
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',
+ ''.$displayname.' ')).' ';
+ }
+ }
+ unless (grep(/^\Q$key\E$/,@delkeys)) {
+ if (exists($changes->{$item}{'tzover'})) {
+ $storehash{'tzover'} = $changes->{$item}{'tzover'};
+ my $tzovertext;
+ if ($changes->{$item}{'tzover'} ne '') {
+ $tzovertext = &mt('Course Time Zone overrides individual user preference');
+ } else {
+ push(@delkeys,'tzover');
+ $tzovertext = &mt('Course Time Zone does not override individual user preference');
+ }
+ if ($displayval eq '') {
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success($tzovertext).' ';
+ } else {
+ $displayval .= ' '.(' 'x5).$tzovertext;
+ }
+ }
+ if ($displayval ne '') {
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
+ ''.$displayname.' ',$displayval)).' ';
+ }
+ }
} else {
next if (!exists($changes->{$item}{$key}));
my ($displayname,$text);
$text = $prefs->{$item}->{'itemtext'}{$key};
my $displayval;
- unless (($key eq 'co-owners') || ($key eq 'discussion_post_fonts')) {
+ unless (($key eq 'co-owners') || ($key eq 'discussion_post_fonts') || ($key eq 'extresource')) {
$displayval = $changes->{$item}{$key};
}
if ($item eq 'feedback') {
@@ -1852,12 +2811,44 @@ sub store_changes {
$displayval = &Apache::lonlocal::locallocaltime($displayval);
} elsif ($key eq 'categories') {
$displayval = $env{'form.categories_display'};
- } elsif (($key eq 'canuse_pdfforms') || ($key eq 'usejsme') || ($key eq 'uselcmath')) {
+ } elsif (($key eq 'canuse_pdfforms') || ($key eq 'usejsme') ||
+ ($key eq 'uselcmath') || ($key eq 'inline_chem')) {
if ($changes->{$item}{$key} eq '1') {
$displayval = &mt('Yes');
} elsif ($changes->{$item}{$key} eq '0') {
$displayval = &mt('No');
}
+ } elsif ($key eq 'extresource') {
+ if ($changes->{$item}{$key} eq 'iframe') {
+ $displayval = &mt('In iframe');
+ } else {
+ my ($selected,$reuse,$width,$height) = split(/:/,$changes->{$item}{$key});
+ if ($selected eq 'tab') {
+ if ($reuse) {
+ $displayval = &mt('[_1]In tab[_2],[_3] and tab re-used for different external resources in course',
+ "'"," '",' ');
+ } else {
+ $displayval = &mt('[_1]In tab[_2],[_3] with new tab for each external resource in course',
+ "'"," '",' ');
+ }
+ } elsif ($selected eq 'window') {
+ if ($reuse) {
+ $displayval = &mt('[_1]In pop-up window[_2],[_3] and window re-used for different external resources in course',
+ "'"," '",' ');
+ } else {
+ $displayval = &mt('[_1]In pop-up window[_2],[_3] with new window for each external resource in course',
+ "'"," '",' ');
+ }
+ if (($width ne '') || ($height ne '')) {
+ if ($width ne '') {
+ $displayval .= ' '.&mt('Window width: [_1]px',$width);
+ }
+ if ($height ne '') {
+ $displayval .= ' '.&mt('Window height: [_1]px',$height);
+ }
+ }
+ }
+ }
}
if ($key eq 'co-owners') {
if (ref($changes->{$item}{$key}) eq 'HASH') {
@@ -1929,9 +2920,11 @@ sub store_changes {
$output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('Numbered menu collections:')).' '.
$displayval.' ';
} else {
+ unless (($key eq 'extresource') && ($changes->{$item}{$key} ne 'iframe')) {
+ $displayval = "'$displayval '";
+ }
$output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',
- ''.$displayname.' ',
- "'$displayval '"));
+ ''.$displayname.' ',$displayval));
if ($key eq 'url') {
my $bkuptime=time;
$output .= (' 'x2).&mt('(Previous URL backed up)').': '.
@@ -2030,6 +3023,378 @@ sub store_changes {
return $output;
}
+sub store_linkprot {
+ my ($cdom,$cnum,$context,$changes,$oldlinkprot) = @_;
+ my ($ltiauth,$home,$lti_save_error,$output,$error,%ltienc,@deletions);
+ if ($context eq 'domain') {
+ $ltiauth = 1;
+ $home = &Apache::lonnet::domain($cdom,'primary');
+ } else {
+ $home = &Apache::lonnet::homeserver($cnum,$cdom);
+ if (exists($env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'})) {
+ $ltiauth = $env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'};
+ } else {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
+ $ltiauth = $domdefs{'crsltiauth'};
+ }
+ }
+ if (ref($changes) eq 'HASH') {
+ foreach my $id (sort { $a <=> $b } keys(%{$changes})) {
+ if (ref($changes->{$id}) eq 'HASH') {
+ if (exists($changes->{$id}->{'key'})) {
+ $ltienc{$id}{'key'} = $changes->{$id}->{'key'};
+ delete($changes->{$id}->{'key'});
+ }
+ if (exists($changes->{$id}->{'secret'})) {
+ $ltienc{$id}{'secret'} = $changes->{$id}->{'secret'};
+ delete($changes->{$id}->{'secret'});
+ } elsif (ref($oldlinkprot->{$id}) eq 'HASH') {
+ if (exists($oldlinkprot->{$id}{'usable'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ if (exists($oldlinkprot->{$id}{'cipher'})) {
+ $changes->{$id}->{'cipher'} = $oldlinkprot->{$id}{'cipher'};
+ }
+ }
+ }
+ }
+ }
+ my @ids=&Apache::lonnet::current_machine_ids();
+ if (keys(%ltienc) > 0) {
+ if ($context eq 'domain') {
+ foreach my $id (keys(%ltienc)) {
+ if (exists($ltienc{$id}{'secret'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ }
+ } else {
+ unless (($home eq 'no_host') || ($home eq '')) {
+ my $allowed;
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
+ if ($allowed) {
+ if (&Apache::lonnet::put('nohist_ltienc',\%ltienc,$cdom,$cnum,1) eq 'ok') {
+ foreach my $id (keys(%ltienc)) {
+ if (exists($ltienc{$id}{'secret'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ }
+ } else {
+ $lti_save_error = 1;
+ }
+ }
+ }
+ }
+ }
+ unless ($lti_save_error) {
+ if ($context eq 'course') {
+ if (&Apache::lonnet::put('lti',$changes,$cdom,$cnum,1) eq 'ok') {
+ my $hashid=$cdom.'_'.$cnum;
+ &Apache::lonnet::devalidate_cache_new('courselti',$hashid);
+ unless (($home eq 'no_host') || ($home eq '')) {
+ if (grep(/^\Q$home\E$/,@ids)) {
+ &Apache::lonnet::devalidate_cache_new('courseltienc',$hashid);
+ }
+ }
+ } else {
+ $lti_save_error = 1;
+ }
+ }
+ unless ($lti_save_error) {
+ foreach my $id (sort { $a <=> $b } %{$changes}) {
+ if (ref($changes->{$id}) eq 'HASH') {
+ my %values = %{$changes->{$id}};
+ my %desc = &linkprot_names();
+ my $display;
+ foreach my $title ('name','lifetime','version','key','secret','returnurl','passbackformat') {
+ if (($title eq 'key') || ($title eq 'secret')) {
+ if (ref($ltienc{$id}) eq 'HASH') {
+ if (exists($ltienc{$id}{$title})) {
+ if ($title eq 'secret') {
+ my $length = length($ltienc{$id}{$title});
+ $display .= $desc{$title}.': ['.&mt('not shown').'], ';
+ } else {
+ $display .= $desc{$title}.': '.$ltienc{$id}{$title}.', ';
+ }
+ }
+ }
+ } elsif ($title eq 'version') {
+ if ($values{$title} eq 'LTI-1p0') {
+ $display .= $desc{$title}.': 1.1, ';
+ }
+ } elsif ($title eq 'returnurl') {
+ if ($values{$title}) {
+ $display .= &mt('Return URL parameter').': '.$values{$title}.', ';
+ }
+ } elsif ($title eq 'passbackformat') {
+ if ($values{$title} eq '1.0') {
+ $display .= &mt('Can return grades to Launcher with Outcomes Service 1.0 format').', ';
+ } elsif ($values{$title} eq '1.1') {
+ $display .= &mt('Can return grades to Launcher with Outcomes Service 1.1 format').', ';
+ }
+ } else {
+ $display .= $desc{$title}.': '.$values{$title}.', ';
+ }
+ }
+ if ($ltiauth) {
+ if (($values{'requser'}) && ($values{'mapuser'} ne '')) {
+ if ($values{'mapuser'} eq 'lis_person_contact_email_primary') {
+ $display .= &mt('Source of username: Email address [_1]',
+ '(lis_person_contact_email_primary)').', ';
+ } elsif ($values{'mapuser'} eq 'lis_person_sourcedid') {
+ $display .= &mt('Source of username: User ID [_1]',
+ '(lis_person_sourcedid)').', ';
+ } else {
+ $display .= &mt('Source of username: [_1]',$values{'mapuser'}).', ';
+ }
+ if ($values{'notstudent'} eq 'auth') {
+ $display .= &mt('Display LON-CAPA login page if no match').', ';
+ } elsif ($values{'notstudent'} eq 'reject') {
+ $display .= &mt('Discontinue launch if no match').', ';
+ }
+ }
+ }
+ $display =~ s/, $//;
+ $output .= ' '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.$id.' ',
+ "'$display'")).' ';
+ } elsif (ref($oldlinkprot->{$id}) eq 'HASH') {
+ my $oldname = $oldlinkprot->{$id}{'name'};
+ $output .= ''.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',''."$id ($oldname)".' ')).' ';
+ }
+ }
+ } else {
+ $lti_save_error = 1;
+ }
+ }
+ unless ($lti_save_error) {
+ foreach my $id (sort { $a <=> $b } keys(%{$changes})) {
+ unless (ref($changes->{$id}) eq 'HASH') {
+ push(@deletions,$id);
+ }
+ }
+ if (@deletions) {
+ if ($context eq 'course') {
+ &Apache::lonnet::del('nohist_ltienc',\@deletions,$cdom,$cnum);
+ }
+ }
+ }
+ if ($lti_save_error) {
+ $output .= ''.
+ ''.
+ &mt('An error occurred when saving changes to link protection settings, which remain unchanged.').
+ ' '.
+ ' ';
+ }
+ return $output;
+}
+
+sub store_ltitools {
+ my ($cdom,$cnum,$context,$changes,$oldltitools) = @_;
+ my ($home,$ltitools_save_error,$output,$error,%toolsenc,@deletions);
+ my %lt = <itools_names();
+ my @courseroles = ('cc','in','ta','ep','st');
+ my @allfields = ('fullname','firstname','lastname','email','user','roles');
+ if ($context eq 'domain') {
+ $home = &Apache::lonnet::domain($cdom,'primary');
+ } else {
+ $home = &Apache::lonnet::homeserver($cnum,$cdom);
+ }
+ if (ref($changes) eq 'HASH') {
+ foreach my $id (sort { $a <=> $b } keys(%{$changes})) {
+ if (ref($changes->{$id}) eq 'HASH') {
+ if (exists($changes->{$id}->{'key'})) {
+ $toolsenc{$id}{'key'} = $changes->{$id}->{'key'};
+ delete($changes->{$id}->{'key'});
+ }
+ if (exists($changes->{$id}->{'secret'})) {
+ $toolsenc{$id}{'secret'} = $changes->{$id}->{'secret'};
+ delete($changes->{$id}->{'secret'});
+ } elsif (ref($oldltitools->{$id}) eq 'HASH') {
+ if (exists($oldltitools->{$id}{'usable'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ if (exists($oldltitools->{$id}{'cipher'})) {
+ $changes->{$id}->{'cipher'} = $oldltitools->{$id}{'cipher'};
+ }
+ }
+ }
+ }
+ }
+ my @ids=&Apache::lonnet::current_machine_ids();
+ if (keys(%toolsenc) > 0) {
+ unless (($home eq 'no_host') || ($home eq '')) {
+ my $allowed;
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
+ if ($allowed) {
+ if (($context eq 'domain') ||
+ (($context eq 'course') &&
+ (&Apache::lonnet::put('nohist_toolsenc',\%toolsenc,$cdom,$cnum,1) eq 'ok'))) {
+ foreach my $id (keys(%toolsenc)) {
+ if (exists($toolsenc{$id}{'secret'})) {
+ $changes->{$id}->{'usable'} = 1;
+ }
+ }
+ } else {
+ $ltitools_save_error = 1;
+ }
+ }
+ }
+ }
+ unless ($ltitools_save_error) {
+ if ($context eq 'course') {
+ if (&Apache::lonnet::put('ltitools',$changes,$cdom,$cnum,1) eq 'ok') {
+ my $hashid=$cdom.'_'.$cnum;
+ &Apache::lonnet::devalidate_cache_new('courseltitools',$hashid);
+ unless (($home eq 'no_host') || ($home eq '')) {
+ if (grep(/^\Q$home\E$/,@ids)) {
+ &Apache::lonnet::devalidate_cache_new('crsltitoolsenc',$hashid);
+ }
+ }
+ } else {
+ $ltitools_save_error = 1;
+ }
+ }
+ unless ($ltitools_save_error) {
+ my %bynum;
+ foreach my $itemid (sort(keys(%{$changes}))) {
+ my $position = $changes->{$itemid}{'order'};
+ $bynum{$position} = $itemid;
+ }
+ foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
+ my $itemid = $bynum{$pos};
+ if (ref($changes->{$itemid}) ne 'HASH') {
+ $output .= ''.&mt('Deleted: [_1]',$changes->{$itemid}).' ';
+ } else {
+ $output .= ''.$changes->{$itemid}{'title'}.' ';
+ if ($changes->{$itemid}{'image'}) {
+ $output .= ' '.
+ ' ';
+ }
+ $output .= '';
+ my $position = $pos + 1;
+ $output .= ''.&mt('Order: [_1]',$position).' ';
+ foreach my $item ('version','msgtype','sigmethod','url','lifetime') {
+ if ($changes->{$itemid}{$item} ne '') {
+ $output .= ''.$lt{$item}.': '.$changes->{$itemid}{$item}.' ';
+ }
+ }
+ if (ref($toolsenc{$itemid}) eq 'HASH') {
+ foreach my $item ('key','secret') {
+ if (exists($toolsenc{$itemid}{$item})) {
+ if ($item eq 'secret') {
+ $output .= ''.$lt{$item}.': ['.&mt('not shown').'] ';
+ } else {
+ $output .= ''.$lt{$item}.': '.$toolsenc{$itemid}{$item}.' ';
+ }
+ }
+ }
+ }
+ $output .= ''.&mt('Configurable in course:');
+ my @possconfig = ('label','title','target','linktext','explanation','append');
+ my $numconfig = 0;
+ if (ref($changes->{$itemid}{'crsconf'}) eq 'HASH') {
+ foreach my $item (@possconfig) {
+ if ($changes->{$itemid}{'crsconf'}{$item}) {
+ $numconfig ++;
+ $output .= ' "'.$lt{'crs'.$item}.'"';
+ }
+ }
+ }
+ if (!$numconfig) {
+ $output .= ' '.&mt('None');
+ }
+ $output .= ' ';
+ foreach my $item ('passback','roster') {
+ $output .= ''.$lt{$item}.' ';
+ if ($changes->{$itemid}{$item}) {
+ $output .= &mt('Yes');
+ if ($changes->{$itemid}{$item.'valid'}) {
+ if ($item eq 'passback') {
+ $output .= ' '.&mt('valid for at least [quant,_1,day] after launch',
+ $changes->{$itemid}{$item.'valid'});
+ } else {
+ $output .= ' '.&mt('valid for at least [quant,_1,second] after launch',
+ $changes->{$itemid}{$item.'valid'});
+ }
+ }
+ } else {
+ $output .= &mt('No');
+ }
+ $output .= ' ';
+ }
+ if (ref($changes->{$itemid}{'display'}) eq 'HASH') {
+ my $displaylist;
+ if ($changes->{$itemid}{'display'}{'target'}) {
+ $displaylist = &mt('Display target').': '.
+ $changes->{$itemid}{'display'}{'target'}.',';
+ }
+ foreach my $size ('width','height') {
+ if ($changes->{$itemid}{'display'}{$size}) {
+ $displaylist .= (' 'x2).$lt{$size}.': '.
+ $changes->{$itemid}{'display'}{$size}.',';
+ }
+ }
+ if ($displaylist) {
+ $displaylist =~ s/,$//;
+ $output .= ''.$displaylist.' ';
+ }
+ foreach my $item ('linktext','explanation') {
+ if ($changes->{$itemid}{'display'}{$item}) {
+ $output .= ''.$lt{$item}.': '.$changes->{$itemid}{'display'}{$item}.' ';
+ }
+ }
+ }
+ if (ref($changes->{$itemid}{'fields'}) eq 'HASH') {
+ my $fieldlist;
+ foreach my $field (@allfields) {
+ if ($changes->{$itemid}{'fields'}{$field}) {
+ $fieldlist .= (' 'x2).$lt{$field}.',';
+ }
+ }
+ if ($fieldlist) {
+ $fieldlist =~ s/,$//;
+ if ($changes->{$itemid}{'fields'}{'user'}) {
+ if ($changes->{$itemid}{'incdom'}) {
+ $fieldlist .= ' ('.&mt('username:domain').')';
+ } else {
+ $fieldlist .= ' ('.&mt('username').')';
+ }
+ }
+ $output .= ''.&mt('Data sent').':'.$fieldlist.' ';
+ }
+ }
+ if (ref($changes->{$itemid}{'roles'}) eq 'HASH') {
+ my $rolemaps;
+ foreach my $role (@courseroles) {
+ if ($changes->{$itemid}{'roles'}{$role}) {
+ $rolemaps .= (' 'x2).&Apache::lonnet::plaintext($role,'Course').'='.
+ $changes->{$itemid}{'roles'}{$role}.',';
+ }
+ }
+ if ($rolemaps) {
+ $rolemaps =~ s/,$//;
+ $output .= ''.&mt('Role mapping:').$rolemaps.' ';
+ }
+ }
+ if (ref($changes->{$itemid}{'custom'}) eq 'HASH') {
+ my $customlist;
+ if (keys(%{$changes->{$itemid}{'custom'}})) {
+ foreach my $key (sort(keys(%{$changes->{$itemid}{'custom'}}))) {
+ $customlist .= $key.':'.$changes->{$itemid}{'custom'}{$key}.(' 'x2);
+ }
+ }
+ if ($customlist) {
+ $output .= ''.&mt('Custom items').': '.$customlist.' ';
+ }
+ }
+ $output .= ' ';
+ }
+ }
+ }
+ }
+ return $output;
+}
+
sub update_env {
my ($cnum,$cdom,$chome,$need_env_update,$storehash) = @_;
my $count = 0;
@@ -2162,10 +3527,15 @@ sub get_course {
sub get_jscript {
my ($cid,$cdom,$phase,$crstype,$settings,$noedit) = @_;
my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype);
- my ($jscript,$categorize_js,$loncaparev_js,$instcode_js);
+ my ($jscript,$categorize_js,$loncaparev_js,$instcode_js,$extresource_js,$localization_js);
my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript();
my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset');
my $cloners_js = &cloners_javascript($phase);
+ my $currltitools;
+ if (ref($settings) eq 'HASH') {
+ $currltitools = $settings->{'ltitools'};
+ }
+ my $ltitools_js = &Apache::lonconfigsettings::ltitools_javascript($currltitools);
my @code_order;
if ($crstype ne 'Community') {
if (ref($settings) eq 'HASH') {
@@ -2185,7 +3555,7 @@ sub get_jscript {
$local_to_standard{$code_order[$i]} = $standardnames[$i];
}
foreach my $cloner (@cloners) {
- if (($cloner !~ /^\Q*:\E$match_domain$/) &&
+ if (($cloner !~ /^\Q*:\E$match_domain$/) &&
($cloner !~ /^$match_username\:$match_domain$/)) {
foreach my $item (split(/\&/,$cloner)) {
my ($key,$val) = split(/\=/,$item);
@@ -2369,12 +3739,55 @@ function toggleAddmenucoll() {
}
ENDSCRIPT
}
+ $extresource_js = <<"ENDSCRIPT";
+function toggleExtRes() {
+ if (document.getElementById('LC_extresource')) {
+ var extressel = document.getElementById('LC_extresource').value;
+ if (document.getElementById('LC_extresreusediv')) {
+ var extresreuse = document.getElementById('LC_extresreusediv');
+ if (document.getElementById('LC_extressize')) {
+ var extressize = document.getElementById('LC_extressize');
+ var setvis;
+ if ((extressel == 'tab') || (extressel == 'window')) {
+ extresreuse.style.display = 'inline-block';
+ setvis = 1;
+ if (extressel == 'window') {
+ extressize.style.display = 'inline-block';
+ } else {
+ extressize.style.display = 'none';
+ }
+ }
+ if (!setvis) {
+ extresreuse.style.display = 'none';
+ extressize.style.display = 'none';
+ }
+ }
+ }
+ }
+}
+ENDSCRIPT
+ $localization_js = <<"ENDSCRIPT";
+function toggleTimeZone() {
+ if (document.getElementById('LC_set_timezone')) {
+ var timezonesel = document.getElementById('LC_set_timezone').value;
+ if (document.getElementById('LC_tzoverdiv')) {
+ var tzoverdiv = document.getElementById('LC_tzoverdiv');
+ if (timezonesel == '') {
+ tzoverdiv.style.display = 'none';
+ } else {
+ tzoverdiv.style.display = 'block';
+ }
+ }
+ }
+}
+ENDSCRIPT
$jscript = ''."\n".$stubrowse_js."\n";
+ $cloners_js."\n".$instcode_js."\n".$localization_js."\n".
+ $syllabus_js."\n".$menuitems_js."\n".$extresource_js."\n".
+ &linkprot_javascript()."\n".'//]]>'."\n".
+ ''."\n".$stubrowse_js."\n".$ltitools_js."\n";
return $jscript;
}
@@ -2459,6 +3872,36 @@ function getIndexByName(item) {
ENDSCRIPT
}
+sub linkprot_javascript {
+ return <<"ENDSCRIPT";
+function toggleLinkProtExtra(form,item,extra,valon,styleon,num) {
+ if (document.getElementById('linkprot_'+extra+'_'+num)) {
+ var extraid = document.getElementById('linkprot_'+extra+'_'+num);
+ var itemname = form.elements['linkprot_'+item+'_'+num];
+ if (itemname) {
+ if (itemname.length > 0) {
+ var setvis;
+ for (var i=0; i';
$editsyllabus = &mt('[_1]Edit[_2]','',
- ' ');
+ '');
}
my %items = (
'url' => {
@@ -2634,7 +4077,7 @@ sub print_courseinfo {
next if (!$env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'});
}
unless (($item eq 'cloners') || ($item eq 'rolenames')) {
- $colspan = 2;
+ $colspan = 2;
}
$count ++;
if (exists $items{$item}{advanced} && $items{$item}{advanced} == 1) {
@@ -2817,12 +4260,12 @@ sub print_courseinfo {
if ($clonesrc =~ m{/$match_domain/$match_courseid}) {
my %clonesrcinfo = &Apache::lonnet::coursedescription($clonesrc);
if ($clonesrcinfo{'description'}) {
- $clonedfrom = $clonesrcinfo{'description'}.' '.($clonesrc);
+ $clonedfrom = $clonesrcinfo{'description'}.' '.($clonesrc);
}
}
$datatable .= $clonedfrom;
} elsif ($item eq 'uniquecode') {
- my $code = $env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'};
+ my $code = $env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'};
if ($code) {
$datatable .= $code;
}
@@ -2869,12 +4312,12 @@ sub print_courseinfo {
} elsif ($uploaded) {
$datatable .= &mt('Uploaded file');
} else {
- $datatable .= &mt('Standard template');
+ $datatable .= &mt('Standard template');
}
$datatable .= (' ' x 2).
&mt('[_1]View[_2]',
'',
- ' ');
+ '');
} elsif ($item eq 'loncaparev') {
my $loncaparev = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'};
my $showreqd;
@@ -2899,7 +4342,7 @@ sub new_cloners_dom_row {
my ($output,$checkedon,$checkedoff);
if ($newdom ne '') {
if ($num eq $default) {
- $checkedon = 'checked="checked" ';
+ $checkedon = 'checked="checked" ';
} else {
$checkedoff = 'checked="checked" ';
}
@@ -3050,7 +4493,7 @@ ENDSCRIPT
sub display_loncaparev_constraints {
my ($r,$navmap,$loncaparev,$crstype) = @_;
- my ($reqdmajor,$reqdminor);
+ my ($reqdmajor,$reqdminor);
my $cid = $env{'request.course.id'};
my $cdom = $env{'course.'.$cid.'.domain'};
my $cnum = $env{'course.'.$cid.'.num'};
@@ -3320,7 +4763,7 @@ sub display_loncaparev_constraints {
if (ref($fromblocks{$type}) eq 'HASH') {
foreach my $rev (keys(%{$fromblocks{$type}})) {
my ($major,$minor) = split(/\./,$rev);
- ($reqdmajor,$reqdminor) =
+ ($reqdmajor,$reqdminor) =
&Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
$output .= &Apache::loncommon::start_data_table_row().
''.$rev.' '.$lt{$type}.' ';
@@ -3407,7 +4850,7 @@ sub display_loncaparev_constraints {
&Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor,
$reqdmajor,$reqdminor);
$checkedrev{$key} = 1;
- }
+ }
push(@{$byresponsetype{$symb}{$rev}},$key);
$allmaps{$enclosing_map} = 1;
}
@@ -3444,10 +4887,7 @@ sub display_loncaparev_constraints {
}
}
}
- my $suppmap = 'supplemental.sequence';
- my ($suppcount,$supptools,$errors) = (0,0,0);
- ($suppcount,$supptools,$errors) = &Apache::loncommon::recurse_supplemental($cnum,$cdom,
- $suppmap,$suppcount,$supptools,$errors);
+ my $supptools = &Apache::lonnet::count_supptools($cnum,$cdom,1,1);
my $mapres_header = ''.
&mt('Requirements for specific folders or resources').
' ';
@@ -3662,7 +5102,7 @@ sub show_contents_view {
sub releases_by_map {
my ($r,$bymap,$url,$scopeorder,$lt) = @_;
return unless ((ref($bymap) eq 'HASH') && (ref($scopeorder) eq 'ARRAY'));
- my $newrow = 0;
+ my $newrow = 0;
if (ref($bymap->{$url}) eq 'HASH') {
foreach my $rev (sort(keys(%{$bymap->{$url}}))) {
if ($newrow) {
@@ -3804,7 +5244,7 @@ sub coowner_invitations {
@pendingcoown = split(',',$pendingcoowners);
}
if (ref($currcoownref) eq 'ARRAY') {
- @currcoown == @{$currcoownref};
+ @currcoown = @{$currcoownref};
}
my $disabled;
if ($noedit) {
@@ -3868,7 +5308,7 @@ sub manage_coownership {
@pendingcoown = split(',',$pendingcoowners);
}
if (ref($currcoownref) eq 'ARRAY') {
- @currcoown == @{$currcoownref};
+ @currcoown = @{$currcoownref};
}
my $disabled;
if ($noedit) {
@@ -3954,9 +5394,23 @@ sub print_localization {
if ($item eq 'timezone') {
my $includeempty = 1;
my $timezone = &Apache::lonlocal::gettimezone();
+ my $onchange;
+ unless ($noedit) {
+ $onchange = ' onchange="javascript:toggleTimeZone();"';
+ }
+ my $id = ' id="LC_set_timezone"';
$datatable .=
- &Apache::loncommon::select_timezone($item,$timezone,undef,
- $includeempty,$disabled);
+ &Apache::loncommon::select_timezone($item,$timezone,$onchange,
+ $includeempty,$id,$disabled);
+ my $tzsty = 'none';
+ if ($timezone ne '') {
+ $tzsty = 'block';
+ }
+ $datatable .= ''.
+ ''.
+ &mt('Override individual user preference?').
+ &yesno_radio('tzover',$settings,undef,1,'',$noedit).
+ '
';
} elsif ($item eq 'datelocale') {
my $includeempty = 1;
my $locale_obj = &Apache::lonlocal::getdatelocale();
@@ -3969,7 +5423,7 @@ sub print_localization {
undef,$includeempty,$disabled);
} else {
if ($settings->{$item} eq '') {
- unless ($noedit) {
+ unless ($noedit) {
$datatable .= ' '.
&Apache::loncommon::select_language('languages_0','',1);
}
@@ -4006,8 +5460,8 @@ sub print_localization {
&Apache::loncommon::select_language('languages_'.$num,'',1).
' '.
' '.&Apache::loncommon::end_data_table_row();
- }
- $datatable .= &Apache::loncommon::end_data_table().' ';
+ }
+ $datatable .= &Apache::loncommon::end_data_table().' ';
}
}
$datatable .= &item_table_row_end();
@@ -4076,8 +5530,8 @@ sub print_feedback {
}
if ($position eq 'top') {
my $includeempty = 0;
- $datatable .= ''.
- &user_table($cdom,$item,\@sections,
+ $datatable .= ' '.
+ &user_table($cdom,$item,\@sections,
$settings->{$item},\%lt,$noedit);
} else {
$datatable .= &Apache::lonhtmlcommon::textbox($item.'.text',
@@ -4293,15 +5747,15 @@ sub print_discussion {
my $colspan;
if ($item eq 'allow_limited_html_in_feedback') {
$colspan = 2;
- }
+ }
$datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan);
if ($item eq 'plc.roles.denied') {
$datatable .= ' '.
''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit).
'
';
} elsif ($item eq 'plc.users.denied') {
- $datatable .= ' '.
- &user_table($cdom,$item,undef,
+ $datatable .= ' '.
+ &user_table($cdom,$item,undef,
$settings->{$item},\%lt,$noedit);
} elsif ($item eq 'pch.roles.denied') {
$datatable .= ' '.
@@ -4338,7 +5792,7 @@ sub print_discussion {
' '.&mt('font-size').' '.
''.&mt('font-weight').' '.
''.&mt('font-style').' '.
- ''.&mt('Other css').' '.
+ ''.&mt('Other css').' '.
&Apache::loncommon::end_data_table_row().
&set_discussion_fonts($cdom,$cnum,$item,$settings,$noedit).
&Apache::loncommon::end_data_table().' ';
@@ -4390,7 +5844,7 @@ sub role_checkboxes {
my $count = 0;
my $disabled;
if ($noedit) {
- $disabled = ' disabled="disabled"';
+ $disabled = ' disabled="disabled"';
}
foreach my $role (@roles) {
my $checked = '';
@@ -4518,7 +5972,7 @@ sub set_discussion_fonts {
sub discussion_vote_classes {
my $classorder = ['twoplus','oneplus','zero','oneminus','twominus'];
- my %classtitles = &Apache::lonlocal::texthash(
+ my %classtitles = &Apache::lonlocal::texthash(
'twoplus' => 'Two sigma above mean',
'oneplus' => 'One sigma above mean',
'zero' => 'Within one sigma of mean',
@@ -4584,7 +6038,7 @@ sub print_classlists {
'defaultcredits' => {
text => ''.&mt($itemtext->{'defaultcredits'}).' ',
},
-
+
'nothideprivileged' => {
text => ''.&mt($itemtext->{'nothideprivileged'}).' ',
input => 'checkbox',
@@ -4671,6 +6125,20 @@ sub print_appearance {
text => ''.&mt($itemtext->{'usejsme'}).' ',
input => 'radio',
},
+ 'inline_chem' => {
+ text => ''.&mt($itemtext->{'inline_chem'}).' ',
+ input => 'radio',
+ },
+ 'extresource' => {
+ text => ''.&mt($itemtext->{'extresource'}).' ',
+ input => 'selectbox',
+ options => {
+ iframe => 'In iframe',
+ tab => 'In new tab',
+ window => 'In pop-up window',
+ },
+ order => ['iframe','tab','window'],
+ },
);
return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'appearance',$noedit);
}
@@ -4862,6 +6330,553 @@ sub print_bridgetasks {
return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'bridgetasks',$noedit);
}
+sub print_ltitools {
+ my ($cdom,$cnum,$settings,$rowtotal,$crstype,$noedit,$context) = @_;
+ my ($datatable,$disabled,$css_class,$dest);
+ if ($noedit) {
+ $disabled = ' disabled="disabled"';
+ }
+ my $itemcount = 1;
+ unless ($context eq 'domain') {
+ my %tooltypes = &Apache::loncommon::usable_exttools();
+ unless ($tooltypes{'crs'}) {
+ my $showtype = 'course';
+ if ($crstype eq 'Community') {
+ $showtype = lc($crstype);
+ }
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ $datatable = ''.
+ &mt("Definition of external tools is not enabled for this $showtype.").' ';
+ if ($tooltypes{'dom'}) {
+ $datatable .= &mt("Contact an administrator for the $showtype domain ([_1]) to request this feature be enabled.",
+ ''.$cdom.' ').
+ ' '.
+ &mt("Use of external tools defined at a domain level is enabled, so the $showtype editor can be used to add tool(s), if any have been defined.");
+ } else {
+ $datatable .= &mt("Use of external tools defined at a domain level is not enabled, either, for this $showtype.").
+ ' '.
+ &mt("Contact an administrator for the $showtype domain ([_1]) to request changes.",
+ ''.$cdom.' ');
+
+ }
+ $datatable .= ' ';
+ $itemcount ++;
+ return $datatable;
+ }
+ }
+ my %lt = <itools_names();
+ my $maxnum = 0;
+ my %ordered;
+ if (ref($settings) eq 'HASH') {
+ foreach my $item (keys(%{$settings})) {
+ if (ref($settings->{$item}) eq 'HASH') {
+ my $num = $settings->{$item}{'order'};
+ $ordered{$num} = $item;
+ }
+ }
+ }
+
+ if ($context eq 'domain') {
+ $dest = '/adm/domainprefs';
+ } else {
+ $dest = '/adm/courseprefs';
+ }
+ my ($switchserver,$switchmessage);
+ $switchserver = &check_switchserver($cdom,$cnum,$context,$dest);
+ if ($switchserver) {
+ if ($context eq 'domain') {
+ $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);
+ } elsif ($crstype eq 'Community') {
+ $switchmessage = &mt("submit from community's home server: [_1].",$switchserver);
+ } else {
+ $switchmessage = &mt("submit from course's home server: [_1].",$switchserver);
+ }
+ }
+ my $maxnum = scalar(keys(%ordered));
+ my @courseroles = ('cc','in','ta','ep','st');
+ my @ltiroles = qw(Instructor ContentDeveloper TeachingAssistant Learner);
+ my @fields = ('fullname','firstname','lastname','email','roles','user');
+ if (keys(%ordered)) {
+ my @items = sort { $a <=> $b } keys(%ordered);
+ for (my $i=0; $i<@items; $i++) {
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $item = $ordered{$items[$i]};
+ my ($title,$key,$url,$usable,$lifetime,$imgsrc,%sigsel);
+ if (ref($settings->{$item}) eq 'HASH') {
+ $title = $settings->{$item}->{'title'};
+ $url = $settings->{$item}->{'url'};
+ $key = $settings->{$item}->{'key'};
+ $usable = $settings->{$item}->{'usable'};
+ $lifetime = $settings->{$item}->{'lifetime'};
+ my $image = $settings->{$item}->{'image'};
+ if ($image ne '') {
+ $imgsrc = ' ';
+ }
+ if ($settings->{$item}->{'sigmethod'} eq 'HMAC-256') {
+ $sigsel{'HMAC-256'} = ' selected="selected"';
+ } else {
+ $sigsel{'HMAC-SHA1'} = ' selected="selected"';
+ }
+ }
+ my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_".$item."'".');"';
+ $datatable .= ''
+ .'';
+ for (my $k=0; $k<=$maxnum; $k++) {
+ my $vpos = $k+1;
+ my $selstr;
+ if ($k == $i) {
+ $selstr = ' selected="selected" ';
+ }
+ $datatable .= ''.$vpos.' ';
+ }
+ $datatable .= ' '.(' 'x2).
+ ' '.
+ &mt('Delete?').' '.
+ ''.
+ ''.&mt('Required settings').' '.
+ ''.$lt{'title'}.': '.
+ (' 'x2).
+ ''.$lt{'version'}.':'.
+ '1.1 '.
+ (' 'x2).
+ ''.$lt{'msgtype'}.':'.
+ 'Launch '.
+ (' 'x2).
+ ''.$lt{'sigmethod'}.':'.
+ 'HMAC-SHA1 '.
+ 'HMAC-SHA256 '.
+ ' '.
+ ''.$lt{'url'}.': '.
+ (' 'x2).
+ ''.$lt{'lifetime'}.':'.
+ ' ';
+ if ($key ne '') {
+ $datatable .= ''.$lt{'key'};
+ if ($noedit) {
+ $datatable .= ': ['.&mt('not shown').']';
+ } elsif ($switchserver) {
+ $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']';
+ } else {
+ $datatable .= ': ';
+ }
+ $datatable .= ' '.(' 'x2);
+ } elsif (!$switchserver) {
+ $datatable .= ''.$lt{'key'}.':'.
+ ' '.
+ ' '.(' 'x2);
+ }
+ if ($switchserver) {
+ if ($usable ne '') {
+ $datatable .= '
'.
+ $lt{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).' '.
+ ''.&mt('Change secret?').
+ ' '.&mt('No').' '.
+ (' 'x2).
+ ' '.&mt('Yes').' '.(' 'x2).
+ '
'.
+ ' - '.$switchmessage.' '.
+ '';
+ } elsif ($key eq '') {
+ $datatable .= ''.&mt('Key and Secret are required').' - '.$switchmessage.' '."\n";
+ } else {
+ $datatable .= ''.&mt('Secret required').' - '.$switchmessage.' '."\n";
+ }
+ $datatable .= ' ';
+ } else {
+ if ($usable ne '') {
+ $datatable .= '
'.
+ $lt{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).' '.
+ ''.&mt('Change?').
+ ' '.&mt('No').' '.
+ (' 'x2).
+ ' '.&mt('Yes').
+ '
'.
+ ''.&mt('New Secret').':'.
+ ' '.
+ ' '.&mt('Visible input').' '.
+ ' ';
+ } else {
+ $datatable .=
+ ''.$lt{'secret'}.':'.
+ ' '.
+ ' '.&mt('Visible input').' '.
+ ' ';
+ }
+ }
+ $datatable .= ' '.
+ ''.&mt('Optional settings').' '.
+ ''.&mt('Display target:');
+ my %currdisp;
+ if (ref($settings->{$item}->{'display'}) eq 'HASH') {
+ if ($settings->{$item}->{'display'}->{'target'} eq 'window') {
+ $currdisp{'window'} = ' checked="checked"';
+ } elsif ($settings->{$item}->{'display'}->{'target'} eq 'tab') {
+ $currdisp{'tab'} = ' checked="checked"';
+ } else {
+ $currdisp{'iframe'} = ' checked="checked"';
+ }
+ if ($settings->{$item}->{'display'}->{'width'} =~ /^(\d+)$/) {
+ $currdisp{'width'} = $1;
+ }
+ if ($settings->{$item}->{'display'}->{'height'} =~ /^(\d+)$/) {
+ $currdisp{'height'} = $1;
+ }
+ $currdisp{'linktext'} = $settings->{$item}->{'display'}->{'linktext'};
+ $currdisp{'explanation'} = $settings->{$item}->{'display'}->{'explanation'};
+ } else {
+ $currdisp{'iframe'} = ' checked="checked"';
+ }
+ foreach my $disp ('iframe','tab','window') {
+ $datatable .= ' '.
+ $lt{$disp}.' '.(' 'x2);
+ }
+ $datatable .= (' 'x4);
+ foreach my $dimen ('width','height') {
+ $datatable .= ''.$lt{$dimen}.' '.
+ ' '.
+ (' 'x2);
+ }
+ $datatable .= ' '.
+ ''.$lt{'linktext'}.' '.
+ '
'.
+ ''.$lt{'explanation'}.' '.
+ '
';
+ my %units = (
+ 'passback' => 'days',
+ 'roster' => 'seconds',
+ );
+ foreach my $extra ('passback','roster') {
+ my $validsty = 'none';
+ my $currvalid;
+ my $checkedon = '';
+ my $checkedoff = ' checked="checked"';
+ if ($settings->{$item}->{$extra}) {
+ $checkedon = $checkedoff;
+ $checkedoff = '';
+ $validsty = 'inline-block';
+ if ($settings->{$item}->{$extra.'valid'} =~ /^\d+\.?\d*$/) {
+ $currvalid = $settings->{$item}->{$extra.'valid'};
+ }
+ }
+ my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','$i'".');"';
+ $datatable .= ''.$lt{$extra}.' '.
+ ' '.
+ &mt('No').' '.(' 'x2).
+ ' '.
+ &mt('Yes').'
'.
+ '
';
+ }
+ $datatable .= ''.$lt{'icon'}.': ';
+ if ($imgsrc) {
+ $datatable .= $imgsrc.
+ ' '.&mt('Delete?').' '.
+ ' '.&mt('Replace:').' ';
+ } else {
+ $datatable .= '('.&mt('if larger than 21x21 pixels, image will be scaled').') ';
+ }
+ if ($switchserver) {
+ $datatable .= &mt('Upload to library server: [_1]',$switchserver);
+ } else {
+ $datatable .= ' ';
+ }
+ $datatable .= ' ';
+ my (%checkedfields,%rolemaps,$userincdom);
+ if (ref($settings->{$item}) eq 'HASH') {
+ if (ref($settings->{$item}->{'fields'}) eq 'HASH') {
+ %checkedfields = %{$settings->{$item}->{'fields'}};
+ }
+ $userincdom = $settings->{$item}->{'incdom'};
+ if (ref($settings->{$item}->{'roles'}) eq 'HASH') {
+ %rolemaps = %{$settings->{$item}->{'roles'}};
+ $checkedfields{'roles'} = 1;
+ }
+ }
+ $datatable .= ''.&mt('User data sent on launch').' '.
+ '';
+ my $userfieldstyle = 'display:none;';
+ my $seluserdom = '';
+ my $unseluserdom = ' selected="selected"';
+ foreach my $field (@fields) {
+ my ($checked,$onclick,$id,$spacer);
+ if ($checkedfields{$field}) {
+ $checked = ' checked="checked"';
+ }
+ if ($field eq 'user') {
+ $id = ' id="ltitools_user_field_'.$i.'"';
+ $onclick = ' onclick="toggleLTITools(this.form,'."'$field','$i'".')"';
+ if ($checked) {
+ $userfieldstyle = 'display:inline-block';
+ if ($userincdom) {
+ $seluserdom = $unseluserdom;
+ $unseluserdom = '';
+ }
+ }
+ } else {
+ $spacer = (' ' x2);
+ }
+ $datatable .= ''.
+ ' '.
+ $lt{$field}.' '.$spacer;
+ }
+ $datatable .= ' ';
+ $datatable .= ''.
+ ' : '.
+ ''.
+ ''.&mt('Select').' '.
+ ''.&mt('username').' '.
+ ''.&mt('username:domain').' '.
+ '
';
+ $datatable .= ' '.
+ ''.&mt('Role mapping').' ';
+ foreach my $role (@courseroles) {
+ my ($selected,$selectnone);
+ if (!$rolemaps{$role}) {
+ $selectnone = ' selected="selected"';
+ }
+ $datatable .= ''.
+ &Apache::lonnet::plaintext($role,'Course').' '.
+ ''.
+ ''.&mt('Select').' ';
+ foreach my $ltirole (@ltiroles) {
+ unless ($selectnone) {
+ if ($rolemaps{$role} eq $ltirole) {
+ $selected = ' selected="selected"';
+ } else {
+ $selected = '';
+ }
+ }
+ $datatable .= ''.$ltirole.' ';
+ }
+ $datatable .= ' ';
+ }
+ $datatable .= '
';
+ my %courseconfig;
+ if (ref($settings->{$item}) eq 'HASH') {
+ if (ref($settings->{$item}->{'crsconf'}) eq 'HASH') {
+ %courseconfig = %{$settings->{$item}->{'crsconf'}};
+ }
+ }
+ $datatable .= ''.&mt('Configurable in course').' ';
+ foreach my $item ('label','title','target','linktext','explanation','append') {
+ my $checked;
+ if ($courseconfig{$item}) {
+ $checked = ' checked="checked"';
+ }
+ $datatable .= ''.
+ ' '.
+ $lt{'crs'.$item}.' '."\n";
+ }
+ $datatable .= ' '.
+ ''.&mt('Custom items sent on launch').' '.
+ ' '."\n";
+ $itemcount ++;
+ }
+ }
+ $css_class = $itemcount%2?' class="LC_odd_row"':'';
+ my $chgstr = ' onchange="javascript:reorderLTITools(this.form,'."'ltitools_add_pos'".');"';
+ $datatable .= ''."\n".
+ ' '."\n".
+ '';
+ for (my $k=0; $k<$maxnum+1; $k++) {
+ my $vpos = $k+1;
+ my $selstr;
+ if ($k == $maxnum) {
+ $selstr = ' selected="selected" ';
+ }
+ $datatable .= ''.$vpos.' ';
+ }
+ $datatable .= ' '."\n".
+ ' '.&mt('Add').' '."\n".
+ ''.
+ ''.&mt('Required settings').' '.
+ ''.$lt{'title'}.': '."\n".
+ (' 'x2).
+ ''.$lt{'version'}.':'.
+ '1.1 '."\n".
+ (' 'x2).
+ ''.$lt{'msgtype'}.':'.
+ 'Launch '.
+ ''.$lt{'sigmethod'}.':'.
+ 'HMAC-SHA1 '.
+ 'HMAC-SHA256 '.
+ ' '.
+ ''.$lt{'url'}.': '."\n".
+ (' 'x2).
+ ''.$lt{'lifetime'}.': ';
+ if ($switchserver) {
+ $datatable .= ''.&mt('Key and Secret are required').' - '.$switchmessage.' '."\n";
+ } else {
+ $datatable .= ''.$lt{'key'}.': '."\n".
+ (' 'x2).
+ ''.$lt{'secret'}.': '.
+ ' '.&mt('Visible input').' '."\n";
+ }
+ $datatable .= ' '.
+ ' '.
+ ''.&mt('Optional settings').' '.
+ ''.&mt('Display target:');
+ my %defaultdisp;
+ $defaultdisp{'iframe'} = ' checked="checked"';
+ foreach my $disp ('iframe','tab','window') {
+ $datatable .= ' '.
+ $lt{$disp}.' '.(' 'x2);
+ }
+ $datatable .= (' 'x4);
+ foreach my $dimen ('width','height') {
+ $datatable .= ''.$lt{$dimen}.' '.
+ ' '.
+ (' 'x2);
+ }
+ $datatable .= ' '.
+ ''.$lt{'linktext'}.' '.
+ '
'.
+ ''.$lt{'explanation'}.' '.
+ ''.
+ '
';
+ my %units = (
+ 'passback' => 'days',
+ 'roster' => 'seconds',
+ );
+ my %defaulttimes = (
+ 'passback' => '7',
+ 'roster' => '300',
+ );
+ foreach my $extra ('passback','roster') {
+ my $onclick = ' onclick="toggleLTITools(this.form,'."'$extra','add'".');"';
+ $datatable .= ''.$lt{$extra}.' '.
+ ' '.
+ &mt('No').' '.(' 'x2).''.
+ ' '.
+ &mt('Yes').'
'.
+ '
';
+ }
+ $datatable .= ''.$lt{'icon'}.': '.
+ '('.&mt('if larger than 21x21 pixels, image will be scaled').') ';
+ if ($switchserver) {
+ $datatable .= &mt('Upload to library server: [_1]',$switchserver);
+ } else {
+ $datatable .= ' ';
+ }
+ $datatable .= ' '.
+ ''.&mt('User data sent on launch').' '.
+ '';
+ foreach my $field (@fields) {
+ my ($id,$onclick,$spacer);
+ if ($field eq 'user') {
+ $id = ' id="ltitools_user_field_add"';
+ $onclick = ' onclick="toggleLTITools(this.form,'."'$field','add'".')"';
+ } else {
+ $spacer = (' ' x2);
+ }
+ $datatable .= ''.
+ ' '.
+ $lt{$field}.' '.$spacer;
+ }
+ $datatable .= ' '.
+ ''.
+ ' : '.
+ ''.
+ ''.&mt('Select').' '.
+ ''.&mt('username').' '.
+ ''.&mt('username:domain').' '.
+ '
';
+ $datatable .= ''.&mt('Role mapping').' ';
+ foreach my $role (@courseroles) {
+ my ($checked,$checkednone);
+ $datatable .= ''.
+ &Apache::lonnet::plaintext($role,'Course').' '.
+ ''.
+ ''.&mt('Select').' ';
+ foreach my $ltirole (@ltiroles) {
+ $datatable .= ''.$ltirole.' ';
+ }
+ $datatable .= ' ';
+ }
+ $datatable .= '
'.
+ ''.&mt('Configurable in course').' ';
+ foreach my $item ('label','title','target','linktext','explanation','append') {
+ $datatable .= ''.
+ ' '.
+ $lt{'crs'.$item}.' '.(' ' x2)."\n";
+ }
+ $datatable .= ' '.
+ ''.&mt('Custom items sent on launch').' '.
+ ' '."\n".
+ ' '."\n".
+ ' '."\n";
+ $itemcount ++;
+ return $datatable;
+}
+
+sub ltitools_names {
+ my %lt = &Apache::lonlocal::texthash(
+ 'title' => 'Title',
+ 'version' => 'Version',
+ 'msgtype' => 'Message Type',
+ 'sigmethod' => 'Signature Method',
+ 'url' => 'URL',
+ 'key' => 'Key',
+ 'lifetime' => 'Nonce lifetime (s)',
+ 'secret' => 'Secret',
+ 'icon' => 'Icon',
+ 'user' => 'User',
+ 'fullname' => 'Full Name',
+ 'firstname' => 'First Name',
+ 'lastname' => 'Last Name',
+ 'email' => 'E-mail',
+ 'roles' => 'Role',
+ 'window' => 'Window',
+ 'tab' => 'Tab',
+ 'iframe' => 'iFrame',
+ 'height' => 'Height',
+ 'width' => 'Width',
+ 'linktext' => 'Default Link Text',
+ 'explanation' => 'Default Explanation',
+ 'passback' => 'Tool can return grades:',
+ 'roster' => 'Tool can retrieve roster:',
+ 'crstarget' => 'Display target',
+ 'crslabel' => 'Course label',
+ 'crstitle' => 'Course title',
+ 'crslinktext' => 'Link Text',
+ 'crsexplanation' => 'Explanation',
+ 'crsappend' => 'Provider URL',
+ );
+ return %lt;
+}
+
sub print_lti {
my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_;
unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {
@@ -5064,7 +7079,7 @@ sub print_menuitems {
my %checked;
my $on = ' checked="checked"';
foreach my $key (keys(%{$menu{$num}})) {
- if (($key eq 'top') || ($key eq 'inline') || ($key eq 'main')) {
+ if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) {
if ($menu{$num}{$key} eq 'y') {
$checked{$key} = $on;
}
@@ -5081,7 +7096,13 @@ sub print_menuitems {
foreach my $category (@order) {
if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) {
$datatable .= ''.$menutitles{$category}.' '."\n";
+ if ($category eq 'text') {
+ $datatable .= ''.&mt('Header').' ';
+ }
foreach my $field (@{$categories{$category}}) {
+ if ($field eq 'disc') {
+ $datatable .= ''.&mt('Footer').' ';
+ }
$datatable .= ' '.
$menufields{$field}.' ';
}
@@ -5131,8 +7152,8 @@ sub menuitems_abbreviations {
sub menuitems_categories {
my @order = ('shown','text','links','list','inline');
my %categories = (
- shown => ['top','inline','main'],
- text => ['name','role','crs'],
+ shown => ['top','inline','foot','main'],
+ text => ['name','role','crs','disc','fdbk'],
links => ['pers','logo','menu','comm','roles','help','logout'],
list => ['about','prefs','port','wish','anno','rss'],
inline => ['cont','grades','chat','people','groups','resv','syll','feeds'],
@@ -5143,7 +7164,7 @@ sub menuitems_categories {
sub menuitems_titles {
return &Apache::lonlocal::texthash (
shown => 'Hierarchy',
- text => 'Header text',
+ text => 'Text',
links => 'Header links',
list => 'Drop-down list',
inline => 'Inline links',
@@ -5154,6 +7175,7 @@ sub menuitems_fields {
return &Apache::lonlocal::texthash (
top => 'Display header',
inline => 'Display inline menu',
+ foot => 'Display footer',
main => 'Access to main menu',
pers => 'Personal',
logo => 'LON-CAPA',
@@ -5165,6 +7187,8 @@ sub menuitems_fields {
name => 'Fullname',
crs => 'Course Title',
role => 'Current Role',
+ disc => 'Discussion',
+ fdbk => 'Feedback',
about => 'Information',
prefs => 'Preferences',
port => 'Portfolio',
@@ -5206,7 +7230,7 @@ sub menucollections_display {
foreach my $num (@current) {
my %checked;
foreach my $key (keys(%{$menu{$num}})) {
- if (($key eq 'top') || ($key eq 'inline') || ($key eq 'main')) {
+ if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) {
if ($menu{$num}{$key} eq 'y') {
$checked{$key} = 1;
}
@@ -5224,7 +7248,13 @@ sub menucollections_display {
if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) {
$output .= ''.
''.$menutitles{$category}.' '."\n";
+ if ($category eq 'text') {
+ $output .= ''.&mt('Header Text').' ';
+ }
foreach my $field (@{$categories{$category}}) {
+ if ($field eq 'disc') {
+ $output .= ''.&mt('Footer Text').' ';
+ }
if ($checked{$field}) {
$output .= &Apache::lonhtmlcommon::confirm_success($menufields{$field});
} else {
@@ -5243,30 +7273,60 @@ sub menucollections_display {
}
sub print_linkprotection {
- my ($cdom,$settings,$rowtotal,$crstype,$noedit) = @_;
- unless (ref($settings) eq 'HASH') {
- return;
- }
+ my ($cdom,$cnum,$settings,$rowtotal,$crstype,$noedit,$context) = @_;
my %linkprotection;
my $count = 0;
my $next = 1;
- my ($datatable,$disabled,$css_class);
+ my ($datatable,$disabled,$css_class,$dest);
if ($noedit) {
$disabled = ' disabled="disabled"';
}
- my %lt = &linkprot_names();
+ my %desc = &linkprot_names();
+ my %lt = &Apache::lonlocal::texthash (
+ 'requ' => 'Required settings',
+ 'opti' => 'Optional settings',
+ );
my $itemcount = 0;
- if (ref($settings->{'linkprotection'}) eq 'HASH') {
- if (keys(%{$settings->{'linkprotection'}})) {
- my @current = sort { $a <=> $b } keys(%{$settings->{'linkprotection'}});
+ my $ltiauth;
+ if ($context eq 'domain') {
+ $ltiauth = 1;
+ } else {
+ if (exists($env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'})) {
+ $ltiauth = $env{'course.'.$env{'request.course.id'}.'.internal.ltiauth'};
+ } else {
+ my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
+ $ltiauth = $domdefs{'crsltiauth'};
+ }
+ }
+ if ($context eq 'domain') {
+ $dest = '/adm/domainprefs';
+ } else {
+ $dest = '/adm/courseprefs';
+ }
+
+ my ($switchserver,$switchmessage);
+ $switchserver = &check_switchserver($cdom,$cnum,$context,$dest);
+ if ($switchserver) {
+ if ($context eq 'domain') {
+ $switchmessage = &mt("submit from domain's primary library server: [_1].",$switchserver);
+ } elsif ($crstype eq 'Community') {
+ $switchmessage = &mt("submit from community's home server: [_1].",$switchserver);
+ } else {
+ $switchmessage = &mt("submit from course's home server: [_1].",$switchserver);
+ }
+ }
+
+ if ((ref($settings) eq 'HASH') && (ref($settings->{'linkprot'}) eq 'HASH')) {
+ if (keys(%{$settings->{'linkprot'}})) {
+ my @current = sort { $a <=> $b } keys(%{$settings->{'linkprot'}});
$next += $current[-1];
for (my $i=0; $i<@current; $i++) {
my $num = $current[$i];
my %values;
- if (ref($settings->{'linkprotection'}->{$num}) eq 'HASH') {
- %values = %{$settings->{'linkprotection'}->{$num}};
+ if (ref($settings->{'linkprot'}->{$num}) eq 'HASH') {
+ %values = %{$settings->{'linkprot'}->{$num}};
} else {
next;
}
@@ -5278,24 +7338,150 @@ sub print_linkprotection {
$datatable .=
''.
' '.
- &mt('Delete?').' '.
- ''.$lt{'name'}.
- ': '.
+ &mt('Delete?').'';
+ my ($usersty,$onclickrequser,%checkedrequser,$onclickreturnurl,%checkedreturnurl,
+ $onclickpassback,%checkedpassback,$passbacksty,%checkedpassbackfmt);
+ $passbacksty = 'none';
+ $onclickpassback = ' onclick="toggleLinkProtExtra(this.form,'."'passback','passbackparam','1','inline-block','$i'".');"';
+ %checkedpassback = (
+ 'no' => ' checked="checked"',
+ 'yes' => '',
+ );
+ %checkedpassbackfmt = (
+ '1p1' => ' checked="checked"',
+ '1p0' => '',
+ );
+ if ($values{'passback'} ne '') {
+ $passbacksty = 'inline-block';
+ $checkedpassback{'yes'} = ' checked="checked"';
+ $checkedpassback{'no'} = '';
+ if ($values{'passbackformat'} eq '1.0') {
+ $checkedpassbackfmt{'1p0'} = ' checked="checked"';
+ $checkedpassbackfmt{'1p1'} = '';
+ }
+ }
+ if ($ltiauth) {
+ $usersty = 'display:none';
+ $onclickrequser = ' onclick="toggleLinkProtExtra(this.form,'."'requser','optional','1','block','$i'".');"';
+ %checkedrequser = (
+ no => ' checked="checked"',
+ yes => '',
+ );
+ if ($values{'requser'}) {
+ $checkedrequser{'yes'} = $checkedrequser{'no'};
+ $checkedrequser{'no'} = '';
+ }
+ $datatable .= ''.$lt{'requ'}.' ';
+ if ($values{'requser'}) {
+ $usersty = 'display:inline-block';
+ }
+ }
+ $onclickreturnurl = ' onclick="toggleLinkProtExtra(this.form,'."'returnurl','divurlparam','1','inline-block','$i'".');"';
+ %checkedreturnurl = (
+ no => ' checked="checked"',
+ yes => '',
+ );
+ if ($values{'returnurl'} ne '') {
+ $checkedreturnurl{'yes'} = $checkedreturnurl{'no'};
+ $checkedreturnurl{'no'} = '';
+ }
+ $datatable .=
+ ''.$desc{'name'}.
+ ': '.
(' 'x2).
- ''.$lt{'version'}.':'.
+ ''.$desc{'version'}.':'.
'1.1 '."\n".
(' 'x2).
- ''.$lt{'lifetime'}.': '.
- ' '.
- ''.$lt{'key'}.
- ': '.
- (' 'x2).
- ''.$lt{'secret'}.':'.
- ' '.
- ' '.&mt('Visible input').' '.
- ' '.
- ' ';
+ ''.$desc{'lifetime'}.': ';
+ if ($values{'key'} ne '') {
+ $datatable .= ''.$desc{'key'};
+ if ($noedit) {
+ $datatable .= ': ['.&mt('not shown').']';
+ } elsif ($switchserver) {
+ $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']';
+ } else {
+ $datatable .= ': ';
+ }
+ $datatable .= ' '.(' 'x2);
+ } elsif (!$switchserver) {
+ $datatable .= ''.$desc{'key'}.':'.
+ ' '.
+ ' '.(' 'x2);
+ }
+ if ($switchserver) {
+ if ($values{'usable'} ne '') {
+ $datatable .= '
'.
+ $desc{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).' '.
+ ''.&mt('Change secret?').
+ ' '.&mt('No').' '.
+ (' 'x2).
+ ' '.&mt('Yes').' '.(' 'x2).
+ '
'.
+ ' - '.$switchmessage.' '.
+ '';
+ } elsif ($values{'key'} eq '') {
+ $datatable .= ''.&mt('Key and Secret are required').' - '.$switchmessage.' '."\n";
+ } else {
+ $datatable .= ''.&mt('Secret required').' - '.$switchmessage.' '."\n";
+ }
+ $datatable .= ' ';
+ } else {
+ if ($values{'usable'} ne '') {
+ $datatable .= '
'.
+ $desc{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).' '.
+ ''.&mt('Change?').
+ ' '.&mt('No').' '.
+ (' 'x2).
+ ' '.&mt('Yes').
+ '
'.
+ ''.&mt('New Secret').':'.
+ ' '.
+ ' '.&mt('Visible input').' '.
+ ' ';
+ } else {
+ $datatable .=
+ ''.$desc{'secret'}.':'.
+ ' '.
+ ' '.&mt('Visible input').' '.
+ ' ';
+ }
+ }
+ $datatable .= ' '.
+ ''.$desc{'passback'}.'?'.
+ ' '.&mt('No').' '.
+ ' '.&mt('Yes').' '.
+ '
'.
+ ''.&mt('Grade format').
+ ' '.
+ &mt('Outcomes Service (1.1)').' '.(' 'x2).
+ ' '.
+ &mt('Outcomes Extension (1.0)').' '.
+ '
'.
+ ' '.
+ ''.$desc{'returnurl'}.'?'.
+ ' '.&mt('No').' '.
+ ' '.&mt('Yes').' '.
+ '
'.
+ ''.&mt('Parameter name').':'.
+ ' '.
+ ' ';
+ if ($ltiauth) {
+ $datatable .= (' 'x2).''.$desc{'requser'}.'?'.
+ ' '.&mt('No').' '.
+ ' '.&mt('Yes').' '.
+ ' '.
+ ''.$lt{'opti'}.' '.
+ &linkprot_options($i,$itemcount,$disabled,\%values,\%desc).
+ ' ';
+ }
+ $datatable .= '';
$itemcount ++;
}
}
@@ -5303,34 +7489,213 @@ sub print_linkprotection {
$css_class = $itemcount%2?' class="LC_odd_row"':'';
$datatable .= ''."\n".
' '."\n".
- ' '.&mt('Add').' '."\n".
- ''.
- ''.$lt{'name'}.
- ': '."\n".
+ ' '.&mt('Add').' '."\n".
+ '';
+ my ($usersty,$onclickrequser,%checkedrequser,$onclickreturnurl,%checkedreturnurl,
+ $onclickpassback,%checkedpassback,%checkedpassbackfmt);
+ if ($ltiauth) {
+ $usersty = 'display:none';
+ $onclickrequser = ' onclick="toggleLinkProtExtra(this.form,'."'requser','optional','1','block','add'".');"';
+ %checkedrequser = (
+ no => ' checked="checked"',
+ yes => '',
+ );
+ $datatable .= ''.$lt{'requ'}.' ';
+ }
+ $onclickpassback = ' onclick="toggleLinkProtExtra(this.form,'."'passback','passbackparam','1','inline-block','add'".');"';
+ %checkedpassback = (
+ 'no' => ' checked="checked"',
+ 'yes' => '',
+ );
+ %checkedpassbackfmt = (
+ '1p1' => ' checked="checked"',
+ '1p0' => '',
+ );
+ $onclickreturnurl = ' onclick="toggleLinkProtExtra(this.form,'."'returnurl','divurlparam','1','inline-block','add'".');"';
+ %checkedreturnurl = (
+ no => ' checked="checked"',
+ yes => '',
+ );
+ $datatable .= ''.$desc{'name'}.
+ ': '."\n".
(' 'x2).
- ''.$lt{'version'}.':'.
+ ''.$desc{'version'}.':'.
'1.1 '."\n".
(' 'x2).
- ''.$lt{'lifetime'}.': '."\n".
- ' '.
- ''.$lt{'key'}.': '."\n".
- (' 'x2).
- ''.$lt{'secret'}.': '.
- ' '.&mt('Visible input').' '."\n".
- ' ';
+ ''.$desc{'lifetime'}.': '."\n".
+ ' ';
+ if ($switchserver) {
+ $datatable .= ''.&mt('Key and Secret are required').' - '.$switchmessage.' '."\n";
+ } else {
+ $datatable .= ''.$desc{'key'}.': '."\n".
+ (' 'x2).
+ ''.$desc{'secret'}.': '.
+ ' '.&mt('Visible input').' '."\n";
+ }
+ $datatable .= ' '.
+ ''.$desc{'passback'}.'?'.
+ ' '.&mt('No').' '.
+ ' '.&mt('Yes').' '.
+ '
'.
+ ''.&mt('Grade format').
+ ' '.
+ &mt('Outcomes Service (1.1)').' '.(' 'x2).
+ ' '.
+ &mt('Outcomes Extension (1.0)').' '.
+ '
'.
+ ' '.
+ ''.$desc{'returnurl'}.'?'.
+ ' '.&mt('No').' '.
+ ' '.&mt('Yes').' '.
+ '
'.
+ ''.&mt('Parameter name').':'.
+ ' '.
+ ' ';
+ if ($ltiauth) {
+ $datatable .= (' 'x2).''.$desc{'requser'}.'?'.
+ ' '.&mt('No').' '.
+ ' '.&mt('Yes').' '.
+ ' '.
+ ''.$lt{'opti'}.' '.
+ &linkprot_options('add',$itemcount,$disabled,{},\%desc).
+ ' ';
+ }
+ $datatable .= '';
$$rowtotal ++;
- return $datatable;;
+ return $datatable;
}
sub linkprot_names {
- my %lt = &Apache::lonlocal::texthash(
+ return &Apache::lonlocal::texthash(
'version' => 'LTI Version',
'key' => 'Key',
'lifetime' => 'Nonce lifetime (s)',
- 'name' => 'Launcher Application Name',
+ 'name' => 'Launcher Application',
'secret' => 'Secret',
+ 'passback' => 'Can return grades to Launcher',
+ 'returnurl' => 'Launcher return URL',
+ 'requser' => 'Use identity',
+ 'email' => 'Email address',
+ 'sourcedid' => 'User ID',
+ 'other' => 'Other',
+ 'auth' => 'Display LON-CAPA login page',
+ 'reject' => 'Discontinue launch process',
);
- return %lt;
+}
+
+sub check_switchserver {
+ my ($cdom,$cnum,$context,$dest) = @_;
+ my ($allowed,$switchserver,$home);
+ if ($context eq 'domain') {
+ $home = &Apache::lonnet::domain($cdom,'primary');
+ } else {
+ $home = &Apache::lonnet::homeserver($cnum,$cdom);
+ }
+ unless (($home eq 'no_host') || ($home eq '')) {
+ my @ids=&Apache::lonnet::current_machine_ids();
+ foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
+ if (!$allowed) {
+ $switchserver=''.&mt('Switch Server').' ';
+ }
+ }
+ return $switchserver;
+}
+
+sub linkprot_options {
+ my ($num,$itemcount,$disabled,$current,$desc) = @_;
+ my %lt;
+ if (ref($desc) eq 'HASH') {
+ %lt = %{$desc};
+ }
+ my $userfieldsty = 'none';
+ my (%checked,$userfield);
+ $checked{'sourcedid'} = ' checked="checked"';
+ $checked{'reject'} = ' checked="checked"';
+ if (ref($current) eq 'HASH') {
+ if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) {
+ $checked{'sourcedid'} = '';
+ if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') {
+ $checked{'email'} = ' checked="checked"';
+ } else {
+ $checked{'other'} = ' checked="checked"';
+ $userfield = $current->{'mapuser'};
+ $userfieldsty = 'inline-block';
+ }
+ }
+ if (($current->{'notstudent'} ne '') && ($current->{'notstudent'} ne 'reject')) {
+ $checked{'reject'} = '';
+ $checked{'auth'} = ' checked="checked"';
+ }
+ }
+ my $onclickuser = ' onclick="toggleLinkProtExtra(this.form,'."'mapuser','userfield','other','inline-block','$num'".');"';
+ my $output = ''.
+ &mt('Source of LON-CAPA username in LTI request').': ';
+ foreach my $option ('sourcedid','email','other') {
+ $output .= ' '.$lt{$option}.' '.
+ ($option eq 'other' ? '' : (' 'x2) );
+ }
+ $output .= '
'.
+ ''.
+ '
';
+ $output .= ' '.
+ ''.
+ &mt('Action when username is not for an enrolled student').': ';
+ foreach my $option ('reject','auth') {
+ $output .= ' '.$lt{$option}.' '.
+ ($option eq 'auth' ? '' : (' 'x2) );
+ }
+ $output .= '
';
+ return $output;
+}
+
+sub print_extresource_row {
+ my ($item,$config,$curr,$noedit) = @_;
+ my $onchange;
+ unless ($noedit) {
+ $onchange = ' onchange="javascript:toggleExtRes();"';
+ }
+ my $id = 'LC_'.$item;
+ my ($selected,$reuse,$width,$height) = split(/:/,$curr);
+ my $output = &select_from_options($item,$config->{'order'},
+ $config->{'options'},$selected,
+ $config->{'nullval'},
+ undef,undef,$onchange,$noedit,$id);
+ my ($checked,$reusesty,$sizesty);
+ if ($reuse) {
+ $checked = ' checked="checked"';
+ }
+ $reusesty = 'none';
+ $sizesty = 'none';
+ if (($selected eq 'window') || ($selected eq 'tab')) {
+ $reusesty = 'inline-block';
+ if ($selected eq 'window') {
+ $sizesty = 'inline-block';
+ }
+ }
+ $output .= ''.
+ ''.
+ ' '.
+ &mt('Re-use tab/window').' '.
+ '
'.
+ ''.
+ ''.&mt('Window size (optional)').' '.
+ ''.
+ &mt('width').': px'.
+ (' ' x 3).
+ &mt('height').': px'.
+ ' ';
+ return $output;
}
sub print_other {
@@ -5504,10 +7869,16 @@ sub make_item_rows {
(($caller eq 'printouts') && ($item ne 'print_header_format'))) {
$colspan = 2;
}
+ my $rowdesc;
+ if ($caller eq 'appearance') {
+ $rowdesc = ''.$items->{$item}{text}.' ';
+ } else {
+ $rowdesc = $items->{$item}{text};
+ }
if (exists $items->{$item}{advanced} && $items->{$item}{advanced} == 1) {
- $datatable .= &item_table_row_start($items->{$item}{text},$count,"advanced",$colspan);
+ $datatable .= &item_table_row_start($rowdesc,$count,"advanced",$colspan);
} else {
- $datatable .= &item_table_row_start($items->{$item}{text},$count,undef,$colspan);
+ $datatable .= &item_table_row_start($rowdesc,$count,undef,$colspan);
}
if ($item eq 'defaultcredits') {
my $defaultcredits = $env{'course.'.$env{'request.course.id'}.'.internal.defaultcredits'};
@@ -5526,6 +7897,8 @@ sub make_item_rows {
$datatable .= &print_hdrfmt_row($item,$settings,$noedit);
} elsif ($item eq 'lti.lcmenu') {
$datatable .= &lcmenu_checkboxes($cdom,$item,$settings,$crstype,$noedit);
+ } elsif ($item eq 'extresource') {
+ $datatable .= &print_extresource_row($item,$items->{$item},$settings->{$item},$noedit);
} elsif ($items->{$item}{input} eq 'dates') {
my $disabled;
if ($noedit) {
@@ -5536,7 +7909,7 @@ sub make_item_rows {
$settings->{$item},$disabled);
} elsif ($items->{$item}{input} eq 'radio') {
my ($unsetdefault,$valueyes,$valueno);
- if (($item eq 'usejsme') || ($item eq 'uselcmath')) {
+ if (($item eq 'usejsme') || ($item eq 'uselcmath') || ($item eq 'inline_chem')) {
my %domdefs = &Apache::lonnet::get_domain_defaults($cdom);
unless ($domdefs{$item} eq '0') {
$unsetdefault = 1;
@@ -5592,7 +7965,7 @@ sub nothidepriv_row {
}
}
if ($settings->{'checkforpriv'}) {
- @checkdoms = split(/,/,$settings->{'checkforpriv'});
+ @checkdoms = split(/,/,$settings->{'checkforpriv'});
}
}
push(@checkdoms,$cdom);
@@ -5606,7 +7979,7 @@ sub nothidepriv_row {
if ($end == -1 || $start == -1) {
next;
}
- foreach my $dom (@checkdoms) {
+ foreach my $dom (@checkdoms) {
if (&Apache::lonnet::privileged($uname,$udom,\@checkdoms,['dc','su'])) {
unless (grep(/^\Q$user\E$/,@privusers)) {
push(@privusers,$user);
@@ -5682,7 +8055,7 @@ sub checkforpriv_row {
my $domdesc = &Apache::lonnet::domain($currdom,'description');
if ($domdesc eq '') {
$domdesc = $currdom;
- }
+ }
$datatable .=
&Apache::loncommon::start_data_table_row().
''.
@@ -5694,13 +8067,13 @@ sub checkforpriv_row {
&mt('Delete').' '.
&Apache::loncommon::end_data_table_row();
$num ++;
- unless (grep(/^\Q$currdom\E$/,@excdoms)) {
+ unless (grep(/^\Q$currdom\E$/,@excdoms)) {
push(@excdoms,$currdom);
}
}
}
if ((scalar(keys(%domains)) - scalar(@excdoms)) > 0) {
- $datatable .=
+ $datatable .=
&Apache::loncommon::start_data_table_row().
''.
&mt('Additional domain:'). ' '.
@@ -5814,7 +8187,7 @@ ENDJS
}
}
my $pos = $currnum+1;
- unless ($noedit) {
+ unless ($noedit) {
$output .=
''.
''.
@@ -5952,6 +8325,30 @@ sub change_clone {
}
}
}
+ return;
+}
+
+sub devalidate_remote_courseprefs {
+ my ($cdom,$cnum,$cachekeys) = @_;
+ return unless (ref($cachekeys) eq 'HASH');
+ my %servers = &Apache::lonnet::internet_dom_servers($cdom);
+ my %thismachine;
+ map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
+ my @posscached = ('courselti','courseltitools');
+ if (keys(%servers)) {
+ foreach my $server (keys(%servers)) {
+ next if ($thismachine{$server});
+ my @cached;
+ foreach my $name (@posscached) {
+ if ($cachekeys->{$name}) {
+ push(@cached,&escape($name).':'.&escape($cdom.'_'.$cnum));
+ }
+ }
+ if (@cached) {
+ &Apache::lonnet::remote_devalidate_cache($server,\@cached);
+ }
+ }
+ }
return;
}