node_authlink.module in Node authorize link 8
Same filename and directory in other branches
Node Authlink hooks and alters.
File
node_authlink.moduleView source
<?php
/**
* @file
* Node Authlink hooks and alters.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
use Drupal\node\NodeInterface;
use Drupal\node_authlink\Access\NodeAuthlinkNodeAccessControlHandler;
use Drupal\node_authlink\Plugin\NodeAuthlinkGroupContentAccessControlHandler;
/**
* Alter of node_type_form.
*/
function node_authlink_form_node_type_form_alter(&$form, FormStateInterface &$form_state) {
if (!\Drupal::currentUser()
->hasPermission('configure node_authlink module')) {
return;
}
/** @var \Drupal\node\Entity\NodeType $node_type */
$node_type = $form_state
->getFormObject();
$type = $node_type
->getEntity()
->id();
$config = \Drupal::config('node_authlink.settings');
$config_enable = $config
->get('enable');
$config_grants = $config
->get('grants');
$config_expire = $config
->get('expire');
$form['node_authlink'] = [
'#type' => 'details',
'#title' => t('Node authorize link'),
'#group' => 'additional_settings',
];
$form['node_authlink']['node_authlink_enable'] = [
'#type' => 'checkbox',
'#title' => t('Enable'),
'#default_value' => isset($config_enable[$type]) ? $config_enable[$type] : 0,
'#description' => t('Disable of this feature will cost erase of authorization keys of all nodes in this node type.'),
];
$form['node_authlink']['node_authlink_grants'] = [
'#type' => 'checkboxes',
'#title' => t('Grants to give'),
'#default_value' => isset($config_grants[$type]) ? $config_grants[$type] : [],
'#options' => [
'view' => t('View'),
'update' => t('Update'),
'delete' => t('Delete'),
],
'#description' => t('What operations will be temporarily given to authorised user for the node. This not affect users who is authorised yet.'),
];
// Time periods: none, 1 day, 1 week, 4 weeks, 3 months, 6 months, 1 year
$time_periods = [
0,
86400,
604800,
2419200,
7776000,
15552000,
31536000,
];
$period = node_authlink_build_options($time_periods);
$period[0] = '<' . t('disabled') . '>';
$form['node_authlink']['node_authlink_expire'] = [
'#type' => 'select',
'#title' => t('Regenerate authkeys after'),
'#default_value' => isset($config_expire[$type]) ? $config_expire[$type] : '',
'#options' => $period,
'#description' => t('Keys older than selected time will be regenerated by cron run.'),
];
$form['node_authlink']['node_authlink_batch'] = [
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#title' => t('Batch operations'),
'#description' => t('Affects all nodes in this node type.'),
];
$form['node_authlink']['node_authlink_batch']['generate'] = [
'#type' => 'submit',
'#value' => t('Generate authkeys'),
'#submit' => [
'node_authlink_batch_generate',
],
];
$form['node_authlink']['node_authlink_batch']['delete'] = [
'#type' => 'submit',
'#value' => t('Delete all authkeys'),
'#submit' => [
'node_authlink_batch_delete',
],
];
$form['actions']['submit']['#submit'][] = 'node_authlink_form_node_type_form_alter_submit';
}
/**
* Helper function to build expire options.
*
* @param array $time_intervals
* @param int $granularity
* @param null $langcode
*
* @return array
*/
function node_authlink_build_options(array $time_intervals, $granularity = 2, $langcode = NULL) {
$callback = function ($value) use ($granularity, $langcode) {
return \Drupal::service('date.formatter')
->formatInterval($value, $granularity, $langcode);
};
return array_combine($time_intervals, array_map($callback, $time_intervals));
}
/**
* Submit for node_type_form.
*/
function node_authlink_form_node_type_form_alter_submit(&$form, FormStateInterface &$form_state) {
// Disabled
$type = $form_state
->getValue('type');
$config_factory = \Drupal::configFactory();
$config = $config_factory
->getEditable('node_authlink.settings');
$enable = $config
->get('enable');
$grants = $config
->get('grants');
$expire = $config
->get('expire');
if (!$form_state
->getValue('node_authlink_enable')) {
unset($enable[$type]);
unset($grants[$type]);
}
else {
$enable[$type] = TRUE;
$grants[$type] = $form_state
->getValue('node_authlink_grants');
}
$expire[$type] = $form_state
->getValue('node_authlink_expire');
$config
->set('enable', $enable);
$config
->set('grants', $grants);
$config
->set('expire', $expire);
$config
->save();
}
/**
* Generate authkeys for all nodes in node type.
*/
function node_authlink_batch_generate(&$form, FormStateInterface &$form_state) {
// Load NIDs that are not in the authkeys table
$query = \Drupal::database()
->select('node', 'n');
$query
->leftJoin('node_authlink_nodes', 'a', 'n.nid = a.nid');
$query
->fields('n', [
'nid',
])
->condition('type', $form_state
->getValue('type'))
->isNull('authkey');
$nids = $query
->execute()
->fetchCol();
// Create keys
foreach ($nids as $nid) {
node_authlink_create($nid);
}
\Drupal::messenger()
->addMessage(t('%num authkeys has been generated.', [
'%num' => count($nids),
]));
}
/**
* Delete authkeys for all nodes in node type.
*
* @param array $form
* Form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Form state.
*/
function node_authlink_batch_delete(array &$form, FormStateInterface &$form_state) {
// NIDs of nodes that are in this node type.
$query = \Drupal::database()
->select('node', 'n');
$query
->leftJoin('node_authlink_nodes', 'a', 'n.nid = a.nid');
$query
->fields('n', [
'nid',
])
->condition('type', $form_state
->getValue('type'))
->isNotNull('authkey');
$nids = $query
->execute()
->fetchCol();
foreach ($nids as $nid) {
node_authlink_delete($nid);
}
\Drupal::messenger()
->addMessage(t('%num authkeys has been deleted.', [
'%num' => count($nids),
]));
}
/**
* Implements hook_node_load().
*
* Appends authke to loaded node object.
*/
function node_authlink_node_load($nodes) {
foreach ($nodes as $nid => $node) {
// TODO: check node type (performance)
if ($authkey = node_authlink_load_authkey($nid)) {
$nodes[$nid]->authkey = $authkey;
}
}
}
/**
* Loads key from NID.
*/
function node_authlink_load_authkey($nid) {
$result = \Drupal::database()
->query('SELECT authkey FROM {node_authlink_nodes} WHERE nid = :nid', [
':nid' => $nid,
]);
return $result
->fetchField();
}
/**
* Get edit URL of specified node.
*
* @param $node Node object or NID.
* @param string $op Operation to do with node. view, update (default) or delete.
* @param null $revision_id
*
* @return bool|\Drupal\Core\GeneratedUrl|string
*/
function node_authlink_get_url($node, $op = 'view', $revision_id = NULL) {
if (is_numeric($node)) {
$node = Node::load($node);
}
if (!isset($node->authkey)) {
return FALSE;
}
switch ($op) {
case 'view':
if (is_numeric($revision_id)) {
$route_name = 'entity.node.revision';
}
else {
$route_name = 'entity.node.canonical';
}
break;
case 'update':
$route_name = 'entity.node.edit_form';
break;
case 'delete':
$route_name = 'entity.node.delete_form';
break;
default:
return FALSE;
}
$arguments = [
'node' => $node
->id(),
];
if (is_numeric($revision_id)) {
$arguments['node_revision'] = $revision_id;
}
$url = Url::fromRoute($route_name, $arguments, [
'absolute' => TRUE,
'query' => [
'authkey' => $node->authkey,
],
]);
return $url
->toString();
}
/**
* Implements hook_node_access().
*/
function node_authlink_node_access(NodeInterface $node, $op, AccountInterface $account) {
// Ignore if just creating node
if ($op == 'create') {
return AccessResult::neutral();
}
// Ignore if node type is not enabled
if (!node_authlink_node_is_enabled($node)) {
return AccessResult::neutral();
}
if (node_authlink_check_authlink($node, $op, $account)) {
return AccessResult::allowed();
}
}
/**
* Checks if a node is enabled for node_authlink
*
* @param \Drupal\node\NodeInterface $node
* The node to check.
*
* @return bool
*/
function node_authlink_node_is_enabled(NodeInterface $node) {
$config = \Drupal::config('node_authlink.settings');
$config_enable = $config
->get('enable');
if (isset($config_enable[$node
->bundle()]) && $config_enable[$node
->bundle()]) {
return TRUE;
}
return FALSE;
}
/**
* Check if a node has access to a node via authlink and grant it the query parameter is correct.
*
* @param \Drupal\node\NodeInterface $node
* @param $op
* @param \Drupal\Core\Session\AccountInterface $account
*
* @return bool
*/
function node_authlink_check_authlink(NodeInterface $node, $op, AccountInterface $account) {
$config = \Drupal::config('node_authlink.settings');
// Check key if:
if (isset($_GET['authkey']) && isset($node->authkey)) {
// authkey in node is setand
if ($node->authkey == $_GET['authkey']) {
// Start session
if ($account
->isAnonymous() && !isset($_SESSION['node_authlink_nodes'])) {
/** @var \Drupal\Core\Session\SessionManager $session_manager */
$session_manager = \Drupal::service('session_manager');
$session_manager
->start();
}
// Save allowed grants to session
$config_grants = $config
->get('grants');
$_SESSION['node_authlink_nodes'][$node
->id()] = $config_grants[$node
->bundle()];
}
}
// Permit if checked
if (isset($_SESSION['node_authlink_nodes'][$node
->id()]) && in_array($op, $_SESSION['node_authlink_nodes'][$node
->id()], TRUE)) {
return TRUE;
}
return FALSE;
}
/**
* Implements hook_ENTITY_TYPE_delete().
*/
function node_authlink_node_delete(Drupal\Core\Entity\EntityInterface $entity) {
$config = \Drupal::config('node_authlink.settings');
$enable = $config
->get('enable');
// Ignore if node type is disabled
if (isset($enable[$entity
->bundle()]) && $enable[$entity
->bundle()]) {
node_authlink_delete($entity
->id());
}
}
/**
* Generate and save auth key for the new node.
*/
function node_authlink_create($node) {
// Allow key generate without load node object
if (is_numeric($node)) {
$nid = $node;
}
else {
$nid = $node
->id();
$config = \Drupal::config('node_authlink.settings');
// Ignore if node type is disabled
if (!$config
->get('enable.' . $node
->bundle())) {
return;
}
}
// Generate key if not yet
$authkey = isset($node->authkey) ? $node->authkey : hash('sha256', random_bytes(64));
// Save to DB
\Drupal::database()
->insert('node_authlink_nodes')
->fields([
'nid' => $nid,
'authkey' => $authkey,
'created' => time(),
])
->execute();
}
/**
* Deletes the node_authlink.
*
* @param $node
*/
function node_authlink_delete($node) {
if (is_numeric($node)) {
$nid = $node;
}
else {
$nid = $node
->id();
}
// Delete keys
$count = \Drupal::database()
->delete('node_authlink_nodes')
->condition('nid', $nid)
->execute();
}
/**
* Implementation of hook_cron().
*/
function node_authlink_cron() {
$node_types = \Drupal\node\Entity\NodeType::loadMultiple();
$config = \Drupal::config('node_authlink.settings');
foreach ($node_types as $type) {
$expire = $config
->get('expire.' . $type
->id());
if (!$expire) {
continue;
}
// NIDs of expired keys
$query = \Drupal::database()
->select('node', 'n');
$query
->leftJoin('node_authlink_nodes', 'a', 'n.nid = a.nid');
$query
->fields('n', [
'nid',
])
->condition('n.type', $type
->id())
->condition('a.created', time() - $expire, '<');
$nids = $query
->execute()
->fetchCol();
// Regenerate keys
foreach ($nids as $nid) {
\Drupal::database()
->delete('node_authlink_nodes')
->condition('nid', $nid)
->execute();
node_authlink_create($nid);
}
}
}
/**
* Implementation of hook_token_info().
*/
function node_authlink_token_info() {
$node['authlink:authkey'] = [
'name' => t("Authorization key"),
'description' => t("Key generated by Node authorize link module."),
];
$node['authlink:view-url'] = [
'name' => t("View URL"),
'description' => t("URL with authorization key."),
];
$node['authlink:edit-url'] = [
'name' => t("Edit URL"),
'description' => t("URL with authorization key."),
];
$node['authlink:delete-url'] = [
'name' => t("Delete URL"),
'description' => t("URL with authorization key."),
];
return [
'tokens' => [
'node' => $node,
],
];
}
/**
* Implements hook_tokens().
*/
function node_authlink_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) {
if ($type != 'node' || empty($data['node'])) {
return;
}
$replacements = [];
if ($type == 'node' && !empty($data['node']->authkey)) {
$node = $data['node'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'authlink:authkey':
$replacements[$original] = $node->authkey;
break;
case 'authlink:view-url':
$replacements[$original] = node_authlink_get_url($node, 'view');
break;
case 'authlink:edit-url':
$replacements[$original] = node_authlink_get_url($node, 'update');
break;
case 'authlink:delete-url':
$replacements[$original] = node_authlink_get_url($node, 'delete');
break;
}
}
}
return $replacements;
}
/**
* Implements hook_group_content_info_alter().
*/
function node_authlink_group_content_info_alter(array &$groupContentInfo) {
// Override the access control handler so authlink can operate first.
foreach ($groupContentInfo as &$info) {
$info['handlers']['access'] = NodeAuthlinkGroupContentAccessControlHandler::class;
}
}
/**
* Implements hook_entity_type_alter().
*/
function node_authlink_entity_type_alter(array &$entity_types) {
if ($entity_types['node'] instanceof ContentEntityTypeInterface) {
$entity_types['node']
->setAccessClass(NodeAuthlinkNodeAccessControlHandler::class);
}
}
Functions
Name | Description |
---|---|
node_authlink_batch_delete | Delete authkeys for all nodes in node type. |
node_authlink_batch_generate | Generate authkeys for all nodes in node type. |
node_authlink_build_options | Helper function to build expire options. |
node_authlink_check_authlink | Check if a node has access to a node via authlink and grant it the query parameter is correct. |
node_authlink_create | Generate and save auth key for the new node. |
node_authlink_cron | Implementation of hook_cron(). |
node_authlink_delete | Deletes the node_authlink. |
node_authlink_entity_type_alter | Implements hook_entity_type_alter(). |
node_authlink_form_node_type_form_alter | Alter of node_type_form. |
node_authlink_form_node_type_form_alter_submit | Submit for node_type_form. |
node_authlink_get_url | Get edit URL of specified node. |
node_authlink_group_content_info_alter | Implements hook_group_content_info_alter(). |
node_authlink_load_authkey | Loads key from NID. |
node_authlink_node_access | Implements hook_node_access(). |
node_authlink_node_delete | Implements hook_ENTITY_TYPE_delete(). |
node_authlink_node_is_enabled | Checks if a node is enabled for node_authlink |
node_authlink_node_load | Implements hook_node_load(). |
node_authlink_tokens | Implements hook_tokens(). |
node_authlink_token_info | Implementation of hook_token_info(). |