Annotation of loncom/interface/lonrelrequtils.pm, revision 1.6
1.1 raeburn 1: #!/usr/bin/perl
2: # The LearningOnline Network
3: #
1.6 ! raeburn 4: # $Id: lonrelrequtils.pm,v 1.5 2016/03/04 21:43:16 raeburn Exp $
1.1 raeburn 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: =pod
31:
32: =head1 NAME
33:
34: lonrelrequtils.pm
35:
36: =head1 SYNOPSIS
37:
38: Contains utilities used to determine the LON-CAPA version
39: requirement in a course, based on course type, parameters,
40: responsetypes, and communication blocking events.
41:
42: =head1 DESCRIPTION
43:
44: lonrelrequtilities.pm includes a main subroutine:
45: get_release_req() which will return the current major
46: version and minor version requirement (if it exists).
47:
48: =head1 SUBROUTINES
49:
50: =over
51:
52: =item &init_global_hashes()
53:
54: Initializes package hashes containing version requirements for
55: parameters, responsetypes, course types, anonsurvey
56: parameter, and randomizetry parameter.
57:
58: =item &get_release_req()
59:
60: Returns current major version and minor version requirements for a course,
61: based on: coursetype, parameters in use, responsetypes in use in course
62: content, and communication blocking features in use in blocks with end dates
63: in the future, or in blocks triggered by activation of a timer in a timed quiz.
64:
65: Inputs: 5
66:
67: =over
68:
69: =item $cnum - course "number"
70:
71: =item $cdom - course domain
72:
73: =item $crstype - course type: Community or Course
74:
75: =item $readmap - boolean; if true, read course's top level map, and any
76: included maps recursively.
77:
78: =item $globals_set - boolean: if false, call init_global_hashes
79:
80: =back
81:
82:
83: =item ¶meter_constraints()
84:
85: Returns major version and minor version requirements for a course,
86: based on parameters in use in the course. (Parameters which have
1.3 raeburn 87: version requirements are listed in /home/httpd/lonTabs/releaseslist.xml).
1.1 raeburn 88:
89: Inputs: 2
90:
91: =over
92:
93: =item $cnum - course "number"
94:
95: =item $cdom - course domain
96:
97: =back
98:
99:
100: =item &coursetype_constraints()
101:
102: Returns major version and minor version requirements for a course,
103: taking into account course type (Community or Course).
104:
105: Inputs: 5
106:
107: =over
108:
109: =item $cnum - course "number"
110:
111: =item $cdom - course domain
112:
113: =item $crstype - course type: Community or Course
114:
115: =item $reqdmajor - major version requirements based on constraints
116: considered so far (parameters).
117:
118: =item $reqdminor - minor version requirements based on constraints
119: considered so far (parameters).
120:
121: =back
122:
123:
124: =item &commblock_constraints()
125:
126: Returns major version and minor version requirements for a course,
127: taking into account use of communication blocking (blocks for
128: printouts, specified folders/resources, and/or triggering of block
129: by a student starting a timed quiz.
130:
131: Inputs: 4
132:
133: =over
134:
135: =item $cnum - course "number"
136:
137: =item $cdom - course domain
138:
139: =item $reqdmajor - major version requirements based on constraints
140: considered so far (parameters and course type).
141:
142: =item $reqdminor - minor version requirements based on constraints
143: considered so far (parameters and course type).
144:
145: =back
146:
147:
148: =item &coursecontent_constraints()
149:
150: Returns major version and minor version requirements for a course,
151: taking into responsetypes in use in published assessment items
152: imported into a course.
153:
154: Inputs: 4
155:
156: =over
157:
158: =item $cnum - course "number"
159:
160: =item $cdom - course domain
161:
162: =item $reqdmajor - major version requirements based on constraints
163: considered so far (parameters, course type, blocks).
164:
165: =item $reqdminor - minor version requirements based on constraints
166: considered so far (parameters, course type, blocks).
167:
168: =back
169:
170:
171: =item &update_reqd_loncaparev()
172:
173: Returns major version and minor version requirements for a course,
174: taking into account new constraint type.
175:
176: Inputs: 4
177:
178: =over
179:
180: =item $major - major version requirements from new constraint type
181:
182: =item $minor - minor version requirements from new constraint type
183:
184: =item $reqdmajor - major version requirements from constraints
185: considered so far.
186:
187: =item $reqdminor - minor version requirements from constraints
188: considered so far.
189:
190: =back
191:
192:
193: =item &read_paramdata()
194:
195: Returns a reference to a hash populated with parameter settings in a
196: course (set both generally, and for specific students).
197:
198: Inputs: 2
199:
200: =over
201:
202: =item $cnum - course "number"
203:
204: =item $cdom - course domain
205:
206: =back
207:
208:
209: =item &modify_course_relreq()
210:
211: Updates course's minimum version requirement (internal.releaserequired) in
212: course's environment.db, and in user's current session, and in course's
213: record in nohist_courseids.db on course's home server. This can include
214: deleting an existing version requirement, downgrading to an earlier version,
215: or updating to a newer version.
216:
217: Note: if the current server's LON-CAPA version is older than the course's
218: current version requirement, and a downgrade to an earlier version is being
219: proposed, the change will NOT be made, because of the possibility that the
220: current server has not checked for an attribute only available with a more
221: recent version of LON-CAPA.
222:
223: Inputs: 9
224:
225: =over
226:
227: =item $newmajor - (optional) major version requirements
228:
229: =item $newminor - (optional) minor version requirements
230:
231: =item $cnum - course "number"
232:
233: =item $cdom - course domain
234:
235: =item $chome - lonHostID of course's home server
236:
237: =item $crstype - course type: Community or Course
238:
239: =item $cid - course ID
240:
241: =item $readmap - boolean; if true, read course's top level map, and any
242: included maps recursively.
243:
244: =item $getrelreq - boolean; if true, call &get_release_req() to
245: return the current major version and minor version requirements.
246: (needed if optional args: $newmajor and $newminor are not passed).
247:
248: =back
249:
250: =back
251:
252: =cut
253:
254: #################################################
255:
256: package Apache::lonrelrequtils;
257:
258: use strict;
259: use Apache::lonnet;
260: use Apache::loncommon();
261: use Apache::lonuserstate();
262: use Apache::loncoursedata();
263: use Apache::lonnavmaps();
264: use LONCAPA qw(:DEFAULT :match);
265:
266: sub init_global_hashes {
267: %Apache::lonrelrequtils::checkparms = ();
1.5 raeburn 268: %Apache::lonrelrequtils::checkparmvalsmatch = ();
269: %Apache::lonrelrequtils::checkparmnamesmatch = ();
1.1 raeburn 270: %Apache::lonrelrequtils::checkresponsetypes = ();
271: %Apache::lonrelrequtils::checkcrstypes = ();
272: %Apache::lonrelrequtils::anonsurvey = ();
273: %Apache::lonrelrequtils::randomizetry = ();
1.6 ! raeburn 274: %Apache::lonrelrequtils::exttool = ();
1.1 raeburn 275:
276: foreach my $key (keys(%Apache::lonnet::needsrelease)) {
1.5 raeburn 277: my ($item,$name,$value,$valuematch,$namematch) = split(/:/,$key);
1.1 raeburn 278: if ($item eq 'parameter') {
1.5 raeburn 279: if ($namematch ne '') {
280: $Apache::lonrelrequtils::checkparmnamesmatch{$namematch} = 1;
281: }
282: if ($name ne '') {
283: if ($value ne '') {
284: if (ref($Apache::lonrelrequtils::checkparms{$name}) eq 'ARRAY') {
285: unless(grep(/^\Q$name\E$/,@{$Apache::lonrelrequtils::checkparms{$name}})) {
286: push(@{$Apache::lonrelrequtils::checkparms{$name}},$value);
287: }
288: } else {
289: push(@{$Apache::lonrelrequtils::checkparms{$name}},$value);
1.3 raeburn 290: }
1.5 raeburn 291: } elsif ($valuematch ne '') {
292: if (ref($Apache::lonrelrequtils::checkparmvalsmatch{$name}) eq 'ARRAY') {
293: unless(grep(/^\Q$name\E$/,@{$Apache::lonrelrequtils::checkparmvalsmatch{$name}})) {
294: push(@{$Apache::lonrelrequtils::checkparmvalsmatch{$name}},$valuematch);
295: }
296: } else {
297: push(@{$Apache::lonrelrequtils::checkparmvalsmatch{$name}},$valuematch);
1.3 raeburn 298: }
299: }
1.1 raeburn 300: }
301: } elsif ($item eq 'resourcetag') {
302: if ($name eq 'responsetype') {
303: $Apache::lonrelrequtils::checkresponsetypes{$value} = $Apache::lonnet::needsrelease{$key}
304: }
305: } elsif ($item eq 'course') {
306: if ($name eq 'crstype') {
307: $Apache::lonrelrequtils::checkcrstypes{$value} = $Apache::lonnet::needsrelease{$key};
1.6 ! raeburn 308: } elsif ($name eq 'courserestype') {
! 309: if ($value eq 'exttool') {
! 310: ($Apache::lonrelrequtils::exttool{major},$Apache::lonrelrequtils::exttool{minor}) =
! 311: split(/\./,$Apache::lonnet::needsrelease{$key});
! 312: }
1.1 raeburn 313: }
314: }
315: }
316: ($Apache::lonrelrequtils::anonsurvey{major},$Apache::lonrelrequtils::anonsurvey{minor}) =
1.5 raeburn 317: split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey::'});
1.1 raeburn 318: ($Apache::lonrelrequtils::randomizetry{major},$Apache::lonrelrequtils::randomizetry{minor}) =
1.5 raeburn 319: split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry::'});
1.1 raeburn 320: return;
321: }
322:
323: sub get_release_req {
324: my ($cnum,$cdom,$crstype,$readmap,$globals_set) = @_;
325: if ($readmap) {
326: &Apache::lonuserstate::readmap($cdom.'/'.$cnum);
327: }
328: unless ($globals_set) {
329: &init_global_hashes();
330: }
331: # check all parameters
332: my ($reqdmajor,$reqdminor) = ¶meter_constraints($cnum,$cdom);
333:
334: # check course type
335: ($reqdmajor,$reqdminor) = &coursetype_constraints($cnum,$cdom,$crstype,$reqdmajor,
336: $reqdminor);
337: # check communication blocks
338: ($reqdmajor,$reqdminor) = &commblock_constraints($cnum,$cdom,$reqdmajor,$reqdminor);
339:
340: # check course contents
341: ($reqdmajor,$reqdminor) = &coursecontent_constraints($cnum,$cdom,$reqdmajor,$reqdminor);
342: return ($reqdmajor,$reqdminor);
343: }
344:
345: sub parameter_constraints {
346: my ($cnum,$cdom) = @_;
347: my ($reqdmajor,$reqdminor);
348: my $resourcedata=&read_paramdata($cnum,$cdom);
1.2 raeburn 349: my $now = time;
1.1 raeburn 350: if (ref($resourcedata) eq 'HASH') {
351: foreach my $key (keys(%{$resourcedata})) {
352: foreach my $item (keys(%Apache::lonrelrequtils::checkparms)) {
353: if ($key =~ /(\Q$item\E)$/) {
354: if (ref($Apache::lonrelrequtils::checkparms{$item}) eq 'ARRAY') {
355: my $value = $resourcedata->{$key};
356: if ($item eq 'examcode') {
357: if (&Apache::lonnet::validCODE($value)) {
358: $value = 'valid';
359: } else {
360: $value = '';
361: }
1.2 raeburn 362: } elsif ($item eq 'printstartdate') {
363: if ($value =~ /^\d+$/) {
364: if ($value > $now) {
365: $value = 'future';
366: }
367: }
368: } elsif ($item eq 'printenddate') {
369: if ($value =~ /^\d+$/) {
370: if ($value < $now) {
371: $value = 'past';
372: }
373: }
1.1 raeburn 374: }
375: if (grep(/^\Q$value\E$/,@{$Apache::lonrelrequtils::checkparms{$item}})) {
1.3 raeburn 376: my ($major,$minor) =
1.5 raeburn 377: split(/\./,$Apache::lonnet::needsrelease{'parameter:'.$item.':'.$value.'::'});
1.1 raeburn 378: ($reqdmajor,$reqdminor) =
379: &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
380: }
381: }
382: }
383: }
1.5 raeburn 384: foreach my $item (keys(%Apache::lonrelrequtils::checkparmvalsmatch)) {
1.3 raeburn 385: if ($key =~ /(\Q$item\E)$/) {
1.5 raeburn 386: if (ref($Apache::lonrelrequtils::checkparmvalsmatch{$item}) eq 'ARRAY') {
1.3 raeburn 387: my $value = $resourcedata->{$key};
1.5 raeburn 388: foreach my $entry (@{$Apache::lonrelrequtils::checkparmvalsmatch{$item}}) {
1.3 raeburn 389: my $regexp;
390: if (($item eq 'lenient') && ($entry eq 'weighted')) {
391: $regexp = '^[\-\.\d]+,[\-\.\d]+,[\-\.\d]+,[\-\.\d]+$';
392: } elsif (($item eq 'acc') && ($entry eq '_denyfrom_')) {
393: $regexp = '\!';
1.4 raeburn 394: } elsif (($item eq 'interval') && ($entry eq 'done')) {
395: $regexp = '^\d+_done$';
1.3 raeburn 396: }
397: if ($regexp ne '') {
398: if ($value =~ /$regexp/) {
399: my ($major,$minor) =
1.5 raeburn 400: split(/\./,$Apache::lonnet::needsrelease{'parameter:'.$item.'::'.$entry.':'});
1.3 raeburn 401: ($reqdmajor,$reqdminor) =
402: &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
403: last;
404: }
405: }
406: }
407: }
408: }
409: }
1.5 raeburn 410: foreach my $item (keys(%Apache::lonrelrequtils::checkparmnamesmatch)) {
411: my $regexp;
412: if ($item eq 'maplevelrecurse') {
413: $regexp = '\.(?:sequence|page)___\(rec\)\.';
414: }
415: if ($regexp ne '') {
416: if ($key =~ /$regexp/) {
417: my ($major,$minor) =
418: split(/\./,$Apache::lonnet::needsrelease{'parameter::::'.$item});
419: ($reqdmajor,$reqdminor) =
420: &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
421:
422: }
423: }
424: }
1.1 raeburn 425: }
426: }
427: return ($reqdmajor,$reqdminor);
428: }
429:
430: sub coursetype_constraints {
431: my ($cnum,$cdom,$crstype,$reqdmajor,$reqdminor) = @_;
432: if (defined($Apache::lonrelrequtils::checkcrstypes{$crstype})) {
433: my ($major,$minor) = split(/\./,$Apache::lonrelrequtils::checkcrstypes{$crstype});
434: ($reqdmajor,$reqdminor) =
435: &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
436: }
437: return ($reqdmajor,$reqdminor);
438: }
439:
440: sub commblock_constraints {
441: my ($cnum,$cdom,$reqdmajor,$reqdminor) = @_;
442: my %comm_blocks = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
443: my $now = time;
444: if (keys(%comm_blocks) > 0) {
445: foreach my $block (keys(%comm_blocks)) {
446: if ($block =~ /^firstaccess____(.+)$/) {
1.5 raeburn 447: my ($major,$minor) = split(/\./,$Apache::lonnet::needsrelease{'course:commblock:timer'});
1.1 raeburn 448: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
449: last;
450: } elsif ($block =~ /^(\d+)____(\d+)$/) {
451: my ($start,$end) = ($1,$2);
452: next if ($end < $now);
453: }
454: if (ref($comm_blocks{$block}) eq 'HASH') {
455: if (ref($comm_blocks{$block}{'blocks'}) eq 'HASH') {
456: if (ref($comm_blocks{$block}{'blocks'}{'docs'}) eq 'HASH') {
457: if (keys(%{$comm_blocks{$block}{'blocks'}{'docs'}}) > 0) {
1.5 raeburn 458: my ($major,$minor) = split(/\./,$Apache::lonnet::needsrelease{'course:commblock:docs'});
1.1 raeburn 459: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
460: last;
461: }
462: }
463: if ($comm_blocks{$block}{'blocks'}{'printout'} eq 'on') {
1.5 raeburn 464: my ($major,$minor) = split(/\./,$Apache::lonnet::needsrelease{'course:commblock:printout'});
1.1 raeburn 465: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
466: last;
467: }
468: }
469: }
470: }
471: }
472: return ($reqdmajor,$reqdminor);
473: }
474:
475: sub coursecontent_constraints {
476: my ($cnum,$cdom,$reqdmajor,$reqdminor) = @_;
477: my $navmap = Apache::lonnavmaps::navmap->new();
478: if (defined($navmap)) {
479: my %anonsubmissions = &Apache::lonnet::dump('nohist_anonsurveys',
480: $cdom,$cnum);
481: my %randomizetrysubm = &Apache::lonnet::dump('nohist_randomizetry',
482: $cdom,$cnum);
483: my %allresponses;
1.6 ! raeburn 484: my ($anonsurv_subm,$randbytry_subm,$exttool);
! 485: foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0)) {
! 486: if ($res->is_tool()) {
! 487: $exttool ++;
! 488: next;
! 489: }
1.1 raeburn 490: my %responses = $res->responseTypes();
491: foreach my $key (keys(%responses)) {
492: next unless(exists($Apache::lonrelrequtils::checkresponsetypes{$key}));
493: $allresponses{$key} += $responses{$key};
494: }
495: my @parts = @{$res->parts()};
496: my $symb = $res->symb();
497: foreach my $part (@parts) {
498: if (exists($anonsubmissions{$symb."\0".$part})) {
499: $anonsurv_subm = 1;
500: }
501: if (exists($randomizetrysubm{$symb."\0".$part})) {
502: $randbytry_subm = 1;
503: }
504: }
505: }
506: foreach my $key (keys(%allresponses)) {
507: my ($major,$minor) = split(/\./,$Apache::lonrelrequtils::checkresponsetypes{$key});
508: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor);
509: }
1.6 ! raeburn 510: if ($exttool) {
! 511: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($Apache::lonrelrequtils::exttool{major},
! 512: $Apache::lonrelrequtils::exttool{minor});
! 513: }
1.1 raeburn 514: if ($anonsurv_subm) {
515: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($Apache::lonrelrequtils::anonsurvey{major},
516: $Apache::lonrelrequtils::anonsurvey{minor},$reqdmajor,$reqdminor);
517: }
518: if ($randbytry_subm) {
519: ($reqdmajor,$reqdminor) = &update_reqd_loncaparev($Apache::lonrelrequtils::randomizetry{major},
520: $Apache::lonrelrequtils::randomizetry{minor},$reqdmajor,$reqdminor);
521: }
522: }
523: return ($reqdmajor,$reqdminor);
524: }
525:
526: sub update_reqd_loncaparev {
527: my ($major,$minor,$reqdmajor,$reqdminor) = @_;
528: if (($major ne '' && $major !~ /\D/) & ($minor ne '' && $minor !~ /\D/)) {
529: if ($reqdmajor eq '' || $reqdminor eq '') {
530: $reqdmajor = $major;
531: $reqdminor = $minor;
532: } elsif (($major > $reqdmajor) ||
533: ($major == $reqdmajor && $minor > $reqdminor)) {
534: $reqdmajor = $major;
535: $reqdminor = $minor;
536: }
537: }
538: return ($reqdmajor,$reqdminor);
539: }
540:
541: sub read_paramdata {
542: my ($cnum,$cdom)=@_;
543: my $resourcedata=&Apache::lonnet::get_courseresdata($cnum,$cdom);
544: my $classlist=&Apache::loncoursedata::get_classlist();
545: foreach my $student (keys(%{$classlist})) {
546: if ($student =~/^($LONCAPA::match_username)\:($LONCAPA::match_domain)$/) {
547: my ($tuname,$tudom)=($1,$2);
548: my $useropt=&Apache::lonnet::get_userresdata($tuname,$tudom);
549: foreach my $userkey (keys(%{$useropt})) {
550: if ($userkey=~/^\Q$cdom\E_\Q$cnum\E/) {
551: my $newkey=$userkey;
552: $newkey=~s/^(\Q$cdom\E_\Q$cnum\E\.)/$1\[useropt\:$tuname\:$tudom\]\./;
553: $$resourcedata{$newkey}=$$useropt{$userkey};
554: }
555: }
556: }
557: }
558: return $resourcedata;
559: }
560:
561: sub modify_course_relreq {
562: my ($newmajor,$newminor,$cnum,$cdom,$chome,$crstype,$cid,$readmap,$getrelreq) = @_;
563: if ($cnum eq '' || $cdom eq '' || $chome eq '' || $crstype eq '' || $cid eq '') {
564: $cid = $env{'request.course.id'};
565: $cdom = $env{'course.'.$cid.'.domain'};
566: $cnum = $env{'course.'.$cid.'.num'};
567: $chome = $env{'course.'.$cid.'.home'};
568: $crstype = $env{'course.'.$cid.'.type'};
569: if ($crstype eq '') {
570: $crstype = 'Course';
571: }
572: }
573: if ($getrelreq) {
574: ($newmajor,$newminor) = &get_release_req($cnum,$cdom,$crstype,$readmap);
575: }
576: my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
577: my $needsupdate;
578: if ($curr_reqd_hash{'internal.releaserequired'} eq '') {
579: if (($newmajor ne '') && ($newminor ne '')) {
580: $needsupdate = 1;
581: }
582: } else {
583: my ($currmajor,$currminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
584: my $lonhost = $Apache::lonnet::perlvar{'lonHostID'};
585: my $serverdom = $Apache::lonnet::perlvar{'lonDefDomain'};
586: my $serverrev = &Apache::lonnet::get_server_loncaparev($serverdom,$lonhost);
587: my ($servermajor,$serverminor) = split(/\./,$serverrev);
588: unless (($currmajor > $servermajor) || (($currmajor == $servermajor) && ($currminor > $serverminor))) {
589: if (($currmajor != $newmajor) || ($currminor != $newminor)) {
590: $needsupdate = 1;
591: }
592: }
593: }
594: if ($needsupdate) {
595: my %crsinfo = &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.');
596: my $result;
597: if (($newmajor eq '') && ($newminor eq '')) {
598: $result = &Apache::lonnet::del('environment',['internal.releaserequired'],$cdom,$cnum);
599: if ($result eq 'ok') {
600: &Apache::lonnet::delenv('course.'.$cid.'.internal.releaserequired');
601: $crsinfo{$cid}{'releaserequired'} = '';
602: }
603: } else {
604: my %needshash = (
605: 'internal.releaserequired' => $newmajor.'.'.$newminor,
606: );
607: $result = &Apache::lonnet::put('environment',\%needshash,$cdom,$cnum);
608: if ($result eq 'ok') {
609: &Apache::lonnet::appenv({'course.'.$cid.'.internal.releaserequired' => $newmajor.'.'.$newminor});
610: if (ref($crsinfo{$cid}) eq 'HASH') {
611: $crsinfo{$cid}{'releaserequired'} = $newmajor.'.'.$newminor
612: }
613: }
614: }
615: if ($result eq 'ok') {
616: &Apache::lonnet::courseidput($cdom,\%crsinfo,$chome,'notime');
617: }
618: }
619: return;
620: }
621:
622: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>