Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- //Сниппет TryLoadDocument
- /**
- Итак, все документы хранятся в базе вот в таком виде(переделано в формат JSON для лучшей читаемости):
- {
- "type":"agreement", - тип документа, текстовый, короткий, примеры: carta, license и т.д.
- "title":"Договор", - заголовок документа
- "text":"Пример. Текст договора. Подпишите здесь: ______ ", - текст документа, XSS контролирует CLeditor, не наша забота. Содержит весь текст какого-то документа со всеми тегами разметки.
- "owner":29, - это владелец документа, то есть тот, с кем наш сайт его заключил. у него в любом случае есть право смотреть и редактировать этот документ(т.к. он "его")
- "edit":[29,555,34,52], - это те, кто может редактировать документ.
- !ВАЖНО! пользователи групп Administrator,Jurists имеют доступ к ЛЮБОМУ документу!
- "view":[5677,599677,5999898677,855677] - те, кто открыв страничку http://.../docs?doc_id=5 увидят этот документ(но редактировать не смогут)
- "view-temp":[{"id":5,"until":1413640050},{"id":9,"until":1413640100},{"id":7,"until":1413640050}] - аналогично view, но "until"(формат timestamp) указывает, вплоть до какого момента времени нужно учитывать эту запись(после этого момента она удаляется)
- "edit-temp":[{"id":5,"until":1413640050},{"id":9,"until":1413640100},{"id":7,"until":1413640050}] - аналогично edit, но "until"(формат timestamp) указывает, вплоть до какого момента времени нужно учитывать эту запись(после этого момента она удаляется)
- }
- вот таким запросом можно такую таблицу создать:
- CREATE TABLE IF NOT EXISTS `documents` (
- `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id документа',
- `type` varchar(255) NOT NULL COMMENT 'тип документа',
- `title` varchar(255) NOT NULL COMMENT 'заголовок документа',
- `text` text NOT NULL COMMENT 'текст документа',
- `owner` bigint(20) NOT NULL COMMENT 'владелец дока',
- `edit` text NOT NULL COMMENT 'все юзеры, у кого есть права на просмотр и редактирование',
- `edit-temp` text NOT NULL COMMENT 'временные разрешения на редактирование',
- `view` text NOT NULL COMMENT 'все юзеры, у кого есть права на просмотр',
- `view-temp` text NOT NULL COMMENT 'временные разрешения на редактирование',
- UNIQUE KEY `id` (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=cp1251 COMMENT='Личные документы пользователей - здесь...';
- */
- class Document {
- private $data;//здесь все данные документа в виде ассоциативного массива(напр $data['title'] - заголовок документа)
- private $uid;//=user id — id того, кто пытается использовать этот документ(или создать)
- private $modx;//для работы с modx API
- public function __construct($modx)
- {//т.к. доступа напрямую к $modx в функциях нет(по крайней мере у меня), передадим ее параметром
- $this->modx=$modx;
- $this->uid=$this->modx->user->get('id');//объект документа можно создать только от имени текущего юзера
- }
- public function &__set ( $name , $value )
- {//снаружи(не используя функций) менять можно только title и text
- $allowed=["title","text"];
- if(in_array($name,$allowed))
- {
- if($this->editAllowed())//если текущему пользователю можно редактировать
- $this->data[$name]=$value;
- }
- }
- public function &__get ( $name )
- {//снаружи класса напрямую получить значения полей могут все из списков edit & view, а также владелец...
- if($this->isOwner() || $this->viewAllowed() || $this->editAllowed())
- {
- switch ($name)
- {
- case "title":return $this->data['title'];
- case "text": return $this->data['text'];
- case "id": return $this->data['id'];
- case "uid": return $this->uid;
- }
- }
- return 'forbidden';
- }
- public function MakeNew($type,$title,$text)//для создания документа по шаблону, либо сгенерированного динамически
- {
- $this->data['text']=$text;//текст документа
- $this->data['title']=$title;//заголовок
- $this->data['view']=[];//кому можно просматривать документ
- $this->data['view-temp']=[];
- $this->data['edit']=[];//кому можно документ редактировать
- $this->data['edit-temp']=[];
- $this->load($this->saveAsNew($type));//сохраняем док и загружаем его в нормальном виде
- }
- public function viewAllowed()
- {//возвращает истину, если этому юзеру можно просматривать этот документ, иначе - ложь..
- $allowed= $this->isOwner()//если запрашивающий - создатель документа
- || in_array($this->uid,$this->data['view']);//или имеет право на его просмотр
- if($allowed)
- return true;
- else
- for($i=0; $i<count($this->data['view-temp']);$i++)
- if($this->data['view-temp'][$i]->id==$this->uid)
- return $this->data['view-temp'][$i]->until > time();
- return false;
- }
- public function editAllowed()
- {//возвращает истину, если этому юзеру можно редактировать этот документ, иначе - ложь..
- $allowed = $this->isOwner() || //если запрашивающий - создатель документа
- in_array($this->uid,$this->data['edit']);//если запрашивающему можно редактировать документ
- if($allowed)
- return true;
- else
- for($i=0; $i<count($this->data['edit-temp']);$i++)
- if($this->data['edit-temp'][$i]->id==$this->uid)
- return $this->data['edit-temp'][$i]->until > time();
- //доступ к временным полям через '->' из-за принципа декодирования функцией json_decode
- return false;
- }
- public function manageAllowed()
- {//true если этому юзеру можно давать другим доступ к документу. false в обратном случае.
- return $this->modx->user->isMember('Jurists')||$this->modx->user->isMember('Administrator');
- }
- public function allow($new_user,$can_edit,$time=0)
- {
- //дать кому-то доступ к документу. $new_user - кому дать,
- //$can_edit - может ли редактировать(только если запросивший сам может редактировать, иначе не сработает)
- //$time - на какое время дать права(по умолчанию 0 - навсегда. измеряется в секундах
- $user_id=(int)$new_user;
- if($user_id!=0 && $this->manageAllowed())
- if($can_edit)
- {
- if($this->editAllowed())
- {
- if($time==0)//выдать права навсегда
- $this->data['edit'][]=$user_id;
- else//выдать права на $time секунд
- $this->data['edit-temp'][]=["id"=>$user_id,"until"=>time()+$time];
- }
- }
- else
- {
- if($time==0)//выдать права навсегда
- $this->data['view'][]=$user_id;
- else//выдать права на $time секунд
- $this->data['view-temp'][]=["id"=>$user_id,"until"=>time()+$time];
- }
- }
- public function isOwner()
- {
- $usual=$this->uid==$this->data['owner'];//права владельца есть у:
- if($usual) return true;//самого владельца,
- else//спец аккаунтов
- return $this->manageAllowed();
- }
- Вспомогательная функция, очищающая документ от устаревших временных разрешений
- private function clearTemp()
- {//очищает все массивы от врeменных разрешений у которых прошел срок действия
- if(count($this->data['view-temp'])+count($this->data['edit-temp']) > 0)//если хоть какие-то временные данные есть
- {
- for($i=0; $i<count($this->data['view-temp']);$i++)
- //удалить все временные разрешения, у которых дата истечения раньше текущего времени(time())
- {
- if($this->data['view-temp'][$i]->until < time())
- unset($this->data['view-temp'][$i]);
- }
- $this->data['view-temp']=array_values($this->data['view-temp']);//просто фикс проблемы с индексами( [1,3,5]=>[0,1,2)]
- for($i=0; $i<count($this->data['edit-temp']);$i++)
- //удалить все временные разрешения, у которых дата истечения раньше текущего времени(time())
- {
- if($this->data['edit-temp'][$i]->until < time())
- unset($this->data['edit-temp'][$i]);
- }
- $this->data['edit-temp'] = array_values($this->data['edit-temp']);//просто фикс проблемы с индексами( [1,3,5]=>[0,1,2)]
- $this->save();//сохранить изменения
- }
- }
- public function load($id)
- {//загружает документ из бд(на это прав хватит у любого, вот только не любой сможет эти данные у класса получить)
- $sql="SELECT * FROM `documents` WHERE `id`=:id";
- $query = new xPDOCriteria($this->modx, $sql,array(':id'=>$id));
- if($query->prepare() && $query->stmt->execute())
- {//если данные удачно загружены
- $this->data = $query->stmt->fetchAll(PDO::FETCH_ASSOC)[0];
- if(count($this->data)==0) return false;//если пришел пустой ответ, сообщаем о фейле зуагрузки
- $this->data['edit']=json_decode($this->data['edit']);///распаковываем список имеющих право на редактирование в массив
- $this->data['edit-temp']=json_decode($this->data['edit-temp']);///распаковываем список имеющих временное право на редактирование в массив
- $this->data['view']=json_decode($this->data['view']);///распаковываем список имеющих право на просмотр в массив
- $this->data['view-temp']=json_decode($this->data['view-temp']);///распаковываем список имеющих временное право на просмотр в массив
- $this->clearTemp();//очищаем массивы view-temp & edit-temp от закончившихся разрешений
- return true;//раз дошли сюда, сообщаем, что все ок
- }
- else return false;//если не выполнился запрос, сообщаем о фейле загрузки
- }
- public function save()
- {//сохраняет новое значение документа в бд
- $sql="UPDATE `documents` SET `title`=:title, `text`=:text, `view`=:view, `edit`=:edit, `view-temp`=:viewtemp, `edit-temp`=:edittemp WHERE `id`=:id";//шаблон запроса
- $this->data['view']=json_encode($this->data['view']);///запаковываем список имеющих право на просмотр в строку
- $this->data['view-temp']=json_encode($this->data['view-temp']);///запаковываем список имеющих право на временный просмотр в строку
- $this->data['edit']=json_encode($this->data['edit']);///запаковываем список имеющих право на редактирование в строку
- $this->data['edit-temp']=json_encode($this->data['edit-temp']);///запаковываем список имеющих право на временное редактирование в строку
- $query=new xPDOCriteria($this->modx, $sql,
- [":title"=>$this->data['title'],":text"=>$this->data['text'],":edit"=>$this->data['edit'],":view"=>$this->data['view'],":edittemp"=>$this->data['edit-temp'],":viewtemp"=>$this->data['view-temp'],":id"=>$this->data["id"]]);//подставляем данные
- $query->prepare() && $query->stmt->execute();//выполняем запрос
- //преобразуем строки обратно в массивы
- $this->data['view']=json_decode($this->data['view']);
- $this->data['view-temp']=json_decode($this->data['view-temp']);
- $this->data['edit']=json_decode($this->data['edit']);
- $this->data['edit-temp']=json_decode($this->data['edit-temp']);
- }
- private function saveAsNew($type)
- {//сохраняет уже заполненный документ как новую запись типа $type
- $sql="INSERT INTO `documents` (`title`,`text`,`view`,`edit`,`owner`,`type`) VALUES(:title,:text,:view,:edit,:uid,:type)";//шаблон запроса
- $this->data['view']=json_encode($this->data['view']);///запаковываем список имеющих право на просмотр в строку
- $this->data['edit']=json_encode($this->data['edit']);///запаковываем список имеющих право на редактирование в строку
- $this->data['view-temp']=json_encode($this->data['view-temp']);///запаковываем список имеющих право на просмотр в строку
- $this->data['edit-temp']=json_encode($this->data['edit-temp']);///запаковываем список имеющих право на редактирование в строку
- $query=new xPDOCriteria($this->modx, $sql,
- [":title"=>$this->data['title'],":text"=>$this->data['text'],":edit"=>$this->data['edit'],":view"=>$this->data['view'],":uid"=>$this->uid,":type"=>$type]);//подставляем данные
- //логгируем создание нового документа, полезно для отладки и чтобы посмотреть как шаблон данными заполняется
- //$this->modx->log(modX::LOG_LEVEL_ERROR,"Выполнение запроса: ".$query->toSQL());
- $query->prepare(); $query->stmt->execute();//выполняем запрос
- return $this->modx->lastInsertId();//вернем id созданного дока
- }
- }
- if(DOC_API_MODE!="API")//если нужен только класс Document, эта часть кода не выполнится)
- {
- if($modx->user->get('id')==0)//если на страницу зашел анон,
- {
- $modx->sendRedirect($modx->makeUrl(14));//отправляем его на страницу номер 14, именно там у нас вход в систему.
- exit;//на случай если редирект ВДРУГ не сработал, завершаем скрипт наверняка(вместо странчики будет просто белый экран)
- }
- /*******/
- $doc=new Document($modx);//создаем объект для работы с документом для вошедшего на страницу пользователя
- if(!$doc->load($_GET['doc_id']))//пытаемся загрузить док из бд
- {//если не удалось, выходим...
- return 'Документ не найден...';
- }
- //!!! сообщаем чанку Rights, отображать ли поле редактирования доступом
- $modx->setPlaceholder('CanManage',$doc->manageAllowed()?'true':'false');
- //!!! сообщаем чанку DocText, отображать ли форму редактирования
- $modx->setPlaceholder('CanEdit',$doc->editAllowed()?'true':'false');
- function DataToUID($userstr,$modx)//для вытаскивания цифры с номером пользователя из поля "пользователю"
- {
- $link_rgx="/(.*uid=)([\d]{1,})(.*)/";//регулярка для ссылки вида http://*путь до личного кабинета*?uid=56
- $id_rgx="/([^\w]{0,})([\d]{1,})/";//регулярка id пользователя(до и после числа могут быть пробелы)
- if(preg_match($link_rgx,$userstr))
- {//для ссылки вида http://*путь до личного кабинета*?uid=56
- $r="$2";
- return preg_replace($link_rgx,$r,$userstr);
- } else
- if(preg_match($id_rgx,$userstr))//если ввод был " 234", например
- {
- $r="$2";
- return preg_replace($id_rgx,$r,$userstr);//вернем только число
- } else//это и не идентификатор юзера и не ссылка на его лк? тогда может это ник?
- {
- $usr=$modx->getObject('modUser',["username"=>$userstr]);//пытаемся найти юзера с таким ником
- return $usr?$usr->get('id'):'-1';
- }
- }
- /*********Эти два для работы в режиме форм***********/
- if(isset($_POST['add']))//если юзер нажал кнопочку "добавить права пользователю...
- {
- $userID=(int)DataToUID($_POST['userid'],$modx);//вытаскиваем id пользователя из поля формы 'userid'
- if($userID!='-1')//если пользователь нашелся
- {
- if($_POST['allow']=="edit")//если надо добавить права на редактирование и просмотр(задается полем формы 'allow')
- {
- //пишем в лог
- $modx->log(modX::LOG_LEVEL_ERROR,"Попытка выдать права на редактирование документа #".$doc->id." пользователем #".$doc->uid." пользователю #".$userID);
- $doc->allow($userID,true,(int)$_POST['length']);
- $doc->save();
- } else
- if($_POST['allow']=="view")////если надо добавить права на просмотр(задается полем формы 'allow')
- {
- //пишем в лог
- $modx->log(modX::LOG_LEVEL_ERROR,"Попытка выдать права на просмотр документа #".$doc->id." пользователем #".$doc->uid." пользователю #".$userID);
- $doc->allow($userID,false,(int)$_POST['length']);
- $doc->save();
- }
- }else $modx->log(modX::LOG_LEVEL_ERROR,"DataToUID не справилась. (".$_POST['userid'].")");//если вместо имени пользователя передали фигню, пишем в лог
- }
- if(isset($_POST['edit']))//если юзер отредактировал документ и нажал "сохранить"
- {
- $modx->log(modX::LOG_LEVEL_ERROR,"Попытка отредактировать текст документа #".$doc->id." пользователем #".$doc->uid);//пишем в лог
- if(!empty($_POST["text"]))//если новый вариант документа не пуст(нету смысла в пустых доках)
- {
- $doc->text=$_POST["text"];//задаем полю класса text новое значение
- $doc->save();
- $modx->log(modX::LOG_LEVEL_ERROR,"Отредактирован текст документа #".$doc->id." пользователем #".$doc->uid);//пишем в лог
- }
- }
- /**********Вывод данных в форму*************/
- if(!isset($_POST['ajax']))//если мы вызваны не через аякс, а для загрузки страницы.
- {
- $output="";
- //грузим док, если нельзя, то объект сам разберется
- //передаем чанку заголовка DocTitle параметром свойство title, то есть заголовок документа. проверять доступ к нему - не наша забота.
- $output.=$modx->getChunk('DocTitle',['title'=>$doc->title]);
- //передаем чанку заголовка DocText параметром свойство title, то есть заголовок документа. проверять доступ к нему - не наша забота.
- $output.=$modx->getChunk('DocText',['text'=>$doc->text]);
- $modx->setPlaceholder('doc', $output);
- return '';
- }
- return 'Ошибка...';//для нормального кода мы здесь вообще не должны оказаться, так что вернем хоть что-то для объяснения неполадки
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement