![]() ![]() | ![]() |
- For 2.11 Backport 1.115 (modified), 1.116
1: # The LearningOnline Network 2: # Request a course 3: # 4: # $Id: lonrequestcourse.pm,v 1.95.2.8 2024/07/03 22:34:22 raeburn Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 28: ### 29: 30: =head1 NAME 31: 32: Apache::lonrequestcourse.pm 33: 34: =head1 SYNOPSIS 35: 36: Allows users to request creation of new courses. 37: 38: This is part of the LearningOnline Network with CAPA project 39: described at http://www.lon-capa.org. 40: 41: =head1 SUBROUTINES 42: 43: =over 44: 45: =item handler() 46: 47: =item get_breadcrumbs() 48: 49: =item header() 50: 51: =item form_elements() 52: 53: =item onload_action() 54: 55: =item print_main_menu() 56: 57: =item request_administration() 58: 59: =item close_popup_form() 60: 61: =item get_instcode() 62: 63: =item print_request_form() 64: 65: =item print_enrollment_menu() 66: 67: =item show_invalid_crosslists() 68: 69: =item inst_section_selector() 70: 71: =item date_setting_table() 72: 73: =item print_personnel_menu() 74: 75: =item print_request_status() 76: 77: =item print_request_logs() 78: 79: =item print_review() 80: 81: =item dates_from_form() 82: 83: =item courseinfo_form() 84: 85: =item clone_form() 86: 87: =item clone_text() 88: 89: =item coursecode_form() 90: 91: =item get_course_dom() 92: 93: =item display_navbuttons() 94: 95: =item print_request_outcome() 96: 97: =item check_autolimit() 98: 99: =item retrieve_settings() 100: 101: =item get_request_settings() 102: 103: =item extract_instcode() 104: 105: =item generate_date_items() 106: 107: =back 108: 109: =cut 110: 111: package Apache::lonrequestcourse; 112: 113: use strict; 114: use Apache::Constants qw(:common :http); 115: use Apache::lonnet; 116: use Apache::loncommon; 117: use Apache::lonlocal; 118: use Apache::loncoursequeueadmin; 119: use Apache::lonuserutils; 120: use LONCAPA qw(:DEFAULT :match); 121: 122: my $registered_flush; 123: my $registered_instcats; 124: my $modified_dom; 125: 126: sub handler { 127: my ($r) = @_; 128: &Apache::loncommon::content_type($r,'text/html'); 129: $r->send_http_header; 130: if ($r->header_only) { 131: return OK; 132: } 133: 134: $registered_flush = 0; 135: $registered_instcats = 0; 136: $modified_dom = ''; 137: 138: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, 139: ['action','showdom','cnum','state','crstype','queue','tabs']); 140: &Apache::lonhtmlcommon::clear_breadcrumbs(); 141: my $dom = &get_course_dom(); 142: my $action = $env{'form.action'}; 143: my $state = $env{'form.state'}; 144: my (%states,%stored); 145: my ($jscript,$uname,$udom,$result,$warning,$showcredits,$instcredits,%can_request, 146: %request_domains,@incdoms); 147: my %domdefs = &Apache::lonnet::get_domain_defaults($dom); 148: if ($domdefs{'officialcredits'} || $domdefs{'unofficialcredits'} || $domdefs{'textbookcredits'}) { 149: $showcredits = 1; 150: } 151: 152: my $canreq = 153: &Apache::lonnet::check_can_request($dom,\%can_request,\%request_domains); 154: 155: foreach my $item (keys(%request_domains)) { 156: if (ref($request_domains{$item}) eq 'ARRAY') { 157: foreach my $possdom (@{$request_domains{$item}}) { 158: unless(grep(/^\Q$possdom\E$/,@incdoms)) { 159: push(@incdoms,$possdom); 160: } 161: } 162: } 163: } 164: 165: if ($canreq) { 166: if (($env{'form.crstype'} eq 'textbook') || 167: (scalar(keys(%can_request)) == 1) && ($can_request{'textbook'})) { 168: my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); 169: if ($action eq 'log') { 170: my $usetabs; 171: if ((scalar(keys(%can_request)) == 1) && ($can_request{'textbook'})) { 172: $usetabs = 1; 173: } elsif ($env{'form.tabs'} eq 'on') { 174: $usetabs = 1; 175: } 176: &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'}); 177: my $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'); 178: &print_request_logs($r,$dom,undef,undef,$crumb,$usetabs); 179: } elsif ($action eq 'process') { 180: if ($can_request{'textbook'}) { 181: &process_textbook_request($r,$dom,$action,\%domdefs,\%domconfig,\%can_request); 182: } else { 183: &textbook_request_disabled($r,$dom,$action,\%can_request); 184: } 185: } elsif ($action eq 'display') { 186: my ($uname,$udom,$result,$warning) = &domcoord_display($dom); 187: if ($warning ne '') { 188: my $args = { only_body => 1 }; 189: $r->print(&header('Course/Community Requests','','' ,'',$args). 190: '<h3>'.&mt('Course/Community Request Details').'</h3>'. 191: '<div class="LC_warning">'.$warning.'</div>'. 192: &close_popup_form()); 193: } else { 194: $states{'display'} = ['details']; 195: my $loaditems = &onload_action($action,$state); 196: my $page = 0; 197: &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, 198: $loaditems,'','','','','',$showcredits,'','', 199: $uname,$udom); 200: } 201: } else { 202: if ($can_request{'textbook'}) { 203: &print_textbook_form($r,$dom,\@incdoms,\%domdefs,$domconfig{'requestcourses'},\%can_request); 204: } else { 205: &textbook_request_disabled($r,$dom,$action,\%can_request); 206: } 207: } 208: return OK; 209: } 210: } 211: 212: $states{'display'} = ['details']; 213: $states{'view'} = ['pick_request','details','cancel','removal']; 214: $states{'log'} = ['display']; 215: $states{'new'} = ['courseinfo','enrollment','personnel','review','process']; 216: 217: if (($action eq 'new') && ($env{'form.crstype'} eq 'official')) { 218: unless ($env{'form.state'} eq 'crstype') { 219: unshift(@{$states{'new'}},'codepick'); 220: } 221: } 222: 223: if (($action eq 'new') && (&Apache::loncoursequeueadmin::author_prompt())) { 224: if (ref($states{$action}) eq 'ARRAY') { 225: push(@{$states{$action}},'reqauthor'); 226: } 227: } 228: 229: foreach my $key (keys(%states)) { 230: if (ref($states{$key}) eq 'ARRAY') { 231: unshift (@{$states{$key}},'crstype'); 232: } 233: } 234: 235: my @invalidcrosslist; 236: my %trail = ( 237: crstype => 'Pick Action', 238: codepick => 'Category', 239: courseinfo => 'Description', 240: enrollment => 'Access Dates', 241: personnel => 'Personnel', 242: review => 'Review', 243: process => 'Result', 244: reqauthor => 'Authoring Space Result', 245: pick_request => 'Display Summary', 246: details => 'Request Details', 247: cancel => 'Cancel Request', 248: removal => 'Outcome', 249: display => 'Request Logs', 250: ); 251: 252: if (($env{'form.crstype'} eq 'official') && (&Apache::lonnet::auto_run('',$dom))) { 253: $trail{'enrollment'} = 'Enrollment'; 254: } 255: 256: my ($page,$crumb,$newinstcode,$codechk,$checkedcode,$description) = 257: &get_breadcrumbs($dom,$action,\$state,\%states,\%trail); 258: if ($action eq 'display') { 259: ($uname,$udom,$result,$warning) = &domcoord_display($dom); 260: } elsif ((defined($state)) && (defined($action))) { 261: if (($action eq 'view') && ($state eq 'details')) { 262: if ((defined($env{'form.showdom'})) && (defined($env{'form.cnum'}))) { 263: my $result = &retrieve_settings($env{'form.showdom'},$env{'form.cnum'}); 264: } 265: } elsif ($env{'form.crstype'} eq 'official') { 266: if (&Apache::lonnet::auto_run('',$dom)) { 267: if (($action eq 'new') && (($state eq 'enrollment') || 268: ($state eq 'personnel'))) { 269: my $checkcrosslist = 0; 270: for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { 271: if ($env{'form.crosslist_'.$i}) { 272: $checkcrosslist ++; 273: } 274: } 275: if ($checkcrosslist) { 276: my %codechk; 277: my (@codetitles,%cat_titles,%cat_order,@code_order,$lastitem); 278: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles, 279: \%cat_titles, 280: \%cat_order, 281: \@code_order); 282: my $numtitles = scalar(@codetitles); 283: if ($numtitles) { 284: for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { 285: if ($env{'form.crosslist_'.$i}) { 286: my $codecheck; 287: my $crosslistcode = ''; 288: foreach my $item (@code_order) { 289: $crosslistcode .= $env{'form.crosslist_'.$i.'_'.$item}; 290: } 291: if ($crosslistcode ne '') { 292: ($codechk{$i}, my $rest) = 293: &Apache::lonnet::auto_validate_instcode('',$dom,$crosslistcode); 294: } 295: unless ($codechk{$i} eq 'valid') { 296: $env{'form.crosslist_'.$i} = ''; 297: push(@invalidcrosslist,$crosslistcode); 298: } 299: } 300: } 301: } 302: } 303: } 304: } 305: } 306: (my $elements,$instcredits) = &form_elements($dom,$showcredits); 307: my $elementsref = {}; 308: if ((ref($elements) eq 'HASH') && (ref($elements->{$action}) eq 'HASH')) { 309: if (ref($elements->{$action}{$state}) eq 'HASH') { 310: $elementsref = $elements->{$action}{$state}; 311: } 312: } 313: if (($state eq 'courseinfo') && ($env{'form.clonedom'} eq '')) { 314: $env{'form.clonedom'} = $dom; 315: } 316: if ($state eq 'crstype') { 317: $jscript = &mainmenu_javascript(); 318: } else { 319: $jscript = &Apache::lonhtmlcommon::set_form_elements($elementsref,\%stored); 320: if ($state eq 'courseinfo') { 321: $jscript .= &cloning_javascript(); 322: } 323: } 324: } 325: 326: if ($state eq 'personnel') { 327: $jscript .= "\n".&Apache::loncommon::userbrowser_javascript(); 328: } 329: 330: my $loaditems = &onload_action($action,$state); 331: 332: if ($action eq 'new') { 333: if ($canreq) { 334: if ($state eq 'crstype') { 335: &print_main_menu($r,\%can_request,\%states,$dom,$jscript,$loaditems, 336: $crumb,\@incdoms); 337: } else { 338: &request_administration($r,$action,$state,$page,\%states,$dom, 339: $jscript,$loaditems,$crumb,$newinstcode, 340: $codechk,$checkedcode,$description, 341: $showcredits,$instcredits,\@invalidcrosslist); 342: } 343: } else { 344: $r->print(&header('Course/Community Requests').$crumb. 345: '<div class="LC_warning">'. 346: &mt('You do not have privileges to request creation of courses or communities.'). 347: '</div>'.&Apache::loncommon::end_page()); 348: } 349: } elsif ($action eq 'view') { 350: if ($state eq 'crstype') { 351: &print_main_menu($r,\%can_request,\%states,$dom,$jscript,$loaditems,$crumb,\@incdoms); 352: } else { 353: &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, 354: $loaditems,$crumb,'','','','',$showcredits); 355: } 356: } elsif ($action eq 'display') { 357: if ($warning ne '') { 358: my $args = { only_body => 1 }; 359: $r->print(&header('Course/Community Requests','','' ,'',$args).$crumb. 360: '<h3>'.&mt('Course/Community Request Details').'</h3>'. 361: '<div class="LC_warning">'.$warning.'</div>'. 362: &close_popup_form()); 363: } else { 364: &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, 365: $loaditems,$crumb,'','','','',$showcredits,'','', 366: $uname,$udom); 367: } 368: } elsif ($action eq 'log') { 369: if ($state eq 'crstype') { 370: &print_main_menu($r,\%can_request,\%states,$dom,$jscript,'',$crumb,\@incdoms); 371: } else { 372: $jscript .= <<ENDJS; 373: 374: function backPage(formname,prevstate) { 375: formname.state.value = prevstate; 376: formname.submit(); 377: } 378: 379: function setPage(formname) { 380: formname.page.value = '1'; 381: return; 382: } 383: 384: ENDJS 385: &print_request_logs($r,$dom,$jscript,$loaditems,$crumb,\%can_request); 386: } 387: } else { 388: &print_main_menu($r,\%can_request,\%states,$dom,$jscript,'',$crumb,\@incdoms); 389: } 390: return OK; 391: } 392: 393: sub mainmenu_javascript { 394: return <<"END"; 395: function setType(courseForm) { 396: for (var i=0; i<courseForm.crstype.length; i++) { 397: if (courseForm.crstype.options[i].value == "$env{'form.crstype'}") { 398: courseForm.crstype.options[i].selected = true; 399: } else { 400: courseForm.crstype.options[i].selected = false; 401: } 402: } 403: } 404: 405: function setAction(courseForm) { 406: for (var i=0; i<courseForm.action.length; i++) { 407: if (courseForm.action.options[i].value == "$env{'form.action'}") { 408: courseForm.action.options[i].selected = true; 409: } else { 410: courseForm.action.options[i].selected = false; 411: } 412: } 413: } 414: END 415: } 416: 417: sub cloning_javascript { 418: return <<"END"; 419: function setCloneDisplay(courseForm) { 420: if (courseForm.cloning.length > 1) { 421: for (var i=0; i<courseForm.cloning.length; i++) { 422: if (courseForm.cloning[i].checked) { 423: if (courseForm.cloning[i].value == 1) { 424: document.getElementById('cloneoptions').style.display="block"; 425: } 426: } 427: } 428: } 429: } 430: END 431: } 432: 433: sub get_breadcrumbs { 434: my ($dom,$action,$state,$states,$trail) = @_; 435: my ($crumb,$newinstcode,$codechk,$checkedcode,$numtitles,$description); 436: my $page = 0; 437: if ((ref($states) eq 'HASH') && (ref($trail) eq 'HASH') && (ref($state))) { 438: if (defined($action)) { 439: my $done = 0; 440: my $i=0; 441: if (ref($states->{$action}) eq 'ARRAY') { 442: while ($i<@{$states->{$action}} && !$done) { 443: if ($states->{$action}[$i] eq $$state) { 444: $page = $i; 445: $done = 1; 446: } 447: $i++; 448: } 449: } 450: if ($env{'form.crstype'} eq 'official') { 451: if ($page > 1) { 452: if ($states->{$action}[$page-1] eq 'codepick') { 453: if ($env{'form.instcode'} eq '') { 454: ($newinstcode,$numtitles) = &get_instcode($dom); 455: if ($numtitles) { 456: if ($newinstcode eq '') { 457: $$state = 'codepick'; 458: $page --; 459: } else { 460: ($codechk,$description) = 461: &Apache::lonnet::auto_validate_instcode('', 462: $dom,$newinstcode); 463: if ($codechk ne 'valid') { 464: $$state = 'codepick'; 465: $page --; 466: } 467: $checkedcode = 1; 468: } 469: } 470: } 471: } 472: } 473: } 474: if (ref($states->{$action}) eq 'ARRAY') { 475: for (my $i=0; $i<@{$states->{$action}}; $i++) { 476: if ($$state eq $states->{$action}[$i]) { 477: &Apache::lonhtmlcommon::add_breadcrumb( 478: {text=>"$trail->{$$state}"}); 479: $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course/Community Requests','Course_Requests'); 480: last; 481: } else { 482: if (($$state eq 'process') || ($$state eq 'removal') || ($$state eq 'reqauthor')) { 483: &Apache::lonhtmlcommon::add_breadcrumb( 484: { href => '/adm/requestcourse', 485: text => "$trail->{$states->{$action}[$i]}", 486: } 487: ); 488: } else { 489: &Apache::lonhtmlcommon::add_breadcrumb( 490: { href => "javascript:backPage(document.requestcrs,'$states->{$action}[$i]')", 491: text => "$trail->{$states->{$action}[$i]}", } 492: ); 493: } 494: } 495: } 496: } 497: } else { 498: &Apache::lonhtmlcommon::add_breadcrumb( 499: {text=>'Pick Action'}); 500: $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course/Community Requests','Course_Requests'); 501: } 502: } else { 503: &Apache::lonhtmlcommon::add_breadcrumb( 504: {text=>'Pick Action'}); 505: $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course/Community Requests','Course_Requests'); 506: } 507: return ($page,$crumb,$newinstcode,$codechk,$checkedcode,$description); 508: } 509: 510: sub header { 511: my ($bodytitle,$jscript,$loaditems,$jsextra,$args) = @_; 512: if ($jscript) { 513: $jscript = '<script type="text/javascript">'."\n". 514: '// <![CDATA['."\n". 515: $jscript."\n".'// ]]>'."\n".'</script>'."\n"; 516: } 517: if ($loaditems) { 518: if (ref($args) eq 'HASH') { 519: my %loadhash = ( 520: 'add_entries' => $loaditems, 521: ); 522: my %arghash = (%loadhash,%{$args}); 523: $args = \%arghash; 524: } else { 525: $args = {'add_entries' => $loaditems,}; 526: } 527: } 528: return &Apache::loncommon::start_page($bodytitle,$jscript.$jsextra,$args); 529: } 530: 531: sub form_elements { 532: my ($dom,$showcredits) = @_; 533: my $instcredits; 534: my %elements = 535: ( 536: new => { 537: crstype => { 538: crstype => 'selectbox', 539: action => 'selectbox', 540: origcnum => 'hidden', 541: }, 542: courseinfo => { 543: cdescr => 'text', 544: cloning => 'radio', 545: clonecrs => 'text', 546: clonedom => 'selectbox', 547: datemode => 'radio', 548: dateshift => 'text', 549: }, 550: enrollment => { 551: accessstart_month => 'selectbox', 552: accessstart_hour => 'selectbox', 553: accessend_month => 'selectbox', 554: accessend_hour => 'selectbox', 555: accessstart_day => 'text', 556: accessstart_year => 'text', 557: accessstart_minute => 'text', 558: accessstart_second => 'text', 559: accessend_day => 'text', 560: accessend_year => 'text', 561: accessend_minute => 'text', 562: accessend_second => 'text', 563: no_end_date => 'checkbox', 564: }, 565: personnel => { 566: addperson => 'checkbox', 567: }, 568: review => { 569: cnum => 'hidden', 570: }, 571: }, 572: view => { 573: crstype => { 574: crstype => 'selectbox', 575: action => 'selectbox', 576: }, 577: }, 578: ); 579: my %servers = &Apache::lonnet::get_servers($dom,'library'); 580: my $numlib = keys(%servers); 581: if ($numlib > 1) { 582: $elements{'new'}{'courseinfo'}{'chome'} = 'selectbox'; 583: } else { 584: $elements{'new'}{'courseinfo'}{'chome'} = 'hidden'; 585: } 586: my (@codetitles,%cat_titles,%cat_order,@code_order,$lastitem); 587: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 588: \%cat_order,\@code_order); 589: my $numtitles = scalar(@codetitles); 590: if ($numtitles) { 591: my %extras; 592: $lastitem = pop(@codetitles); 593: $extras{'instcode_'.$lastitem} = 'text'; 594: foreach my $item (@codetitles) { 595: $extras{'instcode_'.$item} = 'selectbox'; 596: } 597: $elements{'new'}{'codepick'} = \%extras; 598: } 599: if (&Apache::lonnet::auto_run('',$dom)) { 600: my %extras = ( 601: enrollstart_month => 'selectbox', 602: enrollstart_hour => 'selectbox', 603: enrollend_month => 'selectbox', 604: enrollend_hour => 'selectbox', 605: enrollstart_day => 'text', 606: enrollstart_year => 'text', 607: enrollstart_minute => 'text', 608: enrollstart_second => 'text', 609: enrollend_day => 'text', 610: enrollend_year => 'text', 611: enrollend_minute => 'text', 612: enrollend_second => 'text', 613: addcrosslist => 'checkbox', 614: autoadds => 'radio', 615: autodrops => 'radio', 616: ); 617: my ($instcode,$titlescount) = &get_instcode($dom); 618: if ($instcode) { 619: my @sections = &Apache::lonnet::auto_get_sections(undef,$dom,$instcode); 620: if (@sections) { 621: $extras{'sectotal'} = 'hidden'; 622: if ($env{'form.sectotal'} > 0) { 623: for (my $i=0; $i<$env{'form.sectotal'}; $i++) { 624: $extras{'sec_'.$i} = 'radio'; 625: $extras{'secnum_'.$i} = 'text'; 626: $extras{'loncapasec_'.$i} = 'text'; 627: } 628: } 629: } else { 630: $extras{'addsection'} = 'checkbox'; 631: my $sectotal = $env{'form.sectotal'}; 632: if ($env{'form.addsection'}) { 633: $sectotal ++; 634: } 635: for (my $i=0; $i<$sectotal; $i++) { 636: $extras{'sec_'.$i} = 'checkbox'; 637: $extras{'secnum_'.$i} = 'text', 638: $extras{'loncapasec_'.$i} = 'text', 639: } 640: } 641: (my $outcome,my $desc,$instcredits) = 642: &Apache::lonnet::auto_validate_instcode(undef,$dom,$instcode); 643: if ($showcredits && $instcredits eq '') { 644: $extras{'coursecredits'} = 'text'; 645: } 646: } elsif (($env{'form.crstype'} eq 'unofficial') || ($env{'form.crstype'} eq 'textbook')) { 647: if ($showcredits) { 648: $extras{'coursecredits'} = 'text'; 649: } 650: } 651: my $crosslisttotal = $env{'form.crosslisttotal'}; 652: if ($env{'form.addcrosslist'}) { 653: $crosslisttotal ++; 654: } 655: if (!$crosslisttotal) { 656: $crosslisttotal = 1; 657: } 658: for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { 659: if ($numtitles) { 660: $extras{'crosslist_'.$i.'_'.$lastitem} = 'text'; 661: } 662: if (@codetitles > 0) { 663: foreach my $item (@codetitles) { 664: $extras{'crosslist_'.$i.'_'.$item} = 'selectbox'; 665: } 666: } 667: $extras{'crosslist_'.$i} = 'checkbox'; 668: $extras{'crosslist_'.$i.'_instsec'} = 'text', 669: $extras{'crosslist_'.$i.'_lcsec'} = 'text', 670: } 671: my %mergedhash = (%{$elements{'new'}{'enrollment'}},%extras); 672: %{$elements{'new'}{'enrollment'}} = %mergedhash; 673: } 674: my %people; 675: my $persontotal = $env{'form.persontotal'}; 676: if ($env{'form.addperson'}) { 677: $persontotal ++; 678: } 679: if ((!defined($persontotal)) || (!$persontotal)) { 680: $persontotal = 1; 681: } 682: for (my $i=0; $i<$persontotal; $i++) { 683: $people{'person_'.$i.'_uname'} = 'text', 684: $people{'person_'.$i.'_dom'} = 'selectbox', 685: $people{'person_'.$i.'_hidedom'} = 'hidden', 686: $people{'person_'.$i.'_firstname'} = 'text', 687: $people{'person_'.$i.'_lastname'} = 'text', 688: $people{'person_'.$i.'_emailaddr'} = 'text', 689: $people{'person_'.$i.'_role'} = 'selectbox', 690: $people{'person_'.$i.'_sec'} = 'selectbox', 691: $people{'person_'.$i.'_newsec'} = 'text', 692: } 693: my %personnelhash = (%{$elements{'new'}{'personnel'}},%people); 694: %{$elements{'new'}{'personnel'}} = %personnelhash; 695: return (\%elements,$instcredits);; 696: } 697: 698: sub onload_action { 699: my ($action,$state) = @_; 700: my %loaditems; 701: if (($action eq 'new') || ($action eq 'view')) { 702: if ($state eq 'crstype') { 703: $loaditems{'onload'} = 'javascript:setAction(document.mainmenu_action);javascript:setType(document.mainmenu_coursetype)'; 704: } else { 705: $loaditems{'onload'} = 'javascript:setFormElements(document.requestcrs);'; 706: } 707: if ($state eq 'courseinfo') { 708: $loaditems{'onload'} .= 'javascript:setCloneDisplay(document.requestcrs);'; 709: } 710: } 711: return \%loaditems; 712: } 713: 714: sub print_main_menu { 715: my ($r,$can_request,$states,$dom,$jscript,$loaditems,$crumb,$incdoms) = @_; 716: my ($types,$typename) = &Apache::loncommon::course_types(); 717: my $onchange = 'this.form.submit()'; 718: my $nextstate_setter = "\n"; 719: if (ref($states) eq 'HASH') { 720: foreach my $key (keys(%{$states})) { 721: if (ref($states->{$key}) eq 'ARRAY') { 722: $nextstate_setter .= 723: " if (actionchoice == '$key') { 724: nextstate = '".$states->{$key}[1]."'; 725: } 726: "; 727: } 728: } 729: } 730: 731: my $js = <<"END"; 732: 733: function nextPage(formname) { 734: var crschoice = document.mainmenu_coursetype.crstype.value; 735: var actionchoice = document.mainmenu_action.action.value; 736: if (check_can_request(crschoice,actionchoice) == true) { 737: if ((actionchoice == 'new') && (crschoice == 'official')) { 738: nextstate = 'codepick'; 739: } else { 740: $nextstate_setter 741: } 742: formname.crstype.value = crschoice; 743: formname.action.value = actionchoice; 744: formname.state.value= nextstate; 745: formname.submit(); 746: } 747: return; 748: } 749: 750: function check_can_request(crschoice,actionchoice) { 751: var official = ''; 752: var unofficial = ''; 753: var community = ''; 754: var textbook = ''; 755: END 756: if (ref($can_request) eq 'HASH') { 757: foreach my $item (keys(%{$can_request})) { 758: $js .= " 759: $item = 1; 760: "; 761: } 762: } 763: my %js_lt = &Apache::lonlocal::texthash( 764: official => 'You are not permitted to request creation of an official course in this domain.', 765: unofficial => 'You are not permitted to request creation of an unofficial course in this domain.', 766: community => 'You are not permitted to request creation of a community in this domain.', 767: textbook => 'You are not permitted to request creation of a textbook course in this domain', 768: all => 'You must choose a specific course type when making a new course request.', 769: allt => '"All types" is not allowed.', 770: ); 771: &js_escape(\%js_lt); 772: $js .= <<END; 773: if (crschoice == 'official') { 774: if (official != 1) { 775: alert("$js_lt{'official'}"); 776: return false; 777: } 778: } else { 779: if (crschoice == 'unofficial') { 780: if (unofficial != 1) { 781: alert("$js_lt{'unofficial'}"); 782: return false; 783: } 784: } else { 785: if (crschoice == 'community') { 786: if (community != 1) { 787: alert("$js_lt{'community'}"); 788: return false; 789: } 790: } else { 791: if (crschoice == 'textbook') { 792: if (textbook != 1) { 793: alert("$js_lt{'textbook'}"); 794: return false; 795: } 796: } else { 797: if (actionchoice == 'new') { 798: alert('$js_lt{'all'}'+'\\n'+'$js_lt{'allt'}'); 799: return false; 800: } 801: } 802: } 803: } 804: } 805: return true; 806: } 807: END 808: my ($pagetitle,$pageinfo,$domaintitle,$earlyout); 809: if (ref($can_request) eq 'HASH') { 810: if (($can_request->{'official'}) || ($can_request->{'unofficial'}) || $can_request->{'textbook'}) { 811: if ($can_request->{'community'}) { 812: $pagetitle = 'Course/Community Requests'; 813: $pageinfo = &mt('Request creation of a new course or community, or review your pending requests.'); 814: $domaintitle = &mt('Course/Community Domain'); 815: } else { 816: $pagetitle = 'Course Requests'; 817: $pageinfo = &mt('Request creation of a new course, or review your pending course requests.'); 818: $domaintitle = &mt('Course Domain'); 819: } 820: } elsif ($can_request->{'community'}) { 821: $pagetitle = 'Community Requests'; 822: $pageinfo = &mt('Request creation of a new course, or review your pending requests.'); 823: $domaintitle = &mt('Community Domain'); 824: } elsif ((ref($incdoms) eq 'ARRAY') && ((@{$incdoms} > 1) || 825: ((@{$incdoms} == 1) && ($incdoms->[0] ne $dom)))) { 826: $pagetitle = 'Course/Community Requests'; 827: $pageinfo = &mt('You do not have rights to request creation of courses in this domain; please choose a different domain.'); 828: $domaintitle = &mt('Course/Community Domain'); 829: } else { 830: $pagetitle = 'Course/Community Requests'; 831: $pageinfo = &mt('You do not have rights to request creation of courses or communities.'); 832: $earlyout = 1; 833: } 834: } 835: $r->print(&header($pagetitle,$js.$jscript,$loaditems).$crumb. 836: '<p>'.$pageinfo.'</p>'); 837: if ($earlyout) { 838: $r->print(&Apache::loncommon::end_page()); 839: return; 840: } 841: $r->print('<div>'. 842: &Apache::lonhtmlcommon::start_pick_box(). 843: &Apache::lonhtmlcommon::row_title($domaintitle). 844: '<form name="domforcourse" method="post" action="/adm/requestcourse">'. 845: &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms)); 846: if (!$onchange) { 847: $r->print(' <input type="submit" name="godom" value="'. 848: &mt('Change').'" />'); 849: } 850: unless ((ref($can_request) eq 'HASH') && (keys(%{$can_request}) > 0)) { 851: $r->print('</form>'.&Apache::lonhtmlcommon::row_closure(1)."\n". 852: &Apache::lonhtmlcommon::end_pick_box().'</div>'."\n". 853: &Apache::loncommon::end_page()); 854: return; 855: } 856: $r->print('</form>'.&Apache::lonhtmlcommon::row_closure()); 857: my $formname = 'requestcrs'; 858: my $nexttext = &mt('Next'); 859: $r->print(&Apache::lonhtmlcommon::row_title(&mt('Action')).' 860: <form name="mainmenu_action" method="post" action=""> 861: <select size="1" name="action" > 862: <option value="new">'.&mt('New request').'</option> 863: <option value="view">'.&mt('View/Modify/Cancel pending requests').'</option> 864: <option value="log">'.&mt('View request history').'</option> 865: </select></form>'. 866: &Apache::lonhtmlcommon::row_closure(). 867: &Apache::lonhtmlcommon::row_title(&mt('Type')).' 868: <form name="mainmenu_coursetype" method="post" action=""> 869: <select size="1" name="crstype">'); 870: if (ref($can_request) eq 'HASH') { 871: if (keys(%{$can_request}) > 1) { 872: $r->print(' <option value="any">'.&mt('All types').'</option>'); 873: } 874: if ((ref($types) eq 'ARRAY') && (ref($typename) eq 'HASH')) { 875: foreach my $type (@{$types}) { 876: next unless($can_request->{$type}); 877: my $selected = ''; 878: if ($env{'form.crstype'} eq '') { 879: if ($type eq 'official') { 880: $selected = ' selected="selected"'; 881: } 882: } else { 883: if ($type eq $env{'form.crstype'}) { 884: $selected = ' selected="selected"'; 885: } 886: } 887: $r->print('<option value="'.$type.'"'.$selected.'>'.&mt($typename->{$type}). 888: '</option>'."\n"); 889: } 890: } 891: } 892: $r->print('</select></form>'."\n". 893: &Apache::lonhtmlcommon::row_closure(1)."\n". 894: &Apache::lonhtmlcommon::end_pick_box().'</div>'."\n". 895: '<div><form name="'.$formname.'" method="post" action="/adm/requestcourse">'."\n". 896: '<input type="hidden" name="state" value="crstype" />'."\n". 897: '<input type="hidden" name="showdom" value="'.$dom.'" />'."\n". 898: '<input type="hidden" name="crstype" value="" />'."\n". 899: '<input type="hidden" name="action" value="" />'."\n". 900: '<input type="button" name="next" value="'.$nexttext. 901: '" onclick="javascript:nextPage(document.'.$formname.')" />'."\n". 902: '</form></div>'); 903: $r->print(&Apache::loncommon::end_page()); 904: return; 905: } 906: 907: sub request_administration { 908: my ($r,$action,$state,$page,$states,$dom,$jscript,$loaditems,$crumb, 909: $newinstcode,$codechk,$checkedcode,$description,$showcredits, 910: $instcredits,$invalidcrosslist,$uname,$udom) = @_; 911: my $js; 912: if (($action eq 'new') || (($action eq 'view') && ($state eq 'pick_request'))) { 913: $js = <<END; 914: 915: function nextPage(formname,nextstate) { 916: formname.state.value= nextstate; 917: formname.submit(); 918: } 919: 920: END 921: } 922: if (($action eq 'new') || ($action eq 'view')) { 923: $js .= <<END; 924: 925: function backPage(formname,prevstate) { 926: formname.state.value = prevstate; 927: formname.submit(); 928: } 929: 930: END 931: } 932: if ($action eq 'new') { 933: my $jsextra; 934: if (($state eq 'courseinfo') || ($state eq 'codepick')) { 935: $jsextra = "\n".&Apache::loncommon::coursebrowser_javascript($dom,'','','','','', 936: $newinstcode); 937: } elsif ($state eq 'enrollment') { 938: if (($env{'form.crstype'} eq 'official') && 939: (&Apache::lonnet::auto_run('',$dom))) { 940: $js .= "\n".§ion_check_javascript()."\n".&enrollment_lcsec_js(); 941: } 942: } elsif ($state eq 'personnel') { 943: $js .= "\n".§ion_check_javascript()."\n".&personnel_lcsec_js(); 944: } 945: my $title; 946: if ($env{'form.crstype'} eq 'community') { 947: $title = 'Request a community'; 948: } else { 949: $title = 'Request a course'; 950: } 951: $r->print(&header($title,$js.$jscript,$loaditems,$jsextra).$crumb); 952: &print_request_form($r,$action,$state,$page,$states,$dom,$newinstcode, 953: $codechk,$checkedcode,$description,$showcredits, 954: $instcredits,$invalidcrosslist); 955: } elsif ($action eq 'view') { 956: my $jsextra; 957: my $formname = 'requestcrs'; 958: my $prev = $states->{$action}[$page-1]; 959: my $next = $states->{$action}[$page+1]; 960: if ($state eq 'pick_request') { 961: $next = $states->{$action}[$page+1]; 962: $jsextra = &viewrequest_javascript($formname,$next); 963: } elsif ($state eq 'details') { 964: $jsextra = &viewdetails_javascript($formname); 965: 966: } elsif ($state eq 'cancel') { 967: $jsextra = &viewcancel_javascript($formname); 968: } 969: my $title; 970: if ($env{'form.crstype'} eq 'community') { 971: $title = 'Manage community requests'; 972: } else { 973: $title = 'Manage course requests'; 974: } 975: $r->print(&header($title,$js.$jscript.$jsextra,$loaditems).$crumb); 976: my $form = '<form method="post" name="'.$formname.'" action="/adm/requestcourse" />'; 977: if ($state eq 'pick_request') { 978: my $title; 979: if ($env{'form.crstype'} eq 'community') { 980: $title = &mt('Pending community requests'); 981: } elsif ($env{'form.crstype'} eq 'official') { 982: $title = &mt('Pending requests for official courses'); 983: } elsif ($env{'form.crstype'} eq 'unofficial') { 984: $title = &mt('Pending requests for unofficial courses'); 985: } elsif ($env{'form.crstype'} eq 'textbook') { 986: $title = &mt('Pending requests for textbook courses'); 987: } else { 988: $title = &mt('Pending course/community requests'); 989: } 990: $r->print('<h3>'.$title.'</h3><div>'."\n".$form."\n". 991: &print_request_status($dom,$action).'</form></div>'); 992: } elsif ($state eq 'details') { 993: my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); 994: my $origcnum = $env{'form.cnum'}; 995: if ($origcnum eq '') { 996: $origcnum = $env{'form.origcnum'}; 997: } 998: if ($env{'form.crstype'} eq 'official') { 999: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1000: \%cat_order,\@code_order); 1001: } 1002: my $title; 1003: if ($env{'form.crstype'} eq 'community') { 1004: $title = &mt('Community Request Details'); 1005: } else { 1006: $title = &mt('Course Request Details'); 1007: } 1008: $r->print('<h3>'.$title.'</h3><div>'."\n".$form."\n". 1009: &print_review($dom,\@codetitles,\%cat_titles,\%cat_order, 1010: \@code_order,'','','','',$instcredits)."\n". 1011: '<input name="origcnum" value="'.$origcnum.'" type="hidden" />'."\n"); 1012: my @excluded = &get_excluded_elements($dom,$states,'new','review', 1013: $showcredits); 1014: push(@excluded,'origcnum'); 1015: $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).'</div>'); 1016: my $other = 'modify'; 1017: my %navtxt = &Apache::lonlocal::texthash ( 1018: prev => 'Back', 1019: other => 'Modify Request', 1020: next => 'Cancel Request', 1021: ); 1022: &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},$next, 1023: $navtxt{'next'},$state,$other,$navtxt{'other'}); 1024: $r->print('</form>'); 1025: } elsif ($state eq 'cancel') { 1026: my $title; 1027: if ($env{'form.crstype'} eq 'community') { 1028: $title = &mt('Cancel community request'); 1029: } else { 1030: $title = &mt('Cancel course request'); 1031: } 1032: my ($result,$output) = &print_cancel_request($dom,$env{'form.origcnum'}); 1033: $r->print('<h3>'.$title.'</h3><div>'."\n".$form."\n". 1034: $output); 1035: my @excluded = &get_excluded_elements($dom,$states,'view','cancel', 1036: $showcredits); 1037: $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).'</div>'); 1038: my %navtxt = &Apache::lonlocal::texthash ( 1039: prev => 'Back', 1040: next => 'Confirm Cancellation', 1041: ); 1042: if ($result eq 'ok') { 1043: &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},$next, 1044: $navtxt{'next'},$state); 1045: } else { 1046: &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},undef, 1047: '',$state); 1048: } 1049: $r->print('</form>'); 1050: } elsif ($state eq 'removal') { 1051: my $cnum = $env{'form.origcnum'}; 1052: my $statuskey = 'status:'.$dom.':'.$cnum; 1053: my %userreqhash = &Apache::lonnet::get('courserequests',[$statuskey], 1054: $env{'user.domain'},$env{'user.name'}); 1055: my $currstatus = $userreqhash{$statuskey}; 1056: my ($result,$error); 1057: if (($currstatus eq 'approval') || ($currstatus eq 'pending')) { 1058: my %status = ( 1059: $statuskey => 'cancelled', 1060: ); 1061: my $statusresult = &Apache::lonnet::put('courserequests',\%status); 1062: if ($statusresult eq 'ok') { 1063: my $delresult = 1064: &Apache::lonnet::del_dom('courserequestqueue', 1065: [$cnum.'_'.$currstatus],$dom); 1066: if ($delresult eq 'ok') { 1067: $result = 'ok'; 1068: } else { 1069: $error = &mt('An error occurred when updating the pending requests queue: [_1]',$delresult); 1070: } 1071: } else { 1072: $error = &mt("An error occurred when updating the status of this request in the requestor's records: [_1]",$statusresult); 1073: } 1074: } else { 1075: $error = &mt('The current status of this request could not be verified as pending approval/institutional action.'); 1076: } 1077: $r->print('<h3>'.&mt('Request Cancellation').'</h3><div>'."\n".$form."\n". 1078: '<input type="hidden" name="state" value="'.$state.'" />'."\n". 1079: '<input type="hidden" name="action" value="'.$action.'" />'."\n". 1080: '<input type="hidden" name="showdom" value="'.$dom.'" />'."\n". 1081: '<input type="hidden" name="orignum" value="'.$cnum.'" />'."\n"); 1082: if ($result eq 'ok') { 1083: if ($env{'form.crstype'} eq 'community') { 1084: $r->print(&mt('Your community request has been cancelled.')); 1085: } else { 1086: $r->print(&mt('Your course request has been cancelled.')); 1087: } 1088: } else { 1089: $r->print('<div class="LC_error">'. 1090: &mt('The request cancellation process was not complete.'). 1091: '<br />'.$error.'</div>'); 1092: } 1093: $r->print('</form>'); 1094: } 1095: } elsif ($action eq 'display') { 1096: my $formname = 'requestcrs'; 1097: my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); 1098: if ($env{'form.crstype'} eq 'official') { 1099: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1100: \%cat_order,\@code_order); 1101: } 1102: my ($title,$header); 1103: if ($env{'form.crstype'} eq 'community') { 1104: $title = 'Community Request'; 1105: $header = &mt('Community Request'); 1106: } else { 1107: $title = 'Course Request'; 1108: $header = &mt('Course Request'); 1109: } 1110: $r->print(&header($title,'','','',{ 'only_body' => 1}). 1111: $crumb."\n".'<h3>'.$header.'</h3>'. 1112: &print_review($dom,\@codetitles,\%cat_titles,\%cat_order, 1113: \@code_order,$uname,$udom,'','',$instcredits)."\n". 1114: '</div>'. 1115: &close_popup_form()); 1116: } 1117: $r->print(&Apache::loncommon::end_page()); 1118: return; 1119: } 1120: 1121: sub domcoord_display { 1122: my ($dom) = @_; 1123: my ($uname,$udom,$result,$warning); 1124: if (($dom eq $env{'request.role.domain'}) && (&Apache::lonnet::allowed('ccc',$dom))) { 1125: if ($env{'form.cnum'} ne '') { 1126: my $cnum = $env{'form.cnum'}; 1127: my $queue = $env{'form.queue'}; 1128: my $reqkey = $cnum.'_'.$queue; 1129: my $namespace = 'courserequestqueue'; 1130: my $domconfig = &Apache::lonnet::get_domainconfiguser($dom); 1131: my %queued = 1132: &Apache::lonnet::get($namespace,[$reqkey],$dom,$domconfig); 1133: if (ref($queued{$reqkey}) eq 'HASH') { 1134: $uname = $queued{$reqkey}{'ownername'}; 1135: $udom = $queued{$reqkey}{'ownerdom'}; 1136: if (($udom =~ /^$match_domain$/) && ($uname =~ /^$match_username$/)) { 1137: $result = &retrieve_settings($dom,$cnum,$udom,$uname); 1138: } else { 1139: if ($env{'form.crstype'} eq 'community') { 1140: $warning = &mt('Invalid username or domain for community requestor'); 1141: } else { 1142: $warning = &mt('Invalid username or domain for course requestor'); 1143: } 1144: } 1145: } else { 1146: if ($env{'form.crstype'} eq 'community') { 1147: $warning = &mt('No information was found for this community request.'); 1148: } else { 1149: $warning = &mt('No information was found for this course request.'); 1150: } 1151: } 1152: } else { 1153: $warning = &mt('No course request ID provided.'); 1154: } 1155: } else { 1156: if ($env{'form.crstype'} eq 'any') { 1157: $warning = &mt('You do not have rights to view course or community request information.'); 1158: } elsif ($env{'form.crstype'} eq 'community') { 1159: $warning = &mt('You do not have rights to view community request information.'); 1160: } else { 1161: $warning = &mt('You do not have rights to view course request information.'); 1162: } 1163: } 1164: return ($uname,$udom,$result,$warning); 1165: } 1166: 1167: sub enrollment_lcsec_js { 1168: my %alerts = §ion_check_alerts(); 1169: my $secname = $alerts{'badsec'}; 1170: my $secnone = $alerts{'reserved'}; 1171: &js_escape(\$secname); 1172: &js_escape(\$secnone); 1173: my $output = ' 1174: function validateEnrollSections(formname,nextstate) { 1175: var badsectotal = 0; 1176: var reservedtotal = 0; 1177: var secTest = ""; 1178: '; 1179: for (my $i=0; $i<$env{'form.sectotal'}; $i++) { 1180: $output .= " 1181: var selSec = 0; 1182: for (var j=0; j<document.requestcrs.sec_".$i.".length; j++) { 1183: if (document.requestcrs.sec_".$i."[j].checked) { 1184: selSec = document.requestcrs.sec_".$i."[j].value; 1185: } 1186: if (selSec == 1) { 1187: secTest = validsection(document.requestcrs.loncapasec_".$i."); 1188: if (secTest == 'badsec') { 1189: badsectotal++; 1190: } 1191: if (secTest == 'reserved') { 1192: reservedtotal++; 1193: } 1194: } 1195: } 1196: "; 1197: } 1198: for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { 1199: $output .= " 1200: if (document.requestcrs.crosslist_".$i.".checked) { 1201: secTest = validsection(document.requestcrs.crosslist_".$i."_lcsec); 1202: if (secTest == 'badsec') { 1203: badsectotal++; 1204: } 1205: if (secTest == 'reserved') { 1206: reservedtotal++; 1207: } 1208: } 1209: "; 1210: } 1211: $output .= " 1212: if (badsectotal>0) { 1213: alert('$secname'); 1214: return false; 1215: } 1216: if (reservedtotal>0) { 1217: alert('$secnone'); 1218: return false; 1219: } 1220: formname.state.value= nextstate; 1221: formname.submit(); 1222: return; 1223: } 1224: "; 1225: return $output; 1226: } 1227: 1228: sub personnel_lcsec_js { 1229: my %alerts = §ion_check_alerts(); 1230: my $secname = $alerts{'badsec'}."\n".$alerts{'separate'}; 1231: my $secnone = $alerts{'reserved'}; 1232: &js_escape(\$secname); 1233: &js_escape(\$secnone); 1234: my $output = ' 1235: function validatePersonnelSections(formname,nextstate) { 1236: var badsectotal = 0; 1237: var reservedtotal = 0; 1238: var secTest = ""; 1239: '; 1240: for (my $i=0; $i<$env{'form.persontotal'}; $i++) { 1241: $output .= " 1242: if (document.requestcrs.person_".$i."_uname.value != '') { 1243: secTest = validsection(document.requestcrs.person_".$i."_newsec,'1'); 1244: if (secTest == 'badsec') { 1245: badsectotal++; 1246: } 1247: if (secTest == 'reserved') { 1248: reservedtotal++; 1249: } 1250: } 1251: "; 1252: } 1253: $output .= " 1254: if (badsectotal > 0) { 1255: alert('$secname'); 1256: return false; 1257: } else { 1258: if (reservedtotal > 0) { 1259: alert('$secnone'); 1260: return false; 1261: } 1262: } 1263: formname.state.value = nextstate; 1264: formname.submit(); 1265: return; 1266: } 1267: "; 1268: return $output; 1269: } 1270: 1271: sub section_check_alerts { 1272: my %lt = 1273: &Apache::lonlocal::texthash( 1274: reserved => "You need to change one or more LON-CAPA section names - none is a reserved word in the system, and may not be used.", 1275: badsec => 'You need to change one or more LON-CAPA section names - names may only contain letters or numbers.', 1276: separate => 'Separate multiple sections with a comma.' 1277: ); 1278: return %lt; 1279: } 1280: 1281: sub section_check_javascript { 1282: return <<"END"; 1283: function validsection(field,mult) { 1284: var str = field.value; 1285: var badsec=0; 1286: var reserved=0; 1287: if (window.RegExp) { 1288: var badsecnum=0; 1289: var reservednum=0; 1290: var pattern=/[^a-zA-Z0-9]/; 1291: str = str.replace(/(^\\s*)|(\\s*\$)/gi,""); 1292: str = str.replace(/[ ]{2,}/gi," "); 1293: if (mult == '1') { 1294: var sections = new Array(); 1295: sections = str.split(/\\s*[\\s,;:]\\s*/); 1296: var i; 1297: for (i=0; i<sections.length; i++) { 1298: if ((sections[i] != '') && (sections[i] != undefined) && (sections[i] != null)) { 1299: if (pattern.test(sections[i])) { 1300: badsecnum++; 1301: } else { 1302: if (sections[i] == 'none') { 1303: reservednum++; 1304: } 1305: } 1306: } 1307: } 1308: } else { 1309: if ((str != '') && (str != undefined) && (str != null)) { 1310: if (pattern.test(str)) { 1311: badsecnum++; 1312: } else { 1313: if (str == 'none') { 1314: reservednum++; 1315: } 1316: } 1317: } 1318: } 1319: if (badsecnum > 0) { 1320: return 'badsec'; 1321: } 1322: if (reservednum > 0) { 1323: return 'reserved'; 1324: } 1325: } 1326: return; 1327: } 1328: END 1329: } 1330: 1331: sub close_popup_form { 1332: my $close= &mt('Close Window'); 1333: return << "END"; 1334: <p><form name="displayreq" action="" method="post"> 1335: <input type="button" name="closeme" value="$close" onclick="javascript:self.close();" /> 1336: </form></p> 1337: END 1338: } 1339: 1340: sub get_instcode { 1341: my ($dom) = @_; 1342: my ($instcode,$numtitles); 1343: my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); 1344: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1345: \%cat_order,\@code_order); 1346: $numtitles = scalar(@codetitles); 1347: if (@code_order > 0) { 1348: my $message; 1349: foreach my $item (@code_order) { 1350: $instcode .= $env{'form.instcode_'.$item}; 1351: } 1352: } 1353: return ($instcode,$numtitles); 1354: } 1355: 1356: sub print_request_form { 1357: my ($r,$action,$state,$page,$states,$dom,$newinstcode,$codechk,$checkedcode, 1358: $description,$showcredits,$instcredits,$invalidcrosslist) = @_; 1359: my $formname = 'requestcrs'; 1360: my ($next,$prev,$message,$output,$codepicker,$crstype); 1361: $prev = $states->{$action}[$page-1]; 1362: $next = $states->{$action}[$page+1]; 1363: my %navtxt = &Apache::lonlocal::texthash ( 1364: prev => 'Back', 1365: next => 'Next', 1366: ); 1367: $crstype = $env{'form.crstype'}; 1368: $r->print('<br /><form name="'.$formname.'" method="post" action="/adm/requestcourse">'); 1369: my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk, 1370: @disallowed); 1371: if ($crstype eq 'official') { 1372: if ($env{'form.instcode'} ne '') { 1373: $instcode = $env{'form.instcode'}; 1374: } elsif ($newinstcode ne '') { 1375: $instcode = $newinstcode; 1376: } 1377: if ($checkedcode) { 1378: if ($codechk eq 'valid') { 1379: $message = '<div class="LC_info">'. 1380: &mt('The chosen course category [_1] is valid.','<b>'. 1381: $instcode.'</b>'). 1382: '<input type="hidden" name="instcode" value="'. 1383: $instcode.'" /></div>'; 1384: } else { 1385: $message = '<div class="LC_warning">'. 1386: &mt('No course was found matching your choice of institutional course category.'); 1387: if ($codechk ne '') { 1388: $message .= '<br />'.$codechk; 1389: } 1390: $message .= '</div>'; 1391: $prev = 'crstype'; 1392: } 1393: $r->print($message); 1394: } 1395: } 1396: if ($prev eq 'crstype') { 1397: if ($crstype eq 'official') { 1398: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1399: \%cat_order,\@code_order); 1400: } 1401: if (@code_order > 0) { 1402: $codepicker = &coursecode_form($dom,'instcode',\@codetitles, 1403: \%cat_titles,\%cat_order); 1404: if ($codepicker) { 1405: $r->print(&mt('Specify the course to be created.'). 1406: '<div>'.&Apache::lonhtmlcommon::start_pick_box(). 1407: $codepicker. 1408: &Apache::lonhtmlcommon::end_pick_box().'</div>'); 1409: } else { 1410: $next = $states->{$action}[$page+2]; 1411: $r->print(&courseinfo_form($dom,$formname,$crstype,$next)); 1412: } 1413: } else { 1414: if ($crstype eq 'official') { 1415: $next = $states->{$action}[$page+2]; 1416: } 1417: $r->print(&courseinfo_form($dom,$formname,$crstype,$next)); 1418: } 1419: } elsif ($prev eq 'codepick') { 1420: if ($instcode eq '') { 1421: $prev = $states->{$action}[$page-2]; 1422: } 1423: $r->print(&courseinfo_form($dom,$formname,$crstype,$next,$description)); 1424: } elsif ($state eq 'enrollment') { 1425: if ($crstype eq 'official') { 1426: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1427: \%cat_order,\@code_order); 1428: } 1429: $r->print(&print_enrollment_menu($formname,$instcode,$dom,\@codetitles, 1430: \%cat_titles,\%cat_order,\@code_order, 1431: $showcredits,$instcredits,$invalidcrosslist)); 1432: } elsif ($state eq 'personnel') { 1433: $r->print(&print_personnel_menu($dom,$formname,$crstype,$invalidcrosslist)); 1434: } elsif ($state eq 'review') { 1435: my (%alerts,%rulematch,%inst_results,%curr_rules,%got_rules,%disallowmsg); 1436: my $now = time; 1437: for (my $i=0; $i<$env{'form.persontotal'}; $i++) { 1438: my $personname = $env{'form.person_'.$i.'_uname'}; 1439: my $persondom = $env{'form.person_'.$i.'_dom'}; 1440: if (($personname =~ /^$match_username$/) && 1441: ($persondom =~ /^$match_domain$/)) { 1442: if (&Apache::lonnet::domain($persondom)) { 1443: my $personhome = 1444: &Apache::lonnet::homeserver($personname,$persondom); 1445: if ($personhome eq 'no_host') { 1446: if ($persondom ne $dom) { 1447: my $skipuser = 1; 1448: if ($env{'user.role.dc./'.$persondom.'/'}) { 1449: my ($start,$end) = split('.',$env{'user.role.dc./'.$persondom.'/'}); 1450: if (((!$start) || ($start < $now)) && 1451: ((!$end) || ($end > $now))) { 1452: $skipuser = 0; 1453: } 1454: } 1455: if ($skipuser) { 1456: push(@disallowed,$i); 1457: $disallowmsg{$i} = &mt('[_1] was excluded because new users need to be from the course domain','<tt>'.$personname.':'.$persondom.'</tt>'); 1458: next; 1459: } 1460: } 1461: my $usertype = &get_usertype($persondom,$personname,\%curr_rules,\%got_rules); 1462: if (&Apache::lonuserutils::can_create_user($dom,'requestcrs',$usertype)) { 1463: my ($allowed,$msg,$authtype,$authparam) = 1464: &check_newuser_rules($persondom,$personname, 1465: \%alerts,\%rulematch,\%inst_results, 1466: \%curr_rules,\%got_rules); 1467: if ($allowed) { 1468: my %domdefaults = &Apache::lonnet::get_domain_defaults($persondom); 1469: if ($usertype eq 'official') { 1470: if ($authtype eq '') { 1471: $authtype = $domdefaults{'auth_def'}; 1472: $authparam = $domdefaults{'auth_arg_def'}; 1473: } 1474: } elsif ($usertype eq 'unofficial') { 1475: if ($authtype eq '') { 1476: $authtype = 'internal'; 1477: $authparam = ''; 1478: } 1479: } else { 1480: $authtype = $domdefaults{'auth_def'}; 1481: $authparam = $domdefaults{'auth_arg_def'}; 1482: } 1483: if (($authtype eq '') || 1484: (($authtype =~/^krb/) && ($authparam eq ''))) { 1485: push(@disallowed,$i); 1486: $disallowmsg{$i} = &mt('[_1] was excluded because institutional information is incomplete for this new user.','<tt>'.$personname.':'.$persondom.'</tt>'); 1487: next; 1488: } 1489: if (ref($inst_results{$personname.':'.$persondom}) eq 'HASH') { 1490: if ($inst_results{$personname.':'.$persondom}{'lastname'} ne '') { 1491: $env{'form.person_'.$i.'_lastname'} = $inst_results{$personname.':'.$persondom}{'lastname'}; 1492: } 1493: if ($inst_results{$personname.':'.$persondom}{'firstname'} ne '') { 1494: $env{'form.person_'.$i.'_firstname'} = $inst_results{$personname.':'.$persondom}{'firstname'}; 1495: } 1496: if ($inst_results{$personname.':'.$persondom}{'permanentemail'} ne '') { 1497: $env{'form.person_'.$i.'_emailaddr'} = $inst_results{$personname.':'.$persondom}{'permanentemail'}; 1498: } 1499: } 1500: } else { 1501: push(@disallowed,$i); 1502: $disallowmsg{$i} = &mt('[_1] was excluded because the username violated format rules for the domain','<tt>'.$personname.':'.$persondom.'</tt>'); 1503: } 1504: } else { 1505: push(@disallowed,$i); 1506: $disallowmsg{$i} = &mt('[_1] was excluded because you may not request new users in the domain','<tt>'.$personname.':'.$persondom.'</tt>'); 1507: } 1508: } else { 1509: my %userenv = 1510: &Apache::lonnet::userenvironment($persondom,$personname,'lastname','firstname','permanentemail'); 1511: if ($env{'form.person_'.$i.'_lastname'} eq '') { 1512: $env{'form.person_'.$i.'_lastname'} = $userenv{'lastname'}; 1513: } 1514: if ($env{'form.person_'.$i.'_firstname'} eq '') { 1515: $env{'form.person_'.$i.'_firstname'} = $userenv{'firstname'}; 1516: } 1517: if ($env{'form.person_'.$i.'_emailaddr'} eq '') { 1518: $env{'form.person_'.$i.'_emailaddr'} = $userenv{'permanentemail'}; 1519: } 1520: } 1521: } elsif ($personname ne '') { 1522: push(@disallowed,$i); 1523: $disallowmsg{$i} = &mt('[_1] was excluded because the domain is invalid','<tt>'.$personname.':'.$persondom.'</tt>'); 1524: } 1525: } elsif ($personname ne '') { 1526: push(@disallowed,$i); 1527: $disallowmsg{$i} = &mt('[_1] was excluded because the username or domain is invalid.','<tt>'.$personname.':'.$persondom.'</tt>'); 1528: } 1529: } 1530: my $cnum; 1531: if ($env{'form.origcnum'} =~ /^($match_courseid)$/) { 1532: $cnum = $env{'form.origcnum'}; 1533: } else { 1534: my $gentype = 'Course'; 1535: if ($crstype eq 'community') { 1536: $gentype = 'Community'; 1537: } 1538: $cnum = &Apache::lonnet::generate_coursenum($dom,$gentype); 1539: } 1540: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1541: \%cat_order,\@code_order); 1542: if ($crstype eq 'community') { 1543: $r->print('<h3>'.&mt('Review community request details before submission').'</h3>'); 1544: } else { 1545: $r->print('<h3>'.&mt('Review course request details before submission').'</h3>'); 1546: } 1547: $r->print(&print_review($dom,\@codetitles,\%cat_titles,\%cat_order,\@code_order,'','',\@disallowed,\%disallowmsg,$instcredits). 1548: '<input type="hidden" name="cnum" value="'.$cnum.'" />'); 1549: my $fullname = &Apache::loncommon::plainname($env{'user.name'}, 1550: $env{'user.domain'}); 1551: my $postprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'review',$env{'user.name'}, 1552: $env{'user.domain'},$fullname,$env{'form.cdescr'}); 1553: if (ref($postprocess) eq 'HASH') { 1554: if ($postprocess->{'reviewweb'}) { 1555: $r->print($postprocess->{'reviewweb'}); 1556: } 1557: } 1558: if ($crstype eq 'community') { 1559: $navtxt{'next'} = &mt('Submit community request'); 1560: } else { 1561: $navtxt{'next'} = &mt('Submit course request'); 1562: } 1563: } elsif ($state eq 'process') { 1564: if ($crstype eq 'official') { 1565: &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, 1566: \%cat_order,\@code_order); 1567: } 1568: my $lonhost = $r->dir_config('lonHostID'); 1569: my ($storeresult,$result,$customized) = &print_request_outcome($r,$lonhost,$dom,\@codetitles, 1570: \@code_order,$instcredits); 1571: $r->print($result); 1572: if (($storeresult eq 'ok') || ($storeresult eq 'created')) { 1573: if ($storeresult eq 'ok') { 1574: $r->print('<p><a href="/adm/requestcourse?action=view&state=details&showdom='.$dom.'&cnum='. $env{'form.cnum'}.'">'. 1575: &mt('Modify this request').'</a>'.(' 'x4). 1576: '<a href="/adm/requestcourse">'.&mt('Make another request').'</a></p>'); 1577: } 1578: if (&Apache::loncoursequeueadmin::author_prompt()) { 1579: unless ($customized) { 1580: &print_author_prompt($r,$env{'form.action'},$env{'form.cnum'},$env{'form.showdom'}, 1581: $env{'form.crstype'},$storeresult); 1582: } 1583: } elsif ($storeresult eq 'created') { 1584: unless ($customized) { 1585: $r->print('<p><a href="/adm/requestcourse">'.&mt('Make another request').'</a></p>'); 1586: } 1587: } 1588: } 1589: } elsif ($state eq 'reqauthor') { 1590: my ($result,@links); 1591: if ($env{'form.requestauthor'}) { 1592: $r->print(&Apache::loncoursequeueadmin::process_reqauthor(\$result)); 1593: if ($result eq 'created') { 1594: my $role = 'au'; 1595: my $spec = "$role./$env{'form.showdom'}/"; 1596: push(@links,&mt('Enter your Authoring Space with role: [_1]', 1597: '<a href="/adm/roles?selectrole=1&'.$spec.'=1">'. 1598: &Apache::lonnet::plaintext($role).'</a>')); 1599: } 1600: } 1601: if (($env{'form.disposition'} eq 'created') && 1602: ($env{'form.cnum'} =~ /^$match_courseid$/) && 1603: ($env{'form.showdom'} =~ /^$match_domain$/)) { 1604: my ($spec,$area,$role,$type); 1605: my $role = 'cc'; 1606: my $spec = "$role./$env{'form.showdom'}/$env{'form.cnum'}"; 1607: my $type = 'Course'; 1608: if ($env{'form.crstype'} eq 'community') { 1609: $type = 'Community'; 1610: } 1611: my $showrole = &Apache::lonnet::plaintext($role,$type); 1612: unshift(@links,&mt('Enter new course with role: [_1]', 1613: '<a href="/adm/roles?selectrole=1&'.$spec.'=1">'.$showrole.'</a>')); 1614: } 1615: if (@links > 1) { 1616: $r->print(&mt('New roles will be listed on your [_1]Roles[_2] page.', 1617: '<a href="/adm/roles">','</a>').' '.&mt('Choose a role:'). 1618: '<ul>'); 1619: foreach my $link (@links) { 1620: $r->print('<li>'.$link.'</li>'); 1621: } 1622: $r->print('</ul>'); 1623: } elsif (@links == 1) { 1624: $r->print('<p>'.$links[0].'</p>'); 1625: } 1626: } 1627: my @excluded = &get_excluded_elements($dom,$states,$action,$state,$showcredits); 1628: if ($state eq 'personnel') { 1629: push(@excluded,'persontotal'); 1630: } 1631: if ($state eq 'review') { 1632: if (@disallowed > 0) { 1633: my @items = qw(uname dom lastname firstname emailaddr hidedom role newsec); 1634: my @currsecs = ¤t_lc_sections(); 1635: if (@currsecs) { 1636: push(@items,'sec'); 1637: } 1638: my $count = 0; 1639: for (my $i=0; $i<$env{'form.persontotal'}; $i++) { 1640: unless ($env{'form.person_'.$i.'_uname'} eq '') { 1641: if (grep(/^$i$/,@disallowed)) { 1642: foreach my $item (@items) { 1643: $env{'form.person_'.$i.'_'.$item} = ''; 1644: } 1645: } else { 1646: foreach my $item (@items) { 1647: $env{'form.person_'.$count.'_'.$item} = $env{'form.person_'.$i.'_'.$item}; 1648: } 1649: } 1650: } 1651: $count ++; 1652: } 1653: $env{'form.persontotal'} = $count; 1654: } 1655: } 1656: if ($state eq 'enrollment') { 1657: push(@excluded,('sectotal','crosslisttotal')); 1658: } 1659: if (($state eq 'process') || ($state eq 'reqauthor')) { 1660: $r->print('</form>'); 1661: } else { 1662: $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).'</form>'); 1663: &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},$next, 1664: $navtxt{'next'},$state); 1665: } 1666: return; 1667: } 1668: 1669: sub print_author_prompt { 1670: my ($r,$action,$cnum,$showdom,$crstype,$storeresult) = @_; 1671: $r->print('<h3>'.&mt('Access to Authoring Space').'</h3>'. 1672: '<p>'. 1673: &mt('Although assessment items can be created directly inside a course, such items only use part of the assessment capabilities of LON-CAPA.'). 1674: '<br />'. 1675: &mt('By contrast, items created in Authoring Space, then imported into a course, can use all of the features of the assessment engine.').'</p>'. 1676: '<p>'.&mt('Request Authoring Space access now?'). 1677: '<span class="LC_nobreak"> '. 1678: '<label><input type="radio" name="requestauthor" value="1" />'.&mt('Yes').'</label>'. 1679: (' 'x2). 1680: '<label><input type="radio" name="requestauthor" value="0" checked="checked"/>'.&mt('No').'</label>'. 1681: '</span></p>'. 1682: '<input type="submit" name="newauthor" value="'.&mt('Submit authoring request').'" />'. 1683: '<input type="hidden" name="state" value="reqauthor" />'. 1684: '<input type="hidden" name="action" value="'.$action.'" />'. 1685: '<input type="hidden" name="cnum" value="'.$cnum.'" />'. 1686: '<input type="hidden" name="showdom" value="'.$showdom.'" />'. 1687: '<input type="hidden" name="crstype" value="'.$crstype.'" />'. 1688: '<input type="hidden" name="disposition" value="'.$storeresult.'" />'. 1689: '<br />'); 1690: } 1691: 1692: sub get_usertype { 1693: my ($persondom,$personname,$curr_rules,$got_rules) = @_; 1694: my ($rules,$ruleorder) = 1695: &Apache::lonnet::inst_userrules($persondom,'username'); 1696: my $usertype = &Apache::lonuserutils::check_usertype($persondom,$personname, 1697: $rules,$curr_rules,$got_rules); 1698: return $usertype; 1699: } 1700: 1701: sub check_newuser_rules { 1702: my ($persondom,$personname,$alerts,$rulematch,$inst_results,$curr_rules, 1703: $got_rules) = @_; 1704: my $allowed = 1; 1705: my $newuser = 1; 1706: my ($checkhash,$userchkmsg,$authtype,$authparam); 1707: my $checks = { 'username' => 1 }; 1708: $checkhash->{$personname.':'.$persondom} = { 'newuser' => $newuser }; 1709: &Apache::loncommon::user_rule_check($checkhash,$checks,$alerts,$rulematch, 1710: $inst_results,$curr_rules,$got_rules); 1711: if (ref($alerts->{'username'}) eq 'HASH') { 1712: if (ref($alerts->{'username'}{$persondom}) eq 'HASH') { 1713: my $domdesc = 1714: &Apache::lonnet::domain($persondom,'description'); 1715: if ($alerts->{'username'}{$persondom}{$personname}) { 1716: if (ref($curr_rules->{$persondom}) eq 'HASH') { 1717: $userchkmsg = 1718: &Apache::loncommon::instrule_disallow_msg('username', 1719: $domdesc,1). 1720: &Apache::loncommon::user_rule_formats($persondom, 1721: $domdesc,$curr_rules->{$persondom}{'username'}, 1722: 'username'); 1723: } 1724: $allowed = 0; 1725: } 1726: } 1727: } 1728: if ($allowed) { 1729: if (ref($rulematch) eq 'HASH') { 1730: if (ref($rulematch->{$personname.':'.$persondom}) eq 'HASH') { 1731: my $matchedrule = $rulematch->{$personname.':'.$persondom}{'username'}; 1732: my ($rules,$ruleorder) = 1733: &Apache::lonnet::inst_userrules($persondom,'username'); 1734: if (ref($rules) eq 'HASH') { 1735: if (ref($rules->{$matchedrule}) eq 'HASH') { 1736: $authtype = $rules->{$matchedrule}{'authtype'}; 1737: $authparam = $rules->{$matchedrule}{'authparm'}; 1738: } 1739: } 1740: } 1741: } 1742: } 1743: return ($allowed,$userchkmsg,$authtype,$authparam); 1744: } 1745: 1746: sub get_excluded_elements { 1747: my ($dom,$states,$action,$state,$showcredits) = @_; 1748: my @excluded = ('counter'); 1749: my ($elements,$instcredits) = &form_elements($dom,$showcredits); 1750: if (ref($states) eq 'HASH') { 1751: if (ref($states->{$action}) eq 'ARRAY') { 1752: my @items = @{$states->{$action}}; 1753: my $numitems = scalar(@items); 1754: if ($numitems) { 1755: for (my $i=$numitems-1; $i>=0; $i--) { 1756: if ((ref($elements) eq 'HASH') && 1757: (ref($elements->{$action}) eq 'HASH')) { 1758: if (ref($elements->{$action}{$items[$i]}) eq 'HASH') { 1759: foreach my $key (keys(%{$elements->{$action}{$items[$i]}})) { 1760: push(@excluded,$key); 1761: } 1762: } 1763: } 1764: last if ($items[$i] eq $state); 1765: } 1766: } 1767: } 1768: } 1769: if (grep(/^instcode_/,@excluded)) { 1770: push(@excluded,'instcode'); 1771: } 1772: return @excluded; 1773: } 1774: 1775: sub print_enrollment_menu { 1776: my ($formname,$instcode,$dom,$codetitles,$cat_titles,$cat_order,$code_order, 1777: $showcredits,$instcredits,$invalidcrosslist) =@_; 1778: my ($sections,$autoenroll,$access_dates,$output,$hasauto,$hascredits, 1779: $creditsrow,$domdefcredits); 1780: my $starttime = time; 1781: my $endtime = time+(6*30*24*60*60); # 6 months from now, approx 1782: 1783: my %accesstitles = ( 1784: 'start' => 'Default start access', 1785: 'end' => 'Default end access', 1786: ); 1787: my %enrolltitles = ( 1788: 'start' => 'Start auto-enrollment', 1789: 'end' => 'End auto-enrollment', 1790: ); 1791: if ($showcredits) { 1792: unless ($env{'form.crstype'} eq 'community') { 1793: my %domdefs = &Apache::lonnet::get_domain_defaults($dom); 1794: $domdefcredits = $domdefs{$env{'form.crstype'}.'credits'}; 1795: } 1796: } 1797: if ($env{'form.crstype'} eq 'official') { 1798: if (&Apache::lonnet::auto_run('',$dom)) { 1799: $output = &show_invalid_crosslists($invalidcrosslist); 1800: my ($section_form,$crosslist_form); 1801: if ($instcode ne '') { 1802: $section_form = &inst_section_selector($dom,$instcode); 1803: if ($section_form eq '') { 1804: my $sectotal = $env{'form.sectotal'}; 1805: if (!$sectotal) { 1806: $sectotal = 1; 1807: } 1808: if ($env{'form.addsection'}) { 1809: $sectotal ++; 1810: } 1811: for (my $i=0; $i<$sectotal; $i++) { 1812: $section_form .= §ions_form($dom,$instcode,$i); 1813: } 1814: if ($section_form) { 1815: $section_form .= 1816: &Apache::lonhtmlcommon::row_title(&mt('Add another')). 1817: '<input name="sectotal" type="hidden" value="'.$sectotal.'" />'. 1818: '<input name="addsection" type="checkbox" value="'.$sectotal.'"'. 1819: ' onclick="javascript:nextPage(document.'.$formname.",'".$env{'form.state'}. 1820: "'".');" />'.&mt('Add?').&Apache::lonhtmlcommon::row_closure(); 1821: } 1822: } 1823: } 1824: if ($section_form) { 1825: $sections = &Apache::lonhtmlcommon::row_headline(). 1826: '<h3>'.&Apache::loncommon::help_open_topic('Course_Request_Sections'). 1827: ' '.&mt('Sections for auto-enrollment').'</h3>'. 1828: &Apache::lonhtmlcommon::row_closure(1). 1829: $section_form; 1830: } 1831: my $crosslisttotal = $env{'form.crosslisttotal'}; 1832: if (!$crosslisttotal) { 1833: $crosslisttotal = 1; 1834: } 1835: if ($env{'form.addcrosslist'}) { 1836: $crosslisttotal ++; 1837: } 1838: for (my $i=0; $i<$crosslisttotal; $i++) { 1839: $crosslist_form .= &coursecode_form($dom,'crosslist',$codetitles, 1840: $cat_titles,$cat_order,$i); 1841: } 1842: if ($crosslist_form) { 1843: $crosslist_form .= 1844: &Apache::lonhtmlcommon::row_title(&mt('Add another')). 1845: '<input name="crosslisttotal" type="hidden" value="'.$crosslisttotal.'" />'. 1846: '<input name="addcrosslist" type="checkbox" value="'.$crosslisttotal.'"'. 1847: ' onclick="javascript:nextPage(document.'.$formname.",'".$env{'form.state'}. 1848: "'".');" />'.&mt('Add?').&Apache::lonhtmlcommon::row_closure(); 1849: $sections .= &Apache::lonhtmlcommon::row_headline. 1850: '<h3>'.&Apache::loncommon::help_open_topic('Course_Request_Crosslist').' '.&mt('Crosslisted courses for auto-enrollment').'</h3>'. 1851: &Apache::lonhtmlcommon::row_closure(1). 1852: $crosslist_form; 1853: } 1854: $hasauto = 1; 1855: $autoenroll = 1856: &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic('Course_Request_Autoadd').' '.&mt('Add registered students automatically')). 1857: '<span class="LC_nobreak"><label>'. 1858: '<input type="radio" name="autoadds" value="1">'. 1859: &mt('Yes').'</label>'.(' 'x3).'<label>'. 1860: '<input type="radio" name="autoadds" value="0" checked="checked">'. 1861: &mt('No').'</label></span>'. 1862: &Apache::lonhtmlcommon::row_closure(1). 1863: &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic('Course_Request_Autodrop').' '.&mt('Drop unregistered students automatically')). 1864: '<span class="LC_nobreak"><label>'. 1865: '<input type="radio" name="autodrops" value="1">'. 1866: &mt('Yes').'</label>'.(' 'x3).'<label>'. 1867: '<input type="radio" name="autodrops" value="0" checked="checked">'. 1868: &mt('No').'</label></span>'. 1869: &Apache::lonhtmlcommon::row_closure(1). 1870: &date_setting_table($starttime,$endtime,$formname,'enroll', 1871: $hasauto,undef,%enrolltitles); 1872: if ($showcredits) { 1873: if ($instcredits) { 1874: $creditsrow = &mt('[quant,_1,credit]',$instcredits); 1875: } else { 1876: $creditsrow = '<span class="LC_nobreak">'. 1877: '<input type="text" size="3" name="coursecredits"'. 1878: ' value="'.$domdefcredits.'" />'; 1879: } 1880: $hascredits = 1; 1881: } 1882: } 1883: } elsif (($env{'form.crstype'} eq 'unofficial') || ($env{'form.crstype'} eq 'textbook')) { 1884: if ($showcredits) { 1885: $creditsrow = '<span class="LC_nobreak">'. 1886: '<input type="text" size="3" name="coursecredits"'. 1887: ' value="'.$domdefcredits.'"/>'; 1888: $hascredits = 1; 1889: } 1890: } 1891: my $access_dates = 1892: &date_setting_table($starttime,$endtime,$formname,'access',$hasauto, 1893: $hascredits,%accesstitles); 1894: $output .= &Apache::lonhtmlcommon::start_pick_box(); 1895: if ($sections) { 1896: $output .= $sections; 1897: } 1898: if ($autoenroll) { 1899: $output .= &Apache::lonhtmlcommon::row_headline('Auto-enroll'). 1900: '<h3>'.&mt('Auto-enrollment settings').'</h3>'. 1901: &Apache::lonhtmlcommon::row_closure(1). 1902: $autoenroll; 1903: } 1904: if ($access_dates) { 1905: my $header = &mt('Access dates for students'); 1906: if ($env{'form.crstype'} eq 'community') { 1907: $header = &mt('Access dates for community members'); 1908: } 1909: $output .= &Apache::lonhtmlcommon::row_headline('Access'). 1910: '<h3>'.$header.'</h3>'. 1911: &Apache::lonhtmlcommon::row_closure(1). 1912: $access_dates; 1913: } 1914: if ($creditsrow) { 1915: $output .= &Apache::lonhtmlcommon::row_headline('Credits'). 1916: '<h3>'.&mt('Credits earned by students').'</h3>'. 1917: &Apache::lonhtmlcommon::row_closure(1). 1918: &Apache::lonhtmlcommon::row_title(&mt('Default credits')). 1919: $creditsrow. 1920: &Apache::lonhtmlcommon::row_closure(1); 1921: } 1922: return '<div>'.&Apache::lonhtmlcommon::start_pick_box().$output. 1923: &Apache::lonhtmlcommon::end_pick_box().'</div>'; 1924: } 1925: 1926: sub show_invalid_crosslists { 1927: my ($invalidcrosslist) = @_; 1928: my $output; 1929: if (ref($invalidcrosslist) eq 'ARRAY') { 1930: if (@{$invalidcrosslist} > 0) { 1931: $output = '<div class="LC_warning">'. 1932: &mt('The following crosslisted courses were invalid:').'<ul>'; 1933: foreach my $item (@{$invalidcrosslist}) { 1934: $output .= '<li>'.$item.'</li>'; 1935: } 1936: $output .= '</ul></div><br />'; 1937: } 1938: } 1939: return $output; 1940: } 1941: 1942: 1943: sub inst_section_selector { 1944: my ($dom,$instcode) = @_; 1945: my @sections = &Apache::lonnet::auto_get_sections(undef,$dom,$instcode); 1946: my $sectotal = scalar(@sections); 1947: my $output; 1948: if ($sectotal) { 1949: $output .= &Apache::lonhtmlcommon::row_title(&mt('Sections of [_1]',$instcode)). 1950: &Apache::loncommon::start_data_table(). 1951: &Apache::loncommon::start_data_table_row(). 1952: '<th>'.&mt('Include?').'<input type="hidden" name="sectotal" '. 1953: 'value="'.$sectotal.'" /></th>'. 1954: '<th>'.&mt('Institutional Section').'</th>'. 1955: '<th>'.&Apache::loncommon::help_open_topic('Course_Request_LCSection'). 1956: ' '.&mt('LON-CAPA section').'</th>'. 1957: &Apache::loncommon::end_data_table_row(); 1958: for (my $i=0; $i<@sections; $i++) { 1959: my $colflag = $i%2; 1960: my $secon = ' checked="checked"'; 1961: my $secoff = ''; 1962: if ($env{'form.origcnum'}) { 1963: $secoff = $secon; 1964: $secon=''; 1965: } 1966: $output .= &Apache::loncommon::start_data_table_row(). 1967: '<td><label><input type="radio" name="sec_'.$i. 1968: '"'.$secon.' value="1" />'.&mt('Yes').'</label>'. 1969: (' 'x2).'<label><input type="radio" name="sec_'.$i. 1970: '"'.$secoff.' value="0" />'.&mt('No').'</label></td>'. 1971: '<td align="center">'.$sections[$i]. 1972: '<input type="hidden" name="secnum_'.$i.'" value="'. 1973: $sections[$i].'" /></td>'. 1974: '<td><input type="text" size="10" name="loncapasec_'.$i. 1975: '" value="'.$sections[$i].'" /></td>'. 1976: &Apache::loncommon::end_data_table_row(); 1977: } 1978: $output .= &Apache::loncommon::end_data_table(). 1979: &Apache::lonhtmlcommon::row_closure(); 1980: } 1981: return $output; 1982: } 1983: 1984: sub date_setting_table { 1985: my ($starttime,$endtime,$formname,$prefix,$hasauto,$hascredits,%datetitles)=@_; 1986: my ($perpetual,$table); 1987: my $startform = &Apache::lonhtmlcommon::date_setter($formname,$prefix.'start', 1988: $starttime,'','','',1,'','','',1); 1989: my $endform = &Apache::lonhtmlcommon::date_setter($formname,$prefix.'end', 1990: $endtime,'','','',1,'','','',1); 1991: my $closure = ''; 1992: if ($prefix eq 'access') { 1993: $perpetual = ' <span class="LC_nobreak"><label>'. 1994: '<input type="checkbox" name="no_end_date" />'. 1995: &mt('No end date').'</label></span>'; 1996: unless ($hascredits) { 1997: $closure = '1'; 1998: } 1999: } 2000: 2001: my %help_item = ( 2002: access => { 2003: start => 'Course_Request_Access_Start', 2004: end => 'Course_Request_Access_End', 2005: }, 2006: enroll => { 2007: start => 'Course_Request_Enroll_Start', 2008: end => 'Course_Request_Enroll_End', 2009: }, 2010: ); 2011: if ($hasauto) { 2012: $help_item{'access'}{'start'} = 'Course_Request_RegAccess_Start'; 2013: $help_item{'access'}{'end'} = 'Course_Request_RegAccess_End'; 2014: } 2015: 2016: $table = &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic($help_item{$prefix}{'start'}). 2017: ' '.&mt($datetitles{'start'})).$startform. 2018: &Apache::lonhtmlcommon::row_closure(1). 2019: &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic($help_item{$prefix}{'end'}). 2020: ' '.&mt($datetitles{'end'})).$endform.$perpetual. 2021: &Apache::lonhtmlcommon::row_closure($closure); 2022: return $table; 2023: } 2024: 2025: sub print_personnel_menu { 2026: my ($dom,$formname,$crstype,$invalidcrosslist) = @_; 2027: my $output; 2028: if ($crstype eq 'official') { 2029: if (&Apache::lonnet::auto_run('',$dom)) { 2030: $output .= &show_invalid_crosslists($invalidcrosslist); 2031: } 2032: } 2033: $output .= '<div>'.&Apache::lonhtmlcommon::start_pick_box(); 2034: my $persontotal = $env{'form.persontotal'}; 2035: if ((!defined($persontotal)) || (!$persontotal)) { 2036: $persontotal = 1; 2037: } 2038: if ($env{'form.addperson'}) { 2039: $persontotal ++; 2040: } 2041: my @items = ('uname','dom','lastname','firstname','emailaddr','hidedom'); 2042: 2043: my $type = 'Course'; 2044: if ($crstype eq 'community') { 2045: $type = 'Community'; 2046: } 2047: my $roleoptions; 2048: my @roles = &Apache::lonuserutils::roles_by_context('course','',$type); 2049: foreach my $role (@roles) { 2050: my $plrole = &Apache::lonnet::plaintext($role,$type); 2051: $roleoptions .= ' <option value="'.$role.'">'.$plrole.'</option>'."\n"; 2052: } 2053: my %customroles=&Apache::lonuserutils::my_custom_roles(); 2054: if (keys(%customroles) > 0) { 2055: foreach my $cust (sort(keys(%customroles))) { 2056: my $custrole="cr/$env{'user.domain'}/$env{'user.name'}/$cust"; 2057: $roleoptions .= ' <option value="'.$custrole.'">'.$cust.'</option>'."\n"; 2058: } 2059: } 2060: 2061: my @currsecs = ¤t_lc_sections(); 2062: 2063: my ($existtitle,$existops,$existmult,$newtitle,$seccolspan); 2064: if (@currsecs) { 2065: my $existsize = scalar(@currsecs); 2066: if ($existsize > 3) { 2067: $existsize = 3; 2068: } 2069: if ($existsize > 1) { 2070: $existmult = ' multiple="multiple" size="'.$existsize.'" '; 2071: } 2072: @currsecs = sort { $a <=> $b } (@currsecs); 2073: $existtitle = &mt('Official').': '; 2074: $existops = '<option value="">'.&mt('None').'</option>'; 2075: foreach my $sec (@currsecs) { 2076: $existops .= '<option value="'.$sec.'">'.$sec.'</option>'."\n"; 2077: } 2078: $seccolspan = ' colspan="2"'; 2079: $newtitle = &mt('Other').': '; 2080: } 2081: 2082: if ($persontotal) { 2083: my %lt = &Apache::lonlocal::texthash( 2084: community => 'Requestor is automatically assigned Coordinator role.', 2085: official => 'Requestor is automatically assigned Course Coordinator role.', 2086: ); 2087: $lt{'unofficial'} = $lt{'official'}; 2088: $lt{'textbook'} = $lt{'textbook'}; 2089: $output .= &Apache::lonhtmlcommon::row_headline(). 2090: '<h3>'.&Apache::loncommon::help_open_topic('Course_Request_Personnel').' '.$lt{$crstype}.' '.&mt('Include other personnel?').'</h3>'; 2091: } 2092: my $cansearch = 1; 2093: my @alldoms = &Apache::lonnet::all_domains(); 2094: if (@alldoms == 1) { 2095: my %domsrch = &Apache::lonnet::get_dom('configuration', 2096: ['directorysrch'],$alldoms[0]); 2097: if (ref($domsrch{'directorysrch'}) eq 'HASH') { 2098: if ((!$domsrch{'directorysrch'}{'available'}) && 2099: ($domsrch{'directorysrch'}{'lcavailable'} eq '0')) { 2100: $cansearch = 0; 2101: } 2102: } 2103: } 2104: for (my $i=0; $i<$persontotal; $i++) { 2105: my @linkargs = map { 'person_'.$i.'_'.$_ } (@items); 2106: my $linkargstr = join("','",@linkargs); 2107: my $uname_form = '<input type="text" name="person_'.$i.'_uname" value="" size="20" />'; 2108: my $onchange = 'javascript:fix_domain('."'$formname','person_".$i."_dom',". 2109: "'person_".$i."_hidedom','person_".$i."_uname'".');'; 2110: my $udom_form = &Apache::loncommon::select_dom_form($dom,'person_'.$i.'_dom','', 2111: 1,$onchange). 2112: '<input type="hidden" name="person_'.$i.'_hidedom" value="" />'; 2113: my %form_elems; 2114: foreach my $item (@items) { 2115: next if (($item eq 'dom') || ($item eq 'uname') || ($item eq 'hidedom')); 2116: $form_elems{$item} = '<input type="text" name="person_'.$i.'_'.$item.'" '. 2117: 'value="" readonly="readonly" />'; 2118: } 2119: my $roleselector = '<select name="person_'.$i.'_role">'."\n". 2120: $roleoptions.'</select>'; 2121: my $sectionselector; 2122: if (@currsecs) { 2123: $sectionselector = $existtitle.'<select name="person_'.$i.'_sec"'. 2124: $existmult.'>'."\n".$existops.'</select>'.(' ' x3); 2125: } 2126: $sectionselector .= $newtitle. 2127: '<input type="text" name="person_'.$i.'_newsec" size="15" value="" />'."\n"; 2128: my $usersrchlink; 2129: if ($cansearch) { 2130: my $usersrchlinktxt = &mt('Search for user'); 2131: $usersrchlink = &Apache::loncommon::selectuser_link($formname,@linkargs,$dom, 2132: $usersrchlinktxt); 2133: } else { 2134: $usersrchlink = ' '; 2135: } 2136: my $userchklinktxt = &mt('Check username'); 2137: my $userchklink = &Apache::loncommon::selectuser_link($formname,@linkargs,$dom, 2138: $userchklinktxt,'checkusername'); 2139: $output .= 2140: &Apache::lonhtmlcommon::row_title(&mt('Additional Personnel')). 2141: '<table><tr><td align="center" valign="middle"><b>'.$usersrchlink.'</b></td>'."\n". 2142: '<td align="left" valign="top" colspan="2"><span class="LC_nobreak">'. 2143: &mt('Username').': '.$uname_form.' '.$userchklink.'</span><br />'."\n". 2144: '<span class="LC_nobreak">'.&mt('Domain').': '.$udom_form.'</span></td>'. 2145: '</tr>'."\n".'<tr>'. 2146: '<td align="center" valign="top">'.&mt('First Name').'<br />'.$form_elems{'firstname'}.'</td>'."\n". 2147: '<td align="center" valign="top">'.&mt('Last Name').'<br />'.$form_elems{'lastname'}.'</td>'."\n". 2148: '<td align="center" valign="top">'.&mt('E-mail').'<br />'.$form_elems{'emailaddr'}.'</td></tr>'."\n". 2149: '<tr><td align="center" valign="top">'.&Apache::loncommon::help_open_topic('Course_Roles').' '.&mt('Role').'<br />'.$roleselector.'</td>'."\n". 2150: '<td'.$seccolspan.' align="center" valign="top">'. 2151: &Apache::loncommon::help_open_topic('Course_Request_Rolesection').' '.&mt('LON-CAPA Section(s)').'<br />'.$sectionselector.'</td>'."\n". 2152: '</tr></table>'.&Apache::lonhtmlcommon::row_closure(); 2153: } 2154: $output .= &Apache::lonhtmlcommon::row_title(&mt('Add another')). 2155: '<input name="persontotal" type="hidden" value="'.$persontotal.'" />'. 2156: '<input name="addperson" type="checkbox" value="'.$persontotal.'"'. 2157: ' onclick="javascript:nextPage(document.'.$formname.",'".$env{'form.state'}. 2158: "'".');" />'.&mt('Add?').&Apache::lonhtmlcommon::row_closure(1). 2159: &Apache::lonhtmlcommon::end_pick_box().'</div>'; 2160: if ($crstype eq 'community') { 2161: $output .= '<p>'.&mt('You may also add users later, once the community has been created, by using the "Manage community users" link, accessible from the "Main Menu".').'</p>'; 2162: } else { 2163: $output .= '<p>'.&mt('You may also add users later, once the course has been created, by using the "Manage course users" link, accessible from the "Main Menu".').'</p>'; 2164: } 2165: return $output; 2166: } 2167: 2168: sub current_lc_sections { 2169: my @currsecs; 2170: if ($env{'form.sectotal'}) { 2171: for (my $i=0; $i<$env{'form.sectotal'}; $i++) { 2172: if ($env{'form.sec_'.$i}) { 2173: if (defined($env{'form.loncapasec_'.$i})) { 2174: my $lcsec = $env{'form.loncapasec_'.$i}; 2175: unless (grep(/^\Q$lcsec\E$/,@currsecs)) { 2176: push(@currsecs,$lcsec); 2177: } 2178: } 2179: } 2180: } 2181: } 2182: return @currsecs; 2183: } 2184: 2185: sub sorted_request_history { 2186: my ($dom,$action,$curr_req) = @_; 2187: my ($after,$before,$statusfilter,$crstypefilter); 2188: if ($env{'form.status'} ne '') { 2189: $statusfilter = $env{'form.status'}; 2190: } 2191: if ($env{'form.crstype'} ne '') { 2192: $crstypefilter = $env{'form.crstype'}; 2193: } 2194: if (ref($curr_req) eq 'HASH') { 2195: $after = $curr_req->{'requested_after_date'}, 2196: $before = $curr_req->{'requested_before_date'}; 2197: $statusfilter = $curr_req->{'status'}; 2198: $crstypefilter = $curr_req->{'crstype'}; 2199: } 2200: my %statusinfo = &Apache::lonnet::dump('courserequests',$env{'user.domain'}, 2201: $env{'user.name'},'^status:'.$dom); 2202: my %queue_by_date; 2203: my ($types,$typenames) = &Apache::loncommon::course_types(); 2204: foreach my $key (keys(%statusinfo)) { 2205: if ($action eq 'view') { 2206: next unless (($statusinfo{$key} eq 'approval') || ($statusinfo{$key} eq 'pending')); 2207: } else { 2208: next unless (($statusfilter eq 'any') || 2209: ($statusfilter eq $statusinfo{$key})); 2210: } 2211: (undef,my($cdom,$cnum)) = split(':',$key); 2212: next if ($cdom ne $dom); 2213: my $requestkey = $cdom.'_'.$cnum; 2214: if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { 2215: my %history = &Apache::lonnet::restore($requestkey,'courserequests', 2216: $env{'user.domain'},$env{'user.name'}); 2217: my $entry; 2218: my $reqtime = $history{'reqtime'}; 2219: my $lastupdate = $history{'timestamp'}; 2220: my $crstype = $history{'crstype'}; 2221: my $disposition = $history{'disposition'}; 2222: my $status = $history{'status'}; 2223: my $uniquecode = $history{'code'}; 2224: if ($action eq 'view') { 2225: next if ((exists($history{'status'})) && ($history{'status'} eq 'created')); 2226: } else { 2227: next if (($reqtime < $after) || ($reqtime > $before)); 2228: } 2229: next unless (($crstypefilter eq 'any') || 2230: ($crstypefilter eq $crstype)); 2231: if ($action eq 'view') { 2232: next unless (($disposition eq 'approval') || 2233: ($disposition eq 'pending')); 2234: } 2235: if (ref($history{'details'}) eq 'HASH') { 2236: $entry = $requestkey.':'.$crstype.':'. 2237: &escape($history{'details'}{'cdescr'}); 2238: if ($action eq 'log') { 2239: $entry .= ':'.$uniquecode.':'.$lastupdate.':'; 2240: if ($statusinfo{$key} ne '') { 2241: $entry .= $statusinfo{$key}; 2242: } elsif ($status ne '') { 2243: $entry .= $status; 2244: } else { 2245: $entry .= $disposition; 2246: } 2247: } 2248: if ($crstype eq 'official') { 2249: $entry .= ':'.&escape($history{'details'}{'instcode'}); 2250: } 2251: } 2252: if ($entry ne '') { 2253: if (exists($queue_by_date{$reqtime})) { 2254: if (ref($queue_by_date{$reqtime}) eq 'ARRAY') { 2255: push(@{$queue_by_date{$reqtime}},$entry); 2256: } 2257: } else { 2258: @{$queue_by_date{$reqtime}} = ($entry); 2259: } 2260: } 2261: } 2262: } 2263: return %queue_by_date; 2264: } 2265: 2266: sub print_request_status { 2267: my ($dom,$action) = @_; 2268: my %queue_by_date = &sorted_request_history($dom,$action); 2269: my @sortedtimes = sort {$a <=> $b} (keys(%queue_by_date)); 2270: my $formname = 'requestcrs'; 2271: my ($types,$typenames) = &Apache::loncommon::course_types(); 2272: my $output = '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'."\n". 2273: 2274: '<input type="hidden" name="state" value="'.$env{'form.state'}.'" />'."\n". 2275: '<input type="hidden" name="crstype" value="'.$env{'form.crstype'}.'" />'."\n". 2276: '<input type="hidden" name="showdom" value="" />'."\n". 2277: '<input type="hidden" name="cnum" value="" />'."\n"; 2278: if (@sortedtimes > 0) { 2279: my $desctitle; 2280: if ($env{'form.crstype'} eq 'any') { 2281: $desctitle = &mt('Course/Community Description') 2282: } elsif ($env{'form.crstype'} eq 'community') { 2283: $desctitle = &mt('Community Description') 2284: } else { 2285: $desctitle = &mt('Course Description'); 2286: } 2287: $output .= &Apache::loncommon::start_data_table(). 2288: &Apache::loncommon::start_data_table_header_row(). 2289: '<th>'.&mt('Action').'</th>'. 2290: '<th>'.$desctitle.'</th>'. 2291: '<th>'.&mt('Domain').'</th>'; 2292: if ($env{'form.crstype'} eq 'any') { 2293: $output .= '<th>'.&mt('Type').'</th>'; 2294: } 2295: if (($env{'form.crstype'} eq 'any') || ($env{'form.crstype'} eq 'official')) { 2296: $output .= '<th>'.&mt('Institutional Code').'</th>'; 2297: } 2298: $output .= '<th>'.&mt('Date requested').'</th>'. 2299: &Apache::loncommon::end_data_table_header_row(); 2300: my $count = 0; 2301: foreach my $item (@sortedtimes) { 2302: my $showtime = &Apache::lonlocal::locallocaltime($item); 2303: if (ref($queue_by_date{$item}) eq 'ARRAY') { 2304: foreach my $request (sort(@{$queue_by_date{$item}})) { 2305: my ($key,$type,$desc,$instcode) = split(':',$request); 2306: my ($cdom,$cnum) = split('_',$key); 2307: $output .= &Apache::loncommon::start_data_table_row(). 2308: '<td><input type="button" value="'.&mt('Select').'" onclick="javascript:chooseRequest('."'$cdom','$cnum'".')" /></td>'. 2309: '<td>'.&unescape($desc).'</td>'. 2310: '<td>'.$cdom.'</td>'; 2311: if ($env{'form.crstype'} eq 'any') { 2312: my $typename; 2313: if (ref($typenames) eq 'HASH') { 2314: $typename = &mt($typenames->{$type}); 2315: } 2316: if ($typename eq '') { 2317: $typename = &mt('Unknown type'); 2318: } 2319: $output .= '<td>'.$typename.'</td>'; 2320: } 2321: if (($env{'form.crstype'} eq 'any') || 2322: ($env{'form.crstype'} eq 'official')) { 2323: my $showinstcode; 2324: if ($type eq 'official') { 2325: $showinstcode = &unescape($instcode); 2326: } else { 2327: $showinstcode = &mt('Not applicable'); 2328: } 2329: $output .= '<td>'.$showinstcode.'</td>'; 2330: } 2331: $output .= '<td>'.$showtime.'</td>'. 2332: &Apache::loncommon::end_data_table_row(); 2333: } 2334: } 2335: } 2336: $output .= &Apache::loncommon::end_data_table(); 2337: } else { 2338: if ($env{'form.crstype'} eq 'any') { 2339: $output .= '<div>'.&mt('You have no matching course or community requests awaiting approval by a Domain Coordinator or held in a queue pending administrative action at your institution.').'</div>'; 2340: } elsif ($env{'form.crstype'} eq 'community') { 2341: $output .= '<div>'.&mt('You have no matching community requests awaiting approval by a Domain Coordinator or held in a queue pending administrative action at your institution.').'</div>'; 2342: } else { 2343: $output .= '<div>'.&mt('You have no matching course requests awaiting approval by a Domain Coordinator or held in a queue pending administrative action at your institution.').'</div>'; 2344: } 2345: } 2346: $output .= ' 2347: <br /><input type="button" name="prev" value="'.&mt('Back').'" onclick="javascript:backPage(document.'.$formname.",'crstype'".')" />'; 2348: return $output; 2349: } 2350: 2351: sub print_cancel_request { 2352: my ($dom,$cnum) = @_; 2353: my $requestkey = $dom.'_'.$cnum; 2354: my ($result,$output); 2355: if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { 2356: my %history = &Apache::lonnet::restore($requestkey,'courserequests', 2357: $env{'user.domain'},$env{'user.name'}); 2358: my $timestamp = $history{'reqtime'}; 2359: my $crstype = $history{'crstype'}; 2360: my $status = $history{'status'}; 2361: if (($status eq 'cancelled') || ($status eq 'created')) { 2362: if ($status eq 'cancelled') { 2363: $output = &mt('This request has already been cancelled.'); 2364: } elsif ($status eq 'created') { 2365: $output = &mt('This request has already been processed, and a course created.'); 2366: } 2367: $output = &mt('No further action will be taken'); 2368: } elsif (ref($history{'details'}) eq 'HASH') { 2369: my ($types,$typename) = &Apache::loncommon::course_types(); 2370: my $showtype = $crstype; 2371: if (defined($typename->{$crstype})) { 2372: $showtype = $typename->{$crstype}; 2373: } 2374: $output = '<p>'.&Apache::loncommon::start_data_table(). 2375: &Apache::loncommon::start_data_table_header_row(). 2376: '<th>'.&mt('Description').'</th><th>'.&mt('Requested').'</th>'. 2377: '<th>'.&mt('Type').'</th>'. 2378: &Apache::loncommon::end_data_table_header_row(). 2379: &Apache::loncommon::start_data_table_row(). 2380: '<td>'.$history{details}{'cdescr'}.'</td><td>'. 2381: &Apache::lonlocal::locallocaltime($timestamp).'</td>'. 2382: '<td>'.&mt($showtype).'</td>'. 2383: &Apache::loncommon::end_data_table_row(). 2384: &Apache::loncommon::end_data_table(). 2385: '<br /><div class="LC_warning">'; 2386: if ($crstype eq 'community') { 2387: $output .= &mt('Cancelling the request will remove it from the queue of pending community requests').'</div>'; 2388: } else { 2389: $output .= &mt('Cancelling the request will remove it from the queue of pending course requests').'</div>'; 2390: } 2391: $result = 'ok'; 2392: } else { 2393: $output = '<div class="LC_error">'.&mt('No record exists for the course ID').'</div>'; 2394: } 2395: } else { 2396: $output = '<div class="LC_error">'.&mt('Invalid course ID').'</div>'; 2397: } 2398: return ($result,$output); 2399: } 2400: 2401: sub viewrequest_javascript { 2402: my ($formname,$next) = @_; 2403: return <<"ENDJS"; 2404: 2405: function chooseRequest(cdom,cnum) { 2406: document.$formname.showdom.value = cdom; 2407: document.$formname.cnum.value = cnum; 2408: nextPage(document.$formname,'$next'); 2409: } 2410: 2411: ENDJS 2412: } 2413: 2414: sub viewdetails_javascript { 2415: my ($formname) = @_; 2416: return << "ENDJS"; 2417: 2418: function nextPage(formname,nextstate) { 2419: if (nextstate == "modify") { 2420: formname.state.value = "personnel"; 2421: formname.action.value = "new"; 2422: } else { 2423: formname.state.value = nextstate; 2424: } 2425: formname.submit(); 2426: } 2427: 2428: function backPage(formname,prevstate) { 2429: formname.state.value = prevstate; 2430: formname.submit(); 2431: } 2432: 2433: ENDJS 2434: } 2435: 2436: sub viewcancel_javascript { 2437: my $alert = &mt('Are you sure you want to cancel this request?')."\n". 2438: &mt('Your request will be removed.'); 2439: &js_escape(\$alert); 2440: return << "ENDJS"; 2441: function nextPage(formname,nextstate) { 2442: if (confirm('$alert')) { 2443: formname.state.value = nextstate; 2444: formname.submit(); 2445: } 2446: return; 2447: } 2448: 2449: ENDJS 2450: } 2451: 2452: sub print_request_logs { 2453: my ($r,$dom,$jscript,$loaditems,$crumb,$usetabs) = @_; 2454: my $title; 2455: if ($env{'form.crstype'} eq 'community') { 2456: $title = 'Community Request Logs'; 2457: } elsif ($env{'form.crstype'} eq 'any') { 2458: $title = 'Course/Community Request Logs'; 2459: } else { 2460: $title = 'Course Request Logs'; 2461: } 2462: $r->print(&header($title,$jscript,$loaditems).$crumb); 2463: if ($usetabs) { 2464: &startContentScreen($r,'textbooklogs'); 2465: } 2466: my $formname = 'requestcrs'; 2467: $r->print('<form action="/adm/requestcourse" method="post" name="'.$formname.'" onsubmit="javascript:setPage(this);">'."\n". 2468: '<input type="hidden" name="action" value="log" />'."\n". 2469: '<input type="hidden" name="state" value="display" />'."\n"); 2470: # set defaults 2471: my $now = time(); 2472: my $defstart = $now - (7*24*3600); #7 days ago 2473: my %defaults = ( 2474: page => '1', 2475: show => '10', 2476: crstype => 'any', 2477: status => 'any', 2478: requested_before_date => $now, 2479: requested_after_date => $defstart, 2480: ); 2481: my ($types,$typenames) = &Apache::loncommon::course_types(); 2482: my $more_records = 0; 2483: my %curr; 2484: foreach my $item ('show','page','crstype','status') { 2485: $curr{$item} = $env{'form.'.$item}; 2486: } 2487: $curr{'requested_after_date'} = &Apache::lonhtmlcommon::get_date_from_form('requested_after_date'); 2488: $curr{'requested_before_date'} = &Apache::lonhtmlcommon::get_date_from_form('requested_before_date'); 2489: foreach my $key (keys(%defaults)) { 2490: if ($curr{$key} eq '') { 2491: $curr{$key} = $defaults{$key}; 2492: } 2493: } 2494: my ($statuses,$statusnames) = &reqstatus_names($curr{'crstype'}); 2495: $r->print('<input type="hidden" name="page" value="'.$curr{'page'}.'" />'. 2496: &requestlog_display_filter($formname,\%curr)); 2497: my %queue_by_date = &sorted_request_history($dom,$env{'form.action'},\%curr); 2498: my @sortedtimes = sort {$a <=> $b} (keys(%queue_by_date)); 2499: my $showntablehdr = 0; 2500: my $tablehdr = &Apache::loncommon::start_data_table(). 2501: &Apache::loncommon::start_data_table_header_row(). 2502: '<th> </th><th>'.&mt('Request Date').'</th>'. 2503: '<th>'.&mt('Description').'</th>'; 2504: if ($curr{'crstype'} eq 'any') { 2505: $tablehdr .= '<th>'.&mt('Course Type').'</th>'; 2506: } 2507: if (($curr{'crstype'} eq 'official') || ($curr{'crstype'} eq 'any')) { 2508: $tablehdr .= '<th>'.&mt('Institutional Code').'</th>'; 2509: } 2510: my $showuniquecode; 2511: my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); 2512: if (($curr{'status'} eq 'any') || ($curr{'status'} eq 'created')) { 2513: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 2514: if (ref($domconfig{'requestcourses'}{'uniquecode'}) eq 'HASH') { 2515: if ($curr{'crstype'} eq 'any') { 2516: my @types = qw(official unofficial community textbook); 2517: foreach my $type (@types) { 2518: if ($domconfig{'requestcourses'}{'uniquecode'}{$type}) { 2519: $showuniquecode = 1; 2520: last; 2521: } 2522: } 2523: } elsif ($domconfig{'requestcourses'}{'uniquecode'}{$curr{'crstype'}}) { 2524: $showuniquecode = 1; 2525: } 2526: } 2527: } 2528: } 2529: if ($showuniquecode) { 2530: $tablehdr .= '<th>'.&mt('Unique Code').'</th>'; 2531: } 2532: if ($curr{'status'} eq 'any') { 2533: $tablehdr .= '<th>'.&mt('Status').'</th>'; 2534: } elsif ($curr{'status'} eq 'created') { 2535: $tablehdr .= '<th>'.&mt('Creation Date').'</th>'; 2536: } elsif ($curr{'status'} eq 'cancelled') { 2537: $tablehdr .= '<th>'.&mt('Cancellation Date').'</th>'; 2538: } elsif ($curr{'status'} eq 'rejected') { 2539: $tablehdr .= '<th>'.&mt('Rejection Date').'</th>'; 2540: } 2541: $tablehdr .= &Apache::loncommon::end_data_table_header_row(); 2542: my ($minshown,$maxshown); 2543: $minshown = 1; 2544: my $count = 0; 2545: if ($curr{'show'} ne &mt('all')) { 2546: $maxshown = $curr{'page'} * $curr{'show'}; 2547: if ($curr{'page'} > 1) { 2548: $minshown = 1 + ($curr{'page'} - 1) * $curr{'show'}; 2549: } 2550: } 2551: my $norecords; 2552: if (@sortedtimes > 0) { 2553: foreach my $item (@sortedtimes) { 2554: if ($curr{'show'} ne &mt('all')) { 2555: if ($count >= $curr{'page'} * $curr{'show'}) { 2556: $more_records = 1; 2557: last; 2558: } 2559: } 2560: $count ++; 2561: next if ($count < $minshown); 2562: if (!$showntablehdr) { 2563: $r->print($tablehdr); 2564: $showntablehdr = 1; 2565: } 2566: my $showtime = &Apache::lonlocal::locallocaltime($item); 2567: if (ref($queue_by_date{$item}) eq 'ARRAY') { 2568: foreach my $request (sort(@{$queue_by_date{$item}})) { 2569: my ($key,$crstype,$desc,$uniquecode,$timestamp,$status,$instcode) = split(':',$request); 2570: my ($cdom,$cnum) = split('_',$key); 2571: my $output = &Apache::loncommon::start_data_table_row(). 2572: '<td>'.$count.'</td>'. 2573: '<td>'.$showtime.'</td>'. 2574: '<td>'.&unescape($desc).'</td>'; 2575: if ($curr{'crstype'} eq 'any') { 2576: my $typename; 2577: if (ref($typenames) eq 'HASH') { 2578: $typename = &mt($typenames->{$crstype}); 2579: } 2580: if ($typename eq '') { 2581: $typename = &mt('Unknown type'); 2582: } 2583: $output .= '<td>'.$typename.'</td>'; 2584: } 2585: if (($curr{'crstype'} eq 'any') || 2586: ($curr{'crstype'} eq 'official')) { 2587: my $showinstcode; 2588: if ($crstype eq 'official') { 2589: $showinstcode = &unescape($instcode); 2590: } else { 2591: $showinstcode = &mt('Not applicable'); 2592: } 2593: $output .= '<td>'.$showinstcode.'</td>'; 2594: } 2595: if ($showuniquecode) { 2596: if ($status eq 'created') { 2597: $output .= '<td>'.$uniquecode.'</td>'; 2598: } else { 2599: $output .= '<td>'.&mt('Not applicable').'</td>'; 2600: } 2601: } 2602: if ($curr{'status'} eq 'any') { 2603: my $statusname = &mt('Unknown status'); 2604: if (ref($statusnames) eq 'HASH') { 2605: if ($statusnames->{$status} ne '') { 2606: $statusname = $statusnames->{$status}; 2607: } 2608: } 2609: if (($status eq 'created') || ($status eq 'cancelled') || 2610: ($status eq 'rejected')) { 2611: $statusname .= ' '.&Apache::lonlocal::locallocaltime($timestamp); 2612: } 2613: $output .= '<td>'.$statusname.'</td>'; 2614: } elsif (($status eq 'created') || ($status eq 'cancelled') || 2615: ($status eq 'rejected')) { 2616: $output .= '<td>'.&Apache::lonlocal::locallocaltime($timestamp).'</td>'; 2617: } 2618: $output .= &Apache::loncommon::end_data_table_row(); 2619: $r->print($output); 2620: } 2621: } 2622: } 2623: if ($showntablehdr) { 2624: $r->print(&Apache::loncommon::end_data_table()); 2625: if (($curr{'page'} > 1) || ($more_records)) { 2626: $r->print('<table><tr>'); 2627: if ($curr{'page'} > 1) { 2628: $r->print('<td><a href="javascript:chgPage('."'previous'".');">'.&mt('Previous [_1] changes',$curr{'show'}).'</a></td>'); 2629: } 2630: if ($more_records) { 2631: $r->print('<td><a href="javascript:chgPage('."'next'".');">'.&mt('Next [_1] changes',$curr{'show'}).'</a></td>'); 2632: } 2633: $r->print('</tr></table>'); 2634: $r->print(<<"ENDSCRIPT"); 2635: <script type="text/javascript"> 2636: // <![CDATA[ 2637: function chgPage(caller) { 2638: if (caller == 'previous') { 2639: document.$formname.page.value --; 2640: } 2641: if (caller == 'next') { 2642: document.$formname.page.value ++; 2643: } 2644: document.$formname.submit(); 2645: return; 2646: } 2647: // ]]> 2648: </script> 2649: ENDSCRIPT 2650: } 2651: } else { 2652: $norecords = 1; 2653: } 2654: } else { 2655: $norecords = 1; 2656: } 2657: if ($norecords) { 2658: $r->print('<p class="LC_info">'. 2659: &mt('There are no records to display'). 2660: '</p>'); 2661: } 2662: if ($usetabs) { 2663: $r->print('<input type="hidden" name="tabs" value="on" />'); 2664: } 2665: $r->print('</form>'); 2666: if ($usetabs) { 2667: &endContentScreen($r); 2668: } 2669: $r->print(&Apache::loncommon::end_page()); 2670: return; 2671: } 2672: 2673: sub reqstatus_names { 2674: my ($crstype) = @_; 2675: my @statuses = qw(created approval pending rejected cancelled); 2676: my %statusnames = 2677: &Apache::lonlocal::texthash ( 2678: created => 'Created', 2679: approval => 'Queued pending approval', 2680: pending => 'Queued pending validation', 2681: rejected => 'Request rejected', 2682: cancelled => 'Request cancelled', 2683: ); 2684: if (($crstype eq 'official') || ($crstype eq 'unofficial') || ($crstype eq 'textbook')) { 2685: $statusnames{'created'} = &mt('Course created'); 2686: } elsif ($crstype eq 'community') { 2687: $statusnames{'created'} = &mt('Community created'); 2688: } 2689: return (\@statuses,\%statusnames); 2690: } 2691: 2692: sub requestlog_display_filter { 2693: my ($formname,$curr) = @_; 2694: my $nolink = 1; 2695: my $output = '<table><tr><td valign="top">'. 2696: '<span class="LC_nobreak"><b>'.&mt('Records/page:').'</b></span><br />'. 2697: &Apache::lonmeta::selectbox('show',$curr->{'show'},undef, 2698: (&mt('all'),5,10,20,50,100,1000,10000)). 2699: '</td><td> </td>'; 2700: my $startform = 2701: &Apache::lonhtmlcommon::date_setter($formname,'requested_after_date', 2702: $curr->{'requested_after_date'},undef, 2703: undef,undef,undef,undef,undef,undef,$nolink); 2704: my $endform = 2705: &Apache::lonhtmlcommon::date_setter($formname,'requested_before_date', 2706: $curr->{'requested_before_date'},undef, 2707: undef,undef,undef,undef,undef,undef,$nolink); 2708: $output .= '<td valign="top"><b>'.&mt('Window during which course/community was requested:').'</b><br />'. 2709: '<table><tr><td>'.&mt('After:'). 2710: '</td><td>'.$startform.'</td></tr>'. 2711: '<tr><td>'.&mt('Before:').'</td>'. 2712: '<td>'.$endform.'</td></tr></table>'. 2713: '</td>'. 2714: '<td> </td>'; 2715: my ($types,$typenames) = &Apache::loncommon::course_types(); 2716: if (ref($types) eq 'ARRAY') { 2717: if (@{$types} > 1) { 2718: $output .= '<td valign="top"><b>'. 2719: &mt('Course Type:').'</b><br /><select name="crstype">'; 2720: my $selstr = ''; 2721: if ($curr->{'crstype'} eq 'any') { 2722: $selstr = ' selected="selected"'; 2723: } 2724: $output .= '<option value="any"'.$selstr.'>'.&mt('All types').'</option>'."\n"; 2725: foreach my $crstype (@{$types}) { 2726: my $selstr = ''; 2727: if ($curr->{'crstype'} eq $crstype) { 2728: $selstr = ' selected="selected"'; 2729: } 2730: my $typename = $crstype; 2731: if (ref($typenames) eq 'HASH') { 2732: if ($typenames->{$crstype} ne '') { 2733: $typename = $typenames->{$crstype}; 2734: } 2735: } 2736: $output .= '<option value="'.$crstype.'"'.$selstr.'>'.&mt($typename).'</option>'."\n"; 2737: } 2738: $output .= '</select></td>'; 2739: } 2740: } 2741: my ($statuses,$statusnames) = &reqstatus_names($curr->{'crstype'}); 2742: if (ref($statuses) eq 'ARRAY') { 2743: if (@{$statuses} > 1) { 2744: $output .= '<td valign="top"><b>'. 2745: &mt('Request Status:').'</b><br /><select name="status">'; 2746: my $selstr = ''; 2747: if ($curr->{'status'} eq 'any') { 2748: $selstr = ' selected="selected"'; 2749: } 2750: $output .= '<option value="any"'.$selstr.'>'.&mt('Any status').'</option>'."\n"; 2751: foreach my $status (@{$statuses}) { 2752: my $selstr = ''; 2753: if ($curr->{'status'} eq $status) { 2754: $selstr = ' selected="selected"'; 2755: } 2756: my $statusname = $status; 2757: if (ref($statusnames) eq 'HASH') { 2758: if ($statusnames->{$status} ne '') { 2759: $statusname = $statusnames->{$status}; 2760: } 2761: } 2762: $output .= '<option value="'.$status.'"'.$selstr.'>'.$statusname.'</option>'."\n"; 2763: } 2764: $output .= '</select></td>'; 2765: } 2766: } 2767: $output .= '</tr></table>'; 2768: 2769: # Update Display button 2770: $output .= '<p>'. 2771: '<input type="submit" value="'.&mt('Update Display').'" />'. 2772: '</p><hr />'; 2773: return $output; 2774: } 2775: 2776: sub print_review { 2777: my ($dom,$codetitles,$cat_titles,$cat_order,$code_order,$uname,$udom, 2778: $disallowed,$disallowmsg,$instcredits) = @_; 2779: my ($types,$typename) = &Apache::loncommon::course_types(); 2780: my ($owner,$ownername,$owneremail); 2781: if ($uname eq '' || $udom eq '') { 2782: $uname = $env{'user.name'}; 2783: $udom = $env{'user.domain'}; 2784: } 2785: $owner = $uname.':'.$udom; 2786: $ownername = &Apache::loncommon::plainname($uname,$udom,'first'); 2787: my %emails = &Apache::loncommon::getemails($uname,$udom); 2788: foreach my $email ('permanentemail','critnotification','notification') { 2789: $owneremail = $emails{$email}; 2790: last if ($owneremail ne ''); 2791: } 2792: my ($inst_headers,$inst_values,$crstypename,$enroll_headers,$enroll_values, 2793: $section_headers,$section_values,$personnel_headers,$personnel_values); 2794: 2795: $crstypename = $env{'form.crstype'}; 2796: if (ref($typename) eq 'HASH') { 2797: unless ($typename->{$env{'form.crstype'}} eq '') { 2798: $crstypename = &mt($typename->{$env{'form.crstype'}}); 2799: } 2800: } 2801: my $category = 'Course'; 2802: if ($env{'form.crstype'} eq 'community') { 2803: $category = 'Community'; 2804: } 2805: 2806: $inst_headers = '<th>'.&mt('Description').'</th><th>'.&mt('Type').'</th>'; 2807: $inst_values = '<td>'.$env{'form.cdescr'}.'</td><td>'.$crstypename.'</td>'; 2808: 2809: my $enrollrow_title = &mt('Default Access Dates').'<br />'. 2810: '('.&Apache::lonnet::plaintext('st',$category).')'; 2811: my $instcode; 2812: if ($env{'form.crstype'} eq 'official') { 2813: if ((ref($codetitles) eq 'ARRAY') && (ref($cat_titles) eq 'HASH')) { 2814: foreach my $title (@{$codetitles}) { 2815: if ($env{'form.instcode_'.$title} ne '') { 2816: $inst_headers .= '<th>'.$title.'</th>'; 2817: my $longitem = $env{'form.instcode_'.$title}; 2818: if (ref($cat_titles->{$title}) eq 'HASH') { 2819: if ($cat_titles->{$title}{$env{'form.instcode_'.$title}} ne '') { 2820: $longitem = $cat_titles->{$title}{$env{'form.instcode_'.$title}}; 2821: } 2822: } 2823: $inst_values .= '<td>'.$longitem.'</td>'; 2824: } 2825: } 2826: } 2827: if (ref($code_order) eq 'ARRAY') { 2828: foreach my $item (@{$code_order}) { 2829: $instcode .= $env{'form.instcode_'.$item}; 2830: } 2831: } 2832: $inst_headers .= '<th>'.&mt('Credits').'</th>'; 2833: if ($instcredits) { 2834: $inst_values .= '<td>'.$instcredits.'</td>'; 2835: } else { 2836: $inst_values .= '<td>'.$env{'form.coursecredits'}.'</td>'; 2837: } 2838: if (&Apache::lonnet::auto_run('',$dom)) { 2839: $enrollrow_title = &mt('Enrollment'); 2840: $enroll_headers = '<th>'.&mt('Automatic Adds').'</th>'. 2841: '<th>'.&mt('Automatic Drops').'</th>'. 2842: '<th>'.&mt('Enrollment Starts').'</th>'. 2843: '<th>'.&mt('Enrollment Ends').'</th>'; 2844: $section_headers = '<th>'.&mt('Sections').'</th>'. 2845: '<th>'.&mt('Crosslistings').'</th>'; 2846: 2847: my ($enrollstart,$enrollend) = &dates_from_form('enrollstart','enrollend'); 2848: my @autoroster = (&mt('No'),&mt('Yes')); 2849: $enroll_values = '<td>'.$autoroster[$env{'form.autoadds'}].'</td>'. 2850: '<td>'.$autoroster[$env{'form.autodrops'}].'</td>'. 2851: '<td>'.&Apache::lonlocal::locallocaltime($enrollstart).'</td>'. 2852: '<td>'.&Apache::lonlocal::locallocaltime($enrollend).'</td>'; 2853: $section_values = '<td><table class="LC_innerpickbox"><tr><th>'. 2854: &mt('Institutional section').'</th>'. 2855: '<th>'.&mt('LON-CAPA section').'</th></tr>'; 2856: my $secinfo; 2857: if ($env{'form.sectotal'} > 0) { 2858: for (my $i=0; $i<$env{'form.sectotal'}; $i++) { 2859: if ($env{'form.sec_'.$i}) { 2860: $secinfo .= '<tr><td>'.$env{'form.secnum_'.$i}.'</td><td>'; 2861: if ($env{'form.loncapasec_'.$i} ne '') { 2862: $secinfo .= $env{'form.loncapasec_'.$i}; 2863: } else { 2864: $secinfo .= &mt('None'); 2865: } 2866: $secinfo .= '</td></tr>'; 2867: } 2868: } 2869: } 2870: if ($secinfo eq '') { 2871: $secinfo = '<tr><td colspan="2">'.&mt('None').'</td></tr>'; 2872: } 2873: $section_values .= $secinfo.'</table></td><td>'. 2874: '<table class="LC_innerpickbox"><tr><th>'. 2875: &mt('Institutional course/section').'</th>'. 2876: '<th>'.&mt('LON-CAPA section').'</th></tr>'; 2877: my $xlistinfo; 2878: my $crosslisttotal = $env{'form.crosslisttotal'}; 2879: if (!$crosslisttotal) { 2880: $crosslisttotal = 1; 2881: } 2882: for (my $i=0; $i<$crosslisttotal; $i++) { 2883: if ($env{'form.crosslist_'.$i}) { 2884: $xlistinfo .= '<tr><td>'; 2885: if (ref($code_order) eq 'ARRAY') { 2886: if (@{$code_order} > 0) { 2887: foreach my $item (@{$code_order}) { 2888: $xlistinfo .= $env{'form.crosslist_'.$i.'_'.$item}; 2889: } 2890: } 2891: } 2892: $xlistinfo .= $env{'form.crosslist_'.$i.'_instsec'}.'</td><td>'; 2893: if ($env{'form.crosslist_'.$i.'_lcsec'}) { 2894: $xlistinfo .= $env{'form.crosslist_'.$i.'_lcsec'}; 2895: } else { 2896: $xlistinfo .= &mt('None'); 2897: } 2898: $xlistinfo .= '</td></tr>'; 2899: } 2900: } 2901: if ($xlistinfo eq '') { 2902: $xlistinfo = '<tr><td colspan="2">'.&mt('None').'</td></tr>'; 2903: } 2904: $section_values .= $xlistinfo; 2905: } 2906: $section_values .= '</table></td>'; 2907: } elsif (($env{'form.crstype'} eq 'unofficial') || ($env{'form.crstype'} eq 'textbook')) { 2908: $inst_headers .= '<th>'.&mt('Credits').'</th>'; 2909: $inst_values .= '<td>'.$env{'form.coursecredits'}.'</td>'; 2910: } 2911: 2912: my %ctxt = &clone_text(); 2913: $inst_headers .= '<th>'.&mt('Clone From').'</th>'; 2914: if (($env{'form.cloning'}) && 2915: ($env{'form.clonecrs'} =~ /^$match_name$/) && 2916: ($env{'form.clonedom'} =~ /^$match_domain$/)) { 2917: my $canclone = &Apache::loncoursequeueadmin::can_clone_course($uname, 2918: $udom,$env{'form.clonecrs'},$env{'form.clonedom'}, 2919: $env{'form.crstype'},$dom,$instcode); 2920: if ($canclone) { 2921: my %courseenv = &Apache::lonnet::userenvironment($env{'form.clonedom'}, 2922: $env{'form.clonecrs'},('description','internal.coursecode')); 2923: if (keys(%courseenv) > 0) { 2924: $inst_headers .= '<th>'.$ctxt{'dsh'}.'</th>'; 2925: $inst_values .= '<td>'.$courseenv{'description'}.' '; 2926: my $cloneinst = $courseenv{'internal.coursecode'}; 2927: if ($cloneinst ne '') { 2928: $inst_values .= $cloneinst.' '.&mt('in').' '.$env{'form.clonedom'}; 2929: } else { 2930: $inst_values .= &mt('from').' '.$env{'form.clonedom'}; 2931: } 2932: $inst_values .= '</td><td>'; 2933: if ($env{'form.datemode'} eq 'preserve') { 2934: $inst_values .= $ctxt{'prd'}; 2935: } elsif ($env{'form.datemode'} eq 'shift') { 2936: $inst_values .= &mt('Shift dates by [_1] days',$env{'form.dateshift'}); 2937: } else { 2938: $inst_values .= $ctxt{'ncd'}; 2939: } 2940: $inst_values .= '</td>'; 2941: } else { 2942: $inst_values .= '<td>'.&mt('Unknown').'</td>'; 2943: } 2944: } else { 2945: $inst_values .= '<td>'.&mt('Not permitted'),'</td>'; 2946: } 2947: } else { 2948: $inst_values .= '<td>'.&mt('None').'</td>'; 2949: } 2950: $enroll_headers .= '<th>'.&mt('Access Starts').'</th>'. 2951: '<th>'.&mt('Access Ends').'</th>'; 2952: my ($accessstart,$accessend) = &dates_from_form('accessstart','accessend'); 2953: $enroll_values .= '<td>'.&Apache::lonlocal::locallocaltime($accessstart).'</td>'; 2954: if ($accessend == 0) { 2955: $enroll_values .= '<td>'.&mt('No end date').'</td>'; 2956: } else { 2957: $enroll_values .= '<td>'.&Apache::lonlocal::locallocaltime($accessend).'</td>'; 2958: } 2959: 2960: my $container = 'Course'; 2961: my $ccrole = 'cc'; 2962: if ($env{'form.crstype'} eq 'community') { 2963: $container = 'Community'; 2964: $ccrole = 'co'; 2965: } 2966: 2967: $personnel_headers = '<th>'.&mt('Name').'</th><th>'.&mt('Username:Domain'). 2968: '</th><th>'.&mt('Role').'</th><th>'.&mt('LON-CAPA Sections'). 2969: '</th>'; 2970: 2971: $personnel_values .= '<tr><td>'.$ownername.'</td><td>'.$owner.'</td>'. 2972: '<td>'.&Apache::lonnet::plaintext($ccrole,$container).'</td>'. 2973: '<td>'.&mt('None').'</td></tr>'; 2974: for (my $i=0; $i<$env{'form.persontotal'}; $i++) { 2975: if ($env{'form.person_'.$i.'_uname'} ne '') { 2976: if (ref($disallowed) eq 'ARRAY') { 2977: next if (grep(/^$i$/,@{$disallowed})); 2978: } 2979: my @officialsecs = &Apache::loncommon::get_env_multiple('form.person_'.$i.'_sec'); 2980: my @allsecs; 2981: foreach my $sec (@officialsecs) { 2982: next unless ($sec =~ /\w/); 2983: next if ($sec =~ /\W/); 2984: next if ($sec eq 'none'); 2985: push(@allsecs,$sec); 2986: } 2987: my $newsec = $env{'form.person_'.$i.'_newsec'}; 2988: $newsec =~ s/^\s+//; 2989: $newsec =~s/\s+$//; 2990: my @newsecs = split(/\s*[\s,;:]\s*/,$newsec); 2991: foreach my $sec (@newsecs) { 2992: next unless ($sec =~ /\w/); 2993: next if ($sec =~ /\W/); 2994: next if ($sec eq 'none'); 2995: if ($sec ne '') { 2996: unless (grep(/^\Q$sec\E$/,@allsecs)) { 2997: push(@allsecs,$sec); 2998: } 2999: } 3000: } 3001: my $showsec; 3002: if (@allsecs) { 3003: $showsec = join(', ',@allsecs); 3004: } 3005: if ($showsec eq '') { 3006: $showsec = &mt('None'); 3007: } 3008: if ($env{'form.person_'.$i.'_role'} eq $ccrole) { 3009: $showsec = &mt('None'); 3010: } 3011: my $role = $env{'form.person_'.$i.'_role'}; 3012: $personnel_values .= 3013: '<tr><td>'.$env{'form.person_'.$i.'_firstname'}.' '. 3014: $env{'form.person_'.$i.'_lastname'}.'</td>'. 3015: '<td>'.$env{'form.person_'.$i.'_uname'}.':'. 3016: $env{'form.person_'.$i.'_dom'}.'</td>'. 3017: '<td>'.&Apache::lonnet::plaintext($role,$container).'</td>'. 3018: '<td>'.$showsec.'</td></tr>'; 3019: } 3020: } 3021: my $output; 3022: if (ref($disallowed) eq 'ARRAY') { 3023: if (@{$disallowed} > 0) { 3024: if (ref($disallowmsg) eq 'HASH') { 3025: $output = '<p class="LC_warning">'. 3026: &mt('Not all requested personnel could be included.').'<ul>'; 3027: foreach my $item (@{$disallowed}) { 3028: $output .= '<li>'.$disallowmsg->{$item}.'</li>'; 3029: } 3030: $output .= '</ul></p>'; 3031: } 3032: } 3033: } 3034: $output .= '<div>'.&Apache::lonhtmlcommon::start_pick_box(). 3035: &Apache::lonhtmlcommon::row_title(&mt('Owner')). 3036: '<table class="LC_innerpickbox"><tr>'. 3037: '<th>'.&mt('Name').'</th>'. 3038: '<th>'.&mt('Username:Domain').'</th>'. 3039: '<th>'.&mt('E-mail address').'</th>'. 3040: '</tr><tr>'."\n". 3041: '<td>'.$ownername.'</td><td>'.$owner.'</td>'. 3042: '<td>'.$owneremail.'</td>'. 3043: '</tr></table>'."\n". 3044: &Apache::lonhtmlcommon::row_closure(). 3045: &Apache::lonhtmlcommon::row_title(&mt('Description')). 3046: '<table class="LC_innerpickbox"><tr>'.$inst_headers.'</tr>'."\n". 3047: '<tr>'.$inst_values.'</tr></table>'."\n". 3048: &Apache::lonhtmlcommon::row_closure(). 3049: &Apache::lonhtmlcommon::row_title($enrollrow_title). 3050: '<table class="LC_innerpickbox"><tr>'.$enroll_headers.'</tr>'."\n". 3051: '<tr>'.$enroll_values.'</tr></table>'."\n". 3052: &Apache::lonhtmlcommon::row_closure(); 3053: if ($section_headers ne '') { 3054: $output .= &Apache::lonhtmlcommon::row_title(&mt('Sections')). 3055: '<table class="LC_innerpickbox"><tr>'.$section_headers.'</tr>'."\n". 3056: '<tr>'.$section_values.'</tr></table>'."\n". 3057: &Apache::lonhtmlcommon::row_closure(); 3058: } 3059: $output .= &Apache::lonhtmlcommon::row_title(&mt('Personnel')). 3060: '<table class="LC_innerpickbox"><tr>'.$personnel_headers.'</tr>'."\n". 3061: $personnel_values.'</table>'."\n". 3062: &Apache::lonhtmlcommon::row_closure(1). 3063: &Apache::lonhtmlcommon::end_pick_box().'</div>'; 3064: return $output; 3065: } 3066: 3067: sub dates_from_form { 3068: my ($startname,$endname) = @_; 3069: my $startdate = &Apache::lonhtmlcommon::get_date_from_form($startname); 3070: my $enddate = &Apache::lonhtmlcommon::get_date_from_form($endname); 3071: if ($endname eq 'accessend') { 3072: if (exists($env{'form.no_end_date'}) ) { 3073: $enddate = 0; 3074: } 3075: } 3076: return ($startdate,$enddate); 3077: } 3078: 3079: sub courseinfo_form { 3080: my ($dom,$formname,$crstype,$next,$description) = @_; 3081: my %js_lt = &Apache::lonlocal::texthash( 3082: official => 'You must provide a (brief) course description.', 3083: community => 'You must provide a (brief) community description.' 3084: ); 3085: &js_escape(\%js_lt); 3086: $js_lt{'unofficial'} = $js_lt{'official'}; 3087: $js_lt{'textbook'} = $js_lt{'official'}; 3088: my $js_validate = <<"ENDJS"; 3089: <script type="text/javascript"> 3090: // <![CDATA[' 3091: 3092: function validateForm() { 3093: if ((document.$formname.cdescr.value == "") || (document.$formname.cdescr.value == "undefined")) { 3094: alert('$js_lt{$crstype}'); 3095: return; 3096: } 3097: nextPage(document.$formname,'$next'); 3098: } 3099: 3100: function toggleCloning() { 3101: var willclone; 3102: if (document.$formname.cloning.length > 1) { 3103: for (var i=0; i<document.$formname.cloning.length; i++) { 3104: if (document.$formname.cloning[i].checked) { 3105: willclone = document.$formname.cloning[i].value; 3106: } 3107: } 3108: } 3109: if (willclone == 1) { 3110: document.getElementById('cloneoptions').style.display="block"; 3111: } else { 3112: document.getElementById('cloneoptions').style.display="none"; 3113: document.$formname.clonecrs.value = ''; 3114: } 3115: } 3116: 3117: // ]] 3118: </script> 3119: 3120: ENDJS 3121: my $title = &mt('Brief Course Description'); 3122: my $clonetitle = &mt('Clone content and settings from an existing course?'); 3123: if ($crstype eq 'community') { 3124: $title = &mt('Brief Community Description'); 3125: $clonetitle = &mt('Clone content and settings from an existing community?'); 3126: } 3127: my $output .= $js_validate."\n".&Apache::lonhtmlcommon::start_pick_box(). 3128: &Apache::lonhtmlcommon::row_headline(). 3129: '<h3>'.&Apache::loncommon::help_open_topic('Course_Request_Description').' '.$title.'</h3>'. 3130: &Apache::lonhtmlcommon::row_closure(1). 3131: &Apache::lonhtmlcommon::row_title(&mt('Description')). 3132: '<input type="text" size="60" name="cdescr" value="'.$description.'" />'; 3133: my ($home_server_pick,$numlib) = 3134: &Apache::loncommon::home_server_form_item($dom,'chome', 3135: 'default','hide'); 3136: if ($numlib > 1) { 3137: $output .= &Apache::lonhtmlcommon::row_closure(). 3138: &Apache::lonhtmlcommon::row_title(&mt('Home Server for Course')); 3139: } 3140: $output .= $home_server_pick. 3141: &Apache::lonhtmlcommon::row_closure(). 3142: &Apache::lonhtmlcommon::row_headline(). 3143: '<h3>'.&Apache::loncommon::help_open_topic('Course_Request_Clone').' '.$clonetitle. 3144: &Apache::lonhtmlcommon::row_closure(1). 3145: &Apache::lonhtmlcommon::row_title(&mt('Clone?')). 3146: '<label><input type="radio" name="cloning" value="1" '. 3147: 'onclick="javascript:toggleCloning()" />'. 3148: &mt('Yes').(' 'x2).'</label><label>'. 3149: '<input type="radio" name="cloning" value="0" checked="checked" '. 3150: 'onclick="javascript:toggleCloning()" />'.&mt('No').'</label>'. 3151: '</h3>'. 3152: &Apache::lonhtmlcommon::row_closure(1). 3153: &Apache::lonhtmlcommon::row_headline(). 3154: '<div id="cloneoptions" style="display: none" >'. 3155: &Apache::lonhtmlcommon::start_pick_box(). 3156: &clone_form($dom,$formname,$crstype). 3157: &Apache::lonhtmlcommon::end_pick_box().'</div>'. 3158: &Apache::lonhtmlcommon::end_pick_box()."\n"; 3159: return $output; 3160: } 3161: 3162: sub clone_form { 3163: my ($dom,$formname,$crstype) = @_; 3164: my $type = 'Course'; 3165: if ($crstype eq 'community') { 3166: $type = 'Community'; 3167: } 3168: my %lt = &clone_text(); 3169: my $output .= 3170: &Apache::lonhtmlcommon::row_title($lt{'dmn'}).'<label>'. 3171: &Apache::loncommon::select_dom_form($dom,'clonedom').'</label>'. 3172: &Apache::lonhtmlcommon::row_closure(1). 3173: &Apache::lonhtmlcommon::row_title($lt{'cid'}).'<label>'. 3174: '<input type="text" size="25" name="clonecrs" value="" onfocus="this.blur();opencrsbrowser('."'$formname','clonecrs','clonedom','','','','$type'".')" />'. 3175: '</label> '. 3176: &Apache::loncommon::selectcourse_link($formname,'clonecrs','clonedom','','','',$type). 3177: &Apache::lonhtmlcommon::row_closure(1). 3178: &Apache::lonhtmlcommon::row_title($lt{'dsh'}).'<label>'. 3179: '<input type="radio" name="datemode" value="delete" /> '.$lt{'ncd'}. 3180: '</label><br /><label>'. 3181: '<input type="radio" name="datemode" value="preserve" /> '.$lt{'prd'}. 3182: '</label><br /><label>'. 3183: '<input type="radio" name="datemode" value="shift" checked="checked" /> '. 3184: $lt{'shd'}.'</label>'. 3185: '<input type="text" size="5" name="dateshift" value="364" />'. 3186: &Apache::lonhtmlcommon::row_closure(1); 3187: return $output; 3188: } 3189: 3190: sub clone_text { 3191: return &Apache::lonlocal::texthash( 3192: 'cid' => 'Course ID', 3193: 'dmn' => 'Domain', 3194: 'dsh' => 'Date Shift', 3195: 'ncd' => 'Do not clone date parameters', 3196: 'prd' => 'Clone date parameters as-is', 3197: 'shd' => 'Shift date parameters by number of days', 3198: ); 3199: } 3200: 3201: sub coursecode_form { 3202: my ($dom,$context,$codetitles,$cat_titles,$cat_order,$num) = @_; 3203: my $output; 3204: my %rowtitle = &Apache::lonlocal::texthash ( 3205: instcode => 'Course Category', 3206: crosslist => 'Cross Listed Course', 3207: ); 3208: my %helpitem = ( 3209: instcode => 'Course_Request_Category', 3210: ); 3211: if ((ref($codetitles) eq 'ARRAY') && (ref($cat_titles) eq 'HASH') && 3212: (ref($cat_order))) { 3213: my ($sel,$instsec,$lcsec); 3214: $sel = $context; 3215: if ($context eq 'crosslist') { 3216: $sel .= '_'.$num; 3217: $instsec = &mt('Institutional section').'<br />'. 3218: '<input type="text" size="10" name="'.$sel.'_instsec" />'; 3219: $lcsec = &mt('LON-CAPA section').'<br />'. 3220: '<input type="text" size="10" name="'.$sel.'_lcsec" />'; 3221: } 3222: if (@{$codetitles} > 0) { 3223: my $lastitem = pop(@{$codetitles}); 3224: my $lastinput = '<input type="text" size="5" name="'.$sel.'_'.$lastitem.'" />'; 3225: if (@{$codetitles} > 0) { 3226: my $helplink; 3227: if (defined($helpitem{$context})) { 3228: $helplink = &Apache::loncommon::help_open_topic($helpitem{$context}).' '; 3229: } 3230: $output = &Apache::lonhtmlcommon::row_title($helplink.$rowtitle{$context}). 3231: '<table><tr>'; 3232: if ($context eq 'crosslist') { 3233: $output .= '<td>'.&mt('Include?').'<br />'. 3234: '<input type="checkbox" name="'.$sel.'" value="1" /></td>'; 3235: } 3236: foreach my $title (@{$codetitles}) { 3237: if (ref($cat_order->{$title}) eq 'ARRAY') { 3238: if (@{$cat_order->{$title}} > 0) { 3239: $output .= '<td align="center">'.$title.'<br />'."\n". 3240: '<select name="'.$sel.'_'.$title.'">'."\n". 3241: ' <option value="" selected="selected">'. 3242: &mt('Select').'</option>'."\n"; 3243: foreach my $item (@{$cat_order->{$title}}) { 3244: my $longitem = $item; 3245: if (ref($cat_titles->{$title}) eq 'HASH') { 3246: if ($cat_titles->{$title}{$item} ne '') { 3247: $longitem = $cat_titles->{$title}{$item}; 3248: } 3249: } 3250: $output .= '<option value="'.$item.'">'.$longitem. 3251: '</option>'."\n"; 3252: } 3253: } 3254: $output .= '</select></td>'."\n"; 3255: } 3256: } 3257: if ($context eq 'crosslist') { 3258: $output .= '<td align="center">'.$lastitem.'<br />'."\n". 3259: $lastinput.'</td><td align="center">'.$instsec.'</td>'. 3260: '<td align="center">'.$lcsec.'</td></tr></table>'; 3261: } else { 3262: $output .= '</tr></table>'. 3263: &Apache::lonhtmlcommon::row_closure(). 3264: &Apache::lonhtmlcommon::row_title('Course '.$lastitem). 3265: $lastinput; 3266: } 3267: } else { 3268: if ($context eq 'crosslist') { 3269: $output .= &Apache::lonhtmlcommon::row_title($rowtitle{$context}). 3270: '<table><tr>'. 3271: '<td align="center">'.$lastitem.'<br />'.$lastinput.'</td>'. 3272: '<td align="center">'.$instsec.'</td><td>'.$lcsec.'</td>'. 3273: '</tr></table>'; 3274: } else { 3275: $output .= &Apache::lonhtmlcommon::row_title('Course '.$lastitem). 3276: $lastinput; 3277: } 3278: } 3279: $output .= &Apache::lonhtmlcommon::row_closure(1); 3280: push(@$codetitles,$lastitem); 3281: } elsif ($context eq 'crosslist') { 3282: $output .= &Apache::lonhtmlcommon::row_title($rowtitle{$context}). 3283: '<table><tr><td align="center">'. 3284: '<span class="LC_nobreak">'.&mt('Include?'). 3285: '<input type="checkbox" name="'.$sel.'" value="1" /></span>'. 3286: '</td><td align="center">'.&mt('Institutional ID').'<br />'. 3287: '<input type="text" size="10" name="'.$sel.'_instsec" />'. 3288: '</td><td align="center">'.$lcsec.'</td></tr></table>'. 3289: &Apache::lonhtmlcommon::row_closure(1); 3290: } 3291: } 3292: return $output; 3293: } 3294: 3295: sub sections_form { 3296: my ($dom,$instcode,$num) = @_; 3297: my $rowtitle; 3298: if ($instcode eq '') { 3299: $rowtitle = &mt('Sections'); 3300: } else { 3301: $rowtitle = &mt('Sections of [_1]',$instcode); 3302: } 3303: return &Apache::lonhtmlcommon::row_title($rowtitle). 3304: '<table><tr><td align="center">'. 3305: '<span class="LC_nobreak">'.&mt('Include?'). 3306: '<input type="checkbox" name="sec_'.$num.'" value="1" /></span>'. 3307: '</td><td align="center">'.&mt('Institutional section').'<br />'. 3308: '<input type="text" size="10" name="secnum_'.$num.'" />'. 3309: '</td><td align="center">'.&mt('LON-CAPA section').'<br />'. 3310: '<input type="text" size="10" name="loncapasec_'.$num.'" />'. 3311: '</td></tr></table>'. 3312: &Apache::lonhtmlcommon::row_closure(1); 3313: } 3314: 3315: sub get_course_dom { 3316: my $codedom = &Apache::lonnet::default_login_domain(); 3317: if ($env{'form.showdom'} ne '') { 3318: if (&Apache::lonnet::domain($env{'form.showdom'}) ne '') { 3319: return $env{'form.showdom'}; 3320: } 3321: } 3322: if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne 'public')) { 3323: my ($types,$typename) = &Apache::loncommon::course_types(); 3324: if (ref($types) eq 'ARRAY') { 3325: foreach my $type (@{$types}) { 3326: if (&Apache::lonnet::usertools_access($env{'user.name'}, 3327: $env{'user.domain'},$type, 3328: undef,'requestcourses')) { 3329: return $env{'user.domain'}; 3330: } 3331: } 3332: my @possible_doms; 3333: foreach my $type (@{$types}) { 3334: my $dom_str = $env{'environment.reqcrsotherdom.'.$type}; 3335: if ($dom_str ne '') { 3336: my @domains = split(',',$dom_str); 3337: foreach my $entry (@domains) { 3338: my ($extdom,$extopt) = split(':',$entry); 3339: if ($extdom eq $env{'request.role.domain'}) { 3340: return $extdom; 3341: } 3342: unless(grep(/^\Q$extdom\E$/,@possible_doms)) { 3343: push(@possible_doms,$extdom); 3344: } 3345: } 3346: } 3347: } 3348: if (@possible_doms) { 3349: @possible_doms = sort(@possible_doms); 3350: return $possible_doms[0]; 3351: } 3352: } 3353: $codedom = $env{'user.domain'}; 3354: if ($env{'request.role.domain'} ne '') { 3355: $codedom = $env{'request.role.domain'}; 3356: } 3357: } 3358: return $codedom; 3359: } 3360: 3361: sub display_navbuttons { 3362: my ($r,$dom,$formname,$prev,$prevtext,$next,$nexttext,$state,$other,$othertext) = @_; 3363: $r->print('<div class="LC_navbuttons">'); 3364: if ($prev) { 3365: $r->print('<input type="button" name="previous" value = "'.$prevtext.'" '. 3366: 'onclick="javascript:backPage('."document.$formname,'$prev'".')"/>'. 3367: (' 'x3)); 3368: } elsif ($prevtext) { 3369: $r->print('<input type="button" name="previous" value = "'.$prevtext.'" '. 3370: 'onclick="javascript:history.back()"/>'.(' 'x3)); 3371: } 3372: if ($state eq 'details') { 3373: $r->print(' <input type="button" name="other" value="'.$othertext.'" '. 3374: 'onclick="javascript:nextPage('."document.$formname,'$other'". 3375: ')" />'); 3376: } 3377: my $gotnext; 3378: if ($state eq 'courseinfo') { 3379: $r->print('<input type="button" name="next" value="'.$nexttext.'" '. 3380: 'onclick="javascript:validateForm();" />'); 3381: $gotnext = 1; 3382: } elsif ($state eq 'enrollment') { 3383: if (($env{'form.crstype'} eq 'official') && 3384: (&Apache::lonnet::auto_run('',$dom))) { 3385: $r->print('<input type="button" name="next" value="'.$nexttext.'" '. 3386: 'onclick="javascript:validateEnrollSections('."document.$formname,'$next'".');" />'); 3387: $gotnext = 1; 3388: } 3389: } elsif ($state eq 'personnel') { 3390: if ($env{'form.persontotal'} > 0) { 3391: $r->print('<input type="button" name="next" value="'.$nexttext.'" '. 3392: 'onclick="javascript:validatePersonnelSections('."document.$formname,'$next'".');" />'); 3393: $gotnext = 1; 3394: } 3395: } 3396: unless ($gotnext) { 3397: if ($next) { 3398: $r->print(' 3399: <input type="button" name="next" value="'.$nexttext.'" '. 3400: 'onclick="javascript:nextPage('."document.$formname,'$next'".')" />'); 3401: } 3402: } 3403: $r->print('</div>'); 3404: } 3405: 3406: sub print_request_outcome { 3407: my ($r,$lonhost,$dom,$codetitles,$code_order,$instcredits) = @_; 3408: my ($output,$cnum,$now,$req_notifylist,$crstype,$enrollstart,$enrollend, 3409: %sections,%crosslistings,%personnel,@baduname,@missingdom,%domconfig, 3410: $uniquecode); 3411: my $sectotal = $env{'form.sectotal'}; 3412: my $crosslisttotal = 0; 3413: $cnum = $env{'form.cnum'}; 3414: unless ($cnum =~ /^$match_courseid$/) { 3415: $output = &mt('Invalid LON-CAPA course number for the new course')."\n"; 3416: return $output; 3417: } 3418: $crstype = $env{'form.crstype'}; 3419: my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); 3420: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 3421: if (ref($domconfig{'requestcourses'}{'notify'}) eq 'HASH') { 3422: $req_notifylist = $domconfig{'requestcourses'}{'notify'}{'approval'}; 3423: } 3424: if (ref($domconfig{'requestcourses'}{'uniquecode'}) eq 'HASH') { 3425: $uniquecode = $domconfig{'requestcourses'}{'uniquecode'}{$crstype}; 3426: } 3427: } 3428: $now = time; 3429: my $ccrole = 'cc'; 3430: if ($crstype eq 'community') { 3431: $ccrole = 'co'; 3432: } 3433: my @instsections; 3434: if ($crstype eq 'official') { 3435: if (&Apache::lonnet::auto_run('',$dom)) { 3436: ($enrollstart,$enrollend)=&dates_from_form('enrollstart','enrollend'); 3437: } 3438: for (my $i=0; $i<$env{'form.sectotal'}; $i++) { 3439: if ($env{'form.sec_'.$i}) { 3440: if ($env{'form.secnum_'.$i} ne '') { 3441: my $sec = $env{'form.secnum_'.$i}; 3442: $sections{$i}{'inst'} = $sec; 3443: if (($sec ne '') && (!grep(/^\Q$sec\E$/,@instsections))) { 3444: push(@instsections,$sec); 3445: } 3446: $sections{$i}{'loncapa'} = $env{'form.loncapasec_'.$i}; 3447: $sections{$i}{'loncapa'} =~ s/\W//g; 3448: if ($sections{$i}{'loncapa'} eq 'none') { 3449: $sections{$i}{'loncapa'} = ''; 3450: } 3451: } 3452: } 3453: } 3454: for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { 3455: if ($env{'form.crosslist_'.$i}) { 3456: my $xlistinfo = ''; 3457: if (ref($code_order) eq 'ARRAY') { 3458: if (@{$code_order} > 0) { 3459: foreach my $item (@{$code_order}) { 3460: $xlistinfo .= $env{'form.crosslist_'.$i.'_'.$item}; 3461: } 3462: } 3463: } 3464: $crosslistings{$i}{'instcode'} = $xlistinfo; 3465: if ($xlistinfo ne '') { 3466: $crosslisttotal ++; 3467: } 3468: $crosslistings{$i}{'instsec'} = $env{'form.crosslist_'.$i.'_instsec'}; 3469: $crosslistings{$i}{'loncapa'} = $env{'form.crosslist_'.$i.'_lcsec'}; 3470: } 3471: } 3472: } else { 3473: $enrollstart = ''; 3474: $enrollend = ''; 3475: } 3476: my (%alerts,%rulematch,%inst_results,%curr_rules,%got_rules,%disallowmsg,%skipped); 3477: for (my $i=0; $i<$env{'form.persontotal'}; $i++) { 3478: my $uname = $env{'form.person_'.$i.'_uname'}; 3479: my $udom = $env{'form.person_'.$i.'_dom'}; 3480: if (($uname =~ /^$match_username$/) && ($udom =~ /^$match_domain$/)) { 3481: if (&Apache::lonnet::domain($udom) ne '') { 3482: unless (ref($personnel{$uname.':'.$udom}) eq 'HASH') { 3483: $personnel{$uname.':'.$udom} = { 3484: firstname => $env{'form.person_'.$i.'_firstname'}, 3485: lastname => $env{'form.person_'.$i.'_lastname'}, 3486: emailaddr => $env{'form.person_'.$i.'_emailaddr'}, 3487: }; 3488: if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { 3489: my $usertype = &get_usertype($udom,$uname,\%curr_rules,\%got_rules); 3490: if (&Apache::lonuserutils::can_create_user($udom,'requestcrs',$usertype)) { 3491: my ($allowed,$msg,$authtype,$authparam) = 3492: &check_newuser_rules($udom,$uname,\%alerts,\%rulematch, 3493: \%inst_results,\%curr_rules,\%got_rules); 3494: if ($allowed) { 3495: my %domdefaults = &Apache::lonnet::get_domain_defaults($udom); 3496: if ($usertype eq 'official') { 3497: if ($authtype eq '') { 3498: $authtype = $domdefaults{'auth_def'}; 3499: $authparam = $domdefaults{'auth_arg_def'}; 3500: } else { 3501: if ($authtype eq 'loc') { 3502: $authtype = 'localauth'; 3503: } elsif ($authtype eq 'int') { 3504: $authtype = 'internal'; 3505: } 3506: if ($authtype !~ /^(krb4|krb5|internal|localauth)$/) { 3507: $authtype = $domdefaults{'auth_def'}; 3508: $authparam = $domdefaults{'auth_arg_def'}; 3509: } 3510: } 3511: } elsif ($usertype eq 'unofficial') { 3512: if ($authtype eq '') { 3513: $authtype = 'internal'; 3514: $authparam = ''; 3515: } 3516: } else { 3517: $authtype = $domdefaults{'auth_def'}; 3518: $authparam = $domdefaults{'auth_arg_def'}; 3519: } 3520: if (($authtype eq '') || 3521: (($authtype =~/^krb(4|5)$/) && ($authparam eq '')) || 3522: ($authtype !~ /^(krb4|krb5|internal|localauth)$/)) { 3523: $skipped{$uname.':'.$udom} = 1; 3524: next; 3525: } else { 3526: $personnel{$uname.':'.$udom}{'authtype'} = $authtype; 3527: $personnel{$uname.':'.$udom}{'autharg'} = $authparam; 3528: } 3529: } else { 3530: $skipped{$uname.':'.$udom} = 1; 3531: next; 3532: } 3533: } else { 3534: $skipped{$uname.':'.$udom} = 1; 3535: next; 3536: } 3537: } 3538: } 3539: my $role = $env{'form.person_'.$i.'_role'}; 3540: unless ($role eq '') { 3541: if (ref($personnel{$uname.':'.$udom}{'roles'}) eq 'ARRAY') { 3542: my @curr_roles = @{$personnel{$uname.':'.$udom}{'roles'}}; 3543: unless (grep(/^\Q$role\E$/,@curr_roles)) { 3544: push(@{$personnel{$uname.':'.$udom}{'roles'}},$role); 3545: } 3546: } else { 3547: @{$personnel{$uname.':'.$udom}{'roles'}} = ($role); 3548: } 3549: if ($role eq $ccrole) { 3550: @{$personnel{$uname.':'.$udom}{$role}{'usec'}} = (); 3551: } else { 3552: my @currsec = &Apache::loncommon::get_env_multiple('form.person_'.$i.'_sec'); 3553: my @allsecs; 3554: foreach my $sec (@currsec) { 3555: next unless ($sec =~ /\w/); 3556: next if ($sec =~ /\W/); 3557: next if ($sec eq 'none'); 3558: push(@allsecs,$sec); 3559: } 3560: my $newsec = $env{'form.person_'.$i.'_newsec'}; 3561: $newsec =~ s/^\s+//; 3562: $newsec =~s/\s+$//; 3563: my @newsecs = split(/[\s,;]+/,$newsec); 3564: foreach my $sec (@newsecs) { 3565: next if ($sec =~ /\W/); 3566: next if ($sec eq 'none'); 3567: if ($sec ne '') { 3568: unless (grep(/^\Q$sec\E$/,@allsecs)) { 3569: push(@allsecs,$sec); 3570: } 3571: } 3572: } 3573: @{$personnel{$uname.':'.$udom}{$role}{'usec'}} = @allsecs; 3574: } 3575: } 3576: } else { 3577: push(@missingdom,$uname.':'.$udom); 3578: } 3579: } else { 3580: push(@baduname,$uname.':'.$udom); 3581: } 3582: } 3583: if (keys(%skipped)) { 3584: foreach my $key (keys(%skipped)) { 3585: delete($personnel{$key}); 3586: } 3587: } 3588: my ($accessstart,$accessend) = &dates_from_form('accessstart','accessend'); 3589: my $autodrops = 0; 3590: if ($env{'form.autodrops'}) { 3591: $autodrops = $env{'form.autodrops'}; 3592: } 3593: my $autoadds = 0; 3594: if ($env{'form.autoadds'}) { 3595: $autoadds = $env{'form.autoadds'}; 3596: } 3597: my $instcode = ''; 3598: if (exists($env{'form.instcode'})) { 3599: $instcode = $env{'form.instcode'}; 3600: } 3601: my $credits; 3602: if ($instcredits) { 3603: $credits = $instcredits; 3604: } elsif (exists($env{'form.coursecredits'})) { 3605: $credits = $env{'form.coursecredits'}; 3606: } 3607: my $clonecrs = ''; 3608: my $clonedom = ''; 3609: if (($env{'form.cloning'}) && 3610: ($env{'form.clonecrs'} =~ /^($match_courseid)$/) && 3611: ($env{'form.clonedom'} =~ /^($match_domain)$/)) { 3612: my $clonehome = &Apache::lonnet::homeserver($env{'form.clonecrs'}, 3613: $env{'form.clonedom'}); 3614: if ($clonehome ne 'no_host') { 3615: my $canclone = 3616: &Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, 3617: $env{'user.domain'},$env{'form.clonecrs'},$env{'form.clonedom'}, 3618: $crstype,$dom,$instcode); 3619: if ($canclone) { 3620: $clonecrs = $env{'form.clonecrs'}; 3621: $clonedom = $env{'form.clonedom'}; 3622: } 3623: } 3624: } 3625: if ($env{'form.chome'} eq 'default') { 3626: my %servers = &Apache::lonnet::get_servers($dom,'library'); 3627: my $numlib = keys(%servers); 3628: if ($numlib) { 3629: my $loadm=10000000; 3630: my $chome; 3631: foreach my $tryserver (keys(%servers)) { 3632: ($chome,$loadm) = 3633: &Apache::lonnet::compare_server_load($tryserver,$chome,$loadm); 3634: } 3635: $env{'form.chome'} = $chome; 3636: } 3637: } 3638: my $details = { 3639: owner => $env{'user.name'}, 3640: domain => $env{'user.domain'}, 3641: cdom => $dom, 3642: cnum => $cnum, 3643: coursehome => $env{'form.chome'}, 3644: cdescr => $env{'form.cdescr'}, 3645: crstype => $env{'form.crstype'}, 3646: instcode => $instcode, 3647: defaultcredits => $credits, 3648: uniquecode => $uniquecode, 3649: clonedom => $clonedom, 3650: clonecrs => $clonecrs, 3651: datemode => $env{'form.datemode'}, 3652: dateshift => $env{'form.dateshift'}, 3653: sectotal => $sectotal, 3654: sections => \%sections, 3655: crosslisttotal => $crosslisttotal, 3656: crosslists => \%crosslistings, 3657: autoadds => $autoadds, 3658: autodrops => $autodrops, 3659: enrollstart => $enrollstart, 3660: enrollend => $enrollend, 3661: accessstart => $accessstart, 3662: accessend => $accessend, 3663: personnel => \%personnel, 3664: }; 3665: my ($result,$output,$customized) = &process_request($r,$lonhost,$dom,$cnum,$crstype,$now,$details, 3666: $instcode,$req_notifylist,\@instsections,\%domconfig); 3667: return ($result,$output,$customized); 3668: } 3669: 3670: sub process_request { 3671: my ($r,$lonhost,$dom,$cnum,$crstype,$now,$details,$instcode,$req_notifylist,$instsections, 3672: $domconfig) = @_; 3673: my (@inststatuses,$storeresult,$creationresult,$output,$customized); 3674: my $val = 3675: &Apache::loncoursequeueadmin::get_processtype('course',$env{'user.name'}, 3676: $env{'user.domain'},$env{'user.adv'}, 3677: $dom,$crstype,\@inststatuses,$domconfig); 3678: if ($val eq '') { 3679: if ($crstype eq 'official') { 3680: $output = &mt('You are not permitted to request creation of official courses.'); 3681: } elsif ($crstype eq 'unofficial') { 3682: $output = &mt('You are not permitted to request creation of unofficial courses.'); 3683: } elsif ($crstype eq 'community') { 3684: $output = &mt('You are not permitted to request creation of communities'); 3685: } elsif ($crstype eq 'textbook') { 3686: $output = &mt('You are not permitted to request creation of textbook courses'); 3687: } else { 3688: $output = &mt('Unrecognized course type: [_1]',$crstype); 3689: } 3690: $storeresult = 'notpermitted'; 3691: } else { 3692: my ($disposition,$message,$reqstatus,$coursedesc,$accessstart,$accessend,%customvalidation); 3693: my %reqhash = ( 3694: reqtime => $now, 3695: crstype => $crstype, 3696: details => $details, 3697: ); 3698: my $requestkey = $dom.'_'.$cnum; 3699: my $validationerror; 3700: my $fullname = &Apache::loncommon::plainname($env{'user.name'}, 3701: $env{'user.domain'}); 3702: if (ref($details) eq 'HASH') { 3703: $coursedesc = $details->{'cdescr'}; 3704: $accessstart = $details->{'accessstart'}; 3705: $accessend = $details->{'accessend'}; 3706: } 3707: if ($val eq 'autolimit=') { 3708: $disposition = 'process'; 3709: } elsif ($val =~ /^autolimit=(\d+)$/) { 3710: my $limit = $1; 3711: $disposition = &check_autolimit($env{'user.name'},$env{'user.domain'}, 3712: $dom,$crstype,$limit,\$message); 3713: } elsif ($val eq 'validate') { 3714: my ($inststatuslist,$validationchk,$validation); 3715: if (ref($details) eq 'HASH') { 3716: if ($details->{'clonecrs'}) { 3717: $customvalidation{'_LC_clonefrom'} = $details->{'clonedom'}.'_'.$details->{'clonecrs'}; 3718: } 3719: } 3720: if (@inststatuses > 0) { 3721: $inststatuslist = join(',',@inststatuses); 3722: } 3723: my $instseclist; 3724: if (ref($instsections) eq 'ARRAY') { 3725: if (@{$instsections} > 0) { 3726: $instseclist = join(',',@{$instsections}); 3727: } 3728: } 3729: # 3730: # Retrieve any custom form information used for validation 3731: # 3732: my $preprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'prevalidate',$env{'user.name'}, 3733: $env{'user.domain'},$fullname,$coursedesc); 3734: if (ref($preprocess) eq 'HASH') { 3735: &custom_formitems($preprocess,\%customvalidation); 3736: } 3737: $validationchk = 3738: &Apache::lonnet::auto_courserequest_validation($dom, 3739: $env{'user.name'}.':'.$env{'user.domain'},$crstype, 3740: $inststatuslist,$instcode,$instseclist,\%customvalidation); 3741: if ($validationchk =~ /:/) { 3742: ($validation,$message) = split(':',$validationchk); 3743: } else { 3744: $validation = $validationchk; 3745: } 3746: if ($validation =~ /^error(.*)$/) { 3747: $disposition = 'approval'; 3748: $validationerror = $1; 3749: } else { 3750: $disposition = $validation; 3751: } 3752: } else { 3753: $disposition = 'approval'; 3754: } 3755: $reqhash{'disposition'} = $disposition; 3756: $reqstatus = $disposition; 3757: my ($modified,$queued,$token,%customitems); 3758: unless ($disposition eq 'rejected') { 3759: my $inprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'process',$env{'user.name'}, 3760: $env{'user.domain'},$fullname,$coursedesc,undef, 3761: undef,undef,\%customvalidation); 3762: # 3763: # Retrieve any custom form information submitted with review page and include in request details. 3764: # 3765: if (ref($inprocess) eq 'HASH') { 3766: &custom_formitems($inprocess,\%customitems); 3767: foreach my $key (keys(%customitems)) { 3768: $reqhash{'custom'}{$key} = $customitems{$key}; 3769: } 3770: } 3771: } 3772: if ($disposition eq 'rejected') { 3773: if ($crstype eq 'community') { 3774: $output = &mt('Your community request was rejected.'); 3775: } else { 3776: $output = &mt('Your course request was rejected.'); 3777: } 3778: if ($message) { 3779: $output .= '<div class="LC_warning">'.$message.'</div>'; 3780: } 3781: $storeresult = 'rejected'; 3782: } elsif ($disposition eq 'process') { 3783: my %domdefs = &Apache::lonnet::get_domain_defaults($dom); 3784: my ($logmsg,$newusermsg,$addresult,$enrollcount,$response,$keysmsg,%longroles,$code); 3785: my $type = 'Course'; 3786: if ($crstype eq 'community') { 3787: $type = 'Community'; 3788: } 3789: my @roles = &Apache::lonuserutils::roles_by_context('course','',$type); 3790: foreach my $role (@roles) { 3791: $longroles{$role}=&Apache::lonnet::plaintext($role,$type); 3792: } 3793: my $preamble = '<div id="LC_update" class="LC_info">'. 3794: '<br />'. 3795: &mt("Please be patient while your request is processed"). 3796: '<br /></div>'. 3797: '<div style="padding:0;clear:both;margin:0;border:0"></div>'; 3798: my $closure = <<ENDCLOSE; 3799: <script type="text/javascript"> 3800: // <![CDATA[ 3801: \$("#LC_update").hide('slow'); 3802: // ]]> 3803: </script> 3804: ENDCLOSE 3805: my %prog_state = &Apache::lonhtmlcommon::Create_PrgWin($r,undef,$preamble); 3806: &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Processing ...')); 3807: $r->rflush(); 3808: if (ref($details) eq 'HASH') { 3809: if ($details->{'clonecrs'}) { 3810: $customitems{'_LC_clonefrom'} = $details->{'clonedom'}.'_'.$details->{'clonecrs'}; 3811: } 3812: } 3813: $customitems{'_LC_ownerfullname'} = &Apache::loncommon::plainname($env{'user.name'},$env{'user.domain'},'first'); 3814: my $owneremail; 3815: my %emails = &Apache::loncommon::getemails(); 3816: foreach my $email ('permanentemail','critnotification','notification') { 3817: $owneremail = $emails{$email}; 3818: last if ($owneremail ne ''); 3819: } 3820: if ($owneremail ne '') { 3821: $customitems{'_LC_owneremail'} = $owneremail; 3822: } 3823: $customitems{'_LC_coursedomainname'} = &Apache::lonnet::domain($dom,'description'); 3824: $customitems{'_LC_coursedescription'} = $coursedesc; 3825: $customitems{'_LC_coursestartdate'} = $accessstart; 3826: $customitems{'_LC_courseenddate'} = $accessend; 3827: my ($result,$postprocess) = &Apache::loncoursequeueadmin::course_creation($dom,$cnum, 3828: 'autocreate',$details,\$logmsg,\$newusermsg,\$addresult, 3829: \$enrollcount,\$response,\$keysmsg,\%domdefs,\%longroles, 3830: \$code,\%customitems); 3831: &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Finished!')); 3832: &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); 3833: if (ref($postprocess) eq 'HASH') { 3834: $customized = $postprocess->{'createdcustomized'}; 3835: } 3836: if ($result eq 'created') { 3837: $disposition = 'created'; 3838: $reqstatus = 'created'; 3839: my $role_result = &update_requestors_roles($dom,$cnum,$crstype,$details, 3840: \%longroles); 3841: if ($crstype eq 'community') { 3842: $output = '<p>'.&mt('Your community request has been processed and the community has been created.'); 3843: } else { 3844: $output = '<p>'.&mt('Your course request has been processed and the course has been created.'); 3845: } 3846: if (($code) || ((ref($postprocess) eq 'HASH') && 3847: (($postprocess->{'createdweb'}) || ($postprocess->{'createdmsg'})))) { 3848: $output .= ¬ification_information($disposition,$env{'user.name'}.':'.$env{'user.domain'}, 3849: $dom,$cnum,$now,$code,$postprocess); 3850: } 3851: if ($code) { 3852: $reqhash{'code'} = $code; 3853: } 3854: if (ref($postprocess) eq 'HASH') { 3855: if (ref($postprocess->{'createdactions'}) eq 'HASH') { 3856: if (ref($postprocess->{'createdactions'}{'environment'}) eq 'HASH') { 3857: &Apache::loncoursequeueadmin::postprocess_crsenv($dom,$cnum, 3858: $postprocess->{'createdactions'}{'environment'}); 3859: } 3860: } 3861: } 3862: unless ($customized) { 3863: $output .= '<br />'.$role_result; 3864: } 3865: $output .= '</p>'; 3866: $creationresult = 'created'; 3867: # Flush the course logs so reverse user roles immediately updated 3868: unless ($registered_flush) { 3869: my $handlers = $r->get_handlers('PerlCleanupHandler'); 3870: $r->set_handlers('PerlCleanupHandler' => [\&Apache::lonnet::flushcourselogs,@{$handlers}]); 3871: $registered_flush=1; 3872: } 3873: if ($instcode ne '') { 3874: &Apache::lonnet::devalidate_cache_new('instcats',$dom); 3875: # Update cache of self-cataloging courses on institution's server(s). 3876: if (&Apache::lonnet::shared_institution($dom)) { 3877: unless ($registered_instcats) { 3878: my $handlers = $r->get_handlers('PerlCleanupHandler'); 3879: $r->set_handlers('PerlCleanupHandler' => [\&devalidate_remote_instcats,@{$handlers}]); 3880: $registered_instcats=1; 3881: $modified_dom = $dom; 3882: } 3883: } 3884: } 3885: } else { 3886: $output = '<span class="LC_error">'; 3887: if ($crstype eq 'community') { 3888: $output .= &mt('An error occurred when processing your community request.'); 3889: } else { 3890: $output .= &mt('An error occurred when processing your course request.'); 3891: } 3892: $output .= '<br />'. 3893: &mt('You may want to review the request details and submit the request again.'). 3894: '</span>'; 3895: $creationresult = 'error'; 3896: } 3897: } else { 3898: my $requestid = $cnum.'_'.$disposition; 3899: my $request = { 3900: $requestid => { 3901: timestamp => $now, 3902: crstype => $crstype, 3903: ownername => $env{'user.name'}, 3904: ownerdom => $env{'user.domain'}, 3905: description => $env{'form.cdescr'}, 3906: lonhost => $lonhost, 3907: }, 3908: }; 3909: if ($crstype eq 'official') { 3910: $request->{$requestid}->{'instcode'} = $instcode; 3911: } 3912: my $statuskey = 'status:'.$dom.':'.$cnum; 3913: my %userreqhash = &Apache::lonnet::get('courserequests',[$statuskey], 3914: $env{'user.domain'},$env{'user.name'}); 3915: if ($userreqhash{$statuskey} ne '') { 3916: $modified = 1; 3917: my $uname = &Apache::lonnet::get_domainconfiguser($dom); 3918: my %queuehash = &Apache::lonnet::get('courserequestqueue', 3919: [$cnum.'_approval', 3920: $cnum.'_pending'],$dom,$uname); 3921: if (($queuehash{$cnum.'_approval'} ne '') || 3922: ($queuehash{$cnum.'_pending'} ne '')) { 3923: $queued = 1; 3924: if (ref($queuehash{$cnum.'_pending'}) eq 'HASH') { 3925: $token = $queuehash{$cnum.'_pending'}{'token'}; 3926: } 3927: } 3928: } 3929: unless ($queued) { 3930: if (($disposition eq 'pending') && ($crstype ne 'official')) { 3931: my %reqinfo = ( 3932: $cnum.':'.$dom => $now.':'.$env{'user.name'}.':'.$env{'user.domain'}, 3933: ); 3934: $token = &Apache::lonnet::tmpput(\%reqinfo,$lonhost); 3935: $request->{$requestid}->{'token'} = $token; 3936: } 3937: my $putresult = &Apache::lonnet::newput_dom('courserequestqueue',$request, 3938: $dom); 3939: if ($putresult eq 'ok') { 3940: if ($crstype eq 'community') { 3941: $output .= &mt('Your community request has been recorded.'); 3942: } else { 3943: $output .= &mt('Your course request has been recorded.') 3944: } 3945: unless ($disposition eq 'pending') { 3946: $output .= '<br />'. 3947: ¬ification_information($disposition,$req_notifylist, 3948: $dom,$cnum,$now); 3949: } 3950: } else { 3951: $reqstatus = 'domainerror'; 3952: $reqhash{'disposition'} = $disposition; 3953: my $warning = &mt('An error occurred saving your request in the pending requests queue.'); 3954: $output = '<span class"LC_warning">'.$warning.'</span><br />'; 3955: } 3956: } 3957: } 3958: ($storeresult,my $updateresult) = 3959: &Apache::loncoursequeueadmin::update_coursereq_status(\%reqhash,$dom, 3960: $cnum,$reqstatus,'request',$env{'user.domain'},$env{'user.name'}); 3961: if ($storeresult eq 'ok') { 3962: my $postprocess; 3963: if (($disposition eq 'approval') || ($disposition eq 'pending')) { 3964: my $updateaction = $disposition; 3965: if ($disposition eq 'approval') { 3966: $updateaction = 'queued'; 3967: } 3968: my $fullname = &Apache::loncommon::plainname($env{'user.name'}, 3969: $env{'user.domain'}); 3970: $postprocess = 3971: &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,$updateaction,$env{'user.name'}, 3972: $env{'user.domain'},$fullname,$env{'form.cdescr'}); 3973: } 3974: if ($modified && $queued) { 3975: if ($crstype eq 'community') { 3976: $output .= '<p>'.&mt('Your community request has been updated').'</p>'; 3977: } else { 3978: $output .= '<p>'.&mt('Your course request has been updated').'</p>'; 3979: } 3980: if ($disposition eq 'approval') { 3981: $output .= ¬ification_information($disposition,$req_notifylist,$dom,$cnum,$now); 3982: } 3983: } 3984: if ($disposition eq 'approval') { 3985: if ((ref($postprocess) eq 'HASH') && 3986: ((ref($postprocess->{'queuedmsg'}) eq 'HASH') || ($postprocess->{'queuedweb'}))) { 3987: ¬ification_information($disposition,undef,$dom,$cnum,$now,undef,$postprocess); 3988: $customized = $postprocess->{'createdcustomized'}; 3989: } 3990: } elsif ($disposition eq 'pending') { 3991: my $pendingform; 3992: if ($crstype ne 'official') { 3993: $pendingform = &pending_validation_form($r,$dom,$cnum,$crstype,$now,$token, 3994: $lonhost,$env{'form.cdescr'}); 3995: } 3996: if ($pendingform) { 3997: $output .= $pendingform; 3998: } else { 3999: $output .= ¬ification_information($disposition,undef,$dom,$cnum,$now,undef,$postprocess); 4000: } 4001: if (ref($postprocess) eq 'HASH') { 4002: $customized = $postprocess->{'createdcustomized'}; 4003: } 4004: } 4005: } 4006: if ($validationerror ne '') { 4007: $output .= '<p class="LC_warning">'.&mt('An error occurred validating your request with institutional data sources: [_1].',$validationerror).'</p>'; 4008: } 4009: if ($updateresult) { 4010: $output .= $updateresult; 4011: } 4012: } 4013: if ($creationresult ne '') { 4014: return ($creationresult,$output,$customized); 4015: } else { 4016: return ($storeresult,$output,$customized); 4017: } 4018: } 4019: 4020: sub devalidate_remote_instcats { 4021: if ($modified_dom ne '') { 4022: my %servers = &Apache::lonnet::internet_dom_servers($modified_dom); 4023: my %thismachine; 4024: map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); 4025: if (keys(%servers)) { 4026: foreach my $server (keys(%servers)) { 4027: next if ($thismachine{$server}); 4028: &Apache::lonnet::remote_devalidate_cache($server,['instcats:'.$modified_dom]); 4029: } 4030: } 4031: $modified_dom = ''; 4032: } 4033: return; 4034: } 4035: 4036: sub custom_formitems { 4037: my ($preprocess,$customhash) = @_; 4038: return unless ((ref($preprocess) eq 'HASH') && (ref($customhash) eq 'HASH')); 4039: if (ref($preprocess->{'formitems'}) eq 'HASH') { 4040: foreach my $key (keys(%{$preprocess->{'formitems'}})) { 4041: if ($preprocess->{'formitems'}->{$key} eq 'multiple') { 4042: if (exists($env{'form.'.$key})) { 4043: my @items = &Apache::loncommon::get_env_multiple($env{'form.'.$key}); 4044: foreach my $item (@items) { 4045: $item =~ s/(`)/'/g; 4046: $item =~ s/\$/\(\$\)/g; 4047: push(@{$customhash->{$key}},$item); 4048: } 4049: } 4050: } else { 4051: if (exists($env{'form.'.$key})) { 4052: $customhash->{$key} = $env{'form.'.$key}; 4053: $customhash->{$key} =~ s/(`)/'/g; 4054: $customhash->{$key} =~ s/\$/\(\$\)/g; 4055: } 4056: } 4057: } 4058: } 4059: } 4060: 4061: sub update_requestors_roles { 4062: my ($dom,$cnum,$crstype,$details,$longroles) = @_; 4063: my $now = time; 4064: my ($active,$future,$numactive,$numfuture,$output); 4065: my $owner = $env{'user.name'}.':'.$env{'user.domain'}; 4066: if (ref($details) eq 'HASH') { 4067: if (ref($details->{'personnel'}) eq 'HASH') { 4068: my $ccrole = 'cc'; 4069: if ($crstype eq 'community') { 4070: $ccrole = 'co'; 4071: } 4072: unless (ref($details->{'personnel'}{$owner}) eq 'HASH') { 4073: $details->{'personnel'}{$owner} = { 4074: 'roles' => [$ccrole], 4075: $ccrole => { 'usec' => [] }, 4076: }; 4077: } 4078: my @roles; 4079: if (ref($details->{'personnel'}{$owner}{'roles'}) eq 'ARRAY') { 4080: @roles = sort(@{$details->{'personnel'}{$owner}{'roles'}}); 4081: unless (grep(/^\Q$ccrole\E$/,@roles)) { 4082: push(@roles,$ccrole); 4083: } 4084: } else { 4085: @roles = ($ccrole); 4086: } 4087: foreach my $role (@roles) { 4088: my $refresh=$env{'user.refresh.time'}; 4089: if ($refresh eq '') { 4090: $refresh = $env{'user.login.time'}; 4091: } 4092: if ($refresh eq '') { 4093: $refresh = $now; 4094: } 4095: my $start = $refresh-1; 4096: my $end = '0'; 4097: if ($role eq 'st') { 4098: if ($details->{'accessstart'} ne '') { 4099: $start = $details->{'accessstart'}; 4100: } 4101: if ($details->{'accessend'} ne '') { 4102: $end = $details->{'accessend'}; 4103: } 4104: } 4105: my @usecs; 4106: if ($role ne $ccrole) { 4107: if (ref($details->{'personnel'}{$owner}{$role}{'usec'}) eq 'ARRAY') { 4108: @usecs = @{$details->{'personnel'}{$owner}{$role}{'usec'}}; 4109: } 4110: } 4111: if ($role eq 'st') { 4112: if (@usecs > 1) { 4113: my $firstsec = $usecs[0]; 4114: @usecs = ($firstsec); 4115: } 4116: } 4117: if (@usecs == 0) { 4118: push(@usecs,''); 4119: } 4120: foreach my $usec (@usecs) { 4121: my (%userroles,%newrole,%newgroups,$spec,$area); 4122: my $area = '/'.$dom.'/'.$cnum; 4123: my $spec = $role.'.'.$area; 4124: if ($usec ne '') { 4125: $spec .= '/'.$usec; 4126: $area .= '/'.$usec; 4127: } 4128: if ($role =~ /^cr\//) { 4129: &Apache::lonnet::custom_roleprivs(\%newrole,$role,$dom, 4130: $cnum,$spec,$area); 4131: } else { 4132: &Apache::lonnet::standard_roleprivs(\%newrole,$role,$dom, 4133: $spec,$cnum,$area); 4134: } 4135: &Apache::lonnet::set_userprivs(\%userroles,\%newrole, 4136: \%newgroups); 4137: $userroles{'user.role.'.$spec} = $start.'.'.$end; 4138: &Apache::lonnet::appenv(\%userroles,[$role,'cm']); 4139: if (($end == 0) || ($end > $now)) { 4140: my $showrole = $role; 4141: if ($role =~ /^cr\//) { 4142: $showrole = &Apache::lonnet::plaintext($role,$crstype); 4143: } elsif (ref($longroles) eq 'HASH') { 4144: if ($longroles->{$role} ne '') { 4145: $showrole = $longroles->{$role}; 4146: } 4147: } 4148: if ($start <= $now) { 4149: $active .= '<li><a href="/adm/roles?selectrole=1&'. 4150: $spec.'=1">'.$showrole; 4151: if ($usec ne '') { 4152: $active .= ' - '.&mt('section:').' '.$usec; 4153: } 4154: $active .= '</a></li>'; 4155: $numactive ++; 4156: } else { 4157: $future .= '<li>'.$showrole; 4158: if ($usec ne '') { 4159: $future .= ' - '.&mt('section:').' '.$usec; 4160: } 4161: $future .= '</li>'; 4162: $numfuture ++; 4163: } 4164: } 4165: } 4166: } 4167: } 4168: } 4169: if ($active) { 4170: if ($numactive == 1) { 4171: if ($crstype eq 'Community') { 4172: $output = &mt('Use the following link to enter the community:'); 4173: } else { 4174: $output = &mt('Use the following link to enter the course:'); 4175: } 4176: } else { 4177: if ($crstype eq 'Community') { 4178: $output = &mt('Use the following links to your new roles to enter the community:'); 4179: } else { 4180: $output = &mt('Use the following links to your new roles to enter the course:'); 4181: } 4182: } 4183: $output .= ' <ul>'.$active.'</ul><br />'; 4184: } 4185: if ($future) { 4186: if ($crstype eq 'Community') { 4187: $output .= &mt('The following community [quant,_1,role] will become available for selection from your [_2]roles page[_3], once the default student access start date - [_4] - has been reached:',$numfuture,'<a href="/adm/roles">','</a>',&Apache::lonlocal::locallocaltime($details->{'accessstart'})) 4188: } else { 4189: $output .= &mt('The following course [quant,_1,role] will become available for selection from your [_2]roles page[_3], once the default student access start date - [_4] - has been reached:',$numfuture,'<a href="/adm/roles">','</a>',&Apache::lonlocal::locallocaltime($details->{'accessstart'})); 4190: } 4191: $output .= ' <ul>'.$future.'</ul>'; 4192: } 4193: return $output; 4194: } 4195: 4196: sub notification_information { 4197: my ($disposition,$req_notifylist,$dom,$cnum,$now,$code,$postprocess) = @_; 4198: my %emails = &Apache::loncommon::getemails(); 4199: my $address; 4200: if (($emails{'permanentemail'} ne '') || ($emails{'notification'} ne '')) { 4201: $address = $emails{'permanentemail'}; 4202: if ($address eq '') { 4203: $address = $emails{'notification'}; 4204: } 4205: } 4206: my $output; 4207: if ($disposition eq 'approval') { 4208: $output .= &mt('A message will be sent to your LON-CAPA account when a domain coordinator takes action on your request.').'<br />'. 4209: &mt('To access your LON-CAPA message, go to the Main Menu and click on "Send and Receive Messages".').'<br />'; 4210: if ($address ne '') { 4211: $output.= &mt('An e-mail will also be sent to: [_1] when this occurs.',$address).'<br />'; 4212: } 4213: if ($req_notifylist) { 4214: my $fullname = &Apache::loncommon::plainname($env{'user.name'}, 4215: $env{'user.domain'}); 4216: my $sender = $env{'user.name'}.':'.$env{'user.domain'}; 4217: &Apache::loncoursequeueadmin::send_selfserve_notification($req_notifylist,"$fullname ($env{'user.name'}:$env{'user.domain'})", 4218: 'undef',$env{'form.cdescr'},$now,'coursereq',$sender); 4219: } 4220: if (ref($postprocess) eq 'HASH') { 4221: if (ref($postprocess->{'queuedmsg'}) eq 'ARRAY') { 4222: if (scalar(@{$postprocess->{'queuedmsg'}}) > 0) { 4223: my $recipient = $env{'user.name'}.':'.$env{'user.domain'}; 4224: my $sender = $recipient; 4225: my $addmsg = []; 4226: foreach my $item (@{$postprocess->{'queuedmsg'}}) { 4227: if (ref($item) eq 'HASH') { 4228: if ($item->{'mt'} ne '') { 4229: push(@{$addmsg},$item); 4230: } 4231: } 4232: } 4233: if (scalar(@{$addmsg}) > 0) { 4234: &Apache::loncoursequeueadmin::send_selfserve_notification($recipient,$addmsg,undef, 4235: $env{'form.cdescr'},$now, 4236: 'queuedcrsreq',$sender); 4237: } 4238: } 4239: } 4240: if ($postprocess->{'queuedweb'}) { 4241: $output .= $postprocess->{'queuedweb'}; 4242: } 4243: } 4244: } elsif ($disposition eq 'pending') { 4245: my $pending_default = '<div class="LC_info">'. 4246: &mt('Your request has been placed in a queue pending administrative action.').'<br />'. 4247: &mt("Usually this means that your institution's information systems do not list you among the instructional personnel for this course.").'<br />'. 4248: &mt('The list of instructional personnel for the course will be automatically checked daily, and once you are listed the request will be processed.'). 4249: '</div>'; 4250: if (ref($postprocess) eq 'HASH') { 4251: if ($postprocess->{'pendingweb'}) { 4252: $output .= $postprocess->{'pendingweb'}; 4253: } else { 4254: $output .= $pending_default; 4255: } 4256: } else { 4257: $output .= $pending_default; 4258: } 4259: } elsif ($disposition eq 'created') { 4260: if (($code) || ((ref($postprocess) eq 'HASH') && 4261: ((ref($postprocess->{'createdmsg'}) eq 'ARRAY') || ($postprocess->{'createdweb'})))) { 4262: my $addmsg = []; 4263: my $recipient = $env{'user.name'}.':'.$env{'user.domain'}; 4264: my $sender = $recipient; 4265: if ($code) { 4266: push(@{$addmsg},{ 4267: mt => 'Students can automatically select your course: "[_1]" by entering this code: [_2]', 4268: args => [$env{'form.cdescr'},$code], 4269: }); 4270: $output .= '<p>'. 4271: &mt('Students can automatically select your course by entering this code: [_1].','<b>'.$code.'</b>'). 4272: '<br />'. 4273: &mt('A message has been sent to your LON-CAPA account with this information.'); 4274: if ($address ne '') { 4275: $output.= '<br />'.&mt('An e-mail has also been sent to: [_1] with this code.',$address); 4276: } 4277: $output .= '</p>'; 4278: } 4279: if (ref($postprocess) eq 'HASH') { 4280: if (ref($postprocess->{'createdmsg'}) eq 'ARRAY') { 4281: foreach my $item (@{$postprocess->{'createdmsg'}}) { 4282: if (ref($item) eq 'HASH') { 4283: if ($item->{'mt'} ne '') { 4284: push(@{$addmsg},$item); 4285: } 4286: } 4287: } 4288: } 4289: if ($postprocess->{'createdweb'}) { 4290: $output .= $postprocess->{'createdweb'} 4291: } 4292: } 4293: if (scalar(@{$addmsg}) > 0) { 4294: my $type = 'createdcrsreq'; 4295: if ($code) { 4296: $type = 'uniquecode'; 4297: } 4298: &Apache::loncoursequeueadmin::send_selfserve_notification($recipient,$addmsg,$dom.'_'.$cnum,$env{'form.cdescr'}, 4299: $now,$type,$sender); 4300: } 4301: } 4302: } else { 4303: $output .= '<div class="LC_warning">'. 4304: &mt('Your request status is: [_1].',$disposition). 4305: '</div>'; 4306: } 4307: return $output; 4308: } 4309: 4310: sub pending_validation_form { 4311: my ($r,$cdom,$cnum,$crstype,$now,$token,$lonhost,$cdesc) = @_; 4312: my $output; 4313: my %postvalues = ( 4314: 'owner' => $env{'user.name'}.':'.$env{'user.domain'}, 4315: 'course' => $cdom.'_'.$cnum, 4316: 'coursetype' => $crstype, 4317: ); 4318: my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$cdom); 4319: 4320: if (ref($domconfig{'requestcourses'}) eq 'HASH') { 4321: my ($url,$buttontext,$code,@fields); 4322: if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') { 4323: $postvalues{'description'} = $cdesc; 4324: $url = $domconfig{'requestcourses'}{'validation'}{'url'}; 4325: if (ref($domconfig{'requestcourses'}{'validation'}{'fields'}) eq 'ARRAY') { 4326: @fields = @{$domconfig{'requestcourses'}{'validation'}{'fields'}}; 4327: } 4328: $buttontext = $domconfig{'requestcourses'}{'validation'}{'button'}; 4329: $output .= $domconfig{'requestcourses'}{'validation'}{'markup'}; 4330: if (($url =~ m{^(https?\://|/)}) && (@fields > 0)) { 4331: $output .= '<form name="crsreqvalidation" action="'.$url.'" method="post">'."\n"; 4332: foreach my $field (@fields) { 4333: if ($postvalues{$field}) { 4334: $output .= '<input type="hidden" name="'.$field.'" value="'.$postvalues{$field}.'" />'."\n"; 4335: } 4336: } 4337: if ($buttontext eq '') { 4338: if ($crstype eq 'community') { 4339: $buttontext = &mt('Create community'); 4340: } else { 4341: $buttontext = &mt('Create course'); 4342: } 4343: } 4344: my $hostname = &Apache::lonnet::hostname($lonhost); 4345: my $protocol = $Apache::lonnet::protocol{$lonhost}; 4346: $protocol = 'http' if ($protocol ne 'https'); 4347: my $alias = &Apache::lonnet::use_proxy_alias($r,$lonhost); 4348: $hostname = $alias if ($alias ne ''); 4349: my $crscreator = $protocol.'://'.$hostname.'/cgi-bin/createpending.pl'; 4350: $output .= '<input type="hidden" name="crscreator" value="'.$crscreator.'" />'."\n". 4351: '<input type="hidden" name="token" value="'.$token.'" />'."\n". 4352: '<input type="submit" name="validate" value="'.$buttontext.'" />'."\n". 4353: '</form>'."\n"; 4354: } 4355: } 4356: } 4357: return $output; 4358: } 4359: 4360: sub check_autolimit { 4361: my ($uname,$udom,$dom,$crstype,$limit,$message) = @_; 4362: my %crsroles = &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'}, 4363: 'userroles',['active','future'],['cc','co'],[$dom]); 4364: my ($types,$typename) = &Apache::loncommon::course_types(); 4365: my %requests = &Apache::lonnet::dumpstore('courserequests',$udom,$uname); 4366: my $count = 0; 4367: foreach my $key (keys(%requests)) { 4368: my ($cdom,$cnum) = split('_',$key); 4369: if (ref($requests{$key}) eq 'HASH') { 4370: next if ($requests{$key}{'crstype'} ne $crstype); 4371: if (($crstype eq 'community') && 4372: (exists($crsroles{$cnum.':'.$cdom.':co'}))) { 4373: $count ++; 4374: } elsif ((($crstype eq 'official') || ($crstype eq 'unofficial') || ($crstype eq 'textbook')) && 4375: (exists($crsroles{$cnum.':'.$cdom.':cc'}))) { 4376: $count ++; 4377: } 4378: } 4379: } 4380: if ($count < $limit) { 4381: return 'process'; 4382: } else { 4383: if (ref($typename) eq 'HASH') { 4384: if ($crstype eq 'community') { 4385: $$message = &mt('Your request has not been processed because you have reached the limit for the number of communities.'). 4386: '<br />'.&mt("Your limit is [_1].",$limit); 4387: } else { 4388: $$message = &mt('Your request has not been processed because you have reached the limit for the number of courses of this type.'). 4389: '<br />'.&mt("Your $typename->{$crstype} limit is [_1].",$limit); 4390: } 4391: } 4392: return 'rejected'; 4393: } 4394: return; 4395: } 4396: 4397: sub retrieve_settings { 4398: my ($dom,$cnum,$udom,$uname) = @_; 4399: if ($udom eq '' || $uname eq '') { 4400: $udom = $env{'user.domain'}; 4401: $uname = $env{'user.name'}; 4402: } 4403: my ($result,%reqinfo) = &get_request_settings($dom,$cnum,$udom,$uname); 4404: if ($result eq 'ok') { 4405: if (($udom eq $reqinfo{'domain'}) && ($uname eq $reqinfo{'owner'})) { 4406: $env{'form.chome'} = $reqinfo{'coursehome'}; 4407: $env{'form.cdescr'} = $reqinfo{'cdescr'}; 4408: $env{'form.crstype'} = $reqinfo{'crstype'}; 4409: &generate_date_items($reqinfo{'accessstart'},'accessstart'); 4410: &generate_date_items($reqinfo{'accessend'},'accessend'); 4411: if ($reqinfo{'accessend'} == 0) { 4412: $env{'form.no_end_date'} = 1; 4413: } 4414: if (($reqinfo{'crstype'} eq 'official') && (&Apache::lonnet::auto_run('',$dom))) { 4415: &generate_date_items($reqinfo{'enrollstart'},'enrollstart'); 4416: &generate_date_items($reqinfo{'enrollend'},'enrollend'); 4417: } 4418: $env{'form.clonecrs'} = $reqinfo{'clonecrs'}; 4419: $env{'form.clonedom'} = $reqinfo{'clonedom'}; 4420: if (($reqinfo{'clonecrs'} ne '') && ($reqinfo{'clonedom'} ne '')) { 4421: $env{'form.cloning'} = 1; 4422: } 4423: $env{'form.datemode'} = $reqinfo{'datemode'}; 4424: $env{'form.dateshift'} = $reqinfo{'dateshift'}; 4425: if ($reqinfo{'crstype'} eq 'official') { 4426: $env{'form.autoadds'} = $reqinfo{'autoadds'}; 4427: $env{'form.autodrops'} = $reqinfo{'autodrops'}; 4428: if ($reqinfo{'instcode'} ne '') { 4429: $env{'form.sectotal'} = $reqinfo{'sectotal'}; 4430: $env{'form.crosslisttotal'} = $reqinfo{'crosslisttotal'}; 4431: $env{'form.instcode'} = $reqinfo{'instcode'}; 4432: my $crscode = { 4433: $cnum => $reqinfo{'instcode'}, 4434: }; 4435: &extract_instcode($dom,'instcode',$crscode,$cnum); 4436: (undef,undef,my $instcredits) = 4437: &Apache::lonnet::auto_validate_instcode(undef,$dom, 4438: $reqinfo{'instcode'}); 4439: if ($instcredits ne $reqinfo{'defaultcredits'}) { 4440: $env{'form.coursecredits'} = $reqinfo{'defaultcredits'}; 4441: } 4442: } 4443: } elsif (($reqinfo{'crstype'} eq 'unofficial') || ($reqinfo{'crstype'} eq 'textbook')) { 4444: $env{'form.coursecredits'} = $reqinfo{'defaultcredits'}; 4445: } 4446: my @currsec; 4447: if (ref($reqinfo{'sections'}) eq 'HASH') { 4448: foreach my $i (sort(keys(%{$reqinfo{'sections'}}))) { 4449: if (ref($reqinfo{'sections'}{$i}) eq 'HASH') { 4450: my $sec = $reqinfo{'sections'}{$i}{'inst'}; 4451: $env{'form.secnum_'.$i} = $sec; 4452: $env{'form.sec_'.$i} = '1'; 4453: if (!grep(/^\Q$sec\E$/,@currsec)) { 4454: push(@currsec,$sec); 4455: } 4456: $env{'form.loncapasec_'.$i} = $reqinfo{'sections'}{$i}{'loncapa'}; 4457: } 4458: } 4459: } 4460: if (ref($reqinfo{'crosslists'}) eq 'HASH') { 4461: foreach my $i (sort(keys(%{$reqinfo{'crosslists'}}))) { 4462: if (ref($reqinfo{'crosslists'}{$i}) eq 'HASH') { 4463: $env{'form.crosslist_'.$i} = '1'; 4464: $env{'form.crosslist_'.$i.'_instsec'} = $reqinfo{'crosslists'}{$i}{'instsec'}; 4465: $env{'form.crosslist_'.$i.'_lcsec'} = $reqinfo{'crosslists'}{$i}{'loncapa'}; 4466: if ($reqinfo{'crosslists'}{$i}{'instcode'} ne '') { 4467: my $key = $cnum.$i; 4468: my $crscode = { 4469: $key => $reqinfo{'crosslists'}{$i}{'instcode'}, 4470: }; 4471: &extract_instcode($dom,'crosslist',$crscode,$key,$i); 4472: } 4473: } 4474: } 4475: } 4476: if (ref($reqinfo{'personnel'}) eq 'HASH') { 4477: my $i = 0; 4478: foreach my $user (sort(keys(%{$reqinfo{'personnel'}}))) { 4479: my ($uname,$udom) = split(':',$user); 4480: if (ref($reqinfo{'personnel'}{$user}) eq 'HASH') { 4481: if (ref($reqinfo{'personnel'}{$user}{'roles'}) eq 'ARRAY') { 4482: foreach my $role (sort(@{$reqinfo{'personnel'}{$user}{'roles'}})) { 4483: $env{'form.person_'.$i.'_role'} = $role; 4484: $env{'form.person_'.$i.'_firstname'} = $reqinfo{'personnel'}{$user}{'firstname'}; 4485: $env{'form.person_'.$i.'_lastname'} = $reqinfo{'personnel'}{$user}{'lastname'}; ; 4486: $env{'form.person_'.$i.'_emailaddr'} = $reqinfo{'personnel'}{$user}{'emailaddr'}; 4487: $env{'form.person_'.$i.'_uname'} = $uname; 4488: $env{'form.person_'.$i.'_dom'} = $udom; 4489: if (ref($reqinfo{'personnel'}{$user}{$role}) eq 'HASH') { 4490: if (ref($reqinfo{'personnel'}{$user}{$role}{'usec'}) eq 'ARRAY') { 4491: my @usecs = @{$reqinfo{'personnel'}{$user}{$role}{'usec'}}; 4492: my @newsecs; 4493: if (@usecs > 0) { 4494: foreach my $sec (@usecs) { 4495: if (grep(/^\Q$sec\E/,@currsec)) { 4496: $env{'form.person_'.$i.'_sec'} = $sec; 4497: } else { 4498: push(@newsecs,$sec); 4499: } 4500: } 4501: } 4502: if (@newsecs > 0) { 4503: $env{'form.person_'.$i.'_newsec'} = join(',',@newsecs); 4504: } 4505: } 4506: } 4507: $i ++; 4508: } 4509: } 4510: } 4511: } 4512: $env{'form.persontotal'} = $i; 4513: } 4514: } 4515: } 4516: return $result; 4517: } 4518: 4519: sub get_request_settings { 4520: my ($dom,$cnum,$udom,$uname) = @_; 4521: my $requestkey = $dom.'_'.$cnum; 4522: my ($result,%reqinfo); 4523: if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { 4524: my %history = &Apache::lonnet::restore($requestkey,'courserequests',$udom,$uname); 4525: my $disposition = $history{'disposition'}; 4526: if (($disposition eq 'approval') || ($disposition eq 'pending')) { 4527: if (ref($history{'details'}) eq 'HASH') { 4528: %reqinfo = %{$history{'details'}}; 4529: $result = 'ok'; 4530: } else { 4531: $result = 'nothash'; 4532: } 4533: } else { 4534: $result = 'notqueued'; 4535: } 4536: } else { 4537: $result = 'invalid'; 4538: } 4539: return ($result,%reqinfo); 4540: } 4541: 4542: sub extract_instcode { 4543: my ($cdom,$element,$crscode,$crskey,$counter) = @_; 4544: my (%codes,@codetitles,%cat_titles,%cat_order); 4545: if (&Apache::lonnet::auto_instcode_format('requests',$cdom,$crscode,\%codes, 4546: \@codetitles,\%cat_titles, 4547: \%cat_order) eq 'ok') { 4548: if (ref($codes{$crskey}) eq 'HASH') { 4549: if (@codetitles > 0) { 4550: my $sel = $element; 4551: if ($element eq 'crosslist') { 4552: $sel .= '_'.$counter; 4553: } 4554: foreach my $title (@codetitles) { 4555: $env{'form.'.$sel.'_'.$title} = $codes{$crskey}{$title}; 4556: } 4557: } 4558: } 4559: } 4560: return; 4561: } 4562: 4563: sub generate_date_items { 4564: my ($currentval,$item) = @_; 4565: if ($currentval =~ /\d+/) { 4566: my ($tzname,$sec,$min,$hour,$mday,$month,$year) = 4567: &Apache::lonhtmlcommon::get_timedates($currentval); 4568: $env{'form.'.$item.'_day'} = $mday; 4569: $env{'form.'.$item.'_month'} = $month+1; 4570: $env{'form.'.$item.'_year'} = $year; 4571: } 4572: return; 4573: } 4574: 4575: sub print_textbook_form { 4576: my ($r,$dom,$incdoms,$domdefs,$settings,$can_request) = @_; 4577: my (%prefab,%ordered,%numprefab); 4578: my $crstype = 'textbook'; 4579: # 4580: # Retrieve list of prefabricated courses (textbook courses and templates) cloneable by user 4581: # 4582: foreach my $type ('textbooks','templates') { 4583: $numprefab{$type} = 0; 4584: if (ref($settings) eq 'HASH') { 4585: $prefab{$type} = $settings->{$type}; 4586: if (ref($prefab{$type}) eq 'HASH') { 4587: foreach my $item (keys(%{$prefab{$type}})) { 4588: my ($clonedom,$clonecrs) = split(/_/,$item); 4589: if (ref($prefab{$type}{$item}) eq 'HASH') { 4590: if (&Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, 4591: $env{'user.domain'},$clonecrs,$clonedom,$crstype,$dom)) { 4592: 4593: my $num = $prefab{$type}{$item}{'order'}; 4594: $ordered{$type}{$num} = $item; 4595: $numprefab{$type} ++; 4596: } 4597: } 4598: } 4599: } 4600: } 4601: } 4602: 4603: # 4604: # Check if domain has multiple library servers 4605: # 4606: my ($home_server_pick,$numlib) = 4607: &Apache::loncommon::home_server_form_item($dom,'chome', 4608: 'default','hide'); 4609: if ($numlib > 1) { 4610: $home_server_pick = &mt('Home Server for Course').': '.$home_server_pick.'<br />'; 4611: } 4612: 4613: # 4614: # Retrieve information about courses owned by user, or in which user has an active 4615: # Course Coordinator role 4616: # 4617: my $numcurrent; 4618: my %cloneable = &Apache::lonnet::courseiddump($dom,'.',1,'.',$env{'user.name'}.':'.$env{'user.domain'}, 4619: '.',undef,undef,'Course'); 4620: my %ccroles = &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'},'userroles', 4621: ['active'],['cc']); 4622: 4623: my $cc_clone = ''; 4624: foreach my $role (keys(%ccroles)) { 4625: my ($cnum,$cdom,$rest) = split(/:/,$role,3); 4626: $cc_clone .= $cdom.':'.$cnum.'&'; 4627: unless (exists($cloneable{$cdom.'_'.$cnum})) { 4628: my %courseinfo = &Apache::lonnet::coursedescription($cdom.'_'.$cnum,{'one_time' => 1}); 4629: $cloneable{$cdom.'_'.$cnum} = { 4630: context => $courseinfo{'internal.creationcontext'}, 4631: created => $courseinfo{'internal.created'}, 4632: creator => $courseinfo{'internal.creator'}, 4633: description => $courseinfo{'description'}, 4634: inst_code => $courseinfo{'coursecode'}, 4635: owner => $courseinfo{'internal.courseowner'}, 4636: releaserequired => $courseinfo{'internal.releaserequired'}, 4637: type => $courseinfo{'type'}, 4638: }; 4639: } 4640: } 4641: 4642: my $numcurrent = scalar(keys(%cloneable)); 4643: 4644: # 4645: # Retrieve information about courses from user's domain which user can clone, but which not owned 4646: # or cloneable based on Course Coordinator role. 4647: # 4648: my ($numdomcourses,%domcloneable); 4649: my %allcloneable = &Apache::lonnet::courseiddump($dom,'.',1,'.','.','.',undef,undef,'Course', 4650: undef,undef,undef,undef,undef, 4651: $env{'user.name'}.':'.$env{'user.domain'}, 4652: $cc_clone,1); 4653: foreach my $cid (keys(%allcloneable)) { 4654: unless (exists($cloneable{$cid})) { 4655: $domcloneable{$cid} = $allcloneable{$cid}; 4656: } 4657: } 4658: $numdomcourses = scalar(keys(%domcloneable)); 4659: 4660: my $fullname = &Apache::loncommon::plainname($env{'user.name'}, 4661: $env{'user.domain'}); 4662: 4663: # 4664: # Retrieve any custom form information prior to rendering page 4665: # 4666: 4667: my $initprocess = &Apache::lonnet::auto_crsreq_update($dom,undef,$crstype,'initializereview',$env{'user.name'}, 4668: $env{'user.domain'},$fullname); 4669: my %custominit; 4670: if (ref($initprocess) eq 'HASH') { 4671: &custom_formitems($initprocess,\%custominit); 4672: } 4673: 4674: # 4675: # Retrieve any custom onload actions or javascript used for page before rendering 4676: # 4677: 4678: my ($customonload,$customjs,$customvalidationjs); 4679: my $inprocess = &Apache::lonnet::auto_crsreq_update($dom,undef,$crstype,'prereview',$env{'user.name'}, 4680: $env{'user.domain'},$fullname,undef,undef, 4681: undef,undef,\%custominit); 4682: if (ref($inprocess) eq 'HASH') { 4683: $customonload = $inprocess->{'onload'}; 4684: $customjs = $inprocess->{'javascript'}; 4685: $customvalidationjs = $inprocess->{'validationjs'}; 4686: } 4687: 4688: my $postprocess = &Apache::lonnet::auto_crsreq_update($dom,undef,$crstype,'review', 4689: $env{'user.name'}, 4690: $env{'user.domain'},$fullname,undef,undef, 4691: undef,undef,\%custominit); 4692: 4693: my $jscript = &textbook_request_javascript(\%numprefab,$numcurrent,$numdomcourses,$customvalidationjs); 4694: $jscript .= $customjs; 4695: my %loaditems; 4696: $loaditems{'onload'} = 'javascript:uncheckAllRadio();'.$customonload; 4697: $r->print(&header('Course Request',$jscript,\%loaditems)); 4698: 4699: if (ref($can_request) eq 'HASH') { 4700: unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) { 4701: &Apache::lonhtmlcommon::add_breadcrumb( 4702: { href => '/adm/requestcourse', 4703: text => 'Pick action', 4704: }); 4705: } 4706: } 4707: &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'}); 4708: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests')); 4709: 4710: &startContentScreen($r,'textbookrequests'); 4711: # 4712: # Show domain selector form, if required. 4713: # 4714: if (@{$incdoms} > 1) { 4715: my $onchange = 'this.form.submit()'; 4716: $r->print('<form name="domforcourse" method="post" action="/adm/requestcourse">'. 4717: '<div><fieldset><legend>'.&mt('Domain').'</legend>'. 4718: &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms). 4719: '</fieldset></form>'); 4720: } 4721: 4722: # 4723: # Course request form 4724: # 4725: 4726: # 4727: # Course Title 4728: # 4729: $r->print('<form name="requestcourse" method="post" action="/adm/requestcourse" onsubmit="return validTextbookReq();">'. 4730: '<div>'. 4731: '<fieldset>'. 4732: '<legend>'.&mt('Course Information').'</legend>'. 4733: '<span class="LC_nobreak">'.&mt('Title').': '. 4734: '<input type="text" size="60" name="cdescr" value="" /></span><br />'. 4735: $home_server_pick.'<br /></fieldset>'. 4736: '</div>'); 4737: 4738: # 4739: # Content source selection, if more than one available 4740: # 4741: if (keys(%cloneable) || keys(%ordered) || keys(%domcloneable)) { 4742: $r->print('<div>'. 4743: '<fieldset><legend>'.&mt('Course Content').'</legend>'); 4744: if (keys(%ordered)) { 4745: if (ref($ordered{'textbooks'}) eq 'HASH') { 4746: $r->print('<span class="LC_nobreak"><label>'. 4747: '<input type="radio" name="cloning" value="textbook" onclick="javascript:cloneChoice();" />'. 4748: &mt('Load textbook content').'</span>'.(' 'x2).' '); 4749: } 4750: if (ref($ordered{'templates'}) eq 'HASH') { 4751: $r->print('<span class="LC_nobreak"><label>'. 4752: '<input type="radio" name="cloning" value="template" onclick="javascript:cloneChoice();" />'. 4753: &mt('Load pre-existing template').'</span>'.(' 'x2).' '); 4754: } 4755: } 4756: if (keys(%cloneable)) { 4757: $r->print('<span class="LC_nobreak"><label>'. 4758: '<input type="radio" name="cloning" value="existing" onclick="javascript:cloneChoice();" />'. 4759: &mt('Copy one of your courses').'</label></span>'.(' 'x2).' '); 4760: } 4761: if (keys(%domcloneable)) { 4762: $r->print('<span class="LC_nobreak"><label>'. 4763: '<input type="radio" name="cloning" value="colleague" onclick="javascript:cloneChoice();" />'. 4764: &mt("Copy a colleague's course").'</label></span>'.(' 'x2).' '); 4765: } 4766: $r->print('<span class="LC_nobreak"><label>'. 4767: '<input type="radio" name="cloning" value="none" checked="checked" onclick="javascript:cloneChoice();" />'. 4768: &mt('Empty course shell').'</label></span>'); 4769: } else { 4770: $r->print('<input type="hidden" name="cloning" value="none" />'); 4771: } 4772: 4773: # 4774: # Table of cloneable textbook courses 4775: # 4776: if (keys(%ordered)) { 4777: foreach my $type ('textbooks','templates') { 4778: my $divid = 'showtextbook'; 4779: my $radioid = 'book'; 4780: if ($type eq 'templates') { 4781: $divid = 'showtemplate'; 4782: $radioid = 'template'; 4783: } 4784: if (ref($ordered{$type}) eq 'HASH') { 4785: $r->print('<div id="'.$divid.'" style="display:none">'. 4786: &Apache::loncommon::start_data_table(). 4787: &Apache::loncommon::start_data_table_header_row(). 4788: '<th>'.&mt('Title').'</th>'); 4789: if ($type eq 'textbooks') { 4790: $r->print('<th>'.&mt('Author(s)').'</th>'); 4791: } 4792: $r->print('<th>'.&mt('Subject').'</th>'); 4793: if ($type eq 'textbooks') { 4794: $r->print('<th>'.&mt('Publisher').'</th>'. 4795: '<th>'.&mt('Book').'</th>'); 4796: } 4797: $r->print(&Apache::loncommon::end_data_table_header_row()); 4798: my @items = sort { $a <=> $b } keys(%{$ordered{$type}}); 4799: foreach my $num (@items) { 4800: my $item = $ordered{$type}{$num}; 4801: my $cleantitle=&HTML::Entities::encode($prefab{$type}{$item}{'title'},'<>&"'); 4802: $cleantitle=~s/'/\\'/g; 4803: $cleantitle =~ s/^\s+//; 4804: $r->print(&Apache::loncommon::start_data_table_row(). 4805: '<td><label><input type="radio" name="'.$radioid.'" value="'.$item.'" />'. 4806: $cleantitle.'</label></td>'); 4807: if ($type eq 'textbooks') { 4808: $r->print('<td>'.$prefab{$type}{$item}{'author'}.'</td>'); 4809: } 4810: $r->print('<td>'.$prefab{$type}{$item}{'subject'}.'</td>'); 4811: if ($type eq 'textbooks') { 4812: $r->print('<td>'.$prefab{$type}{$item}{'publisher'}.'</td>'. 4813: '<td><img border="0" src="'.$prefab{$type}{$item}{'image'}. 4814: '" alt="'.$cleantitle.'" /></td>'); 4815: } 4816: $r->print(&Apache::loncommon::end_data_table_row()); 4817: } 4818: $r->print(&Apache::loncommon::end_data_table(). 4819: '</div>'); 4820: } 4821: } 4822: } 4823: 4824: # 4825: # Table of user's current courses (owner and/or course coordinator) 4826: # 4827: my %lt = &clone_text(); 4828: if (keys(%cloneable)) { 4829: $r->print('<div id="showexisting" style="display:none">'. 4830: &clone_selection_table($dom,'owned',\%cloneable). 4831: '<p><input type="radio" name="owndatemode" value="delete" /> '.$lt{'ncd'}. 4832: '</label><br /><label>'. 4833: '<input type="radio" name="owndatemode" value="preserve" /> '.$lt{'prd'}. 4834: '</label><br /><label>'. 4835: '<input type="radio" name="owndatemode" value="shift" checked="checked" /> '. 4836: $lt{'shd'}.'</label>'. 4837: '<input type="text" size="5" name="owndateshift" value="364" />'. 4838: '</div>'); 4839: } 4840: # 4841: # Table of other cloneable courses from user's domain (exclude own courses) 4842: # 4843: if (keys(%domcloneable)) { 4844: $r->print('<div id="showcolleague" style="display:none">'. 4845: &clone_selection_table($dom,'colleague',\%domcloneable). 4846: '<p><input type="radio" name="colldatemode" value="delete" /> '.$lt{'ncd'}. 4847: '</label><br /><label>'. 4848: '<input type="radio" name="colldatemode" value="preserve" /> '.$lt{'prd'}. 4849: '</label><br /><label>'. 4850: '<input type="radio" name="colldatemode" value="shift" checked="checked" /> '. 4851: $lt{'shd'}.'</label>'. 4852: '<input type="text" size="5" name="colldateshift" value="364" />'. 4853: '</div>'); 4854: } 4855: 4856: # 4857: # End of content selector 4858: # 4859: if (keys(%cloneable) || keys(%domcloneable) || keys(%ordered)) { 4860: $r->print('</fieldset></div>'); 4861: } 4862: 4863: my %accesstitles = ( 4864: 'start' => 'Default start access', 4865: 'end' => 'Default end access', 4866: ); 4867: my %help_item = ( 4868: start => 'Course_Request_Access_Start', 4869: end => 'Course_Request_Access_End', 4870: ); 4871: my $starttime = time; 4872: my $endtime = time+(6*30*24*60*60); # 6 months from now, approx 4873: my $startform = &Apache::lonhtmlcommon::date_setter('requestcourse','accessstart', 4874: $starttime,'','','',1,'','','',1); 4875: my $endform = &Apache::lonhtmlcommon::date_setter('requestcourse','accessend', 4876: $endtime,'','','',1,'','','',1); 4877: # 4878: # Set default start and end dates for student access 4879: # 4880: $r->print('<div>'. 4881: '<fieldset><legend>'.&mt('Student Access Dates').'</legend>'. 4882: &Apache::loncommon::help_open_topic($help_item{'start'}). 4883: ' '.&mt($accesstitles{'start'}).$startform.'<br />'. 4884: &Apache::loncommon::help_open_topic($help_item{'end'}). 4885: ' '.&mt($accesstitles{'end'}).$endform.'<br /></div>'); 4886: 4887: # 4888: # Display any custom fields for this course type 4889: # 4890: if (ref($postprocess) eq 'HASH') { 4891: if ($postprocess->{'reviewweb'}) { 4892: $r->print($postprocess->{'reviewweb'}); 4893: } 4894: } 4895: 4896: # 4897: # Submit button 4898: # 4899: $r->print('<input type="hidden" name="crstype" value="textbook" />'. 4900: '<input type="hidden" name="action" value="process" />'. 4901: '<input type="submit" value="'.&mt('Create course').'" />'); 4902: 4903: # 4904: # End request form 4905: # 4906: $r->print('</form>'); 4907: &endContentScreen($r). 4908: $r->print(&Apache::loncommon::end_page()); 4909: return; 4910: } 4911: 4912: sub clone_selection_table { 4913: my ($dom,$name,$cloneableref) = @_; 4914: return unless ((ref($cloneableref) eq 'HASH') && (($name eq 'owned') || ($name eq 'colleague'))); 4915: my %allownernames; 4916: my %sortbytitle; 4917: my $output; 4918: foreach my $cid (sort(keys(%{$cloneableref}))) { 4919: if (ref($cloneableref->{$cid}) eq 'HASH') { 4920: my $cdesc = $cloneableref->{$cid}{'description'}; 4921: $cdesc =~ s/`/'/g; 4922: if ($cdesc ne '') { 4923: push(@{$sortbytitle{$cdesc}},$cid); 4924: } 4925: } 4926: } 4927: foreach my $title (sort(keys(%sortbytitle))) { 4928: if (ref($sortbytitle{$title}) eq 'ARRAY') { 4929: foreach my $cid (sort(@{$sortbytitle{$title}})) { 4930: my $cleantitle=&HTML::Entities::encode($title,'<>&"'); 4931: $cleantitle=~s/'/\\'/g; 4932: $cleantitle =~ s/^\s+//; 4933: my ($namestr,@owners,%ownernames); 4934: if ($cloneableref->{$cid}{'owner'} ne '') { 4935: push(@owners,$cloneableref->{$cid}{'owner'}); 4936: } 4937: if ($cloneableref->{$cid}{'co-owners'} ne '') { 4938: foreach my $item (split(/,/,$cloneableref->{$cid}{'co-owners'})) { 4939: if (($item ne '') && (!grep(/^\Q$item\E$/,@owners))) { 4940: push(@owners,$item); 4941: } 4942: } 4943: } 4944: foreach my $owner (@owners) { 4945: my ($ownername,$ownerdom); 4946: if ($owner =~ /:/) { 4947: ($ownername,$ownerdom) = split(/:/,$owner); 4948: } else { 4949: $ownername = $owner; 4950: if ($owner ne '') { 4951: $ownerdom = $dom; 4952: } 4953: } 4954: if ($ownername ne '' && $ownerdom ne '') { 4955: if (exists($allownernames{$ownername.':'.$ownerdom})) { 4956: $ownernames{$ownername.':'.$ownerdom} = $allownernames{$ownername.':'.$ownerdom}; 4957: } else { 4958: my %namehash=&Apache::loncommon::getnames($ownername,$ownerdom); 4959: $ownernames{$ownername.':'.$ownerdom} = \%namehash; 4960: $allownernames{$ownername.':'.$ownerdom} = $ownernames{$ownername.':'.$ownerdom}; 4961: } 4962: } 4963: } 4964: my @lastnames; 4965: foreach my $owner (keys(%ownernames)) { 4966: if (ref($ownernames{$owner}) eq 'HASH') { 4967: push(@lastnames,$ownernames{$owner}{'lastname'}); 4968: } 4969: } 4970: if (@lastnames) { 4971: $namestr = join(', ',sort(@lastnames)); 4972: } 4973: $output .= &Apache::loncommon::start_data_table_row(). 4974: '<td><label><input type="radio" name="'.$name.'" value="'.$cid.'" />'. 4975: ' '.$cleantitle.'</label></td>'. 4976: '<td>'.$namestr.'</td>'. 4977: &Apache::loncommon::end_data_table_row(); 4978: } 4979: } 4980: } 4981: if ($output) { 4982: return &Apache::loncommon::start_data_table(). 4983: &Apache::loncommon::start_data_table_header_row(). 4984: '<th>'.&mt('Title').'</th>'. 4985: '<th>'.&mt('Owner/co-owner(s)').'</th>'. 4986: &Apache::loncommon::end_data_table_header_row(). 4987: $output. 4988: &Apache::loncommon::end_data_table(); 4989: } 4990: return; 4991: } 4992: 4993: sub process_textbook_request { 4994: my ($r,$dom,$action,$domdefs,$domconfig,$can_request) = @_; 4995: my ($uniquecode,$req_notifylist); 4996: my $crstype = 'textbook'; 4997: if (ref($domconfig) eq 'HASH') { 4998: if (ref($domconfig->{'requestcourses'}) eq 'HASH') { 4999: if (ref($domconfig->{'requestcourses'}{'notify'}) eq 'HASH') { 5000: $req_notifylist = $domconfig->{'requestcourses'}{'notify'}{'approval'}; 5001: } 5002: if (ref($domconfig->{'requestcourses'}{'uniquecode'}) eq 'HASH') { 5003: $uniquecode = $domconfig->{'requestcourses'}{'uniquecode'}{$crstype}; 5004: } 5005: } 5006: } 5007: my $now = time; 5008: my $reqtype = $env{'form.cloning'}; 5009: my (@inststatuses,$storeresult,$creationresult); 5010: my $cnum = &Apache::lonnet::generate_coursenum($dom,'Course'); 5011: my ($clonefrom,$clonedom,$clonecrs); 5012: if ($reqtype eq 'textbook') { 5013: $clonefrom = $env{'form.book'}; 5014: } elsif ($reqtype eq 'template') { 5015: $clonefrom = $env{'form.template'}; 5016: } elsif ($reqtype eq 'existing') { 5017: $clonefrom = $env{'form.owned'}; 5018: } elsif ($reqtype eq 'colleague') { 5019: $clonefrom = $env{'form.colleague'}; 5020: } 5021: my ($accessstart,$accessend) = &dates_from_form('accessstart','accessend'); 5022: if ($clonefrom) { 5023: ($clonedom,$clonecrs) = split(/_/,$clonefrom); 5024: if (&Apache::lonnet::homeserver($clonecrs,$clonedom) ne 'no_host') { 5025: my $canclone = 5026: &Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, 5027: $env{'user.domain'},$clonecrs,$clonedom,$crstype,$dom); 5028: unless ($canclone) { 5029: undef($clonecrs); 5030: undef($clonedom); 5031: } 5032: } else { 5033: undef($clonecrs); 5034: undef($clonedom); 5035: } 5036: } 5037: $r->print(&header('Course Creation')); 5038: 5039: if (ref($can_request) eq 'HASH') { 5040: unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) { 5041: &Apache::lonhtmlcommon::add_breadcrumb( 5042: { href => '/adm/requestcourse', 5043: text => 'Pick action', 5044: }); 5045: } 5046: } 5047: &Apache::lonhtmlcommon::add_breadcrumb( 5048: { href => '/adm/requestcourse', 5049: text => "Create Course", 5050: } 5051: ); 5052: &Apache::lonhtmlcommon::add_breadcrumb({text=>'Request Processed'}); 5053: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests')); 5054: &startContentScreen($r,'textbookrequests'); 5055: 5056: my $details = { 5057: owner => $env{'user.name'}, 5058: domain => $env{'user.domain'}, 5059: cdom => $dom, 5060: cnum => $cnum, 5061: coursehome => $env{'form.chome'}, 5062: cdescr => $env{'form.cdescr'}, 5063: crstype => $crstype, 5064: uniquecode => $uniquecode, 5065: clonedom => $clonedom, 5066: clonecrs => $clonecrs, 5067: accessstart => $accessstart, 5068: accessend => $accessend, 5069: personnel => {}, 5070: }; 5071: if (($clonecrs ne '') && ($clonedom ne '')) { 5072: if ($reqtype eq 'existing') { 5073: $details->{datemode} = $env{'form.owndatemode'}; 5074: if ($details->{datemode} eq 'shift') { 5075: $details->{dateshift} = $env{'form.owndateshift'}; 5076: } else { 5077: $details->{dateshift} = ''; 5078: } 5079: } elsif ($reqtype eq 'colleague') { 5080: $details->{datemode} = $env{'form.colldatemode'}; 5081: if ($details->{datemode} eq 'shift') { 5082: $details->{dateshift} = $env{'form.colldateshift'}; 5083: } else { 5084: $details->{dateshift} = ''; 5085: } 5086: } elsif (($reqtype eq 'textbook') || ($reqtype eq 'template')) { 5087: $details->{datemode} = 'delete'; 5088: $details->{dateshift} = ''; 5089: } 5090: if ($details->{dateshift} ne '') { 5091: $details->{dateshift} =~ s/[^\d\.]+//g; 5092: } 5093: } else { 5094: $details->{datemode} = ''; 5095: $details->{dateshift} = ''; 5096: } 5097: my $lonhost = $r->dir_config('lonHostID'); 5098: $r->rflush(); 5099: my ($result,$output,$customized) = &process_request($r,$lonhost,$dom,$cnum,$crstype,$now,$details, 5100: '',$req_notifylist,[],$domconfig); 5101: $r->print($output); 5102: if (&Apache::loncoursequeueadmin::author_prompt()) { 5103: unless ($customized) { 5104: &print_author_prompt($r,$action,$cnum,$dom,$crstype,$result); 5105: } 5106: } elsif ($result eq 'created') { 5107: unless ($customized) { 5108: $r->print('<p><a href="/adm/requestcourse">'.&mt('Create another course').'</a></p>'); 5109: } 5110: } 5111: &endContentScreen($r); 5112: $r->print(&Apache::loncommon::end_page()); 5113: } 5114: 5115: sub textbook_request_javascript { 5116: my ($numprefab,$numcurrent,$numcolleague,$customvalidationjs) = @_; 5117: return unless (ref($numprefab) eq 'HASH'); 5118: return if (!$numprefab->{'textbooks'} && !$numprefab->{'templates'} && !$numcurrent && !$numcolleague); 5119: my %js_lt = &Apache::lonlocal::texthash( 5120: choose => 'Please select a content option.', 5121: textbook => 'Please select a textbook, or choose a different option.', 5122: template => 'Please select a template, or choose a different option.', 5123: existing => 'Please select one of your existing courses to copy, or choose a different option.', 5124: colleague => "Please select a colleague's course to copy, or choose a different option.", 5125: title => 'Please enter a course title.', 5126: ); 5127: &js_escape(\%js_lt); 5128: return <<"ENDSCRIPT"; 5129: function cloneChoice() { 5130: if (document.requestcourse.cloning) { 5131: var radioLength = document.requestcourse.cloning.length; 5132: if (radioLength == undefined) { 5133: var val = document.requestcourse.cloning.value; 5134: if ((val == 'textbook') || (val == 'template') || (val == 'existing') || (val == 'colleague')) { 5135: var elem = document.getElementById('show'+val); 5136: if (document.requestcourse.cloning.checked) { 5137: elem.style.display = 'block'; 5138: } else { 5139: uncheckRadio(val); 5140: elem.style.display = 'none'; 5141: } 5142: } 5143: } else { 5144: for (var i=0; i<radioLength; i++) { 5145: var val = document.requestcourse.cloning[i].value; 5146: if ((val == 'textbook') || (val == 'template') || (val == 'existing') || (val == 'colleague')) { 5147: var elem = document.getElementById('show'+val); 5148: if (document.requestcourse.cloning[i].checked) { 5149: elem.style.display = 'block'; 5150: } else { 5151: if (val == 'textbook') { 5152: uncheckRadio('book'); 5153: } 5154: if (val == 'template') { 5155: uncheckRadio('template'); 5156: } 5157: if (val == 'existing') { 5158: uncheckRadio('owned'); 5159: } 5160: if (val == 'colleague') { 5161: uncheckRadio('colleague'); 5162: } 5163: elem.style.display = 'none'; 5164: } 5165: } 5166: } 5167: } 5168: } 5169: return; 5170: } 5171: 5172: function uncheckRadio(radioGroupName) { 5173: var group = document.getElementsByName(radioGroupName); 5174: var radioLength = group.length; 5175: if (radioLength == undefined) { 5176: group.checked = false; 5177: } else { 5178: for (var i=0; i<radioLength; i++) { 5179: group[i].checked = false; 5180: } 5181: } 5182: return; 5183: } 5184: 5185: function uncheckAllRadio() { 5186: uncheckRadio('cloning'); 5187: var numbook = $numprefab->{'textbooks'}; 5188: var numtemplate = $numprefab->{'templates'}; 5189: var numcurrent = $numcurrent; 5190: var numcolleague = $numcolleague; 5191: if (numbook > 0) { 5192: uncheckRadio('textbook'); 5193: } 5194: if (numtemplate > 0) { 5195: uncheckRadio('template'); 5196: } 5197: if (numcurrent > 0) { 5198: uncheckRadio('existing'); 5199: } 5200: if (numcolleague > 0) { 5201: uncheckRadio('colleague'); 5202: } 5203: return; 5204: } 5205: 5206: function validTextbookReq() { 5207: if (document.requestcourse.cloning) { 5208: var cloneChoice = 0; 5209: var radioLength = document.requestcourse.cloning.length; 5210: if (radioLength == undefined) { 5211: if (document.requestcourse.cloning.checked == false) { 5212: alert("$js_lt{'choose'}"); 5213: return false; 5214: } else { 5215: cloneChoice = document.requestcourse.cloning.value; 5216: } 5217: } else { 5218: for (var i=0; i<radioLength; i++) { 5219: if (document.requestcourse.cloning[i].checked) { 5220: cloneChoice = document.requestcourse.cloning[i].value; 5221: break; 5222: } 5223: } 5224: if (cloneChoice == 0) { 5225: alert("$js_lt{'choose'}"); 5226: return false; 5227: } 5228: } 5229: var group; 5230: if ((cloneChoice == 'textbook') || (cloneChoice == 'template') || (cloneChoice == 'existing') || (cloneChoice == 'colleague')) { 5231: var group; 5232: if (cloneChoice == 'textbook') { 5233: group = document.getElementsByName('book'); 5234: } else { 5235: if (cloneChoice == 'template') { 5236: group = document.getElementsByName('template'); 5237: } else { 5238: if (cloneChoice == 'existing') { 5239: group = document.getElementsByName('owned'); 5240: } else { 5241: group = document.getElementsByName('colleague'); 5242: } 5243: } 5244: } 5245: var groupLength = group.length; 5246: var chosen = 0; 5247: if (groupLength == undefined) { 5248: if (group.checked) { 5249: chosen = 1; 5250: } 5251: } else { 5252: for (var j=0; j<groupLength; j++) { 5253: if (group[j].checked) { 5254: chosen = 1; 5255: break; 5256: } 5257: } 5258: } 5259: if (chosen == 0) { 5260: if (cloneChoice == 'textbook') { 5261: alert("$js_lt{'textbook'}"); 5262: } else { 5263: if (cloneChoice == 'template') { 5264: alert("$js_lt{'template'}"); 5265: } else { 5266: if (cloneChoice == 'existing') { 5267: alert("$js_lt{'existing'}"); 5268: } else { 5269: alert("$js_lt{'colleague'}"); 5270: } 5271: } 5272: } 5273: return false; 5274: } 5275: } 5276: } 5277: if (document.requestcourse.cdescr.value == '') { 5278: alert("$js_lt{'title'}"); 5279: return false; 5280: } 5281: $customvalidationjs 5282: return true; 5283: } 5284: 5285: ENDSCRIPT 5286: 5287: } 5288: 5289: sub textbook_request_disabled { 5290: my ($r,$dom,$action,$can_request) = @_; 5291: if (ref($can_request) eq 'HASH') { 5292: if ($action eq 'process') { 5293: unless ((scalar(keys(%{$can_request})) == 1)) { 5294: &Apache::lonhtmlcommon::add_breadcrumb( 5295: { href => '/adm/requestcourse', 5296: text => 'Pick action', 5297: }); 5298: } 5299: } 5300: } 5301: $r->print(&header('Course Request')); 5302: &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'}); 5303: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'). 5304: '<div>'. 5305: '<p class="LC_info">'.&mt('You do not have privileges to request creation of textbook courses.').'</p>'); 5306: if (ref($can_request) eq 'HASH') { 5307: if (scalar(keys(%{$can_request})) > 1) { 5308: $r->print('<a href="/adm/requestcourse">'.&mt('Go back').'</a>'); 5309: } 5310: } 5311: $r->print('</div>'. 5312: &Apache::loncommon::end_page()); 5313: return; 5314: } 5315: 5316: sub startContentScreen { 5317: my ($r,$mode)=@_; 5318: $r->print("\n".'<ul class="LC_TabContentBigger" id="textbookreq">'."\n"); 5319: $r->print('<li'.(($mode eq 'textbookrequests')?' class="active"':'').'><a href="/adm/requestcourse"><b> '.&mt('Request a Course').' </b></a></li>'."\n"); 5320: $r->print('<li'.(($mode eq 'textbooklogs')?' class="active"':'').'><a href="/adm/requestcourse?action=log&crstype=textbook&tabs=on"><b> '.&mt('Course Request History').' </b></a></li>'."\n"); 5321: $r->print("\n".'</ul>'."\n"); 5322: $r->print('<div class="LC_Box" style="clear:both;margin:0;"><div id="mainbox" style="margin:0 0;padding:0 0;"><div class="LC_ContentBox" id="maincontentbox" style="display: block;">'); 5323: } 5324: 5325: sub endContentScreen { 5326: my ($r)=@_; 5327: $r->print('</div></div></div>'); 5328: } 5329: 5330: 1; 5331: