Subversion Repositories VORC

Rev

Rev 226 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
56 bgadell 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 cPanelUserConfig;
11
use RollerCon;
93 bgadell 12
use tableViewer qw/inArray/;
226 - 13
use CGI qw/param cookie header start_html url url_param/;
56 bgadell 14
use Email::Valid;
15
use WebDB;
16
use HTML::Tiny;
17
our $h = HTML::Tiny->new( mode => 'html' );
18
 
19
my ($FORM, $cookie_string, $ERRMSG);
20
my @ERRORS;
21
my $dbh = getRCDBH;
22
my $depts = getDepartments (); # HashRef of the department TLAs -> Display Names...
23
my $deptDesc = getDepartmentDescriptions ();
24
my $deptLink = getDepartmentLinks ();
25
my $AccessLevel = getAccessLevels;
26
my @tshirtOptions = ("", "MS", "MM", "ML", "MXL", "M2X", "M3X");
86 bgadell 27
my @AUTODEPTS = map { $_->[0] } @{$dbh->selectall_arrayref ("select TLA from department where autoapprove = true")};
122 - 28
my @FIELDS = qw/ derby_name email real_name phone password access department tshirt pronouns timeformat showme /;
93 bgadell 29
my @PRIVFIELDS = qw/ email access /;
30
$ORCUSER->{department} = ref $ORCUSER->{department} eq "HASH" ? $ORCUSER->{department} : convertDepartments($ORCUSER->{department});
56 bgadell 31
 
93 bgadell 32
 
56 bgadell 33
# The page's form might be submitted as a POST or a GET (or both?)
34
#  The initial _view_ likely comes as a GET request (making it easier to embed in an HREF as a URL)
35
#  Unpack any values sent in the GET and add them to the FORM hash
36
$FORM->{'SUB'} = param ('submit') // '';
226 - 37
$FORM->{'RCid'} = param ('RCid'); $FORM->{'RCid'} //= url_param ('RCid');
56 bgadell 38
$FORM->{referer} = param ("referer") // "";
39
if ($FORM->{'SUB'} eq '') {
88 bgadell 40
  if ($ENV{'REQUEST_URI'}) {
41
    my ($g, $keep) = split /\?/, $ENV{'REQUEST_URI'};
42
    if ($keep) {
43
      foreach (split /&/, $keep) {
44
        my ($k, $v) = split /=/;
45
        $k =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
46
        $v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
47
        $k eq "submit" ? $FORM->{'SUB'} = $v : $FORM->{$k} = $v;
48
      }
49
    }
50
  }
56 bgadell 51
}
52
 
53
# Keep track of the original referrer for the 'back' link/button
54
my $goback;
55
if ($FORM->{referer}) {
88 bgadell 56
  $goback = $FORM->{referer};
56 bgadell 57
} else {
88 bgadell 58
  $goback = $ENV{HTTP_REFERER};
56 bgadell 59
}
60
 
61
 
62
if ($FORM->{'SUB'} eq "Save") {
88 bgadell 63
  process_form ($FORM);
56 bgadell 64
} elsif ($FORM->{'SUB'} eq "New User") {
65
  display_form ("New", "New User"); # blank form
112 - 66
} elsif ($FORM->{'SUB'} eq "Make Current") {
67
  $dbh->do ("update official set last_login = now() where RCid = ?", undef, $FORM->{'RCid'}) unless $FORM->{'RCid'} !~ /^\d+$/;
68
  logit ($FORM->{'RCid'}, "An Admin updated last_login time to current.");
69
#  logit ($ORCUSER->{'RCid'}, "Updated user ($FORM->{'RCid'}) last_login time to current.");
70
  display_form ($FORM->{'RCid'}, "View");
134 - 71
} elsif ($FORM->{'SUB'} eq "Verify") {
72
  $cookie_string = authenticate (RollerCon::USER);
73
	validate_emt ($FORM->{RCid}, "add");
74
  display_form ($FORM->{'RCid'}, "View");
75
} elsif ($FORM->{'SUB'} eq "Remove") {
76
  $cookie_string = authenticate (RollerCon::USER);
77
	validate_emt ($FORM->{RCid}, "del");
78
  display_form ($FORM->{'RCid'}, "View");
56 bgadell 79
} elsif ($FORM->{'RCid'}) {
80
  display_form ($FORM->{'RCid'}, $FORM->{'SUB'});
81
} else {
88 bgadell 82
  $cookie_string = authenticate (1);
83
  my ($EM, $PWD, $AL) = split /&/, $cookie_string;
84
  display_form (getUser ($EM)->{'RCid'}, "View");
56 bgadell 85
}
86
 
87
 
