Применение доступа к связанным записям

Версии: 3.x, 2.x.

В некоторых ситуациях требуется, чтобы при изменении прав доступа у записи, можно было автоматически задать доступ для всех связанных записей, которые располагаются во вкладках. В данной статье будет описано, как можно реализовать данную функцию на примере раздела «Объекты».

Итак, задача будет выглядеть следующим образом. На карточке объекта необходимо разместить кнопку «Применить доступ», которая будет менять доступ у всех таблиц, которые связаны с данной записью таблицы «Объекты». Старые права доступа у дочерних записей будут заменяться правами доступа выбранного объекта.

Кнопка копирования прав доступа

Для реализации данного функционала нам потребуется изменить два следующих скрипта.

  1. Клиентский скрипт карточки c_object.js, который вызывается сразу после открытия карточки.
  2. Серверный скрипт c_object.php, который обрабатывает AJAX запросы, поступающие от клиента (c_object.js).

Для начала изменим скрипт c_object.js, чтобы он рисовал на карточке объекта кнопку «Применить доступ». Для этого в конец функции c_object_init() допишем следующие строки.

var bnt_attr = '';
if (card_form._mode.value == 'insert') {
	bnt_attr = 'disabled = "disabled"'; // если новая запись, то сделаем кнопку неактивной 
}
card_form.btn_ok.parentNode.parentNode.parentNode.cells[0].innerHTML = '<input class="button" type="button" title="При применении доступа, доступ ко всем данным, связанным с этим объектом, будет равен доступу к этому объекту" value="Применить доступ" onclick="c_Object_ApplyPermissions(this)" style="width: 120px;" '+bnt_attr+' />';

При этом на карточку объекта добавится кнопка при нажатии которой будет вызываться функция c_Object_ApplyPermissions(). Если открыта картчочка новой записи, то кнопка будет неактивной.

Теперь опишем саму функцию c_Object_ApplyPermissions(). Ее работа заключается в посылке AJAX запроса скрипту c_object.js, и обработке его результата. Определимся, что скрипт будет возвращать нам в JSON формате код ошибки. Если код ошибки 0, то выведем сообщение об успешной смене прав доступа и сделаем саму кнопку неактивной. Иначе выведем предупреждение, что операция не выполенена. Допишем функцию в конце файла c_object.js. Она будет выглядеть следующим образом.

function c_Object_ApplyPermissions(p_this) {
    new Ajax.Request(g_path + c_Object_ScriptFileName, {
        parameters: {'_func': 'ApplyPermissions', 'rec_id': p_this.form._id.value}, 
        onComplete: function(transport) {
            try {
                var result = transport.responseText.evalJSON();
                if (result.errno == 0) {
                    wnd_alert('Права доступа успешно применены', 350, 80);
                    p_this.setAttribute('disabled', 'disabled');
                    return;
                }
            } catch (e) {}
 
            wnd_alert('<b>Внимание!</b><br> Не удалось применить права доступа', 350, 80);
        }
    }); 
}

Логика клиентской части приложения реализована. Теперь изменим логику работы серверной части.

Во-первых, для того, чтобы обработать запрос на изменение прав, нам нужно вызвать соответствующую функцию. Для этого, допишем в скрипте c_object.php вызов функции смены прав доступа.

<?php
case 'ApplyPermissions':
    $response = ApplyPermissions($_POST['rec_id']);
    break;

Теперь, когда скрипту будет приходить запрос с _func = 'ApplyPermissions', то будет вызвана PHP функция ApplyPermissions().

Опишем саму функцию ApplyPermissions() и добавим ее в файл c_object.php. Она будет выглядеть так.

<?php
function ApplyPermissions($p_rec_id) {
    include GetPath()."/config/common/Lib/access.php"; // подключаем функции для работы с правами доступа
    $con = db_connect(); // соединение с БД
 
    // получим права доступа к объекту
    $object_permissions = null; // в данный массив будут помещены права доступа для нужного объекта
    GetRecordPermissions("iris_object", $p_rec_id, &$object_permissions, $con); // получаем права доступа
 
    // указываем список таблиц, которым будем менять доступ. Нужно перечислить те таблицы, 
    // которые ссылаются на таблицу объекты
    $child_tables = array("iris_task", "iris_project", "iris_incident", "iris_file");
 
    foreach ($child_tables as $table) {
        // для каждой таблицы получим перечень дочерних записей, которые ссылаются на нужный объект
        $cmd = $con->prepare("select id as id from ".$table." where objectid=:obj_id");
        $cmd->execute(array(":obj_id" => $p_rec_id));
        $child_records = $cmd->fetchAll(PDO::FETCH_ASSOC);
        // для каждой дочерней записи удалим ее права доступа и установим права доступа от объекта
        foreach ($child_records as $record) {
            $res = 1;
            if (DeleteAllRecordPermissions($table, $record['id'], $con) == 0)
                $res = ChangeRecordPermissions($table, $record['id'], $object_permissions, $con);
            if ($res == 1) {
                // если при удалении или назначении прав возникла ошибка, то вернем код ошибки 1
                return array("errno" => "1", "table" => $table); 
                }
        }
    }
 
    return array("errno" => "0"); // вернем код ошибки 0
}

Для манипуляций с правами доступа здесь используются дополнительные функции, которые содержатся в файле access.php. Данные функции призваны упростить работу с правами доступа. Можно их и не использовать и работать с записями таблиц iris_xxx_access, но тогда нужно самим обрабатывать входные данные и возникшие ошибки.

Рассмотрим более подробно механизм работы функции ApplyPermissions(). В начале подключаются функции для работы с правами доступа и создается соеденение с БД при помощи функции db_connect(). Далее, при помощи функции GetRecordPermissions() в $object_permissions помещаем массив прав доступа для объекта, права доступа которого мы хотим применить к его дочерним записям. После этого в $child_tables поместим массив дочерних таблиц, которые содержат ссылки на таблицу «Объекты». Далее, в цикле будем перебирать все эти таблицы и для всех записей каждой дочерней таблицы, которые ссылаются на наш объект, будем менять права доступа. Права доступа меняются следующим образом. При помощи функции DeleteAllRecordPermissions() мы очищаем все права доступа у дочерней записи, а потом функцией ChangeRecordPermissions() устанавливаем ей права от родительского объекта.

Функция возвращает ассоциативный массив, содержащий один элемент — код ошибки errno. В случае, если возникли ошибки при смене прав, функция также вернет и имя таблицы, на которой произошла ошибка.

Таким образом, в карточке объекта будет размещена кнопка, которая позволит распространить его права доступа на дочерние записи.