<?php /* Question2Answer by Gideon Greenspan and contributors http://www.question2answer.org/ File: qa-include/qa-page-admin-categories.php Description: Controller for admin page for editing categories This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. More about this license: http://www.question2answer.org/license.php */ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser header('Location: ../'); exit; } require_once QA_INCLUDE_DIR.'app/admin.php'; require_once QA_INCLUDE_DIR.'db/selects.php'; require_once QA_INCLUDE_DIR.'db/admin.php'; // Get relevant list of categories $editcategoryid=qa_post_text('edit'); if (!isset($editcategoryid)) $editcategoryid=qa_get('edit'); if (!isset($editcategoryid)) $editcategoryid=qa_get('addsub'); $categories=qa_db_select_with_pending(qa_db_category_nav_selectspec($editcategoryid, true, false, true)); // Check admin privileges (do late to allow one DB query) if (!qa_admin_check_privileges($qa_content)) return $qa_content; // Work out the appropriate state for the page $editcategory=@$categories[$editcategoryid]; if (isset($editcategory)) { $parentid=qa_get('addsub'); if (isset($parentid)) $editcategory=array('parentid' => $parentid); } else { if (qa_clicked('doaddcategory')) $editcategory=array(); elseif (qa_clicked('dosavecategory')) { $parentid=qa_post_text('parent'); $editcategory=array('parentid' => strlen($parentid) ? $parentid : null); } } $setmissing=qa_post_text('missing') || qa_get('missing'); $setparent=(!$setmissing) && (qa_post_text('setparent') || qa_get('setparent')) && isset($editcategory['categoryid']); $hassubcategory=false; foreach ($categories as $category) if (!strcmp($category['parentid'], $editcategoryid)) $hassubcategory=true; // Process saving options $savedoptions=false; $securityexpired=false; if (qa_clicked('dosaveoptions')) { if (!qa_check_form_security_code('admin/categories', qa_post_text('code'))) $securityexpired=true; else { qa_set_option('allow_no_category', (int)qa_post_text('option_allow_no_category')); qa_set_option('allow_no_sub_category', (int)qa_post_text('option_allow_no_sub_category')); $savedoptions=true; } } // Process saving an old or new category if (qa_clicked('docancel')) { if ($setmissing || $setparent) qa_redirect(qa_request(), array('edit' => $editcategory['categoryid'])); elseif (isset($editcategory['categoryid'])) qa_redirect(qa_request()); else qa_redirect(qa_request(), array('edit' => @$editcategory['parentid'])); } elseif (qa_clicked('dosetmissing')) { if (!qa_check_form_security_code('admin/categories', qa_post_text('code'))) $securityexpired=true; else { $inreassign=qa_get_category_field_value('reassign'); qa_db_category_reassign($editcategory['categoryid'], $inreassign); qa_redirect(qa_request(), array('recalc' => 1, 'edit' => $editcategory['categoryid'])); } } elseif (qa_clicked('dosavecategory')) { if (!qa_check_form_security_code('admin/categories', qa_post_text('code'))) $securityexpired=true; elseif (qa_post_text('dodelete')) { if (!$hassubcategory) { $inreassign=qa_get_category_field_value('reassign'); qa_db_category_reassign($editcategory['categoryid'], $inreassign); qa_db_category_delete($editcategory['categoryid']); qa_redirect(qa_request(), array('recalc' => 1, 'edit' => $editcategory['parentid'])); } } else { require_once QA_INCLUDE_DIR.'util/string.php'; $inname=qa_post_text('name'); $incontent=qa_post_text('content'); $inparentid=$setparent ? qa_get_category_field_value('parent') : $editcategory['parentid']; $inposition=qa_post_text('position'); $errors=array(); // Check the parent ID $incategories=qa_db_select_with_pending(qa_db_category_nav_selectspec($inparentid, true)); // Verify the name is legitimate for that parent ID if (empty($inname)) $errors['name']=qa_lang('main/field_required'); elseif (qa_strlen($inname)>QA_DB_MAX_CAT_PAGE_TITLE_LENGTH) $errors['name']=qa_lang_sub('main/max_length_x', QA_DB_MAX_CAT_PAGE_TITLE_LENGTH); else { foreach ($incategories as $category) if ( (!strcmp($category['parentid'], $inparentid)) && strcmp($category['categoryid'], @$editcategory['categoryid']) && qa_strtolower($category['title']) == qa_strtolower($inname) ) $errors['name']=qa_lang('admin/category_already_used'); } // Verify the slug is legitimate for that parent ID for ($attempt=0; $attempt<100; $attempt++) { switch ($attempt) { case 0: $inslug=qa_post_text('slug'); if (!isset($inslug)) $inslug=implode('-', qa_string_to_words($inname)); break; case 1: $inslug=qa_lang_sub('admin/category_default_slug', $inslug); break; default: $inslug=qa_lang_sub('admin/category_default_slug', $attempt-1); break; } $matchcategoryid=qa_db_category_slug_to_id($inparentid, $inslug); // query against DB since MySQL ignores accents, etc... if (!isset($inparentid)) $matchpage=qa_db_single_select(qa_db_page_full_selectspec($inslug, false)); else $matchpage=null; if (empty($inslug)) $errors['slug']=qa_lang('main/field_required'); elseif (qa_strlen($inslug)>QA_DB_MAX_CAT_PAGE_TAGS_LENGTH) $errors['slug']=qa_lang_sub('main/max_length_x', QA_DB_MAX_CAT_PAGE_TAGS_LENGTH); elseif (preg_match('/[\\+\\/]/', $inslug)) $errors['slug']=qa_lang_sub('admin/slug_bad_chars', '+ /'); elseif ( (!isset($inparentid)) && qa_admin_is_slug_reserved($inslug)) // only top level is a problem $errors['slug']=qa_lang('admin/slug_reserved'); elseif (isset($matchcategoryid) && strcmp($matchcategoryid, @$editcategory['categoryid'])) $errors['slug']=qa_lang('admin/category_already_used'); elseif (isset($matchpage)) $errors['slug']=qa_lang('admin/page_already_used'); else unset($errors['slug']); if (isset($editcategory['categoryid']) || !isset($errors['slug'])) // don't try other options if editing existing category break; } // Perform appropriate database action if (empty($errors)) { if (isset($editcategory['categoryid'])) { // changing existing category qa_db_category_rename($editcategory['categoryid'], $inname, $inslug); $recalc=false; if ($setparent) { qa_db_category_set_parent($editcategory['categoryid'], $inparentid); $recalc=true; } else { qa_db_category_set_content($editcategory['categoryid'], $incontent); qa_db_category_set_position($editcategory['categoryid'], $inposition); $recalc=($hassubcategory && ($inslug !== $editcategory['tags'])); } qa_redirect(qa_request(), array('edit' => $editcategory['categoryid'], 'saved' => true, 'recalc' => (int)$recalc)); } else { // creating a new one $categoryid=qa_db_category_create($inparentid, $inname, $inslug); qa_db_category_set_content($categoryid, $incontent); if (isset($inposition)) qa_db_category_set_position($categoryid, $inposition); qa_redirect(qa_request(), array('edit' => $inparentid, 'added' => true)); } } } } // Prepare content for theme $qa_content=qa_content_prepare(); $qa_content['title']=qa_lang_html('admin/admin_title').' - '.qa_lang_html('admin/categories_title'); $qa_content['error']=$securityexpired ? qa_lang_html('admin/form_security_expired') : qa_admin_page_error(); if ($setmissing) { $qa_content['form']=array( 'tags' => 'method="post" action="'.qa_path_html(qa_request()).'"', 'style' => 'tall', 'fields' => array( 'reassign' => array( 'label' => isset($editcategory) ? qa_lang_html_sub('admin/category_no_sub_to', qa_html($editcategory['title'])) : qa_lang_html('admin/category_none_to'), 'loose' => true, ), ), 'buttons' => array( 'save' => array( 'tags' => 'id="dosaveoptions"', // just used for qa_recalc_click() 'label' => qa_lang_html('main/save_button'), ), 'cancel' => array( 'tags' => 'name="docancel"', 'label' => qa_lang_html('main/cancel_button'), ), ), 'hidden' => array( 'dosetmissing' => '1', // for IE 'edit' => @$editcategory['categoryid'], 'missing' => '1', 'code' => qa_get_form_security_code('admin/categories'), ), ); qa_set_up_category_field($qa_content, $qa_content['form']['fields']['reassign'], 'reassign', $categories, @$editcategory['categoryid'], qa_opt('allow_no_category'), qa_opt('allow_no_sub_category')); } elseif (isset($editcategory)) { $qa_content['form']=array( 'tags' => 'method="post" action="'.qa_path_html(qa_request()).'"', 'style' => 'tall', 'ok' => qa_get('saved') ? qa_lang_html('admin/category_saved') : (qa_get('added') ? qa_lang_html('admin/category_added') : null), 'fields' => array( 'name' => array( 'id' => 'name_display', 'tags' => 'name="name" id="name"', 'label' => qa_lang_html(count($categories) ? 'admin/category_name' : 'admin/category_name_first'), 'value' => qa_html(isset($inname) ? $inname : @$editcategory['title']), 'error' => qa_html(@$errors['name']), ), 'questions' => array(), 'delete' => array(), 'reassign' => array(), 'slug' => array( 'id' => 'slug_display', 'tags' => 'name="slug"', 'label' => qa_lang_html('admin/category_slug'), 'value' => qa_html(isset($inslug) ? $inslug : @$editcategory['tags']), 'error' => qa_html(@$errors['slug']), ), 'content' => array( 'id' => 'content_display', 'tags' => 'name="content"', 'label' => qa_lang_html('admin/category_description'), 'value' => qa_html(isset($incontent) ? $incontent : @$editcategory['content']), 'error' => qa_html(@$errors['content']), 'rows' => 2, ), ), 'buttons' => array( 'save' => array( 'tags' => 'id="dosaveoptions"', // just used for qa_recalc_click 'label' => qa_lang_html(isset($editcategory['categoryid']) ? 'main/save_button' : 'admin/add_category_button'), ), 'cancel' => array( 'tags' => 'name="docancel"', 'label' => qa_lang_html('main/cancel_button'), ), ), 'hidden' => array( 'dosavecategory' => '1', // for IE 'edit' => @$editcategory['categoryid'], 'parent' => @$editcategory['parentid'], 'setparent' => (int)$setparent, 'code' => qa_get_form_security_code('admin/categories'), ), ); if ($setparent) { unset($qa_content['form']['fields']['delete']); unset($qa_content['form']['fields']['reassign']); unset($qa_content['form']['fields']['questions']); unset($qa_content['form']['fields']['content']); $qa_content['form']['fields']['parent']=array( 'label' => qa_lang_html('admin/category_parent'), ); $childdepth=qa_db_category_child_depth($editcategory['categoryid']); qa_set_up_category_field($qa_content, $qa_content['form']['fields']['parent'], 'parent', isset($incategories) ? $incategories : $categories, isset($inparentid) ? $inparentid : @$editcategory['parentid'], true, true, QA_CATEGORY_DEPTH-1-$childdepth, @$editcategory['categoryid']); $qa_content['form']['fields']['parent']['options']['']=qa_lang_html('admin/category_top_level'); @$qa_content['form']['fields']['parent']['note'].=qa_lang_html_sub('admin/category_max_depth_x', QA_CATEGORY_DEPTH); } elseif (isset($editcategory['categoryid'])) { // existing category if ($hassubcategory) { $qa_content['form']['fields']['name']['note']=qa_lang_html('admin/category_no_delete_subs'); unset($qa_content['form']['fields']['delete']); unset($qa_content['form']['fields']['reassign']); } else { $qa_content['form']['fields']['delete']=array( 'tags' => 'name="dodelete" id="dodelete"', 'label' => '<span id="reassign_shown">'.qa_lang_html('admin/delete_category_reassign').'</span>'. '<span id="reassign_hidden" style="display:none;">'.qa_lang_html('admin/delete_category').'</span>', 'value' => 0, 'type' => 'checkbox', ); $qa_content['form']['fields']['reassign']=array( 'id' => 'reassign_display', 'tags' => 'name="reassign"', ); qa_set_up_category_field($qa_content, $qa_content['form']['fields']['reassign'], 'reassign', $categories, $editcategory['parentid'], true, true, null, $editcategory['categoryid']); } $qa_content['form']['fields']['questions']=array( 'label' => qa_lang_html('admin/total_qs'), 'type' => 'static', 'value' => '<a href="'.qa_path_html('questions/'.qa_category_path_request($categories, $editcategory['categoryid'])).'">'. ( ($editcategory['qcount']==1) ? qa_lang_html_sub('main/1_question', '1', '1') : qa_lang_html_sub('main/x_questions', number_format($editcategory['qcount'])) ).'</a>', ); if ($hassubcategory && !qa_opt('allow_no_sub_category')) { $nosubcount=qa_db_count_categoryid_qs($editcategory['categoryid']); if ($nosubcount) $qa_content['form']['fields']['questions']['error']= strtr(qa_lang_html('admin/category_no_sub_error'), array( '^q' => number_format($nosubcount), '^1' => '<a href="'.qa_path_html(qa_request(), array('edit' => $editcategory['categoryid'], 'missing' => 1)).'">', '^2' => '</a>', )); } qa_set_display_rules($qa_content, array( 'position_display' => '!dodelete', 'slug_display' => '!dodelete', 'content_display' => '!dodelete', 'parent_display' => '!dodelete', 'children_display' => '!dodelete', 'reassign_display' => 'dodelete', 'reassign_shown' => 'dodelete', 'reassign_hidden' => '!dodelete', )); } else { // new category unset($qa_content['form']['fields']['delete']); unset($qa_content['form']['fields']['reassign']); unset($qa_content['form']['fields']['slug']); unset($qa_content['form']['fields']['questions']); $qa_content['focusid']='name'; } if (!$setparent) { $pathhtml=qa_category_path_html($categories, @$editcategory['parentid']); if (count($categories)) { $qa_content['form']['fields']['parent']=array( 'id' => 'parent_display', 'label' => qa_lang_html('admin/category_parent'), 'type' => 'static', 'value' => (strlen($pathhtml) ? $pathhtml : qa_lang_html('admin/category_top_level')), ); $qa_content['form']['fields']['parent']['value']= '<a href="'.qa_path_html(qa_request(), array('edit' => @$editcategory['parentid'])).'">'. $qa_content['form']['fields']['parent']['value'].'</a>'; if (isset($editcategory['categoryid'])) $qa_content['form']['fields']['parent']['value'].=' - '. '<a href="'.qa_path_html(qa_request(), array('edit' => $editcategory['categoryid'], 'setparent' => 1)). '" style="white-space: nowrap;">'.qa_lang_html('admin/category_move_parent').'</a>'; } $positionoptions=array(); $previous=null; $passedself=false; foreach ($categories as $key => $category) if (!strcmp($category['parentid'], @$editcategory['parentid'])) { if (isset($previous)) $positionhtml=qa_lang_html_sub('admin/after_x', qa_html($passedself ? $category['title'] : $previous['title'])); else $positionhtml=qa_lang_html('admin/first'); $positionoptions[$category['position']]=$positionhtml; if (!strcmp($category['categoryid'], @$editcategory['categoryid'])) $passedself=true; $previous=$category; } if (isset($editcategory['position'])) $positionvalue=$positionoptions[$editcategory['position']]; else { $positionvalue=isset($previous) ? qa_lang_html_sub('admin/after_x', qa_html($previous['title'])) : qa_lang_html('admin/first'); $positionoptions[1+@max(array_keys($positionoptions))]=$positionvalue; } $qa_content['form']['fields']['position']=array( 'id' => 'position_display', 'tags' => 'name="position"', 'label' => qa_lang_html('admin/position'), 'type' => 'select', 'options' => $positionoptions, 'value' => $positionvalue, ); if (isset($editcategory['categoryid'])) { $catdepth=count(qa_category_path($categories, $editcategory['categoryid'])); if ($catdepth<QA_CATEGORY_DEPTH) { $childrenhtml=''; foreach ($categories as $category) if (!strcmp($category['parentid'], $editcategory['categoryid'])) $childrenhtml.=(strlen($childrenhtml) ? ', ' : ''). '<a href="'.qa_path_html(qa_request(), array('edit' => $category['categoryid'])).'">'.qa_html($category['title']).'</a>'. ' ('.$category['qcount'].')'; if (!strlen($childrenhtml)) $childrenhtml=qa_lang_html('admin/category_no_subs'); $childrenhtml.=' - <a href="'.qa_path_html(qa_request(), array('addsub' => $editcategory['categoryid'])). '" style="white-space: nowrap;"><b>'.qa_lang_html('admin/category_add_sub').'</b></a>'; $qa_content['form']['fields']['children']=array( 'id' => 'children_display', 'label' => qa_lang_html('admin/category_subs'), 'type' => 'static', 'value' => $childrenhtml, ); } else { $qa_content['form']['fields']['name']['note']=qa_lang_html_sub('admin/category_no_add_subs_x', QA_CATEGORY_DEPTH); } } } } else { $qa_content['form']=array( 'tags' => 'method="post" action="'.qa_path_html(qa_request()).'"', 'ok' => $savedoptions ? qa_lang_html('admin/options_saved') : null, 'style' => 'tall', 'fields' => array( 'intro' => array( 'label' => qa_lang_html('admin/categories_introduction'), 'type' => 'static', ), ), 'buttons' => array( 'save' => array( 'tags' => 'name="dosaveoptions" id="dosaveoptions"', 'label' => qa_lang_html('main/save_button'), ), 'add' => array( 'tags' => 'name="doaddcategory"', 'label' => qa_lang_html('admin/add_category_button'), ), ), 'hidden' => array( 'code' => qa_get_form_security_code('admin/categories'), ), ); if (count($categories)) { unset($qa_content['form']['fields']['intro']); $navcategoryhtml=''; foreach ($categories as $category) if (!isset($category['parentid'])) $navcategoryhtml.='<a href="'.qa_path_html('admin/categories', array('edit' => $category['categoryid'])).'">'. qa_html($category['title']).'</a> - '.qa_lang_html_sub('main/x_questions', $category['qcount']).'<br/>'; $qa_content['form']['fields']['nav']=array( 'label' => qa_lang_html('admin/top_level_categories'), 'type' => 'static', 'value' => $navcategoryhtml, ); $qa_content['form']['fields']['allow_no_category']=array( 'label' => qa_lang_html('options/allow_no_category'), 'tags' => 'name="option_allow_no_category"', 'type' => 'checkbox', 'value' => qa_opt('allow_no_category'), ); if (!qa_opt('allow_no_category')) { $nocatcount=qa_db_count_categoryid_qs(null); if ($nocatcount) $qa_content['form']['fields']['allow_no_category']['error']= strtr(qa_lang_html('admin/category_none_error'), array( '^q' => number_format($nocatcount), '^1' => '<a href="'.qa_path_html(qa_request(), array('missing' => 1)).'">', '^2' => '</a>', )); } $qa_content['form']['fields']['allow_no_sub_category']=array( 'label' => qa_lang_html('options/allow_no_sub_category'), 'tags' => 'name="option_allow_no_sub_category"', 'type' => 'checkbox', 'value' => qa_opt('allow_no_sub_category'), ); } else unset($qa_content['form']['buttons']['save']); } if (qa_get('recalc')) { $qa_content['form']['ok']='<span id="recalc_ok">'.qa_lang_html('admin/recalc_categories').'</span>'; $qa_content['form']['hidden']['code_recalc']=qa_get_form_security_code('admin/recalc'); $qa_content['script_rel'][]='qa-content/qa-admin.js?'.QA_VERSION; $qa_content['script_var']['qa_warning_recalc']=qa_lang('admin/stop_recalc_warning'); $qa_content['script_onloads'][]=array( "qa_recalc_click('dorecalccategories', document.getElementById('dosaveoptions'), null, 'recalc_ok');" ); } $qa_content['navigation']['sub']=qa_admin_sub_navigation(); return $qa_content; /* Omit PHP closing tag to help avoid accidental output */