Subversion Repositories PEEPS

Rev

Rev 20 | Rev 32 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#!/usr/bin/perl
2
 
3
# Redirect error messages to a log of my choosing. (it's annoying to filter for errors in the shared env)
4
#my $error_log_path = $ENV{SERVER_NAME} eq "volunteers.rollercon.com" ? "/home3/rollerco/logs/" : "/tmp/";
5
#close STDERR;
6
#open STDERR, '>>', $error_log_path.'vorc_error.log' or warn "Failed to open redirected logfile ($0): $!";
7
#warn "Redirecting errors to ${error_log_path}vorc_error.log";
8
 
9
use strict;
10
use PEEPS;
11
use tableViewer qw/inArray notInArray/;
12
use CGI qw/param cookie header start_html url url_param/;
13
use Email::Valid;
14
use WebDB;
15
use HTML::Tiny;
16
use Data::Dumper;
17
our $h = HTML::Tiny->new( mode => 'html' );
4 - 18
$ENV{HTTPS} = 'ON' if $ENV{SERVER_NAME} =~ /^peeps/;
2 - 19
 
20
my ($FORM, $cookie_string, $ERRMSG);
21
my @ERRORS;
22
my $dbh = getDBConnection ();
20 - 23
my @FIELDS = qw/ username derby_name derby_short_name default_jersey_number email name_first name_middle name_last password active pronouns birthdate /;
2 - 24
my @PRIVFIELDS = qw/ email active /;
25
 
26
 
27
# The page's form might be submitted as a POST or a GET (or both?)
28
#  The initial _view_ likely comes as a GET request (making it easier to embed in an HREF as a URL)
29
#  Unpack any values sent in the GET and add them to the FORM hash
30
$FORM->{'SUB'} = WebDB::trim scalar param ('submit') // '';
31
$FORM->{'person_id'} = WebDB::trim scalar param ('person_id'); $FORM->{'person_id'} //= WebDB::trim scalar url_param ('person_id');
32
$FORM->{referer} = WebDB::trim scalar param ("referer") // "";
33
if ($FORM->{'SUB'} eq '') {
34
  if ($ENV{'REQUEST_URI'}) {
35
    my ($g, $keep) = split /\?/, $ENV{'REQUEST_URI'};
36
    if ($keep) {
37
      foreach (split /&/, $keep) {
38
        my ($k, $v) = split /=/;
39
        $k =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
40
        $v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
41
        $k eq "submit" ? $FORM->{'SUB'} = $v : $FORM->{$k} = $v;
42
      }
43
    }
44
  }
45
}
46
 
47
# Keep track of the original referrer for the 'back' link/button
48
my $goback;
49
if ($FORM->{referer}) {
50
  $goback = $FORM->{referer};
51
} else {
52
  $goback = $ENV{HTTP_REFERER};
53
}
54
 
55
if ($FORM->{'SUB'} eq "Save") {
56
  process_form ($FORM);
57
} elsif ($FORM->{'SUB'} eq "New User") {
58
  display_form ("New", "New User"); # blank form
59
} elsif ($FORM->{'person_id'}) {
60
  display_form ($FORM->{'person_id'}, $FORM->{'SUB'});
61
} else {
62
  $cookie_string = authenticate (1);
63
  my ($EM, $PWD, $AL) = split /&/, $cookie_string;
64
  display_form (getUser ($EM)->{'person_id'}, "View");
65
}
66
 
67
 
