feat: enhance player authentication and agent management features
Some checks failed
lotterLaravel CI / test (push) Has been cancelled

- Updated AGENTS.md to clarify player interface bindings and agent account restrictions.
- Improved PlayerAuthLoginController to include captcha verification for player login.
- Enhanced AdminPlayerIndexController with permission checks for admin users.
- Refactored AdminPlayerStoreController to enforce agent node restrictions for non-super admins.
- Introduced new error codes for player authentication failures and updated related services.
- Enhanced validation rules for agent profiles to include settlement cycle options.
- Improved AdminCaptchaService to support separate scopes for admin and player captcha handling.
- Updated various services to ensure proper credit management and settlement processes.
This commit is contained in:
2026-06-17 15:27:00 +08:00
parent b496a9457c
commit 2e0b257160
49 changed files with 714 additions and 334 deletions

View File

@@ -26,6 +26,18 @@ final class AdminAgentScope
return AgentNode::query()->find($agentId);
}
/** 仅站点运营admin_user_site_roles未绑定代理节点。 */
public static function isSiteOnlyOperator(AdminUser $admin): bool
{
if ($admin->isSuperAdmin() || self::primaryAgentNode($admin) !== null) {
return false;
}
$siteIds = $admin->accessibleAdminSiteIds();
return $siteIds !== null && $siteIds !== [];
}
public static function nodeVisibleTo(AdminUser $admin, AgentNode $node): bool
{
if ($admin->isSuperAdmin()) {
@@ -55,30 +67,21 @@ final class AdminAgentScope
return true;
}
// Check if admin is a platform account (bound via admin_user_site_roles)
$accessibleSiteIds = $admin->accessibleAdminSiteIds();
if ($accessibleSiteIds !== null) {
// Platform account (site admin) can access all players in the site
// Site check is done by AdminSiteScope::playerAccessible before calling this
return true;
}
// Agent account (bound via agent node)
$actor = self::primaryAgentNode($admin);
if ($actor === null) {
return false;
if ($actor !== null) {
if ($player->agent_node_id === null) {
return false;
}
$playerAgent = AgentNode::query()->find((int) $player->agent_node_id);
if ($playerAgent === null) {
return false;
}
return $playerAgent->isSameOrDescendantOf($actor);
}
if ($player->agent_node_id === null) {
return false;
}
$playerAgent = AgentNode::query()->find((int) $player->agent_node_id);
if ($playerAgent === null) {
return false;
}
return $playerAgent->isSameOrDescendantOf($actor);
return self::isSiteOnlyOperator($admin);
}
public static function nodeManageableBy(AdminUser $admin, AgentNode $node): bool
@@ -113,32 +116,22 @@ final class AdminAgentScope
return false;
}
// Check if admin is a platform account (bound via admin_user_site_roles)
$accessibleSiteIds = $admin->accessibleAdminSiteIds();
if ($accessibleSiteIds !== null) {
// Platform account (site admin) can edit all nodes in the site
// EXCEPT their own bound agent node
if (in_array((int) $node->admin_site_id, $accessibleSiteIds, true)) {
$actor = self::primaryAgentNode($admin);
if ($actor !== null && (int) $actor->id === (int) $node->id) {
return false; // Cannot edit own bound node
}
return true;
}
return false;
}
// Agent account (bound via agent node)
$actor = self::primaryAgentNode($admin);
if ($actor === null) {
if ($actor !== null) {
if ((int) $actor->id === (int) $node->id) {
return false;
}
return $node->isDescendantOf($actor);
}
if (! self::isSiteOnlyOperator($admin)) {
return false;
}
if ((int) $actor->id === (int) $node->id) {
return false;
}
$accessibleSiteIds = $admin->accessibleAdminSiteIds();
return $node->isDescendantOf($actor);
return in_array((int) $node->admin_site_id, $accessibleSiteIds ?? [], true);
}
/**
@@ -188,18 +181,11 @@ final class AdminAgentScope
return;
}
// Check if admin is a platform account (bound via admin_user_site_roles)
$accessibleSiteIds = $admin->accessibleAdminSiteIds();
if ($accessibleSiteIds !== null) {
// Platform account (site admin) - site filtering is handled by AdminSiteScope
// No agent node filtering needed
return;
}
// Agent account (bound via agent node)
$actor = self::primaryAgentNode($admin);
if ($actor === null) {
$query->whereRaw('0 = 1');
if (! self::isSiteOnlyOperator($admin)) {
$query->whereRaw('0 = 1');
}
return;
}