hosting.module

Hosting module.

Contains just about all the interface magic of hostmaster.

Functions

Namesort descending Description
drush_hosting_setup Initial hosting setup drush command.
hosting_block_info Implements hook_block_info().
hosting_block_view Implements hook_block_view().
hosting_context_delete Delete an alias from the context lookup table.
hosting_context_load Get the node associated with a given provision context.
hosting_context_name Return the hosting context name for a node.
hosting_context_nid Lookup the node ID for a hosting context name.
hosting_context_node_types Define the node types that have associated provision contexts.
hosting_context_register Add a node to the context lookup db.
hosting_create_roles Create the default hosting roles.
hosting_disabled_site Page callback for a site that has been disabled.
hosting_domain_allowed Check site URL is allowed.
hosting_form_alter Implements hook_form_alter().
hosting_form_submit_messages Submit handler for hosting node forms: Display helpful messages.
hosting_init Implements hook_init().
hosting_js_page Page callback for a page to be rendered in modal frame.
hosting_menu Implements hook_menu().
hosting_menu_access Menu access callback for creating a node provided by a Hosting feature.
hosting_menu_alter Implements hook_menu_alter().
hosting_modules_disabled Implements hook_modules_disabled().
hosting_modules_enabled Implements hook_modules_enabled().
hosting_nodeapi Redirects to hosting_nodeapi_$nodetype_$op calls.
hosting_node_delete Implements hook_node_delete().
hosting_node_help Per node type description text. To be stored in the node_type table.
hosting_node_insert Implements hook_node_insert().
hosting_node_load Implements hook_node_load().
hosting_node_prepare Implements hook_node_prepare().
hosting_node_presave Implements hook_node_presave().
hosting_node_revision_delete Implements hook_node_revision_delete().
hosting_node_search_result Implements hook_node_search_result().
hosting_node_update Implements hook_node_update().
hosting_node_update_index Implements hook_node_update_index().
hosting_node_validate Implements hook_node_validate().
hosting_node_view Implements hook_node_view().
hosting_permission Implements hook_permission().
hosting_queues List queues or tasks in a queue if a key is provided.
hosting_queues_configure Form to configure the frequency of queue execution.
hosting_queues_configure_submit Submit callback for the the queue execution frequency form.
hosting_queues_configure_validate Validation callback for the the queue execution frequency form.
hosting_queue_block Build a block of the hosting queues.
hosting_queue_summary_block Build a block summarising the hosting queues.
hosting_settings General settings form.
hosting_set_breadcrumb Generate context sensitive breadcrumbs.
hosting_site_maintenance Page callback for a site that is undergoing maintenance.
hosting_supporting_aegir_block Build a 'Support Aegir' block.
hosting_theme Implements hook_theme().
hosting_views_api Implements hook_views_api().
theme_hosting_queues_configure Theme function to render the queue configuration form.
_hosting_node_add Replacement node/add page.
_hosting_node_link Generates a link to a node.
_hosting_setup_cron Set up the hosting-dispatch command in the aegir user's crontab.

Constants

Namesort descending Description
HOSTING_MAX_ALIAS_LENGTH The maximum length for a site alias. Leaving room to append '.alias.drushrc.php' and keep filenames below 255.

File