68
sub process_form {
69
  my $F = shift // "";
70
  push @ERRORS, "Tried to save an empty form." and return unless $F;
71
  my $changed_username;
72
 
73
  $F->{username}       = WebDB::trim param ('username')   // '';
74
  $F->{email}       = lc WebDB::trim param ('email')   // '';
75
  $F->{password}    = WebDB::trim param ('password')   // '';
76
  $F->{derby_name}  = WebDB::trim param ('derby_name') // '';
77
  $F->{derby_short_name}  = WebDB::trim param ('derby_short_name') // '';
20 - 78
  $F->{default_jersey_number}  = WebDB::trim param ('default_jersey_number') // '';
2 - 79
  $F->{name_first}   = WebDB::trim param ('name_first')  // '';
80
  $F->{name_middle}   = WebDB::trim param ('name_middle')  // '';
81
  $F->{name_last}   = WebDB::trim param ('name_last')  // '';
82
  $F->{pronouns}    = WebDB::trim param ('pronouns')   // '';
83
  $F->{birthdate}      = WebDB::trim param ('birthdate')     // '';
84
  $F->{person_id}        = param ('person_id')       // '';
85
  $F->{newaffiliation}   =  scalar param ('newaffiliation');
86
  $F->{deleteaffiliation}   = scalar param ('deleteaffiliation');
87
 
88
  if (defined $F->{newaffiliation}) { $F->{newaffiliation} = WebDB::trim $F->{newaffiliation}; } else { delete $F->{newaffiliation} };
89
  if (defined $F->{deleteaffiliation}) { $F->{deleteaffiliation} = WebDB::trim $F->{deleteaffiliation}; } else { delete $F->{deleteaffiliation} };
90
 
91
  if ($F->{person_id} eq "New") {
92
  # Saving a new User...
93
    # But first let's do some error checking...0
94
    my $warn_recovery = "Do you want to ".$h->a ({ href=>"recoverAccount"}, "Recover Your Account")." instead?";
95
    if (!$F->{username})  { push @ERRORS, "Blank Username!"; }
96
    if (checkDupes ('username', 'authentication', $F->{username})) { push @ERRORS, "Username already in use. ".$warn_recovery; $F->{username} = ""; }
97
    if (!$F->{password})   { push @ERRORS, "Blank Password!"; }
98
    if (!$F->{name_first})  { push @ERRORS, "Blank First Name!"; }
99
    if (!$F->{name_last})  { push @ERRORS, "Blank Last Name!"; }
100
#    if (!$F->{derby_name}) { $F->{derby_name} = $F->{real_name}; } # If they leave derby_name blank, use their real_name
101
#    if (checkDupes ('derby_name', $F->{derby_name})) { push @ERRORS, "Derby Name already in use. Pick a different one."; $F->{derby_name} = ""; }
102
    if (!$F->{email})      { push @ERRORS, "Blank Email!"; } else {
103
      $F->{email} =~ s/\s+//g; # make sure people aren't accidentally including spaces
104
      $F->{email} = lc $F->{email}; # sometimes people capitalize their email addresses and that's annoying...
105
      if (! Email::Valid->address (-address => $F->{email}, -mxcheck => 1, -tldcheck => 1)) { push @ERRORS, "Mal-formatted (or fake) Email Address!"; $F->{email} = ""; }
106
    }
20 - 107
    if ($F->{default_jersey_number} and $F->{default_jersey_number} !~ /^\d{1,4}$/) { push @ERRORS, "Illegal Jersey Number! (Must be 1 to 4 digits, only.)"; }
2 - 108
    if (checkDupes ('email', 'person', $F->{email})) { push @ERRORS, "Email Address already in use. ".$warn_recovery; $F->{email} = ""; }
109
 
110
    if (scalar @ERRORS) {
111
      $ERRMSG = join $h->br, @ERRORS;
112
      display_form ("New", "New User", $ERRMSG, $F);
113
    } else {
114
      # We have a correctly formatted email address with a mail host record, go ahead and add the user
115
 
20 - 116
      $dbh->do ("insert into person (email, derby_name, derby_short_name, default_jersey_number, name_first, name_middle, name_last, pronouns, birthdate, created, updated)  values (?, password(?), ?, ?, ?, ?, ?, ?, ?, now(), now())", undef,
117
                                  $F->{email}, $F->{derby_name}, $F->{derby_short_name}, $F->{default_jersey_number}, $F->{name_first}, $F->{name_middle}, $F->{name_last}, $F->{pronouns}, $F->{birthdate})
2 - 118
        or display_form ("New", "New User", "ERROR: DB: ".$dbh->errstr, $F);
119
 
120
      ($F->{person_id}) = $dbh->selectrow_array ("select id from person where email = ?", undef, $F->{email});
121
      $dbh->do ("insert into authentication (person_id, username, password, activation) values (?, ?, password(?), md5(rand()))", undef, $F->{person_id}, $F->{username}, $F->{password});
122
      ($F->{activation}) = $dbh->selectrow_array ("select activation from authentication where person_id = ?", undef, $F->{person_id});
123
 
124
      $dbh->do ("replace into full_person select * from v_person where id = ?", undef, $F->{person_id});
125
 
126
      logit ($F->{person_id}, "New User Registration");
127
      sendNewUserEMail ("New User", $F);
128
      $cookie_string = authenticate (PEEPS::USER);
129
    }
130
  } else {
131
  # Save changes to an existing user.
132
    $cookie_string = authenticate (PEEPS::USER);
133
    my ($EM, $PWD, $AL) = split /&/, $cookie_string;
134
 
135
    my $OG = getUser ($F->{person_id});
136
 
137
#    if ($F->{derby_name} ne $OG->{derby_name} and checkDupes ('derby_name', $F->{derby_name})) { push @ERRORS, "Derby Name already in use. Pick a different one."; $F->{derby_name} = ""; }
138
#    if (!$F->{derby_name}) { push @ERRORS, "Blank Derby Name!"; }
20 - 139
 
140
    if ($F->{default_jersey_number} and $F->{default_jersey_number} !~ /^\d{1,4}$/) { push @ERRORS, "Illegal Jersey Number! (Must be 1 to 4 digits, only.)"; }
141
 
2 - 142
    if (exists $F->{newaffiliation}) {
143
      push @ERRORS, "No League Selected." unless $F->{newaffiliation};
144
      push @ERRORS, "That's not a Member Org ID [$F->{newaffiliation}]!" if ($F->{newaffiliation} and $F->{newaffiliation} !~ /^\d+$/);
145
      push @ERRORS, "Already a member of ".getLeagueName ($F->{newaffiliation}) unless notInArray ($F->{newaffiliation}, [keys %{getLeagueAffiliation ($F->{person_id})}]);
146
    } elsif (exists $F->{deleteaffiliation}) {
147
      push @ERRORS, "No League Selected." unless $F->{deleteaffiliation};
148
      push @ERRORS, "That's not a Member Org ID [$F->{deleteaffiliation}]!" if ($F->{deleteaffiliation} and $F->{deleteaffiliation} !~ /^\d+$/);
149
      push @ERRORS, "Not a member of ".getLeagueName ($F->{deleteaffiliation}) if ($F->{deleteaffiliation} and notInArray ($F->{deleteaffiliation}, [keys %{getLeagueAffiliation ($F->{person_id})}]));
150
    } else {
151
      if ($F->{email} ne $OG->{email} and checkDupes ('email', 'person', $F->{email})) { push @ERRORS, "Email Address already in use. Pick a different one."; $F->{email} = ""; }
152
      if (!$F->{name_last})  { push @ERRORS, "Blank Last Name!"; }
153
      if (!$F->{name_first})  { push @ERRORS, "Blank First Name!"; }
154
    }
155
 
156
    if (scalar @ERRORS) {
157
      $ERRMSG = $h->br.join $h->br, @ERRORS;
158
      display_form ($F->{person_id}, (exists $F->{newaffiliation} or exists $F->{deleteaffiliation}) ? "View" : "Edit", $ERRMSG, $F);
159
    }
160
 
161
 
162
    if ($ORCUSER->{person_id} == $F->{person_id} or $AL >= PEEPS::SYSADMIN) {
163
    # They're editing their own record (or a sysadmin).
164
 
165
      if ($F->{newaffiliation}) {
166
 
167
        # warn "new league_id: ".$F->{newaffiliation};
168
        $dbh->do ("insert into role (member_org_id, person_id, role) values (?, ?, ?)", undef, $F->{newaffiliation}, $F->{person_id}, "Pending");
169
 
170
        if ($dbh->errstr) {
171
          my $dberr = $dbh->errstr;
172
          logit ($F->{person_id}, "DB ERROR ($dberr): Requesting league affiliation to ".getLeagueName ($F->{newaffiliation})." [$F->{newaffiliation}]");
173
          push @ERRORS, $dberr;
174
        } else {
175
          logit ($F->{person_id}, "Request to be added to ".getLeagueName ($F->{newaffiliation})." [$F->{newaffiliation}]");
176
          orglogit ($F->{person_id}, $F->{newaffiliation}, "Requested affiliation.");
19 - 177
          PEEPSMailer::emailAffiliationRequest ($F->{person_id}, $F->{newaffiliation});
2 - 178
        }
179
 
180
        $dbh->do ("replace into full_person select * from v_person where id = ? and league_id = ?", undef, $F->{person_id}, $F->{newaffiliation});
181
 
182
      } elsif ($F->{deleteaffiliation}) {
183
        # warn "delete league_id: ".$F->{deleteaffiliation};
184
        $dbh->do ("delete from role where member_org_id = ? and person_id = ?", undef, $F->{deleteaffiliation}, $F->{person_id});
185
 
186
        if ($dbh->errstr) {
187
          my $dberr = $dbh->errstr;
188
          logit ($F->{person_id}, "DB ERROR ($dberr): Deleting league affiliation from ".getLeagueName ($F->{deleteaffiliation})." [$F->{deleteaffiliation}]");
189
          push @ERRORS, $dberr;
190
        } else {
191
          logit ($F->{person_id}, "Deleted Affiliation with ".getLeagueName ($F->{deleteaffiliation})." [$F->{deleteaffiliation}]");
192
          orglogit ($F->{person_id}, $F->{deleteaffiliation}, "Removed affiliation.");
19 - 193
          PEEPSMailer::emailAffiliationRemoved ($F->{person_id}, $F->{deleteaffiliation});
2 - 194
        }
195
 
196
        $dbh->do ("delete from full_person where id = ? and league_id = ?", undef, $F->{person_id}, $F->{deleteaffiliation});
197
 
198
 
199
      } else {
200
        foreach my $field (@FIELDS) {
201
          if ($F->{$field} eq $OG->{$field} or (($field eq "access" or $field eq "showme") and $F->{$field} == $OG->{$field}) or ($field eq "password" and !$F->{$field})) {
202
            # No changes to this field, move on...
203
            next;
204
          }
205
 
206
          if ($AL < PEEPS::SYSADMIN and inArray ($field, \@PRIVFIELDS)) {
207
            push @ERRORS, "ERROR: Only SysAdmins are allowed to change the $field field";
208
            logit ($F->{person_id}, "SECURITY: Only SysAdmins are allowed to change the $field field");
209
            next;
210
          }
211
 
212
          # warn "Changing $field: $F->{$field}";
213
          if (my $err = changeUser ($F->{person_id}, $field, $F->{$field})) {
214
            push @ERRORS, $err;
215
            logit ($F->{person_id}, "DB ERROR: Updating User Details: $err");
216
          }
217
        }
218
      }
219
    } else {
220
      push @ERRORS, "Attempting to update someone else's record, and you don't have permission to do that.";
221
      logit ($ORCUSER->{person_id}, "FAIL: You don't have access to update other people's user record");
222
    }
223
  }
224
  $F->{password} = "*******";
225
  $F->{buttons}   = $h->input ({ type=>"hidden", name=>"person_id", value=>$F->{person_id} }).$h->input ({ type=>"submit", name=>"submit", value=>"Edit" });
226
 
227
  if (scalar @ERRORS) {
228
    $ERRMSG = join ($h->br, @ERRORS);
229
  }
230
 
231
  display_form ($F->{person_id}, "View", $ERRMSG);
232
}
233
 
