| … | |
… | |
| 6 | package WeBWorK::DB; |
6 | package WeBWorK::DB; |
| 7 | |
7 | |
| 8 | =head1 NAME |
8 | =head1 NAME |
| 9 | |
9 | |
| 10 | WeBWorK::DB - interface with the WeBWorK databases. |
10 | WeBWorK::DB - interface with the WeBWorK databases. |
|
|
11 | |
|
|
12 | =head1 SYNOPSIS |
|
|
13 | |
|
|
14 | my $db = WeBWorK::DB->new($courseEnvironment); |
|
|
15 | |
|
|
16 | my @userIDs = $db->listUsers(); |
|
|
17 | my $Sam = $db->{user}->{record}->new(); |
|
|
18 | |
|
|
19 | $Sam->user_id("sammy"); |
|
|
20 | $Sam->first_name("Sam"); |
|
|
21 | $Sam->last_name("Hathaway"); |
|
|
22 | # etc. |
|
|
23 | |
|
|
24 | $db->addUser($User); |
|
|
25 | my $Dennis = $db->getUser("dennis"); |
|
|
26 | $Dennis->status("C"); |
|
|
27 | $db->putUser->($Dennis); |
|
|
28 | |
|
|
29 | $db->deleteUser("sammy"); |
| 11 | |
30 | |
| 12 | =head1 DESCRIPTION |
31 | =head1 DESCRIPTION |
| 13 | |
32 | |
| 14 | WeBWorK::DB provides a consistent interface to a number of database backends. |
33 | WeBWorK::DB provides a consistent interface to a number of database backends. |
| 15 | Access and modification functions are provided for each logical table used by |
34 | Access and modification functions are provided for each logical table used by |
| 16 | the webwork system. The particular backend ("schema" and "driver"), record |
35 | the webwork system. The particular backend ("schema" and "driver"), record |
| 17 | class, data source, and additional parameters are specified by the %dbLayout |
36 | class, data source, and additional parameters are specified by the C<%dbLayout> |
| 18 | hash in the course environment. |
37 | hash in the course environment. |
| 19 | |
38 | |
| 20 | =head1 ARCHITECTURE |
39 | =head1 ARCHITECTURE |
| 21 | |
40 | |
| 22 | The new database system uses a three-tier architecture to insulate each layer |
41 | The new database system uses a three-tier architecture to insulate each layer |
| … | |
… | |
| 36 | =head2 Middle Layer: Schemas |
55 | =head2 Middle Layer: Schemas |
| 37 | |
56 | |
| 38 | The middle layer of the architecture is provided by one or more schema modules. |
57 | The middle layer of the architecture is provided by one or more schema modules. |
| 39 | They are called "schema" modules because they control the structure of the data |
58 | They are called "schema" modules because they control the structure of the data |
| 40 | for a table. This includes odd things like the way multiple tables are encoded |
59 | for a table. This includes odd things like the way multiple tables are encoded |
| 41 | in a single hash in the WWHash schema, and the encoding scheme used. |
60 | in a single hash in the WW1Hash schema, and the encoding scheme used. |
| 42 | |
61 | |
| 43 | The schema modules provide an API that matches the requirements of the DB |
62 | The schema modules provide an API that matches the requirements of the DB |
| 44 | layer, on a per-table basis. Each schema module has a style that determines |
63 | layer, on a per-table basis. Each schema module has a style that determines |
| 45 | which drivers it can interface with. For example, WW1Hash is a "hash" style |
64 | which drivers it can interface with. For example, WW1Hash is a "hash" style |
| 46 | schema. SQL is a "dbi" style schema. |
65 | schema. SQL is a "dbi" style schema. |
| … | |
… | |
| 76 | |
95 | |
| 77 | =head2 Bottom Layer: Drivers |
96 | =head2 Bottom Layer: Drivers |
| 78 | |
97 | |
| 79 | Driver modules implement a style for a schema. They provide physical access to |
98 | Driver modules implement a style for a schema. They provide physical access to |
| 80 | a data source containing the data for a table. The style of a driver determines |
99 | a data source containing the data for a table. The style of a driver determines |
| 81 | what methods it provides. All drivers provide connect(MODE) and disconnect() |
100 | what methods it provides. All drivers provide C<connect(MODE)> and |
| 82 | methods. A hash style driver provides a hash() method which returns the tied |
101 | C<disconnect()> methods. A hash style driver provides a C<hash()> method which |
| 83 | hash. A dbi style driver provides a handle() method which returns the DBI |
102 | returns the tied hash. A dbi style driver provides a C<handle()> method which |
| 84 | handle. |
103 | returns the DBI handle. |
| 85 | |
104 | |
| 86 | =head3 Examples |
105 | =head3 Examples |
| 87 | |
106 | |
| 88 | / hash \ / hash \ / hash \ <- style |
107 | / hash \ / hash \ / hash \ <- style |
| 89 | +--------+ +--------+ +--------+ |
108 | +--------+ +--------+ +--------+ |
| … | |
… | |
| 93 | / dbi \ / ldap \ |
112 | / dbi \ / ldap \ |
| 94 | +-------+ +--------+ |
113 | +-------+ +--------+ |
| 95 | | SQL | | LDAP | |
114 | | SQL | | LDAP | |
| 96 | +-------+ +--------+ |
115 | +-------+ +--------+ |
| 97 | |
116 | |
|
|
117 | =head2 Record Types |
|
|
118 | |
|
|
119 | In C<%dblayout>, each table is assigned a record class, used for passing |
|
|
120 | complete records to and from the database. The default record classes are |
|
|
121 | subclasses of the WeBWorK::DB::Record class, and are named as follows: User, |
|
|
122 | Password, PermissionLevel, Key, Set, UserSet, Problem, UserProblem. In the |
|
|
123 | following documentation, a reference the the record class for a table means the |
|
|
124 | record class currently defined for that table in C<%dbLayout>. |
|
|
125 | |
| 98 | =cut |
126 | =cut |
| 99 | |
127 | |
| 100 | use strict; |
128 | use strict; |
| 101 | use warnings; |
129 | use warnings; |
| 102 | use Data::Dumper; |
130 | use Data::Dumper; |
| … | |
… | |
| 107 | ################################################################################ |
135 | ################################################################################ |
| 108 | # constructor |
136 | # constructor |
| 109 | ################################################################################ |
137 | ################################################################################ |
| 110 | |
138 | |
| 111 | =head1 CONSTRUCTOR |
139 | =head1 CONSTRUCTOR |
|
|
140 | |
| 112 | =over |
141 | =over |
| 113 | =item new (ENVIRONMENT) |
|
|
| 114 | |
142 | |
|
|
143 | =item new($ce) |
|
|
144 | |
| 115 | The C<new> method creates a DB object and brings up the underlying schema/driver |
145 | The C<new> method creates a DB object and brings up the underlying |
| 116 | structure according to the C<%dbLayout> hash in the ENVIRONMENT. Environment is |
146 | schema/driver structure according to the C<%dbLayout> hash in $ce, a |
| 117 | a C<WeBWorK::CourseEnvironment> object. |
147 | WeBWorK::CourseEnvironment object. |
|
|
148 | |
|
|
149 | =back |
| 118 | |
150 | |
| 119 | =cut |
151 | =cut |
| 120 | |
152 | |
| 121 | sub new($$) { |
153 | sub new($$) { |
| 122 | my ($invocant, $ce) = @_; |
154 | my ($invocant, $ce) = @_; |
| … | |
… | |
| 151 | } |
183 | } |
| 152 | |
184 | |
| 153 | return $self; |
185 | return $self; |
| 154 | } |
186 | } |
| 155 | |
187 | |
|
|
188 | =head1 METHODS |
|
|
189 | |
|
|
190 | =cut |
|
|
191 | |
| 156 | ################################################################################ |
192 | ################################################################################ |
| 157 | # password functions |
193 | # password functions |
| 158 | ################################################################################ |
194 | ################################################################################ |
|
|
195 | |
|
|
196 | =head2 Password Methods |
|
|
197 | |
|
|
198 | =over |
|
|
199 | |
|
|
200 | =item listPasswords() |
|
|
201 | |
|
|
202 | Returns a list of user IDs representing the records in the password table. |
|
|
203 | |
|
|
204 | =cut |
| 159 | |
205 | |
| 160 | sub listPasswords($) { |
206 | sub listPasswords($) { |
| 161 | my ($self) = @_; |
207 | my ($self) = @_; |
| 162 | return map { $_->[0] } |
208 | return map { $_->[0] } |
| 163 | $self->{password}->list(undef); |
209 | $self->{password}->list(undef); |
| 164 | } |
210 | } |
| 165 | |
211 | |
|
|
212 | =item addPassword($Password) |
|
|
213 | |
|
|
214 | $Password is a record object. The password will be added to the password table |
|
|
215 | if a password with the same user ID does not already exist. If one does exist, |
|
|
216 | an exception is thrown. To add a password, a user with a matching user ID must |
|
|
217 | exist in the user table. |
|
|
218 | |
|
|
219 | =cut |
|
|
220 | |
| 166 | sub addPassword($$) { |
221 | sub addPassword($$) { |
| 167 | my ($self, $Password) = @_; |
222 | my ($self, $Password) = @_; |
| 168 | die "addPassword failed: user ", $Password->user_id, " does not exist.\n" |
223 | die __PACKAGE__, ": addPassword($Password) failed: user not found.\n" |
| 169 | unless $self->{user}->exists($Password->user_id); |
224 | unless $self->{user}->exists($Password->user_id); |
| 170 | return $self->{password}->add($Password); |
225 | return $self->{password}->add($Password); |
| 171 | } |
226 | } |
| 172 | |
227 | |
|
|
228 | =item getPassword($userID) |
|
|
229 | |
|
|
230 | If a record with a matching user ID exists, a record object containting that |
|
|
231 | record's data will be returned. If no such record exists, an undefined value |
|
|
232 | will be returned. |
|
|
233 | |
|
|
234 | =cut |
|
|
235 | |
| 173 | sub getPassword($$) { |
236 | sub getPassword($$) { |
| 174 | my ($self, $userID) = @_; |
237 | my ($self, $userID) = @_; |
|
|
238 | die __PACKAGE__, ": getPassword() failed: you must specify a userID.\n" |
|
|
239 | unless $userID; |
| 175 | return $self->{password}->get($userID); |
240 | return $self->{password}->get($userID); |
| 176 | } |
241 | } |
|
|
242 | |
|
|
243 | =item putPassword($Password) |
|
|
244 | |
|
|
245 | $Password is a record object. If a password record with the same user ID exists |
|
|
246 | in the password table, the data in the record is replaced with the data in |
|
|
247 | $Password. If a matching password record does not exist, an exception is |
|
|
248 | thrown. |
|
|
249 | |
|
|
250 | =cut |
| 177 | |
251 | |
| 178 | sub putPassword($$) { |
252 | sub putPassword($$) { |
| 179 | my ($self, $Password) = @_; |
253 | my ($self, $Password) = @_; |
| 180 | return $self->{password}->put($Password); |
254 | return $self->{password}->put($Password); |
| 181 | } |
255 | } |
| 182 | |
256 | |
|
|
257 | =item deletePassword($userID) |
|
|
258 | |
|
|
259 | If a password record with a user ID matching $userID exists in the password |
|
|
260 | table, it is removed and the method returns a true value. If one does exist, |
|
|
261 | a false value is returned. |
|
|
262 | |
|
|
263 | =cut |
|
|
264 | |
| 183 | sub deletePassword($$) { |
265 | sub deletePassword($$) { |
| 184 | my ($self, $userID) = @_; |
266 | my ($self, $userID) = @_; |
| 185 | return $self->{password}->delete($userID); |
267 | return $self->{password}->delete($userID); |
| 186 | } |
268 | } |
|
|
269 | |
|
|
270 | =back |
|
|
271 | |
|
|
272 | =cut |
| 187 | |
273 | |
| 188 | ################################################################################ |
274 | ################################################################################ |
| 189 | # permission functions |
275 | # permission functions |
| 190 | ################################################################################ |
276 | ################################################################################ |
| 191 | |
277 | |
| … | |
… | |
| 484 | sub dumpDB($$) { |
570 | sub dumpDB($$) { |
| 485 | my ($self, $table) = @_; |
571 | my ($self, $table) = @_; |
| 486 | return $self->{$table}->dumpDB(); |
572 | return $self->{$table}->dumpDB(); |
| 487 | } |
573 | } |
| 488 | |
574 | |
|
|
575 | =head1 AUTHOR |
|
|
576 | |
|
|
577 | Written by Sam Hathaway, sh002i (at) math.rochester.edu. |
|
|
578 | |
| 489 | 1; |
579 | 1; |