Напишем поле для смены автора записи прямо из списка или из записи

+21
1.04K
Напишем поле для смены автора записи прямо из списка или из записи

Поле, с помощью которого админ сможет менять автора записи ТК прямо из списка записей или из самой записи. Кроме поля напишем еще небольшой компонент, в котором будут храниться экшены для обработки аякс-запросов. Здесь не будет поиска пользователей по никнейму или почте. Для смены автора нужно знать и ввести id нового автора.

Изображение

Начнем с поля.

Как и другие поля, наше поле будет состоять из двух обязательных файлов, а также из файла стилей и файла скриптов. Создадим их.

  • system/fields/changeuserid.php
  • templates/default/assets/fields/changeuserid.tpl.php
  • templates/default/css/fields/changeuserid.css
  • templates/default/js/fields/changeuserid.js

Если вы вдруг обнаружили, что у вас нет папки fields в папках css и js, то создайте.

Файл templates/default/assets/fields/changeuserid.tpl.php будет пустым, создали и закройте.

В файл system/fields/changeuserid.php добавим такой код (описание в комментариях прямо в коде):

  1. <?php class fieldChangeuserid extends cmsFormField{
  2.  
  3. public $title = 'Смена user_id записи';
  4. public $sql = '';
  5. public $is_virtual = true;
  6. public $allow_index = false;
  7.  
  8. public function parse($value) {
  9. // если пользователь не админ - поле не выводим
  10. if (!cmsUser::get('is_admin')) { return ''; }
  11.  
  12. $id = $this->item['id']; // id записи
  13. $user = cmsCore::getModel('users')->getUser($this->item['user_id']); // ищем автора записи среди всех пользователей
  14. // по-умолчанию будем считать, что пользователя нет
  15. // например, если вы его случайно удалили каким-то образом, не через админку
  16. $avatar = ''; // нет аватара
  17. $nickname = 'Пользователь удален'; // нет никнейма
  18. $not_avatar = ' not_avatar'; // это класс для кнопки
  19. // если пользователь есть
  20. if ($user) {
  21. // получаем аватар
  22. // выводим загруженный аватар, заглушку или буквенный аватар
  23. $avatar = $user['avatar'] || !function_exists('html_avatar_image_empty') ? html_avatar_image($user['avatar'], 'micro', $user['nickname']) : html_avatar_image_empty($user['nickname'], 'avatar__mini');
  24. $nickname = $user['nickname']; // никнейм
  25. $not_avatar = ''; // удаляем класс not_avatar
  26. }
  27.  
  28. // подключаем к шаблону файлы стилей и скриптов
  29. cmsTemplate::getInstance()->addCSS('templates/default/css/fields/changeuserid.css');
  30. cmsTemplate::getInstance()->addJS('templates/default/js/fields/changeuserid.js');
  31.  
  32. // кнопка для начала смены автора
  33. // вешаем на нее событие onclick, вызывающее js-функцию changeuserid_start,
  34. // в которую мы передадим id записи, id текущего автора и имя типа контента
  35. $change_btn = '<div class="changeuserid_btn changeuserid_btn_'.$id.'" onclick="changeuserid_start('.$id.', '.$this->item['user_id'].', \''.$this->item['ctype_name'].'\')">&#8634;</div>';
  36.  
  37. // выводим результат
  38. // это блок с классом changeuserid_user_123 (123 - это id записи)
  39. // внутри ссылка на пользователя с аватаром и никнеймом
  40. return '<div class="changeuserid_user'.$not_avatar.' changeuserid_user_'.$id.'"><a href="'.href_to('users', $this->item['user_id']).'" target="_blank">'.$avatar.$nickname.'</a>'.$change_btn.'</div>';
  41.  
  42. }
  43.  
  44. }

Сразу добавим стили, чтобы больше к ним не возвращать. Думаю, пояснять css смысла нет. В файл templates/default/css/fields/changeuserid.css пишем код, сохраняем и закрываем:

  1. .changeuserid_user a{
  2. display:inline-block;
  3. vertical-align:top;
  4. border-radius:3px;
  5. background:#eee;
  6. color:#333;
  7. text-decoration:none!important;
  8. position:relative;
  9. padding:0 10px 0 42px;
  10. line-height:32px;
  11. overflow:hidden;
  12. transition:allease .15s;
  13. }
  14. .changeuserid_user.not_avatar a{
  15. padding:0 10px;
  16. }
  17. .changeuserid_user a:hover{
  18. background:#ddd;
  19. color:#000;
  20. }
  21. .changeuserid_user .icms-profile-avatar__default,
  22. .changeuserid_user img{
  23. position:absolute;
  24. top:0;
  25. left:0;
  26. }
  27. .changeuserid_btn{
  28. display:inline-block;
  29. vertical-align:top;
  30. width:32px;
  31. height:32px;
  32. text-align:center;
  33. line-height:32px;
  34. border-radius:3px;
  35. background:#888;
  36. color:#f5f5f5;
  37. font-size:18px;
  38. transition:all ease .15s;
  39. margin-left:5px;
  40. cursor:pointer;
  41. opacity:.8;
  42. }
  43. .changeuserid_btn_yes{
  44. background:#a6d38f;
  45. font-size:16px;
  46. }
  47. .changeuserid_btn_no{
  48. background:#f16868;
  49. font-size:16px;
  50. }
  51. .changeuserid_btn:hover{
  52. opacity:1;
  53. }
  54. .changeuserid_input{
  55. height:32px;
  56. width:80px;
  57. padding:0 10px;
  58. display:inline-block;
  59. }

В файле system/fields/changeuserid.php, если присмотреться, у нас есть js-событие onclick, вызывающее функцию changeuserid_start. Добавим ее в файл templates/default/js/fields/changeuserid.js

  1. function changeuserid_start(id, user_id, ctype_name){
  2. /* удаляем кнопку */
  3. $('.changeuserid_btn_' + id).remove();
  4.  
  5. /* отправляем запрос экшену start с id записи, юзера и именем типа контента */
  6. $.post('/changeuserid/start/' + id + '/' + user_id + '/' + ctype_name).done(function(response) {
  7. result = $.parseJSON(response);
  8. /* если вернулась ошибка, то перезагрузка страницы */
  9. if (result.action === 'error') {
  10. window.location.reload();
  11. } else {
  12. /* если нормально всё, то вместо ссылки на текущего автора покажем форму */
  13. $('.changeuserid_user_' + id).html(result.form);
  14. }
  15. });
  16. }

Здесь мы обращаемся к экшену start компонента changeuserid. Но у нас его еще нет. Поэтому создаем папку system/controllers/changeuserid, в ней файл frontend.php с таким содержимым:

  1. <?php class changeuserid extends cmsFrontend {}

Сохраняем и закрываем. Теперь в этой же папке создаем папку actions, а в ней файл start.php:

  1. <?php class actionChangeuseridStart extends cmsAction{
  2.  
  3. // сюда мы передали id записи, id текущего автора и имя типа контента
  4. public function run($id, $user_id, $ctype_name){
  5. // возвращать будем массив $result с данными
  6. // по-умолчанию, пока не будут пройдены проверки,
  7. // мы возвращаем ошибку
  8. $result['action'] = 'error';
  9. // убираем из имени типа контента всё лишнее, мало ли кто это балуется
  10. $ctype_name = preg_replace('/[^\w]/', '', $ctype_name);
  11.  
  12. // если кнопки нажимает не админ или если id записи и автора не числа, то возвращаем ошибку
  13. if (!cmsUser::get('is_admin') || !is_numeric($id) || !is_numeric($user_id)) {
  14. return $this->cms_template->renderJSON($result);
  15. }
  16. // меняем $result['action'] на ok
  17. $result['action'] = 'ok';
  18. // сформируем форму для ввода нового id пользователя
  19. // с кнопками подтверждения и отмены
  20.  
  21. // кнопка подтверждения, вешаем на нее событие onclick, вызывающее js-функцию changeuserid_change,
  22. // в которую передадим id записи и имя ТК
  23. $btn_yes = '<div class="changeuserid_btn changeuserid_btn_yes" onclick="changeuserid_change('.$id.', \''.$ctype_name.'\')">&#10004;</div>';
  24. // кнопка отмены, вешаем на нее событие onclick, вызывающее js-функцию changeuserid_cancel,
  25. // в которую передадим id записи
  26. $btn_no = '<div class="changeuserid_btn changeuserid_btn_no" onclick="changeuserid_cancel('.$id.')">&#10006;</div>';
  27. // поле типа "число"
  28. $input = html_input('number', 'changeuserid', $user_id, ['class' => 'changeuserid_input changeuserid_input_'.$id]);
  29. // вся наша форма, состоит из поля и двух кнопок
  30. $result['form'] = $input.$btn_yes.$btn_no;
  31.  
  32. // возвращаемся назад с нашей формой
  33. return $this->cms_template->renderJSON($result);
  34. }
  35. }

Здесь, как видно, еще две js-функции — changeuserid_change и changeuserid_cancel. Добавим их в наш js-файл:

  1. function changeuserid_start(id, user_id, ctype_name){
  2. /* удаляем кнопку */
  3. $('.changeuserid_btn_' + id).remove();
  4.  
  5. /* отправляем запрос экшену start с id записи, юзера и именем типа контента */
  6. $.post('/changeuserid/start/' + id + '/' + user_id + '/' + ctype_name).done(function(response) {
  7. result = $.parseJSON(response);
  8. /* если вернулась ошибка, то перезагрузка страницы */
  9. if (result.action === 'error') {
  10. window.location.reload();
  11. } else {
  12. /* если нормально всё, то вместо ссылки на текущего автора покажем форму */
  13. $('.changeuserid_user_' + id).html(result.form);
  14. }
  15. });
  16. }
  17. function changeuserid_change(id, ctype_name){
  18. /* скрываем кнопки */
  19. $('.changeuserid_user_' + id + ' .changeuserid_btn').hide();
  20. /* получаем id нового автора из поля */
  21. var user_id = $('.changeuserid_input_' + id).val();
  22. /* отправляем запрос экшену change с id записи, юзера и именем типа контента */
  23. $.post('/changeuserid/change/' + id + '/' + user_id + '/' + ctype_name).done(function(response) {
  24. result = $.parseJSON(response);
  25. /* если ошибка, то перезагружаем страницу */
  26. if (result.action === 'error') {
  27. window.location.reload();
  28. }
  29. /* если пользователь не найден */
  30. if (result.action === 'user_not_found') {
  31. /* показываем сообщение */
  32. alert(result.mess);
  33. /* возвращаем кнопки */
  34. $('.changeuserid_user_' + id + ' .changeuserid_btn').show();
  35. }
  36. /* если всё хорошо, то обновляем поле в этой записи */
  37. if (result.action === 'ok'){
  38. changeuseridUpd('.changeuserid_user_' + id);
  39. }
  40. });
  41. }
  42. function changeuserid_cancel(id) {
  43. /* обновляем поле в этой записи */
  44. changeuseridUpd('.changeuserid_user_' + id);
  45. }
  46. async function changeuseridUpd(elem) {
  47. try{
  48. var html = await(await fetch(location.href)).text();
  49. var newdoc = new DOMParser().parseFromString(html, 'text/html');
  50. document.querySelector(elem).outerHTML = newdoc.querySelector(elem).outerHTML;
  51. } catch (err) {
  52. $(elem).remove();
  53. }
  54. return true;
  55. }

Здесь же добавили еще одну функцию — changeuseridUpd. Эта функция для обновления элемента на странице.