234
sub display_form {
235
  my $person_id = shift // "";
236
  my $view = shift; # // "New User";
237
  my $errors = shift // "";
238
  my $F = shift; # // "";
239
 
240
  if ($view eq 'Edit') {
241
    $cookie_string = authenticate (PEEPS::USER);
242
    my ($EM, $PWD, $AL) = split /&/, $cookie_string;
243
    $F = getUser ($person_id);
244
 
245
    if (canView ($ORCUSER, $F)) {
246
      # Editing your own record OR you're a lead/higher
247
      if (lc $EM eq lc $F->{email} or $ORCUSER->{access} < $F->{access}) {
248
        # If you're editing your own record, or someone who has higher access than you, make access level read-only
249
        #$F->{access}      = $h->input ({ type=>"hidden", name=>"access", value=>$F->{access} }).$AccessLevel->{$F->{access}};
250
      } else {
251
        #$F->{access}      = $h->select ({ name=>"access" }, [map { $F->{access} == $_ ? $h->option ({ value=>$_, selected=>[] }, $AccessLevel->{$_}) : $h->option ({ value=>$_ }, $AccessLevel->{$_}) } (-1..$ORCUSER->{access})]);
252
      }
253
      if ($AL == PEEPS::SYSADMIN) {
254
      # TBD:  allow users to change their email, but it'll re-initiate account activation...
255
        $F->{email}      = $h->input ({ type=>"text", name=>"email", value=>$F->{email} });
256
      } else {
257
        $F->{email}      = $F->{email}.$h->input ({ type=>"hidden", name=>"email", value=>$F->{email} });
258
      }
259
      if ($ORCUSER->{person_id} eq $F->{person_id} or $ORCUSER->{access} >= PEEPS::SYSADMIN) {
260
        $F->{username} = $h->input ({ type=>"text", name=>"username", value=>$F->{username} });
261
        $F->{password}   = $h->input ({ type=>"password", name=>"password" });
262
        $F->{derby_name} = $h->input ({ type=>"text", name=>"derby_name", value=>$F->{derby_name} });
263
        $F->{derby_short_name} = $h->input ({ type=>"text", name=>"derby_short_name", value=>$F->{derby_short_name} });
20 - 264
        $F->{default_jersey_number} = $h->input ({ type=>"text", name=>"default_jersey_number", value=>$F->{default_jersey_number} });
2 - 265
        $F->{name_first}  = $h->input ({ type=>"text", name=>"name_first", value=>$F->{name_first} });
266
        $F->{name_middle}  = $h->input ({ type=>"text", name=>"name_middle", value=>$F->{name_middle} });
267
        $F->{name_last}  = $h->input ({ type=>"text", name=>"name_last", value=>$F->{name_last} });
268
        $F->{pronouns}   = $h->input ({ type=>"text", name=>"pronouns", value=>$F->{pronouns} });
269
        $F->{birthdate}   = $h->input ({ type=>"date", name=>"birthdate", value=>$F->{birthdate} });
270
#        $F->{tshirt}     = $h->select ({ name=>"tshirt" }, [map { $F->{tshirt} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } @tshirtOptions] );
271
        $F->{timeformat} = $h->select ({ name=>"timeformat" }, [map { $F->{timeformat} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } qw(24hr ampm)] );
272
      } else {
273
        $F->{password}   = '*******';
274
      }
275
      $F->{person_id}       = $h->input ({ type=>"hidden", name=>"person_id", value=>$F->{person_id} })."$F->{person_id}&nbsp;";
276
      $F->{buttons}    = join " ", $h->input ({ type=>"submit", name=>"submit", value=>"Save" }), $h->input ({ type=>"reset", value=>"Reset" }), $h->input ({ type=>"submit", name=>"submit", value=>"Cancel" });
277
 
278
    } else {
279
      $ERRMSG = "Attempting to update someone else's record, and you don't have permission to do that.";
280
    }
281
 
282
  } elsif ($view eq 'New User') {
283
    $errors .= $h->br."NOTE: You will not be able to login until your account has been activated. Watch your email for further instructions.";
284
    # Skip authentication
285
    $F->{username}   = $h->input ({ type=>"text", name=>"username", value=>$F->{username} });
286
    $F->{email}      = $h->input ({ type=>"text", name=>"email", value=>$F->{email} });
287
    $F->{password}   = $h->input ({ type=>"password", name=>"password" });
288
    $F->{derby_name} = $h->input ({ type=>"text", name=>"derby_name", value=>$F->{derby_name} });
289
    $F->{derby_short_name} = $h->input ({ type=>"text", name=>"derby_short_name", value=>$F->{derby_short_name} });
20 - 290
    $F->{default_jersey_number} = $h->input ({ type=>"text", name=>"default_jersey_number", value=>$F->{default_jersey_number} });
2 - 291
    $F->{name_first}  = $h->input ({ type=>"text", name=>"name_first", value=>$F->{name_first} });
292
    $F->{name_middle}  = $h->input ({ type=>"text", name=>"name_middle", value=>$F->{name_middle} });
293
    $F->{name_last}  = $h->input ({ type=>"text", name=>"name_last", value=>$F->{name_last} });
294
    $F->{pronouns}   = $h->input ({ type=>"text", name=>"pronouns", value=>$F->{pronouns} });
295
    $F->{birthdate}   = $h->input ({ type=>"date", name=>"birthdate", value=>$F->{birthdate} });
296
#    $F->{timeformat} = $h->select ({ name=>"timeformat" }, [map { $F->{timeformat} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } qw(24hr ampm)] );
297
    $F->{person_id}         = $h->input ({ type=>"hidden", name=>"person_id", value=>"New" })."TBD&nbsp;";
298
 
299
    $F->{buttons}   = $h->input ({ type=>"submit", name=>"submit", value=>"Save" })." ".$h->input ({ type=>"reset", value=>"Reset" })." ".$h->input ({ type=>"submit", name=>"submit", value=>"Cancel" });
300
    $cookie_string = '';
301
  } elsif ($view eq 'View' or $view eq 'Cancel' or $view =~ /Affiliation$/ or !$view) {
302
    $cookie_string = authenticate (1);
303
    my ($EM, $PWD, $AL) = split /&/, $cookie_string;
304
 
305
    if (!$view) {
306
      $F->{'person_id'} = getUser ($EM)->{'person_id'};
307
    }
308
 
309
    # Check to make sure they're only looking up their own ID unless they're a lead or higher
310
    my $targetuser = getUser ($person_id);
311
 
312
    if (!$targetuser) {
313
      $errors = "User [$person_id] not found.";
314
      $F->{person_id} = "&nbsp;";
315
    } elsif (canView ($ORCUSER, $targetuser)) {
316
      $F = $targetuser;
317
#      $F->{access} = $AccessLevel->{$F->{access}};
318
      $F->{'password'} = "*******";
319
      ($F->{username}, $F->{last_login}) = $dbh->selectrow_array ("select username, last_login from authentication where person_id = ?", undef, $F->{person_id});
320
 
321
      $F->{buttons}   = $h->input ({ type=>"hidden", name=>"person_id", value=>$F->{'person_id'} }).$h->input ({ type=>"submit", name=>"submit", value=>"Edit" });
322
 
323
    } else {
324
      logit ($ORCUSER->{person_id}, "SECURITY: $ORCUSER->{derby_name} attempted to view another user's ($person_id) info");
325
      $errors = "Unauthorized attempt to view another user.  This has been logged.";
326
      $person_id = "";
327
      $F->{email}       = "&nbsp;";
328
      $F->{password}    = "&nbsp;";
329
      $F->{derby_name}  = "&nbsp;";
330
      $F->{derby_short_name} = "&nbsp;";
20 - 331
      $F->{default_jersey_number} = "&nbsp;";
2 - 332
      $F->{name_first}  = "&nbsp;";
333
      $F->{name_middle} = "&nbsp;";
334
      $F->{name_last}   = "&nbsp;";
335
      $F->{pronouns}    = "&nbsp;";
336
      $F->{birthdate}   = "&nbsp;";
337
      $F->{person_id}   = "&nbsp;";
338
      $F->{buttons}     = "&nbsp;";
339
    }
340
 
341
  }
342
 
343
  #---------------START THE HTML--------------------
344
 
345
  my $PEEPSAUTH_cookie = cookie (-name=>'PEEPSAUTH',-value=>"$cookie_string",-expires=>"+30m");
346
 
347
  print header (-cookie=>$PEEPSAUTH_cookie);
348
 
349
  #foreach (keys %ENV) {
350
  # warn "$_: $ENV{$_}\n<br>";
351
  #}
352
 
353
  if ($errors) {
354
    $errors = $h->div ({ class=>"error" }, $errors);
355
  } else {
356
    $errors = "";
357
  }
358
 
359
  printRCHeader ("User Manager");
360
 
361
  print $errors;
362
  print $h->open ("form", { action=>url, method=>'POST', name=>'UserForm', id=>'UserForm'  });
363
  print $h->input ({ type=>"hidden", name=>"referer", value=>$goback }),
364
    $h->div ({ class=>"index" }, [$h->p ({ class=>"heading" }, "User Details:"),
365
      $h->div ({ class=>"rTable", style=>"min-width: 0%;" },[
366
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Member ID: ",               $F->{person_id}) ]),
367
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Username: ",                $F->{username}) ]),
368
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Email: ",                   $F->{email}) ]),
369
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Password: ",                $F->{password}) ]),
370
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Derby Name: ",              $F->{derby_name}) ]),
371
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Derby Short Name: ",        $F->{derby_short_name}) ]),
20 - 372
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Default Jersey Number: ",   $F->{default_jersey_number}) ]),
2 - 373
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "First Name: ",              $F->{name_first}) ]),
374
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Middle Name: ",             $F->{name_middle}) ]),
375
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Last Name: ",               $F->{name_last}) ]),
376
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Pronouns: ",                $F->{pronouns}) ]),
377
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Birthdate: ",               $F->{birthdate}) ]),
378
#        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Time Format: ",       $F->{timeformat}) ]),
379
        $F->{person_id} =~ /^\d+$/ ? $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "User Added: ",              $F->{created}) ]) : "",
