Один из самых интересных и сложных шагов в настройке сайта.
Administer -> Site building -> Workflow.
Создаем новый workflow с именем "Article Workflow", присваиваем нашему Content type Article только что созданный workflow. Дальше создаем статусы (последовательность имеет значение).
Open for Claim
Открытая для редактирования. Модератор создает статью, при чем указывает только Название и Короткое описание статьи. Ставит статус статьи в "Open for Claim" и эта статья (по умолчанию опубликованная, что указывается в настройках Content type - Article) становится свободной для редактирования другими, простыми смертными пользователями, ну и естесственно для самого модератора.
Draft
Черновик. Мембер зашел на сайт, просмотрел статьи, увидел среди них интересное для себя "Название статьи" и статус "Open for Claim", нажал на статью и начал её редактировать, при этом:
- статус статьи меняется на Draft;
- статься становится неопубликованной (published = 0), нам ведь не надо, чтобы другие пользователи видели черновик;
- автором статьи становится текущий залогиненный пользователь;
Rejected
Отклонена. Собственно это состояние опционально. В моем проекте оно используется для того, чтобы показывать пользователю причину, по которой его статья была отклонена. Если в вашем проекте такой необходимости нет - смело можете пропускать. Но у нас при этом состоянии происходит следующее:
- статья сбрасывается в статус Unpublished
- причина отклонения показывается в трекере пользователя
Pending
На рассмотрении. После того, как пользователь завершил редактирование своей статьи и решил, что пора её уже опубликовать - он жмет на кнопку "Save as Pending", при этом:
- статус статьи устанавливается в Pending;
- статья остается неопубликованной, т.к. она не прошла модерацию;
- в этом статусе пользователь уже не может редактировать свою статью, т.к. позняк метаться, нажал Pending - жди пока её отклонят или опубликуют;
Published
Опубликованная. Модератор зашел, посмотрел статьи со статусом Pending. Какие-то отклонил, какие-то опубликовал. Когда опубликовал, то:
- статья становится опубликованной (published = 1);
- пользователь (автор) не может поменять текст статьи;
Когда отклонил:
- статус статьи становится Draft;
- статья остается неопубликованной, т.к. если было бы что показывать - сделал бы Published.
После создания этих состояний можете настраивать правила переходов. Процесс этот муторный, но простой, поэтому поразбирайтесь с ним сами, а то все я, да я...
Состояния есть, переходы есть, общее понимание процесса тоже надеюсь появилось, осталось только организовать изменение статьи в зависимости от статуса. Для этого нам понадобится модуль Actions, чьей настройкой и займемся.
Изначально модуль предлагает ряд встроенных и наиболее необходимых экшнов. Эти экшны нам тоже пригодятся, но все же придется поковыряться в коде, чтобы добавить некоторые специфические действия. Хотя... Сначала опишем те, которые уже есть и которые нам пригодятся.
Publish node/Unpublish node - опубликование, сокрытие ноды соответственно. Нужны для переходов:
(creation) → Draft - Unpublish node
Published → Rejected - Unpublish node (вдруг модератор передумал?)
(creation) → Open for Claim - Publish node
(creation) → Published - Publish node (если модератор создал статью и сразу хочет опубликовать... он же модератор, ему можно)
Draft → Published - Publish node (тоже для модератора)
Pending → Published - Publish node
И собственно нам больше ничего и не надо из того, что есть. Опишем теперь подводные камни, которые могут встретиться в нашем подводном плавании.
1) Пользователь создал статью, статус статьи "Draft", и по идее он может перевести статью в "Open for Claim" под предлогом того, что он передумал. НО, мы же не знаем что он там понаписал...
2) Проходит какое-то время, модератор смотрит на опубликованные статьи и какая-нибудь из них перестает ему нравиться, что делать? Переводить в "Open for Claim" или в "Rejected"... Если переводим в "Open for Claim", то если автором статьи был простой смертный, мы не знаем что было в первой ревизии этой статьи.
Сплошные "если"...
Приходим к выводу, что нам нужен экшн, который будет смотреть кто является первоначальным автором ноды, и если модератор - то смело откатываем статью до первой ревизии, ставим автора статьи в первоначального автора, опубликовываем статью и не паримся. Если же автор статьи НЕ модератор - просто переводим в статью в её последнее состояние и опять же меняем автора на первоначального. Пишем его в modules/action/actions.inc.
<?phpfunction action_node_to_first_revision($op, $edit = array(), &$node) {
switch($op) {
case 'metadata':
return array(
'description' => t('Try to revert Node to first revision.'),
'type' => t('Node'),
'batchable' => true,
'configurable' => FALSE,
);
case 'do':
$old_sid = db_result(db_query("SELECT old_sid FROM {workflow_node_history} WHERE nid=%d ORDER BY stamp DESC LIMIT 1", $node->nid));
$allow_roles = array('moderator');
$primary_user = user_load(array('uid' => get_node_primary_author($node->nid)));
if (count(array_intersect($primary_user->roles, $allow_roles)) > 0)
{
$primary_vid = get_node_primary_revision($node->nid);
$primary_node = node_load($node->nid, $primary_vid);
if ($primary_node->vid) {
$primary_node->revision = '0';
$primary_node->uid = $primary_user->uid;
$primary_node->status = '1';
node_save($primary_node);
watchdog('action', t('Changed author of node %id to uid %uid', array('%id' => intval($primary_node->nid), '%uid' => intval($primary_node->uid))));
break;
}
}
$node->uid = $primary_user->uid;
node_save($node);
workflow_execute_transition($node, $old_sid);
break;
}
}
?>
Что делают функции "get_node_primary_author()" и "get_node_primary_revision()" понятно из названия. Если нет, то первая берет первоначального автора ноды из таблицы ревизий, а вторая берет ID самой первой ревизии ноды.
Ну и ещё один экшн, который меняет автора ноды на текущего залогиненного пользователя.
<?php function action_node_assign_author_to_clu($op, $edit = array(), &$node) {
switch($op) {
case 'metadata':
return array(
'description' => t('Change node author to Currently Logged User'),
'type' => t('Node'),
'batchable' => true,
'configurable' => FALSE,
);
case 'do':
global $user;
$node->uid = $user->uid;
$node->revision = '0';
node_save($node);
watchdog('action', t('Changed author of node %id to uid %uid', array('%id' => intval($node->nid), '%uid' => intval($user->uid))));
break;
}
}?>
Ничего сложного. Теперь вы умеете писать экшны, не требующие настройки.
Замечание. Если в каком-либо экшне у вас проблемы или просто хотите что-либо исправить надо делать так:
внесли изменения - переименуйте функцию
одновите страницу со списком экшнов
нажмите на ссылку Remove orphaned actions
переименуйте функцию обратно, как она была
одновите страницу со списком экшнов
нажмите на ссылку Remove orphaned actions
изменения вступили в силу, щастье...
Мазафака, почему не работает ?! По желанию можно добавить ещё парочку экшнов из набора стандартных. А точнее на отправку письма пользователю. У меня их 2: Rejected Article Email и Published Article Email. "Recipient" в обоих случаях стоит %author. Соответственно для отправки письма пользователю при отклонении его статьи и при опубликовании.
Комментарии
какие сложности... это все вместо того, чтобы использовать вики?
http://drupal.org/node/102913
Этим я хочу сказать, что на данный момент в друпале нет модулей, обеспечивающих необходимый (для моего проекта) Wiki функционал. Ставить Wiki отдельно - тоже не катит, вот поэтому и извращаюсь.
Не очень хорошо знаком с функционалом Wiki-инструментария в Drupal, но мне кажется что для четкой многоуровневой иерархии утверждения/редактирования статей этот инструментарий не подходит. Или я не прав?
Все зависит от требований проекта...
"Не очень хорошо знаком с функционалом Wiki-инструментария в Drupal"
http://docs.drupal.ru/ - Друпал-вики в действии...
Интересно...
Нет, я так понял это не для вики. Просто описанный Workflow напоминает вики, но можно прописать свои "дорожки" движения документов.
Спасибо за статью.
С Workflow - можно все
Анонсирована версия Workflow 5.x-2.0, которая будет включать возможность указания прав доступа к ноде в зависимости от статуса workflow, что будет ещё удобнее...
Хорошая статья.
Но возникла проблема. Создал states, хочу добавить Workflow actions (/admin/build/workflow/actions/1), но что бы я там не добавлял, выскакивает Fatal error: Call to undefined function: actions_key_lookup() in \sites\all\modules\workflow\workflow.module on line 1429.
Кто знает, как исправить ?
Очень хочется решить проблему, т.к. похоже, что действительно "С Workflow - можно все :)"
Надо откатится на предыдущую версию actions. У меня было тоже самое с Actions 5.x-2.0 поставил 5.x-1.0 и все стало хорошо. Кроме рассылки по ролям...там тоже ошибка, а вот на конкретный email нормально.
Очень полезная статья, Спасибо!
У меня вопрос есть, получается что если пользователь отредактировал страницу, то пока ее не опубликует модератор, страницу никто не увидет. А мне очень надо чтоб была видна исходная страница, пока отредактированную не одобрят. А вот когда одобрят чтоб она заменила исходную.
Action для этого я не нашел.
Попробовал Actions 5.x-1.0
Все равно не работает, Actions выдает
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_node_publish', 'Материал', 'action_node_publish', '', 'Publish node') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_node_unpublish', 'Материал', 'action_node_unpublish', '', 'Unpublish node') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_node_sticky', 'Материал', 'action_node_sticky', '', 'Make node sticky') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_node_unsticky', 'Материал', 'action_node_unsticky', '', 'Make node unsticky') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_node_promote', 'Материал', 'action_node_promote', '', 'Promote node to front page') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_node_unpromote', 'Материал', 'action_node_unpromote', '', 'Remove node from front page') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'func' in 'field list' query: INSERT INTO actions (aid, type, func, params, description) VALUES ('action_workflow_execute_transition', 'Процесс', 'action_workflow_execute_transition', '', 'Change workflow state of a node to next state') in y:\home\info\drupal\includes\database.mysql.inc on line 172.
user warning: Unknown column 'params' in 'where clause' query: SELECT aid FROM actions WHERE params != '' in y:\home\info\drupal\includes\database.mysql.inc on line 172.
В Workflow actions при добавлении действия - почти то же.
Объясните, пожалуйста, где это настраивается?
ps кажется, разобралась