| Textpattern | PHP Cross Reference | Content Management Systems |
1 <?php 2 /* 3 This is Textpattern 4 Copyright 2005 by Dean Allen 5 All rights reserved. 6 7 Use of this software indicates acceptance of the Textpattern license agreement 8 9 $HeadURL: https://textpattern.googlecode.com/svn/releases/4.5.4/source/textpattern/include/txp_list.php $ 10 $LastChangedRevision: 4089 $ 11 12 */ 13 14 if (!defined('txpinterface')) die('txpinterface is undefined.'); 15 16 if ($event == 'list') { 17 global $statuses, $all_cats, $all_authors, $all_sections; 18 19 require_privs('article'); 20 21 $statuses = array( 22 STATUS_DRAFT => gTxt('draft'), 23 STATUS_HIDDEN => gTxt('hidden'), 24 STATUS_PENDING => gTxt('pending'), 25 STATUS_LIVE => gTxt('live'), 26 STATUS_STICKY => gTxt('sticky'), 27 ); 28 29 $all_cats = getTree('root', 'article'); 30 $all_authors = the_privileged('article.edit.own'); 31 $all_sections = safe_column('name', 'txp_section', "name != 'default'"); 32 33 $available_steps = array( 34 'list_list' => false, 35 'list_change_pageby' => true, 36 'list_multi_edit' => true, 37 ); 38 39 if ($step && bouncer($step, $available_steps)) { 40 $step(); 41 } else { 42 list_list(); 43 } 44 } 45 46 //-------------------------------------------------------------- 47 48 function list_list($message = '', $post = '') 49 { 50 global $statuses, $comments_disabled_after, $step, $txp_user, $article_list_pageby, $event; 51 52 pagetop(gTxt('tab_list'), $message); 53 54 extract(gpsa(array('page', 'sort', 'dir', 'crit', 'search_method'))); 55 if ($sort === '') $sort = get_pref('article_sort_column', 'posted'); 56 if ($dir === '') $dir = get_pref('article_sort_dir', 'desc'); 57 $dir = ($dir == 'asc') ? 'asc' : 'desc'; 58 59 $sesutats = array_flip($statuses); 60 61 switch ($sort) 62 { 63 case 'id': 64 $sort_sql = 'ID '.$dir; 65 break; 66 67 case 'title': 68 $sort_sql = 'Title '.$dir.', Posted desc'; 69 break; 70 71 case 'expires': 72 $sort_sql = 'Expires '.$dir; 73 break; 74 75 case 'section': 76 $sort_sql = 'Section '.$dir.', Posted desc'; 77 break; 78 79 case 'category1': 80 $sort_sql = 'Category1 '.$dir.', Posted desc'; 81 break; 82 83 case 'category2': 84 $sort_sql = 'Category2 '.$dir.', Posted desc'; 85 break; 86 87 case 'status': 88 $sort_sql = 'Status '.$dir.', Posted desc'; 89 break; 90 91 case 'author': 92 $sort_sql = 'AuthorID '.$dir.', Posted desc'; 93 break; 94 95 case 'comments': 96 $sort_sql = 'comments_count '.$dir.', Posted desc'; 97 break; 98 99 case 'lastmod': 100 $sort_sql = 'LastMod '.$dir.', Posted desc'; 101 break; 102 103 default: 104 $sort = 'posted'; 105 $sort_sql = 'Posted '.$dir; 106 break; 107 } 108 109 set_pref('article_sort_column', $sort, 'list', 2, '', 0, PREF_PRIVATE); 110 set_pref('article_sort_dir', $dir, 'list', 2, '', 0, PREF_PRIVATE); 111 112 $switch_dir = ($dir == 'desc') ? 'asc' : 'desc'; 113 114 $criteria = 1; 115 116 if ($search_method and $crit != '') 117 { 118 $verbatim = preg_match('/^"(.*)"$/', $crit, $m); 119 $crit_escaped = doSlash($verbatim ? $m[1] : str_replace(array('\\','%','_','\''), array('\\\\','\\%','\\_', '\\\''), $crit)); 120 $critsql = $verbatim ? 121 array( 122 'id' => "ID in ('" .join("','", do_list($crit_escaped)). "')", 123 'title_body_excerpt' => "Title = '$crit_escaped' or Body = '$crit_escaped' or Excerpt = '$crit_escaped'", 124 'section' => "Section = '$crit_escaped'", 125 'keywords' => "FIND_IN_SET('".$crit_escaped."',Keywords)", 126 'categories' => "Category1 = '$crit_escaped' or Category2 = '$crit_escaped'", 127 'status' => "Status = '".(@$sesutats[gTxt($crit_escaped)])."'", 128 'author' => "AuthorID = '$crit_escaped'", 129 'article_image' => "Image in ('" .join("','", do_list($crit_escaped)). "')", 130 'posted' => "Posted = '$crit_escaped'", 131 'lastmod' => "LastMod = '$crit_escaped'" 132 ) : array( 133 'id' => "ID in ('" .join("','", do_list($crit_escaped)). "')", 134 'title_body_excerpt' => "Title like '%$crit_escaped%' or Body like '%$crit_escaped%' or Excerpt like '%$crit_escaped%'", 135 'section' => "Section like '%$crit_escaped%'", 136 'keywords' => "FIND_IN_SET('".$crit_escaped."',Keywords)", 137 'categories' => "Category1 like '%$crit_escaped%' or Category2 like '%$crit_escaped%'", 138 'status' => "Status = '".(@$sesutats[gTxt($crit_escaped)])."'", 139 'author' => "AuthorID like '%$crit_escaped%'", 140 'article_image' => "Image in ('" .join("','", do_list($crit_escaped)). "')", 141 'posted' => "Posted like '$crit_escaped%'", 142 'lastmod' => "LastMod like '$crit_escaped%'" 143 ); 144 145 if (array_key_exists($search_method, $critsql)) 146 { 147 $criteria = $critsql[$search_method]; 148 $limit = 500; 149 } 150 151 else 152 { 153 $search_method = ''; 154 $crit = ''; 155 } 156 } 157 158 else 159 { 160 $search_method = ''; 161 $crit = ''; 162 } 163 164 $criteria .= callback_event('admin_criteria', 'list_list', 0, $criteria); 165 166 $total = safe_count('textpattern', "$criteria"); 167 168 echo '<h1 class="txp-heading">'.gTxt('tab_list').'</h1>'; 169 echo '<div id="'.$event.'_control" class="txp-control-panel">'; 170 171 if ($total < 1) 172 { 173 if ($criteria != 1) 174 { 175 echo n.list_search_form($crit, $search_method). 176 n.graf(gTxt('no_results_found'), ' class="indicator"').'</div>'; 177 } 178 179 else 180 { 181 echo graf(gTxt('no_articles_recorded'), ' class="indicator"').'</div>'; 182 } 183 184 return; 185 } 186 187 $limit = max($article_list_pageby, 15); 188 189 list($page, $offset, $numPages) = pager($total, $limit, $page); 190 191 echo n.list_search_form($crit, $search_method).'</div>'; 192 193 $rs = safe_rows_start('*, unix_timestamp(Posted) as posted, unix_timestamp(LastMod) as lastmod, unix_timestamp(Expires) as expires', 'textpattern', 194 "$criteria order by $sort_sql limit $offset, $limit" 195 ); 196 197 if ($rs) 198 { 199 $show_authors = !has_single_author('textpattern', 'AuthorID'); 200 201 $total_comments = array(); 202 203 // fetch true comment count, not the public comment count 204 // maybe we should have another row in the db? 205 $rs2 = safe_rows_start('parentid, count(*) as num', 'txp_discuss', "1 group by parentid order by parentid"); 206 207 if ($rs2) 208 { 209 while ($a = nextRow($rs2)) 210 { 211 $pid = $a['parentid']; 212 $num = $a['num']; 213 214 $total_comments[$pid] = $num; 215 } 216 } 217 218 echo n.'<div id="'.$event.'_container" class="txp-container">'; 219 echo n.n.'<form name="longform" id="articles_form" class="multi_edit_form" method="post" action="index.php">'. 220 221 n.'<div class="txp-listtables">'. 222 n.startTable('', '', 'txp-list'). 223 n.'<thead>'. 224 n.tr( 225 n.hCell(fInput('checkbox', 'select_all', 0, '', '', '', '', '', 'select_all'), '', ' title="'.gTxt('toggle_all_selected').'" class="multi-edit"'). 226 n.column_head('ID', 'id', 'list', true, $switch_dir, $crit, $search_method, (('id' == $sort) ? "$dir " : '').'id actions'). 227 column_head('title', 'title', 'list', true, $switch_dir, $crit, $search_method, (('title' == $sort) ? "$dir " : '').'title'). 228 column_head('posted', 'posted', 'list', true, $switch_dir, $crit, $search_method, (('posted' == $sort) ? "$dir " : '').'date posted created'). 229 column_head('article_modified', 'lastmod', 'list', true, $switch_dir, $crit, $search_method, (('lastmod' == $sort) ? "$dir " : '').'articles_detail date modified'). 230 column_head('expires', 'expires', 'list', true, $switch_dir, $crit, $search_method, (('expires' == $sort) ? "$dir " : '').'articles_detail date expires'). 231 column_head('section', 'section', 'list', true, $switch_dir, $crit, $search_method, (('section' == $sort) ? "$dir " : '').'section'). 232 column_head('category1', 'category1', 'list', true, $switch_dir, $crit, $search_method, (('category1' == $sort) ? "$dir " : '').'articles_detail category category1'). 233 column_head('category2', 'category2', 'list', true, $switch_dir, $crit, $search_method, (('category2' == $sort) ? "$dir " : '').'articles_detail category category2'). 234 column_head('status', 'status', 'list', true, $switch_dir, $crit, $search_method, (('status' == $sort) ? "$dir " : '').'status'). 235 ($show_authors ? column_head('author', 'author', 'list', true, $switch_dir, $crit, $search_method, (('author' == $sort) ? "$dir " : '').'author') : ''). 236 column_head('comments', 'comments', 'list', true, $switch_dir, $crit, $search_method, (('comments' == $sort) ? "$dir " : '').'articles_detail comments') 237 ). 238 n.'</thead>'; 239 240 include_once txpath.'/publish/taghandlers.php'; 241 242 echo '<tbody>'; 243 244 $validator = new Validator(); 245 246 while ($a = nextRow($rs)) 247 { 248 extract($a); 249 250 if (empty($Title)) 251 { 252 $Title = '<em>'.eLink('article', 'edit', 'ID', $ID, gTxt('untitled')).'</em>'; 253 } 254 255 else 256 { 257 $Title = eLink('article', 'edit', 'ID', $ID, $Title); 258 } 259 260 // Valid section and categories? 261 $validator->setConstraints(array(new SectionConstraint($Section))); 262 $vs = $validator->validate() ? '' : ' error'; 263 264 $validator->setConstraints(array(new CategoryConstraint($Category1, array('type' => 'article')))); 265 $vc[1] = $validator->validate() ? '' : ' error'; 266 267 $validator->setConstraints(array(new CategoryConstraint($Category2, array('type' => 'article')))); 268 $vc[2] = $validator->validate() ? '' : ' error'; 269 270 $Category1 = ($Category1) ? '<span title="'.txpspecialchars(fetch_category_title($Category1)).'">'.$Category1.'</span>' : ''; 271 $Category2 = ($Category2) ? '<span title="'.txpspecialchars(fetch_category_title($Category2)).'">'.$Category2.'</span>' : ''; 272 273 if ($Status != STATUS_LIVE and $Status != STATUS_STICKY) 274 { 275 $view_url = '?txpreview='.intval($ID).'.'.time(); 276 } 277 else 278 { 279 $view_url = permlinkurl($a); 280 } 281 282 $Status = !empty($Status) ? $statuses[$Status] : ''; 283 284 $comments = '(0)'; 285 286 if (isset($total_comments[$ID]) and $total_comments[$ID] > 0) 287 { 288 $comments = href('('.$total_comments[$ID].')', 'index.php?event=discuss'.a.'step=list'.a.'search_method=parent'.a.'crit='.$ID, ' title="'.gTxt('manage').'"'); 289 } 290 291 $comment_status = ($Annotate) ? gTxt('on') : gTxt('off'); 292 293 if ($comments_disabled_after) 294 { 295 $lifespan = $comments_disabled_after * 86400; 296 $time_since = time() - $posted; 297 298 if ($time_since > $lifespan) 299 { 300 $comment_status = gTxt('expired'); 301 } 302 } 303 304 $comments = n.'<span class="comments-status">'.$comment_status.'</span> <span class="comments-manage">'.$comments.'</span>'; 305 306 echo n.n.tr( 307 308 n.td(( 309 ( ($a['Status'] >= STATUS_LIVE and has_privs('article.edit.published')) 310 or ($a['Status'] >= STATUS_LIVE and $AuthorID == $txp_user 311 and has_privs('article.edit.own.published')) 312 or ($a['Status'] < STATUS_LIVE and has_privs('article.edit')) 313 or ($a['Status'] < STATUS_LIVE and $AuthorID == $txp_user and has_privs('article.edit.own')) 314 ) 315 ? fInput('checkbox', 'selected[]', $ID, 'checkbox') 316 : ' ' 317 ), '', 'multi-edit'). 318 319 n.td(eLink('article', 'edit', 'ID', $ID, $ID) .sp. '<span class="articles_detail">[<a href="'.$view_url.'">'.gTxt('view').'</a>]</span>', '', 'id'). 320 321 td($Title, '', 'title'). 322 323 td( 324 gTime($posted), '', ($posted < time() ? '' : 'unpublished ').'date posted created' 325 ). 326 327 td( 328 gTime($lastmod), '', "articles_detail date modified" 329 ). 330 331 td( 332 ($expires ? gTime($expires) : ''), '' ,'articles_detail date expires' 333 ). 334 335 td( 336 '<span title="'.txpspecialchars(fetch_section_title($Section)).'">'.$Section.'</span>' 337 , '', 'section'.$vs). 338 339 td($Category1, '', "articles_detail category category1".$vc[1]). 340 td($Category2, '', "articles_detail category category2".$vc[2]). 341 td('<a href="'.$view_url.'" title="'.gTxt('view').'">'.$Status.'</a>', '', 'status'). 342 343 ($show_authors ? td( 344 '<span title="'.txpspecialchars(get_author_name($AuthorID)).'">'.txpspecialchars($AuthorID).'</span>' 345 , '', 'author' 346 ) : ''). 347 348 td($comments, '', "articles_detail comments") 349 ); 350 } 351 352 echo '</tbody>', 353 n, endTable(), 354 n, '</div>', 355 n, list_multiedit_form($page, $sort, $dir, $crit, $search_method), 356 n, tInput(), 357 n, '</form>', 358 n, graf( 359 toggle_box('articles_detail'), 360 ' class="detail-toggle"' 361 ), 362 n, '<div id="'.$event.'_navigation" class="txp-navigation">', 363 n, nav_form('list', $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit), 364 n, pageby_form('list', $article_list_pageby), 365 n, '</div>', 366 n, '</div>'; 367 } 368 } 369 370 // ------------------------------------------------------------- 371 function list_change_pageby() 372 { 373 event_change_pageby('article'); 374 list_list(); 375 } 376 377 // ------------------------------------------------------------- 378 379 function list_search_form($crit, $method) 380 { 381 $methods = array( 382 'id' => gTxt('ID'), 383 'title_body_excerpt' => gTxt('title_body_excerpt'), 384 'section' => gTxt('section'), 385 'categories' => gTxt('categories'), 386 'keywords' => gTxt('keywords'), 387 'status' => gTxt('status'), 388 'author' => gTxt('author'), 389 'article_image' => gTxt('article_image'), 390 'posted' => gTxt('posted'), 391 'lastmod' => gTxt('article_modified') 392 ); 393 394 return search_form('list', 'list', $crit, $methods, $method, 'title_body_excerpt'); 395 } 396 397 // ------------------------------------------------------------- 398 399 function list_multiedit_form($page, $sort, $dir, $crit, $search_method) 400 { 401 global $statuses, $all_cats, $all_authors, $all_sections; 402 403 if ($all_cats) { 404 $category1 = treeSelectInput('Category1', $all_cats, ''); 405 $category2 = treeSelectInput('Category2', $all_cats, ''); 406 } 407 else 408 { 409 $category1 = $category2 = ''; 410 } 411 412 $sections = $all_sections ? selectInput('Section', $all_sections, '', true) : ''; 413 $comments = onoffRadio('Annotate', get_pref('comments_on_default')); 414 $status = selectInput('Status', $statuses, '', true); 415 $authors = $all_authors ? selectInput('AuthorID', $all_authors, '', true) : ''; 416 417 $methods = array( 418 'changesection' => array('label' => gTxt('changesection'), 'html' => $sections), 419 'changecategory1' => array('label' => gTxt('changecategory1'), 'html' => $category1), 420 'changecategory2' => array('label' => gTxt('changecategory2'), 'html' => $category2), 421 'changestatus' => array('label' => gTxt('changestatus'), 'html' => $status), 422 'changecomments' => array('label' => gTxt('changecomments'), 'html' => $comments), 423 'changeauthor' => array('label' => gTxt('changeauthor'), 'html' => $authors), 424 'delete' => gTxt('delete'), 425 ); 426 427 if (!$all_cats) 428 { 429 unset($methods['changecategory1'], $methods['changecategory2']); 430 } 431 432 if (has_single_author('textpattern', 'AuthorID')) 433 { 434 unset($methods['changeauthor']); 435 } 436 437 if(!has_privs('article.delete.own') && !has_privs('article.delete')) 438 { 439 unset($methods['delete']); 440 } 441 442 return multi_edit($methods, 'list', 'list_multi_edit', $page, $sort, $dir, $crit, $search_method); 443 } 444 445 // ------------------------------------------------------------- 446 447 function list_multi_edit() 448 { 449 global $txp_user, $statuses, $all_cats, $all_authors, $all_sections; 450 451 // Empty entry to permit clearing the categories 452 $categories = array(''); 453 454 foreach ($all_cats as $row) { 455 $categories[] = $row['name']; 456 } 457 458 $selected = ps('selected'); 459 460 if (!$selected or !is_array($selected)) 461 { 462 return list_list(); 463 } 464 465 $selected = array_map('assert_int', $selected); 466 $method = ps('edit_method'); 467 $changed = false; 468 $ids = array(); 469 $key = ''; 470 471 if ($method == 'delete') 472 { 473 if (!has_privs('article.delete')) 474 { 475 $allowed = array(); 476 477 if (has_privs('article.delete.own')) 478 { 479 $allowed = safe_column_num('ID', 'textpattern', 'ID in('.join(',',$selected).') and AuthorID=\''.doSlash($txp_user).'\''); 480 } 481 482 $selected = $allowed; 483 } 484 485 foreach ($selected as $id) 486 { 487 if (safe_delete('textpattern', "ID = $id")) 488 { 489 $ids[] = $id; 490 } 491 } 492 493 $changed = join(', ', $ids); 494 495 if ($changed) 496 { 497 safe_update('txp_discuss', "visible = ".MODERATE, "parentid in($changed)"); 498 callback_event('articles_deleted', '', 0, $ids); 499 } 500 } 501 502 else 503 { 504 $selected = safe_rows('ID, AuthorID, Status', 'textpattern', 505 'ID in ('. implode(',',$selected) .')'); 506 507 $allowed = array(); 508 foreach ($selected as $item) 509 { 510 if ( ($item['Status'] >= STATUS_LIVE and has_privs('article.edit.published')) 511 or ($item['Status'] >= STATUS_LIVE and $item['AuthorID'] == $txp_user and has_privs('article.edit.own.published')) 512 or ($item['Status'] < STATUS_LIVE and has_privs('article.edit')) 513 or ($item['Status'] < STATUS_LIVE and $item['AuthorID'] == $txp_user and has_privs('article.edit.own'))) 514 { 515 $allowed[] = $item['ID']; 516 } 517 } 518 519 $selected = $allowed; 520 unset($allowed); 521 522 switch ($method) 523 { 524 // change author 525 case 'changeauthor': 526 $val = has_privs('article.edit') ? ps('AuthorID') : ''; 527 if (in_array($val, $all_authors)) 528 { 529 $key = 'AuthorID'; 530 } 531 break; 532 533 // change category1 534 case 'changecategory1': 535 $val = ps('Category1'); 536 if (in_array($val, $categories)) 537 { 538 $key = 'Category1'; 539 } 540 break; 541 542 // change category2 543 case 'changecategory2': 544 $val = ps('Category2'); 545 if (in_array($val, $categories)) 546 { 547 $key = 'Category2'; 548 } 549 break; 550 551 // change comments 552 case 'changecomments': 553 $key = 'Annotate'; 554 $val = (int) ps('Annotate'); 555 break; 556 557 // change section 558 case 'changesection': 559 $val = ps('Section'); 560 if (in_array($val, $all_sections)) 561 { 562 $key = 'Section'; 563 } 564 break; 565 566 // change status 567 case 'changestatus': 568 $val = (int) ps('Status'); 569 if (array_key_exists($val, $statuses)) 570 { 571 $key = 'Status'; 572 } 573 574 if (!has_privs('article.publish') && $val >= STATUS_LIVE) 575 { 576 $val = STATUS_PENDING; 577 } 578 break; 579 580 default: 581 $key = ''; 582 $val = ''; 583 break; 584 } 585 586 if ($selected and $key) 587 { 588 foreach ($selected as $id) 589 { 590 if (safe_update('textpattern', "$key = '".doSlash($val)."'", "ID = $id")) 591 { 592 $ids[] = $id; 593 } 594 } 595 596 $changed = join(', ', $ids); 597 } 598 } 599 600 if ($changed) 601 { 602 update_lastmod(); 603 604 return list_list( 605 messenger('article', $changed, (($method == 'delete') ? 'deleted' : 'modified' )) 606 ); 607 } 608 609 return list_list(); 610 } 611 612 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title