Как видно в коде, если админ введет id нового автора и нажмет на кнопку с подтверждения, то мы обратимся еще к одному экшену — change. Поэтому добавим еще один файл в папке system/controllers/changeuserid/actions — change.php с таким кодом:

  1. <?php class actionChangeuseridChange extends cmsAction{
  2.  
  3. // сюда мы передали id записи, id нового автора и имя типа контента
  4. public function run($id, $user_id, $ctype_name){
  5. // возвращать будем массив $result с данными
  6. // по-умолчанию, пока не будут пройдены проверки,
  7. // мы возвращаем ошибку
  8. $result['action'] = 'error';
  9. // если кнопки нажимает не админ или если id записи и автора не числа, то возвращаем ошибку
  10. if (!cmsUser::get('is_admin') || !is_numeric($id) || !is_numeric($user_id)) {
  11. return $this->cms_template->renderJSON($result);
  12. }
  13. // убираем из имени типа контента всё лишнее, мало ли кто это балуется
  14. $ctype_name = preg_replace('/[^\w]/', '', $ctype_name);
  15. // получаем модель контента
  16. $content_model = cmsCore::getModel('content');
  17. // ищем тип контента по имени
  18. $ctype = $content_model->getContentTypeByName($ctype_name);
  19. // если не находим, то возвращаем ошибку
  20. if (!$ctype) {
  21. return $this->cms_template->renderJSON($result);
  22. }
  23. // ищем пользователя с помощью модели пользователей
  24. $user = cmsCore::getModel('users')->getUser($user_id);
  25. // если нет пользователя с таким id, то формируем сообщение об ошибке и возвращаемся
  26. if (!$user) {
  27. $result['action'] = 'user_not_found';
  28. $result['mess'] = 'Пользователь не найден!';
  29. return $this->cms_template->renderJSON($result);
  30. }
  31. // если всё нормально, то обновляем пользователя у записи
  32. $content_model->update('con_'.$ctype_name, $id, ['user_id' => $user_id]);
  33. $result['action'] = 'ok';
  34. // и возвращаемся
  35. return $this->cms_template->renderJSON($result);
  36. }
  37.  
  38. }

Вот и всё. Чтобы использовать на сайте, добавьте поле в типе контента.

Еще раз, какие должны быть файлы:

  • system/controllers/changeuserid/frontend.php
  • system/controllers/changeuserid/actions/start.php
  • system/controllers/changeuserid/actions/change.php
  • system/fields/changeuserid.php
  • templates/default/assets/fields/changeuserid.tpl.php
  • templates/default/css/fields/changeuserid.css
  • templates/default/js/fields/changeuserid.js

Если было лень читать:

0
Zau4man Zau4man 10 месяцев назад #

Имхо, стоит доработать поле, чтобы выбирать по комбинации ник|емайл

+1
&$!#% &$!#% 10 месяцев назад #

Я не против. Можете дорабатывать.

0
Def Def 10 месяцев назад #

круто!)

0
Loadырь Loadырь 10 месяцев назад #

Не очень. Любой гость может менять у любой записи автора на любого из существующих в базе даных. Так как ссылка ваш_site.site/changeuserid/change/тут_id_нужной_записи/тут_id_любого_пользователя/тут_системное_имя_типа_контента с передачей параметров без проверки вводимых данных, как минимум выдаст смену авторства у указанной записи в указанном типе контента на некоего Васю Пупкина. Ну, а если сменить автора записи на себя, то в последствии можно редактировать ее как душе угодно. В обшем надо доработать.

+1
&$!#% &$!#% 10 месяцев назад #

А для чего по-вашему проверка на админа в начале каждого экшена?

nifigasse.ru/changeuserid/change/16/1/board

0
Loadырь Loadырь 10 месяцев назад #

А точно, админа, то я и не заметил. Извините, за «наезд». Обычно ещё вешают проверку csrf_token на подобные экшены, чтобы исключить неконтролируемые запросы, его у вас я и не заметил. Но и так сойдёт )).

0
Happy Happy 10 месяцев назад #

Была бы идеальным возможность  дать права нескольким людям . 

0
Саня Саня 10 месяцев назад #

Круто. Спасибо за то что делитесь такой информацией настолько подробно. 

+7
&$!#% &$!#% 10 месяцев назад #

Обновил. Расписывать нет времени, простите:

  1. Изменен способ отправки запросов в экшены.
  2. Добавлен поиск пользователей по id, email и никнейму.
  3. Добавлена опция для предоставления доступа к полю другим пользователям.

Изображение

instantcms.ru/addons/changeuserid/view-addons-versions

На 2.16 не проверял, но должно работать.

0
CEH9I CEH9I 10 месяцев назад #

