[system] / branches / gage_dev / webwork2 / lib / WeBWorK / ContentGenerator / Instructor / UserList.pm Repository:
ViewVC logotype

Annotation of /branches/gage_dev/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3690 - (view) (download) (as text)
Original Path: trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm

1 : sh002i 1567 ################################################################################
2 : sh002i 1663 # WeBWorK Online Homework Delivery System
3 :     # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4 : sh002i 3690 # $CVSHeader: webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm,v 1.72 2005/10/05 18:16:51 sh002i 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 : apizer 3287 Switch from view mode to password mode:
40 :     - showing visible users
41 :     - showing selected users
42 :     Switch from password mode to view and save changes
43 :     Switch from password mode to view and abandon changes
44 : sh002i 1594 Delete users:
45 :     - visible
46 :     - selected
47 :     Import users:
48 :     - replace:
49 :     - any users
50 :     - visible users
51 :     - selected users
52 :     - no users
53 :     - add:
54 :     - any users
55 :     - no users
56 :     Export users:
57 :     - export:
58 :     - all
59 :     - visible
60 :     - selected
61 :     - to:
62 :     - existing file on server (overwrite): [ list of files ]
63 :     - new file on server (create): [ filename ]
64 :    
65 :     =cut
66 :    
67 : malsyned 832 use strict;
68 :     use warnings;
69 :     use CGI qw();
70 : sh002i 2884 use WeBWorK::File::Classlist;
71 : gage 2137 use WeBWorK::Utils qw(readFile readDirectory cryptPassword);
72 : toenail 2355 use WeBWorK::Authen qw(checkKey);
73 : gage 1712 use Apache::Constants qw(:common REDIRECT DONE); #FIXME -- this should be called higher up in the object tree.
74 : apizer 3304 use constant HIDE_USERS_THRESHHOLD => 200;
75 : sh002i 1594 use constant EDIT_FORMS => [qw(cancelEdit saveEdit)];
76 : apizer 3287 use constant PASSWORD_FORMS => [qw(cancelPassword savePassword)];
77 :     use constant VIEW_FORMS => [qw(filter sort edit password import export add delete)];
78 : toenail 2355
79 :     # permissions needed to perform a given action
80 :     use constant FORM_PERMS => {
81 :     saveEdit => "modify_student_data",
82 :     edit => "modify_student_data",
83 : apizer 3287 savePassword => "change_password",
84 :     password => "change_password",
85 : toenail 2355 import => "modify_student_data",
86 :     export => "modify_classlist_files",
87 :     add => "modify_student_data",
88 :     delete => "modify_student_data",
89 :     };
90 :    
91 :     # permissions needed to view a given field
92 :     use constant FIELD_PERMS => {
93 :     act_as => "become_student",
94 :     sets => "assign_problem_sets",
95 :     };
96 :    
97 : apizer 3312 use constant STATE_PARAMS => [qw(user effectiveUser key visible_users no_visible_users prev_visible_users no_prev_visible_users editMode passwordMode primarySortField secondarySortField ternarySortField labelSortMethod)];
98 : sh002i 1567
99 : sh002i 1594 use constant SORT_SUBS => {
100 :     user_id => \&byUserID,
101 :     first_name => \&byFirstName,
102 :     last_name => \&byLastName,
103 :     email_address => \&byEmailAddress,
104 :     student_id => \&byStudentID,
105 :     status => \&byStatus,
106 :     section => \&bySection,
107 :     recitation => \&byRecitation,
108 :     comment => \&byComment,
109 : apizer 3299 permission => \&byPermission,
110 : sh002i 1594 };
111 :    
112 :     use constant FIELD_PROPERTIES => {
113 :     user_id => {
114 :     type => "text",
115 :     size => 8,
116 :     access => "readonly",
117 :     },
118 :     first_name => {
119 :     type => "text",
120 :     size => 10,
121 :     access => "readwrite",
122 :     },
123 :     last_name => {
124 :     type => "text",
125 :     size => 10,
126 :     access => "readwrite",
127 :     },
128 :     email_address => {
129 :     type => "text",
130 :     size => 20,
131 :     access => "readwrite",
132 :     },
133 :     student_id => {
134 :     type => "text",
135 :     size => 11,
136 :     access => "readwrite",
137 :     },
138 :     status => {
139 : sh002i 3690 #type => "enumerable",
140 :     type => "status",
141 : sh002i 1594 size => 4,
142 :     access => "readwrite",
143 : sh002i 3690 #items => {
144 :     # "C" => "Enrolled",
145 :     # "D" => "Drop",
146 :     # "A" => "Audit",
147 :     #},
148 :     #synonyms => {
149 :     # qr/^[ce]/i => "C",
150 :     # qr/^[dw]/i => "D",
151 :     # qr/^a/i => "A",
152 :     # "*" => "C",
153 :     #}
154 : sh002i 1594 },
155 :     section => {
156 :     type => "text",
157 :     size => 4,
158 :     access => "readwrite",
159 :     },
160 :     recitation => {
161 :     type => "text",
162 :     size => 4,
163 :     access => "readwrite",
164 :     },
165 :     comment => {
166 :     type => "text",
167 :     size => 20,
168 :     access => "readwrite",
169 :     },
170 :     permission => {
171 :     type => "number",
172 :     size => 2,
173 :     access => "readwrite",
174 :     }
175 :     };
176 : gage 1712 sub pre_header_initialize {
177 : gage 1928 my $self = shift;
178 :     my $r = $self->r;
179 :     my $urlpath = $r->urlpath;
180 : toenail 2355 my $authz = $r->authz;
181 : gage 1928 my $ce = $r->ce;
182 :     my $courseName = $urlpath->arg("courseID");
183 : toenail 2355 my $user = $r->param('user');
184 : gage 1712 # Handle redirects, if any.
185 :     ##############################
186 :     # Redirect to the addUser page
187 :     ##################################
188 : toenail 2355
189 :     # Check permissions
190 :     return unless $authz->hasPermissions($user, "access_instructor_tools");
191 : gage 1712
192 :     defined($r->param('action')) && $r->param('action') eq 'add' && do {
193 :     # fix url and redirect
194 :     my $root = $ce->{webworkURLs}->{root};
195 : gage 1928
196 : gage 1712 my $numberOfStudents = $r->param('number_of_students');
197 :     warn "number of students not defined " unless defined $numberOfStudents;
198 : sh002i 1594
199 : gage 2009 my $uri=$self->systemLink( $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::AddUsers',courseID=>$courseName),
200 :     params=>{
201 :     number_of_students=>$numberOfStudents,
202 :     }
203 : gage 1938 );
204 : gage 1712 #FIXME does the display mode need to be defined?
205 :     #FIXME url_authen_args also includes an effective user, so the new one must come first.
206 :     # even that might not work with every browser since there are two effective User assignments.
207 :     $r->header_out(Location => $uri);
208 :     $self->{noContent} = 1; # forces redirect
209 :     return;
210 :     };
211 :     }
212 :     # FIXME -- this should be moved up to instructor or contentgenerator
213 :     sub header {
214 :     my $self = shift;
215 :     return REDIRECT if $self->{noContent};
216 : gage 1928 my $r = $self->r;
217 : gage 1712 $r->content_type('text/html');
218 :     $r->send_http_header();
219 :     return OK;
220 :     }
221 : toenail 1799
222 :     #FIXME -- this should probably be moved up to instructor or contentgenerator as well
223 : sh002i 1973 #sub nbsp {
224 :     # my $str = shift;
225 :     # ($str =~/\S/) ? $str : ' ' ; # returns non-breaking space for empty strings
226 :     # # tricky cases: $str =0;
227 :     # # $str is a complex number
228 :     #}
229 :     # moved to ContentGenerator.pm
230 : toenail 1799
231 : malsyned 1015 sub initialize {
232 : malsyned 1211 my ($self) = @_;
233 : gage 1928 my $r = $self->r;
234 :     my $db = $r->db;
235 :     my $ce = $r->ce;
236 :     my $authz = $r->authz;
237 : gage 1712 my $user = $r->param('user');
238 : malsyned 1211
239 : toenail 2355 # Check permissions
240 :     return unless $authz->hasPermissions($user, "access_instructor_tools");
241 : malsyned 1211
242 : sh002i 1601 #if (defined($r->param('addStudent'))) {
243 :     # my $newUser = $db->newUser;
244 :     # my $newPermissionLevel = $db->newPermissionLevel;
245 :     # my $newPassword = $db->newPassword;
246 :     # $newUser->user_id($r->param('newUserID'));
247 :     # $newPermissionLevel->user_id($r->param('newUserID'));
248 :     # $newPassword->user_id($r->param('newUserID'));
249 :     # $newUser->status('C');
250 :     # $newPermissionLevel->permission(0);
251 :     # $db->addUser($newUser);
252 :     # $db->addPermissionLevel($newPermissionLevel);
253 :     # $db->addPassword($newPassword);
254 :     #}
255 : malsyned 1015 }
256 :    
257 : gage 1295
258 :    
259 : malsyned 1014 sub body {
260 : gage 1928 my ($self) = @_;
261 :     my $r = $self->r;
262 :     my $urlpath = $r->urlpath;
263 :     my $db = $r->db;
264 :     my $ce = $r->ce;
265 :     my $authz = $r->authz;
266 :     my $courseName = $urlpath->arg("courseID");
267 :     my $setID = $urlpath->arg("setID");
268 :     my $user = $r->param('user');
269 : sh002i 1584
270 : gage 1928 my $root = $ce->{webworkURLs}->{root};
271 :    
272 : sh002i 1594 # templates for getting field names
273 :     my $userTemplate = $self->{userTemplate} = $db->newUser;
274 :     my $permissionLevelTemplate = $self->{permissionLevelTemplate} = $db->newPermissionLevel;
275 :    
276 : toenail 2355 return CGI::div({class=>"ResultsWithError"}, CGI::p("You are not authorized to access the instructor tools."))
277 : sh002i 1567 unless $authz->hasPermissions($user, "access_instructor_tools");
278 : sh002i 1584
279 : malsyned 1214 # This table can be consulted when display-ready forms of field names are needed.
280 : sh002i 1594 my %prettyFieldNames = map { $_ => $_ }
281 :     $userTemplate->FIELDS(),
282 :     $permissionLevelTemplate->FIELDS();
283 : sh002i 1567
284 : malsyned 1214 @prettyFieldNames{qw(
285 :     user_id
286 :     first_name
287 :     last_name
288 :     email_address
289 :     student_id
290 :     status
291 :     section
292 :     recitation
293 :     comment
294 :     permission
295 :     )} = (
296 : apizer 3287 "Login Name",
297 : malsyned 1214 "First Name",
298 :     "Last Name",
299 : apizer 3302 "Email Address",
300 : malsyned 1214 "Student ID",
301 :     "Status",
302 :     "Section",
303 :     "Recitation",
304 :     "Comment",
305 : apizer 3299 "Permission Level"
306 : malsyned 1214 );
307 : sh002i 1567
308 : toenail 3060 $self->{prettyFieldNames} = \%prettyFieldNames;
309 : sh002i 1594 ########## set initial values for state fields
310 :    
311 :     my @allUserIDs = $db->listUsers;
312 : toenail 2355 $self->{totalSets} = $db->listGlobalSets; # save for use in "assigned sets" links
313 : sh002i 1594 $self->{allUserIDs} = \@allUserIDs;
314 :    
315 : apizer 3312 if (defined $r->param("visable_user_string")) {
316 :     my @visableUserIDs = split /:/, $r->param("visable_user_string");
317 :     $self->{visibleUserIDs} = [ @visableUserIDs ];
318 :     } elsif (defined $r->param("visible_users")) {
319 :     $self->{visibleUserIDs} = [ $r->param("visible_users") ];
320 : sh002i 1594 } elsif (defined $r->param("no_visible_users")) {
321 :     $self->{visibleUserIDs} = [];
322 :     } else {
323 : apizer 3304 if ((@allUserIDs > HIDE_USERS_THRESHHOLD) and (not defined $r->param("show_all_users") )) {
324 : sh002i 1597 $self->{visibleUserIDs} = [];
325 :     } else {
326 :     $self->{visibleUserIDs} = [ @allUserIDs ];
327 :     }
328 : sh002i 1594 }
329 :    
330 :     $self->{prevVisibleUserIDs} = $self->{visibleUserIDs};
331 :    
332 :     if (defined $r->param("selected_users")) {
333 :     $self->{selectedUserIDs} = [ $r->param("selected_users") ];
334 :     } else {
335 :     $self->{selectedUserIDs} = [];
336 :     }
337 :    
338 :     $self->{editMode} = $r->param("editMode") || 0;
339 : toenail 2355
340 :     return CGI::div({class=>"ResultsWithError"}, CGI::p("You are not authorized to modify student data"))
341 :     if $self->{editMode} and not $authz->hasPermissions($user, "modify_student_data");
342 :    
343 : apizer 3287
344 :     $self->{passwordMode} = $r->param("passwordMode") || 0;
345 :    
346 :     return CGI::div({class=>"ResultsWithError"}, CGI::p("You are not authorized to modify student data"))
347 :     if $self->{passwordMode} and not $authz->hasPermissions($user, "modify_student_data");
348 :    
349 : apizer 3302 if (defined $r->param("labelSortMethod")) {
350 :     $self->{primarySortField} = $r->param("labelSortMethod");
351 :     $self->{secondarySortField} = $r->param("primarySortField");
352 :     $self->{ternarySortField} = $r->param("secondarySortField");
353 :     }
354 :     else {
355 :     $self->{primarySortField} = $r->param("primarySortField") || "last_name";
356 :     $self->{secondarySortField} = $r->param("secondarySortField") || "first_name";
357 :     $self->{ternarySortField} = $r->param("ternarySortField") || "student_id";
358 :     }
359 : sh002i 1594
360 : sh002i 1601 my @allUsers = $db->getUsers(@allUserIDs);
361 :     my (%sections, %recitations);
362 :     foreach my $User (@allUsers) {
363 : sh002i 1973 push @{$sections{defined $User->section ? $User->section : ""}}, $User->user_id;
364 :     push @{$recitations{defined $User->recitation ? $User->recitation : ""}}, $User->user_id;
365 : sh002i 1601 }
366 :     $self->{sections} = \%sections;
367 :     $self->{recitations} = \%recitations;
368 :    
369 : sh002i 1594 ########## call action handler
370 :    
371 :     my $actionID = $r->param("action");
372 :     if ($actionID) {
373 : apizer 3287 unless (grep { $_ eq $actionID } @{ VIEW_FORMS() }, @{ EDIT_FORMS() }, @{ PASSWORD_FORMS() } ) {
374 : sh002i 1594 die "Action $actionID not found";
375 :     }
376 : toenail 2355 # Check permissions
377 :     if (not FORM_PERMS()->{$actionID} or $authz->hasPermissions($user, FORM_PERMS()->{$actionID})) {
378 :     my $actionHandler = "${actionID}_handler";
379 :     my %genericParams;
380 :     foreach my $param (qw(selected_users)) {
381 :     $genericParams{$param} = [ $r->param($param) ];
382 :     }
383 :     my %actionParams = $self->getActionParams($actionID);
384 :     my %tableParams = $self->getTableParams();
385 :     print CGI::p(
386 :     '<div style="color:green">',
387 :     "Result of last action performed: ",
388 :     CGI::i($self->$actionHandler(\%genericParams, \%actionParams, \%tableParams)),
389 :     '</div>',
390 :     CGI::hr()
391 :     );
392 :     } else {
393 :     return CGI::div({class=>"ResultsWithError"}, CGI::p("You are not authorized to perform this action."));
394 : sh002i 1594 }
395 :     }
396 :    
397 :     ########## retrieve possibly changed values for member fields
398 :    
399 :     #@allUserIDs = @{ $self->{allUserIDs} }; # do we need this one?
400 : jj 3563 @allUserIDs = $db->listUsers; # recompute value in case some were added
401 : sh002i 1594 my @visibleUserIDs = @{ $self->{visibleUserIDs} };
402 :     my @prevVisibleUserIDs = @{ $self->{prevVisibleUserIDs} };
403 :     my @selectedUserIDs = @{ $self->{selectedUserIDs} };
404 :     my $editMode = $self->{editMode};
405 : apizer 3287 my $passwordMode = $self->{passwordMode};
406 : toenail 3060 my $primarySortField = $self->{primarySortField};
407 :     my $secondarySortField = $self->{secondarySortField};
408 : apizer 3287 my $ternarySortField = $self->{ternarySortField};
409 : sh002i 1594
410 :     #warn "visibleUserIDs=@visibleUserIDs\n";
411 :     #warn "prevVisibleUserIDs=@prevVisibleUserIDs\n";
412 :     #warn "selectedUserIDs=@selectedUserIDs\n";
413 :     #warn "editMode=$editMode\n";
414 : apizer 3287 #warn "passwordMode=$passwordMode\n";
415 : apizer 3299 #warn "primarySortField=$primarySortField\n";
416 : apizer 3302 #warn "secondarySortField=$secondarySortField\n";
417 :     #warn "ternarySortField=$ternarySortField\n";
418 :    
419 : sh002i 1594 ########## get required users
420 : sh002i 1601
421 :     my @Users = grep { defined $_ } @visibleUserIDs ? $db->getUsers(@visibleUserIDs) : ();
422 : toenail 3060
423 :     my %sortSubs = %{ SORT_SUBS() };
424 :     my $primarySortSub = $sortSubs{$primarySortField};
425 : apizer 3287 my $secondarySortSub = $sortSubs{$secondarySortField};
426 :     my $ternarySortSub = $sortSubs{$ternarySortField};
427 : apizer 3299
428 :     # add permission level to user record hash so we can sort it if necessary
429 :     if ($primarySortField eq 'permission' or $secondarySortField eq 'permission' or $ternarySortField eq 'permission') {
430 :     foreach my $User (@Users) {
431 :     next unless $User;
432 :     my $permissionLevel = $db->getPermissionLevel($User->user_id);
433 :     $User->{permission} = $permissionLevel->permission;
434 :     }
435 :     }
436 : apizer 3287
437 : sh002i 1594
438 : apizer 3287 # # don't forget to sort in opposite order of importance
439 :     # @Users = sort $secondarySortSub @Users;
440 :     # @Users = sort $primarySortSub @Users;
441 :     # #@Users = sort byLnFnUid @Users;
442 :    
443 :     # Always have a definite sort order even if first three sorts don't determine things
444 :     @Users = sort {
445 :     &$primarySortSub
446 :     ||
447 :     &$secondarySortSub
448 :     ||
449 :     &$ternarySortSub
450 :     ||
451 :     byLastName
452 :     ||
453 :     byFirstName
454 :     ||
455 :     byUserID
456 :     }
457 :     @Users;
458 : sh002i 1594
459 :     my @PermissionLevels;
460 :    
461 :     for (my $i = 0; $i < @Users; $i++) {
462 :     my $User = $Users[$i];
463 : gage 1667 my $PermissionLevel = $db->getPermissionLevel($User->user_id); # checked
464 : sh002i 1594
465 :     unless ($PermissionLevel) {
466 :     # uh oh! no permission level record found!
467 :     warn "added missing permission level for user ", $User->user_id, "\n";
468 :    
469 :     # create a new permission level record
470 :     $PermissionLevel = $db->newPermissionLevel;
471 :     $PermissionLevel->user_id($User->user_id);
472 :     $PermissionLevel->permission(0);
473 :    
474 :     # add it to the database
475 :     $db->addPermissionLevel($PermissionLevel);
476 :     }
477 :    
478 :     $PermissionLevels[$i] = $PermissionLevel;
479 :     }
480 :    
481 :     ########## print beginning of form
482 :    
483 : gage 1938 print CGI::start_form({method=>"post", action=>$self->systemLink($urlpath,authen=>0), name=>"userlist"});
484 : sh002i 1594 print $self->hidden_authen_fields();
485 :    
486 :     ########## print state data
487 :    
488 :     print "\n<!-- state data here -->\n";
489 :    
490 :     if (@visibleUserIDs) {
491 : apizer 3312 print CGI::hidden(-name=>"visible_users", -value=>\@visibleUserIDs);
492 : sh002i 1594 } else {
493 :     print CGI::hidden(-name=>"no_visible_users", -value=>"1");
494 :     }
495 :    
496 :     if (@prevVisibleUserIDs) {
497 :     print CGI::hidden(-name=>"prev_visible_users", -value=>\@prevVisibleUserIDs);
498 :     } else {
499 :     print CGI::hidden(-name=>"no_prev_visible_users", -value=>"1");
500 :     }
501 :    
502 :     print CGI::hidden(-name=>"editMode", -value=>$editMode);
503 :    
504 : apizer 3287 print CGI::hidden(-name=>"passwordMode", -value=>$passwordMode);
505 :    
506 : toenail 3060 print CGI::hidden(-name=>"primarySortField", -value=>$primarySortField);
507 : apizer 3287 print CGI::hidden(-name=>"secondarySortField", -value=>$secondarySortField);
508 :     print CGI::hidden(-name=>"ternarySortField", -value=>$ternarySortField);
509 : sh002i 1594
510 :     print "\n<!-- state data here -->\n";
511 :    
512 :     ########## print action forms
513 :    
514 :     print CGI::start_table({});
515 :     print CGI::Tr({}, CGI::td({-colspan=>2}, "Select an action to perform:"));
516 :    
517 :     my @formsToShow;
518 :     if ($editMode) {
519 :     @formsToShow = @{ EDIT_FORMS() };
520 : apizer 3287 }elsif ($passwordMode) {
521 :     @formsToShow = @{ PASSWORD_FORMS() };
522 : sh002i 1594 } else {
523 :     @formsToShow = @{ VIEW_FORMS() };
524 :     }
525 :    
526 :     my $i = 0;
527 :     foreach my $actionID (@formsToShow) {
528 : toenail 2355 # Check permissions
529 :     next if FORM_PERMS()->{$actionID} and not $authz->hasPermissions($user, FORM_PERMS()->{$actionID});
530 : sh002i 1594 my $actionForm = "${actionID}_form";
531 :     my $onChange = "document.userlist.action[$i].checked=true";
532 :     my %actionParams = $self->getActionParams($actionID);
533 :    
534 :     print CGI::Tr({-valign=>"top"},
535 :     CGI::td({}, CGI::input({-type=>"radio", -name=>"action", -value=>$actionID})),
536 :     CGI::td({}, $self->$actionForm($onChange, %actionParams))
537 :     );
538 :    
539 :     $i++;
540 :     }
541 :    
542 :     print CGI::Tr({}, CGI::td({-colspan=>2, -align=>"center"},
543 :     CGI::submit(-value=>"Take Action!"))
544 :     );
545 :     print CGI::end_table();
546 :    
547 : sh002i 1597 ########## print table
548 :    
549 : toenail 2355 print CGI::p("Showing ", scalar @Users, " out of ", scalar @allUserIDs, " users.");
550 : sh002i 1597
551 : apizer 3287 print CGI::p("If a password field is left blank, the student's current password will be maintained.") if $passwordMode;
552 :    
553 : sh002i 1597 $self->printTableHTML(\@Users, \@PermissionLevels, \%prettyFieldNames,
554 :     editMode => $editMode,
555 : apizer 3287 passwordMode => $passwordMode,
556 : sh002i 1597 selectedUserIDs => \@selectedUserIDs,
557 : apizer 3302 primarySortField => $primarySortField,
558 :     secondarySortField => $secondarySortField,
559 :     visableUserIDs => \@visibleUserIDs,
560 : sh002i 1597 );
561 :    
562 :    
563 : sh002i 1594 ########## print end of form
564 :    
565 :     print CGI::end_form();
566 :    
567 :     return "";
568 :     }
569 :    
570 :     ################################################################################
571 :     # extract particular params and put them in a hash (values are ARRAYREFs!)
572 :     ################################################################################
573 :    
574 :     sub getActionParams {
575 :     my ($self, $actionID) = @_;
576 :     my $r = $self->{r};
577 :    
578 :     my %actionParams;
579 :     foreach my $param ($r->param) {
580 :     next unless $param =~ m/^action\.$actionID\./;
581 :     $actionParams{$param} = [ $r->param($param) ];
582 :     }
583 :     return %actionParams;
584 :     }
585 :    
586 :     sub getTableParams {
587 :     my ($self) = @_;
588 :     my $r = $self->{r};
589 :    
590 :     my %tableParams;
591 :     foreach my $param ($r->param) {
592 :     next unless $param =~ m/^(?:user|permission)\./;
593 :     $tableParams{$param} = [ $r->param($param) ];
594 :     }
595 :     return %tableParams;
596 :     }
597 :    
598 :     ################################################################################
599 :     # actions and action triggers
600 :     ################################################################################
601 :    
602 : sh002i 1597 # filter, edit, cancelEdit, and saveEdit should stay with the display module and
603 :     # not be real "actions". that way, all actions are shown in view mode and no
604 :     # actions are shown in edit mode.
605 :    
606 : sh002i 1594 sub filter_form {
607 :     my ($self, $onChange, %actionParams) = @_;
608 : sh002i 1601 #return CGI::table({}, CGI::Tr({-valign=>"top"},
609 :     # CGI::td({},
610 : toenail 3060
611 :     my %prettyFieldNames = %{ $self->{prettyFieldNames} };
612 :    
613 : sh002i 1601 return join("",
614 :     "Show ",
615 :     CGI::popup_menu(
616 :     -name => "action.filter.scope",
617 : toenail 3060 -values => [qw(all none selected match_regex)],
618 :     -default => $actionParams{"action.filter.scope"}->[0] || "match_regex",
619 : sh002i 1601 -labels => {
620 :     all => "all users",
621 :     none => "no users",
622 : apizer 3302 selected => "selected users",
623 : toenail 3060 # match_ids => "users with matching user IDs:",
624 :     match_regex => "users who match:",
625 :     # match_section => "users in selected section",
626 :     # match_recitation => "users in selected recitation",
627 : sh002i 1601 },
628 :     -onchange => $onChange,
629 :     ),
630 :     " ",
631 :     CGI::textfield(
632 :     -name => "action.filter.user_ids",
633 :     -value => $actionParams{"action.filter.user_ids"}->[0] || "",,
634 :     -width => "50",
635 :     -onchange => $onChange,
636 :     ),
637 : toenail 3060 # " (separate multiple IDs with commas)",
638 :     # CGI::br(),
639 :     # "sections: ",
640 :     # CGI::popup_menu(
641 :     # -name => "action.filter.section",
642 :     # -values => [ keys %{ $self->{sections} } ],
643 :     # -default => $actionParams{"action.filter.section"}->[0] || "",
644 :     # -labels => { $self->menuLabels($self->{sections}) },
645 :     # -onchange => $onChange,
646 :     # ),
647 :     # " recitations: ",
648 :     # CGI::popup_menu(
649 :     # -name => "action.filter.recitation",
650 :     # -values => [ keys %{ $self->{recitations} } ],
651 :     # -default => $actionParams{"action.filter.recitation"}->[0] || "",
652 :     # -labels => { $self->menuLabels($self->{recitations}) },
653 :     # -onchange => $onChange,
654 :     # ),
655 :     " in their ",
656 : sh002i 1601 CGI::popup_menu(
657 : toenail 3060 -name => "action.filter.field",
658 :     -value => [ keys %{ FIELD_PROPERTIES() } ],
659 :     -default => $actionParams{"action.filter.field"}->[0] || "user_id",
660 :     -labels => \%prettyFieldNames,
661 : sh002i 1601 -onchange => $onChange,
662 :     ),
663 : sh002i 1594 );
664 : sh002i 1601 # ),
665 :     #));
666 : sh002i 1594 }
667 :    
668 :     # this action handler modifies the "visibleUserIDs" field based on the contents
669 :     # of the "action.filter.scope" parameter and the "selected_users"
670 :     sub filter_handler {
671 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
672 :    
673 : toenail 3060 my $r = $self->r;
674 :     my $db = $r->db;
675 :    
676 : sh002i 1594 my $result;
677 :    
678 :     my $scope = $actionParams->{"action.filter.scope"}->[0];
679 :     if ($scope eq "all") {
680 :     $result = "showing all users";
681 :     $self->{visibleUserIDs} = $self->{allUserIDs};
682 :     } elsif ($scope eq "none") {
683 :     $result = "showing no users";
684 :     $self->{visibleUserIDs} = [];
685 :     } elsif ($scope eq "selected") {
686 :     $result = "showing selected users";
687 :     $self->{visibleUserIDs} = $genericParams->{selected_users}; # an arrayref
688 : toenail 3060 } elsif ($scope eq "match_regex") {
689 :     $result = "showing matching users";
690 :     my $regex = $actionParams->{"action.filter.user_ids"}->[0];
691 :     my $field = $actionParams->{"action.filter.field"}->[0];
692 :     my @userRecords = $db->getUsers(@{$self->{allUserIDs}});
693 :     my @userIDs;
694 :     foreach my $record (@userRecords) {
695 :     next unless $record;
696 : toenail 3089
697 :     # add permission level to user record hash so we can match it if necessary
698 :     if ($field eq "permission") {
699 :     my $permissionLevel = $db->getPermissionLevel($record->user_id);
700 :     $record->{permission} = $permissionLevel->permission;
701 :     }
702 : toenail 3060 push @userIDs, $record->user_id if $record->{$field} =~ /^$regex/i;
703 :     }
704 :     $self->{visibleUserIDs} = \@userIDs;
705 : sh002i 1601 } elsif ($scope eq "match_ids") {
706 :     my @userIDs = split /\s*,\s*/, $actionParams->{"action.filter.user_ids"}->[0];
707 :     $self->{visibleUserIDs} = \@userIDs;
708 :     } elsif ($scope eq "match_section") {
709 :     my $section = $actionParams->{"action.filter.section"}->[0];
710 : sh002i 1604 $self->{visibleUserIDs} = $self->{sections}->{$section}; # an arrayref
711 : sh002i 1601 } elsif ($scope eq "match_recitation") {
712 :     my $recitation = $actionParams->{"action.filter.recitation"}->[0];
713 : sh002i 1604 $self->{visibleUserIDs} = $self->{recitations}->{$recitation}; # an arrayref
714 : sh002i 1594 }
715 :    
716 :     return $result;
717 :     }
718 :    
719 : toenail 3060 sub sort_form {
720 :     my ($self, $onChange, %actionParams) = @_;
721 :     return join ("",
722 : apizer 3287 "Sort by ",
723 : toenail 3060 CGI::popup_menu(
724 :     -name => "action.sort.primary",
725 : apizer 3299 -values => [qw(user_id first_name last_name email_address student_id status section recitation comment permission)],
726 : toenail 3060 -default => $actionParams{"action.sort.primary"}->[0] || "last_name",
727 :     -labels => {
728 :     user_id => "Login Name",
729 :     first_name => "First Name",
730 :     last_name => "Last Name",
731 : apizer 3302 email_address => "Email Address",
732 : toenail 3060 student_id => "Student ID",
733 :     status => "Enrollment Status",
734 :     section => "Section",
735 :     recitation => "Recitation",
736 :     comment => "Comment",
737 : apizer 3299 permission => "Permission Level"
738 : toenail 3060 },
739 :     -onchange => $onChange,
740 :     ),
741 : apizer 3287 ", then by ",
742 : toenail 3060 CGI::popup_menu(
743 :     -name => "action.sort.secondary",
744 : apizer 3299 -values => [qw(user_id first_name last_name email_address student_id status section recitation comment permission)],
745 : toenail 3060 -default => $actionParams{"action.sort.secondary"}->[0] || "first_name",
746 :     -labels => {
747 :     user_id => "Login Name",
748 :     first_name => "First Name",
749 :     last_name => "Last Name",
750 : apizer 3302 email_address => "Email Address",
751 : toenail 3060 student_id => "Student ID",
752 :     status => "Enrollment Status",
753 :     section => "Section",
754 :     recitation => "Recitation",
755 :     comment => "Comment",
756 : apizer 3299 permission => "Permission Level"
757 : toenail 3060 },
758 :     -onchange => $onChange,
759 :     ),
760 : apizer 3287 ", then by ",
761 :     CGI::popup_menu(
762 :     -name => "action.sort.ternary",
763 : apizer 3299 -values => [qw(user_id first_name last_name email_address student_id status section recitation comment permission)],
764 : apizer 3287 -default => $actionParams{"action.sort.ternary"}->[0] || "user_id",
765 :     -labels => {
766 :     user_id => "Login Name",
767 :     first_name => "First Name",
768 :     last_name => "Last Name",
769 : apizer 3302 email_address => "Email Address",
770 : apizer 3287 student_id => "Student ID",
771 :     status => "Enrollment Status",
772 :     section => "Section",
773 :     recitation => "Recitation",
774 :     comment => "Comment",
775 : apizer 3299 permission => "Permission Level"
776 : apizer 3287 },
777 :     -onchange => $onChange,
778 :     ),
779 :    
780 : toenail 3060 ".",
781 :     );
782 :     }
783 :    
784 :     sub sort_handler {
785 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
786 :    
787 :     my $primary = $actionParams->{"action.sort.primary"}->[0];
788 :     my $secondary = $actionParams->{"action.sort.secondary"}->[0];
789 : apizer 3287 my $ternary = $actionParams->{"action.sort.ternary"}->[0];
790 : toenail 3060
791 :     $self->{primarySortField} = $primary;
792 :     $self->{secondarySortField} = $secondary;
793 : apizer 3287 $self->{ternarySortField} = $ternary;
794 : toenail 3060
795 :     my %names = (
796 :     user_id => "Login Name",
797 :     first_name => "First Name",
798 :     last_name => "Last Name",
799 : apizer 3302 email_address => "Email Address",
800 : toenail 3060 student_id => "Student ID",
801 :     status => "Enrollment Status",
802 :     section => "Section",
803 :     recitation => "Recitation",
804 :     comment => "Comment",
805 : apizer 3299 permission => "Permission Level"
806 : toenail 3060 );
807 :    
808 : apizer 3287 return "Users sorted by $names{$primary}, then by $names{$secondary}, then by $names{$ternary}.";
809 : toenail 3060 }
810 :    
811 : sh002i 1594 sub edit_form {
812 :     my ($self, $onChange, %actionParams) = @_;
813 : toenail 2355
814 : sh002i 1594 return join("",
815 :     "Edit ",
816 :     CGI::popup_menu(
817 :     -name => "action.edit.scope",
818 :     -values => [qw(all visible selected)],
819 : gage 1713 -default => $actionParams{"action.edit.scope"}->[0] || "selected",
820 : sh002i 1594 -labels => {
821 :     all => "all users",
822 :     visible => "visible users",
823 :     selected => "selected users"
824 :     },
825 :     -onchange => $onChange,
826 :     ),
827 :     );
828 :     }
829 :    
830 :     sub edit_handler {
831 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
832 : toenail 2355
833 : sh002i 1594 my $result;
834 :    
835 :     my $scope = $actionParams->{"action.edit.scope"}->[0];
836 :     if ($scope eq "all") {
837 :     $result = "editing all users";
838 :     $self->{visibleUserIDs} = $self->{allUserIDs};
839 :     } elsif ($scope eq "visible") {
840 :     $result = "editing visible users";
841 :     # leave visibleUserIDs alone
842 :     } elsif ($scope eq "selected") {
843 :     $result = "editing selected users";
844 :     $self->{visibleUserIDs} = $genericParams->{selected_users}; # an arrayref
845 :     }
846 :     $self->{editMode} = 1;
847 :    
848 :     return $result;
849 :     }
850 :    
851 : apizer 3287
852 :     sub password_form {
853 :     my ($self, $onChange, %actionParams) = @_;
854 :    
855 :     return join("",
856 :     "Give new password to ",
857 :     CGI::popup_menu(
858 :     -name => "action.password.scope",
859 :     -values => [qw(all visible selected)],
860 :     -default => $actionParams{"action.password.scope"}->[0] || "selected",
861 :     -labels => {
862 :     all => "all users",
863 :     visible => "visible users",
864 :     selected => "selected users"
865 :     },
866 :     -onchange => $onChange,
867 :     ),
868 :     );
869 :     }
870 :    
871 :     sub password_handler {
872 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
873 :    
874 :     my $result;
875 :    
876 :     my $scope = $actionParams->{"action.password.scope"}->[0];
877 :     if ($scope eq "all") {
878 :     $result = "giving new passwords to all users";
879 :     $self->{visibleUserIDs} = $self->{allUserIDs};
880 :     } elsif ($scope eq "visible") {
881 :     $result = "giving new passwords to visible users";
882 :     # leave visibleUserIDs alone
883 :     } elsif ($scope eq "selected") {
884 :     $result = "giving new passwords to selected users";
885 :     $self->{visibleUserIDs} = $genericParams->{selected_users}; # an arrayref
886 :     }
887 :     $self->{passwordMode} = 1;
888 :    
889 :     return $result;
890 :     }
891 :    
892 : sh002i 1594 sub delete_form {
893 :     my ($self, $onChange, %actionParams) = @_;
894 : toenail 2355
895 : sh002i 1594 return join("",
896 : toenail 2279 CGI::div({class=>"ResultsWithError"},
897 : sh002i 1594 "Delete ",
898 :     CGI::popup_menu(
899 :     -name => "action.delete.scope",
900 : toenail 2279 -values => [qw(none selected)],
901 : gage 1712 -default => $actionParams{"action.delete.scope"}->[0] || "none",
902 : sh002i 1594 -labels => {
903 : gage 1712 none => "no users.",
904 : sh002i 1782 #visible => "visible users.",
905 : gage 1712 selected => "selected users."
906 : sh002i 1594 },
907 :     -onchange => $onChange,
908 :     ),
909 : sh002i 1597 CGI::em(" Deletion destroys all user-related data and is not undoable!"),
910 : toenail 2279 ),
911 : sh002i 1594 );
912 :     }
913 :    
914 :     sub delete_handler {
915 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
916 : gage 1928 my $r = $self->r;
917 :     my $db = $r->db;
918 : toenail 2355 my $user = $r->param('user');
919 : sh002i 1594 my $scope = $actionParams->{"action.delete.scope"}->[0];
920 :    
921 : gage 1712 my @userIDsToDelete = ();
922 : sh002i 1782 #if ($scope eq "visible") {
923 :     # @userIDsToDelete = @{ $self->{visibleUserIDs} };
924 :     #} elsif ($scope eq "selected") {
925 :     if ($scope eq "selected") {
926 : sh002i 1594 @userIDsToDelete = @{ $self->{selectedUserIDs} };
927 :     }
928 :    
929 :     my %allUserIDs = map { $_ => 1 } @{ $self->{allUserIDs} };
930 :     my %visibleUserIDs = map { $_ => 1 } @{ $self->{visibleUserIDs} };
931 :     my %selectedUserIDs = map { $_ => 1 } @{ $self->{selectedUserIDs} };
932 :    
933 : toenail 2355 my $error = "";
934 :     my $num = 0;
935 : sh002i 1594 foreach my $userID (@userIDsToDelete) {
936 : toenail 2355 if ($user eq $userID) { # don't delete yourself!!
937 :     $error = "You cannot delete yourself!";
938 :     next;
939 :     }
940 : sh002i 1594 delete $allUserIDs{$userID};
941 :     delete $visibleUserIDs{$userID};
942 :     delete $selectedUserIDs{$userID};
943 :     $db->deleteUser($userID);
944 : toenail 2355 $num++;
945 : sh002i 1594 }
946 :    
947 :     $self->{allUserIDs} = [ keys %allUserIDs ];
948 :     $self->{visibleUserIDs} = [ keys %visibleUserIDs ];
949 :     $self->{selectedUserIDs} = [ keys %selectedUserIDs ];
950 :    
951 : toenail 2355 return "deleted $num user" . ($num == 1 ? "" : "s. ") . $error;
952 : sh002i 1594 }
953 : gage 1712 sub add_form {
954 :     my ($self, $onChange, %actionParams) = @_;
955 : sh002i 1594
956 : gage 1712 return "Add ", CGI::input({name=>'number_of_students', value=>1,size => 3}), " student(s). ";
957 :     }
958 :    
959 :     sub add_handler {
960 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
961 :     # This action is redirected to the addUser.pm module using ../instructor/add_user/...
962 :     return "Nothing done by add student handler";
963 :     }
964 : sh002i 1594 sub import_form {
965 :     my ($self, $onChange, %actionParams) = @_;
966 :     return join(" ",
967 :     "Import users from file",
968 :     CGI::popup_menu(
969 :     -name => "action.import.source",
970 : toenail 2285 -values => [ $self->getCSVList() ],
971 : sh002i 1594 -default => $actionParams{"action.import.source"}->[0] || "",
972 :     -onchange => $onChange,
973 : sh002i 1597 ),
974 : sh002i 1594 "replacing",
975 :     CGI::popup_menu(
976 :     -name => "action.import.replace",
977 :     -values => [qw(any visible selected none)],
978 :     -default => $actionParams{"action.import.replace"}->[0] || "none",
979 :     -labels => {
980 :     any => "any",
981 :     visible => "visible",
982 :     selected => "selected",
983 :     none => "no",
984 :     },
985 :     -onchange => $onChange,
986 :     ),
987 : sh002i 1597 "existing users and adding",
988 : sh002i 1594 CGI::popup_menu(
989 :     -name => "action.import.add",
990 :     -values => [qw(any none)],
991 :     -default => $actionParams{"action.import.add"}->[0] || "any",
992 :     -labels => {
993 :     any => "any",
994 :     none => "no",
995 :     },
996 :     -onchange => $onChange,
997 :     ),
998 :     "new users",
999 :     );
1000 :     }
1001 :    
1002 :     sub import_handler {
1003 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1004 :    
1005 :     my $source = $actionParams->{"action.import.source"}->[0];
1006 :     my $add = $actionParams->{"action.import.add"}->[0];
1007 :     my $replace = $actionParams->{"action.import.replace"}->[0];
1008 :    
1009 :     my $fileName = $source;
1010 :     my $createNew = $add eq "any";
1011 :     my $replaceExisting;
1012 :     my @replaceList;
1013 :     if ($replace eq "any") {
1014 :     $replaceExisting = "any";
1015 :     } elsif ($replace eq "none") {
1016 :     $replaceExisting = "none";
1017 :     } elsif ($replace eq "visible") {
1018 :     $replaceExisting = "listed";
1019 :     @replaceList = @{ $self->{visibleUserIDs} };
1020 :     } elsif ($replace eq "selected") {
1021 :     $replaceExisting = "listed";
1022 :     @replaceList = @{ $self->{selectedUserIDs} };
1023 :     }
1024 :    
1025 :     my ($replaced, $added, $skipped)
1026 :     = $self->importUsersFromCSV($fileName, $createNew, $replaceExisting, @replaceList);
1027 :    
1028 : sh002i 1597 # make new users visible... do we really want to do this? probably.
1029 :     push @{ $self->{visibleUserIDs} }, @$added;
1030 :    
1031 : sh002i 1594 my $numReplaced = @$replaced;
1032 :     my $numAdded = @$added;
1033 :     my $numSkipped = @$skipped;
1034 :    
1035 :     return $numReplaced . " user" . ($numReplaced == 1 ? "" : "s") . " replaced, "
1036 :     . $numAdded . " user" . ($numAdded == 1 ? "" : "s") . " added, "
1037 : toenail 3060 . $numSkipped . " user" . ($numSkipped == 1 ? "" : "s") . " skipped"
1038 :     . " (" . join (", ", @$skipped) . ") ";
1039 : sh002i 1594 }
1040 :    
1041 :     sub export_form {
1042 :     my ($self, $onChange, %actionParams) = @_;
1043 : sh002i 1597 return join("",
1044 :     "Export ",
1045 : sh002i 1594 CGI::popup_menu(
1046 :     -name => "action.export.scope",
1047 :     -values => [qw(all visible selected)],
1048 : sh002i 1597 -default => $actionParams{"action.export.scope"}->[0] || "visible",
1049 : sh002i 1594 -labels => {
1050 :     all => "all users",
1051 :     visible => "visible users",
1052 :     selected => "selected users"
1053 :     },
1054 :     -onchange => $onChange,
1055 :     ),
1056 : sh002i 1597 " to ",
1057 : sh002i 1594 CGI::popup_menu(
1058 : sh002i 1597 -name=>"action.export.target",
1059 :     -values => [ "new", $self->getCSVList() ],
1060 :     -labels => { new => "a new file named:" },
1061 :     -default => $actionParams{"action.export.target"}->[0] || "",
1062 : sh002i 1594 -onchange => $onChange,
1063 : sh002i 1597 ),
1064 :     #CGI::br(),
1065 :     #"new file to create: ",
1066 : sh002i 1594 CGI::textfield(
1067 : sh002i 1597 -name => "action.export.new",
1068 :     -value => $actionParams{"action.export.new"}->[0] || "",,
1069 :     -width => "50",
1070 :     -onchange => $onChange,
1071 : sh002i 1594 ),
1072 : sh002i 1597 CGI::tt(".lst"),
1073 : sh002i 1594 );
1074 :     }
1075 :    
1076 : sh002i 1597 sub export_handler {
1077 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1078 : apizer 3303 my $r = $self->r;
1079 :     my $ce = $r->ce;
1080 :     my $dir = $ce->{courseDirs}->{templates};
1081 : sh002i 1597
1082 :     my $scope = $actionParams->{"action.export.scope"}->[0];
1083 :     my $target = $actionParams->{"action.export.target"}->[0];
1084 :     my $new = $actionParams->{"action.export.new"}->[0];
1085 :    
1086 : apizer 3303 #get name of templates directory as it appears in file manager
1087 :     $dir =~ s|.*/||;
1088 :    
1089 : sh002i 1597 my $fileName;
1090 :     if ($target eq "new") {
1091 :     $fileName = $new;
1092 :     } else {
1093 :     $fileName = $target;
1094 :     }
1095 :    
1096 :     $fileName .= ".lst" unless $fileName =~ m/\.lst$/;
1097 :    
1098 :     my @userIDsToExport;
1099 :     if ($scope eq "all") {
1100 :     @userIDsToExport = @{ $self->{allUserIDs} };
1101 :     } elsif ($scope eq "visible") {
1102 :     @userIDsToExport = @{ $self->{visibleUserIDs} };
1103 :     } elsif ($scope eq "selected") {
1104 :     @userIDsToExport = @{ $self->{selectedUserIDs} };
1105 :     }
1106 :    
1107 :     $self->exportUsersToCSV($fileName, @userIDsToExport);
1108 :    
1109 : apizer 3303 return scalar @userIDsToExport . " users exported to file &nbsp;&nbsp; $dir/$fileName";
1110 : sh002i 1597 }
1111 :    
1112 : sh002i 1594 sub cancelEdit_form {
1113 :     my ($self, $onChange, %actionParams) = @_;
1114 :     return "Abandon changes";
1115 :     }
1116 :    
1117 :     sub cancelEdit_handler {
1118 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1119 : gage 1928 my $r = $self->r;
1120 : sh002i 1594
1121 :     #$self->{selectedUserIDs} = $self->{visibleUserIDs};
1122 :     # only do the above if we arrived here via "edit selected users"
1123 :     if (defined $r->param("prev_visible_users")) {
1124 :     $self->{visibleUserIDs} = [ $r->param("prev_visible_users") ];
1125 :     } elsif (defined $r->param("no_prev_visible_users")) {
1126 :     $self->{visibleUserIDs} = [];
1127 :     } else {
1128 :     # leave it alone
1129 :     }
1130 :     $self->{editMode} = 0;
1131 :    
1132 :     return "changes abandoned";
1133 :     }
1134 :    
1135 :     sub saveEdit_form {
1136 :     my ($self, $onChange, %actionParams) = @_;
1137 :     return "Save changes";
1138 :     }
1139 :    
1140 :     sub saveEdit_handler {
1141 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1142 : gage 1928 my $r = $self->r;
1143 :     my $db = $r->db;
1144 : sh002i 1594
1145 :     my @visibleUserIDs = @{ $self->{visibleUserIDs} };
1146 :     foreach my $userID (@visibleUserIDs) {
1147 : gage 1667 my $User = $db->getUser($userID); # checked
1148 :     die "record for visible user $userID not found" unless $User;
1149 :     my $PermissionLevel = $db->getPermissionLevel($userID); # checked
1150 :     die "permissions for $userID not defined" unless defined $PermissionLevel;
1151 : sh002i 1594 foreach my $field ($User->NONKEYFIELDS()) {
1152 :     my $param = "user.${userID}.${field}";
1153 :     if (defined $tableParams->{$param}->[0]) {
1154 :     $User->$field($tableParams->{$param}->[0]);
1155 : malsyned 1233 }
1156 :     }
1157 : sh002i 1594
1158 :     foreach my $field ($PermissionLevel->NONKEYFIELDS()) {
1159 :     my $param = "permission.${userID}.${field}";
1160 :     if (defined $tableParams->{$param}->[0]) {
1161 :     $PermissionLevel->$field($tableParams->{$param}->[0]);
1162 :     }
1163 :     }
1164 :    
1165 :     $db->putUser($User);
1166 :     $db->putPermissionLevel($PermissionLevel);
1167 :     }
1168 :    
1169 :     if (defined $r->param("prev_visible_users")) {
1170 :     $self->{visibleUserIDs} = [ $r->param("prev_visible_users") ];
1171 :     } elsif (defined $r->param("no_prev_visible_users")) {
1172 :     $self->{visibleUserIDs} = [];
1173 :     } else {
1174 :     # leave it alone
1175 :     }
1176 :    
1177 :     $self->{editMode} = 0;
1178 :    
1179 :     return "changes saved";
1180 :     }
1181 :    
1182 : apizer 3287 sub cancelPassword_form {
1183 :     my ($self, $onChange, %actionParams) = @_;
1184 :     return "Abandon changes";
1185 :     }
1186 :    
1187 :     sub cancelPassword_handler {
1188 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1189 :     my $r = $self->r;
1190 :    
1191 :     #$self->{selectedUserIDs} = $self->{visibleUserIDs};
1192 :     # only do the above if we arrived here via "edit selected users"
1193 :     if (defined $r->param("prev_visible_users")) {
1194 :     $self->{visibleUserIDs} = [ $r->param("prev_visible_users") ];
1195 :     } elsif (defined $r->param("no_prev_visible_users")) {
1196 :     $self->{visibleUserIDs} = [];
1197 :     } else {
1198 :     # leave it alone
1199 :     }
1200 :     $self->{passwordMode} = 0;
1201 :    
1202 :     return "changes abandoned";
1203 :     }
1204 :    
1205 :     sub savePassword_form {
1206 :     my ($self, $onChange, %actionParams) = @_;
1207 :     return "Save changes";
1208 :     }
1209 :    
1210 :     sub savePassword_handler {
1211 :     my ($self, $genericParams, $actionParams, $tableParams) = @_;
1212 :     my $r = $self->r;
1213 :     my $db = $r->db;
1214 :    
1215 :     my @visibleUserIDs = @{ $self->{visibleUserIDs} };
1216 :     foreach my $userID (@visibleUserIDs) {
1217 :     my $User = $db->getUser($userID); # checked
1218 :     die "record for visible user $userID not found" unless $User;
1219 :     my $param = "user.${userID}.new_password";
1220 :     if ((defined $tableParams->{$param}->[0]) and ($tableParams->{$param}->[0])) {
1221 :     my $newP = $tableParams->{$param}->[0];
1222 :     my $Password = eval {$db->getPassword($User->user_id)}; # checked
1223 :     my $cryptPassword = cryptPassword($newP);
1224 :     $Password->password(cryptPassword($newP));
1225 :     eval { $db->putPassword($Password) };
1226 :     }
1227 :     }
1228 :    
1229 :     if (defined $r->param("prev_visible_users")) {
1230 :     $self->{visibleUserIDs} = [ $r->param("prev_visible_users") ];
1231 :     } elsif (defined $r->param("no_prev_visible_users")) {
1232 :     $self->{visibleUserIDs} = [];
1233 :     } else {
1234 :     # leave it alone
1235 :     }
1236 :    
1237 :     $self->{passwordMode} = 0;
1238 :    
1239 :     return "new passwords saved";
1240 :     }
1241 :    
1242 :    
1243 : sh002i 1594 ################################################################################
1244 :     # sorts
1245 :     ################################################################################
1246 :    
1247 : sh002i 2845 sub byUserID { lc $a->user_id cmp lc $b->user_id }
1248 : toenail 3060 sub byFirstName { (defined $a->first_name && defined $b->first_name) ? lc $a->first_name cmp lc $b->first_name : 0; }
1249 :     sub byLastName { (defined $a->last_name && defined $b->last_name ) ? lc $a->last_name cmp lc $b->last_name : 0; }
1250 : sh002i 2845 sub byEmailAddress { lc $a->email_address cmp lc $b->email_address }
1251 :     sub byStudentID { lc $a->student_id cmp lc $b->student_id }
1252 :     sub byStatus { lc $a->status cmp lc $b->status }
1253 :     sub bySection { lc $a->section cmp lc $b->section }
1254 :     sub byRecitation { lc $a->recitation cmp lc $b->recitation }
1255 :     sub byComment { lc $a->comment cmp lc $b->comment }
1256 : apizer 3299 sub byPermission { $a->{permission} <=> $b->{permission} } ## permission level is added to user record hash so we can sort it if necessary
1257 : sh002i 1594
1258 : apizer 3287 # sub byLnFnUid { &byLastName || &byFirstName || &byUserID }
1259 : sh002i 1594
1260 :     ################################################################################
1261 :     # utilities
1262 :     ################################################################################
1263 :    
1264 :     # generate labels for section/recitation popup menus
1265 :     sub menuLabels {
1266 :     my ($self, $hashRef) = @_;
1267 :     my %hash = %$hashRef;
1268 :    
1269 :     my %result;
1270 :     foreach my $key (keys %hash) {
1271 :     my $count = @{ $hash{$key} };
1272 :     my $displayKey = $key || "<none>";
1273 :     $result{$key} = "$displayKey ($count users)";
1274 :     }
1275 :     return %result;
1276 :     }
1277 :    
1278 :     sub importUsersFromCSV {
1279 :     my ($self, $fileName, $createNew, $replaceExisting, @replaceList) = @_;
1280 : gage 1928 my $r = $self->r;
1281 :     my $ce = $r->ce;
1282 :     my $db = $r->db;
1283 :     my $dir = $ce->{courseDirs}->{templates};
1284 : toenail 2355 my $user = $r->param('user');
1285 : sh002i 1594
1286 : sh002i 2884 die "illegal character in input: '/'" if $fileName =~ m|/|;
1287 : sh002i 1594 die "won't be able to read from file $dir/$fileName: does it exist? is it readable?"
1288 :     unless -r "$dir/$fileName";
1289 :    
1290 :     my %allUserIDs = map { $_ => 1 } @{ $self->{allUserIDs} };
1291 :     my %replaceOK;
1292 :     if ($replaceExisting eq "none") {
1293 :     %replaceOK = ();
1294 :     } elsif ($replaceExisting eq "listed") {
1295 :     %replaceOK = map { $_ => 1 } @replaceList;
1296 :     } elsif ($replaceExisting eq "any") {
1297 :     %replaceOK = %allUserIDs;
1298 :     }
1299 :    
1300 :     my (@replaced, @added, @skipped);
1301 :    
1302 : sh002i 2884 # get list of hashrefs representing lines in classlist file
1303 :     my @classlist = parse_classlist("$dir/$fileName");
1304 :    
1305 :     foreach my $record (@classlist) {
1306 :     my %record = %$record;
1307 :     my $user_id = $record{user_id};
1308 : sh002i 1594
1309 : toenail 2355 if ($user_id eq $user) { # don't replace yourself!!
1310 :     push @skipped, $user_id;
1311 :     next;
1312 :     }
1313 :    
1314 : sh002i 1594 if (exists $allUserIDs{$user_id} and not exists $replaceOK{$user_id}) {
1315 :     push @skipped, $user_id;
1316 :     next;
1317 :     }
1318 :    
1319 :     if (not exists $allUserIDs{$user_id} and not $createNew) {
1320 :     push @skipped, $user_id;
1321 :     next;
1322 :     }
1323 :    
1324 : sh002i 2884 my $User = $db->newUser(%record);
1325 :     my $PermissionLevel = $db->newPermissionLevel(user_id => $user_id, permission => 0);
1326 :     my $Password = $db->newPassword(user_id => $user_id, password => cryptPassword($record{student_id}));
1327 : sh002i 1594
1328 : sh002i 2890 # use password and permission from record if there
1329 :     if (exists $record{permission}) {
1330 :     $PermissionLevel->permission($record{permission});
1331 :     }
1332 :    
1333 :     if (exists $record{password}) {
1334 :     $Password->password($record{password});
1335 :     }
1336 :    
1337 : sh002i 1594 if (exists $allUserIDs{$user_id}) {
1338 :     $db->putUser($User);
1339 :     $db->putPermissionLevel($PermissionLevel);
1340 :     $db->putPassword($Password);
1341 :     push @replaced, $user_id;
1342 :     } else {
1343 :     $db->addUser($User);
1344 :     $db->addPermissionLevel($PermissionLevel);
1345 :     $db->addPassword($Password);
1346 :     push @added, $user_id;
1347 :     }
1348 :     }
1349 :    
1350 :     return \@replaced, \@added, \@skipped;
1351 :     }
1352 :    
1353 : sh002i 1597 sub exportUsersToCSV {
1354 :     my ($self, $fileName, @userIDsToExport) = @_;
1355 : gage 1928 my $r = $self->r;
1356 :     my $ce = $r->ce;
1357 :     my $db = $r->db;
1358 :     my $dir = $ce->{courseDirs}->{templates};
1359 : sh002i 1597
1360 : sh002i 2884 die "illegal character in input: '/'" if $fileName =~ m|/|;
1361 : sh002i 1597
1362 : sh002i 2890 my @records;
1363 : sh002i 1597
1364 : sh002i 2890 my @Users = $db->getUsers(@userIDsToExport);
1365 :     my @Passwords = $db->getPasswords(@userIDsToExport);
1366 :     my @PermissionLevels = $db->getPermissionLevels(@userIDsToExport);
1367 :     foreach my $i (0 .. $#userIDsToExport) {
1368 :     my $User = $Users[$i];
1369 :     my $Password = $Passwords[$i];
1370 :     my $PermissionLevel = $PermissionLevels[$i];
1371 :     next unless defined $User;
1372 :     my %record = (
1373 :     defined $PermissionLevel ? $PermissionLevel->toHash : (),
1374 :     defined $Password ? $Password->toHash : (),
1375 :     $User->toHash,
1376 :     );
1377 :     push @records, \%record;
1378 :     }
1379 :    
1380 : sh002i 2884 write_classlist("$dir/$fileName", @records);
1381 : sh002i 1597 }
1382 :    
1383 : sh002i 1594 ################################################################################
1384 :     # "display" methods
1385 :     ################################################################################
1386 :    
1387 :     sub fieldEditHTML {
1388 :     my ($self, $fieldName, $value, $properties) = @_;
1389 : sh002i 3690 my $ce = $self->r->ce;
1390 : sh002i 1594 my $size = $properties->{size};
1391 :     my $type = $properties->{type};
1392 :     my $access = $properties->{access};
1393 :     my $items = $properties->{items};
1394 :     my $synonyms = $properties->{synonyms};
1395 :    
1396 : apizer 3660 if ($type eq "email") {
1397 :     if ($value eq '&nbsp;') {
1398 :     return $value;}
1399 :     else {
1400 :     return CGI::a({-href=>"mailto:$value"},$value);
1401 :     }
1402 :     }
1403 :    
1404 : sh002i 1594 if ($access eq "readonly") {
1405 : sh002i 3690 # hack for status
1406 :     if ($type eq "status") {
1407 :     my $status_name = $ce->status_abbrev_to_name($value);
1408 :     if (defined $status_name) {
1409 :     $value = "$status_name ($value)";
1410 :     }
1411 :     }
1412 : sh002i 1594 return $value;
1413 :     }
1414 :    
1415 :     if ($type eq "number" or $type eq "text") {
1416 :     return CGI::input({type=>"text", name=>$fieldName, value=>$value, size=>$size});
1417 :     }
1418 : apizer 3660
1419 : sh002i 1594 if ($type eq "enumerable") {
1420 :     my $matched = undef; # Whether a synonym match has occurred
1421 :    
1422 :     # Process synonyms for enumerable objects
1423 :     foreach my $synonym (keys %$synonyms) {
1424 :     if ($synonym ne "*" and $value =~ m/$synonym/) {
1425 :     $value = $synonyms->{$synonym};
1426 :     $matched = 1;
1427 :     }
1428 :     }
1429 :    
1430 :     if (!$matched and exists $synonyms->{"*"}) {
1431 :     $value = $synonyms->{"*"};
1432 :     }
1433 :    
1434 :     return CGI::popup_menu({
1435 :     name => $fieldName,
1436 :     values => [keys %$items],
1437 :     default => $value,
1438 :     labels => $items,
1439 :     });
1440 :     }
1441 : sh002i 3690
1442 :     if ($type eq "status") {
1443 :     # we used to surreptitously map synonyms to a canonical value...
1444 :     # so should we continue to do that?
1445 :     my $status_name = $ce->status_abbrev_to_name($value);
1446 :     if (defined $status_name) {
1447 :     $value = ($ce->status_name_to_abbrevs($status_name))[0];
1448 :     }
1449 :    
1450 :     my (@values, %labels);
1451 :     while (my ($k, $v) = each %{$ce->{statuses}}) {
1452 :     my @abbrevs = @{$v->{abbrevs}};
1453 :     push @values, $abbrevs[0];
1454 :     foreach my $abbrev (@abbrevs) {
1455 :     $labels{$abbrev} = $k;
1456 :     }
1457 :     }
1458 :    
1459 :     return CGI::popup_menu({
1460 :     name => $fieldName,
1461 :     values => \@values,
1462 :     default => $value,
1463 :     labels => \%labels,
1464 :     });
1465 :     }
1466 : sh002i 1594 }
1467 :    
1468 :     sub recordEditHTML {
1469 :     my ($self, $User, $PermissionLevel, %options) = @_;
1470 : gage 1928 my $r = $self->r;
1471 :     my $urlpath = $r->urlpath;
1472 : toenail 2355 my $db = $r->db;
1473 : gage 1928 my $ce = $r->ce;
1474 : toenail 2355 my $authz = $r->authz;
1475 :     my $user = $r->param('user');
1476 : gage 1928 my $root = $ce->{webworkURLs}->{root};
1477 :     my $courseName = $urlpath->arg("courseID");
1478 : sh002i 1594
1479 :     my $editMode = $options{editMode};
1480 : apizer 3287 my $passwordMode = $options{passwordMode};
1481 : sh002i 1594 my $userSelected = $options{userSelected};
1482 : toenail 2109
1483 : sh002i 3688 my $statusClass = $ce->status_abbrev_to_name($User->status);
1484 : toenail 2355
1485 :     my $sets = $db->countUserSets($User->user_id);
1486 :     my $totalSets = $self->{totalSets};
1487 : sh002i 1594
1488 : gage 1938 my $changeEUserURL = $self->systemLink($urlpath->new(type=>'set_list',args=>{courseID=>$courseName}),
1489 :     params => {effectiveUser => $User->user_id}
1490 :     );
1491 : sh002i 1594
1492 : gage 1938 my $setsAssignedToUserURL = $self->systemLink($urlpath->new(type=>'instructor_sets_assigned_to_user',
1493 :     args=>{courseID => $courseName,
1494 :     userID => $User->user_id
1495 :     }),
1496 :     params => {effectiveUser => $User->user_id}
1497 :     );
1498 : toenail 2285
1499 : apizer 3312 my $userListURL = $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName} )) . "&editMode=1&visible_users=" . $User->user_id;
1500 : toenail 2285
1501 :     my $imageURL = $ce->{webworkURLs}->{htdocs}."/images/edit.gif";
1502 :     my $imageLink = CGI::a({href => $userListURL}, CGI::img({src=>$imageURL, border=>0}));
1503 : sh002i 1640
1504 : sh002i 1594 my @tableCells;
1505 :    
1506 :     # Select
1507 : apizer 3287 if ($editMode or $passwordMode) {
1508 : sh002i 1594 # column not there
1509 :     } else {
1510 :     # selection checkbox
1511 :     push @tableCells, CGI::checkbox(
1512 :     -name => "selected_users",
1513 :     -value => $User->user_id,
1514 :     -checked => $userSelected,
1515 :     -label => "",
1516 :     );
1517 :     }
1518 :    
1519 : sh002i 1640 # Act As
1520 : apizer 3287 if ($editMode or $passwordMode) {
1521 : sh002i 1640 # column not there
1522 :     } else {
1523 :     # selection checkbox
1524 : toenail 2355 if ( FIELD_PERMS()->{act_as} and not $authz->hasPermissions($user, FIELD_PERMS()->{act_as}) ){
1525 :     push @tableCells, $User->user_id . $imageLink;
1526 :     } else {
1527 :     push @tableCells, CGI::a({href=>$changeEUserURL}, $User->user_id) . $imageLink;
1528 :     }
1529 : sh002i 1640 }
1530 :    
1531 : toenail 2355 # Login Status
1532 : apizer 3287 if ($editMode or $passwordMode) {
1533 : toenail 2355 # column not there
1534 :     } else {
1535 :     # check to see if a user is currently logged in
1536 :     my $Key = $db->getKey($User->user_id);
1537 :     push @tableCells, ($Key and WeBWorK::Authen::checkKey($self, $User->user_id, $Key->key)) ? CGI::b("active") : CGI::em("inactive");
1538 :     }
1539 :    
1540 : apizer 3287 # change password (only in password mode)
1541 :     if ($passwordMode) {
1542 :     if ($User->user_id eq $user) {
1543 :     push @tableCells, '' # don't allow a professor to change their own password from this form
1544 :     }
1545 :     else {
1546 :     my $fieldName = 'user.' . $User->user_id . '.' . 'new_password';
1547 :     push @tableCells, CGI::input({type=>"text", name=>$fieldName, size=>14});;
1548 :     }
1549 :     }
1550 : jj 2961 # User ID (edit mode) or Assigned Sets (otherwise)
1551 : apizer 3287 if ($editMode or $passwordMode) {
1552 : sh002i 1594 # straight user ID
1553 : toenail 2109 push @tableCells, CGI::div({class=>$statusClass}, $User->user_id);
1554 : sh002i 1594 } else {
1555 : sh002i 1640 # "edit sets assigned to user" link
1556 : toenail 2355 #push @tableCells, CGI::a({href=>$setsAssignedToUserURL}, "Edit sets");
1557 :     if ( FIELD_PERMS()->{sets} and not $authz->hasPermissions($user, FIELD_PERMS()->{sets}) ) {
1558 :     push @tableCells, "$sets/$totalSets";
1559 :     } else {
1560 :     push @tableCells, CGI::a({href=>$setsAssignedToUserURL}, "$sets/$totalSets");
1561 :     }
1562 : sh002i 1594 }
1563 : toenail 2109
1564 : sh002i 1594 # User Fields
1565 :     foreach my $field ($User->NONKEYFIELDS) {
1566 : apizer 3660 my $fieldName = 'user.' . $User->user_id . '.' . $field,
1567 : sh002i 1594 my $fieldValue = $User->$field;
1568 :     my %properties = %{ FIELD_PROPERTIES()->{$field} };
1569 : apizer 3660 $properties{access} = 'readonly' unless $editMode;
1570 :     $properties{type} = 'email' if ($field eq 'email_address' and !$editMode and !$passwordMode);
1571 : sh002i 1973 $fieldValue = $self->nbsp($fieldValue) unless $editMode;
1572 : toenail 2109 push @tableCells, CGI::div({class=>$statusClass}, $self->fieldEditHTML($fieldName, $fieldValue, \%properties));
1573 : sh002i 1594 }
1574 :    
1575 :     # PermissionLevel Fields
1576 :     foreach my $field ($PermissionLevel->NONKEYFIELDS) {
1577 : apizer 3660 my $fieldName = 'permission.' . $PermissionLevel->user_id . '.' . $field,
1578 : sh002i 1594 my $fieldValue = $PermissionLevel->$field;
1579 :     my %properties = %{ FIELD_PROPERTIES()->{$field} };
1580 : apizer 3660 $properties{access} = 'readonly' unless $editMode;
1581 : sh002i 1973 $fieldValue = $self->nbsp($fieldValue) unless $editMode;
1582 : toenail 2109 push @tableCells, CGI::div({class=>$statusClass}, $self->fieldEditHTML($fieldName, $fieldValue, \%properties));
1583 : sh002i 1594 }
1584 :    
1585 : toenail 2285 return CGI::Tr({}, CGI::td({nowrap=>1}, \@tableCells));
1586 : sh002i 1594 }
1587 :    
1588 :     sub printTableHTML {
1589 :     my ($self, $UsersRef, $PermissionLevelsRef, $fieldNamesRef, %options) = @_;
1590 : gage 1928 my $r = $self->r;
1591 : apizer 3302 my $urlpath = $r->urlpath;
1592 :     my $courseName = $urlpath->arg("courseID");
1593 : gage 1928 my $userTemplate = $self->{userTemplate};
1594 : sh002i 1594 my $permissionLevelTemplate = $self->{permissionLevelTemplate};
1595 : gage 1928 my @Users = @$UsersRef;
1596 :     my @PermissionLevels = @$PermissionLevelsRef;
1597 :     my %fieldNames = %$fieldNamesRef;
1598 : sh002i 1594
1599 : gage 1928 my $editMode = $options{editMode};
1600 : apizer 3287 my $passwordMode = $options{passwordMode};
1601 : gage 1928 my %selectedUserIDs = map { $_ => 1 } @{ $options{selectedUserIDs} };
1602 : apizer 3299 # my $currentSort = $options{currentSort};
1603 : apizer 3302 my $primarySortField = $options{primarySortField};
1604 :     my $secondarySortField = $options{secondarySortField};
1605 :     my @visableUserIDs = @{ $options{visableUserIDs} };
1606 :    
1607 : sh002i 1594 # names of headings:
1608 :     my @realFieldNames = (
1609 :     $userTemplate->KEYFIELDS,
1610 :     $userTemplate->NONKEYFIELDS,
1611 :     $permissionLevelTemplate->NONKEYFIELDS,
1612 : malsyned 1233 );
1613 :    
1614 : apizer 3299 # my %sortSubs = %{ SORT_SUBS() };
1615 : sh002i 1594 #my @stateParams = @{ STATE_PARAMS() };
1616 :     #my $hrefPrefix = $r->uri . "?" . $self->url_args(@stateParams); # $self->url_authen_args
1617 :     my @tableHeadings;
1618 :     foreach my $field (@realFieldNames) {
1619 : gage 1938 my $result = $fieldNames{$field};
1620 : sh002i 1594 push @tableHeadings, $result;
1621 :     };
1622 :    
1623 :     # prepend selection checkbox? only if we're NOT editing!
1624 : apizer 3287 unless($editMode or $passwordMode) {
1625 : apizer 3302
1626 : apizer 3312 #warn "line 1582 visibleUserIDs=@visableUserIDs \n";
1627 : apizer 3302 my %current_state =();
1628 : apizer 3304 if (@visableUserIDs) {
1629 :     # This is a hack to get around: Maximum URL Length Is 2,083 Characters in Internet Explorer.
1630 : apizer 3312 # Without passing visable users the URL is about 250 characters. If the total URL is under the limit
1631 : apizer 3304 # we will pass visable users. If it is over, we will not pass any and all users will be displayed.
1632 : apizer 3312 # Maybe we should replace the GET method by POST (but this doesn't look good) --- AKP
1633 : apizer 3304
1634 : apizer 3312 my $visableUserIDsString = join ':', @visableUserIDs;
1635 :     if (length($visableUserIDsString) < 1830) {
1636 : apizer 3304 %current_state = (
1637 :     primarySortField => "$primarySortField",
1638 :     secondarySortField => "$secondarySortField",
1639 : apizer 3312 visable_user_string => "$visableUserIDsString"
1640 : apizer 3304 );
1641 :     } else {
1642 :     %current_state = (
1643 :     primarySortField => "$primarySortField",
1644 :     secondarySortField => "$secondarySortField",
1645 :     show_all_users => "1"
1646 :     );
1647 :     }
1648 :     } else {
1649 : apizer 3302 %current_state = (
1650 :     primarySortField => "$primarySortField",
1651 :     secondarySortField => "$secondarySortField",
1652 :     no_visible_users => "1"
1653 : apizer 3304 );
1654 :     }
1655 : apizer 3302 @tableHeadings = (
1656 :     "Select",
1657 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'user_id', %current_state})}, 'Login Name'),
1658 :     "Login Status",
1659 :     "Assigned Sets",
1660 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'first_name', %current_state})}, 'First Name'),
1661 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'last_name', %current_state})}, 'Last Name'),
1662 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'email_address', %current_state})}, 'Email Address'),
1663 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'student_id', %current_state})}, 'Student ID'),
1664 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'status', %current_state})}, 'Status'),
1665 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'section', %current_state})}, 'Section'),
1666 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'recitation', %current_state})}, 'Recitation'),
1667 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'comment', %current_state})}, 'Comment'),
1668 :     CGI::a({href => $self->systemLink($urlpath->new(type=>'instructor_user_list', args=>{courseID => $courseName,} ), params=>{labelSortMethod=>'permission', %current_state})}, 'Permission Level'),
1669 :     )
1670 :     }
1671 : apizer 3287 if($passwordMode) {
1672 :     unshift @tableHeadings, "New Password";
1673 :     }
1674 :    
1675 : sh002i 1594 # print the table
1676 : apizer 3287 if ($editMode or $passwordMode) {
1677 : sh002i 1594 print CGI::start_table({});
1678 :     } else {
1679 : toenail 2285 print CGI::start_table({-border=>1, -nowrap=>1});
1680 : sh002i 1594 }
1681 :    
1682 :     print CGI::Tr({}, CGI::th({}, \@tableHeadings));
1683 :    
1684 : gage 1713
1685 : sh002i 1594 for (my $i = 0; $i < @Users; $i++) {
1686 :     my $User = $Users[$i];
1687 :     my $PermissionLevel = $PermissionLevels[$i];
1688 :    
1689 :     print $self->recordEditHTML($User, $PermissionLevel,
1690 :     editMode => $editMode,
1691 : apizer 3287 passwordMode => $passwordMode,
1692 : sh002i 1594 userSelected => exists $selectedUserIDs{$User->user_id}
1693 :     );
1694 :     }
1695 :    
1696 :     print CGI::end_table();
1697 : gage 1713 #########################################
1698 :     # if there are no users shown print message
1699 :     #
1700 :     ##########################################
1701 :    
1702 :     print CGI::p(
1703 :     CGI::i("No students shown. Choose one of the options above to
1704 :     list the students in the course.")
1705 :     ) unless @Users;
1706 : sh002i 1594 }
1707 :    
1708 :     1;
1709 :    

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9