88
sub process_form {
89
  my $F = shift // "";
90
  push @ERRORS, "Tried to save an empty form." and return unless $F;
91
 
88 bgadell 92
  $F->{email}       = lc WebDB::trim param ('email')   // '';
93
  $F->{password}    = WebDB::trim param ('password')   // '';
94
  $F->{derby_name}  = WebDB::trim param ('derby_name') // '';
95
  $F->{real_name}   = WebDB::trim param ('real_name')  // '';
96
  $F->{pronouns}    = WebDB::trim param ('pronouns')   // '';
97
  $F->{tshirt}      = WebDB::trim param ('tshirt')     // '';
98
  $F->{phone}       = WebDB::trim param ('phone')      // '';
99
  $F->{timeformat}  = WebDB::trim param ('timeformat') // '24hr';
122 - 100
  $F->{showme}      = WebDB::trim param ('showme') ? 1 : 0;
134 - 101
  $F->{EMTVerified} = WebDB::trim param ('EMTVerified') ? 1 : 0;
88 bgadell 102
  $F->{RCid}        = param ('RCid')       // '';
103
  $F->{access}      = param ('access')     // 0;
104
  $F->{department}  = join ":", map { "$_-".param ("DEPT-".$_) } map { s/^DEPT-//; $_ } grep { param ($_) ne "" } grep { /^DEPT-/ } param ;
56 bgadell 105
 
106
  if ($F->{RCid} eq "New") {
107
  # Saving a new User...
108
    # But first let's do some error checking...0
88 bgadell 109
    if (!$F->{password})   { push @ERRORS, "Blank Password!"; }
110
    if (!$F->{real_name})  { push @ERRORS, "Blank Full Name!"; }
111
    if (!$F->{derby_name}) { $F->{derby_name} = $F->{real_name}; } # If they leave derby_name blank, use their real_name
112
    if (checkDupes ('derby_name', $F->{derby_name})) { push @ERRORS, "Derby Name already in use. Pick a different one."; $F->{derby_name} = ""; }
113
    if (!$F->{email})      { push @ERRORS, "Blank Email (User-ID)!"; } else {
114
      $F->{email} =~ s/\s+//g; # make sure people aren't accidentally including spaces
115
      $F->{email} = lc $F->{email}; # sometimes people capitalize their email addresses and that's annoying...
116
      if (! Email::Valid->address (-address => $F->{email}, -mxcheck => 1, -tldcheck => 1)) { push @ERRORS, "Mal-formatted (or fake) Email Address!"; $F->{email} = ""; }
117
    }
118
    if (checkDupes ('email', $F->{email})) { push @ERRORS, "Email Address already in use. Pick a different one."; $F->{email} = ""; }
56 bgadell 119
 
88 bgadell 120
    if (scalar @ERRORS) {
121
      $ERRMSG = join $h->br, @ERRORS;
122
      display_form ("New", "New User", $ERRMSG, $F);
123
    } else {
124
      # We have a correctly formatted email address with a mail host record, go ahead and add the user
125
 
126
      # Check to see if any of the departments they've requested are set to autoapprove.
127
      $F->{department} = convertDepartments $F->{department};
128
      map { $F->{department}->{$_} = inArray ($_, \@AUTODEPTS) } keys %{$F->{department}};
129
      $F->{department} = convertDepartments $F->{department};
130
 
122 - 131
      $dbh->do ("insert into official (email,  password,       derby_name,       real_name,       pronouns,       tshirt,       phone,       timeformat,       showme,       access, department, added, activation) values (?, password(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, CONVERT_TZ(now(), 'America/Chicago', 'America/Los_Angeles'), md5(rand()))", undef,
132
                                  $F->{email}, $F->{password}, $F->{derby_name}, $F->{real_name}, $F->{pronouns}, $F->{tshirt}, $F->{phone}, $F->{timeformat}, $F->{showme}, 0,      $F->{department})
93 bgadell 133
        or display_form ("New", "New User", "ERROR: DB: ".$dbh->errstr, $F);
56 bgadell 134
 
94 bgadell 135
      ($F->{RCid}, $F->{activation}) = $dbh->selectrow_array ("select RCid, activation from official where email = ?", undef, $F->{email});
93 bgadell 136
 
118 - 137
      $dbh->do ("replace into RCid_ticket_link select official.RCid, v_ticket.id, year(now()) from official join v_ticket on official.email = v_ticket.email and official.real_name = v_ticket.full_name where official.RCid = ?", undef, $F->{RCid});
88 bgadell 138
      logit ($F->{RCid}, "New User Registration");
139
      sendNewUserEMail ("New User", $F);
93 bgadell 140
      $cookie_string = authenticate (RollerCon::USER);
88 bgadell 141
    }
142
  } else {
93 bgadell 143
  # Save changes to an existing user.
144
    $cookie_string = authenticate (RollerCon::USER);
88 bgadell 145
    my ($EM, $PWD, $AL) = split /&/, $cookie_string;
146
 
147
    my $OG = getUser ($F->{RCid});
93 bgadell 148
 
88 bgadell 149
    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} = ""; }
105 bgadell 150
    if (!$F->{derby_name}) { push @ERRORS, "Blank Derby Name!"; }
88 bgadell 151
    if ($F->{email} ne $OG->{email} and checkDupes ('email', $F->{email})) { push @ERRORS, "Email Address already in use. Pick a different one."; $F->{email} = ""; }
152
    if (!$F->{real_name})  { push @ERRORS, "Blank Full Name!"; }
93 bgadell 153
 
88 bgadell 154
    if (scalar @ERRORS) {
155
      $ERRMSG = join $h->br, @ERRORS;
156
      display_form ($F->{RCid}, "Edit", $ERRMSG, $F);
157
    }
158
 
93 bgadell 159
 
134 - 160
    if ($ORCUSER->{department}->{EMT} >= RollerCon::LEAD or $AL >= RollerCon::SYSADMIN) {
161
      # Check for changes to the emt_verified field...
162
      if ($F->{EMTVerified} != $OG->{emt_verified}) {
163
        warn "Updating emt_verified for $OG->{derby_name} - $F->{EMTVerified} vs $OG->{emt_verified}";
164
        validate_emt ($F->{RCid}, $F->{EMTVerified} ? "add" : "del");
165
      }
166
    }
93 bgadell 167
 
168
    if ($ORCUSER->{RCid} == $F->{RCid} or $AL >= RollerCon::SYSADMIN) {
169
    # They're editing their own record (or a sysadmin).
56 bgadell 170
 
93 bgadell 171
      my $DBDepts = $OG->{department};
172
      if ($F->{department} ne $DBDepts and $AL < RollerCon::SYSADMIN) {
88 bgadell 173
        # They're trying to change one of their own departments.
174
        my $FORMDepts = convertDepartments $F->{department};
175
        $DBDepts =   convertDepartments $DBDepts;
56 bgadell 176
        # the only change to a dept should be a request to be added, some depts are auto-approved.
88 bgadell 177
        map { $FORMDepts->{$_} = inArray ($_, \@AUTODEPTS) } keys %{$FORMDepts};
56 bgadell 178
        # or they can retract their request
88 bgadell 179
        map { do { delete $DBDepts->{$_} } if $DBDepts->{$_} == 0 and !defined $FORMDepts->{$_} } keys %{$DBDepts};
180
        # otherwise, keep the same depts as are in the DB (or have been auto-approved...)
181
        map { $FORMDepts->{$_} = max ($DBDepts->{$_}, $FORMDepts->{$_}) } keys %{$DBDepts};
182
        $F->{department} = convertDepartments $FORMDepts;
183
      }
56 bgadell 184
 
93 bgadell 185
      foreach my $field (@FIELDS) {
122 - 186
        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})) {
93 bgadell 187
          # No changes to this field, move on...
188
          next;
189
        }
