mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-28 11:28:38 +00:00
473fd0afc3
r=dbaron
1303 lines
44 KiB
Perl
Executable File
1303 lines
44 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
|
#
|
|
# The contents of this file are subject to the Mozilla Public
|
|
# License Version 1.1 (the "License"); you may not use this file
|
|
# except in compliance with the License. You may obtain a copy of
|
|
# the License at http://www.mozilla.org/MPL/
|
|
#
|
|
# Software distributed under the License is distributed on an "AS
|
|
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
# implied. See the License for the specific language governing
|
|
# rights and limitations under the License.
|
|
#
|
|
# The Original Code is the Despot Account Administration System.
|
|
#
|
|
# The Initial Developer of the Original Code is Netscape Communications
|
|
# Corporation. Portions created by Netscape are
|
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
|
# Rights Reserved.
|
|
#
|
|
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
|
# Dan Mosedale <dmose@mozilla.org>
|
|
# Zach Lipton <zach@zachlipton.org>
|
|
|
|
use strict;
|
|
use diagnostics;
|
|
|
|
|
|
# a few configurables
|
|
#
|
|
my $despotOwnerMailTo = "mailto:sysadmins\@mozilla.org";
|
|
my $despotOwner = "sysadmins";
|
|
|
|
# Shut up misguided -w warnings about "used only once". "use vars" just
|
|
# doesn't work for me.
|
|
|
|
sub sillyness {
|
|
my $zz;
|
|
$zz = $F::state;
|
|
$zz = $F::description;
|
|
$zz = $F::id;
|
|
$zz = $F::newpassword2;
|
|
$zz = $F::files;
|
|
$zz = $F::partition;
|
|
$zz = $F::doclinks;
|
|
$zz = $F::file;
|
|
$zz = $F::newsgroups;
|
|
}
|
|
|
|
my $emailregexp = q/^[^"'@|&, ]*@[^"'@|&, ]*\.[^"'@|&, ]*$/;
|
|
my $partregexp = q/^[-&:\.\w\d ]+$/;
|
|
my $partidregexp = q/^\d+$/;
|
|
|
|
use CGI::Carp qw(fatalsToBrowser);
|
|
|
|
use CGI qw(:standard :html3);
|
|
|
|
require 'utils.pl';
|
|
|
|
$::POSTTYPE = "Post";
|
|
|
|
$| = 1;
|
|
|
|
$::despot = param("_despot");
|
|
if (!defined $::despot) {
|
|
$::despot = 0;
|
|
}
|
|
|
|
# Whether or not the HTTP response headers and beginning of the HTML page has
|
|
# already been returned to the client. Necessary because some user actions
|
|
# (f.e. AddUser) result in PrintHeader() getting called twice.
|
|
$::header_done = 0;
|
|
|
|
$::disabled = "";
|
|
#$::disabled = "Despot is temporarily disabled. Please try again later.";
|
|
if ($::disabled) {
|
|
PrintHeader();
|
|
print h1("Despot -- access control for mozilla.org.");
|
|
print p($::disabled);
|
|
exit;
|
|
}
|
|
|
|
# handle bad commandline based testing
|
|
my $server_name = defined $ENV{'SERVER_NAME'} ? $ENV{'SERVER_NAME'} : 'localhost';
|
|
my $script_name = defined $ENV{'SCRIPT_NAME'} ? $ENV{'SCRIPT_NAME'} : 'despot.cgi';
|
|
my $is_https = (exists $ENV{"HTTPS"} && (lc($ENV{"HTTPS"}) eq "on")) ? 1 : 0;
|
|
if (!param()) {
|
|
PrintHeader();
|
|
print h1("Despot -- access control for mozilla.org.");
|
|
unless ($is_https) {
|
|
my $fixedurl = "https://$server_name$script_name";
|
|
print b("<font color=red>If possible, please use the " .
|
|
a({href=>$fixedurl}, "secure version of this form") .
|
|
".</font>");
|
|
}
|
|
print h2("Login, please.");
|
|
print img({-align=>"right",-width=>72,-height=>84,-src=>"handcuff.gif"});
|
|
print p("To manage mozilla users, or to change your mozilla.org " .
|
|
"password, you must first log in.");
|
|
PrintLoginForm();
|
|
exit;
|
|
}
|
|
|
|
import_names("F"); # Makes all form values available as F::.
|
|
|
|
use DBI;
|
|
|
|
use vars qw( $db_host $db_name $db_user $db_pass );
|
|
do "config.pl" || die "Couldn't load config file";
|
|
my $dsn = "DBI:mysql:host=$db_host;database=$db_name";
|
|
$::db = DBI->connect($dsn, $db_user, $db_pass)
|
|
|| die "Can't connect to database server";
|
|
|
|
my ($query, @row);
|
|
|
|
$::skiptrailer = 0;
|
|
|
|
sub Authenticate {
|
|
my $query = $::db->prepare("SELECT passwd, despot, neednewpassword, id, disabled FROM users WHERE email = ?");
|
|
$query->execute($F::loginname);
|
|
my @row = $query->fetchrow_array();
|
|
if (!@row || !checkpassword($F::loginpassword, $row[0])) {
|
|
PrintHeader();
|
|
print h1("Authentication Failed");
|
|
print p("I can't figure out who you are. Either your email address/password " .
|
|
"were entered incorrectly, or you didn't enter them. In any case, I " .
|
|
"need to know who you are before I let you do what you wanted to do, " .
|
|
"so please enter your email address and password now.");
|
|
if ($F::loginname && $F::loginname !~ /@/) {
|
|
print p("Note! You must type in your full e-mail address, including the '\@'.");
|
|
}
|
|
PrintLoginForm();
|
|
exit;
|
|
}
|
|
|
|
my $passwd;
|
|
my $disabled;
|
|
($passwd,$::candespot,$::neednewpassword,$::loginid,$disabled) = @row;
|
|
|
|
if ($disabled eq "Yes") {
|
|
Punt("Your account has been disabled.");
|
|
}
|
|
|
|
if ($::candespot eq "Yes") {
|
|
$::candespot = 1;
|
|
} else {
|
|
$::candespot = 0;
|
|
$::despot = 0;
|
|
}
|
|
|
|
if ($::neednewpassword eq "Yes") {
|
|
$::neednewpassword = 1;
|
|
} else {
|
|
$::neednewpassword = 0;
|
|
}
|
|
|
|
}
|
|
|
|
sub PrintHeader {
|
|
return if $::header_done;
|
|
|
|
print header();
|
|
|
|
my $bg = "white";
|
|
my $extra = "";
|
|
if ($::despot) {
|
|
$bg = "lightgreen";
|
|
$extra = " (Wonder-twin powers -- activate!)";
|
|
}
|
|
|
|
print start_html(-Title=>"Despot -- configure mozilla users$extra",
|
|
-BGCOLOR=>$bg);
|
|
|
|
$::header_done = 1;
|
|
}
|
|
|
|
|
|
sub PrintLoginForm {
|
|
# CGI seems to be misbehaving; creating the form tag manually as a workaround.
|
|
print qq|<form method="$::POSTTYPE" enctype="application/x-www-form-urlencoded">\n|;
|
|
# print start_form(-method=>$::POSTTYPE);
|
|
print table(Tr(th({-align=>"right"}, "Email address:"),
|
|
td(textfield(-name=>"loginname",
|
|
-size=>20))),
|
|
Tr(th({-align=>"right"}, "Password:"),
|
|
td(password_field(-name=>"loginpassword",
|
|
-size=>20))));
|
|
print submit(-name=>"Log in");
|
|
|
|
# Add all submitted values to the form (except email address and password,
|
|
# which we want them to retype) as hidden fields so the user can immediately
|
|
# do whatever they wanted to do upon logging in.
|
|
foreach my $field (param()) {
|
|
next if grep($field eq $_, qw(loginname loginpassword));
|
|
print hidden(-name=>$field, -default=>param($field));
|
|
}
|
|
|
|
print hr();
|
|
print p("If you think you should be able to use this system, but you haven't been issued a login, please send mail to " .
|
|
a({href=>$despotOwnerMailTo}, $despotOwner) . ".");
|
|
# print p("If you do not yet have a mozilla.org account, or you have one " .
|
|
# "but have forgotten your password, please fill in your e-mail " .
|
|
# "address above, and click <nobr>here: " .
|
|
# submit({name=>"mailMePassword"}, "Email me a password") . "</nobr>");
|
|
|
|
print end_form();
|
|
}
|
|
|
|
sub MainMenu {
|
|
print h1("Despot -- main menu");
|
|
print table({-width=>"100%"},
|
|
Tr(td(h3("What would you like to do?")) .
|
|
td({-align=>"right"}, a({-href=>"help.html"},
|
|
"Introduction to Despot"))));
|
|
|
|
my @list = ();
|
|
push(@list, li(MyForm("ViewAccount") .
|
|
submit("View info about your account") .end_form()));
|
|
push(@list, li(MyForm("ChangePassword") .
|
|
submit("Change your password") . end_form()));
|
|
push(@list, li(MyForm("ListPartitions") .
|
|
submit("List all the partitions") .end_form()));
|
|
# my $query = $::db->prepare("SELECT partitionid, partitions.name, repositories.name, repositories.id " .
|
|
# "FROM members, partitions, repositories " .
|
|
# "WHERE userid = ? " .
|
|
# "AND class != 'Member' " .
|
|
# "AND partitions.id = members.partitionid " .
|
|
# "AND repositories.id = partitions.repositoryid");
|
|
# $query->execute($::loginid);
|
|
# my @row;
|
|
# while (@row = $query->fetchrow_array()) {
|
|
# my ($partid,$partname,$repname,$repid) = (@row);
|
|
# my $title = "Edit partition '$partname' ($repname)";
|
|
# param("partitionid", $partid);
|
|
# push(@list,
|
|
# li(MyForm("EditPartition") . submit($title) .
|
|
# hidden(-name=>"partitionid") . end_form()));
|
|
# }
|
|
|
|
my $query = $::db->prepare("SELECT id, name FROM repositories ORDER BY name");
|
|
$query->execute();
|
|
my @vals = ();
|
|
my %labels;
|
|
while (my @row = $query->fetchrow_array()) {
|
|
my $v = $row[0];
|
|
push(@vals, $v);
|
|
$labels{$v} = $row[1];
|
|
}
|
|
my $radio = popup_menu(-name=>"repid",
|
|
"-values"=>\@vals,
|
|
-default=>$vals[0],
|
|
-labels=>\%labels);
|
|
push(@list, li(MyForm("FindPartition") .
|
|
submit("Find partition containing file") .
|
|
"named<nobr> " .
|
|
textfield(-name=>"file", -size=>60) .
|
|
"</nobr> in <nobr>repository " . $radio .
|
|
end_form()));
|
|
|
|
if ($::candespot) {
|
|
param("_despot", !$::despot);
|
|
my $str = $::despot ? "Disable" : "Enable";
|
|
push(@list,
|
|
li(MyForm("MainMenu") . submit("$str Despot Powers") .
|
|
end_form()));
|
|
param("_despot", $::despot);
|
|
if ($::despot) {
|
|
my @l2 = ();
|
|
my $opts = popup_menu(-name=>"matchtype",
|
|
"-values"=>["regexp", "not regexp"],
|
|
-default=>"regexp",
|
|
-labels=>{"regexp"=>"Matching regexp",
|
|
"not regexp"=>"Not matching regexp"});
|
|
push(@l2,
|
|
li("<nobr>" .
|
|
MyForm("ListUsers") . submit("List all users") .
|
|
$opts .
|
|
textfield(-name=>"match", -size=>50) .
|
|
"</nobr>" .
|
|
end_form()));
|
|
push(@l2,
|
|
li(MyForm("AddUser") . submit("Add or edit user") .
|
|
"with email<nobr> " .
|
|
textfield(-name=>"email", -size=>25) . "</nobr>" .
|
|
end_form()));
|
|
push(@l2,
|
|
li(MyForm("AddPartition") . submit("Create or edit partition")
|
|
. " named<nobr> " .
|
|
textfield(-name=>"partition", -size=>24) . "</nobr>" .
|
|
"</nobr> in <nobr>repository " . $radio .
|
|
end_form()));
|
|
push(@list, "Despot commands:" . ul(\@l2));
|
|
}
|
|
}
|
|
|
|
|
|
print ul(\@list);
|
|
|
|
if ($::neednewpassword) {
|
|
print "<font color=red>Your account has been frozen. To make it usable, you must change your password.</font>";
|
|
}
|
|
|
|
$::skiptrailer = 1;
|
|
}
|
|
|
|
|
|
sub AddUser() {
|
|
EnsureDespot();
|
|
if ($F::email eq "") {
|
|
Punt("You must enter an email address.");
|
|
}
|
|
my $email = $F::email;
|
|
my $query;
|
|
my @row;
|
|
if ($email !~ /$emailregexp/) {
|
|
Punt("Email addresses must contain exactly one '\@', and at least one '.' after the \@, and may not contain any pipes, ampersands, commas or spaces.");
|
|
}
|
|
|
|
$query = $::db->prepare("SELECT COUNT(*) FROM users WHERE email=?");
|
|
$query->execute($email);
|
|
@row = $query->fetchrow_array();
|
|
|
|
if ($row[0] < 1) {
|
|
my $p = "";
|
|
my $realname = "";
|
|
my $plain = pickrandompassword();
|
|
$p = cryptit($plain);
|
|
my $feedback = "'" . tt($plain) . "'";
|
|
my $mailwords = "of '$plain'";
|
|
my $sth = $::db->do("INSERT INTO users (email, passwd, neednewpassword, realname) VALUES (?,?,?,?)",
|
|
undef, $email, $p, 'Yes', $realname);
|
|
PrintHeader();
|
|
print p("New account created. Password initialized to $feedback; " .
|
|
"please " .
|
|
a({href=>"mailto:$email?subject=Change your mozilla.org password&body=Your new mozilla.org account has been created. It initially has a%0apassword $mailwords. Please go to http://despot.mozilla.org/despot.cgi%0aand change your password as soon as possible. You won't actually be%0aable to use it for anything until you do."},
|
|
"send mail") .
|
|
" and have the user change the password!");
|
|
print hr();
|
|
}
|
|
EditUser();
|
|
}
|
|
|
|
|
|
sub EditUser() {
|
|
EnsureDespot();
|
|
PrintHeader();
|
|
print h1("Edit a user");
|
|
my $query = $::db->prepare("SELECT * FROM users WHERE email=?");
|
|
$query->execute($F::email);
|
|
my @row;
|
|
@row = $query->fetchrow_array();
|
|
my $query2 = $::db->prepare("SHOW COLUMNS FROM users");
|
|
$query2->execute();
|
|
my @list;
|
|
my @desc;
|
|
for (my $i=0 ; $i<@row ; $i++) {
|
|
@desc = $query2->fetchrow_array();
|
|
my $line = th({-align=>"right"}, "$desc[0]:");
|
|
if ($desc[0] ne $query->{NAME}->[$i]) {
|
|
die "show columns in different order than select???";
|
|
}
|
|
$_ = $desc[1];
|
|
if (/^varchar/ || /int\([0-9]*\)$/) {
|
|
if ($desc[0] eq "voucher") {
|
|
$row[$i] = IdToEmail($row[$i]);
|
|
}
|
|
$line .= td(textfield(-name=>$query->{NAME}->[$i],
|
|
-default=>$row[$i],
|
|
-size=>50,
|
|
-override=>1));
|
|
} elsif (/^enum/) {
|
|
s/^enum\(//;
|
|
s/\)$//;
|
|
my @values = split(/,/);
|
|
my $opts = "";
|
|
for (my $j=0 ; $j<@values ; $j++) {
|
|
$values[$j] =~ s/^\'//;
|
|
$values[$j] =~ s/\'$//;
|
|
}
|
|
$line .= td(radio_group(-name=>$desc[0], "-values"=>\@values,
|
|
-default=>$row[$i]));
|
|
}
|
|
$line .= hidden("orig_$desc[0]", $row[$i]);
|
|
|
|
|
|
|
|
push(@list,Tr($line));
|
|
}
|
|
print MyForm("ChangeUser");
|
|
print table(@list);
|
|
print submit("Save changes");
|
|
print end_form();
|
|
print MyForm("GeneratePassword") . hidden(-name=>"email");
|
|
print submit("Generate a new random password for this user");
|
|
print end_form();
|
|
# DeleteUser is currently a bad idea, as it leaves dangling pointers.
|
|
# See bugzilla.mozilla.org bug 17589
|
|
#
|
|
# print MyForm("DeleteUser") . hidden(-name=>"email");
|
|
# print submit("Delete user");
|
|
# print end_form();
|
|
}
|
|
|
|
# DeleteUser is currently a bad idea, as it leaves dangling pointers.
|
|
# See bugzilla.mozilla.org bug 17589
|
|
#
|
|
#sub DeleteUser() {
|
|
# $::db->do("DELETE FROM users WHERE email = ?", undef, $F::email);
|
|
# $::db->do("INSERT INTO syncneeded (needed) VALUES (1)");
|
|
# PrintHeader();
|
|
# print h1("OK, $F::email is gone.");
|
|
# print hr();
|
|
# MainMenu();
|
|
#}
|
|
|
|
sub ChangeUser() {
|
|
foreach my $field ("email") {
|
|
my $value = param($field);
|
|
if ($value ne param("orig_$field")) {
|
|
# XXX: we need to sanitize $field before using it
|
|
my $query = $::db->prepare("SELECT COUNT(*) FROM users WHERE $field = ?");
|
|
$query->execute($value);
|
|
my @row;
|
|
@row = $query->fetchrow_array();
|
|
if ($row[0] > 0) {
|
|
Punt("Can't change $field to '$value'; already used.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
my $query = $::db->prepare("SHOW COLUMNS FROM users");
|
|
$query->execute();
|
|
my @list;
|
|
my @values;
|
|
my @row;
|
|
while (@row = $query->fetchrow_array()) {
|
|
my $old = param("orig_$row[0]");
|
|
my $new = param($row[0]);
|
|
if ($old ne $new) {
|
|
if ($row[0] eq "voucher") {
|
|
$old = EmailToId($old);
|
|
$new = EmailToId($new);
|
|
}
|
|
$::db->do("INSERT INTO CHANGES (email, field, oldvalue, newvalue, who) VALUES (?,?,?,?,?)",
|
|
undef, $F::orig_email, $row[0], $old, $new, $F::loginname);
|
|
}
|
|
push(@list, "$row[0] = ?");
|
|
push(@values, $new);
|
|
}
|
|
my $qstr = "UPDATE users SET " . join(",", @list) . " WHERE email = ?";
|
|
$::db->do($qstr, undef, @values, $F::orig_email);
|
|
PrintHeader();
|
|
print h1("OK, record for $F::email has been updated.");
|
|
print hr();
|
|
MainMenu();
|
|
$::db->do("INSERT INTO syncneeded (needed) VALUES (1)");
|
|
}
|
|
|
|
sub GeneratePassword {
|
|
my $email = $F::email;
|
|
Punt("Email address is too scary for this web application") unless $email =~ /$emailregexp/;
|
|
my $query = $::db->prepare("SELECT id FROM users WHERE email = ?");
|
|
$query->execute($email);
|
|
Punt("$email is not an email address in the database.") unless ($query->fetchrow_array());
|
|
my $plain = pickrandompassword();
|
|
my $p = cryptit($plain);
|
|
$::db->do("UPDATE users SET passwd = ?, neednewpassword='Yes' WHERE email = ?",
|
|
undef, $p, $email);
|
|
PrintHeader();
|
|
print h1("OK, new password generated.");
|
|
print "$email now has a new password of '" . tt($plain) . "'. ";
|
|
print "Please " .
|
|
a({href=>"mailto:$email?subject=Change your mozilla.org password&body=Your mozilla.org account now has a password of '$plain'. Please go to%0ahttp://despot.mozilla.org/despot.cgi and change your password as soon as%0apossible. You won't actually be able to use your mozilla.org account%0afor anything until you do."},
|
|
"send mail") .
|
|
" to have the user change the password!";
|
|
$::db->do("INSERT INTO syncneeded (needed) VALUES (1)");
|
|
}
|
|
|
|
|
|
|
|
|
|
sub ListPartitions () {
|
|
PrintHeader();
|
|
print p("If you're wondering what a 'partition' is, " .
|
|
a({-href=>"help.html#partition"}, "read this") . ".");
|
|
ListSomething("partitions", "id", "ListPartitions", "EditPartition", "name",
|
|
"name,repositoryid,state,description", "",
|
|
{"branchid"=>["branches.name",
|
|
"branches.id=partitions.branchid"],
|
|
"repositoryid"=>["repositories.name",
|
|
"repositories.id=partitions.repositoryid"]
|
|
},
|
|
"");
|
|
}
|
|
|
|
|
|
sub ListUsers() {
|
|
EnsureDespot();
|
|
|
|
PrintHeader();
|
|
# ListSomething("users", "email", "ListUsers", "EditUser", "email", "email,realname,gila_group,cvs_group", "users as u2", {"voucher"=>"u2.email,u2.id=users.voucher"});
|
|
my $wherepart = "";
|
|
if ($F::match ne "") {
|
|
# very very narrow whitelist for matchtype.
|
|
my $matchtype = $F::matchtype eq 'not regexp' ? 'not regexp' : 'regexp';
|
|
$wherepart = "email $matchtype " . $::db->quote($F::match);
|
|
}
|
|
ListSomething("users", "email", "ListUsers", "EditUser", "email", "email,realname,gila_group,cvs_group", "users as u2", {"voucher"=>["if(users.voucher=0,'NONE',u2.email)", "u2.id=if(users.voucher=0,users.id,users.voucher)", "u2"]}, $wherepart);
|
|
}
|
|
|
|
|
|
sub ListSomething {
|
|
my ($tablename,$idcolumn,$listprocname,$editprocname,$defaultsortorder,
|
|
$defaultcolumns,$extratables,$columndefs,$extrawhere) = (@_);
|
|
|
|
|
|
my %columnremap;
|
|
my %columnwhere;
|
|
my %columntable;
|
|
|
|
while (my ($key,$value) = each %$columndefs) {
|
|
($columnremap{$key}, $columnwhere{$key}, $columntable{$key}) = (@$value);
|
|
if (!defined $columntable{$key}) {
|
|
$columntable{$key} = $columnremap{$key};
|
|
$columntable{$key} =~ s/\..*$//;
|
|
}
|
|
}
|
|
|
|
print h1("List of $tablename");
|
|
my $query = $::db->prepare("SHOW COLUMNS FROM $tablename");
|
|
$query->execute();
|
|
my @allcols = ();
|
|
my @cols = ();
|
|
while (@row = $query->fetchrow_array()) {
|
|
push(@allcols, $row[0]);
|
|
}
|
|
|
|
my $sortorder = $defaultsortorder;
|
|
if (defined $F::sortorder) {
|
|
$sortorder = $F::sortorder;
|
|
my @sortorder = ();
|
|
my @passedsortorder = split(",",$sortorder);
|
|
foreach my $column (@passedsortorder) {
|
|
my $dir = "";
|
|
if ($column =~ m/(\S+)( ASC| DESC)$/i) {
|
|
($column, $dir) = ($1, $2);
|
|
}
|
|
if (!grep {$column eq $_} @allcols) {
|
|
die "Invalid sort order passed";
|
|
}
|
|
push @sortorder, $column.$dir;
|
|
}
|
|
$sortorder = join(",",@sortorder);
|
|
}
|
|
|
|
my $hiddencols = "";
|
|
if (defined @F::showcolumns) {
|
|
@cols = @F::showcolumns;
|
|
foreach my $c (@cols) {
|
|
$hiddencols .= hidden(-name=>"showcolumns",
|
|
-default=>$c,
|
|
-override=>1);
|
|
}
|
|
}
|
|
|
|
if (0 == @cols) {
|
|
@cols = split(/,/, $defaultcolumns);
|
|
}
|
|
|
|
my $rtext = th();
|
|
my @list = ();
|
|
my @emaillist = ();
|
|
my $hiddenbits = "";
|
|
if (defined $F::matchtype) {
|
|
$hiddenbits .= hidden(-name=>"matchtype");
|
|
}
|
|
if (defined $F::match) {
|
|
$hiddenbits .= hidden(-name=>"match");
|
|
}
|
|
|
|
foreach my $c (@cols) {
|
|
if ($c eq $sortorder) {
|
|
$rtext .= th({-valign=>"top"}, "sorted by<br>$c");
|
|
} else {
|
|
$rtext .= th({-valign=>"top"},
|
|
MyForm($listprocname) .
|
|
submit($c) .
|
|
$hiddenbits .
|
|
$hiddencols .
|
|
hidden(-name=>"sortorder",
|
|
-default=>$c,
|
|
-override=>1) .
|
|
end_form());
|
|
}
|
|
if (!defined $columnremap{$c}) {
|
|
$columnremap{$c} = "$tablename.$c";
|
|
$columntable{$c} = $tablename;
|
|
}
|
|
}
|
|
|
|
push(@list, $rtext);
|
|
my @mungedcols;
|
|
my %usedtables;
|
|
my $wherepart = "";
|
|
if (defined $extrawhere && $extrawhere ne "") {
|
|
$wherepart = " WHERE " . $extrawhere;
|
|
}
|
|
foreach my $c (@cols) {
|
|
my $t = $columnremap{$c};
|
|
push(@mungedcols,$t);
|
|
$usedtables{$columntable{$c}} = 1;
|
|
if (defined $columnwhere{$c}) {
|
|
if ($wherepart eq "") {
|
|
$wherepart = " WHERE ";
|
|
} else {
|
|
$wherepart .= " AND ";
|
|
}
|
|
$wherepart .= $columnwhere{$c};
|
|
}
|
|
}
|
|
if ($extratables ne "") {
|
|
foreach my $i (split(/,/, $extratables)) {
|
|
$usedtables{$i} = 1;
|
|
if ($i =~ m/as (.*)$/) {
|
|
if (exists $usedtables{$1}) {
|
|
delete $usedtables{$1};
|
|
} else {
|
|
delete $usedtables{$i};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
my $orderby = $columnremap{$sortorder};
|
|
if ($orderby =~ /\(/) {
|
|
# The sort order is too complicated for stupid SQL. Pick something
|
|
# simpler.
|
|
$orderby = "$tablename.$sortorder";
|
|
}
|
|
# XXX: need to verify where the callers are getting the values they pass in here.
|
|
# no clue if it's been sanitized or not, and we can't use placeholders because of
|
|
# the way it's been passed in.
|
|
$query = $::db->prepare("SELECT $tablename.$idcolumn," . join(",", @mungedcols) . " FROM " . join(",", keys(%usedtables)) . $wherepart . " ORDER BY $orderby");
|
|
$query->execute();
|
|
while (@row = $query->fetchrow_array()) {
|
|
my $i;
|
|
for ($i=1 ; $i<@row ; $i++) {
|
|
if (!defined $row[$i]) {
|
|
$row[$i] = "";
|
|
}
|
|
}
|
|
my $thisid = shift(@row);
|
|
push(@emaillist, $thisid);
|
|
push(@list, td(MyForm($editprocname) . hidden($idcolumn, $thisid) .
|
|
submit("Edit") . end_form()) .
|
|
td(\@row));
|
|
}
|
|
print table(Tr(\@list));
|
|
if ($idcolumn eq "email") {
|
|
my $mailtolist = "mailto:" . join(',', @emaillist);
|
|
print p(a({href=>$mailtolist},"Send mail to all users"));
|
|
}
|
|
print hr();
|
|
print MyForm($listprocname);
|
|
print submit("Redisplay with the following columns:") . br();
|
|
print checkbox_group(-name=>"showcolumns",
|
|
"-values"=>\@allcols,
|
|
-default=>\@cols,
|
|
-linebreak=>'true');
|
|
print hidden(-name=>"sortorder", -default=>$sortorder, -override=>1);
|
|
print $hiddenbits;
|
|
print end_form();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sub ViewAccount {
|
|
my $query = $::db->prepare("SELECT * FROM users WHERE email = ?");
|
|
$query->execute($F::loginname);
|
|
my @row;
|
|
@row = $query->fetchrow_array();
|
|
my $query2 = $::db->prepare("SHOW COLUMNS FROM users");
|
|
$query2->execute();
|
|
my @list;
|
|
my @desc;
|
|
my $userid;
|
|
for (my $i=0 ; $i<@row ; $i++) {
|
|
@desc = $query2->fetchrow_array();
|
|
my $line = th({-align=>"right"}, "$desc[0]:");
|
|
if ($desc[0] ne $query->{NAME}->[$i]) {
|
|
die "show columns in different order than select???";
|
|
}
|
|
if ($desc[0] eq "voucher") {
|
|
$row[$i] = IdToEmail($row[$i]);
|
|
}
|
|
$line .= td($row[$i]);
|
|
push(@list,Tr($line));
|
|
}
|
|
PrintHeader();
|
|
print table(@list);
|
|
$query = $::db->prepare("SELECT partitions.id, repositories.name, partitions.name, class " .
|
|
"FROM members, repositories, partitions " .
|
|
"WHERE members.userid = ? " .
|
|
"AND partitions.id = members.partitionid " .
|
|
"AND repositories.id = partitions.repositoryid " .
|
|
"ORDER BY class");
|
|
$query->execute($::loginid);
|
|
while (@row = $query->fetchrow_array()) {
|
|
my ($partid, $repname,$partname,$class) = (@row);
|
|
param("partitionid", $partid);
|
|
print MyForm("EditPartition") . hidden("partitionid") .
|
|
submit("$class of $partname ($repname)") . end_form();
|
|
}
|
|
|
|
if ($::despot) {
|
|
print MyForm("EditUser") . hidden("email", $F::loginname) .
|
|
submit("Edit your account") .
|
|
"(Since you're a despot, you can do this)" .
|
|
end_form();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
sub FindPartition {
|
|
my $repid = $F::repid;
|
|
my $file = $F::file;
|
|
# Excludes the mozilla-toplevel module which would otherwise always match.
|
|
# XXX: installation-specific stuff hardcoded here! (fix eventually)
|
|
my $query = $::db->prepare("SELECT files.pattern, partitions.name, partitions.id " .
|
|
"FROM files, partitions " .
|
|
"WHERE partitions.id = files.partitionid " .
|
|
"AND partitions.repositoryid = ? " .
|
|
"AND files.pattern != 'mozilla/%'");
|
|
$query->execute($repid);
|
|
my @matches = ();
|
|
while (@row = $query->fetchrow_array()) {
|
|
my ($pattern,$name,$id) = (@row);
|
|
if (FileMatches($file, $pattern) || FileMatches($pattern, $file)) {
|
|
push(@matches, { 'name' => $name, 'id' => $id, 'pattern' => $pattern });
|
|
}
|
|
elsif ($file !~ /^mozilla(-org)?\//
|
|
&& (FileMatches("mozilla/$file", $pattern)
|
|
|| FileMatches($pattern, "mozilla/$file")
|
|
|| FileMatches("mozilla-org/$file", $pattern)
|
|
|| FileMatches($pattern, "mozilla-org/$file")))
|
|
{
|
|
push(@matches, { 'name' => $name, 'id' => $id, 'pattern' => $pattern });
|
|
}
|
|
}
|
|
|
|
if (scalar(@matches) > 0) {
|
|
# The "view" parameter means the request came from the "look up owners of file"
|
|
# form on the owners page, so we should redirect the user to the anchor on that
|
|
# page for a single match.
|
|
if (scalar(@matches) == 1 && param("view")) {
|
|
print "Location: http://www.mozilla.org/owners.html#" . name_to_id_token($matches[0]->{name}) . "\n\n";
|
|
exit;
|
|
}
|
|
PrintHeader();
|
|
print h1("Searching for partitions matching $file ...");
|
|
foreach my $match (@matches) {
|
|
if (param("view")) {
|
|
# This should display modules just as they are displayed
|
|
# on owners.html, but that code is embedded into syncit.pl.
|
|
print qq|Module: <a href="http://www.mozilla.org/owners.html#| .
|
|
name_to_id_token($match->{name}) . qq|">$match->{name}</a>
|
|
(matches pattern $match->{pattern})<br>\n|;
|
|
}
|
|
else {
|
|
print MyForm("EditPartition") .
|
|
hidden("partitionid", $match->{id}) .
|
|
submit($match->{name}) .
|
|
"(matches pattern $match->{pattern})" .
|
|
end_form();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PrintHeader();
|
|
print h1("Searching for partitions matching $file ...");
|
|
print "No partitions found.";
|
|
}
|
|
|
|
if (param("view")) {
|
|
# No need for the footer with the "Main Menu" button
|
|
# for "look up owners of file" users.
|
|
print "</body></html>\n";
|
|
exit;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub AddPartition {
|
|
EnsureDespot();
|
|
my $partition = $F::partition;
|
|
if ($partition eq "") {
|
|
Punt("You must enter a partition name.");
|
|
}
|
|
Punt("Partition may only contain letters, numbers, spaces, dashes, ampersands, and colons") unless $partition =~ /$partregexp/;
|
|
my $repid = $F::repid;
|
|
my $query;
|
|
my @row;
|
|
|
|
$query = $::db->prepare("SELECT id FROM partitions WHERE repositoryid = ? AND name = ?");
|
|
$query->execute($repid, $partition);
|
|
|
|
if (!(@row = $query->fetchrow_array())) {
|
|
$::db->do("INSERT INTO partitions (name, repositoryid, state, branchid) VALUES (?,?,?,?)",
|
|
undef, $partition, $repid, 'Open', 1);
|
|
PrintHeader();
|
|
print p("New partition created.") . hr();
|
|
my $query2 = $::db->prepare("SELECT LAST_INSERT_ID()");
|
|
$query2->execute();
|
|
@row = $query2->fetchrow_array();
|
|
}
|
|
|
|
$F::partitionid = $row[0];
|
|
EditPartition();
|
|
}
|
|
|
|
sub EditPartition() {
|
|
my $partitionid;
|
|
if (defined $F::partitionid) {
|
|
$partitionid = $F::partitionid;
|
|
} else {
|
|
$partitionid = $F::id;
|
|
}
|
|
my $canchange = CanChangePartition($partitionid);
|
|
my $query = $::db->prepare("SELECT partitions.name, partitions.description, state, " .
|
|
"repositories.name, repositories.id, branches.name, " .
|
|
"newsgroups, doclinks " .
|
|
"FROM partitions, repositories, branches " .
|
|
"WHERE partitions.id = ? " .
|
|
"AND repositories.id = repositoryid " .
|
|
"AND branches.id = branchid");
|
|
$query->execute($partitionid);
|
|
|
|
my ($partname,$partdesc,$state,$repname,$repid,$branchname,$newsgroups,
|
|
$doclinks) = $query->fetchrow_array();
|
|
PrintHeader();
|
|
print h1(($canchange ? "Edit" : "View") . " partition -- $partname");
|
|
if (!$canchange) {
|
|
print p(b("You can't change anything here!") .
|
|
" You can look, but you won't be permitted to touch.");
|
|
}
|
|
|
|
if ($partname eq "default") {
|
|
print "<font color=red>This is the magic default partition. It gets consulted on any file that does not match any other partition.</font>";
|
|
}
|
|
|
|
my @list;
|
|
|
|
push(@list, Tr(th("Repository:") . td($repname)));
|
|
|
|
push(@list, Tr(th("Description:") . td(textarea(-name=>"description",
|
|
-default=>$partdesc,
|
|
-rows=>4,
|
|
-columns=>50))));
|
|
|
|
push(@list, Tr(th("Newsgroups:"),
|
|
td(textfield(-name=>'newsgroups',
|
|
-default=>$newsgroups,
|
|
-size=>30,
|
|
-override=>1))));
|
|
|
|
push(@list, Tr(th("Doc links:"),
|
|
td(textarea(-name=>'doclinks',
|
|
-default=>$doclinks,
|
|
-rows=>10,
|
|
-columns=>50,
|
|
-override=>1))));
|
|
|
|
|
|
push(@list,
|
|
Tr(th(a({-href=>"help.html#state"},"State:")) .
|
|
td(radio_group(-name=>'state',
|
|
"-values"=>['Open', 'Restricted', 'Closed'],
|
|
-default=>$state,
|
|
-linebreak=>'false'))));
|
|
|
|
push(@list,
|
|
Tr(th(a({-href=>"help.html#branch"}, "Branch:")),
|
|
td(textfield(-name=>'branchname',
|
|
-default=>$branchname,
|
|
-size=>30,
|
|
-override=>1))));
|
|
|
|
$query = $::db->prepare("SELECT pattern FROM files WHERE partitionid = " .
|
|
$::db->quote($partitionid) . " ORDER BY pattern");
|
|
push(@list, CreateListRow("files", $query));
|
|
foreach my $class ("Owner", "Peer", "Member") {
|
|
$query = $::db->prepare("SELECT users.email, users.disabled " .
|
|
"FROM members, users " .
|
|
"WHERE members.partitionid = " . $::db->quote($partitionid) .
|
|
" AND members.class = " . $::db->quote($class) .
|
|
" AND users.id = members.userid " .
|
|
"ORDER BY users.email");
|
|
push(@list, CreateListRow($class, $query));
|
|
}
|
|
|
|
|
|
param("partitionid", $partitionid);
|
|
param("repid", $repid);
|
|
param("repname", $repname);
|
|
my $h = hidden(-name=>"partitionid") .
|
|
hidden(-name=>"repid") .
|
|
hidden(-name=>"repname");
|
|
|
|
print MyForm("ChangePartition");
|
|
print table(@list);
|
|
if ($canchange) {
|
|
print submit("Save changes");
|
|
print $h;
|
|
print end_form();
|
|
print MyForm("DeletePartition");
|
|
print submit("Delete partition");
|
|
print $h;
|
|
}
|
|
print end_form();
|
|
}
|
|
|
|
sub ChangePartition {
|
|
my $query;
|
|
my @row;
|
|
|
|
EnsureCanChangePartition($F::partitionid);
|
|
my $partitionid = $F::partitionid;
|
|
|
|
$::db->do("LOCK TABLES partitions WRITE, branches WRITE, files WRITE, members WRITE, users READ");
|
|
|
|
# Sanity checking first...
|
|
|
|
my @files = split(/\n/, $F::files);
|
|
|
|
$query = $::db->prepare("SELECT files.pattern, partitions.name " .
|
|
"FROM files, partitions, branches " .
|
|
"WHERE files.partitionid != ? " .
|
|
"AND partitions.id = files.partitionid " .
|
|
"AND partitions.repositoryid = ? " .
|
|
"AND branches.id = partitions.branchid " .
|
|
"AND branches.name = ?");
|
|
$query->execute($F::partitionid, $F::repid, $F::branchname);
|
|
while (@row = $query->fetchrow_array()) {
|
|
my $f1 = $row[0];
|
|
foreach my $f2 (@files) {
|
|
$f2 = trim($f2);
|
|
if ($f2 eq "") {
|
|
next;
|
|
}
|
|
if (FileMatches($f1, $f2) || FileMatches($f2, $f1)) {
|
|
Punt("File rule $f2 overlaps with existing rule in partition $row[1]");
|
|
}
|
|
}
|
|
}
|
|
|
|
my %idhash;
|
|
foreach my $class ("Owner", "Peer", "Member") {
|
|
my @names = split(/\n/, param($class));
|
|
foreach my $n (@names) {
|
|
$n =~ s/\(.*\)//g;
|
|
$n = trim($n);
|
|
if ($n eq "") {
|
|
next;
|
|
}
|
|
# XXX: need to sanitize $F::repname
|
|
$query = $::db->prepare("SELECT id, ${F::repname}_group FROM users WHERE email = ?");
|
|
$query->execute($n);
|
|
if (!(@row = $query->fetchrow_array())) {
|
|
Punt("$n is not an email address in the database.");
|
|
}
|
|
my ($userid,$group) = (@row);
|
|
if (exists $idhash{$n}) {
|
|
Punt("$n seems to be mentioned more than once. A given user can only have one class.");
|
|
}
|
|
$idhash{$n} = $userid;
|
|
if ($group eq "None") {
|
|
Punt("$n is not allowed to use the $F::repname repository at all, so it doesn't make sense to put this user into this partition.");
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# And now actually update things.
|
|
|
|
$query = $::db->prepare("SELECT id FROM branches WHERE name = ?");
|
|
$query->execute($F::branchname);
|
|
if (!(@row = $query->fetchrow_array())) {
|
|
$::db->do("INSERT INTO branches (name) VALUES (?)",
|
|
undef, $F::branchname);
|
|
$query = $::db->prepare("SELECT LAST_INSERT_ID()");
|
|
$query->execute();
|
|
@row = $query->fetchrow_array();
|
|
}
|
|
my $branchid = $row[0];
|
|
$::db->do("UPDATE partitions SET description = ?, " .
|
|
"branchid = ?, " .
|
|
"state = ?, " .
|
|
"newsgroups = ?, " .
|
|
"doclinks = ? " .
|
|
"WHERE id = ?",
|
|
undef, $F::description, $branchid, $F::state, $F::newsgroups, $F::doclinks, $F::partitionid);
|
|
|
|
$::db->do("DELETE FROM files WHERE partitionid = ?", undef, $F::partitionid);
|
|
foreach my $f2 (@files) {
|
|
$f2 = trim($f2);
|
|
if ($f2 eq "") {
|
|
next;
|
|
}
|
|
$::db->do("INSERT INTO files (partitionid, pattern) VALUES (?, ?)",
|
|
undef, $F::partitionid, $f2);
|
|
}
|
|
|
|
$::db->do("DELETE FROM members WHERE partitionid = ?", undef, $F::partitionid);
|
|
foreach my $class ("Owner", "Peer", "Member") {
|
|
my @names = split(/\n/, param($class));
|
|
foreach my $n (@names) {
|
|
$n =~ s/\(.*\)//g;
|
|
$n = trim($n);
|
|
if ($n eq "") {
|
|
next;
|
|
}
|
|
$::db->do("INSERT INTO members (userid, partitionid, class) VALUES (?, ?, ?)",
|
|
undef, $idhash{$n}, $F::partitionid, $class);
|
|
}
|
|
}
|
|
|
|
PrintHeader();
|
|
print h1("OK, the partition has been updated.");
|
|
print hr();
|
|
$::db->do("UNLOCK TABLES");
|
|
MainMenu();
|
|
|
|
$::db->do("INSERT INTO syncneeded (needed) VALUES (1)");
|
|
}
|
|
|
|
|
|
sub DeletePartition() {
|
|
EnsureCanChangePartition($F::partitionid);
|
|
my $partitionid = $F::partitionid;
|
|
|
|
$::db->do("DELETE FROM partitions WHERE id = ?", undef, $F::partitionid);
|
|
$::db->do("DELETE FROM files WHERE partitionid = ?", undef, $F::partitionid);
|
|
$::db->do("DELETE FROM members WHERE partitionid = ?", undef, $F::partitionid);
|
|
$::db->do("INSERT INTO syncneeded (needed) VALUES (1)");
|
|
PrintHeader();
|
|
print h1("OK, the partition is gone.");
|
|
print hr();
|
|
MainMenu();
|
|
}
|
|
|
|
sub FileMatches {
|
|
my ($pattern, $name) = (@_);
|
|
my $regexp = $pattern;
|
|
if ($pattern =~ /\%$/) {
|
|
$regexp =~ s:\%$:[^/]*\$:;
|
|
} elsif ($pattern =~ /\*$/) {
|
|
$regexp =~ s:\*$:.*:;
|
|
}
|
|
if ($name =~ /$regexp/) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
sub CreateListRow {
|
|
my ($title, $query) = (@_);
|
|
my $result = "";
|
|
my @row;
|
|
$query->execute();
|
|
while (my @row = $query->fetchrow_array()) {
|
|
my $v = $row[0];
|
|
if (defined $row[1] && $row[1] eq "Yes") {
|
|
$v .= " (disabled)";
|
|
}
|
|
$result .= $v . "\n";
|
|
}
|
|
return Tr(th(a({-href=>"help.html#$title"}, "$title:")) .
|
|
td(textarea(-name=>$title,
|
|
-default=>$result,
|
|
-rows=>10,
|
|
-columns=>50)));
|
|
}
|
|
|
|
|
|
|
|
sub ChangePassword {
|
|
PrintHeader();
|
|
print h1("Change your mozilla.org password.");
|
|
$F::loginpassword = "";
|
|
# CGI seems to be misbehaving; creating the form tag manually as a workaround.
|
|
print qq|<form method="$::POSTTYPE" enctype="application/x-www-form-urlencoded">\n|;
|
|
# print start_form(-method=>$::POSTTYPE);
|
|
print hidden("loginname", $F::loginname);
|
|
print hidden(-name=>"command",
|
|
-default=>"SetNewPassword",
|
|
-override=>1);
|
|
print table(Tr(th({-align=>"right"}, "Old password:"),
|
|
td(password_field(-name=>"loginpassword", -size=>20,
|
|
-override=>1))),
|
|
Tr(th({-align=>"right"}, "New password:"),
|
|
td(password_field(-name=>"newpassword1", -size=>20))),
|
|
Tr(th({-align=>"right"}, "Retype new password:"),
|
|
td(password_field(-name=>"newpassword2", -size=>20))));
|
|
print submit("Change password");
|
|
print end_form();
|
|
}
|
|
|
|
|
|
sub SetNewPassword {
|
|
if ($F::newpassword1 ne $F::newpassword2) {
|
|
Punt("New passwords didn't match.");
|
|
}
|
|
if ($F::newpassword1 eq $F::loginpassword) {
|
|
Punt("Your new password isn't any different than your old one.");
|
|
}
|
|
my $z1;
|
|
my $salt = "";
|
|
my $pass = cryptit($F::newpassword1, $salt);
|
|
|
|
$::db->do("UPDATE users SET passwd = ?, neednewpassword = 'No' WHERE email = ?",
|
|
undef, $pass, $F::loginname);
|
|
PrintHeader();
|
|
print h1("Password has been updated.");
|
|
$::db->do("INSERT INTO syncneeded (needed) VALUES (1)");
|
|
if ($::despot) {
|
|
param("loginpassword", $F::newpassword1);
|
|
print hr();
|
|
MainMenu();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sub MyForm {
|
|
my ($command) = @_;
|
|
# CGI seems to be misbehaving; creating the form tag manually as a workaround.
|
|
my $result = qq|<form method="$::POSTTYPE" enctype="application/x-www-form-urlencoded">| .
|
|
hidden("loginname", $F::loginname) .
|
|
hidden("_despot") .
|
|
hidden("loginpassword", $F::loginpassword) .
|
|
hidden(-name=>"command", -value=>$command, -override=>1);
|
|
return $result;
|
|
}
|
|
|
|
sub Punt {
|
|
my ($header) = @_;
|
|
PrintHeader();
|
|
print h1($header);
|
|
print p("Please hit " . b("back") . " and try again.");
|
|
exit;
|
|
}
|
|
|
|
|
|
sub EnsureDespot {
|
|
if (!$::despot) {
|
|
Punt("You're not a despot. You can't do this.");
|
|
}
|
|
}
|
|
|
|
|
|
sub EnsureCanChangePartition {
|
|
my ($id) = (@_);
|
|
Punt("Invalid partitionid.") unless $id =~ /$partidregexp/;
|
|
if (!CanChangePartition($id)) {
|
|
Punt("You must be an Owner or Peer of the partition to do this.");
|
|
}
|
|
}
|
|
|
|
|
|
sub CanChangePartition {
|
|
my ($id) = (@_);
|
|
if ($::despot) {
|
|
return 1;
|
|
}
|
|
my $query = $::db->prepare("SELECT class FROM members WHERE userid = ? AND partitionid = ?");
|
|
$query->execute($::loginid, $id);
|
|
my @row;
|
|
if (@row = $query->fetchrow_array()) {
|
|
if ($row[0] ne "Member") {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
sub pickrandompassword {
|
|
my $sc = "abcdefghijklmnopqrstuvwxyz";
|
|
my $result = "";
|
|
for (my $i=0 ; $i<8 ; $i++) {
|
|
$result .= substr($sc, int (rand () * 100000) % (length ($sc) + 1), 1);
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
sub IdToEmail {
|
|
my ($id) = (@_);
|
|
if ($id eq "0") {
|
|
return "(none)";
|
|
} else {
|
|
my $query3 =
|
|
$::db->prepare("SELECT email, disabled FROM users WHERE id = ?");
|
|
$query3->execute($id);
|
|
my @row3;
|
|
if (@row3 = $query3->fetchrow_array()) {
|
|
if ($row3[1] eq "Yes") {
|
|
$row3[0] .= " (Disabled)";
|
|
}
|
|
return $row3[0];
|
|
}
|
|
}
|
|
|
|
return "<font color=red>Unknown Id $id</font>";
|
|
}
|
|
|
|
sub EmailToId {
|
|
my ($email, $forcevalid) = (@_);
|
|
|
|
$email =~ s/\(.*\)//g;
|
|
$email = trim($email);
|
|
|
|
my $query = $::db->prepare("SELECT id FROM users WHERE email = ?");
|
|
$query->execute($email);
|
|
my @row;
|
|
if (@row = $query->fetchrow_array()) {
|
|
return $row[0];
|
|
}
|
|
if ($forcevalid || $email ne "") {
|
|
Punt("$email is not a registered email address.");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
{
|
|
my $EnableDeleteUser = 0;
|
|
for ( defined $F::command ? $F::command : 'MainMenu')
|
|
{
|
|
/^FindPartition$/ || do { Authenticate(); };
|
|
param("command", "");
|
|
/^AddPartition$/ && do { AddPartition(); last; };
|
|
/^AddUser$/ && do { AddUser(); last; };
|
|
/^ChangePartition$/ && do { ChangePartition(); last; };
|
|
/^ChangePassword$/ && do { ChangePassword(); last; };
|
|
/^ChangeUser$/ && do { ChangeUser(); last; };
|
|
/^DeletePartition$/ && do { DeletePartition(); last; };
|
|
/^DeleteUser$/ && $EnableDeleteUser && do { DeleteUser(); last; };
|
|
/^EditPartition$/ && do { EditPartition(); last; };
|
|
/^EditUser$/ && do { EditUser(); last; };
|
|
/^FindPartition$/ && do { FindPartition(); last; };
|
|
/^GeneratePassword$/ && do { GeneratePassword(); last; };
|
|
/^ListPartitions$/ && do { ListPartitions(); last; };
|
|
/^ListUsers$/ && do { ListUsers(); last; };
|
|
/^SetNewPassword$/ && do { SetNewPassword(); last; };
|
|
/^ViewAccount$/ && do { ViewAccount(); last; };
|
|
/^MainMenu$|/ && do { PrintHeader(), MainMenu(); last; };
|
|
}
|
|
}
|
|
|
|
|
|
if (!$::skiptrailer) {
|
|
print hr();
|
|
print MyForm("MainMenu") . submit("Main menu") . end_form();
|
|
}
|
|
|
|
$query = $::db->prepare("SELECT needed FROM syncneeded WHERE needed = 1");
|
|
$query->execute();
|
|
@row = $query->fetchrow_array();
|
|
if ($row[0]) {
|
|
print hr();
|
|
print p("Updating external machines...");
|
|
print "<PRE>";
|
|
if (!open(DOSYNC, "./syncit.pl -user $F::loginname|")) {
|
|
print p("Can't do sync (error $?). Please send mail to " .
|
|
a({href=>$despotOwnerMailTo}, $despotOwner) . ".");
|
|
} else {
|
|
while (<DOSYNC>) {
|
|
if ($::despot) {
|
|
s/\&/\&/g;
|
|
s/</\</g;
|
|
s/>/\>/g;
|
|
print $_;
|
|
}
|
|
}
|
|
close(DOSYNC);
|
|
}
|
|
print "</PRE>";
|
|
print p("... update completed.");
|
|
}
|