Commit 258c653f authored by Dries's avatar Dries

- Patch #141637 by merlinofchaos, gabor, et al: provide a site config form at...

- Patch #141637 by merlinofchaos, gabor, et al: provide a site config form at the end of install to collect data, plus allow profiles to modify and add more.
parent 571013af
......@@ -32,6 +32,10 @@ Drupal 6.0, xxxx-xx-xx (development version)
* Used the Garland theme for the installation and maintenance pages.
* Added theme preprocess functions for themes that are templates
- Refactored update.php to a generic batch API to be able to run time consuming operations in multiple subsequent HTTP requests
- Installer:
* Themed the installer with the Garland theme.
* Added form to provide initial site information during installation.
* Added ability to provide extra installation steps programmatically.
Drupal 5.0, 2007-01-15
----------------------
......
......@@ -27,16 +27,19 @@ function install_main() {
// Check existing settings.php.
$verify = install_verify_settings();
// Drupal may already be installed.
if ($verify) {
// Establish a connection to the database.
require_once './includes/database.inc';
db_set_active();
// Check if Drupal is installed.
if (install_verify_drupal()) {
$task = install_verify_drupal();
if ($task == 'done') {
install_already_done_error();
}
}
else {
$task = NULL;
}
// Load module basics (needed for hook invokes).
include_once './includes/module.inc';
......@@ -57,6 +60,9 @@ function install_main() {
install_no_profile_error();
}
// Load the profile.
require_once "./profiles/$profile/$profile.profile";
// Locale selection
if (!empty($_GET['locale'])) {
$install_locale = preg_replace('/[^a-zA-Z_0-9]/', '', $_GET['locale']);
......@@ -65,46 +71,49 @@ function install_main() {
install_goto("install.php?profile=$profile&locale=$install_locale");
}
// Load the profile.
require_once "./profiles/$profile/$profile.profile";
// Check the installation requirements for Drupal and this profile.
install_check_requirements($profile);
// Tasks come after the database is set up
if (!$task) {
// Check the installation requirements for Drupal and this profile.
install_check_requirements($profile);
// Change the settings.php information if verification failed earlier.
// Note: will trigger a redirect if database credentials change.
if (!$verify) {
install_change_settings($profile, $install_locale);
}
// Verify existence of all required modules.
$modules = drupal_verify_profile($profile, $install_locale);
if (!$modules) {
install_missing_modules_error($profile);
}
// Verify existence of all required modules.
$modules = drupal_verify_profile($profile, $install_locale);
if (!$modules) {
install_missing_modules_error($profile);
}
// Change the settings.php information if verification failed earlier.
// Note: will trigger a redirect if database credentials change.
if (!$verify) {
install_change_settings($profile, $install_locale);
}
// Perform actual installation defined in the profile.
drupal_install_profile($profile, $modules);
// Perform actual installation defined in the profile.
drupal_install_profile($profile, $modules);
// Warn about settings.php permissions risk
$settings_file = './'. conf_path() .'/settings.php';
if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) {
drupal_set_message(st('All necessary changes to %file have been made, so you should now remove write permissions to this file. Failure to remove write permissions to this file is a security risk.', array('%file' => $settings_file)), 'error');
}
else {
drupal_set_message(st('All necessary changes to %file have been made. It has been set to read-only for security.', array('%file' => $settings_file)));
// Warn about settings.php permissions risk
$settings_file = './'. conf_path() .'/settings.php';
if (!drupal_verify_install_file($settings_file, FILE_EXIST|FILE_READABLE|FILE_NOT_WRITABLE)) {
drupal_set_message(st('All necessary changes to %file have been made, so you should now remove write permissions to this file. Failure to remove write permissions to this file is a security risk.', array('%file' => $settings_file)), 'error');
}
else {
drupal_set_message(st('All necessary changes to %file have been made. It has been set to read-only for security.', array('%file' => $settings_file)));
}
}
// Show end page.
install_complete($profile);
// The database is set up, turn to further tasks.
install_tasks($profile, $task);
}
/**
* Verify if Drupal is installed.
*/
function install_verify_drupal() {
$result = @db_query("SELECT name FROM {system} WHERE name = 'system'");
return $result && db_result($result) == 'system';
// Read the variable manually using the @ so we don't trigger an error if it fails.
$result = @db_query("SELECT value FROM {variable} WHERE name = 'install_task'");
if ($result) {
return unserialize(db_result($result));
}
}
/**
......@@ -114,7 +123,7 @@ function install_verify_settings() {
global $db_prefix, $db_type, $db_url;
// Verify existing settings (if any).
if ($_SERVER['REQUEST_METHOD'] == 'GET' && !empty($db_url)) {
if (!empty($db_url)) {
// We need this because we want to run form_get_errors.
include_once './includes/form.inc';
......@@ -548,47 +557,90 @@ function install_missing_modules_error($profile) {
global $base_url;
drupal_maintenance_theme();
install_task_list('install');
install_task_list('requirements');
drupal_set_title(st('Modules missing'));
print theme('install_page', '<p>'. st('One or more required modules are missing. Please check the error messages and <a href="!url">try again</a>.', array('!url' => "install.php?profile=$profile")) .'</p>');
exit;
}
/**
* Page displayed when the installation is complete. Called from install.php.
* Tasks performed after the database is initialized. Called from install.php.
*/
function install_complete($profile) {
function install_tasks($profile, $task) {
global $base_url;
$output = '';
// Store install profile for later use.
variable_set('install_profile', $profile);
// Bootstrap newly installed Drupal, while preserving existing messages.
$messages = $_SESSION['messages'];
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
$_SESSION['messages'] = $messages;
// Build final page.
// Build a page for a final task.
drupal_maintenance_theme();
install_task_list();
drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
$output .= '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
// Show profile finalization info.
$function = $profile .'_profile_final';
if (function_exists($function)) {
// More steps required
$profile_message = $function();
if (empty($task)) {
variable_set('install_task', 'configure');
$task = 'configure';
}
menu_rebuild();
// If the profile returned a welcome message, use that instead of default.
if (isset($profile_message)) {
$output .= $profile_message;
if ($task == 'configure') {
drupal_set_title(st('Configure site'));
menu_rebuild();
// We break the form up so we can tell when it's been successfully
// submitted.
$form = drupal_retrieve_form('install_configure_form');
// In order to find out if the form was successfully submitted or not,
// we do a little song and dance to set the form to 'programmed' and check
// to make sure this is really the form being submitted. It'd better be.
if ($_POST && $_POST['form_id'] == 'install_configure_form') {
$form['#programmed'] = TRUE;
$form['#post'] = $_POST;
}
if (!drupal_process_form('install_configure_form', $form)) {
$output = drupal_render_form('install_configure_form', $form);
install_task_list('configure');
}
}
else {
// No more steps
$output .= '<p>'. (drupal_set_message() ? st('Please review the messages above before continuing on to <a href="@url">your new site</a>.', array('@url' => url(''))) : st('You may now visit <a href="@url">your new site</a>.', array('@url' => url('')))) .'</p>';
// If we have no output, then install.php is done and now we turn to
// our profile to run it's own tasks.
if (empty($output)) {
// Profile might define more tasks.
$function = $profile .'_profile_final';
if (function_exists($function)) {
// More tasks are required by this profile.
// $task is sent through as a reference and may be changed!
$output = $function($task);
}
// Safety: if the profile doesn't do anything, catch it.
if ($task == 'configure') {
$task = 'finished';
}
// Display default 'finished' page to user. A custom finished page
// can be displayed by skipping this step and going to 'done' directly.
if ($task == 'finished') {
drupal_set_title(st('@drupal installation complete', array('@drupal' => drupal_install_profile_name())));
$page = '<p>'. st('Congratulations, @drupal has been successfully installed.', array('@drupal' => drupal_install_profile_name())) .'</p>';
$page .= $output;
$messages = drupal_set_message();
$page .= '<p>'. (isset($messages['error']) ? st('Please review the messages above before continuing on to <a href="@url">your new site</a>.', array('@url' => url(''))) : st('You may now visit <a href="@url">your new site</a>.', array('@url' => url('')))) .'</p>';
$output = $page;
$task = 'done';
}
// The end of the install process. Remember profile used.
if ($task == 'done') {
variable_set('install_profile', $profile);
}
// Set task for user, and remember the task in the database.
install_task_list($task);
variable_set('install_task', $task);
}
// Output page.
print theme('maintenance_page', $output);
......@@ -628,20 +680,179 @@ function install_task_list($active = NULL) {
'locale' => st('Choose language'),
'requirements' => st('Verify requirements'),
'database' => st('Database setup'),
'install' => st('Installation'),
'configure' => st('Configure site'),
);
$profiles = install_find_profiles();
// Remove profiles if only one profile exists.
if (count(install_find_profiles()) == 1) {
if (count($profiles) == 1) {
unset($tasks['profile']);
}
// Remove locale if no install profiles use them.
if (count(install_find_locales('.')) == 1) {
$profile = isset($_GET['profile']) && isset($profiles[$_GET['profile']]) ? $_GET['profile'] : '.';
if (count(install_find_locales($profile)) == 1) {
unset($tasks['locale']);
}
if ($profile) {
$function = $profile .'_profile_task_list';
if (function_exists($function)) {
$result = $function();
if (is_array($result)) {
$tasks += $result;
}
}
}
// Add finished step as the last task.
$tasks += array('finished' => st('Finished'));
// Let the theming function know that 'finished' and 'done'
// include everything, so every step is completed.
if (in_array($active, array('finished', 'done'))) {
$active = NULL;
}
drupal_set_content('left', theme_task_list($tasks, $active));
}
function install_configure_form() {
// This is necessary to add the task to the $_GET args so the install
// system will know that it is done and we've taken over.
$form['intro'] = array(
'#value' => st('To configure your web site, please provide the following information.'),
'#weight' => -10,
);
$form['site_information'] = array(
'#type' => 'fieldset',
'#title' => st('Site information'),
'#collapsible' => FALSE,
);
$form['site_information']['site_name'] = array(
'#type' => 'textfield',
'#title' => st('Site name'),
'#default_value' => variable_get('site_name', 'Drupal'),
'#required' => TRUE,
'#weight' => -20,
);
$form['site_information']['site_mail'] = array(
'#type' => 'textfield',
'#title' => st('Site e-mail address'),
'#default_value' => variable_get('site_mail', ini_get('sendmail_from')),
'#description' => st('A valid e-mail address to be used as the "From" address by the auto-mailer during registration, new password requests, notifications, etc. To lessen the likelihood of e-mail being marked as spam, this e-mail address should use the same domain as the website.'),
'#required' => TRUE,
'#weight' => -15,
);
$form['admin_account'] = array(
'#type' => 'fieldset',
'#title' => st('Administrator account'),
'#collapsible' => FALSE,
);
$form['admin_account']['account']['#tree'] = TRUE;
$form['admin_account']['markup'] = array(
'#value' => '<p class="description">'. st('The administrator account has complete access to the site; it will automatically be granted all permissions and can perform any administrative activity. This will be the only account that can perform certain activities, so keep its credentials safe.') .'</p>',
'#weight' => -10,
);
$form['admin_account']['account']['name'] = array('#type' => 'textfield',
'#title' => st('Username'),
'#maxlength' => USERNAME_MAX_LENGTH,
'#description' => st('Spaces are allowed; punctuation is not allowed except for periods, hyphens, and underscores.'),
'#required' => TRUE,
'#weight' => -10,
);
$form['admin_account']['account']['mail'] = array('#type' => 'textfield',
'#title' => st('E-mail address'),
'#maxlength' => EMAIL_MAX_LENGTH,
'#description' => st('All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
'#required' => TRUE,
'#weight' => -5,
);
$form['admin_account']['account']['pass'] = array(
'#type' => 'password_confirm',
'#required' => TRUE,
'#size' => 25,
'#weight' => 0,
);
$zones = _system_zonelist();
$form['server_settings'] = array(
'#type' => 'fieldset',
'#title' => st('Server settings'),
'#collapsible' => FALSE,
);
$form['server_settings']['date_default_timezone'] = array(
'#type' => 'select',
'#title' => st('Default time zone'),
'#default_value' => variable_get('date_default_timezone', 0),
'#options' => $zones,
'#description' => st('By default, dates in this site will be displayed in the chosen time zone.'),
'#weight' => 5,
);
drupal_add_js(drupal_get_path('module', 'system') .'/system.js', 'module');
drupal_add_js(array('cleanURL' => array('success' => st('Your server has been successfully tested to support this feature.'), 'failure' => st('Your system configuration does not currently support this feature. The <a href="http://drupal.org/node/15365">handbook page on Clean URLs</a> has additional troubleshooting information.'), 'testing' => st('Testing clean URLs...'))), 'setting');
drupal_add_js('
// Global Killswitch
if (Drupal.jsEnabled) {
$(document).ready(function() {
Drupal.cleanURLsInstallCheck();
Drupal.installDefaultTimezone();
});
}', 'inline');
$form['server_settings']['clean_url'] = array(
'#type' => 'radios',
'#title' => st('Clean URLs'),
'#default_value' => variable_get('clean_url', 0),
'#options' => array(st('Disabled'), st('Enabled')),
'#description' => st('This option makes Drupal emit "clean" URLs (i.e. without <code>?q=</code> in the URL).'),
'#disabled' => TRUE,
'#prefix' => '<div id="clean-url" class="install">',
'#suffix' => '</div>',
'#weight' => 10,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => st('Submit'),
'#weight' => 15,
);
$hook_form_alter = $_GET['profile'] .'_form_alter';
if (function_exists($hook_form_alter)) {
$form = $hook_form_alter($form, 'install_configure');
}
return $form;
}
function install_configure_form_validate($form_id, $form_values, $form) {
if ($error = user_validate_name($form_values['account']['name'])) {
form_error($form['admin_account']['account']['name'], $error);
}
if ($error = user_validate_mail($form_values['account']['mail'])) {
form_error($form['admin_account']['account']['mail'], $error);
}
if ($error = user_validate_mail($form_values['site_mail'])) {
form_error($form['site_information']['site_mail'], $error);
}
}
function install_configure_form_submit($form_id, $form_values) {
variable_set('site_name', $form_values['site_name']);
variable_set('site_mail', $form_values['site_mail']);
variable_set('date_default_timezone', $form_values['date_default_timezone']);
// Turn this off temporarily so that we can pass a password through.
variable_set('user_email_verification', FALSE);
user_register_submit('user_register', $form_values['account']);
variable_set('user_email_verification', TRUE);
if (isset($form_values['clean_url'])) {
variable_set('clean_url', $form_values['clean_url']);
}
return 'finished';
}
install_main();
......@@ -2448,10 +2448,6 @@ function node_page_default() {
$default_message = t('<h1 class="title">Welcome to your new Drupal website!</h1><p>Please follow these steps to set up and start using your website:</p>');
$default_message .= '<ol>';
if (!$admin) {
$default_message .= '<li>'. t('<strong>Create your administrator account</strong> To begin, <a href="@register">create the first account</a>. This account will have full administration rights and will allow you to configure your website.', array('@register' => url('user/register'))) .'</li>';
}
$default_message .= '<li>'. t('<strong>Configure your website</strong> Once logged in, visit the <a href="@admin">administration section</a>, where you can <a href="@config">customize and configure</a> all aspects of your website.', array('@admin' => url('admin'), '@config' => url('admin/settings'))) .'</li>';
$default_message .= '<li>'. t('<strong>Enable additional functionality</strong> Next, visit the <a href="@modules">module list</a> and enable features which suit your specific needs. You can find additional modules in the <a href="@download_modules">Drupal modules download section</a>.', array('@modules' => url('admin/build/modules'), '@download_modules' => 'http://drupal.org/project/modules')) .'</li>';
$default_message .= '<li>'. t('<strong>Customize your website design</strong> To change the "look and feel" of your website, visit the <a href="@themes">themes section</a>. You may choose from one of the included themes or download additional themes from the <a href="@download_themes">Drupal themes download section</a>.', array('@themes' => url('admin/build/themes'), '@download_themes' => 'http://drupal.org/project/themes')) .'</li>';
......
......@@ -431,3 +431,10 @@ tr.selected td {
thead div.sticky-header {
background: #fff;
}
/*
** Installation clean URLs
*/
#clean-url.install {
display: none;
}
......@@ -3873,6 +3873,14 @@ function system_update_6013() {
system_theme_data();
}
/**
* Record that the installer is done, so it is not
* possible to run the installer on upgraded sites.
*/
function system_update_6014() {
variable_set('install_task', 'done');
}
/**
* @} End of "defgroup updates-5.x-to-6.x"
......
......@@ -24,3 +24,35 @@ Drupal.cleanURLsSettingsCheck = function() {
}
}});
}
/**
* Internal function to check using Ajax if clean URLs can be enabled on the
* install page.
*
* This function is not used to verify whether or not clean URLs
* are currently enabled.
*/
Drupal.cleanURLsInstallCheck = function() {
var pathname = location.pathname +"";
var url = pathname.replace(/\/[^\/]*?$/, '/') +"node";
$("#clean-url .description").append('<span><div id="testing">'+ Drupal.settings.cleanURL.testing +"</div></span>");
$("#clean-url.install").css("display", "block");
$.ajax({url: location.protocol +"//"+ location.host + url, type: "GET", data: " ", complete: function(response) {
$("#testing").toggle();
if (response.status == 200) {
// Check was successful.
$("#clean-url input.form-radio").attr("disabled", "");
$("#clean-url .description span").append('<div class="ok">'+ Drupal.settings.cleanURL.success +"</div>");
$("#clean-url input.form-radio").attr("checked", 1);
}
else {
// Check failed.
$("#clean-url .description span").append('<div class="warning">'+ Drupal.settings.cleanURL.failure +"</div>");
}
}});
}
Drupal.installDefaultTimezone = function() {
var offset = new Date().getTimezoneOffset() * -60;
$("#edit-date-default-timezone").val(offset);
}
......@@ -1374,8 +1374,10 @@ function user_register_submit($form_id, $form_values) {
// The first user may login immediately, and receives a customized welcome e-mail.
if ($account->uid == 1) {
drupal_mail('user-register-admin', $mail, t('Drupal user account details for !s', array('!s' => $name)), strtr(t("!username,\n\nYou may now login to !uri using the following username and password:\n\n username: !username\n password: !password\n\n!edit_uri\n\n--drupal"), $variables), $from);
drupal_set_message(t('<p>Welcome to Drupal. You are user #1, which gives you full and immediate access. All future registrants will receive their passwords via e-mail, so please make sure your website e-mail address is set properly under the general settings on the <a href="@settings">site information settings page</a>.</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass, '@settings' => url('admin/settings/site-information'))));
drupal_set_message(t('<p>Welcome to Drupal. You are now logged in as user #1, which gives you full control over your website.</p>'));
if (variable_get('user_email_verification', TRUE)) {
drupal_set_message(t('</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass)));
}
user_authenticate($account->name, trim($pass));
return 'user/1/edit';
......
......@@ -24,14 +24,49 @@ function default_profile_details() {
);
}
/**
* Return a list of tasks that this profile supports.
*
* @return
* A keyed array of tasks the profile will perform during the _final stage.
*/
function default_profile_task_list() {
}
/**
* Perform any final installation tasks for this profile.
*
* You can implement a state machine here to walk the user through
* more tasks, by setting $task to something other then the reserved
* 'configure', 'finished' and 'done' values. The installer goes
* through the configure-finished-done tasks in this order, if you
* don't modify $task. If you implement your custom tasks, this
* function will get called in every HTTP request (for form
* processing, printing your information screens and so on) until
* you advance to the 'finished' or 'done' tasks. Once ready with
* your profile's tasks, set $task to 'finished' and optionally
* return a final message to be included on the default final
* install page. Alternatively you can set $task to 'done' and
* return a completely custom finished page. In both cases, you
* hand the control back to the installer.
*
* Should a profile want to display a form here, it can; it should set
* the task using variable_set('install_task', 'new_task') and use
* the form technique used in install_tasks() rather than using
* drupal_get_form().
*
* @param $task
* The current $task of the install system. When hook_profile_final()
* is first called, this is 'configure' (the last built-in task of
* the Drupal installer).
*
* @return
* An optional HTML string to display to the user on the final installation
* screen.
* An optional HTML string to display to the user. Used as part of the
* completed page if $task is set to 'finished', or used to display a
* complete page in all other cases.
*/
function default_profile_final() {
function default_profile_final(&$task) {
// Insert default user-defined node types into the database. For a complete
// list of available node type attributes, refer to the node type API
// documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
......@@ -73,4 +108,7 @@ function default_profile_final() {
$theme_settings = variable_get('theme_settings', array());
$theme_settings['toggle_node_info_page'] = FALSE;
variable_set('theme_settings', $theme_settings);
// Let the installer know we're finished:
$task = 'finished';
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment