[system] / trunk / webwork-modperl / lib / WeBWorK / ContentGenerator / Instructor / UserList.pm Repository:
ViewVC logotype

Annotation of /trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1928 - (view) (download) (as text)

1 : sh002i 1567 ################################################################################
2 : sh002i 1663 # WeBWorK Online Homework Delivery System
3 :     # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4 : gage 1928 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm,v 1.43 2004/02/12 21:38:24 toenail Exp $
5 : sh002i 1663 #
6 :     # This program is free software; you can redistribute it and/or modify it under
7 :     # the terms of either: (a) the GNU General Public License as published by the
8 :     # Free Software Foundation; either version 2, or (at your option) any later
9 :     # version, or (b) the "Artistic License" which comes with this package.
10 :     #
11 :     # This program is distributed in the hope that it will be useful, but WITHOUT
12 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14 :     # Artistic License for more details.
15 : sh002i 1567 ################################################################################
16 :    
17 : malsyned 832 package WeBWorK::ContentGenerator::Instructor::UserList;
18 :     use base qw(WeBWorK::ContentGenerator::Instructor);
19 :    
20 :     =head1 NAME
21 :    
22 : sh002i 1567 WeBWorK::ContentGenerator::Instructor::UserList - Entry point for User-specific
23 :     data editing
24 : malsyned 832
25 :     =cut
26 :    
27 : sh002i 1594 =for comment
28 :    
29 :     What do we want to be able to do here?
30 :    
31 :     Filter what users are shown:
32 :     - none, all, selected
33 :     - matching user_id, matching section, matching recitation
34 :     Switch from view mode to edit mode:
35 :     - showing visible users
36 :     - showing selected users
37 :     Switch from edit mode to view and save changes
38 :     Switch from edit mode to view and abandon changes
39 :     Delete users:
40 :     - visible
41 :     - selected
42 :     Import users:
43 :     - replace:
44 :     - any users
45 :     - visible users
46 :     - selected users
47 :     - no users
48 :     - add:
49 :     - any users
50 :     - no users
51 :     Export users:
52 :     - export:
53 :     - all
54 :     - visible
55 :     - selected
56 :     - to:
57 :     - existing file on server (overwrite): [ list of files ]
58 :     - new file on server (create): [ filename ]
59 :    
60 :     =cut
61 :    
62 : malsyned 832 use strict;
63 :     use warnings;
64 :     use CGI qw();
65 : sh002i 1594 use WeBWorK::Utils qw(readFile readDirectory);
66 : gage 1712 use Apache::Constants qw(:common REDIRECT DONE); #FIXME -- this should be called higher up in the object tree.
67 : sh002i 1567 use constant HIDE_USERS_THRESHHOLD => 20;
68 : sh002i 1594 use constant EDIT_FORMS => [qw(cancelEdit saveEdit)];
69 : gage 1712 use constant VIEW_FORMS => [qw(filter edit import export add delete)];
70 : sh002i 1594 use constant STATE_PARAMS => [qw(user effectiveUser key visible_users no_visible_users prev_visible_users no_prev_visible_users editMode sortField)];
71 : sh002i 1567
72 : sh002i 1594 use constant SORT_SUBS => {
73 :     user_id => \&byUserID,
74 :     first_name => \&byFirstName,
75 :     last_name => \&byLastName,
76 :     email_address => \&byEmailAddress,
77 :     student_id => \&byStudentID,
78 :     status => \&byStatus,
79 :     section => \&bySection,
80 :     recitation => \&byRecitation,
81 :     comment => \&byComment,
82 :     };
83 :    
84 :     use constant FIELD_PROPERTIES => {
85 :     user_id => {
86 :     type => "text",
87 :     size => 8,
88 :     access => "readonly",
89 :     },
90 :     first_name => {
91 :     type => "text",
92 :     size => 10,
93 :     access => "readwrite",
94 :     },
95 :     last_name => {
96 :     type => "text",
97 :     size => 10,
98 :     access => "readwrite",
99 :     },
100 :     email_address => {
101 :     type => "text",
102 :     size => 20,
103 :     access => "readwrite",
104 :     },
105 :     student_id => {
106 :     type => "text",
107 :     size => 11,
108 :     access => "readwrite",
109 :     },
110 :     status => {
111 :     type => "enumerable",
112 :     size => 4,
113 :     access => "readwrite",
114 :     items => {
115 :     "C" => "Enrolled",
116 :     "D" => "Drop",
117 :     "A" => "Audit",
118 :     },
119 :     synonyms => {
120 :     qr/^[ce]/i => "C",
121 :     qr/^[dw]/i => "D",
122 :     qr/^a/i => "A",
123 :     "*" => "C",
124 :     }
125 :     },
126 :     section => {
127 :     type => "text",
128 :     size => 4,
129 :     access => "readwrite",
130 :     },
131 :     recitation => {
132 :     type => "text",
133 :     size => 4,
134 :     access => "readwrite",
135 :     },
136 :     comment => {
137 :     type => "text",
138 :     size => 20,
139 :     access => "readwrite",
140 :     },
141 :     permission => {
142 :     type => "number",
143 :     size => 2,
144 :     access => "readwrite",
145 :     }
146 :     };
147 : gage 1712 sub pre_header_initialize {
148 : gage 1928 my $self = shift;
149 :     my $r = $self->r;
150 :     my $urlpath = $r->urlpath;
151 :     my $ce = $r->ce;
152 :     my $courseName = $urlpath->arg("courseID");
153 : gage 1712 # Handle redirects, if any.
154 :     ##############################
155 :     # Redirect to the addUser page
156 :     ##################################
157 :    
158 :     defined($r->param('action')) && $r->param('action') eq 'add' && do {
159 :     # fix url and redirect
160 :     my $root = $ce->{webworkURLs}->{root};
161 : gage 1928
162 : gage 1712 my $numberOfStudents = $r->param('number_of_students');
163 :     warn "number of students not defined " unless defined $numberOfStudents;
164 : sh002i 1594
165 : gage 1712 my $uri="$root/$courseName/instructor/add_users?number_of_students=$numberOfStudents&".$self->url_authen_args;
166 :     #FIXME does the display mode need to be defined?
167 :     #FIXME url_authen_args also includes an effective user, so the new one must come first.
168 :     # even that might not work with every browser since there are two effective User assignments.
169 :     $r->header_out(Location => $uri);
170 :     $self->{noContent} = 1; # forces redirect
171 :     return;
172 :     };
173 :     }
174 :     # FIXME -- this should be moved up to instructor or contentgenerator
175 :     sub header {
176 :     my $self = shift;
177 :     return REDIRECT if $self->{noContent};
178 : gage 1928 my $r = $self->r;
179 : gage 1712 $r->content_type('text/html');
180 :     $r->send_http_header();
181 :     return OK;
182 :     }
183 : toenail 1799
184 :     #FIXME -- this should probably be moved up to instructor or contentgenerator as well
185 :     sub nbsp {
186 :     my $str = shift;
187 :     ($str =~/\S/) ? $str : ' ' ; # returns non-breaking space for empty strings
188 :     # tricky cases: $str =0;
189 :     # $str is a complex number
190 :     }
191 :    
192 : malsyned 1015 sub initialize {
193 : malsyned 1211 my ($self) = @_;
194 : gage 1928 my $r = $self->r;
195 :     my $db = $r->db;
196 :     my $ce = $r->ce;
197 :     my $authz = $r->authz;
198 : gage 1712 my $user = $r->param('user');
199 : malsyned 1211
200 :     unless ($authz->hasPermissions($user, "modify_student_data")) {
201 :     $self->{submitError} = "You are not authorized to modify student data";
202 :     return;
203 :     }
204 :    
205 : sh002i 1601 #if (defined($r->param('addStudent'))) {
206 :     # my $newUser = $db->newUser;
207 :     # my $newPermissionLevel = $db->newPermissionLevel;
208 :     # my $newPassword = $db->newPassword;
209 :     # $newUser->user_id($r->param('newUserID'));
210 :     # $newPermissionLevel->user_id($r->param('newUserID'));
211 :     # $newPassword->user_id($r->param('newUserID'));
212 :     # $newUser->status('C');
213 :     # $newPermissionLevel->permission(0);
214 :     # $db->addUser($newUser);
215 :     # $db->addPermissionLevel($newPermissionLevel);
216 :     # $db->addPassword($newPassword);
217 :     #}
218 : malsyned 1015 }
219 :    
220 : gage 1295
221 :    
222 : malsyned 1014 sub body {
223 : gage 1928 my ($self) = @_;
224 :     my $r = $self->r;
225 :     my $urlpath = $r->urlpath;
226 :     my $db = $r->db;
227 :     my $ce = $r->ce;
228 :     my $authz = $r->authz;
229 :     my $courseName = $urlpath->arg("courseID");
230 :     my $setID = $urlpath->arg("setID");
231 :     my $user = $r->param('user');
232 : sh002i 1584
233 : gage 1928 my $root = $ce->{webworkURLs}->{root};
234 :    
235 : sh002i 1594 # templates for getting field names
236 :     my $userTemplate = $self->{userTemplate} = $db->newUser;
237 :     my $permissionLevelTemplate = $self->{permissionLevelTemplate} = $db->newPermissionLevel;
238 :    
239 : sh002i 1567 return CGI::em("You are not authorized to access the Instructor tools.")
240 :     unless $authz->hasPermissions($user, "access_instructor_tools");
241 : sh002i 1584
242 : malsyned 1214 # This table can be consulted when display-ready forms of field names are needed.
243 : sh002i 1594 my %prettyFieldNames = map { $_ => $_ }
244 :     $userTemplate->FIELDS(),
245 :     $permissionLevelTemplate->FIELDS();
246 : sh002i 1567
247 : malsyned 1214 @prettyFieldNames{qw(
248 :     user_id
249 :     first_name
250 :     last_name
251 :     email_address
252 :     student_id
253 :     status
254 :     section
255 :     recitation
256 :     comment
257 :     permission
258 :     )} = (
259 : gage 1736 "Assigned sets",
260 : malsyned 1214 "First Name",
261 :     "Last Name",
262 :     "E-mail",
263 :     "Student ID",
264 :     "Status",
265 :     "Section",
266 :     "Recitation",
267 :     "Comment",
268 :     "Perm. Level"
269 :     );
270 : sh002i 1567
271 : sh002i 1594 ########## set initial values for state fields
272 :    
273 :     my @allUserIDs = $db->listUsers;
274 :     $self->{allUserIDs} = \@allUserIDs;
275 :    
276 :     if (defined $r->param("visible_users")) {
277 :     $self->{visibleUserIDs} = [ $r->param("visible_users") ];
278 :     } elsif (defined $r->param("no_visible_users")) {
279 :     $self->{visibleUserIDs} = [];
280 :     } else {
281 : sh002i 1597 if (@allUserIDs > HIDE_USERS_THRESHHOLD) {
282 :     $self->{visibleUserIDs} = [];
283 :     } else {
284 :     $self->{visibleUserIDs} = [ @allUserIDs ];
285 :     }
286 : sh002i 1594 }
287 :    
288 :     $self->{prevVisibleUserIDs} = $self->{visibleUserIDs};
289 :    
290 :     if (defined $r->param("selected_users")) {
291 :     $self->{selectedUserIDs} = [ $r->param("selected_users") ];
292 :     } else {
293 :     $self->{selectedUserIDs} = [];
294 :     }
295 :    
296 :     $self->{editMode} = $r->param("editMode") || 0;
297 :    
298 :     $self->{sortField} = $r->param("sortField") || "last_name";
299 :    
300 : sh002i 1601 my @allUsers = $db->getUsers(@allUserIDs);
301 :     my (%sections, %recitations);
302 :     foreach my $User (@allUsers) {
303 :     push @{$sections{$User->section}}, $User->user_id;
304 :     push @{$recitations{$User->recitation}}, $User->user_id;
305 :     }
306 :     $self->{sections} = \%sections;
307 :     $self->{recitations} = \%recitations;
308 :    
309 : sh002i 1594 ########## call action handler
310 :    
311 :     my $actionID = $r->param("action");
312 :     if ($actionID) {
313 :     unless (grep { $_ eq $actionID } @{ VIEW_FORMS() }, @{ EDIT_FORMS() }) {
314 :     die "Action $actionID not found";
315 :     }
316 :     my $actionHandler = "${actionID}_handler";
317 :     my %genericParams;
318 :     foreach my $param (qw(selected_users)) {
319 :     $genericParams{$param} = [ $r->param($param) ];
320 :     }
321 :     my %actionParams = $self->getActionParams($actionID);
322 :     my %tableParams = $self->getTableParams();
323 :     print CGI::p(
324 : gage 1713 '<div style="color:green">',
325 : sh002i 1597 "Result of last action performed: ",
326 : gage 1713 CGI::i($self->$actionHandler(\%genericParams, \%actionParams, \%tableParams)),
327 :     '</div>',
328 :     CGI::hr()
329 :    
330 : sh002i 1594 );
331 :     }
332 :    
333 :     ########## retrieve possibly changed values for member fields
334 :    
335 :     #@allUserIDs = @{ $self->{allUserIDs} }; # do we need this one?
336 :     my @visibleUserIDs = @{ $self->{visibleUserIDs} };
337 :     my @prevVisibleUserIDs = @{ $self->{prevVisibleUserIDs} };
338 :     my @selectedUserIDs = @{ $self->{selectedUserIDs} };
339 :     my $editMode = $self->{editMode};
340 :     my $sortField = $self->{sortField};
341 :    
342 :     #warn "visibleUserIDs=@visibleUserIDs\n";
343 :     #warn "prevVisibleUserIDs=@prevVisibleUserIDs\n";
344 :     #warn "selectedUserIDs=@selectedUserIDs\n";
345 :     #warn "editMode=$editMode\n";
346 :    
347 :     ########## get required users
348 : sh002i 1601
349 :     my @Users = grep { defined $_ } @visibleUserIDs ? $db->getUsers(@visibleUserIDs) : ();
350 : sh002i 1594
351 :     # presort users
352 :     my %sortSubs = %{ SORT_SUBS() };
353 :     my $sortSub = $sortSubs{$sortField};
354 :     #@Users = sort $sortSub @Users;
355 :     @Users = sort byLnFnUid @Users;
356 :    
357 :     my @PermissionLevels;
358 :    
359 :     for (my $i = 0; $i < @Users; $i++) {
360 :     my $User = $Users[$i];
361 : gage 1667 my $PermissionLevel = $db->getPermissionLevel($User->user_id); # checked
362 : sh002i 1594
363 :     unless ($PermissionLevel) {
364 :     # uh oh! no permission level record found!
365 :     warn "added missing permission level for user ", $User->user_id, "\n";
366 :    
367 :     # create a new permission level record
368 :     $PermissionLevel = $db->newPermissionLevel;
369 :     $PermissionLevel->user_id($User->user_id);
370 :     $PermissionLevel->permission(0);
371 :    
372 :     # add it to the database
373 :     $db->addPermissionLevel($PermissionLevel);
374 :     }
375 :    
376 :     $PermissionLevels[$i] = $PermissionLevel;
377 :     }
378 :    
379 :     ########## print beginning of form
380 :    
381 :     print CGI::start_form({method=>"post", action=>$r->uri, name=>"userlist"});
382 :     print $self->hidden_authen_fields();
383 :    
384 :     ########## print state data
385 :    
386 :     print "\n<!-- state data here -->\n";
387 :    
388 :     if (@visibleUserIDs) {
389 :     print CGI::hidden(-name=>"visible_users", -value=>\@visibleUserIDs);
390 :     } else {
391 :     print CGI::hidden(-name=>"no_visible_users", -value=>"1");
392 :     }
393 :    
394 :     if (@prevVisibleUserIDs) {
395 :     print CGI::hidden(-name=>"prev_visible_users", -value=>\@prevVisibleUserIDs);
396 :     } else {
397 :     print CGI::hidden(-name=>"no_prev_visible_users", -value=>"1");
398 :     }
399 :    
400 :     print CGI::hidden(-name=>"editMode", -value=>$editMode);
401 :    
402 :     print CGI::hidden(-name=>"sortField", -value=>$sortField);
403 :    
404 :     print "\n<!-- state data here -->\n";
405 :    
406 :     ########## print action forms
407 :    
408 :     print CGI::start_table({});
409 :     print CGI::Tr({}, CGI::td({-colspan=>2}, "Select an action to perform:"));
410 :    
411 :     my @formsToShow;
412 :     if ($editMode) {
413 :     @formsToShow = @{ EDIT_FORMS() };
414 :     } else {
415 :     @formsToShow = @{ VIEW_FORMS() };
416 :     }
417 :    
418 :     my $i = 0;
419 :     foreach my $actionID (@formsToShow) {
420 :     my $actionForm = "${actionID}_form";
421 :     my $onChange = "document.userlist.action[$i].checked=true";
422 :     my %actionParams = $self->getActionParams($actionID);
423 :    
424 :     print CGI::Tr({-valign=>"top"},
425 :     CGI::td({}, CGI::input({-type=>"radio", -name=>"action", -value=>$actionID})),
426 :     CGI::td({}, $self->$actionForm($onChange, %actionParams))
427 :     );
428 :    
429 :     $i++;
430 :     }
431 :    
432 :     print CGI::Tr({}, CGI::td({-colspan=>2, -align=>"center"},
433 :     CGI::submit(-value=>"Take Action!"))
434 :     );
435 :     print CGI::end_table();
436 :    
437 : sh002i 1597 ########## print table
438 :    
439 :     print CGI::p("Showing ", scalar @visibleUserIDs, " out of ", scalar @allUserIDs, " users.");
440 :    
441 :     $self->printTableHTML(\@Users, \@PermissionLevels, \%prettyFieldNames,
442 :     editMode => $editMode,
443 :     selectedUserIDs => \@selectedUserIDs,
444 :     );
445 :    
446 :    
447 : sh002i 1594 ########## print end of form
448 :    
449 :     print CGI::end_form();
450 :    
451 :     return "";
452 :     }
453 :    
454 :     ################################################################################
455 :     # extract particular params and put them in a hash (values are ARRAYREFs!)
456 :     ################################################################################
457 :    
458 :     sub getActionParams {
459 :     my ($self, $actionID) = @_;
460 :     my $r = $self->{r};
461 :    
462 :     my %actionParams;
463 :     foreach my $param ($r->param) {
464 :     next unless $param =~ m/^action\.$actionID\./;
465 :     $actionParams{$param} = [ $r->param($param) ];
466 :     }
467 :     return %actionParams;
468 :     }
469 :    
470 :     sub getTableParams {
471 :     my ($self) = @_;
472 :     my $r = $self->{r};
473 :    
474 :     my %tableParams;
475 :     foreach my $param ($r->param) {
476 :     next unless $param =~ m/^(?:user|permission)\./;
477 :     $tableParams{$param} = [ $r->param($param) ];
478 :     }
479 :     return %tableParams;
480 :     }
481 :    
482 :     ################################################################################
483 :     # actions and action triggers
484 :     ################################################################################
485 :    
486 : sh002i 1597 # filter, edit, cancelEdit, and saveEdit should stay with the display module and
487 :     # not be real "actions". that way, all actions are shown in view mode and no
488 :     # actions are shown in edit mode.
489 :    
490 : sh002i 1594 sub filter_form {
491 :     my ($self, $onChange, %actionParams) = @_;
492 : sh002i 1601 #return CGI::table({}, CGI::Tr({-valign=>"top"},
493 :     # CGI::td({},
494 :     return join("",
495 :     "Show ",
496 :     CGI::popup_menu(
497 :     -name => "action.filter.scope",
498 :     -values => [qw(all none selected match_ids match_section match_recitation)],
499 : gage 1711 -default => $actionParams{"action.filter.scope"}->[0] || "match_ids",
500 : sh002i 1601 -labels => {
501 :     all => "all users",
502 :     none => "no users",
503 : sh002i 1782 selected => "users checked below",
504 : sh002i 1601 match_ids => "users with matching user IDs:",
505 :     match_section => "users in selected section",
506 :     match_recitation => "users in selected recitation",
507 :     },
508 :     -onchange => $onChange,
509 :     ),
510 :     " ",
511 :     CGI::textfield(
512 :     -name => "action.filter.user_ids",
513 :     -value => $actionParams{"action.filter.user_ids"}->[0] || "",,
514 :     -width => "50",
515 :     -onchange => $onChange,
516 :     ),
517 :     " (separate multiple IDs with commas)",
518 :     CGI::br(),
519 :     "sections: ",
520 :     CGI::popup_menu(
521 :     -name => "action.filter.section",
522 :     -values => [ keys %{ $self->{sections} } ],
523 :     -default => $actionParams{"action.filter.section"}->[0] || "",
524 :     -labels => { $self->menuLabels($self->{sections}) },
525 :     -onchange => $onChange,
526 :     ),
527 :     " recitations: ",
528 :     CGI::popup_menu(
529 :     -name => "action.filter.recitation",
530 :     -values => [ keys %{ $self->{recitations} } ],
531 :     -default => $actionParams{"action.filter.recitation"}->[0] || "",
532 :     -labels => { $self->menuLabels($self->{recitations}) },
533 :     -onchange => $onChange,
534 :     ),
535 : sh002i 1594 );
536 : sh002i 1601 # ),
537 :     #));
538 : sh002i 1594 }
539 :    
540 :     # this action handler modifies the "visibleUserIDs" field based on the contents
541 :     # of the "action.filter.scope" parameter and the "selected_users"
542 :     sub filter_handler {
543 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
544 :    
545 :     my $result;
546 :    
547 :     my $scope = $actionParams->{"action.filter.scope"}->[0];
548 :     if ($scope eq "all") {
549 :     $result = "showing all users";
550 :     $self->{visibleUserIDs} = $self->{allUserIDs};
551 :     } elsif ($scope eq "none") {
552 :     $result = "showing no users";
553 :     $self->{visibleUserIDs} = [];
554 :     } elsif ($scope eq "selected") {
555 :     $result = "showing selected users";
556 :     $self->{visibleUserIDs} = $genericParams->{selected_users}; # an arrayref
557 : sh002i 1601 } elsif ($scope eq "match_ids") {
558 :     my @userIDs = split /\s*,\s*/, $actionParams->{"action.filter.user_ids"}->[0];
559 :     $self->{visibleUserIDs} = \@userIDs;
560 :     } elsif ($scope eq "match_section") {
561 :     my $section = $actionParams->{"action.filter.section"}->[0];
562 : sh002i 1604 $self->{visibleUserIDs} = $self->{sections}->{$section}; # an arrayref
563 : sh002i 1601 } elsif ($scope eq "match_recitation") {
564 :     my $recitation = $actionParams->{"action.filter.recitation"}->[0];
565 : sh002i 1604 $self->{visibleUserIDs} = $self->{recitations}->{$recitation}; # an arrayref
566 : sh002i 1594 }
567 :    
568 :     return $result;
569 :     }
570 :    
571 :     sub edit_form {
572 :     my ($self, $onChange, %actionParams) = @_;
573 :     return join("",
574 :     "Edit ",
575 :     CGI::popup_menu(
576 :     -name => "action.edit.scope",
577 :     -values => [qw(all visible selected)],
578 : gage 1713 -default => $actionParams{"action.edit.scope"}->[0] || "selected",
579 : sh002i 1594 -labels => {
580 :     all => "all users",
581 :     visible => "visible users",
582 :     selected => "selected users"
583 :     },
584 :     -onchange => $onChange,
585 :     ),
586 :     );
587 :     }
588 :    
589 :     sub edit_handler {
590 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
591 :    
592 :     my $result;
593 :    
594 :     my $scope = $actionParams->{"action.edit.scope"}->[0];
595 :     if ($scope eq "all") {
596 :     $result = "editing all users";
597 :     $self->{visibleUserIDs} = $self->{allUserIDs};
598 :     } elsif ($scope eq "visible") {
599 :     $result = "editing visible users";
600 :     # leave visibleUserIDs alone
601 :     } elsif ($scope eq "selected") {
602 :     $result = "editing selected users";
603 :     $self->{visibleUserIDs} = $genericParams->{selected_users}; # an arrayref
604 :     }
605 :     $self->{editMode} = 1;
606 :    
607 :     return $result;
608 :     }
609 :    
610 :     sub delete_form {
611 :     my ($self, $onChange, %actionParams) = @_;
612 :     return join("",
613 : gage 1712 qq!\n<div style="background-color:red">!,
614 : sh002i 1594 "Delete ",
615 :     CGI::popup_menu(
616 :     -name => "action.delete.scope",
617 : gage 1712 -values => [qw(none visible selected)],
618 :     -default => $actionParams{"action.delete.scope"}->[0] || "none",
619 : sh002i 1594 -labels => {
620 : gage 1712 none => "no users.",
621 : sh002i 1782 #visible => "visible users.",
622 : gage 1712 selected => "selected users."
623 : sh002i 1594 },
624 :     -onchange => $onChange,
625 :     ),
626 : sh002i 1597 CGI::em(" Deletion destroys all user-related data and is not undoable!"),
627 : gage 1712 "</div>\n",
628 : sh002i 1594 );
629 :     }
630 :    
631 :     sub delete_handler {
632 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
633 : gage 1928 my $r = $self->r;
634 :     my $db = $r->db;
635 : sh002i 1594 my $scope = $actionParams->{"action.delete.scope"}->[0];
636 :    
637 : gage 1712 my @userIDsToDelete = ();
638 : sh002i 1782 #if ($scope eq "visible") {
639 :     # @userIDsToDelete = @{ $self->{visibleUserIDs} };
640 :     #} elsif ($scope eq "selected") {
641 :     if ($scope eq "selected") {
642 : sh002i 1594 @userIDsToDelete = @{ $self->{selectedUserIDs} };
643 :     }
644 :    
645 :     my %allUserIDs = map { $_ => 1 } @{ $self->{allUserIDs} };
646 :     my %visibleUserIDs = map { $_ => 1 } @{ $self->{visibleUserIDs} };
647 :     my %selectedUserIDs = map { $_ => 1 } @{ $self->{selectedUserIDs} };
648 :    
649 :     foreach my $userID (@userIDsToDelete) {
650 :     delete $allUserIDs{$userID};
651 :     delete $visibleUserIDs{$userID};
652 :     delete $selectedUserIDs{$userID};
653 :     $db->deleteUser($userID);
654 :     }
655 :    
656 :     $self->{allUserIDs} = [ keys %allUserIDs ];
657 :     $self->{visibleUserIDs} = [ keys %visibleUserIDs ];
658 :     $self->{selectedUserIDs} = [ keys %selectedUserIDs ];
659 :    
660 :     my $num = @userIDsToDelete;
661 :     return "deleted $num user" . ($num == 1 ? "" : "s");
662 :     }
663 : gage 1712 sub add_form {
664 :     my ($self, $onChange, %actionParams) = @_;
665 : sh002i 1594
666 : gage 1712 return "Add ", CGI::input({name=>'number_of_students', value=>1,size => 3}), " student(s). ";
667 :     }
668 :    
669 :     sub add_handler {
670 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
671 :     # This action is redirected to the addUser.pm module using ../instructor/add_user/...
672 :     return "Nothing done by add student handler";
673 :     }
674 : sh002i 1594 sub import_form {
675 :     my ($self, $onChange, %actionParams) = @_;
676 :     return join(" ",
677 :     "Import users from file",
678 :     CGI::popup_menu(
679 :     -name => "action.import.source",
680 :     -values => [ "", $self->getCSVList() ],
681 :     -default => $actionParams{"action.import.source"}->[0] || "",
682 :     -onchange => $onChange,
683 : sh002i 1597 ),
684 : sh002i 1594 "replacing",
685 :     CGI::popup_menu(
686 :     -name => "action.import.replace",
687 :     -values => [qw(any visible selected none)],
688 :     -default => $actionParams{"action.import.replace"}->[0] || "none",
689 :     -labels => {
690 :     any => "any",
691 :     visible => "visible",
692 :     selected => "selected",
693 :     none => "no",
694 :     },
695 :     -onchange => $onChange,
696 :     ),
697 : sh002i 1597 "existing users and adding",
698 : sh002i 1594 CGI::popup_menu(
699 :     -name => "action.import.add",
700 :     -values => [qw(any none)],
701 :     -default => $actionParams{"action.import.add"}->[0] || "any",
702 :     -labels => {
703 :     any => "any",
704 :     none => "no",
705 :     },
706 :     -onchange => $onChange,
707 :     ),
708 :     "new users",
709 :     );
710 :     }
711 :    
712 :     sub import_handler {
713 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
714 :    
715 :     my $source = $actionParams->{"action.import.source"}->[0];
716 :     my $add = $actionParams->{"action.import.add"}->[0];
717 :     my $replace = $actionParams->{"action.import.replace"}->[0];
718 :    
719 :     my $fileName = $source;
720 :     my $createNew = $add eq "any";
721 :     my $replaceExisting;
722 :     my @replaceList;
723 :     if ($replace eq "any") {
724 :     $replaceExisting = "any";
725 :     } elsif ($replace eq "none") {
726 :     $replaceExisting = "none";
727 :     } elsif ($replace eq "visible") {
728 :     $replaceExisting = "listed";
729 :     @replaceList = @{ $self->{visibleUserIDs} };
730 :     } elsif ($replace eq "selected") {
731 :     $replaceExisting = "listed";
732 :     @replaceList = @{ $self->{selectedUserIDs} };
733 :     }
734 :    
735 :     my ($replaced, $added, $skipped)
736 :     = $self->importUsersFromCSV($fileName, $createNew, $replaceExisting, @replaceList);
737 :    
738 : sh002i 1597 # make new users visible... do we really want to do this? probably.
739 :     push @{ $self->{visibleUserIDs} }, @$added;
740 :    
741 : sh002i 1594 my $numReplaced = @$replaced;
742 :     my $numAdded = @$added;
743 :     my $numSkipped = @$skipped;
744 :    
745 :     return $numReplaced . " user" . ($numReplaced == 1 ? "" : "s") . " replaced, "
746 :     . $numAdded . " user" . ($numAdded == 1 ? "" : "s") . " added, "
747 :     . $numSkipped . " user" . ($numSkipped == 1 ? "" : "s") . " skipped.";
748 :     }
749 :    
750 :     sub export_form {
751 :     my ($self, $onChange, %actionParams) = @_;
752 : sh002i 1597 return join("",
753 :     "Export ",
754 : sh002i 1594 CGI::popup_menu(
755 :     -name => "action.export.scope",
756 :     -values => [qw(all visible selected)],
757 : sh002i 1597 -default => $actionParams{"action.export.scope"}->[0] || "visible",
758 : sh002i 1594 -labels => {
759 :     all => "all users",
760 :     visible => "visible users",
761 :     selected => "selected users"
762 :     },
763 :     -onchange => $onChange,
764 :     ),
765 : sh002i 1597 " to ",
766 : sh002i 1594 CGI::popup_menu(
767 : sh002i 1597 -name=>"action.export.target",
768 :     -values => [ "new", $self->getCSVList() ],
769 :     -labels => { new => "a new file named:" },
770 :     -default => $actionParams{"action.export.target"}->[0] || "",
771 : sh002i 1594 -onchange => $onChange,
772 : sh002i 1597 ),
773 :     #CGI::br(),
774 :     #"new file to create: ",
775 : sh002i 1594 CGI::textfield(
776 : sh002i 1597 -name => "action.export.new",
777 :     -value => $actionParams{"action.export.new"}->[0] || "",,
778 :     -width => "50",
779 :     -onchange => $onChange,
780 : sh002i 1594 ),
781 : sh002i 1597 CGI::tt(".lst"),
782 : sh002i 1594 );
783 :     }
784 :    
785 : sh002i 1597 sub export_handler {
786 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
787 :    
788 :     my $scope = $actionParams->{"action.export.scope"}->[0];
789 :     my $target = $actionParams->{"action.export.target"}->[0];
790 :     my $new = $actionParams->{"action.export.new"}->[0];
791 :    
792 :     my $fileName;
793 :     if ($target eq "new") {
794 :     $fileName = $new;
795 :     } else {
796 :     $fileName = $target;
797 :     }
798 :    
799 :     $fileName .= ".lst" unless $fileName =~ m/\.lst$/;
800 :    
801 :     my @userIDsToExport;
802 :     if ($scope eq "all") {
803 :     @userIDsToExport = @{ $self->{allUserIDs} };
804 :     } elsif ($scope eq "visible") {
805 :     @userIDsToExport = @{ $self->{visibleUserIDs} };
806 :     } elsif ($scope eq "selected") {
807 :     @userIDsToExport = @{ $self->{selectedUserIDs} };
808 :     }
809 :    
810 :     $self->exportUsersToCSV($fileName, @userIDsToExport);
811 :    
812 :     return scalar @userIDsToExport . " users exported";
813 :     }
814 :    
815 : sh002i 1594 sub cancelEdit_form {
816 :     my ($self, $onChange, %actionParams) = @_;
817 :     return "Abandon changes";
818 :     }
819 :    
820 :     sub cancelEdit_handler {
821 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
822 : gage 1928 my $r = $self->r;
823 : sh002i 1594
824 :     #$self->{selectedUserIDs} = $self->{visibleUserIDs};
825 :     # only do the above if we arrived here via "edit selected users"
826 :     if (defined $r->param("prev_visible_users")) {
827 :     $self->{visibleUserIDs} = [ $r->param("prev_visible_users") ];
828 :     } elsif (defined $r->param("no_prev_visible_users")) {
829 :     $self->{visibleUserIDs} = [];
830 :     } else {
831 :     # leave it alone
832 :     }
833 :     $self->{editMode} = 0;
834 :    
835 :     return "changes abandoned";
836 :     }
837 :    
838 :     sub saveEdit_form {
839 :     my ($self, $onChange, %actionParams) = @_;
840 :     return "Save changes";
841 :     }
842 :    
843 :     sub saveEdit_handler {
844 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
845 : gage 1928 my $r = $self->r;
846 :     my $db = $r->db;
847 : sh002i 1594
848 :     my @visibleUserIDs = @{ $self->{visibleUserIDs} };
849 :     foreach my $userID (@visibleUserIDs) {
850 : gage 1667 my $User = $db->getUser($userID); # checked
851 :     die "record for visible user $userID not found" unless $User;
852 :     my $PermissionLevel = $db->getPermissionLevel($userID); # checked
853 :     die "permissions for $userID not defined" unless defined $PermissionLevel;
854 : sh002i 1594 foreach my $field ($User->NONKEYFIELDS()) {
855 :     my $param = "user.${userID}.${field}";
856 :     if (defined $tableParams->{$param}->[0]) {
857 :     $User->$field($tableParams->{$param}->[0]);
858 : malsyned 1233 }
859 :     }
860 : sh002i 1594
861 :     foreach my $field ($PermissionLevel->NONKEYFIELDS()) {
862 :     my $param = "permission.${userID}.${field}";
863 :     if (defined $tableParams->{$param}->[0]) {
864 :     $PermissionLevel->$field($tableParams->{$param}->[0]);
865 :     }
866 :     }
867 :    
868 :     $db->putUser($User);
869 :     $db->putPermissionLevel($PermissionLevel);
870 :     }
871 :    
872 :     if (defined $r->param("prev_visible_users")) {
873 :     $self->{visibleUserIDs} = [ $r->param("prev_visible_users") ];
874 :     } elsif (defined $r->param("no_prev_visible_users")) {
875 :     $self->{visibleUserIDs} = [];
876 :     } else {
877 :     # leave it alone
878 :     }
879 :    
880 :     $self->{editMode} = 0;
881 :    
882 :     return "changes saved";
883 :     }
884 :    
885 :     ################################################################################
886 :     # sorts
887 :     ################################################################################
888 :    
889 :     sub byUserID { $a->user_id cmp $b->user_id }
890 :     sub byFirstName { $a->first_name cmp $b->first_name }
891 :     sub byLastName { $a->last_name cmp $b->last_name }
892 :     sub byEmailAddress { $a->email_address cmp $b->email_address }
893 :     sub byStudentID { $a->student_id cmp $b->student_id }
894 :     sub byStatus { $a->status cmp $b->status }
895 :     sub bySection { $a->section cmp $b->section }
896 :     sub byRecitation { $a->recitation cmp $b->recitation }
897 :     sub byComment { $a->comment cmp $b->comment }
898 :    
899 :     sub byLnFnUid { &byLastName || &byFirstName || &byUserID }
900 :    
901 :     ################################################################################
902 :     # utilities
903 :     ################################################################################
904 :    
905 :     # generate labels for section/recitation popup menus
906 :     sub menuLabels {
907 :     my ($self, $hashRef) = @_;
908 :     my %hash = %$hashRef;
909 :    
910 :     my %result;
911 :     foreach my $key (keys %hash) {
912 :     my $count = @{ $hash{$key} };
913 :     my $displayKey = $key || "<none>";
914 :     $result{$key} = "$displayKey ($count users)";
915 :     }
916 :     return %result;
917 :     }
918 :    
919 :     sub importUsersFromCSV {
920 :     my ($self, $fileName, $createNew, $replaceExisting, @replaceList) = @_;
921 : gage 1928 my $r = $self->r;
922 :     my $ce = $r->ce;
923 :     my $db = $r->db;
924 :     my $dir = $ce->{courseDirs}->{templates};
925 : sh002i 1594
926 :     die "illegal character in input: \"/\"" if $fileName =~ m|/|;
927 :     die "won't be able to read from file $dir/$fileName: does it exist? is it readable?"
928 :     unless -r "$dir/$fileName";
929 :    
930 :     my %allUserIDs = map { $_ => 1 } @{ $self->{allUserIDs} };
931 :     my %replaceOK;
932 :     if ($replaceExisting eq "none") {
933 :     %replaceOK = ();
934 :     } elsif ($replaceExisting eq "listed") {
935 :     %replaceOK = map { $_ => 1 } @replaceList;
936 :     } elsif ($replaceExisting eq "any") {
937 :     %replaceOK = %allUserIDs;
938 :     }
939 :    
940 :     my (@replaced, @added, @skipped);
941 :    
942 :     my @contents = split /\n/, readFile("$dir/$fileName");
943 :     foreach my $string (@contents) {
944 :     $string =~ s/^\s+//;
945 :     $string =~ s/\s+$//;
946 :     my (
947 :     $student_id, $last_name, $first_name, $status, $comment,
948 :     $section, $recitation, $email_address, $user_id
949 :     ) = split /\s*,\s*/, $string;
950 :    
951 :     if (exists $allUserIDs{$user_id} and not exists $replaceOK{$user_id}) {
952 :     push @skipped, $user_id;
953 :     next;
954 :     }
955 :    
956 :     if (not exists $allUserIDs{$user_id} and not $createNew) {
957 :     push @skipped, $user_id;
958 :     next;
959 :     }
960 :    
961 :     my $User = $db->newUser;
962 :     $User->user_id($user_id);
963 :     $User->first_name($first_name);
964 :     $User->last_name($last_name);
965 :     $User->email_address($email_address);
966 :     $User->student_id($student_id);
967 :     $User->status($status);
968 :     $User->section($section);
969 :     $User->recitation($recitation);
970 :     $User->comment($comment);
971 :    
972 :     my $PermissionLevel = $db->newPermissionLevel;
973 :     $PermissionLevel->user_id($user_id);
974 :     $PermissionLevel->permission(0);
975 :    
976 :     my $Password = $db->newPassword;
977 :     $Password->user_id($user_id);
978 : sh002i 1654 $Password->password(cryptPassword($student_id));
979 : sh002i 1594
980 :     if (exists $allUserIDs{$user_id}) {
981 :     $db->putUser($User);
982 :     $db->putPermissionLevel($PermissionLevel);
983 :     $db->putPassword($Password);
984 :     push @replaced, $user_id;
985 :     } else {
986 :     $db->addUser($User);
987 :     $db->addPermissionLevel($PermissionLevel);
988 :     $db->addPassword($Password);
989 :     push @added, $user_id;
990 :     }
991 :     }
992 :    
993 :     return \@replaced, \@added, \@skipped;
994 :     }
995 :    
996 : sh002i 1597 sub exportUsersToCSV {
997 :     my ($self, $fileName, @userIDsToExport) = @_;
998 : gage 1928 my $r = $self->r;
999 :     my $ce = $r->ce;
1000 :     my $db = $r->db;
1001 :     my $dir = $ce->{courseDirs}->{templates};
1002 : sh002i 1597
1003 :     die "illegal character in input: \"/\"" if $fileName =~ m|/|;
1004 :    
1005 :     open my $fh, ">", "$dir/$fileName"
1006 :     or die "failed to open file $dir/$fileName for writing: $!\n";
1007 :    
1008 :     foreach my $userID (@userIDsToExport) {
1009 : gage 1667 my $User = $db->getUser($userID); # checked
1010 :     die "record for user $userID not found." unless $User;
1011 : sh002i 1597 my @fields = (
1012 :     $User->student_id,
1013 :     $User->last_name,
1014 :     $User->first_name,
1015 :     $User->status,
1016 :     $User->comment,
1017 :     $User->section,
1018 :     $User->recitation,
1019 :     $User->email_address,
1020 :     $User->user_id,
1021 :     );
1022 :     my $string = join ",", @fields;
1023 :     print $fh "$string\n";
1024 :     }
1025 :    
1026 :     close $fh;
1027 :     }
1028 :    
1029 : sh002i 1594 ################################################################################
1030 :     # "display" methods
1031 :     ################################################################################
1032 :    
1033 :     sub fieldEditHTML {
1034 :     my ($self, $fieldName, $value, $properties) = @_;
1035 :     my $size = $properties->{size};
1036 :     my $type = $properties->{type};
1037 :     my $access = $properties->{access};
1038 :     my $items = $properties->{items};
1039 :     my $synonyms = $properties->{synonyms};
1040 :    
1041 :     if ($access eq "readonly") {
1042 :     return $value;
1043 :     }
1044 :    
1045 :     if ($type eq "number" or $type eq "text") {
1046 :     return CGI::input({type=>"text", name=>$fieldName, value=>$value, size=>$size});
1047 :     }
1048 :    
1049 :     if ($type eq "enumerable") {
1050 :     my $matched = undef; # Whether a synonym match has occurred
1051 :    
1052 :     # Process synonyms for enumerable objects
1053 :     foreach my $synonym (keys %$synonyms) {
1054 :     if ($synonym ne "*" and $value =~ m/$synonym/) {
1055 :     $value = $synonyms->{$synonym};
1056 :     $matched = 1;
1057 :     }
1058 :     }
1059 :    
1060 :     if (!$matched and exists $synonyms->{"*"}) {
1061 :     $value = $synonyms->{"*"};
1062 :     }
1063 :    
1064 :     return CGI::popup_menu({
1065 :     name => $fieldName,
1066 :     values => [keys %$items],
1067 :     default => $value,
1068 :     labels => $items,
1069 :     });
1070 :     }
1071 :     }
1072 :    
1073 :     sub recordEditHTML {
1074 :     my ($self, $User, $PermissionLevel, %options) = @_;
1075 : gage 1928 my $r = $self->r;
1076 :     my $urlpath = $r->urlpath;
1077 :     my $ce = $r->ce;
1078 :     my $root = $ce->{webworkURLs}->{root};
1079 :     my $courseName = $urlpath->arg("courseID");
1080 : sh002i 1594
1081 :     my $editMode = $options{editMode};
1082 :     my $userSelected = $options{userSelected};
1083 :    
1084 :     my $changeEUserURL = "$root/$courseName?"
1085 :     . "user=" . $r->param("user")
1086 :     . "&effectiveUser=" . $User->user_id
1087 :     . "&key=" . $r->param("key");
1088 :    
1089 : sh002i 1640 my $setsAssignedToUserURL = "$root/$courseName/instructor/users/"
1090 :     . $User->user_id . "/sets/?"
1091 :     . "user=" . $r->param("user")
1092 :     . "&effectiveUser=" . $r->param("effectiveUser")
1093 :     . "&key=" . $r->param("key");
1094 :    
1095 : sh002i 1594 my @tableCells;
1096 :    
1097 :     # Select
1098 :     if ($editMode) {
1099 :     # column not there
1100 :     } else {
1101 :     # selection checkbox
1102 :     push @tableCells, CGI::checkbox(
1103 :     -name => "selected_users",
1104 :     -value => $User->user_id,
1105 :     -checked => $userSelected,
1106 :     -label => "",
1107 :     );
1108 :     }
1109 :    
1110 : sh002i 1640 # Act As
1111 :     if ($editMode) {
1112 :     # column not there
1113 :     } else {
1114 :     # selection checkbox
1115 : gage 1736 push @tableCells, CGI::a({href=>$changeEUserURL}, $User->user_id);
1116 : sh002i 1640 }
1117 :    
1118 : sh002i 1594 # User ID
1119 :     if ($editMode) {
1120 :     # straight user ID
1121 :     push @tableCells, $User->user_id;
1122 :     } else {
1123 : sh002i 1640 # "edit sets assigned to user" link
1124 : gage 1753 push @tableCells, CGI::a({href=>$setsAssignedToUserURL}, "Edit sets");
1125 : sh002i 1594 }
1126 :    
1127 :     # User Fields
1128 :     foreach my $field ($User->NONKEYFIELDS) {
1129 :     my $fieldName = "user." . $User->user_id . "." . $field,
1130 :     my $fieldValue = $User->$field;
1131 :     my %properties = %{ FIELD_PROPERTIES()->{$field} };
1132 :     $properties{access} = "readonly" unless $editMode;
1133 : toenail 1799 $fieldValue = nbsp($fieldValue) unless $editMode;
1134 : sh002i 1594 push @tableCells, $self->fieldEditHTML($fieldName, $fieldValue, \%properties);
1135 :     }
1136 :    
1137 :     # PermissionLevel Fields
1138 :     foreach my $field ($PermissionLevel->NONKEYFIELDS) {
1139 :     my $fieldName = "permission." . $PermissionLevel->user_id . "." . $field,
1140 :     my $fieldValue = $PermissionLevel->$field;
1141 :     my %properties = %{ FIELD_PROPERTIES()->{$field} };
1142 :     $properties{access} = "readonly" unless $editMode;
1143 : toenail 1799 $fieldValue = nbsp($fieldValue) unless $editMode;
1144 : sh002i 1594 push @tableCells, $self->fieldEditHTML($fieldName, $fieldValue, \%properties);
1145 :     }
1146 :    
1147 :     return CGI::Tr({}, CGI::td({}, \@tableCells));
1148 :     }
1149 :    
1150 :     sub printTableHTML {
1151 :     my ($self, $UsersRef, $PermissionLevelsRef, $fieldNamesRef, %options) = @_;
1152 : gage 1928 my $r = $self->r;
1153 :     my $userTemplate = $self->{userTemplate};
1154 : sh002i 1594 my $permissionLevelTemplate = $self->{permissionLevelTemplate};
1155 : gage 1928 my @Users = @$UsersRef;
1156 :     my @PermissionLevels = @$PermissionLevelsRef;
1157 :     my %fieldNames = %$fieldNamesRef;
1158 : sh002i 1594
1159 : gage 1928 my $editMode = $options{editMode};
1160 :     my %selectedUserIDs = map { $_ => 1 } @{ $options{selectedUserIDs} };
1161 :     my $currentSort = $options{currentSort};
1162 : sh002i 1594
1163 :     # names of headings:
1164 :     my @realFieldNames = (
1165 :     $userTemplate->KEYFIELDS,
1166 :     $userTemplate->NONKEYFIELDS,
1167 :     $permissionLevelTemplate->NONKEYFIELDS,
1168 : malsyned 1233 );
1169 :    
1170 : sh002i 1594 my %sortSubs = %{ SORT_SUBS() };
1171 :     #my @stateParams = @{ STATE_PARAMS() };
1172 :     #my $hrefPrefix = $r->uri . "?" . $self->url_args(@stateParams); # $self->url_authen_args
1173 :     my @tableHeadings;
1174 :     foreach my $field (@realFieldNames) {
1175 :     my $result;
1176 :     #if (exists $sortSubs{$field}) {
1177 :     # $result = CGI::a({-href=>"$hrefPrefix&sort=$field"}, $fieldNames{$field});
1178 :     #} else {
1179 :     $result = $fieldNames{$field};
1180 :     #}
1181 :     push @tableHeadings, $result;
1182 :     };
1183 :    
1184 :     # prepend selection checkbox? only if we're NOT editing!
1185 : sh002i 1640 unshift @tableHeadings, "Select", "Act As" unless $editMode;
1186 : sh002i 1594
1187 :     # print the table
1188 :     if ($editMode) {
1189 :     print CGI::start_table({});
1190 :     } else {
1191 :     print CGI::start_table({-border=>1});
1192 :     }
1193 :    
1194 :     print CGI::Tr({}, CGI::th({}, \@tableHeadings));
1195 :    
1196 : gage 1713
1197 : sh002i 1594 for (my $i = 0; $i < @Users; $i++) {
1198 :     my $User = $Users[$i];
1199 :     my $PermissionLevel = $PermissionLevels[$i];
1200 :    
1201 :     print $self->recordEditHTML($User, $PermissionLevel,
1202 :     editMode => $editMode,
1203 :     userSelected => exists $selectedUserIDs{$User->user_id}
1204 :     );
1205 :     }
1206 :    
1207 :     print CGI::end_table();
1208 : gage 1713 #########################################
1209 :     # if there are no users shown print message
1210 :     #
1211 :     ##########################################
1212 :    
1213 :     print CGI::p(
1214 :     CGI::i("No students shown. Choose one of the options above to
1215 :     list the students in the course.")
1216 :     ) unless @Users;
1217 : sh002i 1594 }
1218 :    
1219 :     1;
1220 :    
1221 :     __END__
1222 :    
1223 :     my $editMode = 0;
1224 :     if (defined $r->param("edit_selected") or defined $r->param("edit_visible")) {
1225 :     $editMode = 1;
1226 :     }
1227 :    
1228 : sh002i 1567 my @userIDs = $db->listUsers;
1229 :     my @userRecords = $db->getUsers(@userIDs);
1230 :    
1231 :     my (%sections, %recitations);
1232 :     foreach my $user (@userRecords) {
1233 :     push @{$sections{$user->section}}, $user;
1234 :     push @{$recitations{$user->recitation}}, $user;
1235 :     }
1236 :    
1237 :     my $filter_type = $r->param("filter_type")
1238 :     || (@userIDs > HIDE_USERS_THRESHHOLD ? "none" : "all");
1239 :     my $filter_user_id = $filter_type eq "filter_user_id"
1240 :     ? $r->param("filter_user_id") || ""
1241 :     : "";
1242 :     my $filter_section = $filter_type eq "filter_section"
1243 :     ? $r->param("filter_section") || ""
1244 :     : "";
1245 :     my $filter_recitation = $filter_type eq "filter_recitation"
1246 :     ? $r->param("filter_recitation") || ""
1247 :     : "";
1248 :    
1249 : sh002i 1584 # override filter selection if "Edit Selected Users" button is pressed
1250 :     if (defined $r->param("edit_selected")) {
1251 :     $filter_type = "filter_selected";
1252 :     }
1253 :    
1254 : sh002i 1567 if ($filter_type eq "none") {
1255 :     @userRecords = ();
1256 : sh002i 1584 } elsif ($filter_type eq "filter_selected") {
1257 :     @userRecords = ();
1258 :     my @userIDs = $r->param("selectUser");
1259 :     if (@userIDs) {
1260 :     @userRecords = $db->getUsers(@userIDs);
1261 :     }
1262 : sh002i 1567 } elsif ($filter_type eq "filter_user_id") {
1263 :     @userRecords = ();
1264 :     if ($filter_user_id ne "") {
1265 :     my $userRecord = $db->getUser($filter_user_id);
1266 :     @userRecords = ($userRecord) if $userRecord;
1267 :     }
1268 :     } elsif ($filter_type eq "filter_section") {
1269 :     @userRecords = ();
1270 :     @userRecords = @{$sections{$filter_section}}
1271 :     if exists $sections{$filter_section};
1272 :     } elsif ($filter_type eq "filter_recitation") {
1273 :     @userRecords = ();
1274 :     @userRecords = @{$recitations{$filter_recitation}}
1275 :     if exists $recitations{$filter_recitation};
1276 :     }
1277 :    
1278 :     @userRecords = sort {
1279 :     (lc $a->section cmp lc $b->section)
1280 :     || (lc $a->last_name cmp lc $b->last_name)
1281 :     || (lc $a->first_name cmp lc $b->first_name)
1282 :     || (lc $a->user_id cmp lc $b->user_id)
1283 :     } @userRecords;
1284 :    
1285 : malsyned 1211 print CGI::start_form({method=>"post", action=>$r->uri()});
1286 : sh002i 1567 print $self->hidden_authen_fields();
1287 :    
1288 : sh002i 1594 filter options
1289 : sh002i 1567 my %labels = (
1290 :     none => "No users",
1291 : sh002i 1584 all => "All " . scalar @userIDs . " users",
1292 :     filter_selected => "Users selected below",
1293 : sh002i 1567 filter_user_id => "User with ID " . CGI::input({
1294 :     type=>"text",
1295 :     name=>"filter_user_id",
1296 :     value=>$filter_user_id,
1297 :     size=>"20"
1298 :     }),
1299 :     filter_section => "Users in section " . CGI::popup_menu(
1300 :     -name=>"filter_section",
1301 :     -values=>[ keys %sections ],
1302 :     -labels=>{ $self->menuLabels(\%sections) },
1303 :     -default=>$filter_section,
1304 :     ),
1305 :     filter_recitation => "Users in recitation " . CGI::popup_menu(
1306 :     -name=>"filter_recitation",
1307 :     -values=>[ sort keys %recitations ],
1308 :     -labels=>{ $self->menuLabels(\%recitations) },
1309 :     -default=>$filter_recitation,
1310 :     ),
1311 :     );
1312 :    
1313 : sh002i 1584 if ($editMode) {
1314 :     print CGI::hidden(
1315 :     -name=>"filter_type",
1316 :     -value=>"filter_selected",
1317 :     );
1318 :     } else {
1319 :     my $cgi = new CGI;
1320 :     $cgi->autoEscape(0);
1321 :     print "Show:", CGI::br();
1322 :     print $cgi->radio_group(
1323 :     -name=>"filter_type",
1324 :     -values=>[ qw(none all filter_selected filter_user_id filter_section filter_recitation) ],
1325 :     -default=>$filter_type,
1326 :     -linebreak=>"true",
1327 :     -labels=>\%labels,
1328 :     -rows=>3,
1329 :     -columns=>2,
1330 :     );
1331 :     print CGI::submit({name=>"filter", value=>"Filter"});
1332 :     }
1333 :    
1334 : malsyned 1110 print CGI::start_table({});
1335 : malsyned 1214
1336 :     # Table headings, prettied-up
1337 : sh002i 1567 my @tableHeadings = (
1338 : sh002i 1584 ($editMode ? () : "Select"),
1339 : sh002i 1567 map {$prettyFieldNames{$_}} (
1340 :     $userTemplate->KEYFIELDS(),
1341 :     $userTemplate->NONKEYFIELDS(),
1342 :     $permissionLevelTemplate->NONKEYFIELDS(),
1343 :     ),
1344 :     );
1345 :    
1346 :     # now print them
1347 : malsyned 1110 print CGI::Tr({},
1348 : sh002i 1567 CGI::th({}, \@tableHeadings)
1349 : malsyned 1110 );
1350 : sh002i 1567
1351 : sh002i 1584 my @userIDsForHiddenSelectField;
1352 :    
1353 : gage 1473 # process user records
1354 :     foreach my $userRecord (@userRecords) {
1355 :     my $currentUser = $userRecord->user_id;
1356 : sh002i 1584 push @userIDsForHiddenSelectField, $currentUser;
1357 : malsyned 1110 my $permissionLevel = $db->getPermissionLevel($currentUser);
1358 : gage 1357 unless (defined $permissionLevel) {
1359 : sh002i 1567 warn "No permissionLevel record for user $currentUser -- added";
1360 : gage 1473 my $newPermissionLevel = $db->newPermissionLevel;
1361 :     $newPermissionLevel->user_id($currentUser);
1362 :     $newPermissionLevel->permission(0);
1363 :     $db->addPermissionLevel($newPermissionLevel);
1364 : sh002i 1567 $permissionLevel = $newPermissionLevel;
1365 : gage 1473 # permission set to minimum level
1366 : gage 1357 }
1367 : malsyned 1110
1368 : malsyned 1214 # A concise way of printing a row containing a cell for each field, editable unless it's a key
1369 : malsyned 1110 print CGI::Tr({},
1370 :     CGI::td({}, [
1371 : sh002i 1584 ($editMode
1372 :     ? () # don't show selection checkbox if we're in edit mode -- hidden field below
1373 :     #: CGI::input({type=>"checkbox", name=>"selectUser", value=>$currentUser})
1374 :     : CGI::checkbox(
1375 :     -name=>"selectUser",
1376 :     -value=>$currentUser,
1377 :     -checked=>($filter_type eq "filter_selected" and not defined $r->param("editingAllVisibleUsers")),
1378 :     -label=>""
1379 :     )
1380 :     ),
1381 :     ($editMode
1382 :     ? $currentUser
1383 :     : (map {
1384 :     my $changeEUserURL = "$root/$courseName?"
1385 :     . "user=" . $r->param("user")
1386 :     . "&effectiveUser=" . $userRecord->user_id
1387 :     . "&key=" . $r->param("key");
1388 :     CGI::a({href=>$changeEUserURL}, $userRecord->$_)
1389 :     } $userRecord->KEYFIELDS)
1390 :     ),
1391 : malsyned 1233 (map {
1392 : sh002i 1567 $self->fieldEditHTML(
1393 :     "user." . $userRecord->user_id . "." .$_,
1394 :     $userRecord->$_, $fieldProperties{$_});
1395 : malsyned 1233 } $userRecord->NONKEYFIELDS()),
1396 :     (map {
1397 : sh002i 1567 $self->fieldEditHTML(
1398 :     "permission." . $permissionLevel->user_id . "." . $_,
1399 :     $permissionLevel->$_, $fieldProperties{$_});
1400 : malsyned 1233 } $permissionLevel->NONKEYFIELDS()),
1401 : malsyned 1110 ])
1402 :     );
1403 :     }
1404 : malsyned 1214
1405 : sh002i 1567 unless (@userRecords) {
1406 :     print CGI::Tr({},
1407 :     CGI::td({-colspan=>scalar(@tableHeadings), -align=>"center"},
1408 :     "No users match the filter criteria above."
1409 :     ),
1410 :     );
1411 :     }
1412 :    
1413 : malsyned 1110 print CGI::end_table();
1414 : sh002i 1584
1415 :     if ($editMode) {
1416 :     print CGI::hidden(-name=>"selectUser", -value=>[ @userIDsForHiddenSelectField ]);
1417 :     if (defined $r->param("edit_visible")) {
1418 :     print CGI::hidden(-name=>"editingAllVisibleUsers", -value=>1);
1419 :     }
1420 :     }
1421 :    
1422 :     if ($editMode) {
1423 :     print CGI::submit({name=>"discard_chagnes", value=>"Discard Changes to Users"});
1424 :     print CGI::submit({name=>"save_classlist", value=>"Save Changes to Users"});
1425 :     } else {
1426 :     print CGI::submit({name=>"edit_visible", value=>"Edit Visible Users"});
1427 :     print CGI::submit({name=>"edit_selected", value=>"Edit Selected Users"});
1428 :     print CGI::submit({name=>"delete_selected", value=>"Delete Selected Users"});
1429 :     }
1430 :    
1431 : malsyned 1211 print CGI::end_form();
1432 : malsyned 1017
1433 : malsyned 1214 # Add a student form
1434 : sh002i 1584 unless ($editMode) {
1435 :     print CGI::start_form({method=>"post", action=>$r->uri()});
1436 :     print $self->hidden_authen_fields();
1437 :     print "User ID:";
1438 :     print CGI::input({type=>"text", name=>"newUserID", value=>"", size=>"20"});
1439 :     print CGI::submit({name=>"addStudent", value=>"Add User"});
1440 :     print CGI::end_form();
1441 :     }
1442 : malsyned 1214
1443 : malsyned 1014 return "";

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9