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 Leanstan\Rules;
use PhpParser\Node;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
class FacadeRule implements Rule
{
private const ALLOWED_FACADES = ['Cache', 'Log', 'parent', 'self'];
public function getNodeType(): string
{
return StaticCall::class;
}
public function processNode(Node $node, Scope $scope): array
{
if (!$node instanceof StaticCall) {
return [];
}
if (!$node->class instanceof \PhpParser\Node\Name) {
return [];
}
$className = $node->class->toString();
// Check if it's likely a facade
$parts = $node->class->getParts();
if (strpos($className, 'Illuminate\\Support\\Facades\\') === 0 || count($parts) === 1) {
$facadeName = count($parts) === 1 ? $parts[0] : end($parts);
if (!in_array($facadeName, self::ALLOWED_FACADES)) {
return [
"Only Cache:: and Log:: facades are allowed. Consider using dependency injection or helpers instead of {$facadeName}::."
];
}
}
return [];
}
}

20
.phpstan/bootstrap.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
use Leantime\Core\Http\HttpKernel;
define('RESTRICTED', true);
define('ROOT', __DIR__);
define('APP_ROOT', dirname(__DIR__, 1));
define('LEAN_CLI', false);
require __DIR__.'/../vendor/autoload.php';
$app = require_once APP_ROOT . '/bootstrap/app.php';
$app->make(\Leantime\Core\Console\ConsoleKernel::class)->bootstrap();
// Register Leantime's CarbonImmutable date/time macros into Carbon's macro registry so
// Carbon's official PHPStan MacroExtension (vendor/nesbot/carbon/extension.neon) can resolve
// them (formatDateForUser, setToDbTimezone, ...). At runtime these are registered by the
// Localization middleware; PHPStan never runs that middleware, so register them here.
\Carbon\CarbonImmutable::mixin(new \Leantime\Core\Support\CarbonMacros);

50
.phpstan/phpstan.neon Normal file
View File