380
        $F->{person_id} =~ /^\d+$/ ? $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Last Login: ",              $F->{last_login}) ]) : "",
381
#        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "vORC Access Level: ",       $F->{access}) ]),
382
#        @printDepartments,
383
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCell" }, "&nbsp;") ]),
12 - 384
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr" }, $h->input ({ type=>"button", onClick=>"window.location.href='$goback'", value=>"Back"}), $F->{buttons}) ])
2 - 385
      ])
386
    ]);
387
  my $YEAR = 1900 + (localtime)[5];
388
 
12 - 389
  # Everything beyond here only applies to an existing user.
390
  return unless $view ne "New User";
391
 
2 - 392
  my ($isAWFTDAAdmin)  = $dbh->selectrow_array ("select 1 from role where role = ? and member_org_id = ? and person_id = ?", undef, "System Admin", 4276, $ORCUSER->{person_id});
393
 
394
  # Display the list of roles per League Affiliation.  If the viewing user is a league (or wftda) admin, include a button to manage roles.
395
  my $leagues = getLeagueAffiliation($person_id);
396
  my @leagueroles;
397
  foreach (sort keys %{$leagues}) {
398
    my ($isALeagueAdmin) = inArray ($_, isLeagueAdmin ($ORCUSER->{person_id}));
399
 
400
    push @leagueroles, $h->div ({ class=>"rTableRow shaded", onClick=>"window.location.href='view_league?id=$_'" },[
401
                         $h->div ({ class=>"rTableCellr".($leagues->{$_}->[0] eq "Pending" ? " highlighted" : ""), style=>"font-size: smaller;".($leagues->{$_}->[0] eq "Pending" ? " font-style: italic;" : "") },
402
                           getLeagueName ($_),
403
                           join ($h->br, sort @{$leagues->{$_}}),
404
                           ($isALeagueAdmin or $isAWFTDAAdmin) ? $h->input ({type=>"button", onClick=>"event.stopPropagation(); window.location.href='manage_role?league_id=$_&person_id=$person_id'", value=>"Manage Role"}) : undef ) ]);
405
  }