190
 
191
        if ($AL < RollerCon::SYSADMIN and inArray ($field, \@PRIVFIELDS)) {
192
          push @ERRORS, "ERROR: Only SysAdmins are allowed to change the $field field";
193
          logit ($F->{RCid}, "SECURITY: Only SysAdmins are allowed to change the $field field");
194
          next;
195
        }
196
 
197
        # warn "Changing $field: $F->{$field}";
198
        if (my $err = changeUser ($F->{RCid}, $field, $F->{$field})) {
199
          push @ERRORS, $err;
200
          logit ($F->{RCid}, "DB ERROR: Updating User Details: $err");
201
        }
88 bgadell 202
      }
203
    } else {
93 bgadell 204
      push @ERRORS, "Attempting to update someone else's record, and you don't have permission to do that.";
205
      logit ($ORCUSER->{RCid}, "FAIL: You don't have access to update other people's user record");
88 bgadell 206
    }
207
  }
208
  $F->{password} = "*******";
209
  $F->{buttons}   = $h->input ({ type=>"hidden", name=>"RCid", value=>$F->{RCid} }).$h->input ({ type=>"submit", name=>"submit", value=>"Edit" });
210
  $F->{department} = convertDepartments ($F->{department});
118 - 211
  $dbh->do ("replace into RCid_ticket_link select official.RCid, v_ticket.id, year(now()) from official join v_ticket on official.email = v_ticket.email and official.real_name = v_ticket.full_name where official.RCid = ?", undef, $F->{RCid});
56 bgadell 212
 
93 bgadell 213
  if (scalar @ERRORS) {
214
    $ERRMSG = join $h->br, @ERRORS;
215
  }
216
 
