OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)

This commit is contained in:
wangruiguo
2026-09-03 18:49:20 +08:00
commit d647428529
3501 changed files with 1988906 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
<?php
namespace Unit\app\Core\Http\Responses;
use Leantime\Core\Http\Responses\Contracts\LeantimeResponseInterface;
use Leantime\Core\Http\Responses\ImageResponse;
use SVG\SVG;
use Symfony\Component\HttpFoundation\Response;
use Unit\TestCase;
/**
* Unit tests for the ImageResponse response type used by the domain image controllers
* (Users\Controllers\ProfileImage, Projects\Controllers\ProjectImage). It is returned
* directly from controllers and converted by Laravel's router via the Responsable contract.
*/
class ImageResponseTest extends TestCase
{
use \Codeception\Test\Feature\Stub;
public function test_it_is_a_leantime_response(): void
{
$this->assertInstanceOf(LeantimeResponseInterface::class, new ImageResponse('/tmp/x'));
}
public function test_to_response_renders_svg_with_cache_headers(): void
{
$svg = $this->make(SVG::class, [
'toXMLString' => fn () => '<svg></svg>',
]);
$response = (new ImageResponse($svg))->toResponse(null);
$this->assertSame('<svg></svg>', $response->getContent());
$this->assertSame('image/svg+xml', $response->headers->get('Content-type'));
$this->assertStringContainsString('max-age=86400', $response->headers->get('Cache-Control'));
}
public function test_to_response_passes_through_an_existing_response(): void
{
$existing = new Response('already built');
// An uploaded file is already a built Response; it must be returned untouched.
$this->assertSame($existing, (new ImageResponse($existing))->toResponse(null));
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace Unit\app\Core\Http\Responses;
use Leantime\Core\Exceptions\AuthorizationException;
use Leantime\Core\Exceptions\ValidationException;
use Leantime\Core\Http\Responses\Contracts\LeantimeResponseInterface;
use Leantime\Core\Http\Responses\JsonRpcErrorResponse;
use RuntimeException;
use Unit\TestCase;
/**
* The JSON-RPC 2.0 error envelope response type and its fromException() bridge — the single
* place a thrown exception becomes a client-facing error. Typed Leantime exceptions expose
* their own code/message/data; any other throwable is collapsed to a generic server error so
* internal detail is never leaked.
*/
class JsonRpcErrorResponseTest extends TestCase
{
public function test_it_is_a_leantime_response(): void
{
$this->assertInstanceOf(LeantimeResponseInterface::class, new JsonRpcErrorResponse(-32000, 'x'));
}
public function test_error_envelope(): void
{
$response = (new JsonRpcErrorResponse(-32602, 'Invalid params', ['field' => ['bad']], 3))->toResponse(null);
$body = json_decode($response->getContent(), true);
$this->assertSame('2.0', $body['jsonrpc']);
$this->assertSame(-32602, $body['error']['code']);
$this->assertSame('Invalid params', $body['error']['message']);
$this->assertSame(['field' => ['bad']], $body['error']['data']);
$this->assertSame(3, $body['id']);
}
public function test_from_validation_exception_maps_code_and_field_errors(): void
{
$errors = ['name' => ['Name is required.']];
$response = JsonRpcErrorResponse::fromException(ValidationException::withMessages($errors), 5)->toResponse(null);
$body = json_decode($response->getContent(), true);
$this->assertSame(-32602, $body['error']['code']);
$this->assertSame($errors, $body['error']['data']);
$this->assertSame(5, $body['id']);
}
public function test_from_authorization_exception_uses_auth_code(): void
{
$response = JsonRpcErrorResponse::fromException(new AuthorizationException, 1)->toResponse(null);
$body = json_decode($response->getContent(), true);
$this->assertSame(-32001, $body['error']['code']);
}
public function test_unknown_throwable_is_generic_and_does_not_leak(): void
{
$secret = 'internal-db-dsn-with-password';
$response = JsonRpcErrorResponse::fromException(new RuntimeException($secret), 9)->toResponse(null);
$body = json_decode($response->getContent(), true);
$this->assertSame(-32000, $body['error']['code']);
$this->assertSame('Server error', $body['error']['message']);
$this->assertNull($body['error']['data']);
$this->assertStringNotContainsString($secret, $response->getContent());
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Unit\app\Core\Http\Responses;
use Leantime\Core\Http\Responses\Contracts\LeantimeResponseInterface;
use Leantime\Core\Http\Responses\JsonRpcResponse;
use Unit\TestCase;
/**
* The JSON-RPC 2.0 success envelope response type. Centralizes the `{jsonrpc, result, id}`
* wire format previously inlined in the Jsonrpc controller.
*/
class JsonRpcResponseTest extends TestCase
{
public function test_it_is_a_leantime_response(): void
{
$this->assertInstanceOf(LeantimeResponseInterface::class, new JsonRpcResponse('x', 1));
}
public function test_success_envelope(): void
{
$response = (new JsonRpcResponse(['ok' => true], 7))->toResponse(null);
$body = json_decode($response->getContent(), true);
$this->assertSame('2.0', $body['jsonrpc']);
$this->assertSame(['ok' => true], $body['result']);
$this->assertSame(7, $body['id']);
}
public function test_scalar_result_and_string_id_pass_through(): void
{
$response = (new JsonRpcResponse(42, 'abc'))->toResponse(null);
$body = json_decode($response->getContent(), true);
$this->assertSame(42, $body['result']);
$this->assertSame('abc', $body['id']);
}
public function test_notification_without_id_returns_empty_200(): void
{
// A JSON-RPC notification (no id) MUST NOT be responded to.
$response = (new JsonRpcResponse('ignored', null))->toResponse(null);
$this->assertSame(200, $response->getStatusCode());
$this->assertSame('', $response->getContent());
}
}