406
  unshift (@leagueroles, $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableHead", style=>"font-size: smaller;" }, ($isAWFTDAAdmin or isLeagueAdmin ($ORCUSER->{person_id})) ? qw(League Role Admin) : qw(League Role) ) ]) );
407
  print $h->ul ([@leagueroles]);
408
 
409
  if ($FORM->{SUB} eq "Request League Affiliation") {
410
    print $h->ul ([
411
      $h->select ({ name => "newaffiliation" }, [$h->option (), map {$h->option ({value=>$_->[0]}, $_->[1])} @{ getLeagues ($person_id) } ] ),
412
      $h->input ( {type=>"submit", name=>"submit", value=>"Save" }).'&nbsp;'.$h->input ({ type=>"submit", name=>"submit", value=>"Cancel" })
413
    ]);
414
  } elsif ($F->{person_id} == $ORCUSER->{person_id}) {
415
    print $h->ul ($h->div ({ class=>"rTableRow" }, $h->input ({ type => "submit", name => "submit", value => "Request League Affiliation", onClick => "document.forms['UserForm'].requestSubmit();" })));
416
  }
417
 
418
  if ($FORM->{SUB} eq "Remove Affiliation") {
419
    print $h->ul ([
420
      $h->select ({ name => "deleteaffiliation", id=>'delaff' }, [$h->option (), map {$h->option ({value=>$_}, getLeagueName ($_))} sort keys %{$leagues} ] ),
421
      $h->input ( {type=>"submit", name=>"submit", value=>"Save", onClick=>"if (confirm('Are you sure you want to be removed from '+document.getElementById('delaff').options[document.getElementById('delaff').selectedIndex].text+'?')==true) {document.forms['UserForm'].requestSubmit();} else {return false;}" }).'&nbsp;'.$h->input ({ type=>"submit", name=>"submit", value=>"Cancel" })
422
    ]);
423
  } elsif ($F->{person_id} == $ORCUSER->{person_id}) {
424
    print $h->ul ($h->div ({ class=>"rTableRow" }, $h->input ({ type => "submit", name => "submit", value => "Remove Affiliation", onClick => "document.forms['UserForm'].requestSubmit();" })));
425
  }
426
 
427
 
428
  my @policyhistory = ($h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableHead", style=>"font-size: smaller;" }, qw(ID Policy Start End) ) ]));
23 - 429
  my @policy_columns = qw(id person_id member_org_id policy_id policy_name fee created start end terminated active);
2 - 430
 
431
  my @policies = @{ $dbh->selectall_arrayref ("select * from coverage where person_id = ? order by start desc, end", undef, $person_id) };
432
  my $active_policy = isPersonCovered ($person_id);
433
  foreach (@policies) {
434
    my %policy;
435
    @policy{@policy_columns} = @{$_};
436
 
437
    push @policyhistory, $h->div ({ class=>"rTableRow ".($policy{id} == $active_policy ? "highlighted" : "shaded"), onClick=>"window.location.href='view_policy?id=$policy{id}'" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: smaller;" }, $policy{id}, $policy{policy_name}, $policy{start}, $policy{end}) ]);
438
 
439
  #  push @classes, $h->div ({ class=>"rTableRow ".($classhash->{signedup} ? "highlighted" : "shaded"), onClick=>"window.location.href='view_class?id=$classid'" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: smaller;" }, @{$class}) ]);
440
  }
441
  print $h->ul ([ @policyhistory ]) if (scalar @policies);
442
 
443
#  print $h->div ({ class=>"index" }, [
444
#                      $h->p ({ class=>"heading" }, "League Affiliation:"),
445
#                      $h->ul ({style=>"margin-right: 200px;"}, [
446
#                                map { $h->li ({class=>"shaded"},[
447
#                                                  $h->div ( {class=>"liLeft"}, getLeagueName ($_)),
448
#                                                  $h->div ( {class=>"liRight"}, join (", ", @{$leagues->{$_}}) )
449
#                                              ])
450
#                                    } sort keys %{$leagues}
451
#                              ])
452
#                ]) unless $person_id !~ /^\d+$/;
453
 
454
 
455
  print $h->div ({ class=>"index" }, [$h->p ({ class=>"heading" }, "Recent Activity:"), getLog ($person_id)]) unless $person_id !~ /^\d+$/;
456
  print $h->close ('form', 'body', 'html');
457
  exit;
458
}
459
 
460
 
461
sub checkDupes {
462
  my $field = shift;
463
  my $table = shift;
464
  my $nametocheck = shift;
465
  my $han = $dbh->prepare("select count(*) from $table where $field = ?");
466
  $han->execute($nametocheck);
467
  my ($person_id) = $han->fetchrow();
468
  return $person_id;
469
}
470
 
471
sub getLog {
472
  my $person_id = shift;
473
 
474
  my @activity_log;
475
  my $alog = $dbh->prepare("select timestamp, event from log where person_id = ? order by eventid desc limit 10");
476
  $alog->execute($person_id);
477
  while (my @logs = $alog->fetchrow_array) {
478
    push @activity_log, $h->li ({ class=>"shaded" }, join " ", @logs);
479
  }
480
 
481
  return $h->ul ([@activity_log]).$h->h5 ($h->a ({ href=>"log?filter-person_id=".$person_id }, "[Entire log history]"));
482
}
483
 
484
sub changeUser {
485
  my ($uid, $field, $newvalue) = @_;
486
 
487
  return "ERROR: Bad (or missing) person_id: [$uid]" unless $uid =~ /^\d+$/;
488
  return "ERROR: Bad (or missing) field name: [$field]" unless $field;
489
#  return "ERROR: Bad (or missing) new value: [$newvalue]" unless $newvalue;
490
  return "ERROR: Can't change someone's person_id" if $field eq "person_id";
491
 
492
  if ($field eq "password") {
493
    return unless $newvalue;
494
    $dbh->do ("update authentication set password = password(?) where person_id = ?", undef, $newvalue, $uid) or return "ERROR: ".$dbh->errstr;
495
  } else {
496
    my $table = ($field eq "username") ? "authentication" : "person";
497
    my $id    = ($field eq "username") ? "person_id" : "id";
17 - 498
    if ($field eq "birthdate" and $newvalue eq "") { $newvalue = undef; }
2 - 499
    $dbh->do ("update $table set $field = ? where $id = ?", undef, $newvalue, $uid) or return "ERROR: ".$dbh->errstr;
500
    $dbh->do ("replace into full_person select * from v_person where id = ?", undef, $uid);
501
  }
502
 
503
  $newvalue = '********' if $field eq "password";
504
  if ($ORCUSER->{person_id} eq $uid) {
505
    logit ($uid, "Updated Profile: $field -> $newvalue");
506
  } else {
507
    logit ($ORCUSER->{person_id}, "Updated User [$uid]: $field -> $newvalue");
508
    logit ($uid, "$ORCUSER->{derby_name} updated your profile: $field -> $newvalue");
509
  }
510
 
511
  return;
5 - 512
}
19 - 513