From 2fbe180d5e8a6e6fdd02b3506896f9355d6bef22 Mon Sep 17 00:00:00 2001 From: Chen Asraf Date: Sun, 16 Nov 2025 14:05:17 +0200 Subject: [PATCH] feat: thread subscriptions & notifications --- appinfo/console.php | 11 + appinfo/info.xml | 3 + lib/AppInfo/Application.php | 4 + lib/Command/TestNotifier.php | 81 + lib/Controller/PostController.php | 10 + lib/Controller/ReadMarkerController.php | 14 + lib/Controller/ThreadController.php | 9 + .../ThreadSubscriptionController.php | 132 + lib/Db/PostMapper.php | 24 + lib/Db/Thread.php | 15 + lib/Db/ThreadSubscription.php | 44 + lib/Db/ThreadSubscriptionMapper.php | 142 + lib/Migration/Version2Date20251114222614.php | 75 + lib/Notification/Notifier.php | 112 + lib/Service/NotificationService.php | 155 + openapi.json | 15820 ++++++++-------- src/types/models.ts | 1 + src/views/ThreadView.vue | 51 + 18 files changed, 8480 insertions(+), 8223 deletions(-) create mode 100644 appinfo/console.php create mode 100644 lib/Command/TestNotifier.php create mode 100644 lib/Controller/ThreadSubscriptionController.php create mode 100644 lib/Db/ThreadSubscription.php create mode 100644 lib/Db/ThreadSubscriptionMapper.php create mode 100644 lib/Migration/Version2Date20251114222614.php create mode 100644 lib/Notification/Notifier.php create mode 100644 lib/Service/NotificationService.php diff --git a/appinfo/console.php b/appinfo/console.php new file mode 100644 index 0000000..f645afd --- /dev/null +++ b/appinfo/console.php @@ -0,0 +1,11 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +use OCA\Forum\Command\TestNotifier; + +/** @var Symfony\Component\Console\Application $application */ +$application->add(\OC::$server->get(TestNotifier::class)); diff --git a/appinfo/info.xml b/appinfo/info.xml index 53c31d2..b523b99 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -55,6 +55,9 @@ The forum integrates seamlessly with your Nextcloud instance, using your existin + + OCA\Forum\Command\TestNotifier + Forum diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 47a3c17..c26b57f 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -6,6 +6,7 @@ namespace OCA\Forum\AppInfo; use OCA\Forum\Listener\UserEventListener; use OCA\Forum\Middleware\PermissionMiddleware; +use OCA\Forum\Notification\Notifier; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; @@ -33,6 +34,9 @@ class Application extends App implements IBootstrap { $context->registerEventListener(UserCreatedEvent::class, UserEventListener::class); $context->registerEventListener(UserDeletedEvent::class, UserEventListener::class); $context->registerEventListener(UserChangedEvent::class, UserEventListener::class); + + // Register notification notifier + $context->registerNotifierService(Notifier::class); } public function boot(IBootContext $context): void { diff --git a/lib/Command/TestNotifier.php b/lib/Command/TestNotifier.php new file mode 100644 index 0000000..e9d5dbf --- /dev/null +++ b/lib/Command/TestNotifier.php @@ -0,0 +1,81 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Command; + +use OCA\Forum\Notification\Notifier; +use OCP\L10N\IFactory; +use OCP\Notification\IManager as INotificationManager; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class TestNotifier extends Command { + public function __construct( + private INotificationManager $notificationManager, + private IFactory $l10nFactory, + ) { + parent::__construct(); + } + + protected function configure(): void { + parent::configure(); + $this->setName('forum:test-notifier') + ->setDescription('Test the forum notification system'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + try { + $output->writeln('Testing Forum Notifier...'); + + // Instantiate the notifier + $notifier = new Notifier($this->l10nFactory); + + $output->writeln('✓ Notifier instantiated successfully'); + $output->writeln(' ID: ' . $notifier->getID()); + $output->writeln(' Name: ' . $notifier->getName()); + + // Create a test notification (matching production structure) + $notification = $this->notificationManager->createNotification(); + + $notification->setApp('forum') + ->setUser('admin') + ->setDateTime(new \DateTime()) + ->setObject('thread', '1') + ->setSubject('new_posts', [ + 'threadId' => 1, + 'threadTitle' => 'Test Thread', + 'threadSlug' => 'test-thread', + 'lastPostId' => 1, + 'postCount' => 1, + ]) + ->setLink('http://localhost/apps/forum/t/test-thread') + ->setIcon('http://localhost/apps/forum/img/app-dark.svg'); + + $output->writeln('✓ Test notification created'); + + // Try to prepare it + $prepared = $notifier->prepare($notification, 'en'); + + $output->writeln('✓ Notification prepared successfully'); + $output->writeln(' Subject: ' . $prepared->getParsedSubject()); + $output->writeln(' Link: ' . $prepared->getLink()); + $output->writeln(' Icon: ' . $prepared->getIcon()); + + $output->writeln(''); + $output->writeln('All tests passed! The notifier is working correctly.'); + + return 0; + } catch (\Exception $e) { + $output->writeln('✗ Error: ' . $e->getMessage() . ''); + $output->writeln('Trace:'); + $output->writeln($e->getTraceAsString()); + + return 1; + } + } +} diff --git a/lib/Controller/PostController.php b/lib/Controller/PostController.php index 906b571..f6e8f0d 100644 --- a/lib/Controller/PostController.php +++ b/lib/Controller/PostController.php @@ -17,6 +17,7 @@ use OCA\Forum\Db\ReadMarkerMapper; use OCA\Forum\Db\ThreadMapper; use OCA\Forum\Db\UserStatsMapper; use OCA\Forum\Service\BBCodeService; +use OCA\Forum\Service\NotificationService; use OCA\Forum\Service\PermissionService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; @@ -41,6 +42,7 @@ class PostController extends OCSController { private BBCodeMapper $bbCodeMapper, private PermissionService $permissionService, private ReadMarkerMapper $readMarkerMapper, + private NotificationService $notificationService, private IUserSession $userSession, private LoggerInterface $logger, ) { @@ -268,6 +270,14 @@ class PostController extends OCSController { // Don't fail the request if category update fails } + // Notify registered users about the new post + try { + $this->notificationService->notifyThreadSubscribers($threadId, $createdPost->getId(), $user->getUID()); + } catch (\Exception $e) { + $this->logger->warning('Failed to send notifications for new post: ' . $e->getMessage()); + // Don't fail the request if notification sending fails + } + return new DataResponse(Post::enrichPostContent($createdPost), Http::STATUS_CREATED); } catch (\Exception $e) { $this->logger->error('Error creating post: ' . $e->getMessage()); diff --git a/lib/Controller/ReadMarkerController.php b/lib/Controller/ReadMarkerController.php index 621561c..0749ab6 100644 --- a/lib/Controller/ReadMarkerController.php +++ b/lib/Controller/ReadMarkerController.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace OCA\Forum\Controller; use OCA\Forum\Db\ReadMarkerMapper; +use OCA\Forum\Service\NotificationService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\ApiRoute; @@ -23,6 +24,7 @@ class ReadMarkerController extends OCSController { string $appName, IRequest $request, private ReadMarkerMapper $readMarkerMapper, + private NotificationService $notificationService, private IUserSession $userSession, private LoggerInterface $logger, ) { @@ -136,6 +138,18 @@ class ReadMarkerController extends OCSController { $lastReadPostId ); + // Dismiss notifications if the user has caught up with the thread + try { + $this->notificationService->dismissNotificationsIfRead( + $user->getUID(), + $threadId, + $lastReadPostId + ); + } catch (\Exception $e) { + $this->logger->warning('Failed to dismiss notifications: ' . $e->getMessage()); + // Don't fail the request if notification dismissal fails + } + return new DataResponse($marker->jsonSerialize()); } catch (\Exception $e) { $this->logger->error('Error marking thread as read: ' . $e->getMessage()); diff --git a/lib/Controller/ThreadController.php b/lib/Controller/ThreadController.php index a02d8ef..6faa960 100644 --- a/lib/Controller/ThreadController.php +++ b/lib/Controller/ThreadController.php @@ -13,6 +13,7 @@ use OCA\Forum\Db\Post; use OCA\Forum\Db\PostMapper; use OCA\Forum\Db\Thread; use OCA\Forum\Db\ThreadMapper; +use OCA\Forum\Db\ThreadSubscriptionMapper; use OCA\Forum\Db\UserStatsMapper; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; @@ -32,6 +33,7 @@ class ThreadController extends OCSController { private CategoryMapper $categoryMapper, private PostMapper $postMapper, private UserStatsMapper $userStatsMapper, + private ThreadSubscriptionMapper $threadSubscriptionMapper, private IUserSession $userSession, private LoggerInterface $logger, ) { @@ -244,6 +246,13 @@ class ThreadController extends OCSController { $this->logger->warning('Failed to update user stats: ' . $e->getMessage()); } + // Auto-subscribe the thread creator to receive notifications + try { + $this->threadSubscriptionMapper->subscribe($user->getUID(), $createdThread->getId()); + } catch (\Exception $e) { + $this->logger->warning('Failed to subscribe thread creator: ' . $e->getMessage()); + } + return new DataResponse($createdThread->jsonSerialize(), Http::STATUS_CREATED); } catch (\Exception $e) { $this->logger->error('Error creating thread: ' . $e->getMessage()); diff --git a/lib/Controller/ThreadSubscriptionController.php b/lib/Controller/ThreadSubscriptionController.php new file mode 100644 index 0000000..d29b7e9 --- /dev/null +++ b/lib/Controller/ThreadSubscriptionController.php @@ -0,0 +1,132 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Controller; + +use OCA\Forum\Db\ThreadSubscriptionMapper; +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 OCP\IUserSession; +use Psr\Log\LoggerInterface; + +class ThreadSubscriptionController extends OCSController { + public function __construct( + string $appName, + IRequest $request, + private ThreadSubscriptionMapper $subscriptionMapper, + private IUserSession $userSession, + private LoggerInterface $logger, + ) { + parent::__construct($appName, $request); + } + + /** + * Subscribe current user to a thread to receive notifications + * + * @param int $threadId Thread ID + * @return DataResponse, array{}> + * + * 200: User subscribed to thread + */ + #[NoAdminRequired] + #[ApiRoute(verb: 'POST', url: '/api/threads/{threadId}/subscribe')] + public function subscribe(int $threadId): DataResponse { + try { + $user = $this->userSession->getUser(); + if (!$user) { + return new DataResponse(['error' => 'User not authenticated'], Http::STATUS_UNAUTHORIZED); + } + + $subscription = $this->subscriptionMapper->subscribe($user->getUID(), $threadId); + return new DataResponse([ + 'success' => true, + 'subscription' => $subscription->jsonSerialize(), + ]); + } catch (\Exception $e) { + $this->logger->error('Error subscribing user to thread: ' . $e->getMessage()); + return new DataResponse(['error' => 'Failed to subscribe to thread'], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + + /** + * Unsubscribe current user from a thread + * + * @param int $threadId Thread ID + * @return DataResponse, array{}> + * + * 200: User unsubscribed from thread + */ + #[NoAdminRequired] + #[ApiRoute(verb: 'DELETE', url: '/api/threads/{threadId}/subscribe')] + public function unsubscribe(int $threadId): DataResponse { + try { + $user = $this->userSession->getUser(); + if (!$user) { + return new DataResponse(['error' => 'User not authenticated'], Http::STATUS_UNAUTHORIZED); + } + + $this->subscriptionMapper->unsubscribe($user->getUID(), $threadId); + return new DataResponse(['success' => true]); + } catch (\Exception $e) { + $this->logger->error('Error unsubscribing user from thread: ' . $e->getMessage()); + return new DataResponse(['error' => 'Failed to unsubscribe from thread'], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + + /** + * Check if current user is subscribed to a thread + * + * @param int $threadId Thread ID + * @return DataResponse, array{}> + * + * 200: Subscription status returned + */ + #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/threads/{threadId}/subscribe')] + public function isSubscribed(int $threadId): DataResponse { + try { + $user = $this->userSession->getUser(); + if (!$user) { + return new DataResponse(['error' => 'User not authenticated'], Http::STATUS_UNAUTHORIZED); + } + + $isSubscribed = $this->subscriptionMapper->isUserSubscribed($user->getUID(), $threadId); + return new DataResponse(['isSubscribed' => $isSubscribed]); + } catch (\Exception $e) { + $this->logger->error('Error checking thread subscription status: ' . $e->getMessage()); + return new DataResponse(['error' => 'Failed to check subscription status'], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + + /** + * Get all threads the current user is subscribed to + * + * @return DataResponse>, array{}> + * + * 200: Thread subscriptions returned + */ + #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/thread-subscriptions')] + public function getUserSubscriptions(): DataResponse { + try { + $user = $this->userSession->getUser(); + if (!$user) { + return new DataResponse(['error' => 'User not authenticated'], Http::STATUS_UNAUTHORIZED); + } + + $subscriptions = $this->subscriptionMapper->findByUserId($user->getUID()); + return new DataResponse(array_map(fn ($r) => $r->jsonSerialize(), $subscriptions)); + } catch (\Exception $e) { + $this->logger->error('Error fetching user thread subscriptions: ' . $e->getMessage()); + return new DataResponse(['error' => 'Failed to fetch thread subscriptions'], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } +} diff --git a/lib/Db/PostMapper.php b/lib/Db/PostMapper.php index 3bc2fd5..6aa7f2a 100644 --- a/lib/Db/PostMapper.php +++ b/lib/Db/PostMapper.php @@ -156,6 +156,30 @@ class PostMapper extends QBMapper { return (int)($row['count'] ?? 0); } + /** + * Count unread posts in a thread after a specific post ID + * + * @param int $threadId Thread ID + * @param int $afterPostId Post ID to count after (0 to count all posts) + * @return int Number of posts after the given post ID + */ + public function countUnreadInThread(int $threadId, int $afterPostId = 0): int { + $qb = $this->db->getQueryBuilder(); + $qb->select($qb->func()->count('*', 'count')) + ->from($this->getTableName()) + ->where($qb->expr()->eq('thread_id', $qb->createNamedParameter($threadId, IQueryBuilder::PARAM_INT))) + ->andWhere($qb->expr()->isNull('deleted_at')); + + if ($afterPostId > 0) { + $qb->andWhere($qb->expr()->gt('id', $qb->createNamedParameter($afterPostId, IQueryBuilder::PARAM_INT))); + } + + $result = $qb->executeQuery(); + $row = $result->fetch(); + $result->closeCursor(); + return (int)($row['count'] ?? 0); + } + /** * Search posts by content (replies only, excluding first posts) * diff --git a/lib/Db/Thread.php b/lib/Db/Thread.php index b413d01..4651e69 100644 --- a/lib/Db/Thread.php +++ b/lib/Db/Thread.php @@ -114,6 +114,21 @@ class Thread extends Entity implements JsonSerializable { $thread['categoryName'] = null; } + // Add subscription status for the current user + try { + $userSession = \OC::$server->get(\OCP\IUserSession::class); + $user = $userSession->getUser(); + if ($user) { + $subscriptionMapper = \OC::$server->get(\OCA\Forum\Db\ThreadSubscriptionMapper::class); + $thread['isSubscribed'] = $subscriptionMapper->isUserSubscribed($user->getUID(), $thread['id']); + } else { + $thread['isSubscribed'] = false; + } + } catch (\Exception $e) { + // If there's an error checking subscription, default to false + $thread['isSubscribed'] = false; + } + return $thread; } } diff --git a/lib/Db/ThreadSubscription.php b/lib/Db/ThreadSubscription.php new file mode 100644 index 0000000..b615db0 --- /dev/null +++ b/lib/Db/ThreadSubscription.php @@ -0,0 +1,44 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Db; + +use JsonSerializable; + +use OCP\AppFramework\Db\Entity; + +/** + * @method int getId() + * @method void setId(int $value) + * @method string getUserId() + * @method void setUserId(string $value) + * @method int getThreadId() + * @method void setThreadId(int $value) + * @method int getCreatedAt() + * @method void setCreatedAt(int $value) + */ +class ThreadSubscription extends Entity implements JsonSerializable { + protected $userId; + protected $threadId; + protected $createdAt; + + public function __construct() { + $this->addType('id', 'integer'); + $this->addType('userId', 'string'); + $this->addType('threadId', 'integer'); + $this->addType('createdAt', 'integer'); + } + + public function jsonSerialize(): array { + return [ + 'id' => $this->getId(), + 'userId' => $this->getUserId(), + 'threadId' => $this->getThreadId(), + 'createdAt' => $this->getCreatedAt(), + ]; + } +} diff --git a/lib/Db/ThreadSubscriptionMapper.php b/lib/Db/ThreadSubscriptionMapper.php new file mode 100644 index 0000000..35cfda5 --- /dev/null +++ b/lib/Db/ThreadSubscriptionMapper.php @@ -0,0 +1,142 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Db; + +use OCA\Forum\AppInfo\Application; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +/** + * @template-extends QBMapper + */ +class ThreadSubscriptionMapper extends QBMapper { + public function __construct( + IDBConnection $db, + ) { + parent::__construct($db, Application::tableName('forum_thread_subs'), ThreadSubscription::class); + } + + /** + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws DoesNotExistException + */ + public function find(int $id): ThreadSubscription { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr() + ->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)) + ); + return $this->findEntity($qb); + } + + /** + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws DoesNotExistException + */ + public function findByUserAndThread(string $userId, int $threadId): ThreadSubscription { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) + ) + ->andWhere( + $qb->expr()->eq('thread_id', $qb->createNamedParameter($threadId, IQueryBuilder::PARAM_INT)) + ); + return $this->findEntity($qb); + } + + /** + * Check if a user is subscribed to a thread + */ + public function isUserSubscribed(string $userId, int $threadId): bool { + try { + $this->findByUserAndThread($userId, $threadId); + return true; + } catch (DoesNotExistException $e) { + return false; + } + } + + /** + * Get all subscribed users for a thread + * + * @return array + */ + public function findByThread(int $threadId): array { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('thread_id', $qb->createNamedParameter($threadId, IQueryBuilder::PARAM_INT)) + ); + return $this->findEntities($qb); + } + + /** + * Get all thread subscriptions for a user + * + * @return array + */ + public function findByUserId(string $userId): array { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + $qb->select('*') + ->from($this->getTableName()) + ->where( + $qb->expr()->eq('user_id', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)) + ); + return $this->findEntities($qb); + } + + /** + * Subscribe a user to a thread + */ + public function subscribe(string $userId, int $threadId): ThreadSubscription { + // Check if already subscribed + if ($this->isUserSubscribed($userId, $threadId)) { + return $this->findByUserAndThread($userId, $threadId); + } + + // Create new subscription + $subscription = new ThreadSubscription(); + $subscription->setUserId($userId); + $subscription->setThreadId($threadId); + $subscription->setCreatedAt(time()); + return $this->insert($subscription); + } + + /** + * Unsubscribe a user from a thread + */ + public function unsubscribe(string $userId, int $threadId): void { + try { + $subscription = $this->findByUserAndThread($userId, $threadId); + $this->delete($subscription); + } catch (DoesNotExistException $e) { + // Already not subscribed, nothing to do + } + } + + /** + * @return array + */ + public function findAll(): array { + /* @var $qb IQueryBuilder */ + $qb = $this->db->getQueryBuilder(); + $qb->select('*')->from($this->getTableName()); + return $this->findEntities($qb); + } +} diff --git a/lib/Migration/Version2Date20251114222614.php b/lib/Migration/Version2Date20251114222614.php new file mode 100644 index 0000000..6b6d0ca --- /dev/null +++ b/lib/Migration/Version2Date20251114222614.php @@ -0,0 +1,75 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version2Date20251114222614 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + */ + public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $this->createForumThreadSubsTable($schema); + + return $schema; + } + + private function createForumThreadSubsTable(ISchemaWrapper $schema): void { + if ($schema->hasTable('forum_thread_subs')) { + return; + } + + $table = $schema->createTable('forum_thread_subs'); + $table->addColumn('id', 'bigint', [ + 'autoincrement' => true, + 'notnull' => true, + 'unsigned' => true, + ]); + $table->addColumn('user_id', 'string', [ + 'notnull' => true, + 'length' => 64, + ]); + $table->addColumn('thread_id', 'bigint', [ + 'notnull' => true, + 'unsigned' => true, + ]); + $table->addColumn('created_at', 'integer', [ + 'notnull' => true, + 'unsigned' => true, + ]); + $table->setPrimaryKey(['id']); + $table->addIndex(['user_id'], 'thread_subs_uid_idx'); + $table->addIndex(['thread_id'], 'thread_subs_tid_idx'); + $table->addUniqueIndex(['user_id', 'thread_id'], 'thread_subs_uniq_idx'); + } + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } +} diff --git a/lib/Notification/Notifier.php b/lib/Notification/Notifier.php new file mode 100644 index 0000000..60b8e36 --- /dev/null +++ b/lib/Notification/Notifier.php @@ -0,0 +1,112 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Notification; + +use OCA\Forum\AppInfo\Application; +use OCP\L10N\IFactory; +use OCP\Notification\INotification; +use OCP\Notification\INotifier; +use OCP\Notification\UnknownNotificationException; + +class Notifier implements INotifier { + public function __construct( + private IFactory $l10nFactory, + ) { + } + + /** + * Identifier of the notifier, only use [a-z0-9_] + */ + public function getID(): string { + return Application::APP_ID; + } + + /** + * Human-readable name describing the notifier + */ + public function getName(): string { + return $this->l10nFactory->get(Application::APP_ID)->t('Forum'); + } + + /** + * Prepare the notification for display + * + * @param INotification $notification + * @param string $languageCode The code of the language that should be used to prepare the notification + * @return INotification + * @throws \InvalidArgumentException When the notification was not prepared by this app or is not of the expected type + */ + public function prepare(INotification $notification, string $languageCode): INotification { + if ($notification->getApp() !== Application::APP_ID) { + throw new UnknownNotificationException(); + } + + $l = $this->l10nFactory->get(Application::APP_ID, $languageCode); + + switch ($notification->getSubject()) { + case 'new_posts': + $parameters = $notification->getSubjectParameters(); + $threadId = $parameters['threadId'] ?? 0; + $threadTitle = $parameters['threadTitle'] ?? 'Unknown Thread'; + $postCount = $parameters['postCount'] ?? 1; + + // Set the rich subject with thread title + $notification->setRichSubject( + $l->n( + 'New reply in {thread}', + '{count} new replies in {thread}', + $postCount + ), + [ + 'thread' => [ + 'type' => 'highlight', + 'id' => (string)$threadId, + 'name' => $threadTitle, + ], + 'count' => [ + 'type' => 'highlight', + 'id' => (string)$postCount, + 'name' => (string)$postCount, + ], + ] + ); + + // Set the parsed subject from rich subject + $this->setParsedSubjectFromRichSubject($notification); + + return $notification; + + default: + throw new UnknownNotificationException(); + } + } + + /** + * Helper function to set the parsed subject from the rich subject + * This extracts the parameter names from rich subject placeholders + * + * @param INotification $notification + */ + protected function setParsedSubjectFromRichSubject(INotification $notification): void { + $placeholders = $replacements = []; + $richParams = $notification->getRichSubjectParameters(); + $richSubject = $notification->getRichSubject(); + + foreach ($richParams as $placeholder => $parameter) { + $placeholders[] = '{' . $placeholder . '}'; + if (isset($parameter['type']) && $parameter['type'] === 'file') { + $replacements[] = $parameter['path'] ?? $parameter['name'] ?? ''; + } else { + $replacements[] = $parameter['name'] ?? ''; + } + } + + $parsedSubject = str_replace($placeholders, $replacements, $richSubject); + $notification->setParsedSubject($parsedSubject); + } +} diff --git a/lib/Service/NotificationService.php b/lib/Service/NotificationService.php new file mode 100644 index 0000000..fff0fa5 --- /dev/null +++ b/lib/Service/NotificationService.php @@ -0,0 +1,155 @@ + +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\Forum\Service; + +use OCA\Forum\Db\PostMapper; +use OCA\Forum\Db\ReadMarkerMapper; +use OCA\Forum\Db\ThreadMapper; +use OCA\Forum\Db\ThreadSubscriptionMapper; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\IURLGenerator; +use OCP\Notification\IManager as INotificationManager; +use Psr\Log\LoggerInterface; + +class NotificationService { + public function __construct( + private INotificationManager $notificationManager, + private ThreadSubscriptionMapper $subscriptionMapper, + private ThreadMapper $threadMapper, + private PostMapper $postMapper, + private ReadMarkerMapper $readMarkerMapper, + private IURLGenerator $urlGenerator, + private LoggerInterface $logger, + ) { + } + + /** + * Notify subscribed users when a new post is added to a thread + */ + public function notifyThreadSubscribers(int $threadId, int $postId, string $authorId): void { + // Get all subscribed users for this thread + $subscriptions = $this->subscriptionMapper->findByThread($threadId); + + // Get thread information + try { + $thread = $this->threadMapper->find($threadId); + } catch (\Exception $e) { + $this->logger->warning('Thread not found for notifications', [ + 'threadId' => $threadId, + 'error' => $e->getMessage(), + ]); + return; + } + + foreach ($subscriptions as $subscription) { + $userId = $subscription->getUserId(); + + // Don't notify the author of the post + if ($userId === $authorId) { + continue; + } + + // Create or update notification (collating multiple posts) + $this->createOrUpdateNotification($userId, $threadId, $postId, $thread->getTitle(), $thread->getSlug()); + } + } + + /** + * Create or update a notification for a user about a thread + * This allows collating multiple posts into a single notification + */ + private function createOrUpdateNotification(string $userId, int $threadId, int $postId, string $threadTitle, string $threadSlug): void { + // Calculate the number of unread posts + $postCount = $this->getUnreadPostCount($userId, $threadId, $postId); + + // Mark existing notifications for this thread/user as processed (to update them) + $existingNotification = $this->notificationManager->createNotification(); + $existingNotification->setApp('forum') + ->setUser($userId) + ->setObject('thread', (string)$threadId) + ->setSubject('new_posts'); + $this->notificationManager->markProcessed($existingNotification); + + // Create new notification with updated post count + $notification = $this->notificationManager->createNotification(); + + // Generate the thread link and icon + $threadLink = $this->urlGenerator->linkToRouteAbsolute('forum.page.index') . 't/' . $threadSlug; + $iconPath = $this->urlGenerator->imagePath('forum', 'app-dark.svg'); + $iconUrl = $this->urlGenerator->getAbsoluteURL($iconPath); + + $notification->setApp('forum') + ->setUser($userId) + ->setDateTime(new \DateTime()) + ->setObject('thread', (string)$threadId) + ->setSubject('new_posts', [ + 'threadId' => $threadId, + 'threadTitle' => $threadTitle, + 'threadSlug' => $threadSlug, + 'lastPostId' => $postId, + 'postCount' => $postCount, + ]) + ->setLink($threadLink) + ->setIcon($iconUrl); + + $this->notificationManager->notify($notification); + } + + /** + * Get the count of unread posts for a user in a thread + * Uses an efficient DB COUNT query instead of fetching all posts + */ + private function getUnreadPostCount(string $userId, int $threadId, int $latestPostId): int { + try { + // Get the user's read marker for this thread + $readMarker = $this->readMarkerMapper->findByUserAndThread($userId, $threadId); + $lastReadPostId = $readMarker->getLastReadPostId(); + + // Count posts after the last read post using DB query + $unreadCount = $this->postMapper->countUnreadInThread($threadId, $lastReadPostId); + + return max(1, $unreadCount); // At least 1 (the current post) + } catch (DoesNotExistException $e) { + // No read marker, count all posts in the thread + $count = $this->postMapper->countUnreadInThread($threadId, 0); + + return max(1, $count); // At least 1 + } + } + + /** + * Dismiss notifications for a user when they view a thread + */ + public function dismissThreadNotifications(string $userId, int $threadId): void { + $notification = $this->notificationManager->createNotification(); + $notification->setApp('forum') + ->setUser($userId) + ->setObject('thread', (string)$threadId); + + $this->notificationManager->markProcessed($notification); + } + + /** + * Dismiss notifications when read marker catches up + */ + public function dismissNotificationsIfRead(string $userId, int $threadId, int $lastReadPostId): void { + // Get the thread to check the last post + try { + $thread = $this->threadMapper->find($threadId); + $lastPostId = $thread->getLastPostId(); + + // If user has read up to or past the last post, dismiss notifications + if ($lastPostId && $lastReadPostId >= $lastPostId) { + $this->dismissThreadNotifications($userId, $threadId); + } + } catch (\Exception $e) { + // Thread not found or error, just dismiss anyway + $this->dismissThreadNotifications($userId, $threadId); + } + } +} diff --git a/openapi.json b/openapi.json index 4470eeb..f4d338b 100644 --- a/openapi.json +++ b/openapi.json @@ -1,8245 +1,7619 @@ { - "openapi": "3.0.3", - "info": { - "title": "forum", - "version": "0.0.1", - "description": "A community-driven forum built right into your Nextcloud instance", - "license": { - "name": "agpl" - } + "openapi": "3.0.3", + "info": { + "title": "forum", + "version": "0.0.1", + "description": "A community-driven forum built right into your Nextcloud instance", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } }, - "components": { - "securitySchemes": { - "basic_auth": { - "type": "http", - "scheme": "basic" - }, - "bearer_auth": { - "type": "http", - "scheme": "bearer" + "schemas": { + "OCSMeta": { + "type": "object", + "required": ["status", "statuscode"], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/forum/api/admin/dashboard": { + "get": { + "operationId": "admin-dashboard", + "summary": "Get dashboard statistics", + "tags": ["admin"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true } - }, - "schemas": { - "OCSMeta": { + } + ], + "responses": { + "200": { + "description": "Dashboard stats returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/admin/users": { + "get": { + "operationId": "admin-users", + "summary": "Get all forum users with their roles", + "tags": ["admin"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Users list returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["users"], + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/admin/settings": { + "get": { + "operationId": "admin-get-settings", + "summary": "Get general forum settings", + "tags": ["admin"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Settings returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "admin-update-settings", + "summary": "Update general forum settings", + "tags": ["admin"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { "type": "object", - "required": [ - "status", - "statuscode" - ], "properties": { - "status": { - "type": "string" - }, - "statuscode": { - "type": "integer" - }, - "message": { - "type": "string" - }, - "totalitems": { - "type": "string" - }, - "itemsperpage": { - "type": "string" - } + "title": { + "type": "string", + "nullable": true, + "default": null, + "description": "Forum title" + }, + "subtitle": { + "type": "string", + "nullable": true, + "default": null, + "description": "Forum subtitle" + } } + } } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } } + } }, - "paths": { - "/ocs/v2.php/apps/forum/api/admin/dashboard": { - "get": { - "operationId": "admin-dashboard", - "summary": "Get dashboard statistics", - "tags": [ - "admin" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Dashboard stats returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } + "/ocs/v2.php/apps/forum/api/bbcodes": { + "get": { + "operationId": "bb_code-index", + "summary": "Get all BBCodes (excludes builtin codes)", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true } - }, - "/ocs/v2.php/apps/forum/api/admin/users": { - "get": { - "operationId": "admin-users", - "summary": "Get all forum users with their roles", - "tags": [ - "admin" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Users list returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "users" - ], - "properties": { - "users": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } + } + ], + "responses": { + "200": { + "description": "BBCodes returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" } + } } + } } + } } + } } - }, - "/ocs/v2.php/apps/forum/api/admin/settings": { - "get": { - "operationId": "admin-get-settings", - "summary": "Get general forum settings", - "tags": [ - "admin" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Settings returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "admin-update-settings", - "summary": "Update general forum settings", - "tags": [ - "admin" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "title": { - "type": "string", - "nullable": true, - "default": null, - "description": "Forum title" - }, - "subtitle": { - "type": "string", - "nullable": true, - "default": null, - "description": "Forum subtitle" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Settings updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/bbcodes": { - "get": { - "operationId": "bb_code-index", - "summary": "Get all BBCodes (excludes builtin codes)", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "BBCodes returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "bb_code-create", - "summary": "Create a new BBCode", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "tag", - "replacement", - "example" - ], - "properties": { - "tag": { - "type": "string", - "description": "BBCode tag name" - }, - "replacement": { - "type": "string", - "description": "Replacement pattern" - }, - "example": { - "type": "string", - "description": "Example usage" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Optional description" - }, - "enabled": { - "type": "boolean", - "default": true, - "description": "Whether BBCode is enabled" - }, - "parseInner": { - "type": "boolean", - "default": true, - "description": "Whether to parse inner BBCode tags" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "BBCode created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/bbcodes/enabled": { - "get": { - "operationId": "bb_code-enabled", - "summary": "Get enabled BBCodes", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Enabled BBCodes returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/bbcodes/builtin": { - "get": { - "operationId": "bb_code-builtin", - "summary": "Get builtin BBCodes (for help dialog)", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Builtin BBCodes returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/bbcodes/{id}": { - "get": { - "operationId": "bb_code-show", - "summary": "Get a single BBCode", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "BBCode ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "BBCode returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "bb_code-update", - "summary": "Update a BBCode", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "tag": { - "type": "string", - "nullable": true, - "default": null, - "description": "BBCode tag name" - }, - "replacement": { - "type": "string", - "nullable": true, - "default": null, - "description": "Replacement pattern" - }, - "example": { - "type": "string", - "nullable": true, - "default": null, - "description": "Example usage" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Description" - }, - "enabled": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Whether BBCode is enabled" - }, - "parseInner": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Whether to parse inner BBCode tags" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "BBCode ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "BBCode updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "bb_code-destroy", - "summary": "Delete a BBCode", - "tags": [ - "bb_code" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "BBCode ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "BBCode deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/headers": { - "get": { - "operationId": "cat_header-index", - "summary": "Get all category headers", - "tags": [ - "cat_header" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category headers returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "cat_header-create", - "summary": "Create a new category header", - "tags": [ - "cat_header" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string", - "description": "Category header name" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category header description" - }, - "sortOrder": { - "type": "integer", - "format": "int64", - "default": 0, - "description": "Sort order" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Category header created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/headers/{id}": { - "get": { - "operationId": "cat_header-show", - "summary": "Get a single category header", - "tags": [ - "cat_header" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category header ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category header returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "cat_header-update", - "summary": "Update a category header", - "tags": [ - "cat_header" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category header name" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category header description" - }, - "sortOrder": { - "type": "integer", - "format": "int64", - "nullable": true, - "default": null, - "description": "Sort order" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category header ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category header updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "cat_header-destroy", - "summary": "Delete a category header", - "tags": [ - "cat_header" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category header ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "migrateToHeaderId", - "in": "query", - "description": "Header ID to migrate categories to (null to delete categories)", - "schema": { - "type": "integer", - "format": "int64", - "nullable": true, - "default": null - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category header deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - }, - "categoriesAffected": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/headers/reorder": { - "post": { - "operationId": "cat_header-reorder", - "summary": "Reorder category headers", - "tags": [ - "cat_header" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "headers" - ], - "properties": { - "headers": { - "type": "array", - "description": "Array of headers with new sort orders", - "items": { - "type": "object", - "required": [ - "id", - "sortOrder" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "sortOrder": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Headers reordered successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories": { - "get": { - "operationId": "category-index", - "summary": "Get all category headers with nested categories", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category headers with nested categories returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "category-create", - "summary": "Create a new category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "headerId", - "name", - "slug" - ], - "properties": { - "headerId": { - "type": "integer", - "format": "int64", - "description": "Category header ID" - }, - "name": { - "type": "string", - "description": "Category name" - }, - "slug": { - "type": "string", - "description": "Category slug" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category description" - }, - "sortOrder": { - "type": "integer", - "format": "int64", - "default": 0, - "description": "Sort order" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Category created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/headers/{headerId}/categories": { - "get": { - "operationId": "category-by-header", - "summary": "Get categories by header ID", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "headerId", - "in": "path", - "description": "Category header ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Categories returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{id}": { - "get": { - "operationId": "category-show", - "summary": "Get a single category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "category-update", - "summary": "Update a category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category name" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category description" - }, - "slug": { - "type": "string", - "nullable": true, - "default": null, - "description": "Category slug" - }, - "sortOrder": { - "type": "integer", - "format": "int64", - "nullable": true, - "default": null, - "description": "Sort order" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "category-destroy", - "summary": "Delete a category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "migrateToCategoryId", - "in": "query", - "description": "Category ID to migrate threads to (null to soft-delete threads)", - "schema": { - "type": "integer", - "format": "int64", - "nullable": true, - "default": null - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - }, - "threadsAffected": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/slug/{slug}": { - "get": { - "operationId": "category-by-slug", - "summary": "Get a category by slug", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "slug", - "in": "path", - "description": "Category slug", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Category returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{id}/thread-count": { - "get": { - "operationId": "category-get-thread-count", - "summary": "Get thread count for a category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread count returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{id}/permissions/{permission}": { - "get": { - "operationId": "category-check-permission", - "summary": "Check if current user has a specific permission on a category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "permission", - "in": "path", - "description": "Permission name (canView, canPost, canReply, canModerate)", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Permission check result", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "hasPermission" - ], - "properties": { - "hasPermission": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{id}/permissions": { - "get": { - "operationId": "category-get-permissions", - "summary": "Get permissions for a category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Permissions returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "category-update-permissions", - "summary": "Update permissions for a category", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "permissions": { - "type": "array", - "description": "Permissions array", - "items": { - "type": "object", - "required": [ - "roleId", - "canView", - "canModerate" - ], - "properties": { - "roleId": { - "type": "integer", - "format": "int64" - }, - "canView": { - "type": "boolean" - }, - "canModerate": { - "type": "boolean" - } - } - } - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Permissions updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/reorder": { - "post": { - "operationId": "category-reorder", - "summary": "Reorder categories", - "tags": [ - "category" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "categories" - ], - "properties": { - "categories": { - "type": "array", - "description": "Array of categories with new sort orders", - "items": { - "type": "object", - "required": [ - "id", - "sortOrder" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "sortOrder": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Categories reordered successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/users": { - "get": { - "operationId": "forum_user-index", - "summary": "Get all user statistics", - "tags": [ - "forum_user" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "User statistics returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "forum_user-create", - "summary": "Create user stats Note: This is typically not needed as stats are auto-created on first post", - "tags": [ - "forum_user" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "userId" - ], - "properties": { - "userId": { - "type": "string", - "description": "Nextcloud user ID" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "User stats created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/users/{userId}": { - "get": { - "operationId": "forum_user-show", - "summary": "Get user statistics by Nextcloud user ID Special case: use \"me\" to get current user stats", - "tags": [ - "forum_user" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "userId", - "in": "path", - "description": "Nextcloud user ID or \"me\" for current user", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "User stats returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "404": { - "description": "User has no stats (hasn't posted yet)", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "User not authenticated (when using \"me\")", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "error" - ], - "properties": { - "error": { - "type": "string" - } - } - } - } - } - } - }, - { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - ] - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{threadId}/posts": { - "get": { - "operationId": "post-by-thread", - "summary": "Get posts by thread", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "threadId", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of posts to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Posts returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/users/{authorId}/posts": { - "get": { - "operationId": "post-by-author", - "summary": "Get posts by author", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "authorId", - "in": "path", - "description": "Author user ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of posts to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "excludeFirstPosts", - "in": "query", - "description": "Whether to exclude first posts (1 or 0)", - "schema": { - "type": "string", - "default": "0" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Posts returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/posts/{id}": { - "get": { - "operationId": "post-show", - "summary": "Get a single post", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Post ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Post returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "post-update", - "summary": "Update a post", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "content": { - "type": "string", - "nullable": true, - "default": null, - "description": "Post content" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Post ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Post updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "post-destroy", - "summary": "Delete a post (soft delete)", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Post ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Post deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/posts/slug/{slug}": { - "get": { - "operationId": "post-by-slug", - "summary": "Get a post by slug", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "slug", - "in": "path", - "description": "Post slug", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Post returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/posts": { - "post": { - "operationId": "post-create", - "summary": "Create a new post", - "tags": [ - "post" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "threadId", - "content" - ], - "properties": { - "threadId": { - "type": "integer", - "format": "int64", - "description": "Thread ID" - }, - "content": { - "type": "string", - "description": "Post content" - }, - "slug": { - "type": "string", - "nullable": true, - "default": null, - "description": "Post slug (auto-generated if not provided)" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Post created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/posts/{postId}/reactions": { - "get": { - "operationId": "reaction-by-post", - "summary": "Get reactions by post", - "tags": [ - "reaction" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "postId", - "in": "path", - "description": "Post ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Reactions returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/reactions/by-posts": { - "post": { - "operationId": "reaction-by-posts", - "summary": "Get reactions for multiple posts (for performance)", - "tags": [ - "reaction" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "postIds" - ], - "properties": { - "postIds": { - "type": "array", - "description": "Array of post IDs", - "items": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Reactions returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/reactions/{id}": { - "get": { - "operationId": "reaction-show", - "summary": "Get a single reaction", - "tags": [ - "reaction" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Reaction ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Reaction returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "reaction-destroy", - "summary": "Delete a reaction", - "tags": [ - "reaction" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Reaction ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Reaction deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/reactions": { - "post": { - "operationId": "reaction-create", - "summary": "Create a new reaction", - "tags": [ - "reaction" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "postId", - "reactionType" - ], - "properties": { - "postId": { - "type": "integer", - "format": "int64", - "description": "Post ID" - }, - "reactionType": { - "type": "string", - "description": "Type of reaction" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Reaction created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/reactions/toggle": { - "post": { - "operationId": "reaction-toggle", - "summary": "Toggle a reaction (add if not exists, remove if exists)", - "tags": [ - "reaction" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "postId", - "reactionType" - ], - "properties": { - "postId": { - "type": "integer", - "format": "int64", - "description": "Post ID" - }, - "reactionType": { - "type": "string", - "description": "Type of reaction (emoji)" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Reaction toggled", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "action" - ], - "properties": { - "action": { - "type": "string" - }, - "reaction": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/read-markers": { - "get": { - "operationId": "read_marker-index", - "summary": "Get read markers for multiple threads", - "tags": [ - "read_marker" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "threadIds", - "in": "query", - "description": "Array of thread IDs (comma-separated in query string)", - "schema": { - "type": "string", - "default": "" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Read markers returned (keyed by thread ID)", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object", - "required": [ - "threadId", - "lastReadPostId", - "readAt" - ], - "properties": { - "threadId": { - "type": "integer", - "format": "int64" - }, - "lastReadPostId": { - "type": "integer", - "format": "int64" - }, - "readAt": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "read_marker-create", - "summary": "Mark a thread as read", - "tags": [ - "read_marker" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "threadId", - "lastReadPostId" - ], - "properties": { - "threadId": { - "type": "integer", - "format": "int64", - "description": "Thread ID" - }, - "lastReadPostId": { - "type": "integer", - "format": "int64", - "description": "Last read post ID" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread marked as read", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{threadId}/read-marker": { - "get": { - "operationId": "read_marker-show", - "summary": "Get read marker for a specific thread", - "tags": [ - "read_marker" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "threadId", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Read marker returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/read-markers/{id}": { - "delete": { - "operationId": "read_marker-destroy", - "summary": "Delete a read marker", - "tags": [ - "read_marker" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Read marker ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Read marker deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/roles": { - "get": { - "operationId": "role-index", - "summary": "Get all roles", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Roles returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "role-create", - "summary": "Create a new role", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "name" - ], - "properties": { - "name": { - "type": "string", - "description": "Role name" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Role description" - }, - "canAccessAdminTools": { - "type": "boolean", - "default": false, - "description": "Can access admin tools" - }, - "canEditRoles": { - "type": "boolean", - "default": false, - "description": "Can edit roles" - }, - "canEditCategories": { - "type": "boolean", - "default": false, - "description": "Can edit categories" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Role created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/roles/{id}": { - "get": { - "operationId": "role-show", - "summary": "Get a single role", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Role returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "role-update", - "summary": "Update a role", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true, - "default": null, - "description": "Role name" - }, - "description": { - "type": "string", - "nullable": true, - "default": null, - "description": "Role description" - }, - "canAccessAdminTools": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Can access admin tools" - }, - "canEditRoles": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Can edit roles" - }, - "canEditCategories": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Can edit categories" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Role updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "role-destroy", - "summary": "Delete a role", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Role deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/roles/{id}/permissions": { - "get": { - "operationId": "role-get-permissions", - "summary": "Get permissions for a role", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Permissions returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "role-update-permissions", - "summary": "Update permissions for a role", - "tags": [ - "role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "permissions": { - "type": "array", - "description": "Permissions array", - "items": { - "type": "object", - "required": [ - "categoryId", - "canView", - "canModerate" - ], - "properties": { - "categoryId": { - "type": "integer", - "format": "int64" - }, - "canView": { - "type": "boolean" - }, - "canModerate": { - "type": "boolean" - } - } - } - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Permissions updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/search": { - "get": { - "operationId": "search-index", - "summary": "Search forum threads and posts", - "tags": [ - "search" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "q", - "in": "query", - "description": "Search query (supports quoted phrases, AND/OR operators, parentheses, -exclusions)", - "schema": { - "type": "string", - "default": "" - } - }, - { - "name": "searchThreads", - "in": "query", - "description": "Include threads in search (title + first post content)", - "schema": { - "type": "boolean", - "default": true - } - }, - { - "name": "searchPosts", - "in": "query", - "description": "Include reply posts in search", - "schema": { - "type": "boolean", - "default": true - } - }, - { - "name": "categoryId", - "in": "query", - "description": "Optional category ID filter", - "schema": { - "type": "integer", - "format": "int64", - "nullable": true, - "default": null - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum results per type", - "schema": { - "type": "integer", - "format": "int64", - "default": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "Results offset per type", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Search results returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "threads", - "posts", - "threadCount", - "postCount", - "query" - ], - "properties": { - "threads": { - "type": "object", - "additionalProperties": { - "type": "object" - } - }, - "posts": { - "type": "object", - "additionalProperties": { - "type": "object" - } - }, - "threadCount": { - "type": "integer", - "format": "int64" - }, - "postCount": { - "type": "integer", - "format": "int64" - }, - "query": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads": { - "get": { - "operationId": "thread-index", - "summary": "Get all threads", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Threads returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "post": { - "operationId": "thread-create", - "summary": "Create a new thread with initial post", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "categoryId", - "title", - "content" - ], - "properties": { - "categoryId": { - "type": "integer", - "format": "int64", - "description": "Category ID" - }, - "title": { - "type": "string", - "description": "Thread title" - }, - "content": { - "type": "string", - "description": "Initial post content" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Thread created", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/categories/{categoryId}/threads": { - "get": { - "operationId": "thread-by-category", - "summary": "Get threads by category", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "categoryId", - "in": "path", - "description": "Category ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of threads to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Threads returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/users/{authorId}/threads": { - "get": { - "operationId": "thread-by-author", - "summary": "Get threads by author", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "authorId", - "in": "path", - "description": "Author user ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of threads to return", - "schema": { - "type": "integer", - "format": "int64", - "default": 50 - } - }, - { - "name": "offset", - "in": "query", - "description": "Offset for pagination", - "schema": { - "type": "integer", - "format": "int64", - "default": 0 - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Threads returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{id}": { - "get": { - "operationId": "thread-show", - "summary": "Get a single thread", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "incrementView", - "in": "query", - "description": "Whether to increment view count (1 or 0)", - "schema": { - "type": "string", - "default": "1" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "put": { - "operationId": "thread-update", - "summary": "Update a thread", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "title": { - "type": "string", - "nullable": true, - "default": null, - "description": "Thread title" - }, - "isLocked": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Whether the thread is locked" - }, - "isPinned": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Whether the thread is pinned" - }, - "isHidden": { - "type": "boolean", - "nullable": true, - "default": null, - "description": "Whether the thread is hidden" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - }, - "delete": { - "operationId": "thread-destroy", - "summary": "Delete a thread (soft delete)", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success", - "categorySlug" - ], - "properties": { - "success": { - "type": "boolean" - }, - "categorySlug": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/slug/{slug}": { - "get": { - "operationId": "thread-by-slug", - "summary": "Get a thread by slug", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "slug", - "in": "path", - "description": "Thread slug", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "incrementView", - "in": "query", - "description": "Whether to increment view count (1 or 0)", - "schema": { - "type": "string", - "default": "1" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{id}/lock": { - "put": { - "operationId": "thread-set-locked", - "summary": "Toggle thread lock status", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "locked" - ], - "properties": { - "locked": { - "type": "boolean", - "description": "New lock status" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread lock status updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/threads/{id}/pin": { - "put": { - "operationId": "thread-set-pinned", - "summary": "Toggle thread pin status", - "tags": [ - "thread" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "pinned" - ], - "properties": { - "pinned": { - "type": "boolean", - "description": "New pin status" - } - } - } - } - } - }, - "parameters": [ - { - "name": "id", - "in": "path", - "description": "Thread ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Thread pin status updated", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/users/{userId}/roles": { - "get": { - "operationId": "user_role-by-user", - "summary": "Get roles for a user", - "tags": [ - "user_role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "userId", - "in": "path", - "description": "Nextcloud user ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "User roles returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/roles/{roleId}/users": { - "get": { - "operationId": "user_role-by-role", - "summary": "Get users with a specific role", - "tags": [ - "user_role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "roleId", - "in": "path", - "description": "Role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "User roles returned", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/user-roles": { - "post": { - "operationId": "user_role-create", - "summary": "Assign a role to a user", - "tags": [ - "user_role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "userId", - "roleId" - ], - "properties": { - "userId": { - "type": "string", - "description": "Nextcloud user ID" - }, - "roleId": { - "type": "integer", - "format": "int64", - "description": "Role ID" - } - } - } - } - } - }, - "parameters": [ - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "201": { - "description": "Role assigned to user", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } - } - } - } - }, - "/ocs/v2.php/apps/forum/api/user-roles/{id}": { - "delete": { - "operationId": "user_role-destroy", - "summary": "Remove a role from a user", - "tags": [ - "user_role" - ], - "security": [ - { - "bearer_auth": [] - }, - { - "basic_auth": [] - } - ], - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User role ID", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "OCS-APIRequest", - "in": "header", - "description": "Required to be true for the API request to pass", - "required": true, - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "Role removed from user", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": { - "type": "object", - "required": [ - "success" - ], - "properties": { - "success": { - "type": "boolean" - } - } - } - } - } - } - } - } - } - }, - "401": { - "description": "Current user is not logged in", - "content": { - "application/json": { - "schema": { - "type": "object", - "required": [ - "ocs" - ], - "properties": { - "ocs": { - "type": "object", - "required": [ - "meta", - "data" - ], - "properties": { - "meta": { - "$ref": "#/components/schemas/OCSMeta" - }, - "data": {} - } - } - } - } - } - } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } } + } } + } } + } } + }, + "post": { + "operationId": "bb_code-create", + "summary": "Create a new BBCode", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["tag", "replacement", "example"], + "properties": { + "tag": { + "type": "string", + "description": "BBCode tag name" + }, + "replacement": { + "type": "string", + "description": "Replacement pattern" + }, + "example": { + "type": "string", + "description": "Example usage" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Optional description" + }, + "enabled": { + "type": "boolean", + "default": true, + "description": "Whether BBCode is enabled" + }, + "parseInner": { + "type": "boolean", + "default": true, + "description": "Whether to parse inner BBCode tags" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "BBCode created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } }, - "tags": [ - { - "name": "forum_user", - "description": "Controller for user statistics Note: User stats are automatically created on first post/thread" + "/ocs/v2.php/apps/forum/api/bbcodes/enabled": { + "get": { + "operationId": "bb_code-enabled", + "summary": "Get enabled BBCodes", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Enabled BBCodes returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } } - ] + } + }, + "/ocs/v2.php/apps/forum/api/bbcodes/builtin": { + "get": { + "operationId": "bb_code-builtin", + "summary": "Get builtin BBCodes (for help dialog)", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Builtin BBCodes returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/bbcodes/{id}": { + "get": { + "operationId": "bb_code-show", + "summary": "Get a single BBCode", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "BBCode ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "BBCode returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "bb_code-update", + "summary": "Update a BBCode", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "tag": { + "type": "string", + "nullable": true, + "default": null, + "description": "BBCode tag name" + }, + "replacement": { + "type": "string", + "nullable": true, + "default": null, + "description": "Replacement pattern" + }, + "example": { + "type": "string", + "nullable": true, + "default": null, + "description": "Example usage" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Description" + }, + "enabled": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Whether BBCode is enabled" + }, + "parseInner": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Whether to parse inner BBCode tags" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "BBCode ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "BBCode updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "bb_code-destroy", + "summary": "Delete a BBCode", + "tags": ["bb_code"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "BBCode ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "BBCode deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/headers": { + "get": { + "operationId": "cat_header-index", + "summary": "Get all category headers", + "tags": ["cat_header"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category headers returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "cat_header-create", + "summary": "Create a new category header", + "tags": ["cat_header"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Category header name" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category header description" + }, + "sortOrder": { + "type": "integer", + "format": "int64", + "default": 0, + "description": "Sort order" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Category header created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/headers/{id}": { + "get": { + "operationId": "cat_header-show", + "summary": "Get a single category header", + "tags": ["cat_header"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category header ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category header returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "cat_header-update", + "summary": "Update a category header", + "tags": ["cat_header"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category header name" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category header description" + }, + "sortOrder": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null, + "description": "Sort order" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category header ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category header updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "cat_header-destroy", + "summary": "Delete a category header", + "tags": ["cat_header"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category header ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "migrateToHeaderId", + "in": "query", + "description": "Header ID to migrate categories to (null to delete categories)", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category header deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + }, + "categoriesAffected": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/headers/reorder": { + "post": { + "operationId": "cat_header-reorder", + "summary": "Reorder category headers", + "tags": ["cat_header"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["headers"], + "properties": { + "headers": { + "type": "array", + "description": "Array of headers with new sort orders", + "items": { + "type": "object", + "required": ["id", "sortOrder"], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "sortOrder": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Headers reordered successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories": { + "get": { + "operationId": "category-index", + "summary": "Get all category headers with nested categories", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category headers with nested categories returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "category-create", + "summary": "Create a new category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["headerId", "name", "slug"], + "properties": { + "headerId": { + "type": "integer", + "format": "int64", + "description": "Category header ID" + }, + "name": { + "type": "string", + "description": "Category name" + }, + "slug": { + "type": "string", + "description": "Category slug" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category description" + }, + "sortOrder": { + "type": "integer", + "format": "int64", + "default": 0, + "description": "Sort order" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Category created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/headers/{headerId}/categories": { + "get": { + "operationId": "category-by-header", + "summary": "Get categories by header ID", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "headerId", + "in": "path", + "description": "Category header ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Categories returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/{id}": { + "get": { + "operationId": "category-show", + "summary": "Get a single category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "category-update", + "summary": "Update a category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category name" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category description" + }, + "slug": { + "type": "string", + "nullable": true, + "default": null, + "description": "Category slug" + }, + "sortOrder": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null, + "description": "Sort order" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "category-destroy", + "summary": "Delete a category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "migrateToCategoryId", + "in": "query", + "description": "Category ID to migrate threads to (null to soft-delete threads)", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + }, + "threadsAffected": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/slug/{slug}": { + "get": { + "operationId": "category-by-slug", + "summary": "Get a category by slug", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Category slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Category returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/{id}/thread-count": { + "get": { + "operationId": "category-get-thread-count", + "summary": "Get thread count for a category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread count returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["count"], + "properties": { + "count": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/{id}/permissions/{permission}": { + "get": { + "operationId": "category-check-permission", + "summary": "Check if current user has a specific permission on a category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "permission", + "in": "path", + "description": "Permission name (canView, canPost, canReply, canModerate)", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Permission check result", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["hasPermission"], + "properties": { + "hasPermission": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/{id}/permissions": { + "get": { + "operationId": "category-get-permissions", + "summary": "Get permissions for a category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Permissions returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "category-update-permissions", + "summary": "Update permissions for a category", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["permissions"], + "properties": { + "permissions": { + "type": "array", + "description": "Permissions array", + "items": { + "type": "object", + "required": ["roleId", "canView", "canModerate"], + "properties": { + "roleId": { + "type": "integer", + "format": "int64" + }, + "canView": { + "type": "boolean" + }, + "canModerate": { + "type": "boolean" + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Permissions updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/reorder": { + "post": { + "operationId": "category-reorder", + "summary": "Reorder categories", + "tags": ["category"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["categories"], + "properties": { + "categories": { + "type": "array", + "description": "Array of categories with new sort orders", + "items": { + "type": "object", + "required": ["id", "sortOrder"], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "sortOrder": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Categories reordered successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/users": { + "get": { + "operationId": "forum_user-index", + "summary": "Get all user statistics", + "tags": ["forum_user"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "User statistics returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "forum_user-create", + "summary": "Create user stats Note: This is typically not needed as stats are auto-created on first post", + "tags": ["forum_user"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "string", + "description": "Nextcloud user ID" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "User stats created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/users/{userId}": { + "get": { + "operationId": "forum_user-show", + "summary": "Get user statistics by Nextcloud user ID Special case: use \"me\" to get current user stats", + "tags": ["forum_user"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "Nextcloud user ID or \"me\" for current user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "User stats returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "404": { + "description": "User has no stats (hasn't posted yet)", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["error"], + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "User not authenticated (when using \"me\")", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["error"], + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + ] + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/{threadId}/posts": { + "get": { + "operationId": "post-by-thread", + "summary": "Get posts by thread", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "threadId", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of posts to return", + "schema": { + "type": "integer", + "format": "int64", + "default": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "schema": { + "type": "integer", + "format": "int64", + "default": 0 + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Posts returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/users/{authorId}/posts": { + "get": { + "operationId": "post-by-author", + "summary": "Get posts by author", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "authorId", + "in": "path", + "description": "Author user ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of posts to return", + "schema": { + "type": "integer", + "format": "int64", + "default": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "schema": { + "type": "integer", + "format": "int64", + "default": 0 + } + }, + { + "name": "excludeFirstPosts", + "in": "query", + "description": "Whether to exclude first posts (1 or 0)", + "schema": { + "type": "string", + "default": "0" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Posts returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/posts/{id}": { + "get": { + "operationId": "post-show", + "summary": "Get a single post", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Post ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Post returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "post-update", + "summary": "Update a post", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "content": { + "type": "string", + "nullable": true, + "default": null, + "description": "Post content" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Post ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Post updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "post-destroy", + "summary": "Delete a post (soft delete)", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Post ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Post deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/posts/slug/{slug}": { + "get": { + "operationId": "post-by-slug", + "summary": "Get a post by slug", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Post slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Post returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/posts": { + "post": { + "operationId": "post-create", + "summary": "Create a new post", + "tags": ["post"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["threadId", "content"], + "properties": { + "threadId": { + "type": "integer", + "format": "int64", + "description": "Thread ID" + }, + "content": { + "type": "string", + "description": "Post content" + }, + "slug": { + "type": "string", + "nullable": true, + "default": null, + "description": "Post slug (auto-generated if not provided)" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Post created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/posts/{postId}/reactions": { + "get": { + "operationId": "reaction-by-post", + "summary": "Get reactions by post", + "tags": ["reaction"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "postId", + "in": "path", + "description": "Post ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Reactions returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/reactions/by-posts": { + "post": { + "operationId": "reaction-by-posts", + "summary": "Get reactions for multiple posts (for performance)", + "tags": ["reaction"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["postIds"], + "properties": { + "postIds": { + "type": "array", + "description": "Array of post IDs", + "items": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Reactions returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/reactions/{id}": { + "get": { + "operationId": "reaction-show", + "summary": "Get a single reaction", + "tags": ["reaction"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Reaction ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Reaction returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "reaction-destroy", + "summary": "Delete a reaction", + "tags": ["reaction"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Reaction ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Reaction deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/reactions": { + "post": { + "operationId": "reaction-create", + "summary": "Create a new reaction", + "tags": ["reaction"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["postId", "reactionType"], + "properties": { + "postId": { + "type": "integer", + "format": "int64", + "description": "Post ID" + }, + "reactionType": { + "type": "string", + "description": "Type of reaction" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Reaction created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/reactions/toggle": { + "post": { + "operationId": "reaction-toggle", + "summary": "Toggle a reaction (add if not exists, remove if exists)", + "tags": ["reaction"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["postId", "reactionType"], + "properties": { + "postId": { + "type": "integer", + "format": "int64", + "description": "Post ID" + }, + "reactionType": { + "type": "string", + "description": "Type of reaction (emoji)" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Reaction toggled", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["action"], + "properties": { + "action": { + "type": "string" + }, + "reaction": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/read-markers": { + "get": { + "operationId": "read_marker-index", + "summary": "Get read markers for multiple threads", + "tags": ["read_marker"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "threadIds", + "in": "query", + "description": "Array of thread IDs (comma-separated in query string)", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Read markers returned (keyed by thread ID)", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object", + "required": ["threadId", "lastReadPostId", "readAt"], + "properties": { + "threadId": { + "type": "integer", + "format": "int64" + }, + "lastReadPostId": { + "type": "integer", + "format": "int64" + }, + "readAt": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "read_marker-create", + "summary": "Mark a thread as read", + "tags": ["read_marker"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["threadId", "lastReadPostId"], + "properties": { + "threadId": { + "type": "integer", + "format": "int64", + "description": "Thread ID" + }, + "lastReadPostId": { + "type": "integer", + "format": "int64", + "description": "Last read post ID" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread marked as read", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/{threadId}/read-marker": { + "get": { + "operationId": "read_marker-show", + "summary": "Get read marker for a specific thread", + "tags": ["read_marker"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "threadId", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Read marker returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/read-markers/{id}": { + "delete": { + "operationId": "read_marker-destroy", + "summary": "Delete a read marker", + "tags": ["read_marker"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Read marker ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Read marker deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/roles": { + "get": { + "operationId": "role-index", + "summary": "Get all roles", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Roles returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "role-create", + "summary": "Create a new role", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "description": "Role name" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Role description" + }, + "canAccessAdminTools": { + "type": "boolean", + "default": false, + "description": "Can access admin tools" + }, + "canEditRoles": { + "type": "boolean", + "default": false, + "description": "Can edit roles" + }, + "canEditCategories": { + "type": "boolean", + "default": false, + "description": "Can edit categories" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Role created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/roles/{id}": { + "get": { + "operationId": "role-show", + "summary": "Get a single role", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Role returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "role-update", + "summary": "Update a role", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "default": null, + "description": "Role name" + }, + "description": { + "type": "string", + "nullable": true, + "default": null, + "description": "Role description" + }, + "canAccessAdminTools": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Can access admin tools" + }, + "canEditRoles": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Can edit roles" + }, + "canEditCategories": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Can edit categories" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Role updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "role-destroy", + "summary": "Delete a role", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Role deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/roles/{id}/permissions": { + "get": { + "operationId": "role-get-permissions", + "summary": "Get permissions for a role", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Permissions returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "role-update-permissions", + "summary": "Update permissions for a role", + "tags": ["role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["permissions"], + "properties": { + "permissions": { + "type": "array", + "description": "Permissions array", + "items": { + "type": "object", + "required": ["categoryId", "canView", "canModerate"], + "properties": { + "categoryId": { + "type": "integer", + "format": "int64" + }, + "canView": { + "type": "boolean" + }, + "canModerate": { + "type": "boolean" + } + } + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Permissions updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/search": { + "get": { + "operationId": "search-index", + "summary": "Search forum threads and posts", + "tags": ["search"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "q", + "in": "query", + "description": "Search query (supports quoted phrases, AND/OR operators, parentheses, -exclusions)", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "searchThreads", + "in": "query", + "description": "Include threads in search (title + first post content)", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "searchPosts", + "in": "query", + "description": "Include reply posts in search", + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "categoryId", + "in": "query", + "description": "Optional category ID filter", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum results per type", + "schema": { + "type": "integer", + "format": "int64", + "default": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "Results offset per type", + "schema": { + "type": "integer", + "format": "int64", + "default": 0 + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Search results returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["threads", "posts", "threadCount", "postCount", "query"], + "properties": { + "threads": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "posts": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "threadCount": { + "type": "integer", + "format": "int64" + }, + "postCount": { + "type": "integer", + "format": "int64" + }, + "query": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads": { + "get": { + "operationId": "thread-index", + "summary": "Get all threads", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Threads returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "post": { + "operationId": "thread-create", + "summary": "Create a new thread with initial post", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["categoryId", "title", "content"], + "properties": { + "categoryId": { + "type": "integer", + "format": "int64", + "description": "Category ID" + }, + "title": { + "type": "string", + "description": "Thread title" + }, + "content": { + "type": "string", + "description": "Initial post content" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Thread created", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/categories/{categoryId}/threads": { + "get": { + "operationId": "thread-by-category", + "summary": "Get threads by category", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "categoryId", + "in": "path", + "description": "Category ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of threads to return", + "schema": { + "type": "integer", + "format": "int64", + "default": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "schema": { + "type": "integer", + "format": "int64", + "default": 0 + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Threads returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/users/{authorId}/threads": { + "get": { + "operationId": "thread-by-author", + "summary": "Get threads by author", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "authorId", + "in": "path", + "description": "Author user ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of threads to return", + "schema": { + "type": "integer", + "format": "int64", + "default": 50 + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for pagination", + "schema": { + "type": "integer", + "format": "int64", + "default": 0 + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Threads returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/{id}": { + "get": { + "operationId": "thread-show", + "summary": "Get a single thread", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "incrementView", + "in": "query", + "description": "Whether to increment view count (1 or 0)", + "schema": { + "type": "string", + "default": "1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "put": { + "operationId": "thread-update", + "summary": "Update a thread", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string", + "nullable": true, + "default": null, + "description": "Thread title" + }, + "isLocked": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Whether the thread is locked" + }, + "isPinned": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Whether the thread is pinned" + }, + "isHidden": { + "type": "boolean", + "nullable": true, + "default": null, + "description": "Whether the thread is hidden" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "thread-destroy", + "summary": "Delete a thread (soft delete)", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success", "categorySlug"], + "properties": { + "success": { + "type": "boolean" + }, + "categorySlug": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/slug/{slug}": { + "get": { + "operationId": "thread-by-slug", + "summary": "Get a thread by slug", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "slug", + "in": "path", + "description": "Thread slug", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "incrementView", + "in": "query", + "description": "Whether to increment view count (1 or 0)", + "schema": { + "type": "string", + "default": "1" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/{id}/lock": { + "put": { + "operationId": "thread-set-locked", + "summary": "Toggle thread lock status", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["locked"], + "properties": { + "locked": { + "type": "boolean", + "description": "New lock status" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread lock status updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/{id}/pin": { + "put": { + "operationId": "thread-set-pinned", + "summary": "Toggle thread pin status", + "tags": ["thread"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["pinned"], + "properties": { + "pinned": { + "type": "boolean", + "description": "New pin status" + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread pin status updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/threads/{threadId}/subscribe": { + "post": { + "operationId": "thread_subscription-subscribe", + "summary": "Subscribe current user to a thread to receive notifications", + "tags": ["thread_subscription"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "threadId", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "User subscribed to thread", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "delete": { + "operationId": "thread_subscription-unsubscribe", + "summary": "Unsubscribe current user from a thread", + "tags": ["thread_subscription"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "threadId", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "User unsubscribed from thread", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + }, + "get": { + "operationId": "thread_subscription-is-subscribed", + "summary": "Check if current user is subscribed to a thread", + "tags": ["thread_subscription"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "threadId", + "in": "path", + "description": "Thread ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Subscription status returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/thread-subscriptions": { + "get": { + "operationId": "thread_subscription-get-user-subscriptions", + "summary": "Get all threads the current user is subscribed to", + "tags": ["thread_subscription"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Thread subscriptions returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/users/{userId}/roles": { + "get": { + "operationId": "user_role-by-user", + "summary": "Get roles for a user", + "tags": ["user_role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "Nextcloud user ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "User roles returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/roles/{roleId}/users": { + "get": { + "operationId": "user_role-by-role", + "summary": "Get users with a specific role", + "tags": ["user_role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "roleId", + "in": "path", + "description": "Role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "User roles returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/user-roles": { + "post": { + "operationId": "user_role-create", + "summary": "Assign a role to a user", + "tags": ["user_role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["userId", "roleId"], + "properties": { + "userId": { + "type": "string", + "description": "Nextcloud user ID" + }, + "roleId": { + "type": "integer", + "format": "int64", + "description": "Role ID" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "201": { + "description": "Role assigned to user", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/forum/api/user-roles/{id}": { + "delete": { + "operationId": "user_role-destroy", + "summary": "Remove a role from a user", + "tags": ["user_role"], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "id", + "in": "path", + "description": "User role ID", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Role removed from user", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "object", + "required": ["success"], + "properties": { + "success": { + "type": "boolean" + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Current user is not logged in", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["ocs"], + "properties": { + "ocs": { + "type": "object", + "required": ["meta", "data"], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + } + }, + "tags": [ + { + "name": "forum_user", + "description": "Controller for user statistics Note: User stats are automatically created on first post/thread" + } + ] } diff --git a/src/types/models.ts b/src/types/models.ts index 8efe852..35e3963 100644 --- a/src/types/models.ts +++ b/src/types/models.ts @@ -44,6 +44,7 @@ export interface Thread { authorIsDeleted?: boolean categorySlug?: string | null categoryName?: string | null + isSubscribed?: boolean } export interface Post { diff --git a/src/views/ThreadView.vue b/src/views/ThreadView.vue index 1069d94..afa0058 100644 --- a/src/views/ThreadView.vue +++ b/src/views/ThreadView.vue @@ -12,6 +12,19 @@