[LON-CAPA-cvs] cvs: loncom /auth lonacc.pm publiccheck.pm /interface lonhtmlcommon.pm portfolio.pm /lonnet/perl lonnet.pm
raeburn
lon-capa-cvs@mail.lon-capa.org
Fri, 16 Jun 2006 22:37:35 -0000
This is a MIME encoded message
--raeburn1150497455
Content-Type: text/plain
raeburn Fri Jun 16 18:37:35 2006 EDT
Modified files:
/loncom/interface portfolio.pm lonhtmlcommon.pm
/loncom/auth lonacc.pm publiccheck.pm
/loncom/lonnet/perl lonnet.pm
Log:
Enable users to set access controls on portfolio files to permit public viewing. Third iteration of data structure in file_permissions.db for storage of access contol records. Now uses key = value for individual access control records and a key = anonymous hash for fast look-ups of all records for a single file. Use of a temporary lock record to prevent others modifying access control records for a specific portfolio file while the record for the same file is being updated. Additional argument added to call to lonhtmlcommon::datesetter() to optionally suppress display of calendar link.
--raeburn1150497455
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20060616183735.txt"
Index: loncom/interface/portfolio.pm
diff -u loncom/interface/portfolio.pm:1.103 loncom/interface/portfolio.pm:1.104
--- loncom/interface/portfolio.pm:1.103 Wed Jun 7 17:15:01 2006
+++ loncom/interface/portfolio.pm Fri Jun 16 18:37:10 2006
@@ -211,17 +211,16 @@
my $curr_access;
my $pub_access = 0;
foreach my $key (sort(keys(%{$access_controls{$fullpath}}))) {
- my ($scope,$end,$start) = ($key =~ /^\d+:(\w+)_(\d*)_?(\d*)$/);
+ my ($scope,$end,$start) = ($key =~ /^[^:]+:([a-z]+)_(\d*)_?(\d*)$/);
if (($now > $start) && (!$end || $end > $now)) {
if ($scope eq 'public') {
$pub_access = 1;
- last;
}
}
}
if (!$pub_access) {
$curr_access = 'Private'
- } elsif ($pub_access) {
+ } else {
$curr_access = 'Public';
}
$r->print('<td><img src="'.&Apache::loncommon::icon($filename).'"></td>');
@@ -442,8 +441,213 @@
$r->print(&done(undef,$url,$group));
}
+sub display_access {
+ my ($r,$url,$group) = @_;
+ my ($uname,$udom) = &get_name_dom($group);
+ my $file_name = $env{'form.currentpath'}.$env{'form.access'};
+ $file_name = &prepend_group($file_name,$group);
+ my $current_permissions = &Apache::lonnet::get_portfile_permissions($udom,
+ $uname);
+ my %access_controls = &Apache::lonnet::get_access_controls($current_permissions,$group,$file_name);
+ &open_form($r,$url);
+ $r->print('<h3>'.&mt('Allowing others to retrieve portfolio file: [_1]',$env{'form.currentpath'}.$env{'form.access'}).'</h3>'."\n");
+ $r->print(&mt('Access to this file by others can be set to be one the following types: public.').'<br /><ul><li>'.&mt('Public files are available to anyone without the need for login.').'</li></ul><br />');
+ &access_setting_table($r,$access_controls{$file_name});
+ &close_form($r,$url,$group);
+}
+
+sub update_access {
+ my ($r,$url,$group) = @_;
+ my $totalprocessed = 0;
+ my %processing;
+ my %title = (
+ 'activate' => 'New controls added',
+ 'delete' => 'Existing controls deleted',
+ 'update' => 'Existing controls modified',
+ );
+ my $changes;
+ foreach my $chg (sort(keys(%title))) {
+ @{$processing{$chg}} = &Apache::loncommon::get_env_multiple('form.'.$chg);
+ $totalprocessed += @{$processing{$chg}};
+ foreach my $num (@{$processing{$chg}}) {
+ my $scope = $env{'form.scope_'.$num};
+ my ($start,$end) = &get_dates_from_form($num);
+ my $newkey = $num.':'.$scope.'_'.$end.'_'.$start;
+ if ($chg eq 'delete') {
+ $$changes{$chg}{$newkey} = 1;
+ } else {
+ $$changes{$chg}{$newkey} =
+ &build_access_record($num,$scope,$start,$end);
+ }
+ }
+ }
+ my $file_name = $env{'form.currentpath'}.$env{'form.selectfile'};
+ $r->print('<h3>'.&mt('Allowing others to retrieve portfolio file: [_1]',$file_name).'</h3>'."\n");
+ $file_name = &prepend_group($file_name,$group);
+ my ($uname,$udom) = &get_name_dom($group);
+ my ($errors,$outcome,$deloutcome,$new_values,$translation);
+ if ($totalprocessed) {
+ ($outcome,$deloutcome,$new_values,$translation) =
+ &Apache::lonnet::modify_access_controls($file_name,$changes,$udom,$uname);
+ }
+ my $current_permissions = &Apache::lonnet::get_portfile_permissions($udom, $uname);
+ my %access_controls = &Apache::lonnet::get_access_controls($current_permissions,$group,$file_name);
+ if ($totalprocessed) {
+ if ($outcome eq 'ok') {
+ my $updated_controls = $access_controls{$file_name};
+ my ($showstart,$showend);
+ $r->print(&Apache::loncommon::start_data_table());
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print('<th>'.&mt('Type of change').'</th><th>'.&mt('Access control').'</th><th>'.&mt('Start date').'</th><th>'.&mt('End date').'</th>');
+ $r->print(&Apache::loncommon::end_data_table_row());
+ foreach my $chg (sort(keys(%processing))) {
+ if (@{$processing{$chg}} > 0) {
+ if ($chg eq 'delete') {
+ if (!($deloutcome eq 'ok')) {
+ $errors .= &mt('A problem occurred deleting access controls: [_1]',$deloutcome);
+ next;
+ }
+ }
+ my $numchgs = @{$processing{$chg}};
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print('<td rowspan="'.$numchgs.'">'.&mt($title{$chg}).'.</td>');
+ my $count = 0;
+ foreach my $key (sort(keys(%{$$changes{$chg}}))) {
+ if ($count) {
+ $r->print(&Apache::loncommon::start_data_table_row());
+ }
+ my ($num,$scope,$end,$start) =
+ ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+ my $newkey = $key;
+ if ($chg eq 'activate') {
+ $newkey =~ s/^(\d+)/$$translation{$1}/;
+ }
+ my %content = &Apache::lonnet::parse_access_controls(
+ $$updated_controls{$newkey});
+ if ($chg eq 'delete') {
+ $showstart = &mt('Deleted');
+ $showend = $showstart;
+ } else {
+ $showstart = localtime($start);
+ if ($end == 0) {
+ $showend = &mt('No end date');
+ } else {
+ $showend = localtime($end);
+ }
+ }
+ $r->print('<td>'.&mt($scope).'</td><td>'.$showstart.
+ '</td><td>'. $showend.'</td>');
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $count ++;
+ }
+ }
+ }
+ $r->print(&Apache::loncommon::end_data_table());
+ } else {
+ if ((@{$processing{'activate'}} > 0) || (@{$processing{'update'}} > 0)) {
+ $errors .= &mt('A problem occurred storing access control settings: [_1]',$outcome);
+ }
+ }
+ if ($errors) {
+ $r->print($errors);
+ }
+ }
+ $r->print('<br /><a href="'.$url.'?access='.$env{'form.selectfile'}.'¤tpath='.$env{'form.currentpath'}.'">'.&mt('Display all access settings for this file').'</a>');
+ return;
+}
+
+sub build_access_record {
+ my ($num,$scope,$start,$end) = @_;
+ my $record = '<scope type="'.$scope.'"><start>'.$start.'</start><end>'.$end.
+ '</end></scope>';
+ return $record;
+}
+
+sub get_dates_from_form {
+ my ($id) = @_;
+ my $startdate;
+ my $enddate;
+ $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate_'.$id);
+ $enddate = &Apache::lonhtmlcommon::get_date_from_form('enddate_'.$id);
+ if ( exists ($env{'form.noend_'.$id}) ) {
+ $enddate = 0;
+ }
+ return ($startdate,$enddate);
+}
+
+sub access_setting_table {
+ my ($r,$access_controls) = @_;
+ my ($public,$publictext);
+ $publictext = '<b>'.&mt('Off').'</b>';
+ my ($guest,$guesttext);
+ $guesttext = '<b>'.&mt('Off').'</b>';
+ my @courses = ();
+ my @groups = ();
+ my @domains = ();
+ my @users = ();
+ my $now = time;
+ my $then = $now + (60*60*24*180); # six months approx.
+ foreach my $key (sort(keys(%{$access_controls}))) {
+ my ($scope) = ($key =~ /^[^:]+:([a-z]+)_\d*_?\d*$/);
+ if ($scope eq 'public') {
+ $public = $key;
+ $publictext = '<b>'.&mt('On').'</b>';
+ }
+ }
+ $r->print(&Apache::loncommon::start_data_table());
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print('<th>'.&mt('Access Type').'</th><th colspan="3">'.
+ &mt('Settings').'</th>'."\n");
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $r->print(&Apache::loncommon::start_data_table_row());
+ $r->print('<td><b>Public</b><br />'.$publictext.'</td><td colspan="3">');
+ $r->print(&Apache::loncommon::start_data_table());
+ $r->print(&Apache::loncommon::start_data_table_row());
+ my ($pub_startdate,$pub_enddate,$pub_action,$pub_noend);
+ if ($public) {
+ my ($num,$end,$start) = ($public =~ /^([^:]+):[a-z]+_(\d*)_?(\d*)$/);
+ if ($end == 0) {
+ $pub_noend = 'checked="checked"';
+ }
+ $pub_action = '<td><input type="checkbox" name="delete" value="'.$num.
+ '" />'.&mt('Delete').'<br /><input type="checkbox" '.
+ 'name="update" value="'.$num.'" />'.&mt('Update').
+ '<input type="hidden" name="scope_'.$num.'"'.
+ ' value="public" /></td>';
+ $pub_startdate = &Apache::lonhtmlcommon::date_setter('portform',
+ 'startdate_'.$num,$start,undef,undef,undef,1,undef,
+ undef,undef,1);
+ $pub_enddate = &Apache::lonhtmlcommon::date_setter('portform',
+ 'enddate_'.$num,$end,undef,undef,undef,1,undef,
+ undef,undef,1).
+ ' <nobr><input type="checkbox" name="noend_'.
+ $num.'" '.$pub_noend.' />'.&mt('No end date').'</nobr>';
+ } else {
+ $pub_action = '<input type="checkbox" name="activate" value="0" />'.
+ &mt('Activate').
+ '<input type="hidden" name="scope_0" value="public" />';
+ $pub_startdate = &Apache::lonhtmlcommon::date_setter('portform',
+ 'startdate_0',$now,undef,undef,undef,1,undef,
+ undef,undef,1);
+ $pub_enddate = &Apache::lonhtmlcommon::date_setter('portform',
+ 'enddate_0',$then,,undef,undef,undef,1,undef,
+ undef,undef,1).
+ '  <nobr><input type="checkbox" '.
+ 'name="noend_0" />'.&mt('No end date').
+ '</nobr>';
+
+ }
+ $r->print('<td>'.$pub_action.'</td><td>'.&mt('Start: ').$pub_startdate.
+ '<br />'.&mt('End: ').$pub_enddate.'</td>');
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $r->print(&Apache::loncommon::end_data_table());
+ $r->print('</td>');
+ $r->print(&Apache::loncommon::end_data_table_row());
+ $r->print(&Apache::loncommon::end_data_table());
+}
+
sub select_files {
- my ($r,$group)=@_;
+ my ($r,$group) = @_;
if ($env{'form.continue'} eq 'true') {
# here we update the selections for the currentpath
# eventually, have to handle removing those not checked, but . . .
@@ -771,6 +975,12 @@
$env{'form.selectfile'} = $env{'form.rename'};
$env{'form.action'} = 'rename';
&rename($r,$url,$group);
+ } elsif ($env{'form.access'}) {
+ $env{'form.selectfile'} = $env{'form.access'};
+ $env{'form.action'} = 'chgaccess';
+ &display_access($r,$url,$group);
+ } elsif ($env{'form.action'} eq 'chgaccess') {
+ &update_access($r,$url,$group);
} elsif ($env{'form.createdir'}) {
&createdir($r,$url,$group);
} elsif ($env{'form.lockinfo'}) {
Index: loncom/interface/lonhtmlcommon.pm
diff -u loncom/interface/lonhtmlcommon.pm:1.133 loncom/interface/lonhtmlcommon.pm:1.134
--- loncom/interface/lonhtmlcommon.pm:1.133 Wed Jun 14 14:34:46 2006
+++ loncom/interface/lonhtmlcommon.pm Fri Jun 16 18:37:10 2006
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common html routines
#
-# $Id: lonhtmlcommon.pm,v 1.133 2006/06/14 18:34:46 albertel Exp $
+# $Id: lonhtmlcommon.pm,v 1.134 2006/06/16 22:37:10 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -288,7 +288,7 @@
##############################################
sub date_setter {
my ($formname,$dname,$currentvalue,$special,$includeempty,$state,
- $no_hh_mm_ss,$defhour,$defmin,$defsec) = @_;
+ $no_hh_mm_ss,$defhour,$defmin,$defsec,$nolink) = @_;
my $wasdefined=1;
if (! defined($state) || $state ne 'disabled') {
$state = '';
@@ -436,17 +436,24 @@
$hourselector .= " </select>\n";
my $minuteselector = qq{<input type="text" name="$dname\_minute" $special $state value="$min" size="3" />};
my $secondselector= qq{<input type="text" name="$dname\_second" $special $state value="$sec" size="3" />};
- my $cal_link = qq{<a href="javascript:$dname\_opencalendar()">};
+ my $cal_link;
+ if (!$nolink) {
+ $cal_link = qq{<a href="javascript:$dname\_opencalendar()">};
+ }
#
if ($no_hh_mm_ss) {
- $result .= &mt('[_1] [_2] [_3] [_4]Select Date[_5]',
- $monthselector,$dayselector,$yearselector,
- $cal_link,'</a>');
+ $result .= &mt('[_1] [_2] [_3] ',
+ $monthselector,$dayselector,$yearselector);
+ if (!$nolink) {
+ $result .= &mt('[_4]Select Date[_5]',$cal_link,'</a>');
+ }
} else {
- $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s [_7]Select Date[_8]',
- $monthselector,$dayselector,$yearselector,
- $hourselector,$minuteselector,$secondselector,
- $cal_link,'</a>');
+ $result .= &mt('[_1] [_2] [_3] [_4] [_5]m [_6]s ',
+ $monthselector,$dayselector,$yearselector,
+ $hourselector,$minuteselector,$secondselector);
+ if (!$nolink) {
+ $result .= &mt('[_7]Select Date[_8]',$cal_link,'</a>');
+ }
}
$result .= "</nobr>\n<!-- end $dname date setting form -->\n";
return $result;
Index: loncom/auth/lonacc.pm
diff -u loncom/auth/lonacc.pm:1.78 loncom/auth/lonacc.pm:1.79
--- loncom/auth/lonacc.pm:1.78 Fri Jun 2 15:38:21 2006
+++ loncom/auth/lonacc.pm Fri Jun 16 18:37:29 2006
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Cookie Based Access Handler
#
-# $Id: lonacc.pm,v 1.78 2006/06/02 19:38:21 albertel Exp $
+# $Id: lonacc.pm,v 1.79 2006/06/16 22:37:29 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -135,6 +135,34 @@
$r->headers_in->unset('Content-length');
}
+sub portfolio_access {
+ my ($udom,$unum,$file_name,$group) = @_;
+ my $current_perms = &Apache::lonnet::get_portfile_permissions($udom,$unum);
+ my %access_controls = &Apache::lonnet::get_access_controls(
+ $current_perms,$group,$file_name);
+ my ($public);
+ my $now = time;
+ my $access_hash = $access_controls{$file_name};
+ if (ref($access_hash) eq 'HASH') {
+ foreach my $key (keys(%{$access_hash})) {
+ my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+ if ($start > $now) {
+ next;
+ }
+ if ($end && $end<$now) {
+ next;
+ }
+ if ($scope eq 'public') {
+ $public = $key;
+ last;
+ }
+ }
+ if ($public) {
+ return 'ok';
+ }
+ }
+ return;
+}
sub handler {
my $r = shift;
@@ -197,7 +225,18 @@
&Apache::lonacc::get_posted_cgi($r);
# ---------------------------------------------------------------- Check access
-
+ my $now = time;
+ if ($requrl =~ m#/+uploaded/([^/]+)/([^/]+)/portfolio(/.+)$#) {
+ my $result = &portfolio_access($1,$2,$3);
+ if ($result eq 'ok') {
+ return OK;
+ }
+ } elsif ($requrl =~ m#/+uploaded/([^/]+)/([^/]+)/groups/([^/]+)/portfolio/(.+)$#) {
+ my $result = &portfolio_access($1,$2,$4.'/'.$3,$3);
+ if ($result eq 'ok') {
+ return OK;
+ }
+ }
if ($requrl!~/^\/adm|public|prtspool\//) {
my $access=&Apache::lonnet::allowed('bre',$requrl);
if ($access eq '1') {
@@ -310,6 +349,18 @@
if ($requrl=~m|^/+adm/+help/+|) {
return OK;
}
+# ------------------------------------- See if this is a viewable portfolio file
+ if ($requrl =~ m#/+uploaded/([^/]+)/([^/]+)/portfolio(/.+)$#) {
+ my $result = &portfolio_access($1,$2,$3);
+ if ($result eq 'ok') {
+ return OK;
+ }
+ } elsif ($requrl =~ m#/+uploaded/([^/]+)/([^/]+)/groups/([^/]+)/portfolio/(.+)$#) {
+ my $result = &portfolio_access($1,$2,$4.'/'.$3,$3);
+ if ($result eq 'ok') {
+ return OK;
+ }
+ }
# -------------------------------------------------------------- Not authorized
$requrl=~/\.(\w+)$/;
# if ((&Apache::loncommon::fileembstyle($1) eq 'ssi') ||
Index: loncom/auth/publiccheck.pm
diff -u loncom/auth/publiccheck.pm:1.2 loncom/auth/publiccheck.pm:1.3
--- loncom/auth/publiccheck.pm:1.2 Thu Apr 13 15:07:33 2006
+++ loncom/auth/publiccheck.pm Fri Jun 16 18:37:29 2006
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Cookie Based Access Handler
#
-# $Id: publiccheck.pm,v 1.2 2006/04/13 19:07:33 albertel Exp $
+# $Id: publiccheck.pm,v 1.3 2006/06/16 22:37:29 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -57,24 +57,60 @@
}
if ($requrl=~m|^/public/|
|| (&Apache::lonnet::metadata($requrl,'copyright') eq 'public')) {
- &Apache::lonnet::logthis('Granting public access: '.$requrl);
- if ($env{'user.name'} ne 'public'
- && $env{'user.domain'} ne 'public') {
- my $cookie=
- &Apache::lonauth::success($r,'public','public','public');
- my $lonidsdir=$r->dir_config('lonIDsDir');
- &Apache::lonnet::transfer_profile_to_env($lonidsdir,$cookie);
- $r->header_out('Set-cookie',"lonID=$cookie; path=/");
- }
- &Apache::lonacc::get_posted_cgi($r);
- $env{'request.state'} = "published";
- $env{'request.publicaccess'} = 1;
- $env{'request.filename'} = $r->filename;
+ &process_public($r,$requrl);
return OK;
+ } elsif ($requrl =~ m#/+uploaded/([^/]+)/([^/]+)/portfolio(/.+)$#) {
+ if (&process_portfolio($1,$2,$3)) {
+ &process_public($r,$requrl);
+ return OK;
+ }
+ } elsif ($requrl =~ m#/+uploaded/([^/]+)/([^/]+)/groups/([^/]+)/portfolio/(.+)$#) {
+ if (&process_portfolio($1,$2,$3.'/'.$4,$3)) {
+ &process_public($r,$requrl);
+ return OK;
+ }
}
return DECLINED;
}
+sub process_public {
+ my ($r,$requrl) = @_;
+ &Apache::lonnet::logthis('Granting public access: '.$requrl);
+ if ($env{'user.name'} ne 'public' && $env{'user.domain'} ne 'public') {
+ my $cookie=&Apache::lonauth::success($r,'public','public','public');
+ my $lonidsdir=$r->dir_config('lonIDsDir');
+ &Apache::lonnet::transfer_profile_to_env($lonidsdir,$cookie);
+ $r->header_out('Set-cookie',"lonID=$cookie; path=/");
+ }
+ &Apache::lonacc::get_posted_cgi($r);
+ $env{'request.state'} = "published";
+ $env{'request.publicaccess'} = 1;
+ $env{'request.filename'} = $r->filename;
+ return;
+}
+
+sub process_portfolio {
+ my ($udom,$unum,$file_name,$group) = @_;
+ my $current_perms = &Apache::lonnet::get_portfile_permissions($udom,$unum);
+ my %access_controls = &Apache::lonnet::get_access_controls($current_perms,$group,$file_name);
+ my $public_access = 0;
+ my $now = time;
+ foreach my $key (keys(%{$access_controls{$file_name}})) {
+ my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+ if ($start > $now) {
+ next;
+ }
+ if ($end && $end<$now) {
+ next;
+ }
+ if ($scope eq 'public') {
+ $public_access = 1;
+ last;
+ }
+ }
+ return $public_access;
+}
+
1;
__END__
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.748 loncom/lonnet/perl/lonnet.pm:1.749
--- loncom/lonnet/perl/lonnet.pm:1.748 Thu Jun 8 16:53:34 2006
+++ loncom/lonnet/perl/lonnet.pm Fri Jun 16 18:37:35 2006
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.748 2006/06/08 20:53:34 albertel Exp $
+# $Id: lonnet.pm,v 1.749 2006/06/16 22:37:35 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -4664,31 +4664,140 @@
#---------------------------------------------Get portfolio file access controls
-sub get_access_controls {
+sub get_access_controls {
my ($current_permissions,$group,$file) = @_;
- my @access_checks = ();
my %access;
if (defined($file)) {
- @access_checks = ($file);
+ if (ref($$current_permissions{$file."\0".'accesscontrol'}) eq 'HASH') {
+ foreach my $control (keys(%{$$current_permissions{$file."\0".'accesscontrol'}})) {
+ $access{$file}{$control} = $$current_permissions{$file."\0".$control};
+ }
+ }
} else {
- @access_checks = keys(%{$current_permissions});
+ foreach my $key (keys(%{$current_permissions})) {
+ if ($key =~ /\0accesscontrol$/) {
+ if (defined($group)) {
+ if ($key !~ m-^\Q$group\E/-) {
+ next;
+ }
+ }
+ my ($fullpath) = split(/\0/,$key);
+ if (ref($$current_permissions{$key}) eq 'HASH') {
+ foreach my $control (keys(%{$$current_permissions{$key}})) {
+ $access{$fullpath}{$control}=$$current_permissions{$fullpath."\0".$control};
+ }
+ }
+ }
+ }
}
- foreach my $file_name (@access_checks) {
- my $value = $$current_permissions{$file_name};
- if (defined($group)) {
- if ($file_name !~ m-^\Q$group\E/-) {
- next;
+ return %access;
+}
+
+sub parse_access_controls {
+ my ($access_item) = @_;
+ my %content;
+ my $token;
+ my $parser=HTML::TokeParser->new(\$access_item);
+ while ($token=$parser->get_token) {
+ if ($token->[0] eq 'S') {
+ my $entry=$token->[1];
+ if ($entry eq 'scope') {
+ my $type = $token->[2]{'type'};
+ } else {
+ my $value=$parser->get_text('/'.$entry);
+ $content{$entry}=$value;
}
}
- if (ref($value) eq "ARRAY") {
- foreach my $stored_what (@{$value}) {
- if (ref($stored_what) eq 'HASH') {
- $access{$file_name} = $$stored_what{'access'};
+ }
+ return %content;
+}
+
+sub modify_access_controls {
+ my ($file_name,$changes,$domain,$user)=@_;
+ my ($outcome,$deloutcome);
+ my %store_permissions;
+ my %new_values;
+ my %new_control;
+ my %translation;
+ my @deletions = ();
+ my $now = time;
+ if (exists($$changes{'activate'})) {
+ if (ref($$changes{'activate'}) eq 'HASH') {
+ my @newitems = sort(keys(%{$$changes{'activate'}}));
+ my $numnew = scalar(@newitems);
+ for (my $i=0; $i<$numnew; $i++) {
+ my $newkey = $newitems[$i];
+ my $newid = &Apache::loncommon::get_cgi_id();
+ $newkey =~ s/^(\d+)/$newid/;
+ $translation{$1} = $newid;
+ $new_values{$file_name."\0".$newkey} =
+ $$changes{'activate'}{$newitems[$i]};
+ $new_control{$newkey} = $now;
+ }
+ }
+ }
+ my %todelete;
+ my %changed_items;
+ foreach my $action ('delete','update') {
+ if (exists($$changes{$action})) {
+ if (ref($$changes{$action}) eq 'HASH') {
+ foreach my $key (keys(%{$$changes{$action}})) {
+ my ($itemnum) = ($key =~ /^([^:]+):/);
+ if ($action eq 'delete') {
+ $todelete{$itemnum} = 1;
+ } else {
+ $changed_items{$itemnum} = $key;
+ }
}
}
}
}
- return %access;
+ # get lock on access controls for file.
+ my $lockhash = {
+ $file_name."\0".'locked_access_records' => $env{'user.name'}.
+ ':'.$env{'user.domain'},
+ };
+ my $tries = 0;
+ my $gotlock = &newput('file_permissions',$lockhash,$domain,$user);
+
+ while (($gotlock ne 'ok') && $tries <3) {
+ $tries ++;
+ sleep 1;
+ $gotlock = &newput('file_permissions',$lockhash,$domain,$user);
+ }
+ if ($gotlock eq 'ok') {
+ my %curr_permissions = &dump('file_permissions',$domain,$user,$file_name);
+ my ($tmp)=keys(%curr_permissions);
+ if ($tmp=~/^error:/) { undef(%curr_permissions); }
+ if (exists($curr_permissions{$file_name."\0".'accesscontrol'})) {
+ my $curr_controls = $curr_permissions{$file_name."\0".'accesscontrol'};
+ if (ref($curr_controls) eq 'HASH') {
+ foreach my $control_item (keys(%{$curr_controls})) {
+ my ($itemnum) = ($control_item =~ /^([^:]+):/);
+ if (defined($todelete{$itemnum})) {
+ push(@deletions,$file_name."\0".$control_item);
+ } else {
+ if (defined($changed_items{$itemnum})) {
+ $new_control{$changed_items{$itemnum}} = $now;
+ push(@deletions,$file_name."\0".$control_item);
+ $new_values{$file_name."\0".$changed_items{$itemnum}} = $$changes{'update'}{$changed_items{$itemnum}};
+ } else {
+ $new_control{$control_item} = $$curr_controls{$control_item};
+ }
+ }
+ }
+ }
+ }
+ $deloutcome = &del('file_permissions',\@deletions,$domain,$user);
+ $new_values{$file_name."\0".'accesscontrol'} = \%new_control;
+ $outcome = &put('file_permissions',\%new_values,$domain,$user);
+ # remove lock
+ my @del_lock = ($file_name."\0".'locked_access_records');
+ my $dellockoutcome = &del('file_permissions',\@del_lock,$domain,$user);
+ } else {
+ $outcome = "error: could not obtain lockfile\n";
+ }
+ return ($outcome,$deloutcome,\%new_values,\%translation);
}
#------------------------------------------------------Get Marked as Read Only
@@ -4708,9 +4817,7 @@
if (ref($value) eq "ARRAY"){
foreach my $stored_what (@{$value}) {
my $cmp2=$stored_what;
- if (ref($stored_what eq 'HASH')) {
- next;
- } elsif (ref($stored_what eq 'ARRAY')) {
+ if (ref($stored_what eq 'ARRAY')) {
$cmp2=join('',@{$stored_what});
}
if ($cmp1 eq $cmp2) {
@@ -4770,9 +4877,7 @@
if (ref($current_locks) eq "ARRAY"){
foreach my $locker (@{$current_locks}) {
my $compare=$locker;
- if (!ref($locker) eq 'ARRAY') {
- push(@new_locks,$locker);
- } else {
+ if (ref($locker) eq 'ARRAY') {
$compare=join('',@{$locker});
if ($compare ne $symb_crs) {
push(@new_locks, $locker);
@@ -7844,24 +7949,82 @@
file: (optional) the file you want access info on
Returns:
- a hash containing
- keys of 'control type' (possiblities?)
- values are XML contianing settings
+ a hash (keys are file names) of hashes containing
+ keys are: path to file/file_name\0uniqueID:scope_end_start (see below)
+ values are XML containing access control settings (see below)
Internal notes:
- access controls are stored in file_permissions.db as array of arrays and a hash.
- array refs -> are locks
- hash refs -> all other types of controls
- and will contain keys
-
- 'access' -> hash where keys are access controls and
- values are settings (in XML)
-
- 'accesscount' -> scalar - equal to the next number to
- use as the first part of an access
- control key when defining a new
- control.
+ access controls are stored in file_permissions.db as key=value pairs.
+ key -> path to file/file_name\0uniqueID:scope_end_start
+ where scope -> public,guest,course,group,domains or users.
+ end -> UNIX time for end of access (0 -> no end date)
+ start -> UNIX time for start of access
+
+ value -> XML description of access control
+ <scope type=""> (type =1 of: public,guest,course,group,domains,users">
+ <start></start>
+ <end></end>
+
+ <password></password> for scope type = guest
+
+ <domain></domain> for scope type = course or group
+ <number></number>
+ <roles id="">
+ <role></role>
+ <access></access>
+ <section></section>
+ <group></group>
+ </roles>
+
+ <dom></dom> for scope type = domains
+
+ <users> for scope type = users
+ <user>
+ <uname></uname>
+ <udom></udom>
+ </user>
+ </users>
+ </scope>
+
+ Access data is also aggregated for each file in an additional key=value pair:
+ key -> path to file/file_name\0accesscontrol
+ value -> reference to hash
+ hash contains key = value pairs
+ where key = uniqueID:scope_end_start
+ value = UNIX time record was last updated
+
+ Used to improve speed of look-ups of access controls for each file.
+
+ Locks on files (resulting from submission of portfolio file to a homework problem stored in array of arrays.
+
+parse_access_controls():
+
+Parses XML of an access control record
+Args
+1. Text string (XML) of access comtrol record
+
+Returns:
+1. Hash of access control settings.
+
+modify_access_controls():
+
+Modifies access controls for a portfolio file
+Args
+1. file name
+2. reference to hash of required changes,
+3. domain
+4. username
+ where domain,username are the domain of the portfolio owner
+ (either a user or a course)
+
+Returns:
+1. result of additions or updates ('ok' or 'error', with error message).
+2. result of deletions ('ok' or 'error', with error message).
+3. reference to hash of any new or updated access controls.
+4. reference to hash used to map incoming IDs to uniqueIDs assigned to control.
+ key = integer (inbound ID)
+ value = uniqueID
=back
--raeburn1150497455--