217
  display_form ($F->{RCid}, "View", $ERRMSG);
56 bgadell 218
}
219
 
220
sub display_form {
221
  my $RCID = shift // "";
222
  my $view = shift; # // "New User";
223
  my $errors = shift // "";
224
  my $F = shift; # // "";
225
 
226
  if ($view eq 'Edit') {
93 bgadell 227
    $cookie_string = authenticate (RollerCon::USER);
88 bgadell 228
    my ($EM, $PWD, $AL) = split /&/, $cookie_string;
229
    $F = getUser ($RCID);
230
 
93 bgadell 231
    if (canView ($ORCUSER, $F)) {
88 bgadell 232
      # Editing your own record OR you're a lead/higher
93 bgadell 233
      if (lc $EM eq lc $F->{email} or $ORCUSER->{access} < $F->{access}) {
88 bgadell 234
        # If you're editing your own record, or someone who has higher access than you, make access level read-only
235
        $F->{access}      = $h->input ({ type=>"hidden", name=>"access", value=>$F->{access} }).$AccessLevel->{$F->{access}};
236
      } else {
93 bgadell 237
        $F->{access}      = $h->select ({ name=>"access" }, [map { $F->{access} == $_ ? $h->option ({ value=>$_, selected=>[] }, $AccessLevel->{$_}) : $h->option ({ value=>$_ }, $AccessLevel->{$_}) } (-1..$ORCUSER->{access})]);
88 bgadell 238
      }
93 bgadell 239
      if ($ORCUSER->{access} >= RollerCon::MANAGER) {
240
        #this would be the place to test for other types of managers that can update the MVP Pass setting
58 bgadell 241
        if ($F->{MVPid}) {
242
          $F->{MVPid} .= "->link to change...<-";
243
        }
88 bgadell 244
      } else {
245
      }
93 bgadell 246
      if ($AL == RollerCon::SYSADMIN) {
88 bgadell 247
        $F->{email}      = $h->input ({ type=>"text", name=>"email", value=>$F->{email} });
248
      } else {
249
        $F->{email}      = $F->{email}.$h->input ({ type=>"hidden", name=>"email", value=>$F->{email} });
250
      }
93 bgadell 251
      if ($ORCUSER->{RCid} eq $F->{RCid} or $ORCUSER->{access} >= RollerCon::SYSADMIN) {
88 bgadell 252
        $F->{password}   = $h->input ({ type=>"password", name=>"password" });
253
        $F->{derby_name} = $h->input ({ type=>"text", name=>"derby_name", value=>$F->{derby_name} });
254
        $F->{real_name}  = $h->input ({ type=>"text", name=>"real_name", value=>$F->{real_name} });
255
        $F->{pronouns}   = $h->input ({ type=>"text", name=>"pronouns", value=>$F->{pronouns} });
256
        $F->{tshirt}     = $h->select ({ name=>"tshirt" }, [map { $F->{tshirt} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } @tshirtOptions] );
257
        $F->{phone}      = $h->input ({ type=>"text", name=>"phone", value=>$F->{phone} });
258
        $F->{timeformat} = $h->select ({ name=>"timeformat" }, [map { $F->{timeformat} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } qw(24hr ampm)] );
122 - 259
        if ($F->{showme}) {
260
          $F->{showme}   = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"showme", value=>1, checked=>[] }), $h->span ({ class=>"slider round" })]);
261
        } else {
262
          $F->{showme}   = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"showme", value=>1 }), $h->span ({ class=>"slider round" })]);
263
        }
88 bgadell 264
      } else {
265
        $F->{password}   = '*******';
266
      }
267
      $F->{RCid}       = $h->input ({ type=>"hidden", name=>"RCid", value=>$F->{RCid} })."$F->{RCid}&nbsp;";
268
      $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" });
269
 
270
      $F->{department} = convertDepartments ($F->{department});
134 - 271
      if (exists $F->{department}->{EMT} and ($ORCUSER->{department}->{EMT} >= RollerCon::LEAD or $ORCUSER->{access} >= RollerCon::SYSADMIN)) {
272
        if ($F->{emt_verified}) {
273
          $F->{EMTVerified} = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"EMTVerified", value=>1, checked=>[] }), $h->span ({ class=>"slider round" })]);
274
        } else {
275
          $F->{EMTVerified} = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"EMTVerified", value=>1 }), $h->span ({ class=>"slider round" })]);
276
        }
277
      }
278
 
