t('Domain access'),
'path' => 'admin/build/domain',
'access' => $admin,
'callback' => 'domain_admin',
'callback arguments' => array('configure'),
'description' => t('Settings for the Domain Access module.')
);
$items[] = array(
'title' => t('Settings'),
'path' => 'admin/build/domain/settings',
'access' => $admin,
'type' => MENU_DEFAULT_LOCAL_TASK,
'callback' => 'domain_admin',
'callback arguments' => array('configure'),
'weight' => -10
);
$items[] = array(
'title' => t('Domain list'),
'path' => 'admin/build/domain/view',
'access' => $admin,
'type' => MENU_LOCAL_TASK,
'callback' => 'domain_admin',
'callback arguments' => array('view'),
'weight' => -8
);
$items[] = array(
'title' => t('Create domain record'),
'path' => 'admin/build/domain/create',
'access' => $admin,
'type' => MENU_LOCAL_TASK,
'callback' => 'domain_admin',
'callback arguments' => array('create'),
'weight' => -4
);
$items[] = array(
'title' => t('Node settings'),
'path' => 'admin/build/domain/advanced',
'access' => $admin,
'type' => MENU_LOCAL_TASK,
'callback' => 'domain_admin',
'callback arguments' => array('advanced'),
'weight' => -2
);
}
else {
$items[] = array(
'title' => t('Edit domain record'),
'path' => 'admin/build/domain/edit',
'access' => $admin,
'type' => MENU_CALLBACK,
'callback' => 'domain_admin',
'callback arguments' => array('edit', arg(4))
);
$items[] = array(
'title' => t('Delete domain record'),
'path' => 'admin/build/domain/delete',
'access' => $admin,
'type' => MENU_CALLBACK,
'callback' => 'domain_admin',
'callback arguments' => array('delete', arg(4))
);
}
return $items;
}
/**
* Implements hook_perm()
*
* @ingroup drupal
*/
function domain_perm() {
$rule = variable_get('domain_editors', DOMAIN_EDITOR_RULE);
if ($rule) {
return array('administer domains', 'set domain access', 'edit domain nodes');
}
else {
return array('administer domains', 'set domain access');
}
}
/**
* Implements hook_block()
*
* A nifty little domain-switcher block, useful during debugging.
*
* @ingroup drupal
*/
function domain_block($op = 'list', $delta = 0, $edit = array()) {
global $_domain, $base_url;
$blocks = array();
switch ($op) {
case 'list':
$blocks[0] = array(
'info' => t('Domain switcher'),
);
return $blocks;
break;
case 'view':
$block['subject'] = t('Domain switcher');
$items = array();
$domains = domain_domains();
foreach ($domains as $domain) {
$items[] = l($domain['sitename'], domain_get_uri($domain));
}
$block['content'] = theme('item_list', $items);
return $block;
break;
}
}
/**
* Implements hook_user()
*
* Attached domain_id records to all registering users. These
* are used to determine which 'domain_editor' group that users
* with the 'edit domain nodes' permission are in.
*
* @ingroup drupal
*/
function domain_user($op, &$edit, &$account, $category = NULL) {
switch ($op) {
case 'form':
case 'register':
global $_domain;
$result = db_query("SELECT domain_id, subdomain, sitename, scheme FROM {domain}");
$options = array();
// By default, the requesting domain is assigned.
if (empty($account->domain_user)) {
($_domain['domain_id'] == 0) ? $default = array(-1) : $default = array($_domain['domain_id']);
}
else {
$default = $account->domain_user;
}
$options[-1] = variable_get('domain_sitename', variable_get('sitename', 'Drupal'));
while ($data = db_fetch_array($result)) {
$options[$data['domain_id']] = $data['sitename'];
}
if (user_access('set domain access')) {
$form['domain_user'] = array(
'#type' => 'fieldset',
'#title' => t('Domain access'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#weight' => 1
);
$form['domain_user']['domain_user'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#title' => t('Domain access setttings'),
'#description' => t('Select the affiliates that this user belongs to. Used to grant editing permissions for users with the "edit domain nodes" permission.'),
'#default_value' => $default
);
}
else {
$form['domain_user'] = array(
'#type' => 'value',
'#value' => $default
);
}
return $form;
break;
case 'validate':
return array('domain_user' => $edit['domain_user']);
break;
case 'view':
if (user_access('set domain access') && !empty($account->domain_user)) {
$output = '
';
foreach ($account->domain_user as $id) {
if (abs($id) > 0) {
if ($id > 0) {
$domain = domain_lookup($id);
$output .= '- '. $domain['sitename'] .'
';
}
else {
$output .= '- '. variable_get('domain_sitename', variable_get('sitename', 'Drupal')) . '
';
}
}
}
$output .= '
';
$items['domain'] = array('title' => t('Domain settings'),
'value' => $output,
);
return array(t('Domain status') => $items);
}
break;
}
}
/**
* Implements hook_cron()
*
* This function invokes hook_domaincron() and allows
* Domain Access modules to run functions for all active affiliates.
*
* @ingroup drupal
*/
function domain_cron() {
global $_domain;
// Check to see if this function is needed at all.
$modules = module_implements('domaincron');
if (!empty($modules)) {
// Store the current $_domain global.
$_temp = $_domain;
// Get the domain list.
$domains = domain_domains();
// Run the hook for each active domain.
foreach ($domains as $domain) {
// Set the global to the current $domain.
$_domain = $domain;
foreach ($modules as $module) {
module_invoke($module, 'domaincron', $domain);
}
}
// Set the $_domain global back.
$_domain = $_temp;
}
}
/**
* Router function to call various administration tasks
*
* @param $action
* The function to be performed.
* @param $id
* The domain_id of the record to be acted upon.
*
* @ingroup domain
*/
function domain_admin($action, $id = NULL) {
include_once('domain_admin.inc');
$func = 'domain_'. $action;
return $func($id);
}
/**
* Runs a lookup against the {domain} table. One of the two values must be present
*
* This function also calls hook_domainload(), which lets module developers overwrite
* or add to the $domain array.
*
* @param $domain_id
* The domain_id taken from {domain}. Optional.
* @param $subdomain
* The string representation of a {domain} entry. Optional.
* @return
* An array containing the requested row from the {domain} table, plus the
* elements added by hook_domainload(). Returns -1 on failure.
*
* @ingroup domain
*/
function domain_lookup($domain_id = NULL, $subdomain = NULL) {
if ($domain_id === 0) {
$domain = domain_default();
}
else if ($domain_id) {
$domain = db_fetch_array(db_query("SELECT domain_id, subdomain, sitename, scheme FROM {domain} WHERE domain_id = %d", $domain_id));
}
else if ($subdomain) {
$domain = db_fetch_array(db_query("SELECT domain_id, subdomain, sitename, scheme FROM {domain} WHERE subdomain = '%s'", $subdomain));
}
if (!is_null($domain['domain_id'])) {
// Let submodules overwrite the defaults, if they wish.
$extra = module_invoke_all('domainload', $domain);
$domain = array_merge($domain, $extra);
return $domain;
}
else {
return -1;
}
}
/**
* Assigns the default settings to domain 0, the root domain.
*
* This value is used throughout the modules, so needed abstraction.
*
* @ingroup domain
*/
function domain_default() {
static $default;
if (empty($default)) {
$default['domain_id'] = 0;
$default['sitename'] = variable_get('domain_sitename', variable_get('sitename', 'Drupal'));
$default['subdomain'] = variable_get('domain_root', '');
$default['scheme'] = variable_get('domain_scheme', 'http');
// Let submodules overwrite the defaults, if they wish.
$extra = module_invoke_all('domainload', $default);
$default = array_merge($default, $extra);
}
return $default;
}
/**
* Return all active domains (including the default) as an array.
*
* @ingroup domain
*/
function domain_domains() {
static $domains;
if (empty($domains)) {
$domains = array();
$domains[] = domain_default();
// Query the db for active domain records.
$result = db_query("SELECT domain_id FROM {domain}");
while ($data = db_fetch_array($result)) {
$domain = domain_lookup($data['domain_id']);
$domains[] = $domain;
}
}
return $domains;
}
/**
* Implements hook_domainload()
*
* Adds the home page 'path' and 'site_grant' boolean.
*
* @ingroup domain
*/
function domain_domainload($domain) {
// Get the path to the home page for this domain.
$domain['path'] = domain_get_path($domain);
// Grant access to all affiliates.
$domain['site_grant'] = DOMAIN_SITE_GRANT;
return $domain;
}
/**
* Determine an absolute path for a domain
*
* @param $domain
* The currently active $domain array, privided by domain_lookup().
*
* @ingroup domain
*/
function domain_get_path($domain) {
global $base_url;
$_url = parse_url($base_url);
// If in a subfolder, the web server needs the trailing slash.
(!empty($_url['path'])) ? $_path = $_url['path'] .'/' : $_path = $_url['path'];
$path = $domain['scheme'] .'://'. $domain['subdomain'] . $_path;
return $path;
}
/**
* Determine a relative path to the current page
*/
function domain_get_uri($domain) {
global $base_url;
$_url = parse_url($base_url);
$path = $domain['scheme'] .'://'. $domain['subdomain'] . request_uri();
return $path;
}
/**
* Determine if we must switch the active domain.
*
* This function will execute a drupal_goto() to pop users to the correct
* domain.
*
* @param $domain
* The currently active $domain array, provided by domain_lookup().
*
* @ingroup domain
*/
function domain_goto($domain) {
global $_domain;
// We must be on the proper domain, see http://drupal.org/node/186153.
if ($domain != -1 && $_domain['domain_id'] != $domain['domain_id']) {
$path = domain_get_uri($domain);
drupal_goto($path);
}
}
/**
* Implements hook_nodeapi().
*
* This function is used to provide debugging information and to prep values from
* the {node_access} table when editing nodes. Since not all users can see the
* domain access editing checkboxes, we pass some node_access values as hidden elements.
*
* @ingroup node
*/
function domain_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
switch ($op) {
case 'prepare':
case 'load':
// Append the domain grants to the node for editing.
$node->domains = array();
$node->editors = array();
$node->domain_site = FALSE;
$result = db_query("SELECT gid, realm, grant_view, grant_update, grant_delete FROM {node_access} WHERE nid = %d AND (realm = '%s' OR realm = '%s' OR realm = '%s')", $node->nid, 'domain_id', 'domain_site', 'domain_editor');
while ($data = db_fetch_object($result)) {
if ($data->realm == 'domain_id') {
// Transform the 0 to -1, since {node_access} is unsigned.
($data->gid == 0) ? $gid = -1 : $gid = $data->gid;
$node->domains[] = $gid;
if ($gid > 0) {
$domain = domain_lookup($gid);
$node->subdomains[] = $domain['sitename'];
}
else {
$node->subdomains[] = variable_get('domain_sitename', variable_get('sitename', 'Drupal'));
}
}
else if ($data->realm == 'domain_site') {
$node->domain_site = TRUE;
$node->subdomains[] = t('All affiliates');
}
else if ($data->realm == 'domain_editor') {
$node->domain_editor = TRUE;
if ($gid > 0) {
$domain = domain_lookup($gid);
$node->editors[] = $domain['sitename'];
}
else {
$node->editors[] = variable_get('domain_sitename', variable_get('sitename', 'Drupal'));
}
}
}
break;
case 'view':
$output = '';
$debug = variable_get('domain_debug', 0);
if ($debug && user_access('set domain access')) {
if (!empty($node->subdomains)) {
$output .= 'Subdomains
';
foreach($node->subdomains as $name) {
$output .= '- '. $name .'
';
}
$output .= '
';
$node->content['subdomains'] = array('#value' => $output, '#weight' => 20);
}
if (!empty($node->editors)) {
$output = 'Editors
';
foreach($node->editors as $name) {
$output .= '- '. $name .'
';
}
$output .= '
';
$node->content['editors'] = array('#value' => $output, '#weight' => 21);
}
if (empty($output)) {
$node->content['domain'] = array('#value' => t('This node is not assigned to a domain.'), '#weight' => 22);
}
}
break;
}
}
/**
* Implements hook_node_grants()
*
* Informs the node access system what permissions the user has. By design
* all users are in the realm defined by the currently active domain_id.
*
* @ingroup node
*/
function domain_node_grants($account, $op) {
global $_domain;
// By design, all users can see content sent to all affiliates,
// but the $_domain['site_grant'] can be set to FALSE.
// In the case of node batch editing and node_access_rebuild(), we
// deliberately set this value to FALSE.
if ($_domain['site_grant']) {
$grants['domain_site'][] = 0;
}
// Grant based on active subdomain.
$grants['domain_id'][] = $_domain['domain_id'];
// Special permissions for editors
$editors = variable_get('domain_editors', DOMAIN_EDITOR_RULE);
if ($editors && user_access('edit domain nodes', $account)) {
if (!empty($account->domain_user)) {
foreach ($account->domain_user as $id) {
if (abs($id) > 0) {
if ($id > 0) {
$grants['domain_editor'][] = $id;
}
else {
$grants['domain_editor'][] = 0;
}
}
}
}
}
// Let Domain Access module extensions act to override the defaults.
$grants = module_invoke_all('domaingrants', $grants, $account, $op);
return $grants;
}
/**
* Implements hook_domaingrants()
*
* Allows us to set the $grants by invoking module_invoke_all().
*
* @ingroup domain
*/
function domain_domaingrants(&$grants, $account, $op) {
// Return default grants
return $grants;
}
/**
* Implements hook_node_access_records()
*
* Set permissions for a node to be written to the database. By design
* if no options are selected, the node is assigned to the main site.
*
* @ingroup node
*/
function domain_node_access_records($node) {
if (domain_disabling()) {
return;
}
// Promote content to all affliates on module activation
if (domain_enabling()) {
// How is core content handled for this site?
$behavior = variable_get('domain_behavior', DOMAIN_INSTALL_RULE);
if ($behavior == 1) {
$node->domain_site = TRUE;
}
}
$grants = array();
// If the form is hidden, we are passed the 'domains_raw' variable.
if (is_array($node->domains_raw)) {
$node->domains = array();
foreach ($node->domains_raw as $value) {
$node->domains[$value] = $value;
}
}
// If set, grant access to the core site, otherwise
// The grant must be explicitly given to a domain.
if ($node->domain_site) {
$grants[] = array(
'realm' => 'domain_site',
'gid' => 0,
'grant_view' => TRUE,
'grant_update' => FALSE,
'grant_delete' => FALSE,
'priority' => 0, // If this value is > 0, then other grants will not be recorded
);
}
// Special permissions for editors, if activated.
$editors = variable_get('domain_editors', DOMAIN_EDITOR_RULE);
if (!empty($node->domains)) {
foreach($node->domains as $key => $value) {
// We can't use a 0 value in an $options list, so convert -1 to 0.
if (abs($value) > 0) {
($key == -1) ? $key = 0 : $key = $key;
$grants[] = array(
'realm' => 'domain_id',
'gid' => $key,
'grant_view' => TRUE,
'grant_update' => FALSE,
'grant_delete' => FALSE,
'priority' => 0,
);
if ($editors) {
$grants[] = array(
'realm' => 'domain_editor',
'gid' => $key,
'grant_view' => FALSE,
'grant_update' => TRUE,
'grant_delete' => TRUE,
'priority' => 0,
);
}
}
}
}
// At least one option must be present, and it is the default site
// this prevents null values in the form.
// There is probably a more elegant way to do this, earlier in the routine.
if (empty($grants)) {
$grants[] = array(
'realm' => 'domain_id',
'gid' => 0,
'grant_view' => TRUE,
'grant_update' => FALSE,
'grant_delete' => FALSE,
'priority' => 0,
);
if ($editors) {
$grants[] = array(
'realm' => 'domain_editor',
'gid' => 0,
'grant_view' => FALSE,
'grant_update' => TRUE,
'grant_delete' => TRUE,
'priority' => 0,
);
}
}
// Let Domain Access module extensions act to override the defaults.
$grants = module_invoke_all('domainrecords', $grants, $node);
return $grants;
}
/**
* Implements hook_domainrecords()
*
* Allows us to set the $grants by invoking module_invoke_all().
*
* @ingroup domain
*/
function domain_domainrecords(&$grants, $node) {
// Return default grants
return $grants;
}
/**
* Implements hook_enable()
*
* @ingroup node
*/
function domain_enable() {
domain_enabling(TRUE);
node_access_rebuild();
}
/**
* Implements hook_disable()
*
* @ingroup node
*/
function domain_disable() {
domain_disabling(TRUE);
// This lets us control how the module updates the {node_access} table.
variable_del('domain_behavior');
variable_del('domain_editors');
node_access_rebuild();
}
/**
* Simple function to make sure we don't respond with grants when disabling ourselves.
*
* @ingroup node
*/
function domain_disabling($set = NULL) {
static $disabling = false;
if ($set !== NULL) {
$disabling = $set;
}
return $disabling;
}
/**
* Simple function to make sure we respond with the correct grants when enabling ourselves.
*
* @ingroup node
*/
function domain_enabling($set = NULL) {
static $enabling = false;
if ($set !== NULL) {
$enabling = $set;
}
return $enabling;
}
/**
* Implements hook_form_alter()
*
* This function is crucial, as it appends our node access elements to the node edit form.
* For users without the "set domain access" permission, this happens silently.
*
* @ingroup node
*/
function domain_form_alter($form_id, &$form) {
// Apply to all node editing forms, but make sure we are not on the CCK field configuration form.
if ($form['#id'] == 'node-form' && !$form['#node']->cck_dummy_node_form) {
global $_domain;
$result = db_query("SELECT domain_id, subdomain, sitename, scheme FROM {domain}");
$options = array();
// By default, the requesting domain is assigned.
$default = array($_domain['domain_id']);
// How is core content handled for this site?
$behavior = variable_get('domain_behavior', DOMAIN_INSTALL_RULE);
if ($behavior == 1 || $_domain['domain_id'] == 0) {
$default[] = -1;
}
$options[-1] = variable_get('domain_sitename', variable_get('sitename', 'Drupal'));
while ($data = db_fetch_array($result)) {
$options[$data['domain_id']] = $data['sitename'];
}
// If the user is a site admin, show the form, otherwise pass it silently.
if (user_access('set domain access')) {
$form['domain'] = array(
'#type' => 'fieldset',
'#title' => t('Domain access options'),
'#collapsible' => TRUE,
'#collapsed' => FALSE
);
$form['domain']['domain_site'] = array(
'#type' => 'checkbox',
'#prefix' => t('Publishing options:'),
'#suffix' => '
',
'#title' => t('Send to all affiliates'),
'#required' => FALSE,
'#description' => t('Select if this content can be shown to all affiliates. This setting will override the options below.'),
'#default_value' => ($form['#node']->nid) ? $form['#node']->domain_site : variable_get('domain_node_'. $form['#node']->type, $behavior),
);
$form['domain']['domains'] = array(
'#type' => 'checkboxes',
'#title' => t('Publish to'),
'#options' => $options,
'#required' => TRUE,
'#description' => t('Select which affiliates can access this content.'),
'#default_value' => ($form['#node']->nid) ? $form['#node']->domains : $default,
);
}
else {
$form['domain_site'] = array(
'#type' => 'value',
'#value' => ($form['#node']->nid) ? $form['#node']->domain_site : variable_get('domain_node_'. $form['#node']->type, $behavior),
);
// Name this element for special handling.
$form['domains_raw'] = array(
'#type' => 'value',
'#value' => ($form['#node']->nid) ? $form['#node']->domains : $default
);
}
// THIS SECTION BREAKS CCK! See http://drupal.org/node/186624
// Some editors cannot administer nodes, so we have to add these form elements.
if (variable_get('domain_editors', DOMAIN_EDITOR_RULE) == 1 && user_access('edit domain nodes')) {
$access = variable_get('domain_form_elements', array('options', 'delete', 'comment_settings', 'path'));
foreach ($access as $item) {
$form[$item]['#access'] = TRUE;
}
}
}
}