diff options
-rw-r--r-- | Bugzilla/Install.pm | 125 | ||||
-rwxr-xr-x | checksetup.pl | 231 | ||||
-rw-r--r-- | template/en/default/global/messages.html.tmpl | 20 |
3 files changed, 157 insertions, 219 deletions
diff --git a/Bugzilla/Install.pm b/Bugzilla/Install.pm index d8fc47894..43981da02 100644 --- a/Bugzilla/Install.pm +++ b/Bugzilla/Install.pm @@ -26,8 +26,11 @@ package Bugzilla::Install; use strict; +use Bugzilla::Constants; +use Bugzilla::Error; use Bugzilla::Group; use Bugzilla::Product; +use Bugzilla::User; use Bugzilla::User::Setting; use Bugzilla::Version; @@ -136,6 +139,128 @@ sub create_default_product { } +sub create_admin { + my ($params) = @_; + my $dbh = Bugzilla->dbh; + my $template = Bugzilla->template; + + my $admin_group = new Bugzilla::Group({ name => 'admin' }); + my $admin_inheritors = + Bugzilla::User->flatten_group_membership($admin_group->id); + my $admin_group_ids = join(',', @$admin_inheritors); + + my ($admin_count) = $dbh->selectrow_array( + "SELECT COUNT(*) FROM user_group_map + WHERE group_id IN ($admin_group_ids)"); + + return if $admin_count; + + my %answer = %{$params->{answer} || {}}; + my $login = $answer{'ADMIN_EMAIL'}; + my $password = $answer{'ADMIN_PASSWORD'}; + my $full_name = $answer{'ADMIN_REALNAME'}; + + if (!$login || !$password || !$full_name) { + print "\n" . get_text('install_admin_setup') . "\n\n"; + } + + while (!$login) { + print get_text('install_admin_get_email') . ' '; + $login = <STDIN>; + chomp $login; + eval { Bugzilla::User->check_login_name_for_creation($login); }; + if ($@) { + print $@ . "\n"; + undef $login; + } + } + + while (!defined $full_name) { + print get_text('install_admin_get_name') . ' '; + $full_name = <STDIN>; + chomp($full_name); + } + + while (!$password) { + # trap a few interrupts so we can fix the echo if we get aborted. + local $SIG{HUP} = \&_create_admin_exit; + local $SIG{INT} = \&_create_admin_exit; + local $SIG{QUIT} = \&_create_admin_exit; + local $SIG{TERM} = \&_create_admin_exit; + + system("stty","-echo") unless ON_WINDOWS; # disable input echoing + + print get_text('install_admin_get_password') . ' '; + $password = <STDIN>; + print "\n", get_text('install_admin_get_password2') . ' '; + my $pass2 = <STDIN>; + eval { validate_password($password, $pass2); }; + if ($@) { + print "\n$@\n"; + undef $password; + } + system("stty","echo") unless ON_WINDOWS; + } + + my $admin = Bugzilla::User->create({ login_name => $login, + realname => $full_name, + cryptpassword => $password }); + make_admin($admin); +} + +sub make_admin { + my ($user) = @_; + my $dbh = Bugzilla->dbh; + + $user = ref($user) ? $user + : new Bugzilla::User(login_to_id($user, THROW_ERROR)); + + my $admin_group = new Bugzilla::Group({ name => 'admin' }); + + # Admins get explicit membership and bless capability for the admin group + $dbh->selectrow_array("SELECT id FROM groups WHERE name = 'admin'"); + + my $group_insert = $dbh->prepare( + 'INSERT INTO user_group_map (user_id, group_id, isbless, grant_type) + VALUES (?, ?, ?, ?)'); + # These are run in an eval so that we can ignore the error of somebody + # already being granted these things. + eval { + $group_insert->execute($user->id, $admin_group->id, 0, GRANT_DIRECT); + }; + eval { + $group_insert->execute($user->id, $admin_group->id, 1, GRANT_DIRECT); + }; + + # Admins should also have editusers directly, even though they'll usually + # inherit it. People could have changed their inheritance structure. + my $editusers = new Bugzilla::Group({ name => 'editusers' }); + eval { + $group_insert->execute($user->id, $editusers->id, 0, GRANT_DIRECT); + }; + + print "\n", get_text('install_admin_created', { user => $user }), "\n"; +} + +# This is just in case we get interrupted while getting the admin's password. +sub _create_admin_exit { + # re-enable input echoing + system("stty","echo") unless ON_WINDOWS; + exit 1; +} + +sub get_text { + my ($name, $vars) = @_; + my $template = Bugzilla->template; + $vars ||= {}; + $vars->{'message'} = $name; + my $message; + $template->process('global/message.txt.tmpl', $vars, \$message) + || ThrowTemplateError($template->error()); + $message =~ s/^\s+//gm; + return $message; +} + 1; __END__ diff --git a/checksetup.pl b/checksetup.pl index 27ee5d6ea..169ccb652 100755 --- a/checksetup.pl +++ b/checksetup.pl @@ -44,6 +44,7 @@ checksetup.pl - A do-it-all upgrade and installation script for Bugzilla. ./checksetup.pl [--help|--check-modules] ./checksetup.pl [SCRIPT [--verbose]] [--no-templates|-t] + ./checksetup.pl --make-admin=user@domain.com =head1 OPTIONS @@ -65,6 +66,12 @@ Display this help text Only check for correct module dependencies and quit afterward. +=item B<--make-admin>=username@domain.com + +Makes the specified user into a Bugzilla administrator. This is +in case you accidentally lock yourself out of the Bugzilla administrative +interface. + =item B<--no-templates> (B<-t>) Don't compile the templates at all. Existing compiled templates will @@ -204,7 +211,6 @@ The format of that file is as follows: (Any localconfig variable or parameter can be specified as above.) - $answer{'ADMIN_OK'} = 'Y'; $answer{'ADMIN_EMAIL'} = 'myadmin@mydomain.net'; $answer{'ADMIN_PASSWORD'} = 'fooey'; $answer{'ADMIN_REALNAME'} = 'Joel Peshkin'; @@ -270,7 +276,7 @@ sub read_answers_file { my %switch; GetOptions(\%switch, 'help|h|?', 'check-modules', 'no-templates|t', - 'verbose|v|no-silent'); + 'verbose|v|no-silent', 'make-admin=s'); # Print the help message if that switch was selected. pod2usage({-verbose => 1, -exitval => 1}) if $switch{'help'}; @@ -343,6 +349,8 @@ require Bugzilla::Template; require Bugzilla::Field; require Bugzilla::Install; +Bugzilla->usage_mode(USAGE_MODE_CMDLINE); + ########################################################################### # Check and update --LOCAL-- configuration ########################################################################### @@ -585,215 +593,8 @@ Bugzilla::Install::update_settings(); # Create Administrator --ADMIN-- ########################################################################### -sub bailout { # this is just in case we get interrupted while getting passwd - if ($^O !~ /MSWin32/i) { - system("stty","echo"); # re-enable input echoing - } - exit 1; -} - -my @groups = (); -$sth = $dbh->prepare("SELECT id FROM groups"); -$sth->execute(); -while ( my @row = $sth->fetchrow_array() ) { - push (@groups, $row[0]); -} - -# Prompt the user for the email address and name of an administrator. Create -# that login, if it doesn't exist already, and make it a member of all groups. - -$sth = $dbh->prepare("SELECT user_id FROM groups INNER JOIN user_group_map " . - "ON id = group_id WHERE name = 'admin'"); -$sth->execute; -# when we have no admin users, prompt for admin email address and password ... -if ($sth->rows == 0) { - my $login = ""; - my $realname = ""; - my $pass1 = ""; - my $pass2 = "*"; - my $admin_ok = 0; - my $admin_create = 1; - my $mailcheckexp = ""; - my $mailcheck = ""; - - # Here we look to see what the emailregexp is set to so we can - # check the email address they enter. Bug 96675. If they have no - # params (likely but not always the case), we use the default. - if (-e "$datadir/params") { - require "$datadir/params"; # if they have a params file, use that - } - if (Bugzilla->params->{'emailregexp'}) { - $mailcheckexp = Bugzilla->params->{'emailregexp'}; - $mailcheck = Bugzilla->params->{'emailregexpdesc'}; - } else { - $mailcheckexp = '^[\\w\\.\\+\\-=]+@[\\w\\.\\-]+\\.[\\w\\-]+$'; - $mailcheck = 'A legal address must contain exactly one \'@\', - and at least one \'.\' after the @.'; - } - - print "\nLooks like we don't have an administrator set up yet.\n"; - print "Either this is your first time using Bugzilla, or your\n "; - print "administrator's privileges might have accidentally been deleted.\n"; - while(! $admin_ok ) { - while( $login eq "" ) { - print "Enter the e-mail address of the administrator: "; - $login = $answer{'ADMIN_EMAIL'} - || ($silent && die("cant preload ADMIN_EMAIL")) - || <STDIN>; - chomp $login; - if(! $login ) { - print "\nYou DO want an administrator, don't you?\n"; - } - unless ($login =~ /$mailcheckexp/) { - print "\nThe login address is invalid:\n"; - print "$mailcheck\n"; - print "You can change this test on the params page once checksetup has successfully\n"; - print "completed.\n\n"; - # Go round, and ask them again - $login = ""; - } - } - $sth = $dbh->prepare("SELECT login_name FROM profiles " . - "WHERE " . $dbh->sql_istrcmp('login_name', '?')); - $sth->execute($login); - if ($sth->rows > 0) { - print "$login already has an account.\n"; - print "Make this user the administrator? [Y/n] "; - my $ok = $answer{'ADMIN_OK'} - || ($silent && die("cant preload ADMIN_OK")) - || <STDIN>; - chomp $ok; - if ($ok !~ /^n/i) { - $admin_ok = 1; - $admin_create = 0; - } else { - print "OK, well, someone has to be the administrator.\n"; - print "Try someone else.\n"; - $login = ""; - } - } else { - print "You entered $login. Is this correct? [Y/n] "; - my $ok = $answer{'ADMIN_OK'} - || ($silent && die("cant preload ADMIN_OK")) - || <STDIN>; - chomp $ok; - if ($ok !~ /^n/i) { - $admin_ok = 1; - } else { - print "That's okay, typos happen. Give it another shot.\n"; - $login = ""; - } - } - } - - if ($admin_create) { - while( $realname eq "" ) { - print "Enter the real name of the administrator: "; - $realname = $answer{'ADMIN_REALNAME'} - || ($silent && die("cant preload ADMIN_REALNAME")) - || <STDIN>; - chomp $realname; - if(! $realname ) { - print "\nReally. We need a full name.\n"; - } - if(! is_7bit_clean($realname)) { - print "\nSorry, but at this stage the real name can only " . - "contain standard English\ncharacters. Once Bugzilla " . - "has been installed, you can use the 'Prefs' page\nto " . - "update the real name.\n"; - $realname = ''; - } - } - - # trap a few interrupts so we can fix the echo if we get aborted. - $SIG{HUP} = \&bailout; - $SIG{INT} = \&bailout; - $SIG{QUIT} = \&bailout; - $SIG{TERM} = \&bailout; - - if ($^O !~ /MSWin32/i) { - system("stty","-echo"); # disable input echoing - } - - while( $pass1 ne $pass2 ) { - while( $pass1 eq "" || $pass1 !~ /^[[:print:]]{3,16}$/ ) { - print "Enter a password for the administrator account: "; - $pass1 = $answer{'ADMIN_PASSWORD'} - || ($silent && die("cant preload ADMIN_PASSWORD")) - || <STDIN>; - chomp $pass1; - if(! $pass1 ) { - print "\n\nAn empty password is a security risk. Try again!\n"; - } elsif ( $pass1 !~ /^.{3,16}$/ ) { - print "\n\nThe password must be 3-16 characters in length.\n"; - } elsif ( $pass1 !~ /^[[:print:]]{3,16}$/ ) { - print "\n\nThe password contains non-printable characters.\n"; - } - } - print "\nPlease retype the password to verify: "; - $pass2 = $answer{'ADMIN_PASSWORD'} - || ($silent && die("cant preload ADMIN_PASSWORD")) - || <STDIN>; - chomp $pass2; - if ($pass1 ne $pass2) { - print "\n\nPasswords don't match. Try again!\n"; - $pass1 = ""; - $pass2 = "*"; - } - } - - if ($^O !~ /MSWin32/i) { - system("stty","echo"); # re-enable input echoing - } - - $SIG{HUP} = 'DEFAULT'; # and remove our interrupt hooks - $SIG{INT} = 'DEFAULT'; - $SIG{QUIT} = 'DEFAULT'; - $SIG{TERM} = 'DEFAULT'; - - Bugzilla::User->create({ - login_name => $login, - realname => $realname, - cryptpassword => $pass1}); - } - - # Put the admin in each group if not already - my $userid = $dbh->selectrow_array("SELECT userid FROM profiles WHERE " . - $dbh->sql_istrcmp('login_name', '?'), - undef, $login); - - # Admins get explicit membership and bless capability for the admin group - my ($admingroupid) = $dbh->selectrow_array("SELECT id FROM groups - WHERE name = 'admin'"); - $dbh->do("INSERT INTO user_group_map - (user_id, group_id, isbless, grant_type) - VALUES ($userid, $admingroupid, 0, " . GRANT_DIRECT . ")"); - $dbh->do("INSERT INTO user_group_map - (user_id, group_id, isbless, grant_type) - VALUES ($userid, $admingroupid, 1, " . GRANT_DIRECT . ")"); - - # Admins get inherited membership and bless capability for all groups - foreach my $group ( @groups ) { - my $sth_check = $dbh->prepare("SELECT member_id FROM group_group_map - WHERE member_id = ? - AND grantor_id = ? - AND grant_type = ?"); - $sth_check->execute($admingroupid, $group, GROUP_MEMBERSHIP); - unless ($sth_check->rows) { - $dbh->do("INSERT INTO group_group_map - (member_id, grantor_id, grant_type) - VALUES ($admingroupid, $group, " . GROUP_MEMBERSHIP . ")"); - } - $sth_check->execute($admingroupid, $group, GROUP_BLESS); - unless ($sth_check->rows) { - $dbh->do("INSERT INTO group_group_map - (member_id, grantor_id, grant_type) - VALUES ($admingroupid, $group, " . GROUP_BLESS . ")"); - } - } - - print "\n$login is now set up as an administrator account.\n"; -} +Bugzilla::Install::make_admin($switch{'make-admin'}) if $switch{'make-admin'}; +Bugzilla::Install::create_admin({ answer => \%answer }); ########################################################################### # Create default Product and Classification @@ -805,14 +606,6 @@ Bugzilla::Install::create_default_product(); # Final checks ########################################################################### -$sth = $dbh->prepare("SELECT user_id " . - "FROM groups INNER JOIN user_group_map " . - "ON groups.id = user_group_map.group_id " . - "WHERE groups.name = 'admin'"); -$sth->execute; -my ($adminuid) = $sth->fetchrow_array; -if (!$adminuid) { die "No administrator!" } # should never get here - # Check if the default parameter for urlbase is still set, and if so, give # notification that they should go and visit editparams.cgi diff --git a/template/en/default/global/messages.html.tmpl b/template/en/default/global/messages.html.tmpl index 4a7c4591c..096791805 100644 --- a/template/en/default/global/messages.html.tmpl +++ b/template/en/default/global/messages.html.tmpl @@ -262,6 +262,26 @@ <a href="editflagtypes.cgi">Back to flag types.</a> </p> + [% ELSIF message_tag == "install_admin_get_email" %] + Enter the e-mail address of the administrator: + + [% ELSIF message_tag == "install_admin_get_name" %] + Enter the real name of the administrator: + + [% ELSIF message_tag == "install_admin_get_password" %] + Enter a password for the administrator account: + + [% ELSIF message_tag == "install_admin_get_password2" %] + Please retype the password to verify: + + [% ELSIF message_tag == "install_admin_created" %] + [% user.login FILTER html %] is now set up as an administrator. + + [% ELSIF message_tag == "install_admin_setup" %] + Looks like we don't have an administrator set up yet. + Either this is your first time using Bugzilla, or your + administrator's privileges might have accidentally been deleted. + [% ELSIF message_tag == "product_invalid" %] [% title = "$terms.Bugzilla Component Descriptions" %] The product <em>[% product FILTER html %]</em> does not exist |