View source
<?php
use TQ\Git\Repository\Repository;
use GitWrapper\GitWrapper;
use GitWrapper\GitWorkingCopy;
use GitWrapper\GitException;
use DevShop\Component\PowerProcess\PowerProcess;
define('HOSTING_SITE_DELETED', -2);
define('HOSTING_SITE_DISABLED', -1);
define('HOSTING_SITE_QUEUED', 0);
define('HOSTING_SITE_ENABLED', 1);
include_once 'hosting_site.nodeapi.inc';
include_once 'hosting_site.form.inc';
include_once 'hosting_site.backups.inc';
if (module_exists('hosting_quota')) {
include_once 'hosting_site.quota.inc';
}
function hosting_site_menu() {
$items = array();
$items['hosting/sites/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['hosting/sites/add'] = array(
'title' => 'Add site',
'type' => MENU_LOCAL_TASK,
'page callback' => 'drupal_goto',
'page arguments' => array(
'node/add/site',
),
'access callback' => 'node_access',
'access arguments' => array(
'create',
'site',
),
);
$items['node/%node/platform-add-site'] = array(
'title' => 'Add site',
'type' => MENU_LOCAL_TASK,
'page callback' => 'hosting_site_add_by_platform',
'page arguments' => array(
1,
),
'access callback' => 'hosting_site_add_by_platform_access',
'access arguments' => array(
1,
),
);
$items['hosting/hosting_site_form_check'] = array(
'page callback' => '_hosting_site_form_check',
'type' => MENU_CALLBACK,
'access arguments' => array(
'access content',
),
);
$items['hosting/sites/autocomplete'] = array(
'title' => 'Autocomplete for sites',
'page callback' => 'hosting_site_autocomplete_sites',
'access arguments' => array(
'access content',
),
'type' => MENU_CALLBACK,
);
$items['node/%node/goto_site'] = array(
'page callback' => 'hosting_site_goto',
'page arguments' => array(
1,
),
'access callback' => 'node_access',
'access arguments' => array(
'view',
1,
),
'type' => MENU_CALLBACK,
);
return $items;
}
function hosting_site_theme($existing, $type, $theme, $path) {
$items = array();
$items['hosting_site_profile'] = array(
'arguments' => array(
'profile' => NULL,
'html' => FALSE,
),
);
$items['hosting_site_goto_link'] = array(
'arguments' => array(
'title' => NULL,
'url' => NULL,
),
);
return $items;
}
function _hosting_site_form_check() {
$platform = NULL;
if (isset($_GET['platform'])) {
$platform = $_GET['platform'];
}
drupal_json_output(hosting_site_available_options($_POST, $platform));
exit;
}
function hosting_site_autocomplete_sites($string) {
$query = db_select('node', 'n');
$query
->join('hosting_site', 's', 's.nid = n.nid');
$results = $query
->fields('n', array(
'nid',
'title',
))
->condition('n.type', 'site')
->condition('n.title', '%' . db_like($string) . '%', 'LIKE')
->condition('s.status', HOSTING_SITE_DELETED, '!=')
->execute();
$matches = array();
foreach ($results as $row) {
$matches[$row->title] = check_plain($row->title);
}
drupal_json_output($matches);
}
function hosting_site_wildcard_load($arg) {
if (!is_numeric($arg)) {
return FALSE;
}
if ($node = node_load($arg)) {
if ($node->type == 'site') {
return $node;
}
}
return FALSE;
}
function _hosting_site_goto_link($node) {
$cache = cache_get("hosting:site:" . $node->nid . ":login_link");
if (user_access('create login-reset task') && $cache && REQUEST_TIME < $cache->data['expire']) {
$title = t("Log in to !url", array(
'!url' => hosting_site_canonical_url($node),
));
}
else {
$title = t("Go to !url", array(
'!url' => hosting_site_canonical_url($node),
));
}
$url = "node/" . $node->nid . "/goto_site";
return theme('hosting_site_goto_link', array(
'title' => $title,
'url' => $url,
));
}
function theme_hosting_site_goto_link($variables) {
$options['attributes']['class'] = 'hosting-goto-site-link';
$options['attributes']['target'] = '_blank';
return l($variables['title'], $variables['url'], $options);
}
function hosting_site_goto($node) {
$cid = "hosting:site:" . $node->nid . ":login_link";
$cache = cache_get($cid);
if (user_access('create login-reset task') && is_object($cache) && REQUEST_TIME < $cache->data['expire']) {
$theurl = $cache->data['link'];
cache_clear_all($cid, 'cache');
}
else {
$theurl = _hosting_site_url($node);
}
drupal_goto($theurl);
exit;
}
function hosting_site_get_port($node) {
$platform = node_load($node->platform);
$server = node_load($platform->web_server);
return $server->services['http']->port;
}
function _hosting_site_url($node) {
$schema = 'http';
$port = NULL;
$url = hosting_site_canonical_url($node);
$platform = node_load($node->platform);
$server = node_load($platform->web_server);
if ($server->services['http']
->has_port()) {
$port = $server->services['http']->port;
if ($port == 80) {
$port = NULL;
}
}
$hosting_ssl_required = isset($node->ssl_enabled) && $node->ssl_enabled == 2;
$hosting_https_required = isset($node->https_enabled) && $node->https_enabled == 2;
if ($hosting_ssl_required || $hosting_https_required) {
$schema = 'https';
if ($server->services['http']
->has_port()) {
$port = $server->services['http']->ssl_port;
if ($port == 443) {
$port = NULL;
}
}
}
if (is_numeric($port)) {
return "{$schema}://{$url}:{$port}";
}
return "{$schema}://{$url}";
}
function hosting_site_canonical_url($node) {
$url = isset($node->redirection) && $node->redirection ? $node->redirection : $node->title;
return hosting_site_clean_domain($url);
}
function hosting_site_hosting_tasks() {
$tasks = array();
$tasks['site']['backup'] = array(
'title' => t('Backup'),
'description' => t('Generate a backup of this site that can be restored to at any time'),
'dialog' => TRUE,
);
$tasks['site']['restore'] = array(
'title' => t('Restore'),
'description' => t('Restore this site to a previous backup. A new backup will be created before this is attempted.'),
'dialog' => TRUE,
);
$tasks['site']['verify'] = array(
'title' => t('Verify Site'),
'description' => t('Confirm that the site has been correctly installed and regenerate all configuration files to match the hosting front end.'),
'provision_save' => TRUE,
);
$tasks['site']['disable'] = array(
'title' => t('Disable'),
'description' => t('Disabling this site will stop it from being accessible.
It can be enabled again later.'),
'dialog' => TRUE,
);
$tasks['site']['enable'] = array(
'title' => t('Enable'),
'description' => t('Enabling this site will allow it to be accesible again.
It may be disabled again if needed.'),
);
$tasks['site']['delete'] = array(
'title' => t('Delete Site'),
'description' => t('Deleting this site will completely remove it from the hosting system,
but will keep the last backup available. This process can not be undone.
Are you really sure you want to delete this site?'),
'dialog' => TRUE,
);
$tasks['site']['login-reset'] = array(
'title' => t('Reset password'),
'description' => t('Generate a one-time login reset url for this site.'),
);
$tasks['site']['backup-delete'] = array(
'title' => t('Delete backups'),
'description' => t('Delete one or more backup files of a site.'),
'dialog' => TRUE,
);
$tasks['site']['install'] = array(
'title' => t('Install'),
'description' => t('Install a site'),
'provision_save' => TRUE,
'dialog' => TRUE,
);
$tasks['site']['import'] = array(
'title' => t('Import'),
'description' => t('Import an existing site into Aegir'),
'hidden' => TRUE,
);
$tasks['site']['deploy'] = array(
'title' => t('Deploy'),
'description' => t('Deploy new code and run pre- and post- deployment scripts.'),
'dialog' => TRUE,
'icon' => 'truck',
'provision_save' => TRUE,
);
return $tasks;
}
function hosting_site_permission() {
return array(
'create site' => array(
'title' => t('create site'),
),
'view site' => array(
'title' => t('view site'),
),
'edit site' => array(
'title' => t('edit site'),
),
'delete site' => array(
'title' => t('delete site'),
),
'administer sites' => array(
'title' => t('administer sites'),
),
);
}
function hosting_site_node_access($node, $op, $account) {
if (hosting_feature('client') && $op != 'create') {
return NODE_ACCESS_IGNORE;
}
$type = is_string($node) ? $node : $node->type;
if ($type != 'site') {
return NODE_ACCESS_IGNORE;
}
if ($op == 'create' && user_access('create site', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'update' && user_access('edit site', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'delete' && user_access('delete site', $account)) {
return NODE_ACCESS_ALLOW;
}
if ($op == 'view' && user_access('view site', $account)) {
return NODE_ACCESS_ALLOW;
}
}
function hosting_site_backup_action($node) {
hosting_add_task($node->nid, 'backup');
}
function hosting_site_verify_action($node) {
hosting_add_task($node->nid, 'verify');
}
function hosting_site_disable_action($node) {
hosting_add_task($node->nid, 'disable');
}
function hosting_site_enable_action($node) {
hosting_add_task($node->nid, 'enable');
}
function hosting_site_delete_action($node) {
hosting_add_task($node->nid, 'delete');
}
function hosting_site_op_login_reset($node) {
hosting_add_task($node->nid, 'login-reset');
}
function hosting_site_add_by_platform_access($node) {
return $node->type == 'platform' && $node->platform_status == HOSTING_PLATFORM_ENABLED && node_access('create', 'site');
}
function hosting_site_add_by_platform($node) {
drupal_goto('node/add/site', array(
'query' => array(
'platform' => $node->nid,
),
));
}
function hosting_site_count($platform = NULL, $statuses = NULL) {
if (is_null($statuses)) {
$statuses = array(
HOSTING_SITE_ENABLED,
);
}
$query = db_select('hosting_site')
->addTag('hosting_site_count')
->fields('hosting_site', array(
'nid',
));
if (count($statuses)) {
$query
->condition('status', $statuses);
}
if (!is_null($platform)) {
$query
->condition('platform', $platform);
}
return $query
->countQuery()
->execute()
->fetchField();
}
function hosting_get_sites_by_status($platform, $status) {
$nodes = array();
$result = db_query("SELECT nid FROM {hosting_site} WHERE platform = :platform AND status = :status", array(
':platform' => $platform,
':status' => $status,
));
while ($nid = $result
->fetch()) {
$nodes[$nid->nid] = node_load($nid->nid);
}
return $nodes;
}
function hosting_get_site_by_url($url, $loaded_object = TRUE) {
if (hosting_feature('alias')) {
$nid = db_query("SELECT n.nid\n FROM {node} n\n JOIN {hosting_site} h\n ON n.nid = h.nid\n LEFT JOIN {hosting_site_alias} ha\n ON h.vid = ha.vid\n WHERE (n.title = :title OR ha.alias = :alias)\n AND n.type = :type\n AND NOT (h.status = :status)", array(
':title' => $url,
':alias' => $url,
':type' => 'site',
':status' => HOSTING_SITE_DELETED,
))
->fetchField();
}
else {
$query = new EntityFieldQuery();
$entities = $query
->entityCondition('entity_type', 'node')
->propertyCondition('type', 'site')
->propertyCondition('title', $url)
->addTag('site_not_deleted')
->range(0, 1)
->execute();
if (!empty($entities['node'])) {
$nids = array_keys($entities['node']);
$nid = array_shift($nids);
}
else {
$nid = FALSE;
}
}
if ($nid) {
return $loaded_object ? node_load($nid) : $nid;
}
return FALSE;
}
function hosting_site_query_site_not_deleted_alter(QueryAlterableInterface $query) {
$query
->join('hosting_site', 'site', 'site.nid = node.nid');
$query
->condition('site.status', HOSTING_SITE_DELETED, '!=');
}
function _hosting_site_status($node) {
$status = is_numeric($node) ? $node : $node->site_status;
$labels = hosting_site_status_codes('label');
return $labels[$status];
}
function hosting_site_status_codes_labels() {
return hosting_site_status_codes('label');
}
function hosting_site_status_codes($type = NULL) {
static $codes = array(
HOSTING_SITE_QUEUED => array(
'label' => 'Queued',
'class' => 'hosting-queue',
),
HOSTING_SITE_ENABLED => array(
'label' => 'Enabled',
'class' => 'hosting-success',
),
HOSTING_SITE_DELETED => array(
'label' => 'Deleted',
'class' => 'hosting-error',
),
HOSTING_SITE_DISABLED => array(
'label' => 'Disabled',
'class' => 'hosting-disable',
),
);
if (!is_null($type)) {
$return = array();
foreach ($codes as $code => $types) {
$return[$code] = $types[$type];
}
return $return;
}
else {
return $codes;
}
}
function hosting_site_allow_domain($url, $params = array()) {
$query = "SELECT COUNT(n.nid) FROM {node} n\n JOIN {hosting_site} h ON n.nid = h.nid\n WHERE type = 'site' AND n.title = :title AND h.status <> :status";
$args[':title'] = $url;
$args[':status'] = HOSTING_SITE_DELETED;
if (isset($params['nid'])) {
$query .= " AND n.nid <> :nid";
$args[':nid'] = $params['nid'];
}
$result = !db_query($query, $args)
->fetchField();
return $result;
}
function hosting_site_task_status($nid) {
return hosting_task_status_output('nid', $nid, 'install');
}
function _hosting_site_list_class($node, $verified = NULL) {
$status = is_numeric($node) ? $node : $node->site_status;
$classes = hosting_site_status_codes('class');
if ($status == HOSTING_SITE_ENABLED && $verified <= 1) {
return 'hosting-warning';
}
return $classes[$status];
}
function hosting_site_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'hosting_site') . '/includes/views',
);
}
function theme_hosting_site_profile($variables) {
if ($variables['html']) {
return "{$variables['profile']->title} <em>({$variables['profile']->short_name})</em>";
}
return "{$variables['profile']->title} ({$variables['profile']->short_name})";
}
function hosting_site_preprocess(&$variables) {
if (isset($variables['node'])) {
$variables['title'] = hosting_site_canonical_url($variables['node']);
}
}
function hosting_site_client_list_block_visibility() {
global $user;
$node = menu_get_object();
$menu_item = menu_get_item();
if (!empty($node) && $menu_item['number_parts'] == 2) {
return $node->type == 'client' && !user_access('administer clients', $user);
}
return FALSE;
}
function hosting_site_client_admin_block_visibility() {
global $user;
$node = menu_get_object();
$menu_item = menu_get_item();
if (!empty($node) && $menu_item['number_parts'] == 2) {
return $node->type == 'client' && user_access('administer clients', $user);
}
return FALSE;
}
function hosting_site_profile_block_visibility() {
$node = menu_get_object();
$menu_item = menu_get_item();
if (!empty($node) && $menu_item['number_parts'] == 2) {
return $node->type == 'package' && $node->package_type == 'profile';
}
return FALSE;
}
function hosting_site_block_view_alter(&$data, $block) {
if ($block->delta == 'hosting_site_list-block_sites') {
if ($node = menu_get_object()) {
if ($node->type == 'server' && !array_key_exists('db', $node->services) || $node->type == 'package' && $node->package_type != 'profile') {
unset($data['subject']);
unset($data['content']);
}
}
}
}
function hosting_site_action_info_alter(&$actions) {
if (variable_get('hosting_require_disable_before_delete', TRUE)) {
unset($actions['hosting_site_delete_action']);
}
}
function hosting_site_hosting_task_guarded_nodes() {
return array(
hosting_get_hostmaster_site_nid(),
);
}
function hosting_task_deploy_form($node) {
$form = array();
if ($node->type == 'site') {
try {
$wrapper = new GitWrapper();
$git = $wrapper
->workingCopy($node->git_root);
$diff = $git
->diff()
->getOutput();
$status = $git
->getStatus();
} catch (GitException $e) {
drupal_set_message($e
->getMessage(), 'error');
}
$two_col_classes = array(
'col-sm-6',
'col-md-6',
'col-lg-6',
);
$form['info'] = array(
'#type' => 'container',
'#attributes' => array(
'class' => array(
'container',
),
),
'current' => array(
'#type' => 'container',
'#attributes' => array(
'class' => $two_col_classes,
),
),
'target' => array(
'#type' => 'container',
'#attributes' => array(
'class' => $two_col_classes,
),
),
);
$form['info']['current']['current_git_reference'] = array(
'#title' => t('Current Git Reference'),
'#type' => 'item',
'#markup' => $node->git_reference,
'#description' => t('The current branch, tag, or SHA of the site code at &path.', array(
'&path' => $node->git_root,
)),
'#field_prefix' => '<div class="label label-default git-ref-label">',
'#field_suffix' => '</div>',
);
$form['info']['target']['target_git_reference'] = array(
'#title' => t('Target Git Reference'),
'#type' => 'textfield',
'#default_value' => $_GET['git_reference'] ?: $node->git_reference,
'#description' => t('Enter the desired git branch, tag, or SHA. If a branch is entered, the git repository will pulled and reset to match the remote repository. If a tag or SHA is entered, it will be checked out, resulting in a "DETACHED HEAD" state.'),
'#parents' => array(
'parameters',
'target_git_reference',
),
'#attributes' => array(
'class' => array(
'col-md-6',
),
),
);
}
$form['git_info'] = array(
'#title' => t('View git status in &path', array(
'&path' => $node->git_root,
)),
'#type' => 'fieldset',
'#collapsed' => true,
'#collapsible' => true,
'status' => array(
'#prefix' => '<h4>' . t('Git Status') . '</h4><pre>',
'#markup' => $status,
'#suffix' => '</pre>',
'#access' => !empty($status),
),
'diff' => array(
'#prefix' => '<h4>' . t('Git diff') . '</h4><pre>',
'#markup' => $diff,
'#suffix' => '</pre>',
'#access' => !empty($diff),
),
'clean' => array(
'#prefix' => '<h4>',
'#markup' => t('Git working copy is clean. No changes.'),
'#suffix' => '</h4>',
'#access' => empty($diff) && empty($status),
),
);
return $form;
}
function _hosting_task_deploy_command_form_title($command_name, $commands) {
$command = isset($commands[$command_name]) ? $commands[$command_name] : '';
$command_title_text = '<span class="command-label"><code>!command_name</code></span> !command';
$missing_prefix = '<span class="alert alert-warning alert-inline"><i class="fa fa-warning"></i> ';
$missing_text = 'MISSING. Add desired command to <code>composer.json:extra.devshop.commands.!name</code>';
$missing_suffix = '</span>';
return t($command_title_text, array(
'!command_name' => $command_name,
'!command' => $command ? '<kbd>' . $command . '</kbd>' : $missing_prefix . t($missing_text, array(
'!name' => $command_name,
)) . $missing_suffix,
));
}
function hosting_task_delete_form($node) {
$form = array();
if ($node->type == 'site') {
$form['confirm'] = array(
'#title' => t('Confirm: All data in this site will be destroyed. Check this box to confirm your intentions to do this.'),
'#type' => 'checkbox',
'#required' => TRUE,
'#description' => t('WARNING: Taking this action will destroy all data in the site !link.', array(
'!link' => l($node->title, $node->title, array(
'options' => array(
'attributes' => array(
'target' => '_blank',
),
),
)),
)),
);
}
return $form;
}
function hosting_site_get_domain($domain) {
drupal_alter('hosting_site_domain', $domain);
return $domain;
}
function hosting_site_hosting_site_domain_alter(&$domain) {
$domain = hosting_site_clean_domain($domain);
}
function hosting_site_clean_domain($domain) {
return strtolower(trim($domain));
}