Files
nextcloud-forum/lib/Controller/BBCodeController.php
2026-03-16 22:51:06 +02:00

247 lines
8.5 KiB
PHP

<?php
declare(strict_types=1);
// SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
// SPDX-License-Identifier: AGPL-3.0-or-later
namespace OCA\Forum\Controller;
use OCA\Forum\Attribute\RequirePermission;
use OCA\Forum\Db\BBCodeMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\ApiRoute;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
use Psr\Log\LoggerInterface;
class BBCodeController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
private BBCodeMapper $bbCodeMapper,
private LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}
/**
* Get all BBCodes (excludes builtin codes)
*
* @param int<1, 100> $limit Maximum number of BBCodes to return
* @param int<0, max> $offset Offset for pagination
* @return DataResponse<Http::STATUS_OK, list<array<string, mixed>>, array{}>
*
* 200: BBCodes returned
*/
#[NoAdminRequired]
#[RequirePermission('canAccessAdminTools')]
#[ApiRoute(verb: 'GET', url: '/api/bbcodes')]
public function index(int $limit = 100, int $offset = 0): DataResponse {
try {
$bbcodes = array_slice($this->bbCodeMapper->findAllNonBuiltin(), $offset, $limit);
return new DataResponse(array_map(fn ($b) => $b->jsonSerialize(), $bbcodes));
} catch (\Exception $e) {
$this->logger->error('Error fetching BBCodes: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to fetch BBCodes'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Get enabled BBCodes
*
* @param int<1, 100> $limit Maximum number of BBCodes to return
* @param int<0, max> $offset Offset for pagination
* @return DataResponse<Http::STATUS_OK, list<array<string, mixed>>, array{}>
*
* 200: Enabled BBCodes returned
*/
#[NoAdminRequired]
#[ApiRoute(verb: 'GET', url: '/api/bbcodes/enabled')]
public function enabled(int $limit = 100, int $offset = 0): DataResponse {
try {
$bbcodes = array_slice($this->bbCodeMapper->findAllEnabled(), $offset, $limit);
return new DataResponse(array_map(fn ($b) => $b->jsonSerialize(), $bbcodes));
} catch (\Exception $e) {
$this->logger->error('Error fetching enabled BBCodes: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to fetch BBCodes'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Get builtin BBCodes (for help dialog)
*
* @param int<1, 100> $limit Maximum number of BBCodes to return
* @param int<0, max> $offset Offset for pagination
* @return DataResponse<Http::STATUS_OK, list<array<string, mixed>>, array{}>
*
* 200: Builtin BBCodes returned
*/
#[NoAdminRequired]
#[ApiRoute(verb: 'GET', url: '/api/bbcodes/builtin')]
public function builtin(int $limit = 100, int $offset = 0): DataResponse {
try {
$bbcodes = array_slice($this->bbCodeMapper->findAllBuiltin(), $offset, $limit);
return new DataResponse(array_map(fn ($b) => $b->jsonSerialize(), $bbcodes));
} catch (\Exception $e) {
$this->logger->error('Error fetching builtin BBCodes: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to fetch BBCodes'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Get a single BBCode
*
* @param int $id BBCode ID
* @return DataResponse<Http::STATUS_OK, array<string, mixed>, array{}>
*
* 200: BBCode returned
*/
#[NoAdminRequired]
#[RequirePermission('canAccessAdminTools')]
#[ApiRoute(verb: 'GET', url: '/api/bbcodes/{id}')]
public function show(int $id): DataResponse {
try {
$bbcode = $this->bbCodeMapper->find($id);
// Prevent access to builtin BBCodes
if ($bbcode->getIsBuiltin()) {
return new DataResponse(['error' => 'Cannot access builtin BBCode'], Http::STATUS_FORBIDDEN);
}
return new DataResponse($bbcode->jsonSerialize());
} catch (DoesNotExistException $e) {
return new DataResponse(['error' => 'BBCode not found'], Http::STATUS_NOT_FOUND);
} catch (\Exception $e) {
$this->logger->error('Error fetching BBCode: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to fetch BBCode'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Create a new BBCode
*
* @param string $tag BBCode tag name
* @param string $replacement Replacement pattern
* @param string $example Example usage
* @param string|null $description Optional description
* @param bool $enabled Whether BBCode is enabled
* @param bool $parseInner Whether to parse inner BBCode tags
* @return DataResponse<Http::STATUS_CREATED, array<string, mixed>, array{}>
*
* 201: BBCode created
*/
#[NoAdminRequired]
#[RequirePermission('canAccessAdminTools')]
#[ApiRoute(verb: 'POST', url: '/api/bbcodes')]
public function create(string $tag, string $replacement, string $example, ?string $description = null, bool $enabled = true, bool $parseInner = true): DataResponse {
try {
$bbcode = new \OCA\Forum\Db\BBCode();
$bbcode->setTag($tag);
$bbcode->setReplacement($replacement);
$bbcode->setExample($example);
$bbcode->setDescription($description);
$bbcode->setEnabled($enabled);
$bbcode->setParseInner($parseInner);
$bbcode->setIsBuiltin(false); // User-created BBCodes are never builtin
$bbcode->setCreatedAt(time());
/** @var \OCA\Forum\Db\BBCode */
$createdBBCode = $this->bbCodeMapper->insert($bbcode);
return new DataResponse($createdBBCode->jsonSerialize(), Http::STATUS_CREATED);
} catch (\Exception $e) {
$this->logger->error('Error creating BBCode: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to create BBCode'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Update a BBCode
*
* @param int $id BBCode ID
* @param string|null $tag BBCode tag name
* @param string|null $replacement Replacement pattern
* @param string|null $example Example usage
* @param string|null $description Description
* @param bool|null $enabled Whether BBCode is enabled
* @param bool|null $parseInner Whether to parse inner BBCode tags
* @return DataResponse<Http::STATUS_OK, array<string, mixed>, array{}>
*
* 200: BBCode updated
*/
#[NoAdminRequired]
#[RequirePermission('canAccessAdminTools')]
#[ApiRoute(verb: 'PUT', url: '/api/bbcodes/{id}')]
public function update(int $id, ?string $tag = null, ?string $replacement = null, ?string $example = null, ?string $description = null, ?bool $enabled = null, ?bool $parseInner = null): DataResponse {
try {
$bbcode = $this->bbCodeMapper->find($id);
// Prevent updating builtin BBCodes
if ($bbcode->getIsBuiltin()) {
return new DataResponse(['error' => 'Cannot update builtin BBCode'], Http::STATUS_FORBIDDEN);
}
if ($tag !== null) {
$bbcode->setTag($tag);
}
if ($replacement !== null) {
$bbcode->setReplacement($replacement);
}
if ($example !== null) {
$bbcode->setExample($example);
}
if ($description !== null) {
$bbcode->setDescription($description);
}
if ($enabled !== null) {
$bbcode->setEnabled($enabled);
}
if ($parseInner !== null) {
$bbcode->setParseInner($parseInner);
}
/** @var \OCA\Forum\Db\BBCode */
$updatedBBCode = $this->bbCodeMapper->update($bbcode);
return new DataResponse($updatedBBCode->jsonSerialize());
} catch (DoesNotExistException $e) {
return new DataResponse(['error' => 'BBCode not found'], Http::STATUS_NOT_FOUND);
} catch (\Exception $e) {
$this->logger->error('Error updating BBCode: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to update BBCode'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Delete a BBCode
*
* @param int $id BBCode ID
* @return DataResponse<Http::STATUS_OK, array{success: bool}, array{}>
*
* 200: BBCode deleted
*/
#[NoAdminRequired]
#[RequirePermission('canAccessAdminTools')]
#[ApiRoute(verb: 'DELETE', url: '/api/bbcodes/{id}')]
public function destroy(int $id): DataResponse {
try {
$bbcode = $this->bbCodeMapper->find($id);
// Prevent deleting builtin BBCodes
if ($bbcode->getIsBuiltin()) {
return new DataResponse(['error' => 'Cannot delete builtin BBCode'], Http::STATUS_FORBIDDEN);
}
$this->bbCodeMapper->delete($bbcode);
return new DataResponse(['success' => true]);
} catch (DoesNotExistException $e) {
return new DataResponse(['error' => 'BBCode not found'], Http::STATUS_NOT_FOUND);
} catch (\Exception $e) {
$this->logger->error('Error deleting BBCode: ' . $e->getMessage());
return new DataResponse(['error' => 'Failed to delete BBCode'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
}