added on WebSTLs (webstls.com) at 2026-07-01 22:26:19
| 1 | #!/usr/bin/perl | |
| 2 | #====================================================================== | |
| 3 | # WebSTLs - SUPER-ADMIN: Teams management | |
| 4 | # Create teams, assign staff (is_admin=1 users) to teams. | |
| 5 | #====================================================================== | |
| 6 | use strict; use warnings; | |
| 7 | use lib '/var/www/vhosts/webstls.com/httpdocs'; | |
| 8 | use CGI; | |
| 9 | use MODS::Template; | |
| 10 | use MODS::DBConnect; | |
| 11 | use MODS::Login; | |
| 12 | use MODS::WebSTLs::Config; | |
| 13 | use MODS::WebSTLs::Wrapper; | |
| 14 | use MODS::WebSTLs::Admin; | |
| 15 | ||
| 16 | my $q = CGI->new; | |
| 17 | my $form = $q->Vars; | |
| 18 | my $auth = MODS::Login->new; | |
| 19 | my $wrap = MODS::WebSTLs::Wrapper->new; | |
| 20 | my $tfile = MODS::Template->new; | |
| 21 | my $db = MODS::DBConnect->new; | |
| 22 | my $cfg = MODS::WebSTLs::Config->new; | |
| 23 | my $admin = MODS::WebSTLs::Admin->new; | |
| 24 | my $DB = $cfg->settings('database_name'); | |
| 25 | ||
| 26 | my $u = $auth->login_verify(); | |
| 27 | unless ($u) { print "Status: 302 Found\nLocation: /login.cgi\n\n"; exit; } | |
| 28 | $admin->require_admin($u); | |
| 29 | ||
| 30 | my $uid = $u->{user_id}; $uid =~ s/[^0-9]//g if defined $uid; | |
| 31 | my $dbh = $db->db_connect(); | |
| 32 | ||
| 33 | # Verify super-admin via direct lookup (login_verify doesn't populate) | |
| 34 | my $sa = $db->db_readwrite($dbh, | |
| 35 | "SELECT is_super_admin FROM `${DB}`.users WHERE id='$uid' LIMIT 1", | |
| 36 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 37 | unless ($sa && $sa->{is_super_admin}) { | |
| 38 | $db->db_disconnect($dbh); | |
| 39 | print "Status: 403 Forbidden\nContent-Type: text/plain\n\nSuper-admin only.\n"; exit; | |
| 40 | } | |
| 41 | ||
| 42 | # POST actions | |
| 43 | if (($ENV{REQUEST_METHOD}||'') eq 'POST') { | |
| 44 | my $act = $form->{act} || ''; | |
| 45 | if ($act eq 'create') { | |
| 46 | my $name = $form->{name} || ''; $name =~ s/^\s+|\s+$//g; $name = substr($name, 0, 120); | |
| 47 | my $color = $form->{color} || '#5aa9ff'; | |
| 48 | $color = '#5aa9ff' unless $color =~ /^#[0-9a-fA-F]{6}$/; | |
| 49 | my $parent = $form->{parent_team_id} || 0; $parent =~ s/[^0-9]//g; | |
| 50 | my $parent_clause = $parent ? "'$parent'" : 'NULL'; | |
| 51 | if (length $name) { | |
| 52 | my $n_sql = $name; $n_sql =~ s/'/\\'/g; | |
| 53 | $db->db_readwrite($dbh, | |
| 54 | "INSERT INTO `${DB}`.teams (name, color, parent_team_id) VALUES ('$n_sql', '$color', $parent_clause)", | |
| 55 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 56 | } | |
| 57 | } elsif ($act eq 'assign') { | |
| 58 | my $user_id = $form->{user_id} || 0; $user_id =~ s/[^0-9]//g; | |
| 59 | my $team_id = $form->{team_id} || 0; $team_id =~ s/[^0-9]//g; | |
| 60 | my $tc = $team_id ? "'$team_id'" : 'NULL'; | |
| 61 | if ($user_id) { | |
| 62 | $db->db_readwrite($dbh, | |
| 63 | "UPDATE `${DB}`.users SET team_id=$tc WHERE id='$user_id'", | |
| 64 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 65 | } | |
| 66 | } elsif ($act eq 'delete') { | |
| 67 | my $team_id = $form->{team_id} || 0; $team_id =~ s/[^0-9]//g; | |
| 68 | if ($team_id) { | |
| 69 | $db->db_readwrite($dbh, | |
| 70 | "UPDATE `${DB}`.users SET team_id=NULL WHERE team_id='$team_id'", | |
| 71 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 72 | $db->db_readwrite($dbh, | |
| 73 | "DELETE FROM `${DB}`.teams WHERE id='$team_id'", | |
| 74 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 75 | } | |
| 76 | } | |
| 77 | $db->db_disconnect($dbh); | |
| 78 | print "Status: 302 Found\nLocation: /admin_teams.cgi\n\n"; exit; | |
| 79 | } | |
| 80 | ||
| 81 | my @teams = $db->db_readwrite_multiple($dbh, | |
| 82 | "SELECT t.id, t.name, t.color, t.parent_team_id, p.name AS parent_name, | |
| 83 | (SELECT COUNT(*) FROM `${DB}`.users u WHERE u.team_id=t.id) AS members_n | |
| 84 | FROM `${DB}`.teams t | |
| 85 | LEFT JOIN `${DB}`.teams p ON p.id = t.parent_team_id | |
| 86 | ORDER BY t.name", | |
| 87 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 88 | ||
| 89 | my @staff = $db->db_readwrite_multiple($dbh, | |
| 90 | "SELECT u.id, u.email, u.display_name, u.team_id, t.name AS team_name, t.color AS team_color | |
| 91 | FROM `${DB}`.users u | |
| 92 | LEFT JOIN `${DB}`.teams t ON t.id = u.team_id | |
| 93 | WHERE u.is_admin = 1 | |
| 94 | ORDER BY u.display_name, u.email", | |
| 95 | $ENV{SCRIPT_NAME}, __LINE__); | |
| 96 | ||
| 97 | foreach my $t (@teams) { | |
| 98 | $t->{name} = _h($t->{name}); | |
| 99 | $t->{parent_name} = _h($t->{parent_name} || ''); | |
| 100 | } | |
| 101 | foreach my $s (@staff) { | |
| 102 | $s->{display_name} = _h($s->{display_name} || $s->{email}); | |
| 103 | $s->{email} = _h($s->{email}); | |
| 104 | $s->{team_name} = _h($s->{team_name} || ''); | |
| 105 | } | |
| 106 | ||
| 107 | $db->db_disconnect($dbh); | |
| 108 | ||
| 109 | my $tvars = { | |
| 110 | teams => \@teams, | |
| 111 | has_teams => scalar(@teams) ? 1 : 0, | |
| 112 | staff => \@staff, | |
| 113 | has_staff => scalar(@staff) ? 1 : 0, | |
| 114 | }; | |
| 115 | ||
| 116 | print "Content-Type: text/html; charset=utf-8\nCache-Control: no-store\n\n"; | |
| 117 | my $body = join('', $tfile->template('webstls_admin_teams.html', $tvars, $u)); | |
| 118 | $wrap->render({ userinfo => $u, page_key => 'admin_teams', title => 'Teams', body => $body }); | |
| 119 | ||
| 120 | sub _h { | |
| 121 | my $s = shift; return '' unless defined $s; | |
| 122 | $s =~ s/&/&/g; $s =~ s/</</g; $s =~ s/>/>/g; $s =~ s/"/"/g; | |
| 123 | return $s; | |
| 124 | } |