88 bgadell 279
      foreach my $k (keys %{$depts}) {
280
        next if $k eq "CMP";
93 bgadell 281
        if ($ORCUSER->{access} > 4) {
88 bgadell 282
          # SysAdmin can change anyone's department level
283
          $F->{department}->{$k} = $h->select ({ name=>"DEPT-".$k }, [ $h->option ({ value=>"" }, ""), map { $_ eq $F->{department}->{$k} ? $h->option ({ value=>$_, selected=>[] }, $AccessLevel->{$_}) : $h->option ({ value=>$_ }, $AccessLevel->{$_}) } (0..4) ]);
93 bgadell 284
        } elsif ($ORCUSER->{department}->{$k} > 1 and $ORCUSER->{department}->{$k} > $F->{department}->{$k}) {
88 bgadell 285
          # Department Leads and above can change someone's level within the dept (up to their own level -1)
93 bgadell 286
          $F->{department}->{$k} = $h->select ({ name=>"DEPT-".$k }, [ $h->option ({ value=>"" }, ""), map { $_ eq $F->{department}->{$k} ? $h->option ({ value=>$_, selected=>[] }, $AccessLevel->{$_}) : $h->option ({ value=>$_ }, $AccessLevel->{$_}) } (0..$ORCUSER->{department}->{$k}-1) ]);
88 bgadell 287
        } else {
288
          # Or it's your own record, you can still submit a request to be added to the dept.
289
          if (!defined $F->{department}->{$k}) {
86 bgadell 290
            $F->{department}->{$k} = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"DEPT-$k", value=>0 }), $h->span ({ class=>"slider round" })]) unless !inArray ($k, \@AUTODEPTS);
56 bgadell 291
          } elsif ($F->{department}->{$k} == 0) {
134 - 292
            $F->{department}->{$k} = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"DEPT-$k", value=>0, checked=>[] }), $h->span ({ class=>"slider round" })]);
56 bgadell 293
          }
88 bgadell 294
        }
295
      }
296
    } else {
297
      $ERRMSG = "Attempting to update someone else's record, and you don't have permission to do that.";
298
    }
56 bgadell 299
 
300
  } elsif ($view eq 'New User') {
93 bgadell 301
    $errors .= $h->br."NOTE: You will not be able to login until your account has been activated. Watch your email for further instructions.";
88 bgadell 302
    # Skip authentication
303
    $F->{email}      = $h->input ({ type=>"text", name=>"email", value=>$F->{email} });
304
    $F->{password}   = $h->input ({ type=>"password", name=>"password" });
305
    $F->{derby_name} = $h->input ({ type=>"text", name=>"derby_name", value=>$F->{derby_name} });
306
    $F->{real_name}  = $h->input ({ type=>"text", name=>"real_name", value=>$F->{real_name} });
307
    $F->{pronouns}   = $h->input ({ type=>"text", name=>"pronouns", value=>$F->{pronouns} });
308
    $F->{tshirt}     = $h->select ({ name=>"tshirt" }, [map { $F->{tshirt} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } @tshirtOptions] );
309
    $F->{phone}      = $h->input ({ type=>"text", name=>"phone", value=>$F->{phone} });
310
    $F->{timeformat} = $h->select ({ name=>"timeformat" }, [map { $F->{timeformat} eq $_ ? $h->option ({ selected=>[] }, $_) : $h->option ($_) } qw(24hr ampm)] );
122 - 311
    if ($F->{showme}) {
312
      $F->{showme}   = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"showme", value=>1, checked=>[] }), $h->span ({ class=>"slider round" })]);
313
    } else {
314
      $F->{showme}   = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"showme", value=>1 }), $h->span ({ class=>"slider round" })]);
315
    }
88 bgadell 316
    $F->{RCid}         = $h->input ({ type=>"hidden", name=>"RCid", value=>"New" })."TBD&nbsp;";
317
    $F->{access}      = $h->input ({ type=>"hidden", name=>"access", value=>0 })."0";
56 bgadell 318
 
319
    $F->{department} = convertDepartments ($F->{department});
88 bgadell 320
    foreach (sort keys %{$depts}) {
321
      next if $_ eq "CMP";
322
      next unless inArray($_, \@AUTODEPTS);
323
      if (defined param ("DEPT-$_")) {
324
        $F->{department}->{$_} = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"DEPT-$_", value=>0, checked=>[] }), $h->span ({ class=>"slider round" })]);
325
      } else {
326
        $F->{department}->{$_} = $h->label ({ class=>"switch" }, [$h->input ({ type=>"checkbox", name=>"DEPT-$_", value=>0 }), $h->span ({ class=>"slider round" })]);
327
      }
328
    }
329
    $F->{buttons}   = $h->input ({ type=>"submit", name=>"submit", value=>"Save" })." ".$h->input ({ type=>"reset", value=>"Reset" })." ".$h->input ({ type=>"submit", name=>"submit", value=>"Cancel" });
330
    $cookie_string = '';
