fix(admin): separate forum admin and server admin endpoints

This commit is contained in:
2026-03-25 15:17:51 +02:00
parent 7fc7778f45
commit 28a0cd8153
7 changed files with 729 additions and 634 deletions

View File

@@ -13,9 +13,7 @@ use OCA\Forum\Db\ForumUserMapper;
use OCA\Forum\Db\PostMapper;
use OCA\Forum\Db\RoleMapper;
use OCA\Forum\Db\ThreadMapper;
use OCA\Forum\Migration\SeedHelper;
use OCA\Forum\Service\AdminSettingsService;
use OCA\Forum\Service\StatsService;
use OCA\Forum\Service\UserRoleService;
use OCA\Forum\Service\UserService;
use OCP\AppFramework\Http;
@@ -26,7 +24,6 @@ use OCP\AppFramework\OCSController;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Migration\IOutput;
use Psr\Log\LoggerInterface;
class AdminController extends OCSController {
@@ -44,7 +41,6 @@ class AdminController extends OCSController {
private IUserManager $userManager,
private IUserSession $userSession,
private AdminSettingsService $settingsService,
private StatsService $statsService,
private LoggerInterface $logger,
) {
parent::__construct($appName, $request);
@@ -242,109 +238,6 @@ class AdminController extends OCSController {
}
}
/**
* Run the repair seeds command to restore default forum data
*
* @return DataResponse<Http::STATUS_OK, array{success: bool, message: string}, array{}>
*
* 200: Seeds repaired successfully
*/
#[ApiRoute(verb: 'POST', url: '/api/admin/repair-seeds')]
public function repairSeeds(): DataResponse {
try {
$messages = [];
$migrationOutput = new class($messages) implements IOutput {
/** @var array<string> */
private array $messages;
public function __construct(array &$messages) {
$this->messages = &$messages;
}
public function info($message): void {
$this->messages[] = $message;
}
public function warning($message): void {
$this->messages[] = '[Warning] ' . $message;
}
public function debug($message): void {
$this->messages[] = '[Debug] ' . $message;
}
public function startProgress($max = 0): void {
}
public function advance($step = 1, $description = ''): void {
}
public function finishProgress(): void {
}
};
SeedHelper::seedAll($migrationOutput, true);
$this->logger->info('Forum repair seeds completed successfully');
return new DataResponse([
'success' => true,
'message' => implode("\n", $messages),
]);
} catch (\Exception $e) {
$this->logger->error('Error running repair seeds: ' . $e->getMessage());
return new DataResponse([
'success' => false,
'message' => 'Failed to repair seeds: ' . $e->getMessage(),
], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Rebuild all forum statistics (users, categories, threads)
*
* @return DataResponse<Http::STATUS_OK, array{success: bool, message: string}, array{}>
*
* 200: Stats rebuilt successfully
*/
#[ApiRoute(verb: 'POST', url: '/api/admin/rebuild-stats')]
public function rebuildStats(): DataResponse {
try {
$userResult = $this->statsService->rebuildAllUserStats();
$categoryResult = $this->statsService->rebuildAllCategoryStats();
$threadResult = $this->statsService->rebuildAllThreadStats();
$messages = [];
$messages[] = sprintf(
'Users processed: %d, created: %d, updated: %d',
$userResult['users'],
$userResult['created'],
$userResult['updated']
);
$messages[] = sprintf(
'Categories processed: %d, updated: %d',
$categoryResult['categories'],
$categoryResult['updated']
);
$messages[] = sprintf(
'Threads processed: %d, updated: %d',
$threadResult['threads'],
$threadResult['updated']
);
$this->logger->info('Forum stats rebuild completed successfully');
return new DataResponse([
'success' => true,
'message' => implode("\n", $messages),
]);
} catch (\Exception $e) {
$this->logger->error('Error rebuilding stats: ' . $e->getMessage());
return new DataResponse([
'success' => false,
'message' => 'Failed to rebuild stats: ' . $e->getMessage(),
], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Get all available roles
*

View File

@@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
// SPDX-FileCopyrightText: Chen Asraf <contact@casraf.dev>
// SPDX-License-Identifier: AGPL-3.0-or-later
namespace OCA\Forum\Controller;
use OCA\Forum\Migration\SeedHelper;
use OCA\Forum\Service\StatsService;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\ApiRoute;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
use OCP\Migration\IOutput;
use Psr\Log\LoggerInterface;
class ServerAdminController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
private StatsService $statsService,
private LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}
/**
* Run the repair seeds command to restore default forum data
*
* @return DataResponse<Http::STATUS_OK, array{success: bool, message: string}, array{}>
*
* 200: Seeds repaired successfully
*/
#[ApiRoute(verb: 'POST', url: '/api/server-admin/repair-seeds')]
public function repairSeeds(): DataResponse {
try {
$messages = [];
$migrationOutput = new class($messages) implements IOutput {
/** @var array<string> */
private array $messages;
public function __construct(array &$messages) {
$this->messages = &$messages;
}
public function info($message): void {
$this->messages[] = $message;
}
public function warning($message): void {
$this->messages[] = '[Warning] ' . $message;
}
public function debug($message): void {
$this->messages[] = '[Debug] ' . $message;
}
public function startProgress($max = 0): void {
}
public function advance($step = 1, $description = ''): void {
}
public function finishProgress(): void {
}
};
SeedHelper::seedAll($migrationOutput, true);
$this->logger->info('Forum repair seeds completed successfully');
return new DataResponse([
'success' => true,
'message' => implode("\n", $messages),
]);
} catch (\Exception $e) {
$this->logger->error('Error running repair seeds: ' . $e->getMessage());
return new DataResponse([
'success' => false,
'message' => 'Failed to repair seeds: ' . $e->getMessage(),
], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
/**
* Rebuild all forum statistics (users, categories, threads)
*
* @return DataResponse<Http::STATUS_OK, array{success: bool, message: string}, array{}>
*
* 200: Stats rebuilt successfully
*/
#[ApiRoute(verb: 'POST', url: '/api/server-admin/rebuild-stats')]
public function rebuildStats(): DataResponse {
try {
$userResult = $this->statsService->rebuildAllUserStats();
$categoryResult = $this->statsService->rebuildAllCategoryStats();
$threadResult = $this->statsService->rebuildAllThreadStats();
$messages = [];
$messages[] = sprintf(
'Users processed: %d, created: %d, updated: %d',
$userResult['users'],
$userResult['created'],
$userResult['updated']
);
$messages[] = sprintf(
'Categories processed: %d, updated: %d',
$categoryResult['categories'],
$categoryResult['updated']
);
$messages[] = sprintf(
'Threads processed: %d, updated: %d',
$threadResult['threads'],
$threadResult['updated']
);
$this->logger->info('Forum stats rebuild completed successfully');
return new DataResponse([
'success' => true,
'message' => implode("\n", $messages),
]);
} catch (\Exception $e) {
$this->logger->error('Error rebuilding stats: ' . $e->getMessage());
return new DataResponse([
'success' => false,
'message' => 'Failed to rebuild stats: ' . $e->getMessage(),
], Http::STATUS_INTERNAL_SERVER_ERROR);
}
}
}

View File

@@ -47,266 +47,6 @@
}
},
"paths": {
"/ocs/v2.php/apps/forum/api/admin/repair-seeds": {
"post": {
"operationId": "admin-repair-seeds",
"summary": "Run the repair seeds command to restore default forum data",
"description": "This endpoint requires admin access",
"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": "Seeds repaired 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"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/rebuild-stats": {
"post": {
"operationId": "admin-rebuild-stats",
"summary": "Rebuild all forum statistics (users, categories, threads)",
"description": "This endpoint requires admin access",
"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": "Stats rebuilt 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"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/init/admin-users": {
"get": {
"operationId": "init-get-admin-users",
@@ -722,6 +462,266 @@
}
}
}
},
"/ocs/v2.php/apps/forum/api/server-admin/repair-seeds": {
"post": {
"operationId": "server_admin-repair-seeds",
"summary": "Run the repair seeds command to restore default forum data",
"description": "This endpoint requires admin access",
"tags": [
"server_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": "Seeds repaired 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"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/server-admin/rebuild-stats": {
"post": {
"operationId": "server_admin-rebuild-stats",
"summary": "Rebuild all forum statistics (users, categories, threads)",
"description": "This endpoint requires admin access",
"tags": [
"server_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": "Stats rebuilt 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
}
},
"tags": [

View File

@@ -11967,266 +11967,6 @@
}
}
},
"/ocs/v2.php/apps/forum/api/admin/repair-seeds": {
"post": {
"operationId": "admin-repair-seeds",
"summary": "Run the repair seeds command to restore default forum data",
"description": "This endpoint requires admin access",
"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": "Seeds repaired 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"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/rebuild-stats": {
"post": {
"operationId": "admin-rebuild-stats",
"summary": "Rebuild all forum statistics (users, categories, threads)",
"description": "This endpoint requires admin access",
"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": "Stats rebuilt 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"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/init/admin-users": {
"get": {
"operationId": "init-get-admin-users",
@@ -12642,6 +12382,266 @@
}
}
}
},
"/ocs/v2.php/apps/forum/api/server-admin/repair-seeds": {
"post": {
"operationId": "server_admin-repair-seeds",
"summary": "Run the repair seeds command to restore default forum data",
"description": "This endpoint requires admin access",
"tags": [
"server_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": "Seeds repaired 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"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/server-admin/rebuild-stats": {
"post": {
"operationId": "server_admin-rebuild-stats",
"summary": "Rebuild all forum statistics (users, categories, threads)",
"description": "This endpoint requires admin access",
"tags": [
"server_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": "Stats rebuilt 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",
"message"
],
"properties": {
"success": {
"type": "boolean"
},
"message": {
"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": {}
}
}
}
}
}
}
},
"403": {
"description": "Logged in account must be an admin",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ocs"
],
"properties": {
"ocs": {
"type": "object",
"required": [
"meta",
"data"
],
"properties": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
"data": {}
}
}
}
}
}
}
}
}
}
}
},
"tags": [

View File

@@ -221,7 +221,7 @@ export default {
return runTask(
this.repairSeeds,
async (task) => {
const resp = await ocs.post('/admin/repair-seeds')
const resp = await ocs.post('/server-admin/repair-seeds')
task.success = resp.data.success
task.result = resp.data.message
if (resp.data.success) {
@@ -235,7 +235,7 @@ export default {
return runTask(
this.rebuildStats,
async (task) => {
const resp = await ocs.post('/admin/rebuild-stats')
const resp = await ocs.post('/server-admin/rebuild-stats')
task.success = resp.data.success
task.result = resp.data.message
},

View File

@@ -12,7 +12,6 @@ use OCA\Forum\Db\PostMapper;
use OCA\Forum\Db\RoleMapper;
use OCA\Forum\Db\ThreadMapper;
use OCA\Forum\Service\AdminSettingsService;
use OCA\Forum\Service\StatsService;
use OCA\Forum\Service\UserRoleService;
use OCA\Forum\Service\UserService;
use OCP\IRequest;
@@ -46,8 +45,6 @@ class AdminControllerTest extends TestCase {
private IUserSession $userSession;
/** @var AdminSettingsService&MockObject */
private AdminSettingsService $settingsService;
/** @var StatsService&MockObject */
private StatsService $statsService;
/** @var LoggerInterface&MockObject */
private LoggerInterface $logger;
/** @var IRequest&MockObject */
@@ -65,7 +62,6 @@ class AdminControllerTest extends TestCase {
$this->userManager = $this->createMock(IUserManager::class);
$this->userSession = $this->createMock(IUserSession::class);
$this->settingsService = $this->createMock(AdminSettingsService::class);
$this->statsService = $this->createMock(StatsService::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->controller = new AdminController(
@@ -81,7 +77,6 @@ class AdminControllerTest extends TestCase {
$this->userManager,
$this->userSession,
$this->settingsService,
$this->statsService,
$this->logger
);
}

View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace OCA\Forum\Tests\Controller;
use OCA\Forum\AppInfo\Application;
use OCA\Forum\Controller\ServerAdminController;
use OCA\Forum\Service\StatsService;
use OCP\IRequest;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class ServerAdminControllerTest extends TestCase {
private ServerAdminController $controller;
/** @var StatsService&MockObject */
private StatsService $statsService;
/** @var LoggerInterface&MockObject */
private LoggerInterface $logger;
/** @var IRequest&MockObject */
private IRequest $request;
protected function setUp(): void {
$this->request = $this->createMock(IRequest::class);
$this->statsService = $this->createMock(StatsService::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->controller = new ServerAdminController(
Application::APP_ID,
$this->request,
$this->statsService,
$this->logger
);
}
public function testRebuildStatsReturnsResults(): void {
$this->statsService->expects($this->once())
->method('rebuildAllUserStats')
->willReturn(['users' => 10, 'created' => 2, 'updated' => 8]);
$this->statsService->expects($this->once())
->method('rebuildAllCategoryStats')
->willReturn(['categories' => 5, 'updated' => 5]);
$this->statsService->expects($this->once())
->method('rebuildAllThreadStats')
->willReturn(['threads' => 20, 'updated' => 20]);
$response = $this->controller->rebuildStats();
$this->assertEquals(200, $response->getStatus());
$data = $response->getData();
$this->assertTrue($data['success']);
$this->assertStringContainsString('Users processed: 10', $data['message']);
$this->assertStringContainsString('Categories processed: 5', $data['message']);
$this->assertStringContainsString('Threads processed: 20', $data['message']);
}
public function testRebuildStatsHandlesException(): void {
$this->statsService->expects($this->once())
->method('rebuildAllUserStats')
->willThrowException(new \Exception('DB error'));
$this->logger->expects($this->once())
->method('error')
->with($this->stringContains('Error rebuilding stats'));
$response = $this->controller->rebuildStats();
$this->assertEquals(500, $response->getStatus());
$data = $response->getData();
$this->assertFalse($data['success']);
}
}