|
|
1 | ################################################################################ |
|
|
2 | # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project |
|
|
3 | # $Id$ |
|
|
4 | ################################################################################ |
|
|
5 | |
| 1 | package WeBWorK::CourseEnvironment; |
6 | package WeBWorK::CourseEnvironment; |
|
|
7 | |
|
|
8 | =head1 NAME |
|
|
9 | |
|
|
10 | WeBWorK::CourseEnvironment - Read configuration information from global.conf |
|
|
11 | and course.conf files. |
|
|
12 | |
|
|
13 | =cut |
| 2 | |
14 | |
| 3 | use strict; |
15 | use strict; |
| 4 | use warnings; |
16 | use warnings; |
| 5 | use Safe; |
17 | use Safe; |
|
|
18 | use WeBWorK::Utils qw(readFile); |
|
|
19 | use Opcode qw(empty_opset); |
| 6 | |
20 | |
| 7 | # new($invocant, $webworkRoot, $courseName) |
21 | # new($invocant, $webworkRoot, $webworkURLRoot, $pgRoot, $courseName) |
| 8 | # $invocant implicitly set by caller |
22 | # $invocant implicitly set by caller |
| 9 | # $webworkRoot directory that contains the WeBWorK distribution |
23 | # $webworkRoot directory that contains the WeBWorK distribution |
|
|
24 | # $webworkURLRoot URL that points to the WeBWorK system |
|
|
25 | # $pgRoot directory that contains the PG distribution |
| 10 | # $courseName name of the course being used |
26 | # $courseName name of the course being used |
| 11 | sub new { |
27 | sub new { |
| 12 | my $invocant = shift; |
28 | my $invocant = shift; |
| 13 | my $class = ref($invocant) || $invocant; |
29 | my $class = ref($invocant) || $invocant; |
| 14 | my $webworkRoot = shift; |
30 | my $webworkRoot = shift; |
|
|
31 | my $webworkURLRoot = shift; |
|
|
32 | my $pgRoot = shift; |
| 15 | my $courseName = shift; |
33 | my $courseName = shift || ""; |
| 16 | my $safe = Safe->new; |
34 | my $safe = Safe->new; |
| 17 | |
35 | |
| 18 | # set up some defaults that the environment files will need |
36 | # set up some defaults that the environment files will need |
| 19 | $safe->reval("\$webworkRoot = '$webworkRoot'"); |
37 | $safe->reval("\$webworkRoot = '$webworkRoot'"); |
|
|
38 | $safe->reval("\$webworkURLRoot = '$webworkURLRoot'"); |
|
|
39 | $safe->reval("\$pgRoot = '$pgRoot'"); |
| 20 | $safe->reval("\$courseName = '$courseName'"); |
40 | $safe->reval("\$courseName = '$courseName'"); |
| 21 | |
41 | |
|
|
42 | # Compile the "include" function with all opcodes available. |
|
|
43 | # why did this first version work (see the grep pattern?) |
|
|
44 | # my guess it's because the path on webwork.math starts with |
|
|
45 | # /ww/ !!!!!! |
|
|
46 | # my $include = 'sub include { |
|
|
47 | # my ($file) = @_; |
|
|
48 | # my $fullPath = "'.$webworkRoot.'/$file"; |
|
|
49 | # # This regex matches any string that: |
|
|
50 | # # : begins with ../ |
|
|
51 | # # : ends with /.. |
|
|
52 | # # : contains /../, or |
|
|
53 | # # : is .. |
|
|
54 | # if ($fullPath =~ m!(?:^|/)..(?:/|$)!) { |
|
|
55 | # die "Included file $file has potentially insecure path: contains \"..\""; |
|
|
56 | # } else { |
|
|
57 | # local @INC = (); |
|
|
58 | # do $fullPath; |
|
|
59 | # } |
|
|
60 | # }'; |
|
|
61 | my $include = q[ sub include { |
|
|
62 | my ($file) = @_; |
|
|
63 | my $fullPath = "].$webworkRoot.q[/$file"; |
|
|
64 | # This regex matches any string that: |
|
|
65 | # : begins with ../ |
|
|
66 | # : ends with /.. |
|
|
67 | # : contains /../, or |
|
|
68 | # : is .. |
|
|
69 | if ($fullPath =~ m!(?:^|/)\.\.(?:/|$)!) { |
|
|
70 | die "Included file $file has potentially insecure path: contains \"..\""; |
|
|
71 | } else { |
|
|
72 | local @INC = (); |
|
|
73 | do $fullPath or die "\n\n Couldn't include $fullPath. Has it been created from a distribution file?\n\n"; |
|
|
74 | } |
|
|
75 | } ]; |
|
|
76 | |
|
|
77 | my $maskBackup = $safe->mask; |
|
|
78 | $safe->mask(empty_opset); |
|
|
79 | $safe->reval($include); |
|
|
80 | $safe->mask($maskBackup); |
|
|
81 | |
| 22 | # determine location of globalEnvironmentFile |
82 | # determine location of globalEnvironmentFile |
| 23 | my $globalEnvironmentFile = "$webworkRoot/conf/global.conf"; |
83 | my $globalEnvironmentFile = "$webworkRoot/conf/global.conf"; |
| 24 | |
84 | |
| 25 | # read and evaluate the global environment file |
85 | # read and evaluate the global environment file |
| 26 | my $globalFileContents = readFile($globalEnvironmentFile); |
86 | my $globalFileContents = readFile($globalEnvironmentFile); |
| … | |
… | |
| 69 | |
129 | |
| 70 | bless $self, $class; |
130 | bless $self, $class; |
| 71 | return $self; |
131 | return $self; |
| 72 | } |
132 | } |
| 73 | |
133 | |
| 74 | sub hash2string { |
134 | 1; |
| 75 | my $hr = shift; |
|
|
| 76 | my $indent = shift || 0; |
|
|
| 77 | my $result; |
|
|
| 78 | foreach (keys %$hr) { |
|
|
| 79 | $result .= "\t"x$indent . "{$_} ="; |
|
|
| 80 | if (ref $hr->{$_} eq 'HASH') { |
|
|
| 81 | $result .= "\n"; |
|
|
| 82 | $result .= hash2string($hr->{$_}, $indent+1); |
|
|
| 83 | } elsif (ref $hr->{$_} eq 'ARRAY') { |
|
|
| 84 | $result .= "\n"; |
|
|
| 85 | $result .= array2string($hr->{$_}, $indent+1); |
|
|
| 86 | } else { |
|
|
| 87 | $result .= " " . $hr->{$_} . "\n"; |
|
|
| 88 | } |
|
|
| 89 | } |
|
|
| 90 | return $result; |
|
|
| 91 | } |
|
|
| 92 | |
135 | |
| 93 | sub array2string { |
136 | __END__ |
| 94 | my $ar = shift; |
|
|
| 95 | my $indent = shift || 0; |
|
|
| 96 | my $result; |
|
|
| 97 | foreach (0 .. @$ar-1) { |
|
|
| 98 | $result .= "\t"x$indent . "[$_] ="; |
|
|
| 99 | if (ref $ar->[$_] eq 'HASH') { |
|
|
| 100 | $result .= "\n"; |
|
|
| 101 | $result .= hash2string($ar->[$_], $indent+1); |
|
|
| 102 | } elsif (ref $ar->[$_] eq 'ARRAY') { |
|
|
| 103 | $result .= "\n"; |
|
|
| 104 | $result .= array2string($ar->[$_], $indent+1); |
|
|
| 105 | } else { |
|
|
| 106 | $result .= " " . $ar->[$_] . "\n"; |
|
|
| 107 | } |
|
|
| 108 | } |
|
|
| 109 | return $result; |
|
|
| 110 | } |
|
|
| 111 | |
137 | |
| 112 | # ----- utils ----- |
138 | =head1 SYNOPSIS |
| 113 | |
139 | |
| 114 | sub readFile { |
140 | use WeBWorK::CourseEnvironment; |
| 115 | my $fileName = shift; |
141 | $courseEnv = WeBWorK::CourseEnvironment->new($webworkRoot, $courseName); |
| 116 | open INPUTFILE, "<", $fileName |
142 | |
| 117 | or return; #die "Couldn't open environment file $fileName: $!"; |
143 | $timeout = $courseEnv->{sessionKeyTimeout}; |
| 118 | my $result = join "\n", <INPUTFILE>; |
144 | $mode = $courseEnv->{pg}->{options}->{displayMode}; |
| 119 | close INPUTFILE; |
145 | # etc... |
| 120 | return $result; |
|
|
| 121 | } |
|
|
| 122 | |
146 | |
| 123 | 1; |
147 | =head1 DESCRIPTION |
|
|
148 | |
|
|
149 | The WeBWorK::CourseEnvironment module reads the system-wide F<global.conf> and |
|
|
150 | course-specific F<course.conf> files used by WeBWorK to calculate and store |
|
|
151 | settings needed throughout the system. The F<.conf> files are perl source files |
|
|
152 | that can contain any code allowed under the default safe compartment opset. |
|
|
153 | After evaluation of both files, any package variables are copied out of the |
|
|
154 | safe compartment into a hash. This hash becomes the course environment. |
|
|
155 | |
|
|
156 | =head1 CONSTRUCTION |
|
|
157 | |
|
|
158 | =over |
|
|
159 | |
|
|
160 | =item new (ROOT, COURSE) |
|
|
161 | |
|
|
162 | The C<new> method finds the file F<conf/global.conf> relative to the given ROOT |
|
|
163 | directory. After reading this file, it uses the C<$courseFiles{environment}> |
|
|
164 | variable, if present, to locate the course environment file. If found, the file |
|
|
165 | is read and added to the environment. |
|
|
166 | |
|
|
167 | =back |
|
|
168 | |
|
|
169 | =head1 ACCESS |
|
|
170 | |
|
|
171 | There are no formal accessor methods. However, since the course environemnt is |
|
|
172 | a hash of hashes and arrays, is exists as the self hash of an instance |
|
|
173 | variable: |
|
|
174 | |
|
|
175 | $courseEnvironment->{someKey}->{someOtherKey}; |
|
|
176 | |
|
|
177 | =head1 AUTHOR |
|
|
178 | |
|
|
179 | Written by Sam Hathaway, sh002i (at) math.rochester.edu. |
|
|
180 | |
|
|
181 | =cut |