56 bgadell 331
  } elsif ($view eq 'View' or $view eq 'Cancel' or !$view) {
88 bgadell 332
    $cookie_string = authenticate (1);
333
    my ($EM, $PWD, $AL) = split /&/, $cookie_string;
56 bgadell 334
 
88 bgadell 335
    if (!$view) {
56 bgadell 336
      $F->{'RCid'} = getUser ($EM)->{'RCid'};
88 bgadell 337
    }
56 bgadell 338
 
88 bgadell 339
    # Check to make sure they're only looking up their own ID unless they're a lead or higher
228 - 340
    my $targetuser = getUser ($RCID);
341
 
342
    if (!$targetuser) {
343
      $errors = "User [$RCID] not found.";
344
      $F->{RCid} = "&nbsp;";
345
    } elsif (canView ($ORCUSER, $targetuser)) {
88 bgadell 346
      $F = $targetuser;
347
      $F->{department} = convertDepartments ($F->{department});
134 - 348
      if (exists $F->{department}->{EMT}) {
349
        $F->{EMTVerified} = $F->{emt_verified} ? "True" : "False";
350
        if ($ORCUSER->{department}->{EMT} >= RollerCon::LEAD or $AL >= RollerCon::SYSADMIN) {
351
					if ($F->{emt_verified}) {
352
						$F->{EMTVerified} = "True"."&nbsp;&nbsp;".$h->input ({ type=>"submit", name=>"submit", value=>"Remove" });
353
					} else {
354
						$F->{EMTVerified} = "False"."&nbsp;&nbsp;".$h->input ({ type=>"submit", name=>"submit", value=>"Verify" });
355
	      	}
356
        }
357
      }
222 - 358
      if ($F->{department}->{COA} >= RollerCon::USER) {
359
        ($F->{bio}) = $dbh->selectrow_array ("select concat(left(bio, 24), if(length(bio)>16, '...', '')) as truncated_bio from coach_bio where RCid = ?", undef, $F->{RCid});
360
        if ($ORCUSER->{RCid} eq $F->{RCid} or $ORCUSER->{access} >= RollerCon::SYSADMIN) {
361
          $F->{bio} .= $h->input ({ type=>"button", value=>"Edit", onClick=>"window.location.href='view_coach_bio.pl?RCid=$F->{RCid}&choice=Update'; return false;" });
362
        }
363
      }
56 bgadell 364
      $F->{access} = $AccessLevel->{$F->{access}};
122 - 365
      $F->{showme} = $F->{showme} ? "True" : "False";
88 bgadell 366
      $F->{'password'} = "*******";
367
      $F->{buttons}   = $h->input ({ type=>"hidden", name=>"RCid", value=>$F->{'RCid'} }).$h->input ({ type=>"submit", name=>"submit", value=>"Edit" });
71 bgadell 368
 
112 - 369
      if ($ORCUSER->{access} >= RollerCon::SYSADMIN or ($ORCUSER->{department} and $ORCUSER->{department}->{VCI} > 2)) {
370
        $F->{last_login} .= $h->input ({ type=>"submit", name=>"submit", value=>"Make Current" });
371
      }
372
 
373
 
93 bgadell 374
      if ($ORCUSER->{access} > 2 or ($ORCUSER->{department} and $ORCUSER->{department}->{MVP} >= 2)) {
58 bgadell 375
        if($F->{MVPid}) {
376
          $F->{MVPid} .= '&nbsp;&nbsp;' . $h->button ({ onClick=>"window.open('update_mvp_ticket.pl?change=Delete&RCid=$F->{RCid}&MVPid=$F->{MVPid}','Change MVP Ticket','resizable,height=260,width=370'); return false;" }, "Delete Match");
377
        } else {
378
          $F->{MVPid} .= $h->button ({ onClick=>"window.open('update_mvp_ticket.pl?change=lookup&RCid=$F->{RCid}','Change MVP Ticket','resizable,height=260,width=370'); return false;" }, "Manual Match");
379
          my $possible_matches = $dbh->selectall_arrayref ("select id, full_name from v_ticket where isnull(RCid) = true and email = (select email from official where RCid = ?) union
380
            select id, full_name from v_ticket where isnull(RCid) = true and full_name = (select real_name from official where RCid = ?) union
381
            select id, full_name from v_ticket where isnull(RCid) = true and derby_name = (select derby_name from official where RCid = ?)", undef, $F->{RCid}, $F->{RCid}, $F->{RCid});
382
 
383
          foreach my $match (@$possible_matches) {
384
            my ($MVPid, $fullname) = @$match;
71 bgadell 385
 
58 bgadell 386
            $F->{MVPid} .= $h->div ({ class => "hint" }, ["Possible Match: @$match", '&nbsp;&nbsp;', $h->button ({ onClick=>"window.open('update_mvp_ticket.pl?change=add&RCid=$F->{RCid}&MVPid=$MVPid','Change MVP Ticket','resizable,height=260,width=370'); return false;" }, "Accept Match")]);
387
          }
388
        }
389
      }
88 bgadell 390
    } else {
93 bgadell 391
      logit ($ORCUSER->{RCid}, "SECURITY: $ORCUSER->{derby_name} attempted to view another user's ($RCID) info");
88 bgadell 392
      $errors = "Unauthorized attempt to view another user.  This has been logged.";
93 bgadell 393
      $RCID = "";
88 bgadell 394
      $F->{email}      = "&nbsp;";
395
      $F->{password}   = "&nbsp;";
396
      $F->{derby_name} = "&nbsp;";
397
      $F->{real_name}  = "&nbsp;";
398
      $F->{pronouns}   = "&nbsp;";
399
      $F->{tshirt}     = "&nbsp;";
400
      $F->{phone}      = "&nbsp;";
401
      $F->{timeformat} = "&nbsp;";
122 - 402
      $F->{showme}     = "&nbsp;";
88 bgadell 403
      $F->{RCid}       = "&nbsp;";
404
      $F->{access}     = "&nbsp;";
405
      $F->{MVPid}      = "&nbsp;";
406
      $F->{buttons}    = "&nbsp;";
56 bgadell 407
    }
408
 
93 bgadell 409
  }
56 bgadell 410
 
411
  #---------------START THE HTML--------------------
412
 
413
  my $RCAUTH_cookie = cookie (-name=>'RCAUTH',-value=>"$cookie_string",-expires=>"+30m");
414
 
415
  print header (-cookie=>$RCAUTH_cookie);
416
 
417
  #foreach (keys %ENV) {
93 bgadell 418
  # warn "$_: $ENV{$_}\n<br>";
56 bgadell 419
  #}
420
 
421
  if ($errors) {
88 bgadell 422
    $errors = $h->div ({ class=>"error" }, $errors);
56 bgadell 423
  } else {
88 bgadell 424
    $errors = "";
56 bgadell 425
  }
426
 
58 bgadell 427
   my @printDepartments = ( $h->div ({ class=>"index", style=>"display: unset;" }, $h->p ({ class=>"heading" }, "Volunteer Department Access:")) );
56 bgadell 428
  push @printDepartments, $h->div ({ class=>"rTableRowSpan" },[ $h->div ({ style=>"rTableCellr" }, $h->div ({ class=>"hint" }, "Here is where you're signed up to volunteer at RollerCon:")) ]);
429
  foreach (sort grep { !/^PER$/ } keys %{$F->{department}}) {
430
    push @printDepartments, $h->div ({ class=>"rTableRow" }, [
431
      $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" },
432
        [ $h->span ({ class=>"tooltip-wrap" }, [$h->img ({src=>"/images/qm.png", width=>"18", height=>"18"}), $h->div ({ class=>"tooltip-content" }, $h->div ({class=>"bold"}, $depts->{$_}).$deptDesc->{$_} . (exists $deptLink->{$_} ? $h->a ({ href=>$deptLink->{$_}, target=>"_new"}, " [More Info]") : "") )]), $depts->{$_}.":" ],
433
        $F->{department}->{$_} =~ /^\d$/ ? $AccessLevel->{$F->{department}->{$_}} : $F->{department}->{$_}),
434
    ]);
435
  }
