Admidio/admidio

View on GitHub
adm_program/modules/categories/categories_function.php

Summary

Maintainability
A
40 mins
Test Coverage
<?php
/**
 ***********************************************************************************************
 * Various functions for categories
 *
 * @copyright The Admidio Team
 * @see https://www.admidio.org/
 * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License v2.0 only
 ***********************************************************************************************
 * Parameters:
 *
 * uuid : Uuid of the category, that should be edited
 * type     : Type of categories that could be maintained
 *            ROL = Categories for roles
 *            LNK = Categories for weblinks
 *            ANN = Categories for announcements
 *            USF = Categories for profile fields
 *            EVT = Calendars for events
 * mode     : edit     - Create or edit categories
 *            delete   - Delete category
 *            sequence - Change sequence for parameter cat_id
 * direction : Direction to change the sequence of the category
 *****************************************************************************/
use Admidio\Exception;

try {
    require_once(__DIR__ . '/../../system/common.php');
    require(__DIR__ . '/../../system/login_valid.php');

    // Initialize and check the parameters
    $getCatUUID = admFuncVariableIsValid($_GET, 'uuid', 'uuid');
    $getType = admFuncVariableIsValid($_GET, 'type', 'string', array('validValues' => array('ROL', 'LNK', 'USF', 'ANN', 'EVT', 'AWA')));
    $getMode = admFuncVariableIsValid($_GET, 'mode', 'string', array('requireValue' => true, 'validValues' => array('edit', 'delete', 'sequence')));

    // check the CSRF token of the form against the session token
    SecurityUtils::validateCsrfToken($_POST['admidio-csrf-token']);

    // create category object
    $category = new TableCategory($gDb);

    if ($getCatUUID !== '') {
        $category->readDataByUuid($getCatUUID);

        // if system category then set cat_name to default
        if ($category->getValue('cat_system') == 1) {
            $_POST['cat_name'] = $category->getValue('cat_name');
        }
        if ($getType === '') {
            $getType = $category->getValue('cat_type');
        }
    } else {
        // create a new category
        $category->setValue('cat_org_id', $gCurrentOrgId);
        $category->setValue('cat_type', $getType);
    }

    // set text strings for the different modules
    switch ($getType) {
        case 'ANN':
            $component = 'ANNOUNCEMENTS';
            break;

        case 'EVT':
            $component = 'EVENTS';
            break;

        case 'LNK':
            $component = 'LINKS';
            break;

        case 'ROL':
            $component = 'GROUPS-ROLES';
            break;

        case 'USF': // fallthrough
        case 'AWA':
            $component = 'CORE';
            break;

        default:
            $component = '';
    }

    // check if the current user has the right to
    if (!Component::isAdministrable($component)) {
        throw new Exception('SYS_INVALID_PAGE_VIEW');
    }

    // check if this category is editable by the current user and current organization
    if (!$category->isEditable()) {
        throw new Exception('SYS_NO_RIGHTS');
    }

    if ($getMode === 'edit') {
        // create or edit category

        // check form field input and sanitized it from malicious content
        $categoryEditForm = $gCurrentSession->getFormObject($_POST['admidio-csrf-token']);
        $formValues = $categoryEditForm->validate($_POST);

        if ($getType !== 'ROL'
            && ((bool)$category->getValue('cat_system') === false || $gCurrentOrganization->countAllRecords() === 1)
            && !isset($_POST['adm_categories_view_right'])) {
            throw new Exception('SYS_FIELD_EMPTY', array('SYS_VISIBLE_FOR'));
        }

        if (!isset($_POST['adm_categories_edit_right'])) {
            // The editing right does not have to be set, as the module administrators still have the right,
            // so initialize the parameter
            $_POST['adm_categories_edit_right'] = array();
        }

        // set a global category if it's not a role category and the flag was set,
        // if it's a profile field category and only 1 organization exists,
        // if it's the role category of events
        if (($getType !== 'ROL' && isset($_POST['show_in_several_organizations']))
            || ($getType === 'USF' && $gCurrentOrganization->countAllRecords() === 1)
            || ($getType === 'ROL' && $category->getValue('cat_name_intern') === 'EVENTS')) {
            $category->setValue('cat_org_id', 0);
            $sqlSearchOrga = ' AND (  cat_org_id = ? -- $gCurrentOrgId
                               OR cat_org_id IS NULL )';
        } else {
            $category->setValue('cat_org_id', $gCurrentOrgId);
            $sqlSearchOrga = ' AND cat_org_id = ? -- $gCurrentOrgId';
        }

        if ($category->getValue('cat_name') !== $_POST['cat_name']) {
            // See if the category already exists
            $sql = 'SELECT COUNT(*) AS count
                  FROM ' . TBL_CATEGORIES . '
                 WHERE cat_type = ? -- $getType
                   AND cat_name = ? -- $_POST[\'cat_name\']
                   AND cat_uuid <> ? -- $getCatUUID
                       ' . $sqlSearchOrga;
            $categoriesStatement = $gDb->queryPrepared($sql, array($getType, $_POST['cat_name'], $getCatUUID, $gCurrentOrgId));

            if ($categoriesStatement->fetchColumn() > 0) {
                throw new Exception('SYS_CATEGORY_EXISTS_IN_ORGA');
            }
        }

        // write form values in category object
        foreach ($formValues as $key => $value) {
            if (str_starts_with($key, 'cat_')) {
                $category->setValue($key, $value);
            }
        }

        $gDb->startTransaction();

        // write category into database
        $category->save();

        if ($getType !== 'ROL' && $category->getValue('cat_name_intern') !== 'BASIC_DATA') {
            $rightCategoryView = new RolesRights($gDb, 'category_view', (int)$category->getValue('cat_id'));

            // roles have their own preferences for visibility, so only allow this for other types
            // until now we do not support visibility for categories that belong to several organizations
            if ($category->getValue('cat_org_id') > 0
                || ((int)$category->getValue('cat_org_id') === 0 && $gCurrentOrganization->countAllRecords() === 1)) {
                // save changed roles rights of the category
                $rightCategoryView->saveRoles(array_map('intval', $_POST['adm_categories_view_right']));
            } else {
                // delete existing roles rights of the category
                $rightCategoryView->delete();
            }

            if ($getType === 'USF') {
                // delete cache with profile categories rights
                $gProfileFields = new ProfileFields($gDb, $gCurrentOrgId);
            } else {
                // until now, we don't use edit rights for profile fields
                $rightCategoryEdit = new RolesRights($gDb, 'category_edit', (int)$category->getValue('cat_id'));
                $rightCategoryEdit->saveRoles(array_map('intval', $_POST['adm_categories_edit_right']));
            }
        }

        // if a category has been converted from all organizations to a specific one or the other way around,
        // then the sequence must be reset for all categories of this type
        $sequenceCategory = new TableCategory($gDb);
        $sequence = 0;

        $sql = 'SELECT *
              FROM ' . TBL_CATEGORIES . '
             WHERE cat_type = ? -- $getType
               AND (  cat_org_id  = ? -- $gCurrentOrgId
                   OR cat_org_id IS NULL )
          ORDER BY cat_org_id, cat_sequence';
        $categoriesStatement = $gDb->queryPrepared($sql, array($getType, $gCurrentOrgId));

        while ($row = $categoriesStatement->fetch()) {
            ++$sequence;
            $sequenceCategory->clear();
            $sequenceCategory->setArray($row);

            $sequenceCategory->setValue('cat_sequence', $sequence);
            $sequenceCategory->save();
        }

        $gDb->endTransaction();

        $gNavigation->deleteLastUrl();
        echo json_encode(array('status' => 'success', 'url' => $gNavigation->getUrl()));
        exit();
    } elseif ($getMode === 'delete') {
        // delete category
        if ($category->delete()) {
            echo json_encode(array('status' => 'success'));
            exit();
        }
    } elseif ($getMode === 'sequence') {
        // Update category sequence
        $postSequence = admFuncVariableIsValid($_POST, 'direction', 'string', array('requireValue' => true, 'validValues' => array(TableCategory::MOVE_UP, TableCategory::MOVE_DOWN)));

        if ($category->moveSequence($postSequence)) {
            echo json_encode(array('status' => 'success'));
        } else {
            throw new Exception('Sequence could not be changed.');
        }
        exit();
    }
} catch (Exception $e) {
    echo json_encode(array('status' => 'error', 'message' => $e->getMessage()));
}