File:
[LON-CAPA] /
loncom /
interface /
lonsyllabus.pm
Revision
1.151:
download - view:
text,
annotated -
select for diffs
Sun Sep 18 22:33:45 2022 UTC (2 years, 8 months ago) by
raeburn
Branches:
MAIN
CVS tags:
HEAD
- URLs in direct links to LON-CAPA messages in notification email, and to
publicly accessible syllabus or portfolio files can be set to use hostname
of portal server instead of user's homeserver as first part of URL.
# The LearningOnline Network
# Syllabus
#
# $Id: lonsyllabus.pm,v 1.151 2022/09/18 22:33:45 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
package Apache::lonsyllabus;
use strict;
use Apache::lontemplate;
use Apache::Constants qw(:common);
use Apache::loncommon;
use Apache::lonnet;
use Apache::lontexconvert;
use Apache::lonfeedback;
use Apache::lonhtmlgateway;
use Apache::lonannounce;
use Apache::lonlocal;
use Apache::lonhtmlcommon;
use Apache::lonspeller();
use HTML::Entities();
sub handler {
my $r = shift;
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
return OK if $r->header_only;
my $target=$env{'form.grade_target'};
# --------------------------------------------------- Get course info from URL
my (undef,undef,$cdom,$cnum)=split(/\//,$r->uri);
# ------------------------------------------------------------ Get query string
&Apache::loncommon::get_unprocessed_cgi
($ENV{'QUERY_STRING'},['register','forceedit','todocs',
'folderpath','title','only_body']);
# ----------------------------------------------------- Is this even a course?
my $homeserver=&Apache::lonnet::homeserver($cnum,$cdom);
if ($homeserver eq 'no_host') {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
&Apache::loncommon::simple_error_page($r,'No syllabus available',
'No syllabus available');
return OK;
} elsif (!&Apache::lonnet::is_course($cdom,$cnum)) {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
&Apache::loncommon::simple_error_page($r,'No syllabus available',
'The course/community for which the syllabus was requested does not exist.');
return OK;
}
# ------------------------------------- There is such a course, get environment
my %courseenv=&Apache::lonnet::dump('environment',$cdom,$cnum);
my $crstype = &Apache::loncommon::course_type();
# --------------------------------------------------------------- Force Student
my ($forceedit,$forcestudent);
if ($env{'form.forceedit'}) { $forceedit=1; }
if (!$forceedit) {
$forcestudent=1;
}
# --------------------------------------------------------------- Check Privileges
my $allowed = 0;
if ($env{'user.environment'}) {
# does this user have privileges to post, etc?
if ($env{'request.course.id'}
&& $cdom eq $env{'course.'.$env{'request.course.id'}.'.domain'}
&& $cnum eq $env{'course.'.$env{'request.course.id'}.'.num'}) {
$allowed=&Apache::lonnet::allowed('mdc',$env{'request.course.id'});
if ($forcestudent or $target eq 'tex') { $allowed=0; }
}
}
# -------------------------------------------------- Let's see who handles this
my $external=$courseenv{'externalsyllabus'};
my $uploaded=$courseenv{'uploadedsyllabus'};
my $minimal=$courseenv{'minimalsyllabus'};
if (($minimal =~/\w/) || ($uploaded =~/\w/)) {
my ($item,$is_pdf);
if ($minimal =~/\w/) {
if ($external =~ m{\Q$minimal\E$}) {
undef($external);
}
$item = $minimal;
} elsif ($uploaded =~/\w/) {
if ($external =~ m{\Q$uploaded\E$}) {
undef($external);
}
$item = $uploaded;
if ($item =~ /\.pdf$/i) {
$is_pdf = 1;
}
}
unless ($allowed && $forceedit) {
my $file=&Apache::lonnet::filelocation("",$item);
if ($file =~ /\.(tex|x?html?)$/) {
my $filetype = $1;
my $filecontents=&Apache::lonnet::getfile($file);
if ($filecontents eq -1) {
$r->print(&mt('Syllabus file unavailable'));
} elsif ($filetype eq 'tex') {
if ($target eq 'tex') {
$r->print($filecontents);
} else {
my $texengine = $env{'form.texengine'};
if ($texengine eq '') {
$texengine = 'tth';
} elsif (lc($texengine) eq 'jsmath') {
$texengine = 'MathJax';
}
my $result = &Apache::lontexconvert::converted(\$filecontents,$texengine);
my %args;
&get_breadcrumbs($cdom,$cnum,$crstype,\%args);
if ($env{'form.only_body'}) {
$args{'only_body'} = 1;
}
if ($env{'request.use_absolute'}) {
$args{'use_absolute'} = $env{'request.use_absolute'};
}
$r->print(&Apache::loncommon::start_page("Syllabus",undef,\%args).
$result.
&Apache::loncommon::end_page());
}
} else {
my %mystyle;
unless ($target eq 'tex') {
$target = 'web';
}
&Apache::structuretags::reset_problem_globals();
my $oldfile = $env{'request.filename'};
$env{'request.filename'} = $item;
my $result = &Apache::lonxml::xmlparse($r,$target,$filecontents,
'',%mystyle);
&Apache::structuretags::reset_problem_globals();
&Apache::lonhomework::finished_parsing();
$env{'request.filename'} = $oldfile;
&Apache::lonxml::add_messages(\$result);
$r->print($result);
}
} else {
if ($target eq 'tex') {
$r->print(&Apache::lonprintout::print_latex_header($env{'form.latex_type'}).
' \strut \\\\ \textbf{'.&mt('Syllabus').'} \strut \\\\ '.
&mt('Unsupported file type.').' \strut \\\\ '.
&mt('Print the syllabus directly from your web browser').
'\end{document}');
} else {
my $brcrum;
if ($env{'form.folderpath'} =~ /^supplemental/) {
my $title = $env{'form.title'};
if ($title eq '') {
$title = &mt('Syllabus');
}
$brcrum =
&Apache::lonhtmlcommon::docs_breadcrumbs(undef,$crstype,undef,$title,1);
}
$r->print(&Apache::lonwrapper::wrapper($r,$item,$brcrum,$env{'request.use_absolute'},
undef,$is_pdf,undef,'','',&mt('Syllabus')));
}
}
return OK;
}
} elsif ($external=~/\w/) {
unless ($allowed && $forceedit) {
if (($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public') &&
($ENV{'SERVER_PORT'} == 443) && ($external =~ m{^http://}) && !($env{'form.usehttp'})) {
my $hostname = $r->hostname();
unless ((&Apache::lonnet::uses_sts()) || (&Apache::lonnet::waf_allssl($hostname))) {
&redirect_to_http($r);
return OK;
}
}
if ($target eq 'tex') {
$r->print(&Apache::lonprintout::print_latex_header($env{'form.latex_type'}).
' \strut \\\\ \textbf{'.&mt('Syllabus').'} \strut \\\\ '.$external.' '.
' \strut \\\\ '.&mt('Print the syllabus directly from your web browser').
'\end{document}');
} else {
my $is_ext = 1;
my ($is_pdf,$brcrum);
if ($external =~ /\.pdf$/i) {
$is_pdf = 1;
}
if ($env{'form.folderpath'} =~ /^supplemental/) {
my $title = $env{'form.title'};
if ($title eq '') {
$title = &mt('Syllabus');
}
$brcrum =
&Apache::lonhtmlcommon::docs_breadcrumbs(undef,$crstype,undef,$title,1);
}
$r->print(&Apache::lonwrapper::wrapper($r,$external,$brcrum,$env{'request.use_absolute'},
$is_ext,$is_pdf,undef,'','',&mt('Syllabus')));
}
return OK;
}
}
# ------------------------------------------------------------ Print the screen
if ($target eq 'tex') {
$r->print(&Apache::lonprintout::print_latex_header($env{'form.latex_type'}));
}
# ------------------------------ The buck stops here: internal syllabus display
# --------------------------------------------------------- The syllabus fields
my %syllabusfields=&Apache::lonlocal::texthash(
'aaa_instructorinfo' => 'Instructor Information',
'bbb_description' => 'Course Description',
'ccc_prereq' => 'Prerequisites',
'cdc_classhours' => 'Class Hours',
'ddd_officehours' => 'Office Hours',
'eee_helproom' => 'Helproom Hours',
'efe_projectinfo' => 'Project Information',
'fff_examinfo' => 'Exam Information',
'fgf_deadlines' => 'Deadlines',
'ggg_grading' => 'Grading Information',
'hhh_readings' => 'Readings',
'iii_coursepack' => 'Coursepack',
'jjj_weblinks' => 'Web Links',
'kkk_textbook' => 'Textbook',
'lll_includeurl' => 'URLs To Include in Syllabus');
# ---------------------------------------------------------- Load syllabus info
my %syllabus=&Apache::lonnet::dump('syllabus',$cdom,$cnum);
my ($output,%displayfields,%noshow);
# This handler might be called anonymously ...
# ----------------------------------------------------- Only if not public call
if ($allowed) {
if (($env{'form.choice'} =~ /^(template|minimal|url|file)$/) ||
($env{'form.phase'} =~ /^(upload|check)_embedded$/)) {
my $earlyout;
($earlyout,$uploaded,$external,$minimal,$output) =
&save_changes($cnum,$cdom,$uploaded,$external,$minimal,
\%syllabus,\%syllabusfields,\%courseenv);
if (($env{'form.choice'} eq 'minimal') &&
($minimal eq "/uploaded/$cdom/$cnum/portfolio/syllabus/loncapa.html")) {
delete($env{'form.symb'});
delete($env{'request.symb'});
$r->internal_redirect("$minimal?editmode=1&forceedit=1");
return OK;
}
if ($earlyout) {
if ($target ne 'tex') {
&print_header($r,$cnum,$cdom,$crstype,$allowed,$forceedit,
\%syllabus,\%syllabusfields);
$r->print($output.
&Apache::loncommon::end_page());
}
return OK;
}
}
}
if ($target ne 'tex') {
&print_header($r,$cnum,$cdom,$crstype,$allowed,$forceedit,\%syllabus,
\%syllabusfields);
$r->print($output);
}
# -------------------------------------------- Determine which fields are shown
if ($syllabus{'uploaded.fields'}) {
if ($syllabus{'uploaded.fields'} eq 'none') {
foreach my $field (keys(%syllabusfields)) {
$displayfields{$field} = ' style="display:none;"';
$noshow{$field} = 1;
}
} else {
my %included;
map { $included{$_} = 1; } split(/,/,$syllabus{'uploaded.fields'});
foreach my $field (keys(%syllabusfields)) {
my ($prefix) = split(/_/,$field);
if ($included{$prefix}) {
$displayfields{$field} = ' style="display:block;"';
} else {
$displayfields{$field} = ' style="display:none;"';
$noshow{$field} = 1;
}
}
}
} else {
foreach my $field (keys(%syllabusfields)) {
if ($syllabus{$field} ne '') {
$displayfields{$field} = ' style="display:block;"';
} else {
$displayfields{$field} = ' style="display:none;"';
}
}
}
if ($allowed) {
#---------------------------------- Print External URL Syllabus Info if editing
if ($target ne 'tex') {
my $link = &Apache::lonnet::url_prefix($r,$cdom,$homeserver,'web').
$r->uri;
$r->print('<div class="LC_left_float">'
.'<span class="LC_help_open_topic LC_info">'
.'<span class="LC_info">'
.&mt('Public link (no log-in): [_1]','<tt>'.$link.'</tt>')
.' </span>'.&Apache::loncommon::help_open_topic('Syllabus_ExtLink')
.'</span>'
.'</div><div style="padding:0;clear:both;margin:0;border:0"></div>'."\n");
my $lonhost = $r->dir_config('lonHostID');
$r->print(&chooser($r,$external,$uploaded,$minimal,$cdom,$cnum,$lonhost,
\%syllabusfields,\%syllabus));
}
} else {
#--------------------------------------------- Print last update unless editing
my $lastmod=$syllabus{'uploaded.lastmodified'};
$lastmod=($lastmod?&Apache::lonlocal::locallocaltime($lastmod):&mt('never'));
my $who;
if ($syllabus{'uploaded.lastmodified'}) {
if (($env{'user.name'} ne 'public') && ($env{'user.domain'} ne 'public')) {
$who = &Apache::loncommon::aboutmewrapper(
&Apache::loncommon::plainname($syllabus{'uploaded.name'},
$syllabus{'uploaded.domain'}),$syllabus{'uploaded.name'},
$syllabus{'uploaded.domain'});
} else {
# Public user?
# Only display name of user, but no link to personal information page
$who = &Apache::loncommon::plainname(
$syllabus{'uploaded.name'},
$syllabus{'uploaded.domain'});
}
}
if ($target ne 'tex') {
$r->print('<div class="LC_info">'.&mt('Last updated').': '.
$lastmod . ' '.
($who ? &mt('by').' '.$who
: '' ) .
'</div>' );
} else {
$r->print('\\\\ '.&mt('Last updated').': '.$lastmod.' '.
($who? &mt('by').'\\\\ '.
&Apache::loncommon::plainname($syllabus{'uploaded.name'},$syllabus{'uploaded.domain'})
:'')
.'\\\\');
}
}
#-------------------------------------------------------------- Print Headtitle
if ($target ne 'tex') {
my $display = 'block';
if ($external || $uploaded || $minimal) {
$display = 'none';
}
$r->print('<div class="LC_Box" id="template" style="display: '.$display.'">'.
'<h2 class="LC_hcell">'.$courseenv{'description'}.'</h2>');
if ($allowed) {
$r->print('<div style="margin: 0; float:left;">'.
'<h3>'.&Apache::lonnet::domain($cdom,'description').'</h3>'.
'</div>');
# Print Help Text if editing at right side of screen
$r->print('<div style="margin: 0; float:right;">'.
&Apache::loncommon::help_open_topic('Uploaded_Templates_TextBoxes',&mt('Help with filling in text boxes')).
'</div><br clear="all" />');
} else {
$r->print('<h3>'.&Apache::lonnet::domain($cdom,'description').'</h3>');
}
} else {
$r->print('\noindent{\large\textbf{'.$courseenv{'description'}.'}}\\\\\\\\\textbf{'.
&Apache::lonnet::domain($cdom,'description').'}\\\\');
}
# -------------------------------------------------------- Get course personnel
my $hidepersonnel;
if (($syllabus{'uploaded.fields'}) &&
(($syllabus{'uploaded.fields'} eq 'none') ||
($syllabus{'uploaded.fields'} !~ /000/))) {
$hidepersonnel = 1;
}
if ($target ne 'tex') {
if ($allowed) {
my $display = ' style="display:block;"';
if ($hidepersonnel) {
$display = ' style="display:none;"';
}
&Apache::lontemplate::print_start_template($r,&mt('Personnel'),'LC_Box',
'box_000_showpeople',$display);
$r->print(&get_personnel($r,$target,$cdom,$cnum,$allowed,$crstype,\%syllabus));
&Apache::lontemplate::print_end_template($r);
} else {
unless ($hidepersonnel) {
&Apache::lontemplate::print_start_template($r,&mt('Personnel'),'LC_Box');
$r->print(&get_personnel($r,$target,$cdom,$cnum,$allowed,$crstype,\%syllabus));
&Apache::lontemplate::print_end_template($r);
}
}
} else {
unless ($hidepersonnel) {
$r->print(&get_personnel($r,$target,$cdom,$cnum,$allowed,$crstype,%syllabus));
}
}
# -------------------------------------------------------------- Announcements?
my $day = &Apache::lonannounce::showday(time,2,
&Apache::lonannounce::readcalendar($cdom.'_'.$cnum));
my $hidefeeds;
if (($syllabus{'uploaded.fields'}) &&
(($syllabus{'uploaded.fields'} eq 'none') ||
($syllabus{'uploaded.fields'} !~ /111/))) {
$hidefeeds = 1;
}
if ($target ne 'tex') {
if ($allowed) {
my $display = ' style="display:block;"';
if ($hidefeeds) {
$display = ' style="display:none;"';
}
&Apache::lontemplate::print_start_template($r,&mt('RSS Feeds and Blogs'),'LC_Box',
'box_111_showrssfeeds',$display);
my ($numfeeds,$hiddenfeeds,$rsslinktext);
my $feeds=&Apache::lonrss::advertisefeeds($cnum,$cdom,$forceedit,\$numfeeds,
\$hiddenfeeds);
if ($numfeeds) {
$r->print($feeds);
$rsslinktext = &mt('New RSS Feed or Blog');
} else {
my $msg = '<br />'.
&mt("RSS Feeds and Blogs item is not included in a student's view of the syllabus.");
if ($hiddenfeeds) {
$r->print('<p class="LC_info">'.
&mt('All feeds currently hidden').
$msg.
'</p>');
} else {
$r->print('<p class="LC_info">'.
&mt('No current feeds').
$msg.
'</p>');
}
$rsslinktext = &mt('Manage Course RSS Feeds/Blogs');
if ($crstype eq 'Community') {
$rsslinktext = &mt('Manage Community RSS Feeds/Blogs');
}
}
my $editurl= &Apache::lonnet::absolute_url().'/adm/'.$cdom.'/'.$cnum.'/_rss.html';
$r->print( '<a href="'.$editurl.'">'.$rsslinktext.'</a>');
&Apache::lontemplate::print_end_template($r);
} else {
unless ($hidefeeds) {
my $feeds = &Apache::lonrss::advertisefeeds($cnum,$cdom,$forceedit);
if ($feeds ne '') {
&Apache::lontemplate::print_start_template($r,&mt('RSS Feeds and Blogs'),'LC_Box');
$r->print($feeds);
&Apache::lontemplate::print_end_template($r);
}
}
}
} else {
$r->print(&Apache::lonxml::xmlparse($r,'tex',$day));
}
# ---------------------------------------------------------------- Get syllabus
if (($syllabus{'uploaded.lastmodified'}) || ($allowed)) {
my $url_include_handler = sub {
my ($r, $field, $message, $group, $data_ref, $fields_ref, $target, $allowed, $display) = @_;
my %data = %{$data_ref};
my %fields = %{$fields_ref};
my $urls=$message;
$message='';
foreach my $filelink (split(/\n/,$urls)) {
my $output='';
# embed style?
my ($curfext)=($filelink=~/\.([^\.]+)$/);
my $embstyle=&Apache::loncommon::fileembstyle($curfext);
if (($embstyle eq 'ssi') || ($curfext=~/\/$/)) {# make ssi call and remove everything but the body contents
$output=&Apache::lonnet::ssi_body($filelink);
} elsif ($embstyle eq 'img') {# embed as an image
$output='<img src="'.$filelink.'" />';
}
if ($output ne '') {
if ($target ne 'tex') {
$message.='<p>'.$output.'</p>';
} else {
$message.=' '.&Apache::lonxml::xmlparse($r,'tex','<p>'.$output.'</p>').' ';
}
}
}
if ($allowed) {
&Apache::lonfeedback::newline_to_br(\$urls);
&Apache::lontemplate::print_start_template($r,$fields{$field}.
&Apache::loncommon::help_open_topic('Syllabus_URLs'),'LC_Box',
'box_'.$field,$display);
$r->print($urls);
$r->print("<br /><div>");
&Apache::lontemplate::print_textarea_template($r, $data{$field},
$field, Apache::lontemplate->RICH_TEXT_ALWAYS_OFF);
&Apache::lontemplate::print_saveall_template($r);
$r->print("</div>");
&Apache::lontemplate::print_end_template($r);
} else {
$r->print($message);
}
};
my %custom_hash = ( 'lll_includeurl' => $url_include_handler );
&Apache::lontemplate::print_template_fields($r, \%syllabus, \%syllabusfields,
$target, $allowed, Apache::lontemplate->RICH_TEXT_DETECT_HTML, \%custom_hash,
undef,\%displayfields,\%noshow);
if ($allowed) {
$r->print('</div></form>'.
&Apache::lonhtmlcommon::htmlareaselectactive());
}
} else {
if ($target ne 'tex') {$r->print('<p class="LC_info">');} else {$r->print('\par ');}
$r->print(&mt('No syllabus information provided.'));
if ($target ne 'tex') {$r->print('</p>');}
}
if ($target ne 'tex') {
if ($env{'form.backto'} eq 'coursecatalog') {
$r->print('<form name="backtocat" method="post" action="/adm/coursecatalog">'.
&Apache::lonhtmlcommon::echo_form_input(['backto','courseid']).
'</form>');
}
$r->print(&Apache::loncommon::end_page());
} else {
$r->print('\end{document}');
}
return OK;
}
sub print_header {
my ($r,$cnum,$cdom,$crstype,$allowed,$forceedit,$syllabus,$syllabusfields) = @_;
return unless ((ref($syllabus) eq 'HASH') || (ref($syllabusfields) eq 'HASH'));
# ----------------------------------------------------------------- Make header
my $rss_link = &Apache::lonrss::rss_link($cnum,$cdom);
my $js;
if ($env{'form.backto'} eq 'coursecatalog') {
$js .= <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function ToCatalog(caller) {
numidx = getIndexByName('coursenum');
if (numidx > -1) {
if (caller != 'details') {
document.backtocat.elements[numidx].value = '';
}
}
document.backtocat.submit();
}
function getIndexByName(item) {
for (var i=0;i<document.backtocat.elements.length;i++) {
if (document.backtocat.elements[i].name == item) {
return i;
}
}
return -1;
}
// ]]>
</script>
ENDSCRIPT
}
if ($allowed && $forceedit) {
my $check_uncheck = &Apache::loncommon::check_uncheck_jscript();
my @fieldnames = sort(keys(%{$syllabusfields}));
unshift(@fieldnames,'000_showpeople','111_showrssfeeds');
my (@checked,@unchecked);
if ($syllabus->{'uploaded.fields'} eq 'none') {
my $lastidx = scalar(@fieldnames)-1;
@unchecked = (0..$lastidx);
} elsif ($syllabus->{'uploaded.fields'}) {
my %included;
map { $included{$_} = 1; } split(/,/,$syllabus->{'uploaded.fields'});
for (my $i=0; $i<@fieldnames; $i++) {
my ($prefix) = split(/_/,$fieldnames[$i]);
if ($included{$prefix}) {
push(@checked,$i);
} else {
push(@unchecked,$i);
}
}
} else {
@checked = (0,1);
for (my $i=2; $i<@fieldnames; $i++) {
if ($syllabus->{$fieldnames[$i]}) {
push(@checked,$i);
} else {
push(@unchecked,$i);
}
}
}
my $fieldstr = "var fields = new Array('".join("','",@fieldnames)."');";
my $checkedstr = "var include = new Array('".join("','",@checked)."');";
my $uncheckedstr = "var exclude = new Array('".join("','",@unchecked)."');";
my $invurl = &mt('Invalid URL');
&js_escape(\$invurl);
my $urlregexp = <<'ENDREGEXP';
/^([a-z]([a-z]|\d|\+|-|\.)*):(\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?((\[(|(v[\da-f]{1,}\.(([a-z]|\d|-|\.|_|~)|[!\$&'\(\)\*\+,;=]|:)+))\])|((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=])*)(:\d*)?)(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*|(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)){0})(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i
ENDREGEXP
$js .= <<"ENDSCRIPT";
<script type="text/javascript">
// <![CDATA[
function toggleEditor(pick) {
var choices = new Array('template','minimal','url','file','templatebox');
for (var i=0; i<choices.length; i++) {
if (((choices[i] == 'templatebox') && (pick == 'template')) ||
(choices[i] == pick)) {
document.getElementById(choices[i]).style.display='block';
} else {
document.getElementById(choices[i]).style.display='none';
}
}
return;
}
var regexp = $urlregexp;
function extUrlPreview(caller,protocol) {
if (document.getElementById(caller)) {
var url = document.getElementById(caller).value;
if (regexp.test(url)) {
var http_regex = /^http\:\/\//gi;
if ((protocol == 'https') && (http_regex.test(url))) {
window.open(url,"syllabuspreview","height=400,width=500,scrollbars=1,resizable=1,menubar=0,location=1");
} else {
openMyModal(url,500,400,'yes');
}
} else {
alert("$invurl");
}
}
}
function toggleBox(name,caller) {
if (name == 'all') {
if (document.syllabus.showfield.length > 0) {
for (var i=0; i<document.syllabus.showfield.length; i++) {
if (document.syllabus.showfield[i].checked) {
if (document.getElementById('box_'+document.syllabus.showfield[i].value)) {
document.getElementById('box_'+document.syllabus.showfield[i].value).style.display='block';
}
} else {
if (document.getElementById('box_'+document.syllabus.showfield[i].value)) {
document.getElementById('box_'+document.syllabus.showfield[i].value).style.display='none';
}
}
}
}
} else {
if (caller.checked) {
if (document.getElementById('box_'+caller.value)) {
document.getElementById('box_'+caller.value).style.display='block';
}
} else {
if (document.getElementById('box_'+caller.value)) {
document.getElementById('box_'+caller.value).style.display='none';
}
}
}
return;
}
function setTemplateBoxes() {
$fieldstr
$checkedstr
$uncheckedstr
if (include.length > 0) {
for (var i=0; i<include.length; i++) {
if (document.getElementById('showfield_'+include[i])) {
document.getElementById('showfield_'+include[i]).checked = true;
if (document.getElementById('box_'+fields[include[i]])) {
document.getElementById('box_'+fields[include[i]]).style.display='block';
}
}
}
}
if (exclude.length > 0) {
for (var i=0; i<exclude.length; i++) {
if (document.getElementById('showfield_'+exclude[i])) {
document.getElementById('showfield_'+exclude[i]).checked = false;
if (document.getElementById('box_'+fields[exclude[i]])) {
document.getElementById('box_'+fields[exclude[i]]).style.display='none';
}
}
}
}
return;
}
$check_uncheck
// ]]>
</script>
ENDSCRIPT
}
my $args = {'function' => undef,
'domain' => $cdom};
my $forcereg;
if ($env{'form.register'}) {
$forcereg = 1;
$args->{'force_register'} = $forcereg;
}
if ($env{'form.backto'} eq 'coursecatalog') {
&Apache::lonhtmlcommon::clear_breadcrumbs();
my $brcrum = [{href=>"javascript:ToCatalog();",
text=>&mt('Course/Community Catalog'),
no_mt=>1}
];
if ($env{'form.coursenum'} ne '') {
push(@{$brcrum},
{href=>"javascript:ToCatalog('details')",
text=>"Course details"});
}
push(@{$brcrum},
{href=>$r->uri,
text=>"Course syllabus"});
$args->{'bread_crumbs'} = $brcrum;
} else {
&get_breadcrumbs($cdom,$cnum,$crstype,$args);
}
if ($allowed) {
my %loaditem = (
onload => 'setTemplateBoxes();',
);
$args->{'add_entries'} = \%loaditem;
} else {
if ($env{'request.use_absolute'}) {
$args->{'use_absolute'} = $env{'request.use_absolute'};
}
}
if ($env{'form.only_body'}) {
$args->{'only_body'} = 1;
}
$args->{'hostname'} = $r->hostname();
my $start_page =
&Apache::loncommon::start_page("Syllabus", $rss_link.$js,$args);
if ($start_page) {
$r->print($start_page);
}
}
sub get_breadcrumbs{
my ($cdom,$cnum,$crstype,$args) = @_;
return unless (ref($args) eq 'HASH');
if ($env{'form.folderpath'} =~ /^supplemental/) {
my $title = $env{'form.title'};
if ($title eq '') {
$title = &mt('Syllabus');
}
my $brcrum =
&Apache::lonhtmlcommon::docs_breadcrumbs(undef,$crstype,undef,$title,1);
if (ref($brcrum) eq 'ARRAY') {
$args->{'bread_crumbs'} = $brcrum;
}
} else {
if ((&Apache::lonnet::is_on_map("public/$cdom/$cnum/syllabus"))
&& (($env{'form.symb'}) || ($env{'form.register'}))) {
&Apache::lonhtmlcommon::clear_breadcrumbs();
} else {
$args->{'bread_crumbs'} = [
{'href' => "/public/$cdom/$cnum/syllabus",
'text' => 'Syllabus'},
];
}
}
return;
}
sub chooser {
my ($r,$external,$uploaded,$minimal,$cdom,$cnum,$lonhost,$fields,$values) = @_;
my %lt = &Apache::lonlocal::texthash(
'type' => 'Syllabus Type',
'url' => 'External URL',
'file' => 'Uploaded file',
'minimal' => 'Minimal template',
'template' => 'Standard template',
'templateboxes' => 'Choose template items ... ',
'curr' => 'Current:',
'rep' => 'Replace:',
'upl' => 'Upload:',
'pr' => 'Preview',
'save' => 'Save',
'sved' => 'Save and Edit',
'chourl' => 'External URL',
'chofile' => 'Uploaded syllabus file',
'parse' => 'Upload embedded images/multimedia files if HTML file',
);
my %checked = (
file => '',
minimal => '',
url => '',
template => '',
);
my %display = (
file => 'none',
minimal => 'none',
url => 'none',
templatebox => 'none',
);
my $check = ' checked="checked" ';
if ($uploaded) {
$checked{'file'} = $check;
$display{'file'} = 'block';
} elsif ($external) {
$checked{'url'} = $check;
$display{'url'} = 'block';
} elsif ($minimal) {
$checked{'minimal'} = $check;
$display{'minimal'} = 'block';
} else {
$checked{'template'} = $check;
$checked{'templatebox'} = $check;
$display{'templatebox'} = 'block';
}
my $protocol = ($ENV{'SERVER_PORT'} == 443?'https':'http');
my $output =
'<form name="syllabus" method="post" enctype="multipart/form-data" action="">'."\n".
'<input type="hidden" name="forceedit" value="1" />'."\n".
'<div class="LC_left_float"><fieldset><legend>'.$lt{'type'}.'</legend>';
foreach my $item ('minimal','template','url','file') {
$output .= '<label><input type="radio" name="choice" value="'.$item.'" '.$checked{$item}.' onclick="toggleEditor('."'$item'".')" />'.
$lt{$item}.'</label><br />';
}
$output .= '</fieldset></div>'."\n".
'<div id="url" class="LC_left_float" style="display: '.$display{'url'}.'">'."\n".
'<fieldset><legend>'.$lt{'chourl'}.'</legend><span class="LC_nobreak">'."\n".
'<a href="javascript:extUrlPreview('."'syllabusurl','$protocol'".');">'.$lt{'pr'}.'</a></span> '."\n".
'<input type="text" id="syllabusurl" name="externalsyllabus" value="'.$external.'" size="55" />'."\n".
' <input type="submit" name="storeurl" value="'.$lt{'save'}.'" />'."\n".
'</fieldset></div>'."\n".
'<div id="minimal" class="LC_left_float" style="display: '.$display{'minimal'}.'">'."\n".
'<fieldset><legend>'.$lt{'minimal'}.'</legend>';
if ($minimal) {
my ($absurl,$filename,$depbutton) = &syllabus_file_info($r,$minimal,$cnum,$cdom,$lonhost,'minimal');
$output .= '<a href="javascript:extUrlPreview('."'currminimal'".');">'.$lt{'pr'}.'</a>'.
'<input type="hidden" name="minimalfile" value="'.&HTML::Entities::encode($absurl).'?inhibitmenu=yes" id="currminimal" />'.
$depbutton;
} else {
$output .= &mt('Title of Syllabus Page:').' '.
'<input type="text" id="minimaltitle" name="syllabustitle" value="'.&mt('Syllabus').'" size="30" />'."\n".
' <input type="submit" name="storeminimal" value="'.$lt{'sved'}.'" />'."\n";
}
$output .= '</fieldset></div>'."\n".
'<div id="file" class="LC_left_float" style="display: '.$display{'file'}.'">'."\n".
'<fieldset><legend>'.$lt{'file'}.'</legend>';
if ($uploaded) {
my ($absurl,$filename,$depbutton) = &syllabus_file_info($r,$uploaded,$cnum,$cdom,$lonhost,'file');
$output .= '<span class="LC_nobreak">'.$lt{'curr'}.' '.
'<input type="hidden" name="uploadedfile" value="'.&HTML::Entities::encode($absurl).'?inhibitmenu=yes" id="currfile" />'.
'<a href="javascript:extUrlPreview('."'currfile'".');">'.$filename.'</a></span>'.$depbutton.
'<br /><br />'.$lt{'rep'};
} else {
$output .= $lt{'upl'};
}
$output .= '<br />'."\n".
'<span class="LC_nobreak">'.
'<input type="file" name="syllabusfile" size="55" />'."\n".
' <input type="submit" name="storefile" value="'.$lt{'save'}.'" />'.
'</span><br />'.
'<label>'.
'<input type="checkbox" name="parserflag" checked="checked" />'.
$lt{'parse'}.
'</label>'.
'</fieldset></div>'.
'<div id="templatebox" class="LC_left_float" style="display: '.
$display{'templatebox'}.';"><fieldset><legend>'.$lt{'templateboxes'}.
' <input type="button" value="'.&mt('check all').'" '.
'onclick="javascript:checkAll('."document.syllabus.showfield".');javascript:toggleBox('."'all'".');" />'.
(' 'x2).
'<input type="button" value="'.&mt('uncheck all').'" '.
'onclick="javascript:uncheckAll('."document.syllabus.showfield".');javascript:toggleBox('."'all'".');" />'.
'</legend>'.
&fields_check_uncheck($fields,$values).
'</fieldset><br />'.
'<input type="submit" name="storesyl" value="'.&mt('Save All').'" />'.
'</div>';
$output .= '<div style="padding:0;clear:both;margin:0;border:0"></div>';
return $output;
}
sub syllabus_file_info {
my ($r,$item,$cnum,$cdom,$lonhost,$context) = @_;
my $hostname = &Apache::lonnet::hostname($lonhost);
my $protocol = $Apache::lonnet::protocol{$lonhost};
$protocol = 'http' if ($protocol ne 'https');
my $alias = &Apache::lonnet::use_proxy_alias($r,$lonhost);
$hostname = $alias if ($alias ne '');
my $absurl = $protocol.'://'.$hostname.$item;
my ($filename) = ($item =~ m{([^/]+)$});
my $file=&Apache::lonnet::filelocation("",$item);
my ($depbutton,$filetype,$editable);
if ($file =~ /\.(xhtml|xml|tex|html|htm)$/) {
$filetype=$1;
}
if ($filetype) {
unless ($filetype eq 'tex') {
$filetype='html';
}
}
if ($filetype eq 'html') {
my $filecontents=&Apache::lonnet::getfile($file);
unless ($filecontents eq -1) {
my $mm = new File::MMagic;
my $mimetype = $mm->checktype_contents($filecontents);
if ($mimetype eq 'text/html') {
my (%codebase,%allfiles);
my $parse_result = &Apache::lonnet::extract_embedded_items($item,\%allfiles,
\%codebase,\$filecontents);
my $actionurl = "/public/$cdom/$cnum/syllabus";
my ($ignore,$num,$numpathchanges,$existing,$mapping) =
&Apache::loncommon::ask_for_embedded_content($actionurl,undef,\%allfiles,
\%codebase,
{'context' => 'rewrites',
'ignore_remote_references' => 1,});
$editable = 1;
}
}
}
$depbutton = (' ' x 3).
&editfile_button($item,$context,$editable).
&editbutton_js();
return ($absurl,$filename,$depbutton);
}
sub fields_check_uncheck {
my ($fields,$values) = @_;
return unless ((ref($fields) eq 'HASH') && (ref($values) eq 'HASH'));
my $numinrow = 4;
my $table;
my @fieldnames = sort(keys(%{$fields}));
unshift(@fieldnames,'000_showpeople','111_showrssfeeds');
my $numfields = scalar(@fieldnames);
my %included;
if (($values->{'uploaded.fields'}) && ($values->{'uploaded.fields'} ne 'none')) {
map { $included{$_} = 1; } split(/,/,$values->{'uploaded.fields'});
}
for (my $i=0; $i<$numfields; $i++) {
my ($name,$checked);
if ($fieldnames[$i] eq '000_showpeople') {
$name = &mt('Personnel');
} elsif ($fieldnames[$i] eq '111_showrssfeeds') {
$name = &mt('RSS Feeds and Blogs');
} else {
$name = $fields->{$fieldnames[$i]};
}
if ($values->{'uploaded.fields'}) {
unless ($values->{'uploaded.fields'} eq 'none') {
my ($prefix) = split(/_/,$fieldnames[$i]);
if ($included{$prefix}) {
$checked = ' checked="checked"';
}
}
} else {
if ($fieldnames[$i] eq '000_showpeople') {
$checked = ' checked="checked"';
} elsif ($fieldnames[$i] eq '111_showrssfeeds') {
$checked = ' checked="checked"';
} else {
if ($values->{$fieldnames[$i]} ne '') {
$checked = ' checked="checked"';
}
}
}
my $rem = $i%($numinrow);
if ($rem == 0) {
if (($i > 0) && ($i < $numfields)) {
$table .= '</tr>';
}
if ($i < $numfields) {
$table .= '<tr>';
}
}
if ($i == $numfields-1) {
my $rem = $numfields%($numinrow);
my $colsleft = $numinrow - $rem;
if ($colsleft > 1) {
$table .= '<td colspan="'.$colsleft.'">';
} else {
$table .= '</td>';
}
} else {
$table .= '<td>';
}
$table .=
'<label><input type="checkbox" name="showfield" value="'.$fieldnames[$i].'" '.
$checked.' id="showfield_'.$i.'" onclick="javascript:toggleBox('."'$fieldnames[$i]',this".');" />'.
$name.'</label></td>'."\n";
}
if ($table ne '') {
my $rem = $numfields%($numinrow);
my $colsleft = $numinrow - $rem;
if ($colsleft > 1 ) {
$table .= '<td colspan="'.$colsleft.'"> </td>';
} elsif ($colsleft == 1) {
$table .= '<td> </td>';
}
$table = '<table>'.$table.'</tr></table>';
}
return $table;
}
sub get_personnel {
my ($r,$target,$cdom,$cnum,$allowed,$crstype,$syllabus) = @_;
my (%hiddenroles,%hiddenusers);
if (ref($syllabus) eq 'HASH') {
if (ref($syllabus->{'personnel'}) eq 'HASH') {
if ($syllabus->{'personnel'}{'hiderole'}) {
map { $hiddenroles{$_} = 1; } split(/,/,$syllabus->{'personnel'}{'hiderole'});
}
if ($syllabus->{'personnel'}{'hideuser'}) {
map { $hiddenusers{$_} = 1; } split(/,/,$syllabus->{'personnel'}{'hideuser'});
}
}
}
my $output;
my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'/'.$cnum,1);
if ($target ne 'tex') {
if ($allowed) {
$r->print(&Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row().
'<th>'.&mt('Role hidden?').'</th><th>'.&mt('Role').'</th>'.
'<th>'.&mt('Personnel (hidden if checked)').'</th>'.
&Apache::loncommon::end_data_table_header_row());
} else {
$r->print(&Apache::lonhtmlcommon::start_pick_box());
}
} else {
$r->print('\begin{tabular}{|p{0.45\textwidth}|p{0.45\textwidth}|}\hline');
}
my @personnel=sort(keys(%coursepersonnel));
my $lastpers=$personnel[$#personnel];
foreach my $element (@personnel) {
unless ($allowed) {
next if ($hiddenroles{$element})
}
my ($role,$sec);
if ($element =~ /:/) {
($role,$sec) = split(/:/,$element);
} else {
$role = $element;
}
my $roletext = &Apache::lonnet::plaintext($role,$crstype);
if ($sec) {
$roletext .=' ('.&Apache::lonlocal::mt('Section [_1]',$sec).')';
}
if ($target ne 'tex') {
if ($allowed) {
my $checked;
if ($hiddenroles{$element}) {
$checked = ' checked="checked"';
}
$r->print(&Apache::loncommon::start_data_table_row().
'<td>'.
'<input type="checkbox" name="hiderole" value="'.$element.'" '.
$checked.' />'.
'</td><td>'.$roletext.'</td><td>');
} else {
$r->print(&Apache::lonhtmlcommon::row_title($roletext));
}
} else {
$r->print(' '.&Apache::lonxml::xmlparse($r,'tex',$roletext).' & ');
}
my @coursepersonlist;
foreach my $user (split(/\,/,$coursepersonnel{$element})) {
my ($puname,$pudom)=split(/\:/,$user);
if ($target ne 'tex') {
my $courseperson = &Apache::loncommon::plainname($puname,$pudom);
my $checked;
if ($hiddenusers{$element.'&'.$puname.':'.$pudom}) {
$checked = ' checked="checked"';
}
if ($allowed) {
my $item = '<span class="LC_nobreak"><label>'.
'<input type="checkbox" name="hideuser" value="'.$element.'&'.$puname.':'.$pudom.'"'.$checked.' />'.
&Apache::loncommon::aboutmewrapper($courseperson
,
$puname,$pudom).
'</label>'.(' 'x2).'</span> ';
push(@coursepersonlist,$item);
} else {
next if ($hiddenusers{$element.'&'.$puname.':'.$pudom});
if (($env{'user.name'} eq '') || ($env{'user.name'} eq 'public') ||
($env{'user.domain'} eq '') || ($env{'user.domain'} eq 'public')) {
push(@coursepersonlist,$courseperson);
} else {
push(@coursepersonlist,&Apache::loncommon::aboutmewrapper($courseperson,
$puname,$pudom));
}
}
} else {
push(@coursepersonlist,&Apache::loncommon::plainname($puname,
$pudom).' ');
}
}
if ($allowed) {
$r->print(join('',@coursepersonlist));
} else {
$r->print(join(', ',@coursepersonlist));
}
if ($target ne 'tex') {
if ($allowed) {
$r->print('</td>'.&Apache::loncommon::end_data_table_row());
} else {
my $lastclose=$element eq $lastpers?1:0;
$r->print(&Apache::lonhtmlcommon::row_closure($lastclose));
}
} else {
$r->print('\\\\ \hline');
}
}
if ($target ne 'tex') {
if ($allowed) {
$r->print(&Apache::loncommon::end_data_table());
} else {
$r->print(&Apache::lonhtmlcommon::end_pick_box());
}
} else {
$r->print('\end{tabular}\\\\');
}
return;
}
sub save_changes {
my ($cnum,$cdom,$uploaded,$external,$minimal,$syllabus,$syllabusfields,$courseenv) = @_;
my ($earlyout,$output);
unless ((ref($syllabus) eq 'HASH') && (ref($syllabusfields) eq 'HASH') ||
(ref($courseenv) eq 'HASH')) {
return ($earlyout,$uploaded,$external,$minimal,$output);
}
my ($was_ext,$is_ext,$putres);
if ($external) {
$was_ext = $external;
}
if (($env{'form.deleteuploaded_file'}) || ($env{'form.deleteuploaded_minimal'})) {
my %storehash;
if (($env{'form.choice'} eq 'file') &&
($env{'form.deleteuploaded_file'}) && ($uploaded =~ /\w/)) {
if ($courseenv->{'uploadedsyllabus'} =~ m{^\Q/uploaded/$cdom/$cnum/portfolio\E(/syllabus/.+)$}) {
my $filename = $1;
&update_access_permissions($cdom,$cnum,$filename);
}
&Apache::lonnet::delenv('course.'.$env{'request.course.id'}.'.uploadedsyllabus');
&Apache::lonnet::delenv('course.'.$env{'request.course.id'}.'.externalsyllabus');
$storehash{'uploadedsyllabus'} = '';
$storehash{'externalsyllabus'} = '';
$putres = &Apache::lonnet::put('environment',\%storehash,$cdom,$cnum);
undef($uploaded);
undef($external);
} elsif (($env{'form.choice'} eq 'minimal') &&
($env{'form.deleteuploaded_minimal'}) && ($minimal =~ /\w/)) {
my $minimalurl = "/uploaded/$cdom/$cnum/portfolio/syllabus/loncapa.html";
if ($courseenv->{'minimalsyllabus'} eq "$minimalurl") {
my $filecontents=&Apache::lonnet::getfile(&Apache::lonnet::filelocation("",$minimalurl));
unless ($filecontents eq -1) {
$env{'form.output'} = $filecontents;
&Apache::lonnet::finishuserfileupload($cnum,$cdom,'output',
'portfolio/syllabus/loncapa.html.bak');
$minimalurl = &default_minimal_syllabus($cnum,$cdom);
}
}
&update_access_permissions($cdom,$cnum,'/syllabus/loncapa.html');
&Apache::lonnet::delenv('course.'.$env{'request.course.id'}.'.externalsyllabus');
&Apache::lonnet::delenv('course.'.$env{'request.course.id'}.'.minimalsyllabus');
$storehash{'externalsyllabus'} = '';
$storehash{'minimalsyllabus'} = '';
$putres = &Apache::lonnet::put('environment',\%storehash,$cdom,$cnum);
undef($external);
undef($minimal);
}
} elsif ($env{'form.choice'} eq 'template') {
#store what the user typed in to the template
my @shown = &Apache::loncommon::get_env_multiple('form.showfield');
$syllabus->{'uploaded.fields'} = '';
if (@shown == 0) {
$syllabus->{'uploaded.fields'} = 'none';
} else {
foreach my $field (sort(@shown)) {
if (($field eq '000_showpeople') ||
($field eq '111_showrssfeeds') ||
($syllabusfields->{$field})) {
my ($prefix) = split(/_/,$field);
$syllabus->{'uploaded.fields'} .= $prefix.',';
}
if ($field eq '000_showpeople') {
my @hideusers = &Apache::loncommon::get_env_multiple('form.hideuser');
my @hideroles = &Apache::loncommon::get_env_multiple('form.hiderole');
my %coursepersonnel=&Apache::lonnet::get_course_adv_roles($cdom.'/'.$cnum,1);
my %personnel;
foreach my $key (keys(%coursepersonnel)) {
map { $personnel{$key}{$_} = 1; } split(/,/,$coursepersonnel{$key});
}
%{$syllabus->{'personnel'}} = ();
$syllabus->{'personnel'}{'hideuser'} = '';
$syllabus->{'personnel'}{'hiderole'} = '';
foreach my $role (@hideroles) {
if (exists($personnel{$role})) {
$syllabus->{'personnel'}{'hiderole'} .= $role.',';
}
}
foreach my $item (@hideusers) {
my ($role,$user) = split(/\&/,$item);
if (ref($personnel{$role}) eq 'HASH') {
if ($personnel{$role}{$user}) {
$syllabus->{'personnel'}{'hideuser'} .= $item.',';
}
}
}
$syllabus->{'personnel'}{'hideuser'} =~ s/,$//;
$syllabus->{'personnel'}{'hiderole'} =~ s/,$//;
}
}
$syllabus->{'uploaded.fields'} =~ s/,$//;
}
foreach my $syl_field (keys(%{$syllabusfields})) {
my $field=$env{'form.'.$syl_field};
chomp($field);
my $gateway = Apache::lonhtmlgateway->new();
$field = $gateway->process_incoming_html($field,1);
#here it will be stored
$syllabus->{$syl_field}=$field;
if ($syl_field eq 'lll_includeurl') { # clean up included URLs
my $field='';
foreach my $value (split(/\n/,$syllabus->{$syl_field})) {
my $url=$value;
# get rid of leading and trailing spaces
$url=~s/^\s+//;
$url=~s/\s+$//;
if ($url=~m|^https?\://([^/]+)/(.+)$|) {
my $host = $1;
my $remainder=$2;
# remove the hostname from internal URLs
my $hostname = &Apache::lonnet::hostname($host);
my %all_hostnames = &Apache::lonnet::all_hostnames();
foreach my $possible_host (keys(%all_hostnames)) {
if ($possible_host =~ /\Q$hostname\E/i) {
$url=$remainder;
}
}
}
# norm internal URLs
unless ($url=~/^https?\:/) {
$url=&Apache::lonnet::clutter($url);
}
# re-assemble field
if ($url) {
$field.=$url."\n";
}
}
$syllabus->{$syl_field}=$field;
}
}
my $now = time;
$syllabus->{'uploaded.domain'}=$env{'user.domain'};
$syllabus->{'uploaded.name'}=$env{'user.name'};
$syllabus->{'uploaded.lastmodified'} = $now;
$putres = &Apache::lonnet::put('syllabus',$syllabus,$cdom,$cnum);
if ($putres eq 'ok') {
($uploaded,$minimal,$external) =
&update_syllabus_env($cdom,$cnum,$courseenv,$env{'form.choice'},$uploaded,
$minimal,$external);
$output = '<div>'.
&Apache::lonhtmlcommon::confirm_success(&mt('Template saved.')).
'</div>';
} else {
$output = '<div class="LC_error">'.
&mt('An error occurred storing the template: [_1]',$putres).
'</div>';
}
} elsif ($env{'form.choice'} eq 'url') {
if ($env{'form.externalsyllabus'} =~ m{^https?://}) {
if ($env{'form.externalsyllabus'} eq $external) {
$output = '<div class="LC_info">'.
&mt('External URL unchanged.').
'</div>';
($uploaded,$minimal,$external) =
&update_syllabus_env($cdom,$cnum,$courseenv,$env{'form.choice'},$uploaded,
$minimal,$external);
} else {
$external=$env{'form.externalsyllabus'};
$external =~ s/(`)//g;
$putres =
&Apache::lonnet::put('environment',{externalsyllabus=>$external},
$cdom,$cnum);
if ($putres eq 'ok') {
&Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.externalsyllabus' => $external});
$output = '<div>'.
&Apache::lonhtmlcommon::confirm_success(&mt('External URL saved.')).
'</div>';
($uploaded,$minimal,$external) =
&update_syllabus_env($cdom,$cnum,$courseenv,$env{'form.choice'},$uploaded,
$minimal,$external);
} else {
$output = '<div class="LC_error">'.
&mt('An error occurred storing the external URL: [_1]',$putres).
'</div>';
}
}
$is_ext = $external;
} else {
$output = '<div class="LC_error">'.
&mt('External URL not saved -- invalid URL.').
'</div>';
}
} elsif (($env{'form.choice'} eq 'file') || ($env{'form.choice'} eq 'minimal')) {
# Process file upload - phase one - upload and parse primary file.
my ($upload_result,$uploadphase,$url,$needlink,$error,$errormsg);
if ($env{'form.choice'} eq 'file') {
if ($env{'form.syllabusfile.filename'}) {
my %allfiles = ();
my %codebase = ();
($url,$needlink) = &process_upload(\$output,$cnum,$cdom,
\%allfiles,\%codebase);
} else {
$output = '<div class="LC_info">'.
&mt('No file uploaded').
'</div>';
}
} elsif ($env{'form.choice'} eq 'minimal') {
$url = "/uploaded/$cdom/$cnum/portfolio/syllabus/loncapa.html";
my $filecontents=&Apache::lonnet::getfile(&Apache::lonnet::filelocation("",$url));
if ($filecontents eq -1) {
$url = &default_minimal_syllabus($cnum,$cdom);
}
}
if ($url =~ m{^/uploaded/\Q$cdom\E/\Q$cnum\E.*/[^/]+$}) {
my $exturl = &home_http_host($cdom,$cnum);
if ($exturl) {
$exturl .= $url;
}
my %storehash;
if ($env{'form.choice'} eq 'minimal') {
$storehash{'minimalsyllabus'} = $url;
} else {
$storehash{'uploadedsyllabus'} = $url;
}
if ($exturl) {
$storehash{'externalsyllabus'} = $exturl;
if ($exturl =~ /\.(html?|txt|js|css)$/) {
$exturl .= '?inhibitmenu=yes';
}
} else {
$storehash{'externalsyllabus'} = '',
}
$putres =
&Apache::lonnet::put('environment',\%storehash,$cdom,$cnum);
if ($putres eq 'ok') {
&Apache::lonnet::make_public_indefinitely($url);
foreach my $key (keys(%storehash)) {
&Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.'.$key => $storehash{$key}});
}
if ($env{'form.choice'} eq 'minimal') {
$minimal = $url;
} else {
$uploaded = $url;
}
if ($needlink) {
$output .= &return_to_editor($cdom,$cnum);
$earlyout = 1;
}
($uploaded,$minimal,$external) =
&update_syllabus_env($cdom,$cnum,$courseenv,$env{'form.choice'},$uploaded,
$minimal,$external);
} else {
$error = 1;
$errormsg = $putres;
}
} else {
$error = 1;
}
if ($error) {
$output = '<div class="LC_error">';
if ($env{'form.choice'} eq 'minimal') {
$output = &mt('An error occurred creating the minimal template file [_1]',$errormsg);
} else {
$output = &mt('An error occurred storing the uploaded file [_1]',$errormsg);
}
$output .= '</div>';
}
} elsif ($env{'form.phase'} eq 'upload_embedded') {
# Process file upload - phase two - upload embedded objects
my $uploadphase = 'check_embedded';
my $primaryurl = &HTML::Entities::encode($env{'form.primaryurl'},'<>&"');
my $state = &embedded_form_elems($uploadphase,$primaryurl);
my $url_root = '/uploaded/'.$cdom.'/'.$cnum;
my $actionurl = "/public/$cdom/$cnum/syllabus";
my ($result,$flag,$numpathchgs) =
&Apache::loncommon::upload_embedded('syllabus','portfolio/syllabus',
$cnum,$cdom,'/userfiles',$url_root,undef,undef,undef,$state,
$actionurl);
unless ($numpathchgs) {
my $modres =
&Apache::loncommon::modify_html_refs('syllabus','portfolio/syllabus',
$cnum,$cdom,
'/userfiles',$env{'form.primaryurl'});
$result .= $modres;
}
$output = $result.&return_to_editor($cdom,$cnum);
$earlyout = 1;
} elsif ($env{'form.phase'} eq 'check_embedded') {
# Process file upload - phase three - modify references in HTML file
my $uploadphase = 'modified_orightml';
my $result =
&Apache::loncommon::modify_html_refs('syllabus','portfolio/syllabus',
$cnum,$cdom,
'/userfiles',$env{'form.primaryurl'});
$output = $result.&return_to_editor($cdom,$cnum);
$earlyout = 1;
}
if ($putres eq 'ok') {
if ((($is_ext) && ($is_ext ne $was_ext)) || ($was_ext)) {
my $chome = &Apache::lonnet::homeserver($cnum,$cdom);
unless ($chome eq 'no_host') {
my %crsinfo = &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.');
if (ref($crsinfo{$cdom.'_'.$cnum}) eq 'HASH') {
if ($external =~ m{^http://}) {
$crsinfo{$cdom.'_'.$cnum}{'extsyllplain'} = 1;
} elsif ($crsinfo{$cdom.'_'.$cnum}{'extsyllplain'}) {
delete($crsinfo{$cdom.'_'.$cnum}{'extsyllplain'});
}
&Apache::lonnet::courseidput($cdom,\%crsinfo,$chome,'notime');
}
}
}
}
return ($earlyout,$uploaded,$external,$minimal,$output);
}
sub default_minimal_syllabus {
my ($cnum,$cdom) = @_;
my $title;
if ($env{'form.syllabustitle'}) {
$title = $env{'form.syllabustitle'};
$title =~ s{`}{}g;
$title=~s/^\s+//;
$title=~s/\s+$//;
}
if ($title eq '') {
$title = &mt('Syllabus');
}
my $initialtext = &mt('Replace with your own content.');
my $newhtml = <<END;
<html>
<head>
<title>$title</title>
</head>
<body bgcolor="#ffffff">
<h2>$title</h2>
$initialtext
</body>
</html>
END
$env{'form.output'}=$newhtml;
return &Apache::lonnet::finishuserfileupload($cnum,$cdom,'output',
'portfolio/syllabus/loncapa.html');
}
sub update_syllabus_env {
my ($cdom,$cnum,$courseenv,$saved,$uploaded,$minimal,$external) = @_;
return ($uploaded,$minimal,$external) unless(ref($courseenv) eq 'HASH');
my $now = time;
my (@envkeys,%storehash);
if ($saved eq 'template') {
if ($uploaded || $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}) {
push(@envkeys,'uploaded');
}
if ($minimal || $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}) {
push(@envkeys,'minimal');
}
if ($external || $env{'course.'.$env{'request.course.id'}.'.externalsyllabus'}) {
push(@envkeys,'external');
}
$storehash{'updatedsyllabus'} = $now;
&Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.updatedsyllabus' => $now
});
} elsif ($saved eq 'url') {
my $prefix = &home_http_host($cdom,$cnum);
if ($external =~ m{^\Q$prefix/uploaded/$cdom/$cnum/portfolio/syllabus/\E(.+)$}) {
my $file = $1;
if ($file eq 'loncapa.html') {
if ($uploaded || $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}) {
push(@envkeys,'uploaded');
}
} elsif ($minimal || $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}) {
push(@envkeys,'minimal');
}
} else {
if ($uploaded || $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}) {
push(@envkeys,'uploaded');
}
if ($minimal || $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}) {
push(@envkeys,'minimal');
}
}
} elsif ($saved eq 'file') {
if ($minimal || $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}) {
push(@envkeys,'minimal');
}
} elsif ($saved eq 'minimal') {
if ($uploaded || $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}) {
push(@envkeys,'uploaded');
}
}
if (@envkeys > 0) {
foreach my $item (@envkeys) {
my $key = $item.'syllabus';
if ($courseenv->{$key} ne '') {
&Apache::lonnet::delenv('course.'.$env{'request.course.id'}.'.'.$key);
if ($item eq 'minimal') {
&update_access_permissions($cdom,$cnum,'/syllabus/loncapa.html');
} elsif ($item eq 'uploaded') {
if ($courseenv->{$key} =~ m{^\Q/uploaded/$cdom/$cnum/portfolio\E(/syllabus/.+)$}) {
my $filename = $1;
&update_access_permissions($cdom,$cnum,$filename);
}
}
$storehash{$key} = '';
} elsif ($env{'course.'.$env{'request.course.id'}.'.'.$key} ne '') {
&Apache::lonnet::delenv('course.'.$env{'request.course.id'}.'.'.$key);
}
if ($item eq 'uploaded') {
undef($uploaded);
}
if ($item eq 'external') {
undef($external);
}
if ($item eq 'minimal') {
undef($minimal);
}
}
}
if (keys(%storehash) > 0) {
&Apache::lonnet::put('environment',\%storehash,$cdom,$cnum);
}
return ($uploaded,$minimal,$external);
}
sub update_access_permissions {
my ($cdom,$cnum,$file_name) = @_;
my $current_permissions = &Apache::lonnet::get_portfile_permissions($cdom,$cnum);
my %access_controls =
&Apache::lonnet::get_access_controls($current_permissions,'',$file_name);
if (keys(%access_controls) > 0) {
my %changes;
foreach my $key (keys(%{$access_controls{$file_name}})) {
$changes{'delete'}{$key} = 1;
}
if (keys(%changes) > 0) {
my ($outcome,$deloutcome,$new_values,$translation) =
&Apache::lonnet::modify_access_controls($file_name,\%changes,
$cdom,$cnum);
}
}
return;
}
sub home_http_host {
my ($cdom,$cnum) = @_;
my $home=&Apache::lonnet::homeserver($cnum,$cdom);
if ($home ne 'no_host') {
my $hostname = &Apache::lonnet::hostname($home);
my $protocol = $Apache::lonnet::protocol{$home};
$protocol = 'http' if ($protocol ne 'https');
return $protocol.'://'.$hostname;
}
return;
}
sub process_upload {
my ($upload_output,$cnum,$cdom,$allfiles,$codebase) = @_;
my ($parseaction,$showupload,$mimetype);
my $dest = 'portfolio/syllabus';
if ($env{'form.parserflag'}) {
$parseaction = 'parse';
}
my $url=&Apache::lonnet::userfileupload('syllabusfile','syllabus',$dest,
$parseaction,$allfiles,
$codebase,undef,undef,undef,undef,
undef,undef,\$mimetype);
if ($url =~ m{^/uploaded/\Q$cdom\E/\Q$cnum\E.*/([^/]+)$}) {
my $stored = $1;
$showupload = '<p>'.&mt('Uploaded [_1]',
'<span class="LC_filename">'.$stored.'</span>').
'</p>';
} else {
my ($filename) = ($env{'form.syllabusfile.filename'} =~ m{([^/]+)$});
$$upload_output = '<div class="LC_error" id="uploadfileresult">'.
&mt('Unable to save file [_1].',
'<span class="LC_filename">'.$filename.'</span>').
'</div>';
return ();
}
my $needlink;
if (($parseaction eq 'parse') && ($mimetype eq 'text/html')) {
$$upload_output = $showupload;
my $total_embedded = scalar(keys(%{$allfiles}));
if ($total_embedded > 0) {
my $uploadphase = 'upload_embedded';
my $primaryurl = &HTML::Entities::encode($url,'<>&"');
my $state = &embedded_form_elems($uploadphase,$primaryurl);
my $actionurl = "/public/$cdom/$cnum/syllabus";
my ($embedded,$num,$numpathchanges,$existing);
($embedded,$num,$numpathchanges,$existing) =
&Apache::loncommon::ask_for_embedded_content($actionurl,$state,
$allfiles,$codebase,
{'error_on_invalid_names' => 1,
'ignore_remote_references' => 1,});
if ($embedded) {
$needlink = 1;
if ($num) {
$$upload_output .=
'<p>'.&mt('This file contains embedded multimedia objects, which need to be uploaded.').'</p>'.$embedded;
} elsif ($numpathchanges) {
$$upload_output .= $embedded;
} else {
$$upload_output .= $embedded;
&Apache::loncommon::modify_html_refs('syllabus','portfolio/syllabus',
$cnum,$cdom,'/userfiles',$url);
}
} else {
$$upload_output .= &mt('Embedded item(s) already present, so no additional upload(s) required').'<br />';
&Apache::loncommon::modify_html_refs('syllabus','portfolio/syllabus',
$cnum,$cdom,'/userfiles',$url);
}
} else {
$$upload_output .= &mt('No embedded items identified').'<br />';
}
$$upload_output = '<div id="uploadfileresult">'.$$upload_output.'</div>';
}
return ($url,$needlink);
}
sub embedded_form_elems {
my ($phase,$primaryurl) = @_;
return <<STATE;
<input type="hidden" name="forceedit" value="1" />
<input type="hidden" name="cmd" value="upload_embedded" />
<input type="hidden" name="phase" value="$phase" />
<input type="hidden" name="primaryurl" value="$primaryurl" />
STATE
}
sub return_to_editor {
my ($cdom,$cnum) = @_;
my $actionurl = "/public/$cdom/$cnum/syllabus";
return '<p><form name="backtoeditor" method="post" action="'.$actionurl.'" />'.
'<input type="hidden" name="forceedit" value="1" />'."\n".
'<a href="javascript:document.backtoeditor.submit();">'.&mt('Return to Editor').
'</a></p>';
}
sub editfile_button {
my ($url,$context,$editable) = @_;
my $edittext=&mt('Edit');
my $deltext=&mt('Delete');
my $output;
if ($editable) {
$output = '
<input type="button" value="'.$edittext.'" onclick="javascript:gotoeditor('."'$url'".');" name="edit_'.$context.'" />
';
}
$output .= '
<input type="button" value="'.$deltext.'" onclick="javascript:dodelete('."'$context'".');" name="del_'.$context.'" />
<input type="hidden" value="" name="deleteuploaded_'.$context.'" id="deleteuploaded_'.$context.'" />
';
return $output;
}
sub editbutton_js {
my %js_lt = &Apache::lonlocal::texthash(
min => 'Are you sure you want to delete the contents of the syllabus template?',
file => 'Are you sure you want to delete the uploaded syllabus file?',
noundo => 'This action cannot be reversed.'
);
&js_escape(\%js_lt);
return <<ENDJS;
<script type="text/javascript">
// <![CDATA[
function gotoeditor(url) {
document.location.href = url+'?editmode=1&forceedit=1';
}
function dodelete(caller,url) {
if (document.getElementById('deleteuploaded_'+caller)) {
document.getElementById('deleteuploaded_'+caller).value=1;
if (caller == 'minimal') {
if (confirm("$js_lt{'min'}"+"\\n"+"$js_lt{'noundo'}")) {
document.syllabus.submit();
}
}
if (caller == 'file') {
if (confirm("$js_lt{'file'}"+"\\n"+"$js_lt{'noundo'}")) {
document.syllabus.submit();
}
}
}
return;
}
// ]]>
</script>
ENDJS
}
sub redirect_to_http {
my ($r) = @_;
&Apache::loncommon::content_type($r,'text/html');
&Apache::loncommon::no_cache($r);
$r->send_http_header;
my $url = 'http://'.$r->hostname().$r->uri().'?usehttp=1';
$r->print(&Apache::loncommon::start_page(undef,undef,
{'redirect' => [0,$url],}).
&Apache::loncommon::end_page());
return;
}
1;
__END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>