436
 
437
  printRCHeader ("User Manager");
438
 
439
  print $errors;
440
  print $h->form ({ action=>url, method=>'POST', name=>'Req' },[
441
    $h->input ({ type=>"hidden", name=>"referer", value=>$goback }),
442
    $h->div ({ class=>"index" }, [$h->p ({ class=>"heading" }, "User Details:"),
443
      $h->div ({ class=>"rTable", style=>"min-width: 0%;" },[
444
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "User-ID / Email Address: ", $F->{email}) ]),
445
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Password: ",                $F->{password}) ]),
446
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Derby Name: ",              $F->{derby_name}) ]),
58 bgadell 447
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Full Name: ",               $F->{real_name}) ]),
56 bgadell 448
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Pronouns: ",                $F->{pronouns}) ]),
449
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "TShirt Size: ",             $F->{tshirt}) ]),
450
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Phone: ",                   $F->{phone}) ]),
451
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Time Format: ",       $F->{timeformat}) ]),
122 - 452
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Share My Shifts: ",         $F->{showme}) ]),
56 bgadell 453
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Database ID: ",             $F->{RCid}) ]),
454
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "User Added: ",              $F->{added}) ]),
455
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Last Login: ",              $F->{last_login}) ]),
456
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "vORC Access Level: ",       $F->{access}) ]),
58 bgadell 457
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "MVP Pass: ",                $F->{MVPid}) ]),
222 - 458
        exists $F->{EMTVerified} ? $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "EMT Verified: ", $F->{EMTVerified}) ]) : "",
