Добрый день, вроде тема простая, но запутался окончательно с логикой всех этих realm-ов и gid-ов :/
Задача выглядит просто:
* есть роль пользователя REVIEWER
* есть типа материала NEWS для хранения материалов типа новости,
внутри которого есть числовое поле STATE, представляющее собой текущий статус жизненного цикла новости
данное поле может хранить значения 2,3,4 (2 - это черновик, 3 - премодерация, 4 - публикация)
Суть такова, что нужно сделать так, чтобы когда значения STATE - 2, то новость как бы в режиме черновика у автора, и данную новость автор может просматривать, редактировать и удалять, все остальные при этом (кроме админа соответственно) не могут её видеть в принципе.
Когда же статус 3, т.е. на премодерации, то автор её уже может только просматривать (редактировать и соответственно удалять не может), а также просматривать её может любой пользователь с ролью REVIEWER
И собственно когда статус 4 - любой пользователь сайта может её просматривать, и никто не может редактировать и удалять
Другими словами получается тут скорее в статусе 2 нужно запретить просмотр, редактирование и удаление всем пользователям кроме автора, в статусе 3 нужно запретить просмотр всем пользователям кроме автора и пользователей с ролью REVIEWER, при этом также запретить всем редактирование и просмотр, а в статусе 4 - просто всем запретить редактирование и удаление.
Читая справки так понимаю, что по уму здесь нужно делать через 2 хука - hook_node_access_records и hook_node_grants
В первом хуке (hook_node_access_records) будет происходит запись в базу - в пределах какого реалма (realm)? какой уровень доступа (gid) необходим пользователю для доступа к ноде (nid) и какие при этом будут доступны действия над ней (grant_view, grant_update, grant_delete)
А во втором (hook_node_grants) в зависимости от какого действия над нодой на текущий момент ($op) и для какого текущего пользователя ($account) будет предоставлен определенный грант
И в общем - совсем запутался
Начал с простого:
<?php
/**
* Implements hook_node_access_records().
*/
function mymodule_node_access_records($node) {
$grants = array();
if ($node->type == 'news') {
$workflow_state = field_get_items('node', $node, 'field_news_workflow');
if ($workflow_state[0]['value'] == 2) {
$grants[] = array(
'realm' => 'mymodule_access_news',
'gid' => $node->uid,
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 1,
'priority' => 0,
);
}
}
return $grants;
}
/**
* Implements hook_node_grants().
*/
function mymodule_node_grants($account, $op) {
$grants = array();
$grants['mymodule_access_news'] = array($account->uid);
return $grants;
}
?>
Получается сделал проверку, если нода со статусом 2 (т.е. черновик), то создай для неё грант с id-шником автора ноды, при этом предоставь этому гранту: просмотр, правку и удаление. А дальше относительно текущего пользователя, без разницы кто он вообще, осуществляй проверку что ему доступно на основе его гранта в виде его uid-шника.
Ну и как результат ему будет доступно все его ноды в полных правах, которые имеют статус 2 (черновик)
А дальше я туплю, как нужно описать например для статуса 3, т.е. когда нужно автору предоставить только просмотр, а reviewer-у тоже только просмотр.
Получается первый хук будет представлять собой, что то следующее:
<?php
/**
* Implements hook_node_access_records().
*/
function mymodule_node_access_records($node) {
$grants = array();
if ($node->type == 'news') {
$workflow_state = field_get_items('node', $node, 'field_news_workflow');
if ($workflow_state[0]['value'] == 2) {
$grants[] = array(
'realm' => 'mymodule_access_news',
'gid' => $node->uid,
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 1,
'priority' => 0,
);
} elseif ($workflow_state[0]['value'] == 3) {
$grants[] = array(
'realm' => 'mymodule_access_news',
'gid' => ??????????,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
}
}
return $grants;
}
?>
Но что нужно указывать в gid-е? И как это нужно описать ниже в hook_node_grants?
Вроде всё наверняка просто, но не могу логику понять
Комментарии
Я бы сделал проще. В hook_form_alter проверял бы значение поля статуса и давал разрешение на редактирование по вашей логике. Аналогично и на удаление. Для управлением просмотром есть hook_node_view
В общем, Вы слишком глубоко закопались, я думаю
Если, конечно, это не тестовое задание и сделать его нужно именно этими хуками
Это делаю для себя, просто как читал - через гранты это более правильное решения, а также считая, что отображать контент я ещё буду через Views, то он на них тоже внимание обращает при рендеринге
вы уверены что gid - Это ид пользователя? что если это просто число от 0 до xxx определяющее логику в hook_node_grants
По идее это не id пользователя, просто в первом случае это как бы наверное идеально подошло бы, когда нужно разграничить доступ только для автора ноды, т.е. чтобы могло быть как бы одно совпадение между hook_node_grants и hook_node_access_records касательно этой ноды.
Т.е. предоставить полный доступ только одному уникальному gid-у, и таким гид как раз касательно ноды может быть uid её автора
А вот дальше, когда уже на втором и третьем статусе нужно дать доступ уже не только автору, но и reviewer-у (а также всем), то там уже какое то идеологическое значение должно быть
Т.е. первый статус у меня сейчас вроде как работает, так как я и ожидаю, а со следующими вариантами не могу додуматься
https://niklan.net/blog/63 вот тут похожий случай очень хорошо разобран.
Вот я как раз у Никиты уже вдоль и поперёк прочитал этот материал , но не могу додуматься как в моём случае сделать
В его статье он получается создаёт 2 варианта определенного типа ноды, первый в котором есть галочка members_only и во втором когда её нету, соответственно в первом случае это типа приватный материал, во втором публичный. Таким образом в пространстве реалма mymodule_access_article создал 2 вида гранта (приватный и публичный) - их ещё называют, что то вроде замков
А далее когда приходит пользователь к этому замку (реалму), он на основе его членства в определенной роли, выдаёт ему один ключ (публичный) либо сразу 2 (публичный и приватный)
Иногда практикую одно и тоже пересказывать как будто самому себе на паровозиках, и иногда понимает разобраться, но в данном случае не помогло
Так вот в моём случае похоже есть 3 замка
1) первый всегда имеет один ключ, и он может быть только у одного пользователя в разрезе одной ноды (именно поэтому наверняка в таблице node_access первичный ключ состоит из nid, gid и realm). Потому я в реалме mymodule_access_news создаю ему gid с id-шником автора.
2) второй получается должен уже предоставлять немного иные права, только на view, но при этом gid уже похоже будет более статичный, и похоже скорее всего здесь уже другое имя realm-а должно быть
3) ...
Таким образом я сейчас уже пришёл к следующему коду:
<?php /**
* Implements hook_node_access_records().
*/
function mymodule_node_access_records($node) {
$grants = array();
if ($node->type == 'news') {
$workflow_state = field_get_items('node', $node, 'field_news_workflow');
if ($workflow_state[0]['value'] == 2) {
$grants[] = array(
'realm' => 'mymodule_draft_news',
'gid' => $node->uid,
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 1,
'priority' => 0,
);
} elseif ($workflow_state[0]['value'] == 3) {
$grants[] = array(
'realm' => 'mymodule_review_news',
'gid' => 0,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
} elseif ($workflow_state[0]['value'] == 4) {
$grants[] = array(
'realm' => 'mymodule_publish_news',
'gid' => 0,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
}
}
return $grants;
} /**
* Implements hook_node_grants().
*/
function mymodule_node_grants($account, $op) {
$grants = array();
if ($op == 'view') {
$grants['mymodule_draft_news'] = array($account->uid);
if (in_array('reviewer', $account->roles)) {
$grants['mymodule_review_news'] = array(0);
}
}
return $grants;
} ?>
Т.е. я создал 3 реалма под каждый статус, первый отрабатывает успешно,
второй успешно уже предоставляет доступ только на просмотр для пользователей с ролью reviewer (только для нод со статусом 3 = review)
но тут проблема, получается нужно также дать доступ только на просмотр этой ноды ещё и автору, и как вот это описать в hook_node_grants
<?php
/**
* @file
* Здесь мы будем писать весь код.
*/ define('ADVANSED_ACCESS_REALM', 'advansed_access_node_access_records');
define('ADVANSED_ACCESS_VIEW', 1);
define('ADVANSED_ACCESS_EDIT', 2);
define('ADVANSED_ACCESS_DENIED', 3); /**
* Используем hook_node_grants().
*
* Данный хук срабатывает при просмотре содержимого и выдаёт пользователю
* соответствующий уровень доступа к содержимому.
*
* $account - информация о пользователе, который обратился к ноде.
* $op - операция которая выполняется (view, edit, delete).
*/
function advansed_access_node_grants($account, $op) {
// Получим автора ноды
// Нас интересует лишь просмотр и редактирование содержимого.
// Удаление будет ограничено системными правами (что в админке друпала).
$grants[ADVANSED_ACCESS_REALM] = array(
ADVANSED_ACCESS_VIEW,
ADVANSED_ACCESS_EDIT,
);
}
if ($op == 'update') {
$grants[ADVANSED_ACCESS_REALM] = array(
ADVANSED_ACCESS_VIEW,
ADVANSED_ACCESS_EDIT,
);
}
if ($op == 'delete') {
$grants[ADVANSED_ACCESS_REALM] = array(
ADVANSED_ACCESS_VIEW,
ADVANSED_ACCESS_EDIT,
);
}
return $grants;
} /**
* Используем hook_node_access_records().
*
* В данном хуке определяется, какой уровень доступа необходим для ноды.
* Данная запись делется при редактировании\добавлении нового материала.
*
* Если у вас уже есть содержимое, которому нужно "пересобрать" права, то
* воспользуйтесь фукнцией node_access_rebuild() или в админке:
* admin/reports/status/rebuild
*/
function advansed_access_node_access_records($node) {
global $user;
watchdog('advansed_access', $user->uid);
$members_only = field_get_items('node', $node, 'field_members_only');
$members_only = $members_only[0]['value'];
// Если отмечено "Для своих".
if ($members_only == 2) {
// Указываем ноде, что смотреть её могут пользователи только с gid
// который отвечает за просмотр приватного содержимого.
if ($user->uid == 0) {
$grants[] = array(
'realm' => ADVANSED_ACCESS_REALM,
'gid' => ADVANSED_ACCESS_VIEW,
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 0,
'priority' => 0,
);
return $grants;
}
elseif ($user->uid == $node->uid && $user->uid != 0) {
$grants[] = array(
'realm' => ADVANSED_ACCESS_REALM,
'gid' => ADVANSED_ACCESS_EDIT,
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 0,
'priority' => 0,
);
}
elseif (in_array('authenticated user', $user->roles)) {
$grants[] = array(
'realm' => ADVANSED_ACCESS_REALM,
'gid' => ADVANSED_ACCESS_EDIT,
'grant_view' => 1,
'grant_update' => 1,
'grant_delete' => 0,
'priority' => 0,
);
}
else {
$grants[] = array(
'realm' => ADVANSED_ACCESS_REALM,
'gid' => ADVANSED_ACCESS_DENIED,
'grant_view' => 0,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
}
}
if ($members_only == 3) {
if ($user->uid == $node->uid) {
$grants[] = array(
'realm' => ADVANSED_ACCESS_REALM,
'gid' => ADVANSED_ACCESS_EDIT,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
} else {
$grants[] = array(
'realm' => ADVANSED_ACCESS_REALM,
'gid' => ADVANSED_ACCESS_DENIED,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
}
}
}
return
$grants;} ?>
Написано на коленке. Надо разобраться с очерёдностью и условиями.
не забывайте про /admin/reports/status/rebuild