Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/include/txp_link.php - 721 lines - 24157 bytes - Summary - Text - Print

Description: Links panel.

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

title

Description

title

Description

title

Description

title

title

Body