hosting.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * Hosting module.
  5. *
  6. * Contains just about all the interface magic of hostmaster.
  7. */
  8. /**
  9. * The maximum length for a site alias.
  10. * Leaving room to append '.alias.drushrc.php' and keep filenames below 255.
  11. */
  12. define('HOSTING_MAX_ALIAS_LENGTH', 235);
  13. /**
  14. * Not split for performance reasons. Just to keep code together.
  15. */
  16. include_once dirname(__FILE__) . '/hosting.inc';
  17. include_once dirname(__FILE__) . '/hosting.queues.inc';
  18. include_once dirname(__FILE__) . '/hosting.features.inc';
  19. /**
  20. * Implements hook_menu().
  21. */
  22. function hosting_menu() {
  23. global $user;
  24. $items = array();
  25. $items['hosting/disabled'] = array(
  26. 'title' => 'Site disabled',
  27. 'page callback' => 'hosting_disabled_site',
  28. 'access arguments' => array('access disabled sites'),
  29. 'type' => MENU_CALLBACK,
  30. );
  31. $items['hosting/js'] = array(
  32. 'title' => 'ahah callback',
  33. 'page callback' => 'hosting_js_page',
  34. 'access arguments' => array('access content'),
  35. 'type' => MENU_CALLBACK,
  36. );
  37. $items['hosting/maintenance'] = array(
  38. 'title' => 'Site maintenance',
  39. 'page callback' => 'hosting_site_maintenance',
  40. 'access arguments' => array('access content'),
  41. 'type' => MENU_CALLBACK,
  42. );
  43. $items['admin/hosting'] = array(
  44. 'title' => 'Hosting',
  45. 'description' => 'Configure and manage the hosting system',
  46. 'page callback' => 'drupal_get_form',
  47. 'page arguments' => array('hosting_features_form'),
  48. 'access arguments' => array('administer hosting'),
  49. 'type' => MENU_NORMAL_ITEM,
  50. );
  51. $items['admin/hosting/features'] = array(
  52. 'title' => 'Features',
  53. 'description' => 'Configure the exposed functionality of the Hosting system',
  54. 'weight' => -100,
  55. 'page callback' => 'drupal_get_form',
  56. 'page arguments' => array('hosting_features_form'),
  57. 'type' => MENU_DEFAULT_LOCAL_TASK,
  58. 'access arguments' => array('administer hosting features'),
  59. );
  60. $items['admin/hosting/queues'] = array(
  61. 'title' => 'Queues',
  62. 'description' => 'Configure the frequency that cron, backup and task events are process',
  63. 'page callback' => 'drupal_get_form',
  64. 'page arguments' => array('hosting_queues_configure'),
  65. 'type' => MENU_LOCAL_TASK,
  66. 'access arguments' => array('administer hosting queues'),
  67. );
  68. $items['admin/hosting/settings'] = array(
  69. 'title' => 'Settings',
  70. 'description' => 'Configure general Hosting settings',
  71. 'page callback' => 'drupal_get_form',
  72. 'page arguments' => array('hosting_settings'),
  73. 'type' => MENU_LOCAL_TASK,
  74. 'access arguments' => array('administer hosting settings'),
  75. );
  76. $items['hosting/queues'] = array(
  77. 'page callback' => 'hosting_queues',
  78. 'type' => MENU_CALLBACK,
  79. 'access arguments' => array('access task logs'),
  80. );
  81. return $items;
  82. }
  83. /**
  84. * Page callback for a page to be rendered in modal frame.
  85. */
  86. function hosting_js_page() {
  87. modalframe_child_js();
  88. $args = func_get_args();
  89. $path = implode('/', $args);
  90. // In case Aegir is running in a sub-directory, the base_path should be
  91. // stripped away here. Remove the leading slash from base_path as $path
  92. // doesn't have one either.
  93. $path = str_replace(ltrim(base_path(), '/'), '', $path);
  94. menu_set_active_item($path);
  95. if ($router_item = menu_get_item($path)) {
  96. if ($router_item['access']) {
  97. if ($router_item['file']) {
  98. require_once $router_item['file'];
  99. }
  100. $return = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
  101. }
  102. else {
  103. $return = drupal_access_denied();
  104. }
  105. }
  106. // Menu status constants are integers; page content is a string.
  107. if (is_int($return) && module_exists('overlay')) {
  108. overlay_close_dialog();
  109. }
  110. return $return;
  111. }
  112. /**
  113. * Implements hook_menu_alter().
  114. */
  115. function hosting_menu_alter(&$items) {
  116. $items['node/add']['page callback'] = '_hosting_node_add';
  117. $types = hosting_feature_node_types(TRUE);
  118. foreach ($types as $feature => $type) {
  119. $path = sprintf('node/add/%s', str_replace('_', '-', $type));
  120. $items[$path]['access callback'] = 'hosting_menu_access';
  121. $items[$path]['access arguments'] = array(
  122. str_replace('_', ' ', $type),
  123. $feature,
  124. );
  125. }
  126. // These node types should remain hidden, and provide no user interface.
  127. $items['node/add/package']['page callback'] = 'drupal_access_denied';
  128. $items['node/add/task']['page callback'] = 'drupal_access_denied';
  129. $items['node/add/package']['type'] = MENU_CALLBACK;
  130. $items['node/add/task']['type'] = MENU_CALLBACK;
  131. }
  132. /**
  133. * Menu access callback for creating a node provided by a Hosting feature.
  134. *
  135. * @param string $type
  136. * The node type that the user wants to create.
  137. * @param string $feature
  138. * The machine name of the host feature that should be additionally checked to
  139. * see if it's enabled.
  140. *
  141. * @return bool
  142. * TRUE if the user can access, FALSE otherwise.
  143. */
  144. function hosting_menu_access($type, $feature) {
  145. global $user;
  146. return (($user->uid == 1) || user_access('create ' . $type)) && (hosting_feature($feature) != HOSTING_FEATURE_DISABLED);
  147. }
  148. /**
  149. * Page callback for a site that has been disabled.
  150. */
  151. function hosting_disabled_site() {
  152. drupal_set_breadcrumb(array());
  153. return t("This site has been disabled by the site administrators");
  154. }
  155. /**
  156. * Page callback for a site that is undergoing maintenance.
  157. */
  158. function hosting_site_maintenance() {
  159. drupal_set_breadcrumb(array());
  160. return t("This site is currently in maintenance. Check back later.");
  161. }
  162. /**
  163. * Implements hook_node_delete().
  164. *
  165. * @see hook_nodeapi_TYPE_OP()
  166. */
  167. function hosting_node_delete($node) {
  168. // Redispatch through our custom nodeapi implementation.
  169. hosting_nodeapi($node, 'delete');
  170. }
  171. /**
  172. * Implements hook_node_insert().
  173. *
  174. * @see hook_nodeapi_TYPE_OP()
  175. */
  176. function hosting_node_insert($node) {
  177. // Redispatch through our custom nodeapi implementation.
  178. hosting_nodeapi($node, 'insert');
  179. }
  180. /**
  181. * Implements hook_node_load().
  182. *
  183. * @see hook_nodeapi_TYPE_OP()
  184. */
  185. function hosting_node_load($nodes, $types) {
  186. // Decide whether any of $types are relevant to our purposes.
  187. if (count(array_intersect(hosting_context_node_types(), $types))) {
  188. // Gather our extra data for each of these nodes.
  189. $result = db_query("SELECT nid, name AS hosting_name FROM {hosting_context} WHERE nid IN(:nids)", array(':nids' => array_keys($nodes)))->fetchAllKeyed();
  190. // Add our extra data to the node objects.
  191. foreach ($result as $nid => $hosting_name) {
  192. $nodes[$nid]->hosting_name = $hosting_name;
  193. // Redispatch through our custom nodeapi implementation.
  194. hosting_nodeapi($nodes[$nid], 'load');
  195. }
  196. }
  197. }
  198. /**
  199. * Implements hook_node_prepare().
  200. *
  201. * @see hook_nodeapi_TYPE_OP()
  202. */
  203. function hosting_node_prepare($node) {
  204. // Redispatch through our custom nodeapi implementation.
  205. hosting_nodeapi($node, 'prepare');
  206. }
  207. /**
  208. * Implements hook_node_presave().
  209. *
  210. * @see hook_nodeapi_TYPE_OP()
  211. */
  212. function hosting_node_presave($node) {
  213. if (in_array($node->type, hosting_context_node_types())) {
  214. if (!isset($node->uid)) {
  215. global $user;
  216. $node->uid = $user->uid;
  217. }
  218. }
  219. // Redispatch through our custom nodeapi implementation.
  220. hosting_nodeapi($node, 'presave');
  221. }
  222. /**
  223. * Implements hook_node_revision_delete().
  224. *
  225. * @see hook_nodeapi_TYPE_OP()
  226. */
  227. function hosting_node_revision_delete($node) {
  228. // Redispatch through our custom nodeapi implementation.
  229. hosting_nodeapi($node, 'delete revision');
  230. }
  231. /**
  232. * Implements hook_node_search_result().
  233. *
  234. * @see hook_nodeapi_TYPE_OP()
  235. */
  236. function hosting_node_search_result($node) {
  237. // Redispatch through our custom nodeapi implementation.
  238. hosting_nodeapi($node, 'search result');
  239. }
  240. /**
  241. * Implements hook_node_update().
  242. *
  243. * @see hook_nodeapi_TYPE_OP()
  244. */
  245. function hosting_node_update($node) {
  246. // Redispatch through our custom nodeapi implementation.
  247. hosting_nodeapi($node, 'update');
  248. }
  249. /**
  250. * Implements hook_node_update_index().
  251. *
  252. * @see hook_nodeapi_TYPE_OP()
  253. */
  254. function hosting_node_update_index($node) {
  255. // Redispatch through our custom nodeapi implementation.
  256. hosting_nodeapi($node, 'update index');
  257. }
  258. /**
  259. * Implements hook_node_validate().
  260. *
  261. * @see hook_nodeapi_TYPE_OP()
  262. */
  263. function hosting_node_validate($node, $form, &$form_state) {
  264. // Redispatch through our custom nodeapi implementation.
  265. hosting_nodeapi($node, 'validate', $form);
  266. }
  267. /**
  268. * Implements hook_node_view().
  269. *
  270. * @see hook_nodeapi_TYPE_OP()
  271. */
  272. function hosting_node_view($node, $view_mode, $langcode) {
  273. // Redispatch through our custom nodeapi implementation.
  274. if ($view_mode == 'teaser') {
  275. hosting_nodeapi($node, 'view', TRUE, FALSE);
  276. }
  277. elseif ($view_mode == 'full') {
  278. hosting_nodeapi($node, 'view', FALSE, TRUE);
  279. }
  280. }
  281. /**
  282. * Redirects to hosting_nodeapi_$nodetype_$op calls.
  283. *
  284. * To save ourselves from an incessant amount of intricately nested code,
  285. * and allow easier extension and maintenance.
  286. *
  287. * @see hook_nodeapi_TYPE_OP()
  288. */
  289. function hosting_nodeapi(&$node, $op, $arg1 = NULL, $arg2 = NULL) {
  290. // We need to practically re-invent module_invoke_all here because
  291. // we have to pass the node as a reference.
  292. $return = array();
  293. $hook = "nodeapi_" . $node->type . "_" . str_replace(" ", "_", $op);
  294. foreach (module_implements($hook) as $module) {
  295. $function = $module . '_' . $hook;
  296. $result = $function($node, $arg1, $arg2);
  297. if (isset($result) && is_array($result)) {
  298. $return = array_merge_recursive($return, $result);
  299. }
  300. elseif (isset($result)) {
  301. $return[] = $result;
  302. }
  303. }
  304. return $return;
  305. }
  306. /**
  307. * Implements hook_permission().
  308. */
  309. function hosting_permission() {
  310. return array(
  311. 'access hosting wizard' => array(
  312. 'title' => t('access hosting wizard'),
  313. 'description' => t("TODO Remove 'access hosting wizard', as it is not checked anywhere."),
  314. ),
  315. 'administer hosting queues' => array(
  316. 'title' => t('administer hosting queues'),
  317. 'description' => t('Configure the frequency that cron, backup and task events are process.'),
  318. ),
  319. 'administer hosting features' => array(
  320. 'title' => t('administer hosting features'),
  321. 'description' => t('Configure the exposed functionality of the hosting system.'),
  322. ),
  323. 'administer hosting' => array(
  324. 'title' => t('administer hosting'),
  325. 'description' => t('Configure and manage the hosting system.'),
  326. ),
  327. 'access disabled sites' => array(
  328. 'title' => t('access disabled sites'),
  329. 'description' => t('Access disabled sites.'),
  330. ),
  331. 'administer hosting settings' => array(
  332. 'title' => t('administer hosting settings'),
  333. 'description' => t('Configure general hosting settings.'),
  334. ),
  335. );
  336. }
  337. /**
  338. * Per node type description text. To be stored in the node_type table.
  339. *
  340. * @param string $type
  341. * The node type.
  342. *
  343. * @return string
  344. * Description text for the node type.
  345. */
  346. function hosting_node_help($type) {
  347. switch ($type) {
  348. case 'site':
  349. return t("<strong>An instance of a hosted site.</strong>\nIt contains information relating to the site, most notably the domain name, database server and platform it is being published on. A site may also have several aliases for additional domains the site needs to be accessible on.");
  350. case 'platform':
  351. return t("<strong>The file system location on a specific web server on which to publish sites.</strong>\nMultiple platforms can co-exist on the same web server, and need to do so for upgrades to be managed, as this is accomplished by migrating the site between platforms. Platforms are most commonly built for specific releases of Drupal.");
  352. case 'client':
  353. return t("<strong>The person or group that runs the site.</strong>\nThis information is usually required for billing and access purposes, to ensure that only certain people are able to view the information for sites they run. If you do not intend on having more than one client access the system, you will not need to create any additional clients for your purposes.");
  354. case 'server':
  355. return t("<strong>The physical machine which will provide various services to your site.</strong>\n Each server can have multiple services associated to it. To host a site you require a database service and a web service, which can either be provided by a single or multiple servers.");
  356. case 'task':
  357. return t("<strong>The mechanism whereby Hostmaster keeps track of all changes that occur to the system.</strong>\nEach task acts as a command for the back-end, and contains a full log of all changes that have occurred. If a task should fail, the administrator will be notified with an explanation of exactly what went wrong, and how to fix it.");
  358. case 'package':
  359. return t("PLACEHOLDER");
  360. }
  361. }
  362. /**
  363. * Implements hook_init().
  364. */
  365. function hosting_init() {
  366. static $already_called = FALSE;
  367. if ($already_called) {
  368. return;
  369. }
  370. $already_called = TRUE;
  371. // Definitions for the default platforms, clients etc.
  372. // Done to avoid using 'magic numbers'
  373. define('HOSTING_DEFAULT_CLIENT', variable_get('hosting_default_client', 1));
  374. define('HOSTING_DEFAULT_DB_SERVER', variable_get('hosting_default_db_server', 4));
  375. define('HOSTING_DEFAULT_WEB_SERVER', variable_get('hosting_default_web_server', 3));
  376. // This client has access to everything, see hosting_client.access.inc
  377. define('HOSTING_ADMIN_CLIENT', variable_get('hosting_admin_client', 1));
  378. define('HOSTING_OWN_DB_SERVER', variable_get('hosting_own_db_server', 2));
  379. define('HOSTING_OWN_WEB_SERVER', variable_get('hosting_own_web_server', 3));
  380. define('HOSTING_OWN_PLATFORM', variable_get('hosting_own_platform', 6));
  381. // Find the base URL, this is used by the initial 'hosting-setup' Drush
  382. // command. This gets defined in the bootstrap, so just using the global
  383. // definition.
  384. define('HOSTING_DEFAULT_BASE_URL', $GLOBALS['base_url']);
  385. // Moved from hook_menu()
  386. drupal_add_css(drupal_get_path('module', 'hosting') . '/hosting.css');
  387. }
  388. /**
  389. * Implements hook_theme().
  390. */
  391. function hosting_theme() {
  392. return array(
  393. 'hosting_queues_configure' => array(
  394. 'file' => 'hosting.module',
  395. 'render element' => 'form',
  396. ),
  397. 'hosting_feature_dependencies' => array(
  398. 'file' => 'hosting.features.inc',
  399. 'arguments' => array(
  400. 'dependencies' => NULL,
  401. 'prefix' => NULL,
  402. 'features' => NULL,
  403. ),
  404. ),
  405. );
  406. }
  407. /**
  408. * Generates a link to a node.
  409. */
  410. function _hosting_node_link($nid, $title = NULL) {
  411. if (is_null($nid)) {
  412. return t("None");
  413. }
  414. $node = node_load($nid);
  415. if (!isset($title)) {
  416. $title = isset($node->title) ? $node->title : NULL;
  417. // Override with the human-readable name, when available.
  418. $title = isset($node->human_name) && strlen($node->human_name) ? $node->human_name : $title;
  419. }
  420. $title = filter_xss($title);
  421. if (isset($node->nid)) {
  422. return node_access('view', $node) ? l($title, "node/" . $node->nid) : $title;
  423. }
  424. }
  425. /**
  426. * Implements hook_block_info().
  427. */
  428. function hosting_block_info() {
  429. $blocks['hosting_summary'] = array(
  430. 'info' => t('Hosting summary'),
  431. 'enabled' => 1,
  432. 'status' => 1,
  433. 'region' => 'sidebar_second',
  434. 'weight' => 10,
  435. );
  436. $blocks['hosting_queues'] = array(
  437. 'info' => t('Hosting queues'),
  438. 'enabled' => 1,
  439. 'status' => 1,
  440. 'region' => 'sidebar_first',
  441. 'weight' => 0,
  442. );
  443. $blocks['hosting_queues_summary'] = array(
  444. 'info' => t('Hosting queues summary'),
  445. 'enabled' => 1,
  446. 'status' => 1,
  447. 'region' => 'sidebar_first',
  448. 'weight' => 1,
  449. 'cache' => 'BLOCK_NO_CACHE',
  450. );
  451. $blocks['hosting_supporting_aegir'] = array(
  452. 'info' => t('Support Aegir'),
  453. 'enabled' => 1,
  454. 'status' => 1,
  455. 'region' => 'sidebar_second',
  456. 'weight' => 1,
  457. );
  458. return $blocks;
  459. }
  460. /**
  461. * Implements hook_block_view().
  462. */
  463. function hosting_block_view($delta) {
  464. $out = NULL;
  465. switch ($delta) {
  466. case 'hosting_queues':
  467. $out = array(
  468. 'title' => t('Queues'),
  469. 'content' => hosting_queue_block(),
  470. );
  471. break;
  472. case 'hosting_queues_summary':
  473. $out = array(
  474. 'title' => t('Queues summary'),
  475. 'content' => hosting_queue_summary_block(),
  476. );
  477. break;
  478. case 'hosting_supporting_aegir':
  479. $out = array(
  480. 'title' => t('Support Aegir'),
  481. 'content' => hosting_supporting_aegir_block(),
  482. );
  483. break;
  484. }
  485. return $out;
  486. // @todo where is 'hosting_summary'?
  487. }
  488. /**
  489. * Build a block summarising the hosting queues.
  490. */
  491. function hosting_queue_summary_block() {
  492. if (user_access('administer hosting queues')) {
  493. $queues = hosting_get_queues();
  494. $output = '';
  495. foreach ($queues as $queue => $info) {
  496. $disp = array();
  497. // Special case.
  498. if (!$info['enabled']) {
  499. $disp[] = t('Status: disabled');
  500. continue;
  501. }
  502. $disp[] = t('Status: enabled');
  503. foreach (array(
  504. 'description' => t('Description'),
  505. 'frequency' => t('Frequency'),
  506. 'items' => t('Items per run'),
  507. 'total_items' => t('Items in queue'),
  508. 'last_run' => t('Last run'),
  509. ) as $key => $title) {
  510. if ($key == 'last_run') {
  511. $info[$key] = hosting_format_interval($info[$key]);
  512. }
  513. elseif ($key == 'frequency') {
  514. $info[$key] = t('every @interval', array('@interval' => format_interval($info[$key])));
  515. }
  516. $disp[] = $title . ": " . $info[$key];
  517. }
  518. $output .= theme('item_list', array('items' => $disp, 'title' => $info['name']));
  519. }
  520. return $output;
  521. }
  522. }
  523. /**
  524. * Build a block of the hosting queues.
  525. *
  526. * @see hosting_TASK_SINGULAR_summary()
  527. */
  528. function hosting_queue_block() {
  529. if (user_access('access task logs')) {
  530. $queues = hosting_get_queues();
  531. $output = '';
  532. foreach ($queues as $queue => $info) {
  533. $func = 'hosting_' . $info['singular'] . '_summary';
  534. if (function_exists($func)) {
  535. $output .= $func();
  536. }
  537. }
  538. return $output;
  539. }
  540. }
  541. /**
  542. * Build a 'Support Aegir' block.
  543. */
  544. function hosting_supporting_aegir_block() {
  545. if (user_access('administer hosting')) {
  546. $output = "
  547. <p>Aegir will always cost you nothing to use, but that doesn't mean it costs us nothing to make.</p>
  548. <p><strong>Aegir needs your continued support to grow and thrive.</strong></p>
  549. <p>If you feel that Aegir has added significant value to your business or endeavour, please consider donating!</p>
  550. <p><strong>How much is Aegir worth to you?</strong></p>
  551. <a href=\"http://community.aegirproject.org/donate\" target=_blank>Donate Now ... </a>
  552. <footer style=\"font-size: smaller;\">This block is only displayed to you, the superuser.</footer>
  553. ";
  554. return $output;
  555. }
  556. }
  557. /**
  558. * Check site URL is allowed.
  559. *
  560. * This function hooks into hook_allow_domain to let contrib modules
  561. * weigh in on whether the site should be created.
  562. *
  563. * All the hooks must return true for the domain to be allowed.
  564. *
  565. * @see hook_allow_domain()
  566. */
  567. function hosting_domain_allowed($url, $params = array()) {
  568. $results = module_invoke_all('allow_domain', $url, $params);
  569. $return = !in_array(FALSE, $results);
  570. return $return;
  571. }
  572. /**
  573. * Initial hosting setup drush command.
  574. *
  575. * Runs the 'hosting-dispatch' command, and sets up the crontab.
  576. */
  577. function drush_hosting_setup() {
  578. if (drush_confirm("This command will replace your crontab for this user. continue?")) {
  579. variable_set('hosting_dispatch_enabled', FALSE);
  580. // Attempt to run the dispatch command, to make sure it runs without the
  581. // queue being enabled.
  582. variable_set('hosting_dispatch_enabled', TRUE);
  583. drush_print(_hosting_dispatch_cmd());
  584. exec(_hosting_dispatch_cmd(), $return, $code);
  585. variable_set('hosting_dispatch_enabled', FALSE);
  586. $return = implode("\n", $return);
  587. $data = unserialize($return);
  588. if ($code == DRUSH_SUCCESS) {
  589. variable_set('hosting_dispatch_enabled', TRUE);
  590. drush_log(t("Dispatch command was run successfully"), 'success');
  591. _hosting_setup_cron();
  592. }
  593. else {
  594. drush_set_error('DRUSH_FRAMEWORK_ERROR', dt("Dispatch command could not be run. Returned: \n@return", array('@return' => $return)));
  595. }
  596. if (drush_get_error()) {
  597. drush_log(t("The command did not complete successfully, please fix the issues and re-run this script"), 'error');
  598. }
  599. }
  600. }
  601. /**
  602. * Set up the hosting-dispatch command in the aegir user's crontab.
  603. *
  604. * Replace the crontab entry if it exists, else create it from scratch.
  605. */
  606. function _hosting_setup_cron($add = TRUE) {
  607. $existing = FALSE;
  608. $cron = '';
  609. $cron_lines = array();
  610. // Load any existing crontab.
  611. exec('crontab -l 2> /dev/null', $cron_lines);
  612. variable_set('hosting_cron_backup', $cron_lines);
  613. if (count($cron_lines)) {
  614. drush_log(dt("Replacing existing crontab"), 'warning');
  615. $cron_lines = hosting_queues_cron_removal($cron_lines);
  616. $cron = implode("\n", $cron_lines);
  617. }
  618. else {
  619. drush_log(dt("No existing crontab was found"), 'message');
  620. }
  621. if ($add) {
  622. // Append the fresh Aegir specific lines.
  623. $cron .= "\n" . hosting_queues_cron_cmd();
  624. drush_log(dt("Adding hosting-dispatch cron entry to run every minute"), 'ok');
  625. }
  626. // Write a new crontab.
  627. $fp = popen('crontab -', 'w');
  628. $success = TRUE;
  629. if ($fp) {
  630. if (fwrite($fp, $cron) && fwrite($fp, "\n")) {
  631. $success = TRUE;
  632. }
  633. else {
  634. $success = FALSE;
  635. }
  636. // 'pclose' returns shell exit codes (ie. 0 is success).
  637. if (pclose($fp)) {
  638. $success = FALSE;
  639. }
  640. }
  641. else {
  642. $success = FALSE;
  643. }
  644. if ($success) {
  645. drush_log(dt("Installed a new crontab entry."), 'success');
  646. }
  647. else {
  648. drush_set_error('PROVISION_CRON_FAILED', dt('Failed to install cron job'));
  649. }
  650. }
  651. /**
  652. * Replacement node/add page.
  653. *
  654. * Major kludge to remove the hidden node types from node/add page.
  655. *
  656. * Copied from node.module.
  657. */
  658. function _hosting_node_add($type = '') {
  659. global $user;
  660. $types = node_type_get_types();
  661. $type = ($type) ? str_replace('-', '_', $type) : NULL;
  662. // If a node type has been specified, validate its existence.
  663. if (isset($types[$type]) && user_access('create ' . $type) && (hosting_feature($type) !== HOSTING_FEATURE_DISABLED)) {
  664. // Initialize settings:
  665. $node = array(
  666. 'uid' => $user->uid,
  667. 'name' => $user->name,
  668. 'type' => $type,
  669. );
  670. drupal_set_title(t('Submit @name', array('@name' => $types[$type]->name)), PASS_THROUGH);
  671. // TODO $node needs to have $form as its first parameter.
  672. $output = drupal_get_form($type . '_node_form', $node);
  673. }
  674. else {
  675. // If no (valid) node type has been provided, display a node type overview.
  676. foreach ($types as $type) {
  677. if (function_exists($type->module . '_form') && user_access('create ' . $type->type) && (hosting_feature($type->type) !== HOSTING_FEATURE_DISABLED)) {
  678. $type_url_str = str_replace('_', '-', $type->type);
  679. $title = t('Add a new @s.', array('@s' => $type->name));
  680. $out = '<dt>' . l(drupal_ucfirst($type->name), "node/add/$type_url_str", array('attributes' => array('title' => $title))) . '</dt>';
  681. $out .= '<dd>' . filter_xss_admin($type->description) . '</dd>';
  682. $item[$type->name] = $out;
  683. }
  684. }
  685. if (isset($item)) {
  686. uksort($item, 'strnatcasecmp');
  687. $output = t('Choose the appropriate item from the list:') . '<dl>' . implode('', $item) . '</dl>';
  688. }
  689. else {
  690. $output = t('No content types available.');
  691. }
  692. }
  693. return $output;
  694. }
  695. /**
  696. * List queues or tasks in a queue if a key is provided.
  697. *
  698. * @see hosting_TASK_SINGULAR_list()
  699. */
  700. function hosting_queues($key = '') {
  701. $queues = hosting_get_queues();
  702. $output = '';
  703. if ($queues[$key]) {
  704. if ($queues[$key]['name']) {
  705. $output .= "<h1>" . $queues[$key]['name'] . "</h1>";
  706. }
  707. $func = 'hosting_' . $queues[$key]['singular'] . '_list';
  708. if (function_exists($func)) {
  709. $output .= $func();
  710. }
  711. }
  712. else {
  713. foreach ($queues as $key => $queue) {
  714. $item[] = l($queue['name'], 'hosting/queues/' . $key);
  715. }
  716. $output .= theme('item_list', array('items' => $item, 'title' => t('Queues')));
  717. }
  718. return $output;
  719. }
  720. /**
  721. * Generate context sensitive breadcrumbs.
  722. *
  723. * @param object $node
  724. * A node object to use for context of the breadcrumbs.
  725. */
  726. function hosting_set_breadcrumb($node) {
  727. $breadcrumbs[] = l(t('Home'), NULL);
  728. switch ($node->type) {
  729. case 'task':
  730. $breadcrumbs[] = _hosting_node_link($node->rid);
  731. break;
  732. case 'platform':
  733. $breadcrumbs[] = _hosting_node_link($node->web_server);
  734. break;
  735. case 'site':
  736. $breadcrumbs[] = _hosting_node_link($node->platform);
  737. break;
  738. case 'server':
  739. $breadcrumbs[] = l(t('Servers'), 'hosting/servers');
  740. break;
  741. }
  742. drupal_set_breadcrumb($breadcrumbs);
  743. }
  744. /**
  745. * Form to configure the frequency of queue execution.
  746. */
  747. function hosting_queues_configure($form, &$form_state) {
  748. drupal_add_css(drupal_get_path('module', 'hosting') . '/hosting.css');
  749. $units = array(
  750. strtotime("1 second", 0) => t("Seconds"),
  751. strtotime("1 minute", 0) => t("Minutes"),
  752. strtotime("1 hour", 0) => t("Hours"),
  753. strtotime("1 day", 0) => t("Days"),
  754. strtotime("1 week", 0) => t("Weeks"),
  755. );
  756. $queues = hosting_get_queues();
  757. $form['#tree'] = TRUE;
  758. foreach ($queues as $queue => $info) {
  759. $form[$queue]['description'] = array(
  760. '#type' => 'item',
  761. '#value' => $info['name'],
  762. '#description' => $info['description'],
  763. );
  764. $form[$queue]["enabled"] = array(
  765. '#type' => 'checkbox',
  766. '#default_value' => $info['enabled'],
  767. );
  768. $form[$queue]["last_run"] = array(
  769. '#value' => hosting_format_interval(variable_get('hosting_queue_' . $queue . '_last_run', FALSE)),
  770. );
  771. $form[$queue]['frequency']['#prefix'] = "<div class='hosting-queue-frequency'>";
  772. $form[$queue]['frequency']['#suffix'] = "</div>";
  773. if ($info['type'] == 'batch') {
  774. $form[$queue]['frequency']['items'] = array(
  775. '#markup' => t('%count %items every', array(
  776. "%count" => $info['total_items'],
  777. "%items" => format_plural($info['total_items'], $info['singular'], $info['plural']),
  778. )),
  779. '#prefix' => "<div class='hosting-queue-frequency-items'>",
  780. '#suffix' => "</div>",
  781. );
  782. }
  783. else {
  784. $form[$queue]['frequency']['items'] = array(
  785. '#type' => 'textfield',
  786. '#size' => 3,
  787. '#maxlength' => 3,
  788. '#default_value' => $info['items'],
  789. // @ignore i18n_11
  790. '#suffix' => ' ' . t('%items every', array('%items' => $info['plural'])) . ' ',
  791. '#attributes' => array(
  792. 'class' => array('hosting-select-frequency-items'),
  793. ),
  794. );
  795. }
  796. foreach (array_reverse(array_keys($units)) as $length) {
  797. $unit = $units[$length];
  798. if (!($info['frequency'] % $length)) {
  799. $frequency_ticks = $info['frequency'] / $length;
  800. $frequency_length = $length;
  801. break;
  802. }
  803. }
  804. $form[$queue]['frequency']["ticks"] = array(
  805. '#type' => 'textfield',
  806. '#default_value' => $frequency_ticks,
  807. '#maxlength' => 5,
  808. '#size' => 5,
  809. '#attributes' => array(
  810. 'class' => array('hosting-select-frequency-ticks'),
  811. ),
  812. );
  813. $form[$queue]['frequency']["unit"] = array(
  814. '#type' => 'select',
  815. '#options' => $units,
  816. '#default_value' => $frequency_length,
  817. '#attributes' => array(
  818. 'class' => array('hosting-select-frequency-unit'),
  819. ),
  820. );
  821. }
  822. $form['help'] = array(
  823. '#type' => 'item',
  824. '#description' => t("Increasing the queue frequency to every 1 second will not cause them to be dispatched every second, as the dispatcher can only run once per minute via cron. However, with such a short frequency, executing the hosting-dispatch command manually from the CLI will allow you to 'force' the queues to be dispatched between cron runs. This may be useful for development purposes."),
  825. );
  826. $form['submit'] = array(
  827. '#type' => 'submit',
  828. '#value' => t('Save changes'),
  829. );
  830. return $form;
  831. }
  832. /**
  833. * Theme function to render the queue configuration form.
  834. *
  835. * @see hosting_queues_configure()
  836. */
  837. function theme_hosting_queues_configure($variables) {
  838. $form = $variables['form'];
  839. $queues = hosting_get_queues();
  840. $rows = array();
  841. $header = array(
  842. '',
  843. t('Description'),
  844. array(
  845. 'data' => t('Frequency'),
  846. 'class' => array('hosting-queue-frequency-head'),
  847. ),
  848. t('Last run'),
  849. );
  850. foreach ($queues as $key => $info) {
  851. $row = array();
  852. $row[] = drupal_render($form[$key]['enabled']);
  853. $row[] = drupal_render($form[$key]['description']);
  854. $row[] = drupal_render($form[$key]['frequency']);
  855. $row[] = drupal_render($form[$key]['last_run']);
  856. $rows[] = $row;
  857. }
  858. $output = theme('table', array('header' => $header, 'rows' => $rows));
  859. $output .= drupal_render($form['help']);
  860. $output .= drupal_render($form['submit']);
  861. $output .= drupal_render_children($form);
  862. return $output;
  863. }
  864. /**
  865. * Validation callback for the the queue execution frequency form.
  866. *
  867. * @see hosting_queues_configure()
  868. */
  869. function hosting_queues_configure_validate($form, &$form_state) {
  870. foreach (hosting_get_queues() as $queue => $info) {
  871. if ($form_state['values'][$queue]) {
  872. if ($form_state['values'][$queue]['frequency']['ticks'] && !is_numeric($form_state['values'][$queue]['frequency']['ticks'])) {
  873. form_set_error($queue, t('Please enter a valid frequency.'));
  874. }
  875. if (isset($form_state['values'][$queue]['frequency']['items']) && !is_numeric($form_state['values'][$queue]['frequency']['items'])) {
  876. form_set_error($queue, t('Please enter a valid amount of items.'));
  877. }
  878. }
  879. }
  880. }
  881. /**
  882. * Submit callback for the the queue execution frequency form.
  883. *
  884. * @see hosting_queues_configure()
  885. */
  886. function hosting_queues_configure_submit($form, &$form_state) {
  887. foreach (hosting_get_queues() as $queue => $info) {
  888. if ($form_state['values'][$queue]) {
  889. variable_set("hosting_queue_" . $queue . "_enabled", $form_state['values'][$queue]['enabled']);
  890. variable_set("hosting_queue_" . $queue . "_frequency", $form_state['values'][$queue]['frequency']['ticks'] * $form_state['values'][$queue]['frequency']['unit']);
  891. if ($info['type'] == 'serial') {
  892. variable_set("hosting_queue_" . $queue . "_items", $form_state['values'][$queue]['frequency']['items']);
  893. }
  894. }
  895. }
  896. drupal_set_message(t('The queue settings have been updated.'));
  897. }
  898. /**
  899. * Implements hook_form_alter().
  900. */
  901. function hosting_form_alter(&$form, &$form_state, $form_id) {
  902. // Do not allow package or task nodes to be edited through the interface.
  903. if ($form_id == 'package_node_form' || $form_id == 'task_node_form') {
  904. drupal_access_denied();
  905. exit;
  906. }
  907. // Alter the 'Add User' form to remind users that this is not the New Client
  908. // form.
  909. if ($form_id == 'user_register') {
  910. $form['user_registration_help'] = array(
  911. '#type' => 'item',
  912. '#description' => t('<strong>Adding a system user account does not make the user a Client that can add sites.</strong><br />
  913. To add a Client, enable the Client feature and then add a new Client node.<br />
  914. If you wish, you may then assign this system user to the Client as an \'Allowed user\' to inherit the permissions to add sites.'),
  915. '#weight' => '-10',
  916. );
  917. }
  918. // Remove additional UI added by core modules, it conflicts with the our UI.
  919. $node_types = array('site', 'platform', 'server', 'client');
  920. foreach ($node_types as $type) {
  921. if ($form_id == $type . '_node_form') {
  922. $form['options']['#access'] = FALSE;
  923. $form['revision_information']['#access'] = FALSE;
  924. $form['author']['#access'] = FALSE;
  925. // Because these aren't really posts, 'preview' doesn't make sense in
  926. // this context.
  927. $form['actions']['preview']['#access'] = FALSE;
  928. // Add our own helpful messages.
  929. $form['#submit'][] = 'hosting_form_submit_messages';
  930. }
  931. }
  932. }
  933. /**
  934. * Submit handler for hosting node forms: Display helpful messages.
  935. */
  936. function hosting_form_submit_messages($form, $form_state) {
  937. // Only act on sites, platforms, & servers.
  938. if (in_array($form_state['node']->type, array('site', 'platform', 'server'))) {
  939. // Translation array.
  940. $t = array(
  941. '@type' => $form_state['node']->type,
  942. '%title' => $form_state['values']['title'],
  943. '%task' => t('Verify'),
  944. );
  945. // If this is an add form...
  946. if (!isset($form_state['node']->nid)) {
  947. $t['!message'] = t('It will be available once the task is completed.');
  948. // If node is a site, task is "install".
  949. if ($form_state['node']->type == 'site') {
  950. $t['%task'] = t('Install');
  951. }
  952. }
  953. // If this is an edit form, mention changes being applied.
  954. else {
  955. $t['!message'] = t('Changes will be applied once the task is completed.');
  956. }
  957. // Display the message.
  958. drupal_set_message(t('%task task has been queued for @type %title. !message', $t));
  959. // If using the hosting queue, mention the scheduled time.
  960. $queues = hosting_get_queues();
  961. if ($queues['tasks']['enabled']) {
  962. $until = _hosting_queue_next_run('tasks') - REQUEST_TIME;
  963. drupal_set_message(t('Task is scheduled to start in approximately %until.', array('%until' => format_interval($until))));
  964. }
  965. }
  966. }
  967. /**
  968. * Get the node associated with a given provision context.
  969. *
  970. * @param string $name
  971. * The name of the context to load.
  972. *
  973. * @return bool|object
  974. * Either the node object associated with the context, or FALSE if no
  975. */
  976. function hosting_context_load($name) {
  977. $name = ltrim($name, '@');
  978. // TODO: introduce static caching ?
  979. $result = db_query("SELECT nid FROM {hosting_context} WHERE name = :name", array(':name' => $name));
  980. if ($obj = $result->fetch()) {
  981. return node_load($obj->nid);
  982. }
  983. return FALSE;
  984. }
  985. /**
  986. * Add a node to the context lookup db.
  987. *
  988. * @param int $nid
  989. * The nid of the node to associate to the given provision context name.
  990. * @param string $name
  991. * The name of the provision context.
  992. */
  993. function hosting_context_register($nid, $name) {
  994. // Check first to see if this nid exists in the system. If so, update its
  995. // name.
  996. if ($result = db_query("SELECT nid FROM {hosting_context} WHERE nid = :nid", array(':nid' => $nid))->fetch()) {
  997. db_update('hosting_context')
  998. ->fields(array(
  999. 'name' => $name,
  1000. ))
  1001. ->condition('nid', $nid)
  1002. ->execute();
  1003. }
  1004. else {
  1005. // It's a new item.
  1006. $id = db_insert('hosting_context')
  1007. ->fields(array(
  1008. 'nid' => $nid,
  1009. 'name' => $name,
  1010. ))
  1011. ->execute();
  1012. }
  1013. // We include the file instead of enabling the module,
  1014. // because we do not want the overhead of having all the
  1015. // path UI stuff on nodes.
  1016. require_once DRUPAL_ROOT . '/modules/path/path.module';
  1017. // Delete an existing alias,
  1018. // could be left behind after migrating a site from this name.
  1019. path_delete(array('alias' => "hosting/c/$name"));
  1020. // Add the new alias.
  1021. $path = array('source' => "node/$nid", 'alias' => "hosting/c/$name");
  1022. path_save($path);
  1023. }
  1024. /**
  1025. * Delete an alias from the context lookup table.
  1026. *
  1027. * @param int $nid
  1028. * The nid of the node to remove the association from.
  1029. */
  1030. function hosting_context_delete($nid) {
  1031. path_delete(array('source' => 'node/' . $nid));
  1032. db_delete('hosting_context')
  1033. ->condition('nid', $nid)
  1034. ->execute();
  1035. }
  1036. /**
  1037. * Return the hosting context name for a node.
  1038. *
  1039. * @param int $nid
  1040. * The nid of the node to get the provision context name for.
  1041. *
  1042. * @return string|bool
  1043. * The provision context name associated with the specified node, will be
  1044. * prefixed with '@' or FALSE if node doesnt exist.
  1045. */
  1046. function hosting_context_name($nid) {
  1047. $node = node_load($nid);
  1048. if (!$node) {
  1049. drupal_set_message(t('Error: cannot load node id %nid to find its context', array('%nid' => $nid)), 'error');
  1050. return FALSE;
  1051. }
  1052. return '@' . $node->hosting_name;
  1053. }
  1054. /**
  1055. * Lookup the node ID for a hosting context name.
  1056. *
  1057. * @param object|string $alias
  1058. * The name of the provision context to import.
  1059. *
  1060. * @return int
  1061. * The node ID associated with the alias.
  1062. */
  1063. function hosting_context_nid($alias) {
  1064. $name = (is_object($alias)) ? $alias->name : $alias;
  1065. $name = ltrim($name, '@');
  1066. $result = db_query("SELECT nid FROM {hosting_context} WHERE name = :name", array(':name' => $name));
  1067. if ($obj = $result->fetch()) {
  1068. return $obj->nid;
  1069. }
  1070. else {
  1071. return hosting_drush_import($alias);
  1072. }
  1073. }
  1074. /**
  1075. * Define the node types that have associated provision contexts.
  1076. */
  1077. function hosting_context_node_types() {
  1078. return array('site', 'platform', 'server');
  1079. }
  1080. /**
  1081. * Implements hook_views_api().
  1082. */
  1083. function hosting_views_api() {
  1084. return array(
  1085. 'api' => 3,
  1086. 'path' => drupal_get_path('module', 'hosting') . '/includes/views',
  1087. );
  1088. }
  1089. /**
  1090. * General settings form.
  1091. */
  1092. function hosting_settings($form, &$form_state) {
  1093. $form['settings'] = array(
  1094. '#type' => 'item',
  1095. '#title' => t('General Hosting settings'),
  1096. '#value' => t('Here you may set various general settings that apply to site management or to the frontend system.'),
  1097. '#weight' => 0,
  1098. );
  1099. $profiles = array();
  1100. foreach (hosting_get_profiles() as $id => $name) {
  1101. $profile = hosting_package_instance_load(array('p.nid' => $id));
  1102. $profiles[$profile->short_name] = theme('hosting_site_profile', array('profile' => $profile, 'html' => ''));
  1103. // Don't allow a site to be provisioned a restricted profile.
  1104. if (in_array($name, array('Hostslave', 'Hostmaster'))) {
  1105. unset($profiles[$profile->short_name]);
  1106. }
  1107. }
  1108. natcasesort($profiles);
  1109. $default_value = hosting_package_instance_load(array('p.nid' => hosting_get_default_profile()))->short_name;
  1110. $form['hosting_default_profile'] = array(
  1111. '#type' => 'select',
  1112. '#title' => t('Default profile'),
  1113. '#options' => $profiles,
  1114. '#description' => t('The default install profile to use when creating new sites.'),
  1115. '#default_value' => $default_value,
  1116. );
  1117. $form['hosting_ignore_default_profiles'] = array(
  1118. '#type' => 'checkbox',
  1119. '#title' => t('Hide platforms with non-default profiles'),
  1120. '#description' => t('When selecting a Drupal core profile, hide platforms that also contain other profiles (i.e intended as distributions). Warning: requires a platform other than the Hostmaster platform.'),
  1121. '#default_value' => variable_get('hosting_ignore_default_profiles', FALSE),
  1122. );
  1123. $form['hosting_lock_platforms_by_default'] = array(
  1124. '#type' => 'checkbox',
  1125. '#title' => t('Lock platforms by default on initial creation'),
  1126. '#description' => t("When verifying a new platform, set its initial state to 'Locked'. This can avoid having sites created on a new platform before there has been a chance to test it. Those users with the 'create sites on locked platforms' permission (e.g., with the 'platform manager' role) will still be able to build sites."),
  1127. '#default_value' => variable_get('hosting_lock_platforms_by_default', FALSE),
  1128. );
  1129. $form['hosting_require_disable_before_delete'] = array(
  1130. '#type' => 'checkbox',
  1131. '#title' => t('Require site to be disabled before deletion'),
  1132. '#description' => t('Check if you wish for users to run the Disable task on a site prior to running the Delete task.'),
  1133. '#default_value' => variable_get('hosting_require_disable_before_delete', TRUE),
  1134. );
  1135. if (hosting_feature('cron')) {
  1136. $form['hosting_cron_use_backend'] = array(
  1137. '#type' => 'radios',
  1138. '#title' => t('Cron method'),
  1139. '#description' => t('For running cron on a site. You can use the drush cron implementation or the web-based cron.php method using builtin HTTP requests. The drush implementation is more reliable but will be slower than the web-based approach if the webserver has an opcode cache (like APC) configured.'),
  1140. '#options' => array('Web-based', 'Drush'),
  1141. '#default_value' => variable_get('hosting_cron_use_backend', TRUE),
  1142. );
  1143. }
  1144. return system_settings_form($form);
  1145. }
  1146. /**
  1147. * Create the default hosting roles.
  1148. */
  1149. function hosting_create_roles() {
  1150. // Only allow access to our splash pages for anyone without a specific role.
  1151. user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access disabled sites'));
  1152. user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, array('access disabled sites'));
  1153. // Create a default role for Aegir clients.
  1154. $client_role = new stdClass();
  1155. $client_role->name = 'aegir client';
  1156. $client_role->weight = 4;
  1157. user_role_save($client_role);
  1158. // Create a default role for Aegir account managers.
  1159. $acct_mgr_role = new stdClass();
  1160. $acct_mgr_role->name = 'aegir account manager';
  1161. $acct_mgr_role->weight = 6;
  1162. user_role_save($acct_mgr_role);
  1163. // Create a default role for Aegir platform managers.
  1164. $plat_mgr_role = new stdClass();
  1165. $plat_mgr_role->name = 'aegir platform manager';
  1166. $plat_mgr_role->weight = 8;
  1167. user_role_save($plat_mgr_role);
  1168. // Create a default role for Aegir administrators.
  1169. $aegir_admin_role = new stdClass();
  1170. $aegir_admin_role->name = 'aegir administrator';
  1171. $aegir_admin_role->weight = 10;
  1172. user_role_save($aegir_admin_role);
  1173. // Create a default role for site administrators,
  1174. // with all available permissions assigned.
  1175. $admin_role = new stdClass();
  1176. $admin_role->name = 'administrator';
  1177. $admin_role->weight = 20;
  1178. user_role_save($admin_role);
  1179. user_role_grant_permissions($admin_role->rid, array_keys(module_invoke_all('permission')));
  1180. // Set this as the administrator role.
  1181. variable_set('user_admin_role', $admin_role->rid);
  1182. // Assign user 1 the "administrator" role.
  1183. db_insert('users_roles')
  1184. ->fields(array('uid' => 1, 'rid' => $admin_role->rid))
  1185. ->execute();
  1186. node_access_rebuild();
  1187. }
  1188. /**
  1189. * Implements hook_modules_enabled().
  1190. */
  1191. function hosting_modules_enabled($modules) {
  1192. // List any features whose module was just enabled.
  1193. $features = hosting_get_features();
  1194. $enable = array();
  1195. foreach ($features as $feature => $info) {
  1196. if (in_array($info['module'], $modules) && !variable_get('hosting_feature_' . $feature, FALSE)) {
  1197. $enable[$info['module']] = $feature;
  1198. }
  1199. }
  1200. hosting_features_enable($enable, TRUE, FALSE);
  1201. }
  1202. /**
  1203. * Implements hook_modules_disabled().
  1204. */
  1205. function hosting_modules_disabled($modules) {
  1206. // List any features whose module was just disabled.
  1207. $features = hosting_get_features();
  1208. $disable = array();
  1209. foreach ($features as $feature => $info) {
  1210. if (in_array($info['module'], $modules) && variable_get('hosting_feature_' . $feature, TRUE)) {
  1211. $disable[$info['module']] = $feature;
  1212. }
  1213. }
  1214. hosting_features_disable($disable, $rebuild = TRUE, $disable_module = FALSE);
  1215. }