[system] / branches / rel-2-2-dev / webwork2 / lib / WeBWorK / DB.pm Repository:
ViewVC logotype

Annotation of /branches/rel-2-2-dev/webwork2/lib/WeBWorK/DB.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1236 - (view) (download) (as text)
Original Path: trunk/webwork2/lib/WeBWorK/DB.pm

1 : sh002i 775 ################################################################################
2 :     # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project
3 :     # $Id$
4 :     ################################################################################
5 :    
6 :     package WeBWorK::DB;
7 :    
8 :     =head1 NAME
9 :    
10 : sh002i 956 WeBWorK::DB - interface with the WeBWorK databases.
11 : sh002i 775
12 : sh002i 1012 =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");
30 :    
31 : sh002i 956 =head1 DESCRIPTION
32 :    
33 :     WeBWorK::DB provides a consistent interface to a number of database backends.
34 :     Access and modification functions are provided for each logical table used by
35 :     the webwork system. The particular backend ("schema" and "driver"), record
36 : sh002i 1012 class, data source, and additional parameters are specified by the C<%dbLayout>
37 : sh002i 956 hash in the course environment.
38 :    
39 :     =head1 ARCHITECTURE
40 :    
41 :     The new database system uses a three-tier architecture to insulate each layer
42 :     from the adjacent layers.
43 :    
44 :     =head2 Top Layer: DB
45 :    
46 :     The top layer of the architecture is the DB module. It provides the methods
47 :     listed below, and uses schema modules (via tables) to implement those methods.
48 :    
49 : sh002i 1201 / new* list* exists* add* get* put* delete* \ <- api
50 : sh002i 956 +------------------------------------------------------------------+
51 :     | DB |
52 :     +------------------------------------------------------------------+
53 :     \ password permission key user set set_user problem problem_user / <- tables
54 :    
55 :     =head2 Middle Layer: Schemas
56 :    
57 :     The middle layer of the architecture is provided by one or more schema modules.
58 :     They are called "schema" modules because they control the structure of the data
59 :     for a table. This includes odd things like the way multiple tables are encoded
60 : sh002i 1012 in a single hash in the WW1Hash schema, and the encoding scheme used.
61 : sh002i 956
62 :     The schema modules provide an API that matches the requirements of the DB
63 :     layer, on a per-table basis. Each schema module has a style that determines
64 :     which drivers it can interface with. For example, WW1Hash is a "hash" style
65 :     schema. SQL is a "dbi" style schema.
66 :    
67 :     =head3 Examples
68 :    
69 :     Both WeBWorK 1.x and 2.x courses use:
70 :    
71 :     / password permission key \ / user \ <- tables provided
72 :     +-----------------------------+ +----------------+
73 :     | Auth1Hash | | Classlist1Hash |
74 :     +-----------------------------+ +----------------+
75 :     \ hash / \ hash / <- driver style required
76 :    
77 :     WeBWorK 1.x courses also use:
78 :    
79 :     / set_user problem_user \ / set problem \
80 :     +-------------------------+ +---------------------+
81 :     | WW1Hash | | GlobalTableEmulator |
82 :     +-------------------------+ +---------------------+
83 :     \ hash / \ null /
84 :    
85 :     The GlobalTableEmulator schema emulates the global set and problem tables using
86 :     data from the set_user and problem_user tables.
87 :    
88 :     WeBWorK 2.x courses also use:
89 :    
90 :     / set set_user problem problem_user \
91 :     +-------------------------------------+
92 :     | WW2Hash |
93 :     +-------------------------------------+
94 :     \ hash /
95 :    
96 :     =head2 Bottom Layer: Drivers
97 :    
98 :     Driver modules implement a style for a schema. They provide physical access to
99 :     a data source containing the data for a table. The style of a driver determines
100 : sh002i 1012 what methods it provides. All drivers provide C<connect(MODE)> and
101 :     C<disconnect()> methods. A hash style driver provides a C<hash()> method which
102 :     returns the tied hash. A dbi style driver provides a C<handle()> method which
103 :     returns the DBI handle.
104 : sh002i 956
105 :     =head3 Examples
106 :    
107 :     / hash \ / hash \ / hash \ <- style
108 :     +--------+ +--------+ +--------+
109 :     | DB | | GDBM | | DB3 |
110 :     +--------+ +--------+ +--------+
111 :    
112 :     / dbi \ / ldap \
113 :     +-------+ +--------+
114 :     | SQL | | LDAP |
115 :     +-------+ +--------+
116 :    
117 : sh002i 1012 =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 :    
126 : sh002i 775 =cut
127 :    
128 :     use strict;
129 :     use warnings;
130 : sh002i 1096 use Carp;
131 : sh002i 904 use Data::Dumper;
132 : sh002i 1226 use WeBWorK::Timing;
133 : sh002i 775 use WeBWorK::Utils qw(runtime_use);
134 :    
135 :     ################################################################################
136 :     # constructor
137 :     ################################################################################
138 :    
139 : sh002i 956 =head1 CONSTRUCTOR
140 : sh002i 1012
141 : sh002i 956 =over
142 :    
143 : sh002i 1012 =item new($ce)
144 : sh002i 956
145 : sh002i 1012 The C<new> method creates a DB object and brings up the underlying
146 : sh002i 1035 schema/driver structure according to the C<%dbLayout> hash in C<$ce>, a
147 : sh002i 1012 WeBWorK::CourseEnvironment object.
148 :    
149 :     =back
150 :    
151 : sh002i 1108 =head2 C<%dbLayout> Format
152 :    
153 :     The C<%dbLayout> hash consists of items keyed by table names. The value of each
154 :     item is a reference to a hash containing the following items:
155 :    
156 :     =over
157 :    
158 :     =item record
159 :    
160 :     The name of a perl module to use for representing the data in a record.
161 :    
162 :     =item schema
163 :    
164 :     The name of a perl module to use for access to the table.
165 :    
166 :     =item driver
167 :    
168 :     The name of a perl module to use for access to the data source.
169 :    
170 :     =item source
171 :    
172 :     The location of the data source that should be used by the driver module.
173 :     Depending on the driver, this may be a path, a url, or a DBI spec.
174 :    
175 :     =item params
176 :    
177 :     A reference to a hash containing extra information needed by the schema. Some
178 :     schemas require parameters, some do not. Consult the documentation for the
179 :     schema in question.
180 :    
181 :     =back
182 :    
183 : sh002i 1167 For each table defined in C<%dbLayout>, C<new> loads the record, schema, and
184 :     driver modules. It the schema module's C<tables> method lists the current table
185 :     (or contains the string "*") and the output of the schema and driver modules'
186 :     C<style> methods match, the table is installed. Otherwise, an exception is
187 :     thrown.
188 :    
189 : sh002i 956 =cut
190 :    
191 : sh002i 775 sub new($$) {
192 : sh002i 814 my ($invocant, $ce) = @_;
193 : sh002i 775 my $class = ref($invocant) || $invocant;
194 : sh002i 798 my $self = {};
195 : sh002i 931 bless $self, $class; # bless this here so we can pass it to the schema
196 : sh002i 775
197 :     # load the modules required to handle each table, and create driver
198 : sh002i 1167 my %dbLayout = %{$ce->{dbLayout}};
199 :     foreach my $table (keys %dbLayout) {
200 :     my $layout = $dbLayout{$table};
201 : sh002i 798 my $record = $layout->{record};
202 : sh002i 775 my $schema = $layout->{schema};
203 :     my $driver = $layout->{driver};
204 :     my $source = $layout->{source};
205 : sh002i 808 my $params = $layout->{params};
206 : sh002i 775
207 : sh002i 798 runtime_use($record);
208 : sh002i 1096
209 :     runtime_use($driver);
210 :     my $driverObject = eval { $driver->new($source, $params) };
211 : sh002i 1167 croak "error instantiating DB driver $driver for table $table: $@"
212 : sh002i 1096 if $@;
213 :    
214 : sh002i 798 runtime_use($schema);
215 : sh002i 1096 my $schemaObject = eval { $schema->new(
216 :     $self, $driver->new($source, $params),
217 :     $table, $record, $params) };
218 : sh002i 1167 croak "error instantiating DB schema $schema for table $table: $@"
219 : sh002i 1096 if $@;
220 :    
221 :     $self->{$table} = $schemaObject;
222 : sh002i 775 }
223 :    
224 :     return $self;
225 :     }
226 :    
227 : sh002i 1012 =head1 METHODS
228 :    
229 :     =cut
230 :    
231 : sh002i 775 ################################################################################
232 :     # password functions
233 :     ################################################################################
234 :    
235 : sh002i 1012 =head2 Password Methods
236 :    
237 :     =over
238 :    
239 : sh002i 1201 =item newPassword()
240 :    
241 :     Returns a new, empty password object.
242 :    
243 :     =cut
244 :    
245 :     sub newPassword {
246 : sh002i 1236 my ($self, $prototype) = @_;
247 :     return $self->{password}->{record}->new($prototype);
248 : sh002i 1201 }
249 :    
250 : sh002i 1012 =item listPasswords()
251 :    
252 :     Returns a list of user IDs representing the records in the password table.
253 :    
254 :     =cut
255 :    
256 : sh002i 1096 sub listPasswords {
257 : sh002i 775 my ($self) = @_;
258 : sh002i 1096
259 :     croak "listPasswords: requires 0 arguments"
260 :     unless @_ == 1;
261 :    
262 : sh002i 808 return map { $_->[0] }
263 :     $self->{password}->list(undef);
264 : sh002i 775 }
265 :    
266 : sh002i 1012 =item addPassword($Password)
267 :    
268 :     $Password is a record object. The password will be added to the password table
269 :     if a password with the same user ID does not already exist. If one does exist,
270 :     an exception is thrown. To add a password, a user with a matching user ID must
271 :     exist in the user table.
272 :    
273 :     =cut
274 :    
275 : sh002i 808 sub addPassword($$) {
276 : sh002i 775 my ($self, $Password) = @_;
277 : sh002i 1096
278 :     croak "addPassword: requires 1 argument"
279 :     unless @_ == 2;
280 :     croak "addPassword: argument 1 must be of type ", $self->{password}->{record}
281 :     unless ref $Password eq $self->{password}->{record};
282 :     croak "addPassword: password exists (perhaps you meant to use putPassword?)"
283 :     if $self->{password}->exists($Password->user_id);
284 :     croak "addPassword: user ", $Password->user_id, " not found"
285 : sh002i 775 unless $self->{user}->exists($Password->user_id);
286 : sh002i 1096
287 : sh002i 1199 checkKeyfields($Password);
288 :    
289 : sh002i 775 return $self->{password}->add($Password);
290 :     }
291 :    
292 : sh002i 1012 =item getPassword($userID)
293 :    
294 :     If a record with a matching user ID exists, a record object containting that
295 :     record's data will be returned. If no such record exists, an undefined value
296 :     will be returned.
297 :    
298 :     =cut
299 :    
300 : sh002i 775 sub getPassword($$) {
301 :     my ($self, $userID) = @_;
302 : sh002i 1096
303 :     croak "getPassword: requires 1 argument"
304 :     unless @_ == 2;
305 :     croak "getPassword: argument 1 must contain a user_id"
306 :     unless defined $userID;
307 :    
308 : sh002i 775 return $self->{password}->get($userID);
309 :     }
310 :    
311 : sh002i 1012 =item putPassword($Password)
312 :    
313 :     $Password is a record object. If a password record with the same user ID exists
314 :     in the password table, the data in the record is replaced with the data in
315 :     $Password. If a matching password record does not exist, an exception is
316 :     thrown.
317 :    
318 :     =cut
319 :    
320 : sh002i 775 sub putPassword($$) {
321 :     my ($self, $Password) = @_;
322 : sh002i 1096
323 :     croak "putPassword: requires 1 argument"
324 :     unless @_ == 2;
325 :     croak "putPassword: argument 1 must be of type ", $self->{password}->{record}
326 :     unless ref $Password eq $self->{password}->{record};
327 :     croak "putPassword: password not found (perhaps you meant to use addPassword?)"
328 :     unless $self->{password}->exists($Password->user_id);
329 :    
330 : sh002i 1199 checkKeyfields($Password);
331 :    
332 : sh002i 775 return $self->{password}->put($Password);
333 :     }
334 :    
335 : sh002i 1012 =item deletePassword($userID)
336 :    
337 :     If a password record with a user ID matching $userID exists in the password
338 :     table, it is removed and the method returns a true value. If one does exist,
339 :     a false value is returned.
340 :    
341 :     =cut
342 :    
343 : sh002i 775 sub deletePassword($$) {
344 :     my ($self, $userID) = @_;
345 : sh002i 1096
346 :     croak "putPassword: requires 1 argument"
347 :     unless @_ == 2;
348 :     croak "deletePassword: argument 1 must contain a user_id"
349 :     unless defined $userID;
350 :    
351 : sh002i 775 return $self->{password}->delete($userID);
352 :     }
353 :    
354 : sh002i 1012 =back
355 :    
356 :     =cut
357 :    
358 : sh002i 775 ################################################################################
359 :     # permission functions
360 :     ################################################################################
361 :    
362 : sh002i 1108 =head2 Permission Level Methods
363 :    
364 :     =over
365 :    
366 : sh002i 1201 =item newPermissionLevel()
367 :    
368 :     Returns a new, empty permission level object.
369 :    
370 :     =cut
371 :    
372 :     sub newPermissionLevel {
373 : sh002i 1236 my ($self, $prototype) = @_;
374 :     return $self->{permission}->{record}->new($prototype);
375 : sh002i 1201 }
376 :    
377 : sh002i 1108 =item listPermissionLevels()
378 :    
379 :     Returns a list of user IDs representing the records in the permission table.
380 :    
381 :     =cut
382 :    
383 : sh002i 775 sub listPermissionLevels($) {
384 :     my ($self) = @_;
385 : sh002i 1096
386 :     croak "listPermissionLevels: requires 0 arguments"
387 :     unless @_ == 1;
388 :    
389 : sh002i 808 return map { $_->[0] }
390 :     $self->{permission}->list(undef);
391 : sh002i 775 }
392 :    
393 : sh002i 1108 =item addPermissionLevel($PermissionLevel)
394 :    
395 :     $PermissionLevel is a record object. The permission level will be added to the
396 :     permission table if a permission level with the same user ID does not already
397 :     exist. If one does exist, an exception is thrown. To add a permission level, a
398 :     user with a matching user ID must exist in the user table.
399 :    
400 :     =cut
401 :    
402 : sh002i 808 sub addPermissionLevel($$) {
403 : sh002i 775 my ($self, $PermissionLevel) = @_;
404 : sh002i 1096
405 :     croak "addPermissionLevel: requires 1 argument"
406 :     unless @_ == 2;
407 :     croak "addPermissionLevel: argument 1 must be of type ", $self->{permission}->{record}
408 :     unless ref $PermissionLevel eq $self->{permission}->{record};
409 :     croak "addPermissionLevel: permission level exists (perhaps you meant to use putPermissionLevel?)"
410 :     if $self->{permission}->exists($PermissionLevel->user_id);
411 :     croak "addPermissionLevel: user ", $PermissionLevel->user_id, " not found"
412 : sh002i 775 unless $self->{user}->exists($PermissionLevel->user_id);
413 : sh002i 1096
414 : sh002i 1199 checkKeyfields($PermissionLevel);
415 :    
416 : sh002i 775 return $self->{permission}->add($PermissionLevel);
417 :     }
418 :    
419 : sh002i 1108 =item getPermissionLevel($userID)
420 :    
421 :     If a record with a matching user ID exists, a record object containting that
422 :     record's data will be returned. If no such record exists, an undefined value
423 :     will be returned.
424 :    
425 :     =cut
426 :    
427 : sh002i 775 sub getPermissionLevel($$) {
428 :     my ($self, $userID) = @_;
429 : sh002i 1096
430 :     croak "getPermissionLevel: requires 1 argument"
431 :     unless @_ == 2;
432 :     croak "getPermissionLevel: argument 1 must contain a user_id"
433 :     unless defined $userID;
434 :    
435 : sh002i 775 return $self->{permission}->get($userID);
436 :     }
437 :    
438 : sh002i 1108 =item putPermissionLevel($PermissionLevel)
439 :    
440 :     $PermissionLevel is a record object. If a permission level record with the same
441 :     user ID exists in the permission table, the data in the record is replaced with
442 :     the data in $PermissionLevel. If a matching permission level record does not
443 :     exist, an exception is thrown.
444 :    
445 :     =cut
446 :    
447 : sh002i 775 sub putPermissionLevel($$) {
448 :     my ($self, $PermissionLevel) = @_;
449 : sh002i 1096
450 :     croak "putPermissionLevel: requires 1 argument"
451 :     unless @_ == 2;
452 :     croak "putPermissionLevel: argument 1 must be of type ", $self->{permission}->{record}
453 :     unless ref $PermissionLevel eq $self->{permission}->{record};
454 :     croak "putPermissionLevel: permission level not found (perhaps you meant to use addPermissionLevel?)"
455 :     unless $self->{permission}->exists($PermissionLevel->user_id);
456 :    
457 : sh002i 1199 checkKeyfields($PermissionLevel);
458 :    
459 : sh002i 775 return $self->{permission}->put($PermissionLevel);
460 :     }
461 :    
462 : sh002i 1108 =item deletePermissionLevel($userID)
463 :    
464 :     If a permission level record with a user ID matching $userID exists in the
465 :     permission table, it is removed and the method returns a true value. If one
466 :     does exist, a false value is returned.
467 :    
468 :     =cut
469 :    
470 : sh002i 775 sub deletePermissionLevel($$) {
471 :     my ($self, $userID) = @_;
472 : sh002i 1096
473 :     croak "deletePermissionLevel: requires 1 argument"
474 :     unless @_ == 2;
475 :     croak "deletePermissionLevel: argument 1 must contain a user_id"
476 :     unless defined $userID;
477 :    
478 : sh002i 775 return $self->{permission}->delete($userID);
479 :     }
480 :    
481 :     ################################################################################
482 :     # key functions
483 :     ################################################################################
484 :    
485 : sh002i 1108 =head2 Key Methods
486 :    
487 :     =over
488 :    
489 : sh002i 1201 =item newKey()
490 :    
491 :     Returns a new, empty key object.
492 :    
493 :     =cut
494 :    
495 :     sub newKey {
496 : sh002i 1236 my ($self, $prototype) = @_;
497 :     return $self->{key}->{record}->new($prototype);
498 : sh002i 1201 }
499 :    
500 : sh002i 1108 =item listKeys()
501 :    
502 :     Returns a list of user IDs representing the records in the key table.
503 :    
504 :     =cut
505 :    
506 : sh002i 775 sub listKeys($) {
507 :     my ($self) = @_;
508 : sh002i 1096
509 :     croak "listKeys: requires 0 arguments"
510 :     unless @_ == 1;
511 :    
512 : sh002i 808 return map { $_->[0] }
513 :     $self->{key}->list(undef);
514 : sh002i 775 }
515 :    
516 : sh002i 1108 =item addKey($Key)
517 :    
518 :     $Key is a record object. The key will be added to the key table if a key with
519 :     the same user ID does not already exist. If one does exist, an exception is
520 :     thrown. To add a key, a user with a matching user ID must exist in the user
521 :     table.
522 :    
523 :     =cut
524 :    
525 : sh002i 808 sub addKey($$) {
526 : sh002i 775 my ($self, $Key) = @_;
527 : sh002i 1096
528 :     croak "addKey: requires 1 argument"
529 :     unless @_ == 2;
530 :     croak "addKey: argument 1 must be of type ", $self->{key}->{record}
531 :     unless ref $Key eq $self->{key}->{record};
532 :     croak "addKey: key exists (perhaps you meant to use putKey?)"
533 :     if $self->{key}->exists($Key->user_id);
534 :     croak "addKey: user ", $Key->user_id, " not found"
535 : sh002i 775 unless $self->{user}->exists($Key->user_id);
536 : sh002i 1096
537 : sh002i 1199 checkKeyfields($Key);
538 :    
539 : sh002i 775 return $self->{key}->add($Key);
540 :     }
541 :    
542 : sh002i 1108 =item getKey($userID)
543 :    
544 :     If a record with a matching user ID exists, a record object containting that
545 :     record's data will be returned. If no such record exists, an undefined value
546 :     will be returned.
547 :    
548 :     =cut
549 :    
550 : sh002i 775 sub getKey($$) {
551 :     my ($self, $userID) = @_;
552 : sh002i 1096
553 :     croak "getKey: requires 1 argument"
554 :     unless @_ == 2;
555 :     croak "getKey: argument 1 must contain a user_id"
556 :     unless defined $userID;
557 :    
558 : sh002i 775 return $self->{key}->get($userID);
559 :     }
560 :    
561 : sh002i 1108 =item putKey($Key)
562 :    
563 :     $Key is a record object. If a key record with the same user ID exists in the
564 :     key table, the data in the record is replaced with the data in $Key. If a
565 :     matching key record does not exist, an exception is thrown.
566 :    
567 :     =cut
568 :    
569 : sh002i 775 sub putKey($$) {
570 :     my ($self, $Key) = @_;
571 : sh002i 1096
572 :     croak "putKey: requires 1 argument"
573 :     unless @_ == 2;
574 :     croak "putKey: argument 1 must be of type ", $self->{key}->{record}
575 :     unless ref $Key eq $self->{key}->{record};
576 :     croak "putKey: key not found (perhaps you meant to use addKey?)"
577 :     unless $self->{key}->exists($Key->user_id);
578 :    
579 : sh002i 1199 checkKeyfields($Key);
580 :    
581 : sh002i 775 return $self->{key}->put($Key);
582 :     }
583 :    
584 : sh002i 1108 =item deleteKey($userID)
585 :    
586 :     If a key record with a user ID matching $userID exists in the key table, it is
587 :     removed and the method returns a true value. If one does exist, a false value
588 :     is returned.
589 :    
590 :     =cut
591 :    
592 : sh002i 775 sub deleteKey($$) {
593 :     my ($self, $userID) = @_;
594 : sh002i 1096
595 :     croak "deleteKey: requires 1 argument"
596 :     unless @_ == 2;
597 :     croak "deleteKey: argument 1 must contain a user_id"
598 :     unless defined $userID;
599 :    
600 : sh002i 775 return $self->{key}->delete($userID);
601 :     }
602 :    
603 :     ################################################################################
604 :     # user functions
605 :     ################################################################################
606 :    
607 : sh002i 1108 =head2 User Methods
608 :    
609 :     =over
610 :    
611 : sh002i 1201 =item newUser()
612 :    
613 :     Returns a new, empty user object.
614 :    
615 :     =cut
616 :    
617 :     sub newUser {
618 : sh002i 1236 my ($self, $prototype) = @_;
619 :     return $self->{user}->{record}->new($prototype);
620 : sh002i 1201 }
621 :    
622 : sh002i 1108 =item listUsers()
623 :    
624 :     Returns a list of user IDs representing the records in the user table.
625 :    
626 :     =cut
627 :    
628 : sh002i 775 sub listUsers($) {
629 :     my ($self) = @_;
630 : sh002i 1096
631 :     croak "listUsers: requires 0 arguments"
632 :     unless @_ == 1;
633 :    
634 : sh002i 808 return map { $_->[0] }
635 :     $self->{user}->list(undef);
636 : sh002i 775 }
637 :    
638 : sh002i 1108 =item addUser($User)
639 :    
640 :     $User is a record object. The user will be added to the user table if a user
641 :     with the same user ID does not already exist. If one does exist, an exception
642 :     is thrown.
643 :    
644 :     =cut
645 :    
646 : sh002i 808 sub addUser($$) {
647 : sh002i 775 my ($self, $User) = @_;
648 : sh002i 1096
649 :     croak "addUser: requires 1 argument"
650 :     unless @_ == 2;
651 :     croak "addUser: argument 1 must be of type ", $self->{user}->{record}
652 :     unless ref $User eq $self->{user}->{record};
653 :     croak "addUser: user exists (perhaps you meant to use putUser?)"
654 :     if $self->{user}->exists($User->user_id);
655 :    
656 : sh002i 1199 checkKeyfields($User);
657 :    
658 : sh002i 775 return $self->{user}->add($User);
659 :     }
660 :    
661 : sh002i 1108 =item getUser($userID)
662 :    
663 :     If a record with a matching user ID exists, a record object containting that
664 :     record's data will be returned. If no such record exists, an undefined value
665 :     will be returned.
666 :    
667 :     =cut
668 :    
669 : sh002i 775 sub getUser($$) {
670 :     my ($self, $userID) = @_;
671 : sh002i 1096
672 :     croak "getUser: requires 1 argument"
673 :     unless @_ == 2;
674 :     croak "getUser: argument 1 must contain a user_id"
675 :     unless defined $userID;
676 :    
677 : sh002i 775 return $self->{user}->get($userID);
678 :     }
679 :    
680 : sh002i 1108 =item putUser($User)
681 :    
682 :     $User is a record object. If a user record with the same user ID exists in the
683 :     user table, the data in the record is replaced with the data in $User. If a
684 :     matching user record does not exist, an exception is thrown.
685 :    
686 :     =cut
687 :    
688 : sh002i 775 sub putUser($$) {
689 :     my ($self, $User) = @_;
690 : sh002i 1096
691 :     croak "putUser: requires 1 argument"
692 :     unless @_ == 2;
693 :     croak "putUser: argument 1 must be of type ", $self->{user}->{record}
694 :     unless ref $User eq $self->{user}->{record};
695 :     croak "putUser: user not found (perhaps you meant to use addUser?)"
696 :     unless $self->{user}->exists($User->user_id);
697 :    
698 : sh002i 1199 checkKeyfields($User);
699 :    
700 : sh002i 775 return $self->{user}->put($User);
701 :     }
702 :    
703 : sh002i 1108 =item deleteUser($userID)
704 :    
705 :     If a user record with a user ID matching $userID exists in the user table, it
706 :     is removed and the method returns a true value. If one does exist, a false
707 :     value is returned. When a user record is deleted, all records associated with
708 :     that user are also deleted. This includes the password, permission, and key
709 :     records, and all user set records for that user.
710 :    
711 :     =cut
712 :    
713 : sh002i 775 sub deleteUser($$) {
714 :     my ($self, $userID) = @_;
715 : sh002i 1096
716 :     croak "deleteUser: requires 1 argument"
717 :     unless @_ == 2;
718 :     croak "deleteUser: argument 1 must contain a user_id"
719 :     unless defined $userID;
720 :    
721 : sh002i 1167 #$self->deleteUserSet($userID, $_)
722 :     # foreach $self->listUserSets($userID);
723 :     $self->deleteUserSet($userID, undef);
724 : sh002i 775 $self->deletePassword($userID);
725 :     $self->deletePermissionLevel($userID);
726 :     $self->deleteKey($userID);
727 :     return $self->{user}->delete($userID);
728 :     }
729 :    
730 :     ################################################################################
731 :     # set functions
732 :     ################################################################################
733 :    
734 : sh002i 1201 sub newGlobalSet {
735 : sh002i 1236 my ($self, $prototype) = @_;
736 :     return $self->{set}->{record}->new($prototype);
737 : sh002i 1201 }
738 :    
739 : sh002i 775 sub listGlobalSets($) {
740 :     my ($self) = @_;
741 : sh002i 1096
742 :     croak "listGlobalSets: requires 0 arguments"
743 :     unless @_ == 1;
744 :    
745 : sh002i 808 return map { $_->[0] }
746 :     $self->{set}->list(undef);
747 : sh002i 775 }
748 :    
749 : sh002i 808 sub addGlobalSet($$) {
750 : sh002i 775 my ($self, $GlobalSet) = @_;
751 : sh002i 1096
752 :     croak "addGlobalSet: requires 1 argument"
753 :     unless @_ == 2;
754 :     croak "addGlobalSet: argument 1 must be of type ", $self->{set}->{record}
755 :     unless ref $GlobalSet eq $self->{set}->{record};
756 :     croak "addGlobalSet: global set exists (perhaps you meant to use putGlobalSet?)"
757 :     if $self->{set}->exists($GlobalSet->set_id);
758 :    
759 : sh002i 1199 checkKeyfields($GlobalSet);
760 :    
761 : sh002i 775 return $self->{set}->add($GlobalSet);
762 :     }
763 :    
764 :     sub getGlobalSet($$) {
765 :     my ($self, $setID) = @_;
766 : sh002i 1096
767 :     croak "getGlobalSet: requires 1 argument"
768 :     unless @_ == 2;
769 :     croak "getGlobalSet: argument 1 must contain a set_id"
770 :     unless defined $setID;
771 :    
772 : sh002i 775 return $self->{set}->get($setID);
773 :     }
774 :    
775 :     sub putGlobalSet($$) {
776 :     my ($self, $GlobalSet) = @_;
777 : sh002i 1096
778 :     croak "putGlobalSet: requires 1 argument"
779 :     unless @_ == 2;
780 :     croak "putGlobalSet: argument 1 must be of type ", $self->{set}->{record}
781 :     unless ref $GlobalSet eq $self->{set}->{record};
782 :     croak "putGlobalSet: global set not found (perhaps you meant to use addGlobalSet?)"
783 :     unless $self->{set}->exists($GlobalSet->set_id);
784 :    
785 : sh002i 1199 checkKeyfields($GlobalSet);
786 :    
787 : sh002i 775 return $self->{set}->put($GlobalSet);
788 :     }
789 :    
790 :     sub deleteGlobalSet($$) {
791 :     my ($self, $setID) = @_;
792 : sh002i 1096
793 :     croak "deleteGlobalSet: requires 1 argument"
794 :     unless @_ == 2;
795 :     croak "deleteGlobalSet: argument 1 must contain a set_id"
796 : sh002i 1167 unless defined $setID or caller eq __PACKAGE__;
797 : sh002i 1096
798 : sh002i 1167 #$self->deleteUserSet($_, $setID)
799 :     # foreach $self->listSetUsers($setID);
800 :     #$self->deleteGlobalProblem($setID, $_)
801 :     # foreach $self->listGlobalProblems($setID);
802 :     $self->deleteUserSet(undef, $setID);
803 :     $self->deleteGlobalProblem($setID, undef);
804 : sh002i 775 return $self->{set}->delete($setID);
805 :     }
806 :    
807 :     ################################################################################
808 :     # set_user functions
809 :     ################################################################################
810 :    
811 : sh002i 1201 sub newUserSet {
812 : sh002i 1236 my ($self, $prototype) = @_;
813 :     return $self->{set_user}->{record}->new($prototype);
814 : sh002i 1201 }
815 :    
816 : sh002i 909 sub listSetUsers($$) {
817 :     my ($self, $setID) = @_;
818 : sh002i 1096
819 :     croak "listSetUsers: requires 1 argument"
820 :     unless @_ == 2;
821 :     croak "listSetUsers: argument 1 must contain a set_id"
822 :     unless defined $setID;
823 :    
824 : sh002i 909 return map { $_->[0] } # extract user_id
825 :     $self->{set_user}->list(undef, $setID);
826 :     }
827 :    
828 :     sub listUserSets($$) {
829 : sh002i 775 my ($self, $userID) = @_;
830 : sh002i 1096
831 :     croak "listUserSets: requires 1 argument"
832 :     unless @_ == 2;
833 :     croak "listUserSets: argument 1 must contain a user_id"
834 :     unless defined $userID;
835 :    
836 : sh002i 808 return map { $_->[1] } # extract set_id
837 :     $self->{set_user}->list($userID, undef);
838 : sh002i 775 }
839 :    
840 : sh002i 808 sub addUserSet($$) {
841 : sh002i 775 my ($self, $UserSet) = @_;
842 : sh002i 1096
843 :     croak "addUserSet: requires 1 argument"
844 :     unless @_ == 2;
845 :     croak "addUserSet: argument 1 must be of type ", $self->{set_user}->{record}
846 :     unless ref $UserSet eq $self->{set_user}->{record};
847 :     croak "addUserSet: user set exists (perhaps you meant to use putUserSet?)"
848 :     if $self->{set_user}->exists($UserSet->user_id, $UserSet->set_id);
849 :     croak "addUserSet: user ", $UserSet->user_id, " not found"
850 : sh002i 775 unless $self->{user}->exists($UserSet->user_id);
851 : sh002i 1096 croak "addUserSet: set ", $UserSet->set_id, " not found"
852 : sh002i 775 unless $self->{set}->exists($UserSet->set_id);
853 : sh002i 1096
854 : sh002i 1199 checkKeyfields($UserSet);
855 :    
856 : sh002i 775 return $self->{set_user}->add($UserSet);
857 :     }
858 :    
859 : sh002i 909 sub getUserSet($$$) {
860 : sh002i 775 my ($self, $userID, $setID) = @_;
861 : sh002i 1096
862 :     croak "getUserSet: requires 2 arguments"
863 :     unless @_ == 3;
864 :     croak "getUserSet: argument 1 must contain a user_id"
865 :     unless defined $userID;
866 :     croak "getUserSet: argument 2 must contain a set_id"
867 :     unless defined $setID;
868 :    
869 : sh002i 775 return $self->{set_user}->get($userID, $setID);
870 :     }
871 :    
872 :     sub putUserSet($$) {
873 :     my ($self, $UserSet) = @_;
874 : sh002i 1096
875 :     croak "putUserSet: requires 1 argument"
876 :     unless @_ == 2;
877 :     croak "putUserSet: argument 1 must be of type ", $self->{set_user}->{record}
878 :     unless ref $UserSet eq $self->{set_user}->{record};
879 :     croak "putUserSet: user set not found (perhaps you meant to use addUserSet?)"
880 :     unless $self->{set_user}->exists($UserSet->user_id, $UserSet->set_id);
881 :     croak "putUserSet: user ", $UserSet->user_id, " not found"
882 :     unless $self->{user}->exists($UserSet->user_id);
883 :     croak "putUserSet: set ", $UserSet->set_id, " not found"
884 :     unless $self->{set}->exists($UserSet->set_id);
885 :    
886 : sh002i 1199 checkKeyfields($UserSet);
887 :    
888 : sh002i 775 return $self->{set_user}->put($UserSet);
889 :     }
890 :    
891 : sh002i 909 sub deleteUserSet($$$) {
892 : sh002i 775 my ($self, $userID, $setID) = @_;
893 : sh002i 1096
894 :     croak "getUserSet: requires 2 arguments"
895 :     unless @_ == 3;
896 :     croak "getUserSet: argument 1 must contain a user_id"
897 : sh002i 1167 unless defined $userID or caller eq __PACKAGE__;
898 : sh002i 1096 croak "getUserSet: argument 2 must contain a set_id"
899 : sh002i 1167 unless defined $userID or caller eq __PACKAGE__;
900 : sh002i 1096
901 : sh002i 1167 #$self->deleteUserProblem($userID, $setID, $_)
902 :     # foreach $self->listUserProblems($userID, $setID);
903 :     $self->deleteUserProblem($userID, $setID, undef);
904 : sh002i 775 return $self->{set_user}->delete($userID, $setID);
905 :     }
906 :    
907 :     ################################################################################
908 :     # problem functions
909 :     ################################################################################
910 :    
911 : sh002i 1201 sub newGlobalProblem {
912 : sh002i 1236 my ($self, $prototype) = @_;
913 :     return $self->{problem}->{record}->new($prototype);
914 : sh002i 1201 }
915 :    
916 : sh002i 775 sub listGlobalProblems($$) {
917 :     my ($self, $setID) = @_;
918 : sh002i 1096
919 :     croak "listGlobalProblems: requires 1 arguments"
920 :     unless @_ == 2;
921 :     croak "listGlobalProblems: argument 1 must contain a set_id"
922 :     unless defined $setID;
923 :    
924 : sh002i 775 return map { $_->[1] }
925 : sh002i 1096 $self->{problem}->list($setID, undef);
926 : sh002i 775 }
927 :    
928 : sh002i 808 sub addGlobalProblem($$) {
929 : sh002i 775 my ($self, $GlobalProblem) = @_;
930 : sh002i 1096
931 :     croak "addGlobalProblem: requires 1 argument"
932 :     unless @_ == 2;
933 :     croak "addGlobalProblem: argument 1 must be of type ", $self->{problem}->{record}
934 :     unless ref $GlobalProblem eq $self->{problem}->{record};
935 :     croak "addGlobalProblem: global problem exists (perhaps you meant to use putGlobalProblem?)"
936 :     if $self->{problem}->exists($GlobalProblem->set_id, $GlobalProblem->problem_id);
937 :     croak "addGlobalProblem: set ", $GlobalProblem->set_id, " not found"
938 : sh002i 775 unless $self->{set}->exists($GlobalProblem->set_id);
939 : sh002i 1096
940 : sh002i 1199 checkKeyfields($GlobalProblem);
941 :    
942 : sh002i 775 return $self->{problem}->add($GlobalProblem);
943 :     }
944 :    
945 :     sub getGlobalProblem($$$) {
946 :     my ($self, $setID, $problemID) = @_;
947 : sh002i 1096
948 :     croak "getGlobalProblem: requires 2 arguments"
949 :     unless @_ == 3;
950 :     croak "getGlobalProblem: argument 1 must contain a set_id"
951 :     unless defined $setID;
952 :     croak "getGlobalProblem: argument 2 must contain a problem_id"
953 :     unless defined $problemID;
954 :    
955 : sh002i 916 return $self->{problem}->get($setID, $problemID);
956 : sh002i 775 }
957 :    
958 :     sub putGlobalProblem($$) {
959 :     my ($self, $GlobalProblem) = @_;
960 : sh002i 1096
961 :     croak "putGlobalProblem: requires 1 argument"
962 :     unless @_ == 2;
963 :     croak "putGlobalProblem: argument 1 must be of type ", $self->{problem}->{record}
964 :     unless ref $GlobalProblem eq $self->{problem}->{record};
965 :     croak "putGlobalProblem: global problem not found (perhaps you meant to use addGlobalProblem?)"
966 :     unless $self->{problem}->exists($GlobalProblem->set_id, $GlobalProblem->problem_id);
967 :     croak "putGlobalProblem: set ", $GlobalProblem->set_id, " not found"
968 :     unless $self->{set}->exists($GlobalProblem->set_id);
969 :    
970 : sh002i 1199 checkKeyfields($GlobalProblem);
971 :    
972 : sh002i 775 return $self->{problem}->put($GlobalProblem);
973 :     }
974 :    
975 :     sub deleteGlobalProblem($$$) {
976 :     my ($self, $setID, $problemID) = @_;
977 : sh002i 1096
978 : sh002i 1167 croak "deleteGlobalProblem: requires 2 arguments"
979 : sh002i 1096 unless @_ == 3;
980 : sh002i 1167 croak "deleteGlobalProblem: argument 1 must contain a set_id"
981 :     unless defined $setID or caller eq __PACKAGE__;
982 :     croak "deleteGlobalProblem: argument 2 must contain a problem_id"
983 :     unless defined $problemID or caller eq __PACKAGE__;
984 : sh002i 1096
985 : sh002i 1167 #$self->deleteUserProblem($_, $setID, $problemID)
986 :     # foreach $self->listProblemUsers($setID, $problemID);
987 :     $self->deleteUserProblem(undef, $setID, $problemID);
988 : sh002i 775 return $self->{problem}->delete($setID, $problemID);
989 :     }
990 :    
991 :     ################################################################################
992 :     # problem_user functions
993 :     ################################################################################
994 :    
995 : sh002i 1201 sub newUserProblem {
996 : sh002i 1236 my ($self, $prototype) = @_;
997 :     return $self->{problem_user}->{record}->new($prototype);
998 : sh002i 1201 }
999 :    
1000 : sh002i 923 sub listProblemUsers($$$) {
1001 :     my ($self, $setID, $problemID) = @_;
1002 : sh002i 1096
1003 :     croak "listProblemUsers: requires 2 arguments"
1004 :     unless @_ == 3;
1005 :     croak "listProblemUsers: argument 1 must contain a set_id"
1006 :     unless defined $setID;
1007 :     croak "listProblemUsers: argument 2 must contain a problem_id"
1008 :     unless defined $problemID;
1009 :    
1010 : sh002i 923 return map { $_->[0] } # extract user_id
1011 :     $self->{problem_user}->list(undef, $setID, $problemID);
1012 :     }
1013 :    
1014 : sh002i 775 sub listUserProblems($$$) {
1015 :     my ($self, $userID, $setID) = @_;
1016 : sh002i 1096
1017 :     croak "listUserProblems: requires 2 arguments"
1018 :     unless @_ == 3;
1019 :     croak "listUserProblems: argument 1 must contain a user_id"
1020 :     unless defined $userID;
1021 :     croak "listUserProblems: argument 2 must contain a set_id"
1022 :     unless defined $setID;
1023 :    
1024 : sh002i 923 return map { $_->[2] } # extract problem_id
1025 : sh002i 808 $self->{problem_user}->list($userID, $setID, undef);
1026 : sh002i 775 }
1027 :    
1028 : sh002i 808 sub addUserProblem($$) {
1029 : sh002i 775 my ($self, $UserProblem) = @_;
1030 : sh002i 1096
1031 :     croak "addUserProblem: requires 1 argument"
1032 :     unless @_ == 2;
1033 :     croak "addUserProblem: argument 1 must be of type ", $self->{problem_user}->{record}
1034 :     unless ref $UserProblem eq $self->{problem_user}->{record};
1035 :     croak "addUserProblem: user problem exists (perhaps you meant to use putUserProblem?)"
1036 : malsyned 1185 if $self->{problem_user}->exists($UserProblem->user_id, $UserProblem->set_id, $UserProblem->problem_id);
1037 : sh002i 1096 croak "addUserProblem: user set ", $UserProblem->set_id, " for user ", $UserProblem->user_id, " not found"
1038 : sh002i 808 unless $self->{set_user}->exists($UserProblem->user_id, $UserProblem->set_id);
1039 : sh002i 1096 croak "addUserProblem: problem ", $UserProblem->problem_id, " in set ", $UserProblem->set_id, " not found"
1040 : sh002i 914 unless $self->{problem}->exists($UserProblem->set_id, $UserProblem->problem_id);
1041 : sh002i 1096
1042 : sh002i 1199 checkKeyfields($UserProblem);
1043 :    
1044 : sh002i 775 return $self->{problem_user}->add($UserProblem);
1045 :     }
1046 :    
1047 : sh002i 798 sub getUserProblem($$$$) {
1048 : sh002i 775 my ($self, $userID, $setID, $problemID) = @_;
1049 : sh002i 1096
1050 :     croak "getUserProblem: requires 3 arguments"
1051 :     unless @_ == 4;
1052 :     croak "getUserProblem: argument 1 must contain a user_id"
1053 :     unless defined $userID;
1054 :     croak "getUserProblem: argument 2 must contain a set_id"
1055 :     unless defined $setID;
1056 :     croak "getUserProblem: argument 3 must contain a problem_id"
1057 :     unless defined $problemID;
1058 :    
1059 : sh002i 775 return $self->{problem_user}->get($userID, $setID, $problemID);
1060 :     }
1061 :    
1062 :     sub putUserProblem($$) {
1063 :     my ($self, $UserProblem) = @_;
1064 : sh002i 1096
1065 :     croak "putUserProblem: requires 1 argument"
1066 :     unless @_ == 2;
1067 :     croak "putUserProblem: argument 1 must be of type ", $self->{problem_user}->{record}
1068 :     unless ref $UserProblem eq $self->{problem_user}->{record};
1069 :     croak "putUserProblem: user set ", $UserProblem->set_id, " for user ", $UserProblem->user_id, " not found"
1070 :     unless $self->{set_user}->exists($UserProblem->user_id, $UserProblem->set_id);
1071 : malsyned 1104 croak "putUserProblem: user problem not found (perhaps you meant to use addUserProblem?)"
1072 :     unless $self->{problem_user}->exists($UserProblem->user_id, $UserProblem->set_id, $UserProblem->problem_id);
1073 : sh002i 1096 croak "putUserProblem: problem ", $UserProblem->problem_id, " in set ", $UserProblem->set_id, " not found"
1074 :     unless $self->{problem}->exists($UserProblem->set_id, $UserProblem->problem_id);
1075 :    
1076 : sh002i 1199 checkKeyfields($UserProblem);
1077 :    
1078 : sh002i 775 return $self->{problem_user}->put($UserProblem);
1079 :     }
1080 :    
1081 : sh002i 798 sub deleteUserProblem($$$$) {
1082 : sh002i 775 my ($self, $userID, $setID, $problemID) = @_;
1083 : sh002i 1096
1084 :     croak "getUserProblem: requires 3 arguments"
1085 :     unless @_ == 4;
1086 :     croak "getUserProblem: argument 1 must contain a user_id"
1087 : sh002i 1167 unless defined $userID or caller eq __PACKAGE__;
1088 : sh002i 1096 croak "getUserProblem: argument 2 must contain a set_id"
1089 : sh002i 1167 unless defined $setID or caller eq __PACKAGE__;
1090 : sh002i 1096 croak "getUserProblem: argument 3 must contain a problem_id"
1091 : sh002i 1167 unless defined $problemID or caller eq __PACKAGE__;
1092 : sh002i 1096
1093 : sh002i 775 return $self->{problem_user}->delete($userID, $setID, $problemID);
1094 :     }
1095 :    
1096 :     ################################################################################
1097 :     # set+set_user functions
1098 :     ################################################################################
1099 :    
1100 : sh002i 1096 sub getGlobalUserSet {
1101 :     carp "getGlobalUserSet: this method is deprecated -- use getMergedSet instead";
1102 :     return shift->getMergedSet(@_);
1103 :     }
1104 :    
1105 :     sub getMergedSet {
1106 : sh002i 798 my ($self, $userID, $setID) = @_;
1107 : sh002i 1096
1108 : sh002i 1226 #my $timer = WeBWorK::Timing->new("getMergedSet");
1109 :    
1110 : sh002i 1096 croak "getGlobalUserSet: requires 2 arguments"
1111 :     unless @_ == 3;
1112 :     croak "getGlobalUserSet: argument 1 must contain a user_id"
1113 :     unless defined $userID;
1114 :     croak "getGlobalUserSet: argument 2 must contain a set_id"
1115 :     unless defined $setID;
1116 :    
1117 : sh002i 1226 #$timer->start;
1118 : sh002i 814 my $UserSet = $self->getUserSet($userID, $setID);
1119 : sh002i 1226 #$timer->continue("got user set");
1120 : sh002i 814 return unless $UserSet;
1121 :     my $GlobalSet = $self->getGlobalSet($setID);
1122 : sh002i 1226 #$timer->continue("got global set");
1123 : sh002i 814 if ($GlobalSet) {
1124 :     foreach ($UserSet->FIELDS()) {
1125 :     next unless $GlobalSet->can($_);
1126 :     next if $UserSet->$_();
1127 :     $UserSet->$_($GlobalSet->$_());
1128 :     }
1129 :     }
1130 : sh002i 1226 #$timer->continue("merged records");
1131 :     #$timer->stop;
1132 : sh002i 814 return $UserSet;
1133 : sh002i 798 }
1134 : sh002i 775
1135 :     ################################################################################
1136 :     # problem+problem_user functions
1137 :     ################################################################################
1138 :    
1139 : sh002i 1096 sub getGlobalUserProblem {
1140 :     carp "getGlobalUserProblem: this method is deprecated -- use getMergedProblem instead";
1141 :     return shift->getMergedProblem(@_);
1142 :     }
1143 :    
1144 :     sub getMergedProblem {
1145 : sh002i 798 my ($self, $userID, $setID, $problemID) = @_;
1146 : sh002i 1096
1147 : sh002i 1226 #my $timer = WeBWorK::Timing->new("getMergedSet");
1148 :    
1149 : sh002i 1096 croak "getGlobalUserSet: requires 3 arguments"
1150 :     unless @_ == 4;
1151 :     croak "getGlobalUserSet: argument 1 must contain a user_id"
1152 :     unless defined $userID;
1153 :     croak "getGlobalUserSet: argument 2 must contain a set_id"
1154 :     unless defined $setID;
1155 :     croak "getGlobalUserSet: argument 3 must contain a problem_id"
1156 :     unless defined $problemID;
1157 :    
1158 : sh002i 1226 #$timer->start;
1159 : sh002i 814 my $UserProblem = $self->getUserProblem($userID, $setID, $problemID);
1160 : sh002i 1226 #$timer->continue("got user problem");
1161 : sh002i 814 return unless $UserProblem;
1162 :     my $GlobalProblem = $self->getGlobalProblem($setID, $problemID);
1163 : sh002i 1226 #$timer->continue("got global problem");
1164 : sh002i 814 if ($GlobalProblem) {
1165 :     foreach ($UserProblem->FIELDS()) {
1166 :     next unless $GlobalProblem->can($_);
1167 :     next if $UserProblem->$_();
1168 :     $UserProblem->$_($GlobalProblem->$_());
1169 :     }
1170 :     }
1171 : sh002i 1226 #$timer->continue("merged records");
1172 :     #$timer->stop;
1173 : sh002i 814 return $UserProblem;
1174 : sh002i 798 }
1175 : sh002i 775
1176 : sh002i 808 ################################################################################
1177 :     # debugging
1178 :     ################################################################################
1179 :    
1180 :     sub dumpDB($$) {
1181 :     my ($self, $table) = @_;
1182 :     return $self->{$table}->dumpDB();
1183 :     }
1184 :    
1185 : sh002i 1199 ################################################################################
1186 :     # sanity checking
1187 :     ################################################################################
1188 :    
1189 :     sub checkKeyfields($) {
1190 :     my ($Record) = @_;
1191 :     foreach my $keyfield ($Record->KEYFIELDS) {
1192 : sh002i 1226 my $value = $Record->$keyfield;
1193 :     croak "checkKeyfields: $keyfield is empty"
1194 :     unless defined $value and $value ne "";
1195 :    
1196 :     if ($keyfield eq "problem_id") {
1197 :     croak "checkKeyfields: invalid characters in $keyfield field: $value (valid characters are [0-9])"
1198 :     unless $value =~ m/^\d*$/;
1199 :     } else {
1200 :     croak "checkKeyfields: invalid characters in $keyfield field: $value (valid characters are [A-Za-z0-9_])"
1201 :     unless $value =~ m/^\w*$/;
1202 :     }
1203 : sh002i 1199 }
1204 :     }
1205 :    
1206 : sh002i 1012 =head1 AUTHOR
1207 :    
1208 :     Written by Sam Hathaway, sh002i (at) math.rochester.edu.
1209 :    
1210 : sh002i 1035 =cut
1211 : gage 1023
1212 : sh002i 775 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9