@@ -0,0 +1,50 @@
includes:
# Carbon's official PHPStan extension: resolves macros registered via mixin()/macro()
# (including Leantime's date/time macros, registered in bootstrap.php) on all Carbon types.
- ../vendor/nesbot/carbon/extension.neon
parameters:
bootstrapFiles:
- bootstrap.php
level: 5
inferPrivatePropertyTypeFromConstructor: true
paths:
- ../public
- ../app
- ../.phpstan/Rules
excludePaths:
- ../app/Plugins/*
scanDirectories:
- ../vendor
- ../config
stubFiles:
# Declares Leantime's runtime-registered methods (Str/Carbon macros, Collection::countNested,
# Event::discoverListeners) so vanilla PHPStan stops reporting them as undefined.
- stubs/leantime-macros.stub
# Declares concrete Laravel methods our code calls through looser contracts (no Larastan).
- stubs/laravel-gaps.stub
ignoreErrors:
# Legacy templates receive their variables from the view layer ($tpl->assign / extract)
# and blade files via compiled-in view data. PHPStan analyses them as plain PHP and so
# cannot see those variables. This is a known limitation of the template pattern, not a
# code defect. reportUnmatched is off because templates are mid-migration (paths come and
# go) and app/Plugins is a private submodule absent in CI.
-
identifier: variable.undefined
reportUnmatched: false
paths:
- ../app/Domain/*/Templates/*
- ../app/Views/*
- ../app/Plugins/*/Templates/*
universalObjectCratesClasses:
- Leantime\Core\Configuration\Environment
earlyTerminatingMethodCalls:
Leantime\Core\UI\Templates:
- redirect
- display
- displayPartial
# services:
# -
# class: Leanstan\Rules\FacadeRule
# tags:
# - phpstan.rules.rule

View File

@@ -0,0 +1,108 @@
<?php
/**
* PHPStan stub: methods that exist on the CONCRETE Laravel classes our code uses at
* runtime, but are not declared on the looser contracts/interfaces we type-hint against.
*
* Leantime intentionally does NOT use Larastan, so vanilla PHPStan only sees the contract
* (e.g. ConnectionInterface) and reports the concrete method (e.g. getDriverName()) as
* undefined — even though the runtime object (Illuminate\Database\Connection) always has it.
*
* These @method tags merge onto the real interfaces/classes; native members are unaffected.
* Each entry is documented with the concrete class that actually provides the method.
*/
namespace Illuminate\Database;
/**
* Provided at runtime by the abstract Illuminate\Database\Connection that
* DatabaseManager::connection() always returns.
*
* @method string getDriverName()
* @method \PDO getPdo()
* @method \Illuminate\Database\Query\Grammars\Grammar getQueryGrammar()
*/
interface ConnectionInterface {}
namespace Illuminate\Contracts\Cache;
/**
* The concrete Illuminate\Cache\Repository (what Cache::store() returns) forwards lock() via
* __call to its underlying store when that store is a LockProvider (Redis/File/Database/...).
* StartSession::cache() is typed against this contract and uses it for session locking.
*
* @method \Illuminate\Cache\Lock lock(string $name, int $seconds = 0, ?string $owner = null)
*/
interface Repository {}
namespace Illuminate\Contracts\Filesystem;
/**
* Provided by the concrete Illuminate\Filesystem\FilesystemAdapter (and the Cloud contract
* for url()/temporaryUrl()). Storage::disk() returns that adapter.
*
* @method string url(string $path)
* @method string temporaryUrl(string $path, \DateTimeInterface $expiration, array $options = [])
* @method string|false mimeType(string $path)
*/
interface Filesystem {}
namespace Illuminate\Contracts\Foundation;
/**
* Provided by Illuminate\Foundation\Application (which Leantime\Core\Application extends).
*
* @method void rebinding(string $abstract, \Closure $callback)
* @method string getCachedConfigPath()
* @method string detectEnvironment(\Closure $callback)
*/
interface Application {}
namespace Illuminate\Container;
/**
* terminating() lives on Illuminate\Foundation\Application; the container instance Leantime
* passes around is that application.
*
* @method void terminating(\Closure|string $callback)
*/
class Container {}
namespace Illuminate\Contracts\Auth;
/**
* Provided by the concrete Illuminate\Auth\AuthManager bound to 'auth'.
*
* @method string getDefaultDriver()
* @method \Illuminate\Contracts\Auth\Authenticatable|null user()
*/
interface Factory {}
/**
* viaRemember()/getRecallerName()/logoutCurrentDevice() are provided by the concrete
* session guard (Illuminate\Auth\SessionGuard) that AuthManager::guard() returns.
*
* @method bool viaRemember()
* @method string getRecallerName()
* @method void logoutCurrentDevice()
*/
interface Guard {}
namespace Illuminate\Support;
/**
* addRealMinutes() is a Carbon magic method (Carbon 3 dropped its @method annotation but the
* __call magic still resolves it). Used by StartSession exactly as upstream Laravel does.
*
* @method \Illuminate\Support\Carbon addRealMinutes(int $value = 1)
*/
class Carbon {}
namespace Laravel\Socialite\Contracts;
/**
* setScopes() is provided by the concrete Laravel\Socialite\Two\AbstractProvider.
*
* @method \Laravel\Socialite\Contracts\Provider setScopes(array|string $scopes)
*/
interface Provider {}

View File

@@ -0,0 +1,45 @@
<?php
/**
* PHPStan stub: declares Leantime's custom runtime-registered methods that vanilla
* PHPStan (no Larastan) cannot see. These are NOT real source definitions — they
* only teach the analyzer that the methods exist with these signatures.
*
* - Str macros are registered via Str::mixin(...) in
* app/Core/Support/LoadMacrosServiceProvider.php. Each mixin method returns a
* closure; the closure's parameters are the real call signature (registration-time
* params are baked in and declared here as optional so existing call sites pass).
* - Collection::countNested is registered via Collection::macro(...) in the same provider.
* - Event::discoverListeners() lives on Leantime\Core\Events\EventDispatcher, which is
* bound to the 'events' container singleton (app/Core/Events/EventsServiceProvider.php).
*
* The @method tags merge onto the real classes; native methods are unaffected.
*
* NOTE: Leantime's CarbonImmutable macros (formatDateForUser, setToDbTimezone, ...) are NOT
* stubbed here — stubbing Carbon\CarbonInterface would clobber Carbon's own @method API.
* They are resolved by Carbon's official PHPStan MacroExtension instead (vendor extension.neon
* included from phpstan.neon), fed by the mixin registration in .phpstan/bootstrap.php.
*/
namespace Illuminate\Support;
/**
* @method static string alphaNumeric(string $value, bool $removeSpaces = false)
* @method static string beautifyFilename(string $filename)
* @method static string sanitizeFilename(string $filename, bool $beautify = true)
* @method static string sanitizeForLLM(string $value, bool $removeNewlines = false)
* @method static string toMarkdown(mixed $data, int $headerLevel = 2)
*/
class Str {}
/**
* @method int countNested(string $childrenKey = 'children')
*/
class Collection {}
namespace Illuminate\Support\Facades;
/**
* @method static void discoverListeners()
*/
class Event {}