459
        exists $F->{bio} ? $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr", style=>"font-size: unset;" }, "Coach Bio: ",            $F->{bio}) ]) : "",
56 bgadell 460
        @printDepartments,
461
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCell" }, "&nbsp;") ]),
462
        $h->div ({ class=>"rTableRow" },[ $h->div ({ class=>"rTableCellr" }, $h->a ({ href=>$goback }, "[go back]"), $F->{buttons}) ])
463
      ])
464
    ])
93 bgadell 465
  ]);
211 - 466
  my $YEAR = 1900 + (localtime)[5];
467
  print $h->div ({ class=>"index" }, [$h->p ({ class=>"heading" }, "$YEAR Schedule:"), getSchedule ($RCID, "all")]) unless $RCID !~ /^\d+$/;
212 - 468
  if (param ("prior_years")) {
469
    print $h->div ({ class=>"index" }, [$h->p ({ class=>"heading" }, "Prior Years:"), getSchedule ($RCID, "prior")]) unless $RCID !~ /^\d+$/;
470
  } elsif ($view ne "New User" and $view ne "Edit") {
471
    print $h->h5 ($h->a ({href=>"view_user.pl?submit=View&RCid=$F->{RCid}&prior_years=1"}, "[ Show Prior Years ]"));
472
  }
56 bgadell 473
  print $h->div ({ class=>"index" }, [$h->p ({ class=>"heading" }, "Recent Activity:"), getLog ($RCID)]) unless $RCID !~ /^\d+$/;
474
  print $h->close ('html');
93 bgadell 475
  exit;
56 bgadell 476
}
477
 
478
 
479
sub checkDupes {
480
  my $field = shift;
481
  my $nametocheck = shift;
482
  my $han = $dbh->prepare("select RCid from official where $field = ?");
483
  $han->execute($nametocheck);
484
  my ($rcid) = $han->fetchrow();
485
  return $rcid;
486
}
487
 
488
sub getLog {
489
  my $RCID = shift;
490
 
491
  my @activity_log;
492
  my $alog = $dbh->prepare("select timestamp, event from v_log where RCid = ? limit 10");
493
  $alog->execute($RCID);
494
  while (my @logs = $alog->fetchrow_array) {
88 bgadell 495
    push @activity_log, $h->li ({ class=>"shaded" }, join " ", @logs);
56 bgadell 496
  }
497
 
498
  return $h->ul ([@activity_log]).$h->h5 ($h->a ({ href=>"log.pl?filter-RCid=".$RCID }, "[Entire log history]"));
499
}
500
 
501
sub getDepartmentDescriptions {
88 bgadell 502
  my %HASH;
503
  my $sth = $dbh->prepare("select TLA, description from department");
504
  $sth->execute();
505
  while (my ($tla, $name) = $sth->fetchrow) {
506
    $HASH{$tla} = $name;
56 bgadell 507
  }
508
  return \%HASH;
509
}
510
 
511
sub getDepartmentLinks {
88 bgadell 512
  my %HASH;
513
  my $sth = $dbh->prepare("select TLA, link from department where link <> ''");
514
  $sth->execute();
515
  while (my ($tla, $name) = $sth->fetchrow) {
516
    $HASH{$tla} = $name;
56 bgadell 517
  }
518
  return \%HASH;
519
}
93 bgadell 520
 
521
sub changeUser {
522
  my ($uid, $field, $newvalue) = @_;
523
 
524
  return "ERROR: Bad (or missing) RCid: [$uid]" unless $uid =~ /^\d+$/;
525
  return "ERROR: Bad (or missing) field name: [$field]" unless $field;
526
#  return "ERROR: Bad (or missing) new value: [$newvalue]" unless $newvalue;
527
  return "ERROR: Can't change someone's RCid" if $field eq "RCid";
528
 
529
  if ($field eq "password") {
530
    return unless $newvalue;
531
    $dbh->do ("update official set password = password(?) where RCid = ?", undef, $newvalue, $uid) or return "ERROR: ".$dbh->errstr;
532
  } else {
533
    $dbh->do ("update official set $field = ? where RCid = ?", undef, $newvalue, $uid) or return "ERROR: ".$dbh->errstr;
534
  }
535
 
536
  $newvalue = '********' if $field eq "password";
537
  if ($ORCUSER->{RCid} eq $uid) {
538
    logit ($uid, "Updated Profile: $field -> $newvalue");
539
  } else {
540
    logit ($ORCUSER->{RCid}, "Updated User [$uid]: $field -> $newvalue");
541
    logit ($uid, "$ORCUSER->{derby_name} updated your profile: $field -> $newvalue");
542
  }
543
 
544
  return;
545
}