Changing Category Permissions via API

AI-generated summary

Changing Category Permissions via API

Marcos_Conceicao is trying to change category permissions via API but is receiving an error 400. After trying different approaches suggested by DeanMarkTaylor, including modifying the function call and array handling, the issue persists.

DeanMarkTaylor suggests reviewing the implementation of _putRequest and checking the body text of the error. Marcos_Conceicao provides the implementation and error details, which show an empty error message.

DeanMarkTaylor recommends a different approach, involving:

  1. Retrieving existing category properties from Discourse
  2. Reducing the result to a known whitelist of properties
  3. Adding the permissions
  4. Making the PUT request

This approach may help resolve the issue by ensuring only required properties are sent in the request.

I’m trying to change a category permission via API, but returning error 400.

I created this function with the php api.

And calling on my script:
$r = $api->editCategoryPermissions(641, array(‘admins’ => 1));

But returning error 400.

Can anyone help me?

Probably call with something more like:

$r = $api->editCategoryPermissions(641, array(
  array('group_name' => 'admins', 'permission_type' => 1)
));

Still giving error 400.

OK, this will likely be due to array handling for parameters in PHP:

Change the function to:

function editCategoryPermissions( $categoryId, $permissions, $username = 'system' ) {
  $params = array();
  foreach ( $permissions as $group => $permission ) {
    $params['permissions[' . $group . ']'] = $permission;
  }

  if ( empty( $params ) ) {
    // @todo consider throwing an exception here
    // sending empty parameters is most likely bad
  }
  return $this->_putRequest( '/categories/' . $categoryId, $params, $username );
}

And call as you did before:

$r = $api->editCategoryPermissions( 641, array( 'admins' => 1 ) );

Thanks @DeanMarkTaylor, but still throwing 400

What does the body text of the 400 error say?

What does the implementation of _putRequest look like?

Nothing :confused:

stdClass Object ( [http_code] => 400 [apiresult] => )
private function _putRequest($reqString, $paramArray, $apiUser = 'system')
    {
        return $this->_putpostRequest($reqString, $paramArray, $apiUser, true);
    }

private function _putpostRequest($reqString, $paramArray, $apiUser = 'system', $putMethod = false)
    {
        $ch = curl_init();
        $url = sprintf(
            '%s://%s%s?api_key=%s&api_username=%s',
            $this->_protocol, 
            $this->_dcHostname, 
            $reqString, 
            $this->_apiKey, 
            $apiUser
        );
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($paramArray));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        if ($putMethod) {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
        }
        $body = curl_exec($ch);
        $rc = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $resObj = new \stdClass();
        $resObj->http_code = $rc;
        $resObj->apiresult = json_decode($body);
        return $resObj;
    }

Personally I always:

  1. get the existing properties for the category from Discourse first
  2. reduce the result properties down to a known whitelist of properties
  3. add the permissions
  4. then make the PUT request

It might be that one or more of the of the properties is required.

The category permissions editor built into Discourse follows a similar process, however it knows exactly what should be sent back without needing a whitelist.

Filtering by a whitelist could be risky if other properties are added (by a new version of Discourse, a plugin, or custom fields), I haven’t checked the Discourse code to see if it removes the property if not set.