Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/include/txp_link.php - 689 lines - 22474 bytes - Summary - Text - Print

Description: Links panel.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * http://textpattern.com
   6   *
   7   * Copyright (C) 2005 Dean Allen
   8   * Copyright (C) 2016 The Textpattern Development Team
   9   *
  10   * This file is part of Textpattern.
  11   *
  12   * Textpattern is free software; you can redistribute it and/or
  13   * modify it under the terms of the GNU General Public License
  14   * as published by the Free Software Foundation, version 2.
  15   *
  16   * Textpattern is distributed in the hope that it will be useful,
  17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19   * GNU General Public License for more details.
  20   *
  21   * You should have received a copy of the GNU General Public License
  22   * along with Textpattern. If not, see <http://www.gnu.org/licenses/>.
  23   */
  24  
  25  /**
  26   * Links panel.
  27   *
  28   * @package Admin\Link
  29   */
  30  
  31  use Textpattern\Validator\CategoryConstraint;
  32  use Textpattern\Validator\Validator;
  33  use Textpattern\Search\Filter;
  34  
  35  if (!defined('txpinterface')) {
  36      die('txpinterface is undefined.');
  37  }
  38  
  39  if ($event == 'link') {
  40      require_privs('link');
  41  
  42      global $vars;
  43      $vars = array('category', 'url', 'linkname', 'linksort', 'description', 'id');
  44  
  45      global $all_link_cats, $all_link_authors;
  46      $all_link_cats = getTree('root', 'link');
  47      $all_link_authors = the_privileged('link.edit.own');
  48  
  49      $available_steps = array(
  50          'link_list'          => false,
  51          'link_edit'          => false,
  52          'link_save'          => true,
  53          'link_change_pageby' => true,
  54          'link_multi_edit'    => true,
  55      );
  56  
  57      if ($step && bouncer($step, $available_steps)) {
  58          $step();
  59      } else {
  60          link_list();
  61      }
  62  }
  63  
  64  /**
  65   * The main panel listing all links.
  66   *
  67   * @param string|array $message The activity message
  68   */
  69  
  70  function link_list($message = '')
  71  {
  72      global $event, $step, $link_list_pageby, $txp_user;
  73  
  74      pagetop(gTxt('tab_link'), $message);
  75  
  76      extract(gpsa(array(
  77          'page',
  78          'sort',
  79          'dir',
  80          'crit',
  81          'search_method',
  82      )));
  83  
  84      if ($sort === '') {
  85          $sort = get_pref('link_sort_column', 'name');
  86      } else {
  87          if (!in_array($sort, array('id', 'description', 'url', 'category', 'date', 'author'))) {
  88              $sort = 'name';
  89          }
  90  
  91          set_pref('link_sort_column', $sort, 'link', 2, '', 0, PREF_PRIVATE);
  92      }
  93  
  94      if ($dir === '') {
  95          $dir = get_pref('link_sort_dir', 'asc');
  96      } else {
  97          $dir = ($dir == 'desc') ? "desc" : "asc";
  98          set_pref('link_sort_dir', $dir, 'link', 2, '', 0, PREF_PRIVATE);
  99      }
 100  
 101      switch ($sort) {
 102          case 'id':
 103              $sort_sql = "txp_link.id $dir";
 104              break;
 105          case 'description':
 106              $sort_sql = "txp_link.description $dir, txp_link.id ASC";
 107              break;
 108          case 'url':
 109              $sort_sql = "txp_link.url $dir, txp_link.id ASC";
 110              break;
 111          case 'category':
 112              $sort_sql = "txp_category.title $dir, txp_link.id ASC";
 113              break;
 114          case 'date':
 115              $sort_sql = "txp_link.date $dir, txp_link.id ASC";
 116              break;
 117          case 'author':
 118              $sort_sql = "txp_users.RealName $dir, txp_link.id ASC";
 119              break;
 120          default:
 121              $sort = 'name';
 122              $sort_sql = "txp_link.linksort $dir, txp_link.id ASC";
 123              break;
 124      }
 125  
 126      $switch_dir = ($dir == 'desc') ? 'asc' : 'desc';
 127  
 128      $search = new Filter($event,
 129          array(
 130              'id' => array(
 131                  'column' => 'txp_link.id',
 132                  'label'  => gTxt('ID'),
 133                  'type'   => 'integer',
 134              ),
 135              'name' => array(
 136                  'column' => 'txp_link.linkname',
 137                  'label'  => gTxt('link_name'),
 138              ),
 139              'url' => array(
 140                  'column' => 'txp_link.url',
 141                  'label'  => gTxt('url'),
 142              ),
 143              'description' => array(
 144                  'column' => 'txp_link.description',
 145                  'label'  => gTxt('description'),
 146              ),
 147              'category' => array(
 148                  'column' => array('txp_link.category', 'txp_category.title'),
 149                  'label'  => gTxt('link_category'),
 150              ),
 151              'author' => array(
 152                  'column' => array('txp_link.author', 'txp_users.RealName'),
 153                  'label'  => gTxt('author'),
 154              ),
 155              'linksort' => array(
 156                  'column' => 'txp_link.linksort',
 157                  'label'  => gTxt('sort_value'),
 158              ),
 159          )
 160      );
 161  
 162      list($criteria, $crit, $search_method) = $search->getFilter(array(
 163              'id' => array('can_list' => true),
 164          ));
 165  
 166      $search_render_options = array(
 167          'placeholder' => 'search_links',
 168      );
 169  
 170      $sql_from =
 171          safe_pfx_j('txp_link')."
 172          LEFT JOIN ".safe_pfx_j('txp_category')." ON txp_category.name = txp_link.category AND txp_category.type = 'link'
 173          LEFT JOIN ".safe_pfx_j('txp_users')." ON txp_users.name = txp_link.author";
 174  
 175      if ($criteria === 1) {
 176          $total = safe_count('txp_link', $criteria);
 177      } else {
 178          $total = getThing("SELECT COUNT(*) FROM $sql_from WHERE $criteria");
 179      }
 180  
 181      echo n.'<div class="txp-layout">'.
 182          n.tag(
 183              hed(gTxt('tab_link'), 1, array('class' => 'txp-heading')),
 184              'div', array('class' => 'txp-layout-4col-alt')
 185          );
 186  
 187      $searchBlock =
 188          n.tag(
 189              $search->renderForm('link_list', $search_render_options),
 190              'div', array(
 191                  'class' => 'txp-layout-4col-3span',
 192                  'id'    => $event.'_control',
 193              )
 194          );
 195  
 196      $createBlock = array();
 197  
 198      if (has_privs('link.edit')) {
 199          $createBlock[] =
 200              n.tag(
 201                  sLink('link', 'link_edit', gTxt('add_new_link'), 'txp-button'),
 202                  'div', array('class' => 'txp-control-panel')
 203              );
 204      }
 205  
 206      $contentBlockStart = n.tag_start('div', array(
 207              'class' => 'txp-layout-1col',
 208              'id'    => $event.'_container',
 209          ));
 210  
 211      $createBlock = implode(n, $createBlock);
 212  
 213      if ($total < 1) {
 214          if ($criteria != 1) {
 215              echo $searchBlock.
 216                  $contentBlockStart.
 217                  $createBlock.
 218                  graf(
 219                      span(null, array('class' => 'ui-icon ui-icon-info')).' '.
 220                      gTxt('no_results_found'),
 221                      array('class' => 'alert-block information')
 222                  );
 223          } else {
 224              echo $contentBlockStart.
 225                  $createBlock.
 226                  graf(
 227                      span(null, array('class' => 'ui-icon ui-icon-info')).' '.
 228                      gTxt('no_links_recorded'),
 229                      array('class' => 'alert-block information')
 230                  );
 231          }
 232  
 233          echo n.tag_end('div'). // End of .txp-layout-1col.
 234              n.'</div>'; // End of .txp-layout.;
 235  
 236          return;
 237      }
 238  
 239      $limit = max($link_list_pageby, 15);
 240  
 241      list($page, $offset, $numPages) = pager($total, $limit, $page);
 242  
 243      echo $searchBlock.$contentBlockStart.$createBlock;
 244  
 245      $rs = safe_query(
 246          "SELECT
 247              txp_link.id,
 248              UNIX_TIMESTAMP(txp_link.date) AS uDate,
 249              txp_link.category,
 250              txp_link.url,
 251              txp_link.linkname,
 252              txp_link.description,
 253              txp_link.author,
 254              txp_users.RealName AS realname,
 255              txp_category.Title AS category_title
 256          FROM $sql_from WHERE $criteria ORDER BY $sort_sql LIMIT $offset, $limit"
 257      );
 258  
 259      if ($rs && numRows($rs)) {
 260          $show_authors = !has_single_author('txp_link');
 261  
 262          echo n.tag(
 263                  toggle_box('links_detail'), 'div', array('class' => 'txp-list-options')).
 264              n.tag_start('form', array(
 265                  'class'  => 'multi_edit_form',
 266                  'id'     => 'links_form',
 267                  'name'   => 'longform',
 268                  'method' => 'post',
 269                  'action' => 'index.php',
 270              )).
 271              n.tag_start('div', array('class' => 'txp-listtables')).
 272              n.tag_start('table', array('class' => 'txp-list')).
 273              n.tag_start('thead').
 274              tr(
 275                  hCell(
 276                      fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'),
 277                          '', ' class="txp-list-col-multi-edit" scope="col" title="'.gTxt('toggle_all_selected').'"'
 278                  ).
 279                  column_head(
 280                      'ID', 'id', 'link', true, $switch_dir, $crit, $search_method,
 281                          (('id' == $sort) ? "$dir " : '').'txp-list-col-id'
 282                  ).
 283                  column_head(
 284                      'link_name', 'name', 'link', true, $switch_dir, $crit, $search_method,
 285                          (('name' == $sort) ? "$dir " : '').'txp-list-col-name'
 286                  ).
 287                  column_head(
 288                      'description', 'description', 'link', true, $switch_dir, $crit, $search_method,
 289                          (('description' == $sort) ? "$dir " : '').'txp-list-col-description links_detail'
 290                  ).
 291                  column_head(
 292                      'link_category', 'category', 'link', true, $switch_dir, $crit, $search_method,
 293                          (('category' == $sort) ? "$dir " : '').'txp-list-col-category category'
 294                  ).
 295                  column_head(
 296                      'url', 'url', 'link', true, $switch_dir, $crit, $search_method,
 297                          (('url' == $sort) ? "$dir " : '').'txp-list-col-url'
 298                  ).
 299                  column_head(
 300                      'date', 'date', 'link', true, $switch_dir, $crit, $search_method,
 301                          (('date' == $sort) ? "$dir " : '').'txp-list-col-created date links_detail'
 302                  ).
 303                  (
 304                      $show_authors
 305                      ? column_head('author', 'author', 'link', true, $switch_dir, $crit, $search_method,
 306                          (('author' == $sort) ? "$dir " : '').'txp-list-col-author name')
 307                      : ''
 308                  )
 309              ).
 310              n.tag_end('thead').
 311              n.tag_start('tbody');
 312  
 313          $validator = new Validator();
 314  
 315          while ($a = nextRow($rs)) {
 316              extract($a, EXTR_PREFIX_ALL, 'link');
 317  
 318              $edit_url = array(
 319                  'event'         => 'link',
 320                  'step'          => 'link_edit',
 321                  'id'            => $link_id,
 322                  'sort'          => $sort,
 323                  'dir'           => $dir,
 324                  'page'          => $page,
 325                  'search_method' => $search_method,
 326                  'crit'          => $crit,
 327              );
 328  
 329              $validator->setConstraints(array(new CategoryConstraint($link_category, array('type' => 'link'))));
 330              $vc = $validator->validate() ? '' : ' error';
 331  
 332              if ($link_category) {
 333                  $link_category = span(txpspecialchars($link_category_title), array('title' => $link_category));
 334              }
 335  
 336              $can_edit = has_privs('link.edit') || ($link_author === $txp_user && has_privs('link.edit.own'));
 337              $view_url = txpspecialchars($link_url);
 338  
 339              echo tr(
 340                  td(
 341                      fInput('checkbox', 'selected[]', $link_id), '', 'txp-list-col-multi-edit'
 342                  ).
 343                  hCell(
 344                      ($can_edit ? href($link_id, $edit_url, ' title="'.gTxt('edit').'"') : $link_id), '', ' class="txp-list-col-id" scope="row"'
 345                  ).
 346                  td(
 347                      ($can_edit ? href(txpspecialchars($link_linkname), $edit_url, ' title="'.gTxt('edit').'"') : txpspecialchars($link_linkname)), '', 'txp-list-col-name'
 348                  ).
 349                  td(
 350                      txpspecialchars($link_description), '', 'txp-list-col-description links_detail'
 351                  ).
 352                  td(
 353                      $link_category, '', 'txp-list-col-category category'.$vc
 354                  ).
 355                  td(
 356                      href($view_url, $view_url, ' rel="external" target="_blank"'), '', 'txp-list-col-url'
 357                  ).
 358                  td(
 359                      gTime($link_uDate), '', 'txp-list-col-created date links_detail'
 360                  ).
 361                  (
 362                      $show_authors
 363                      ? td(span(txpspecialchars($link_realname), array('title' => $link_author)), '', 'txp-list-col-author name')
 364                      : ''
 365                  )
 366              );
 367          }
 368  
 369          echo n.tag_end('tbody').
 370              n.tag_end('table').
 371              n.tag_end('div').
 372              link_multiedit_form($page, $sort, $dir, $crit, $search_method).
 373              tInput().
 374              n.tag_end('form').
 375  
 376              n.tag_start('div', array(
 377                  'class' => 'txp-navigation',
 378                  'id'    => $event.'_navigation',
 379              )).
 380              pageby_form('link', $link_list_pageby).
 381              nav_form('link', $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit).
 382              n.tag_end('div');
 383      }
 384  
 385      echo n.tag_end('div'). // End of .txp-layout-1col.
 386          n.'</div>'; // End of .txp-layout.
 387  }
 388  
 389  /**
 390   * Renders and outputs the link editor panel.
 391   *
 392   * @param string|array $message The activity message
 393   */
 394  
 395  function link_edit($message = '')
 396  {
 397      global $vars, $event, $step, $txp_user;
 398  
 399      pagetop(gTxt('tab_link'), $message);
 400  
 401      extract(array_map('assert_string', gpsa($vars)));
 402  
 403      $is_edit = ($id && $step == 'link_edit');
 404  
 405      $rs = array();
 406  
 407      if ($is_edit) {
 408          $id = assert_int($id);
 409          $rs = safe_row("*", 'txp_link', "id = $id");
 410  
 411          if ($rs) {
 412              extract($rs);
 413  
 414              if (!has_privs('link.edit') && !($author === $txp_user && has_privs('link.edit.own'))) {
 415                  link_list(gTxt('restricted_area'));
 416  
 417                  return;
 418              }
 419          }
 420      }
 421  
 422      if (has_privs('link.edit') || has_privs('link.edit.own')) {
 423          $caption = gTxt(($is_edit) ? 'edit_link' : 'add_new_link');
 424  
 425          echo form(
 426              hed($caption, 2).
 427              inputLabel(
 428                  'link_name',
 429                  fInput('text', 'linkname', $linkname, '', '', '', INPUT_REGULAR, '', 'link_name'),
 430                  'title', '', array('class' => 'txp-form-field edit-link-name')
 431              ).
 432              inputLabel(
 433                  'link_sort',
 434                  fInput('text', 'linksort', $linksort, 'input-medium', '', '', INPUT_MEDIUM, '', 'link_sort'),
 435                  'sort_value', 'link_sort', array('class' => 'txp-form-field edit-link-sort')
 436              ).
 437              // TODO: maybe use type="url" once browsers are less strict.
 438              inputLabel(
 439                  'link_url',
 440                  fInput('text', 'url', $url, '', '', '', INPUT_REGULAR, '', 'link_url'),
 441                  'url', 'link_url', array('class' => 'txp-form-field edit-link-url')
 442              ).
 443              inputLabel(
 444                  'link_category',
 445                  event_category_popup('link', $category, 'link_category').
 446                  n.eLink('category', 'list', '', '', gTxt('edit'), '', '', '', 'txp-option-link'),
 447                  'link_category', 'link_category', array('class' => 'txp-form-field edit-link-category')
 448              ).
 449              inputLabel(
 450                  'link_description',
 451                  '<textarea id="link_description" name="description" cols="'.INPUT_LARGE.'" rows="'.TEXTAREA_HEIGHT_SMALL.'">'.txpspecialchars($description).'</textarea>',
 452                  'description', 'link_description', array('class' => 'txp-form-field txp-form-field-textarea edit-link-description')
 453              ).
 454              pluggable_ui('link_ui', 'extend_detail_form', '', $rs).
 455              graf(
 456                  sLink('link', '', gTxt('cancel'), 'txp-button').
 457                  fInput('submit', '', gTxt('save'), 'publish'),
 458                  array('class' => 'txp-edit-actions')
 459              ).
 460              eInput('link').
 461              sInput('link_save').
 462              hInput('id', $id).
 463              hInput('search_method', gps('search_method')).
 464              hInput('crit', gps('crit')),
 465          '', '', 'post', 'txp-edit', '', 'link_details');
 466      }
 467  }
 468  
 469  /**
 470   * Legacy link category HTML select field.
 471   *
 472   * @param      string $cat
 473   * @return     string
 474   * @deprecated in 4.6.0
 475   */
 476  
 477  function linkcategory_popup($cat = '')
 478  {
 479      return event_category_popup('link', $cat, 'link_category');
 480  }
 481  
 482  // -------------------------------------------------------------
 483  
 484  function link_save()
 485  {
 486      global $vars, $txp_user;
 487  
 488      $varray = array_map('assert_string', gpsa($vars));
 489      extract(doSlash($varray));
 490  
 491      if ($id) {
 492          $id = $varray['id'] = assert_int($id);
 493      }
 494  
 495      if ($linkname === '' && $url === '' && $description === '') {
 496          link_list(array(gTxt('link_empty'), E_ERROR));
 497  
 498          return;
 499      }
 500  
 501      $author = fetch('author', 'txp_link', 'id', $id);
 502      if (!has_privs('link.edit') && !($author === $txp_user && has_privs('link.edit.own'))) {
 503          link_list(gTxt('restricted_area'));
 504  
 505          return;
 506      }
 507  
 508      if (!$linksort) {
 509          $linksort = $linkname;
 510      }
 511  
 512      $constraints = array(
 513          'category' => new CategoryConstraint($varray['category'], array('type' => 'link')),
 514      );
 515  
 516      callback_event_ref('link_ui', 'validate_save', 0, $varray, $constraints);
 517      $validator = new Validator($constraints);
 518  
 519      if ($validator->validate()) {
 520          if ($id) {
 521              $ok = safe_update('txp_link',
 522                  "category   = '$category',
 523                  url         = '".trim($url)."',
 524                  linkname    = '$linkname',
 525                  linksort    = '$linksort',
 526                  description = '$description',
 527                  author      = '".doSlash($txp_user)."'",
 528                  "id = $id"
 529              );
 530          } else {
 531              $ok = safe_insert('txp_link',
 532                  "category   = '$category',
 533                  date        = NOW(),
 534                  url         = '".trim($url)."',
 535                  linkname    = '$linkname',
 536                  linksort    = '$linksort',
 537                  description = '$description',
 538                  author      = '".doSlash($txp_user)."'"
 539              );
 540              if ($ok) {
 541                  $GLOBALS['ID'] = $_POST['id'] = $ok;
 542              }
 543          }
 544  
 545          if ($ok) {
 546              // update lastmod due to link feeds
 547              update_lastmod('link_saved', compact('id', 'linkname', 'linksort', 'url', 'category', 'description'));
 548              $message = gTxt(($id ? 'link_updated' : 'link_created'), array('{name}' => doStrip($linkname)));
 549          } else {
 550              $message = array(gTxt('link_save_failed'), E_ERROR);
 551          }
 552      } else {
 553          $message = array(gTxt('link_save_failed'), E_ERROR);
 554      }
 555  
 556      link_list($message);
 557  }
 558  
 559  // -------------------------------------------------------------
 560  
 561  function link_change_pageby()
 562  {
 563      event_change_pageby('link');
 564      link_list();
 565  }
 566  
 567  // -------------------------------------------------------------
 568  
 569  function link_multiedit_form($page, $sort, $dir, $crit, $search_method)
 570  {
 571      global $all_link_cats, $all_link_authors;
 572  
 573      $categories = $all_link_cats ? treeSelectInput('category', $all_link_cats, '') : '';
 574      $authors = $all_link_authors ? selectInput('author', $all_link_authors, '', true) : '';
 575  
 576      $methods = array(
 577          'changecategory' => array('label' => gTxt('changecategory'), 'html' => $categories),
 578          'changeauthor'   => array('label' => gTxt('changeauthor'), 'html' => $authors),
 579          'delete'         => gTxt('delete'),
 580      );
 581  
 582      if (!$categories) {
 583          unset($methods['changecategory']);
 584      }
 585  
 586      if (has_single_author('txp_link') || !has_privs('link.edit')) {
 587          unset($methods['changeauthor']);
 588      }
 589  
 590      if (!has_privs('link.delete.own') && !has_privs('link.delete')) {
 591          unset($methods['delete']);
 592      }
 593  
 594      return multi_edit($methods, 'link', 'link_multi_edit', $page, $sort, $dir, $crit, $search_method);
 595  }
 596  
 597  // -------------------------------------------------------------
 598  
 599  function link_multi_edit()
 600  {
 601      global $txp_user, $all_link_cats, $all_link_authors;
 602  
 603      // Empty entry to permit clearing the category
 604      $categories = array('');
 605  
 606      foreach ($all_link_cats as $row) {
 607          $categories[] = $row['name'];
 608      }
 609  
 610      $selected = ps('selected');
 611  
 612      if (!$selected or !is_array($selected)) {
 613          link_list();
 614  
 615          return;
 616      }
 617  
 618      $selected = array_map('assert_int', $selected);
 619      $method = ps('edit_method');
 620      $changed = array();
 621      $key = '';
 622  
 623      switch ($method) {
 624          case 'delete' :
 625              if (!has_privs('link.delete')) {
 626                  if (has_privs('link.delete.own')) {
 627                      $selected = safe_column("id", 'txp_link', "id IN (".join(',', $selected).") AND author = '".doSlash($txp_user)."'");
 628                  } else {
 629                      $selected = array();
 630                  }
 631              }
 632              foreach ($selected as $id) {
 633                  if (safe_delete('txp_link', "id = $id")) {
 634                      $changed[] = $id;
 635                  }
 636              }
 637  
 638              if ($changed) {
 639                  callback_event('links_deleted', '', 0, $changed);
 640              }
 641  
 642              $key = '';
 643              break;
 644          case 'changecategory':
 645              $val = ps('category');
 646              if (in_array($val, $categories)) {
 647                  $key = 'category';
 648              }
 649              break;
 650          case 'changeauthor':
 651              $val = ps('author');
 652              if (has_privs('link.edit') && in_array($val, $all_link_authors)) {
 653                  $key = 'author';
 654              }
 655              break;
 656          default:
 657              $key = '';
 658              $val = '';
 659              break;
 660      }
 661  
 662      if (!has_privs('link.edit')) {
 663          if (has_privs('link.edit.own')) {
 664              $selected = safe_column("id", 'txp_link', "id IN (".join(',', $selected).") AND author = '".doSlash($txp_user)."'");
 665          } else {
 666              $selected = array();
 667          }
 668      }
 669  
 670      if ($selected and $key) {
 671          foreach ($selected as $id) {
 672              if (safe_update('txp_link', "$key = '".doSlash($val)."'", "id = $id")) {
 673                  $changed[] = $id;
 674              }
 675          }
 676      }
 677  
 678      if ($changed) {
 679          update_lastmod('link_updated', $changed);
 680  
 681          link_list(gTxt(
 682              ($method == 'delete' ? 'links_deleted' : 'link_updated'),
 683              array(($method == 'delete' ? '{list}' : '{name}') => join(', ', $changed))));
 684  
 685          return;
 686      }
 687  
 688      link_list();
 689  }

title

Description

title

Description

title

Description

title

title

Body