А возможно это поле заставить работать из админки при массовом редактировании записей? К примеру я хочу 100 записей передать другому человеку, каждому вручную заколебешься изменять авторство))

+1
SEOrigin SEOrigin 9 месяцев назад #

В админке такая опция есть по умолчанию. Выделите все записи, в верхнем меню кликните на пункт «Записи», затем «Изменить», там выберите поле «Автор», укажите ID автора и нажмите сохранить. 

0
Pascal Pascal 9 месяцев назад #

Нет там возможности менять поле «Автор».

0
Гарри Гарри 8 месяцев назад #

Сейчас проверил и всё там есть. 

0
CEH9I CEH9I 8 месяцев назад #

Да есть

+5
&$!#% &$!#% 10 месяцев назад #

v.1.0.2 — добавлена возможность отправлять уведомления новым авторам.

Изображение

instantcms.ru/addons/changeuserid/view-addons-versions

0
Pisces Pisces 10 месяцев назад #

Нифигасее… ❤🌹🌸🌷💐

0
Сергей Сергей 10 месяцев назад #

Читаю ваши посты с большим удовольствием, познавательно и разработки нужные, давно причём. Первый раз, возник маленький конфликт с установкой вашего поля, думаю не дружит оно со вкладками Александра DWD. 

Notice: Undefined index: user_ap in /public_html/templates/default/content/rent_item.tpl.php on line 41                               и так тоже:    Notice: Undefined index: user_ap in /  /public_html/templates/modern/content/rent_item.tpl.php on line 41  как бы ваше поле подружить со вкладками Александра? Буду очень признателен.

В типах контента где файлы DWD не используются, всё нормально работает.

+2
&$!#% &$!#% 10 месяцев назад #

Удалите поле из типа контента. После этого откройте файл system/fileds/changeuserid.php/

  1. public $sql = '';

замените на 

  1. public $sql = 'INT(1) NULL DEFAULT 1';

удалите строку:

  1. public $is_virtual = true;

и перед этой строкой

  1. public function parse($value) {

добавьте

  1. public function store($value, $is_submitted, $old_value = null) { return 1; }

Добавьте заново поле в тип контента.

0
Сергей Сергей 10 месяцев назад #

Всё случилось, как надо, заработало во вкладках без проблем. Благодарю за помощь, очень мужное поле.

0
Pascal Pascal 9 месяцев назад #

При создании поля ошибка 503 (на 2.13.1).

Ошибка в запросе БД: 

У вас ошибка в синтаксисе SQL возле '' в строке 1

ALTER TABLE cms_con_news ADD `userid`
Последние вызовы:

 modelContent->addContentField() @ /system/controllers/admin/actions/ctypes_fields_add.php: 50
 actionAdminCtypesFieldsAdd->run() @ /system/core/controller.php: 585
 cmsController->runExternalAction() @ /system/core/action.php: 37
 cmsAction->__call() @ /system/controllers/admin/actions/ctypes.php: 11
 actionAdminCtypes->run() @ /system/core/controller.php: 585
 cmsController->runExternalAction() @ /system/core/controller.php: 456
 cmsController->executeAction() @ /system/core/controller.php: 432
 cmsController->runAction() @ /system/core/core.php: 786
 cmsCore->runController() @ /index.php: 46

+1
&$!#% &$!#% 9 месяцев назад #

Тогда, видимо, не работали виртуальные поля. Установите версию 1.0.3: instantcms.ru/addons/changeuserid/view-addons-versions

0
Pascal Pascal 9 месяцев назад #

Спасибо, теперь создаётся поле.

Еще от автора

Складчина на платные дополнения. Дубль 2
Понимаю, что я всем уже надоел со своими акциями/складчинами. Последняя попытка, простите.
Google Indexing, v. 1.1.1
Добавлен собственный API для автоматического добавления ссылок в очередь при публикации новых материалов на других ваших сайтах. И другое по мелочи.
Обновление компонента "UpJump - продвижение записей в списках"
Обнаружены и исправлены ошибки. Обновление бесплатное.
Используя этот сайт, вы соглашаетесь с тем, что мы используем файлы cookie.