From 9049fdccad7cb2102d44e07f45c486e53a34172b Mon Sep 17 00:00:00 2001 From: hashbro Date: Sat, 15 Aug 2026 04:17:24 +0800 Subject: [PATCH] feat: new channel --- app/Models/Channel.php | 17 +++++++++ app/Telegram/Handlers/ChannelCommand.php | 13 +++++-- app/Telegram/Handlers/HelpCommand.php | 2 +- app/Telegram/TelegramRegistrar.php | 2 +- tests/Feature/TelegramBotTest.php | 47 ++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/app/Models/Channel.php b/app/Models/Channel.php index 6018005..e173cfb 100644 --- a/app/Models/Channel.php +++ b/app/Models/Channel.php @@ -172,6 +172,23 @@ class Channel extends Model return array_values(array_unique($links)); } + /** + * Hidden iframe snippet for embedding the landing URL (same as admin「复制推广代码」). + */ + public function promoIframeSnippet(?string $url = null): ?string + { + $url = trim((string) ($url ?? ($this->supportLinks()[0] ?? ''))); + if ($url === '') { + $base = rtrim((string) config('app.url'), '/'); + if ($base === '') { + return null; + } + $url = $base.$this->landingPath(); + } + + return ''; + } + public static function randomChannelId(): string { return bin2hex(random_bytes(16)); diff --git a/app/Telegram/Handlers/ChannelCommand.php b/app/Telegram/Handlers/ChannelCommand.php index a21c355..c8dc08a 100644 --- a/app/Telegram/Handlers/ChannelCommand.php +++ b/app/Telegram/Handlers/ChannelCommand.php @@ -31,7 +31,7 @@ class ChannelCommand return; } - $lines = ['📎 渠道列表(点按钮复制链接)', '']; + $lines = ['📎 渠道列表(点按钮复制;新版=推广 iframe,旧版=投放链接)', '']; $markup = InlineKeyboardMarkup::make(); foreach ($channels as $i => $channel) { @@ -43,10 +43,17 @@ class ChannelCommand $lines[] = ' 备注: '.$remarkLabel.' | 归属: '.$owner.' | '.$status; if ($channel->isNewBuilder()) { - $btnText = ($remark !== '' ? mb_substr($remark, 0, 18) : $channel->channel_id).' · 渠道码'; + $snippet = $channel->promoIframeSnippet(); + if ($snippet === null || $snippet === '') { + $btnText = ($remark !== '' ? mb_substr($remark, 0, 18) : $channel->channel_id).' · 渠道码'; + $copy = $channel->channel_id; + } else { + $btnText = ($remark !== '' ? mb_substr($remark, 0, 16) : $channel->channel_id).' · 推广代码'; + $copy = strlen($snippet) > 256 ? substr($snippet, 0, 256) : $snippet; + } $markup->addRow(InlineKeyboardButton::make( text: $btnText, - copy_text: CopyTextButton::make($channel->channel_id), + copy_text: CopyTextButton::make($copy), )); continue; diff --git a/app/Telegram/Handlers/HelpCommand.php b/app/Telegram/Handlers/HelpCommand.php index e1844a5..771bbe6 100644 --- a/app/Telegram/Handlers/HelpCommand.php +++ b/app/Telegram/Handlers/HelpCommand.php @@ -32,7 +32,7 @@ class HelpCommand ' 例: /data 0.0.01', '', '/channel', - ' 列出渠道:ID、备注、归属;点按钮复制链接', + ' 列出渠道:ID、备注、归属;新版点按钮复制推广 iframe,旧版复制投放链接', ]; if ($this->context->isOfficial()) { diff --git a/app/Telegram/TelegramRegistrar.php b/app/Telegram/TelegramRegistrar.php index 19a6817..1389f61 100644 --- a/app/Telegram/TelegramRegistrar.php +++ b/app/Telegram/TelegramRegistrar.php @@ -51,7 +51,7 @@ class TelegramRegistrar ->description('Visit stats for 1/7/30 days, optional channelId'); $bot->onCommand('channel', ChannelCommand::class) - ->description('List channels with copyable support links'); + ->description('List channels; copy promo iframe (new) or support link (old)'); if ($allowTransfer) { $bot->onCommand('transfer {args}', TransferCommand::class) diff --git a/tests/Feature/TelegramBotTest.php b/tests/Feature/TelegramBotTest.php index 1b2ffea..108dce6 100644 --- a/tests/Feature/TelegramBotTest.php +++ b/tests/Feature/TelegramBotTest.php @@ -331,6 +331,53 @@ class TelegramBotTest extends TestCase $this->assertArrayHasKey('reply_markup', $last); } + #[Test] + public function admin_channel_new_builder_copies_promo_iframe(): void + { + config([ + 'coruna.channel_domains' => ['cdn.example.com'], + 'coruna.static_site.scheme' => 'https', + ]); + + Channel::query()->create([ + 'channel_id' => 'S.U.N2', + 'builder_type' => Channel::BUILDER_NEW, + 'user_id' => Channel::OFFICIAL_USER_ID, + 'remark' => 'SUN02', + 'status' => 1, + ]); + + /** @var FakeNutgram $bot */ + $bot = app(Nutgram::class); + + $bot->willReceivePartial([ + 'status' => ChatMemberStatus::ADMINISTRATOR->value, + 'user' => ['id' => self::USER_ID, 'is_bot' => false, 'first_name' => 'Admin'], + 'can_manage_chat' => true, + ]); + + $bot->hearMessage([ + 'text' => '/channel', + 'chat' => ['id' => self::OWNER_CHAT, 'type' => ChatType::SUPERGROUP->value], + 'from' => ['id' => self::USER_ID, 'is_bot' => false, 'first_name' => 'Admin'], + ])->reply(); + + $bot->assertCalled('sendMessage', 1); + $history = $bot->getRequestHistory(); + $last = FakeNutgram::getActualData(array_values($history[array_key_last($history)])[0]); + $this->assertStringContainsString('S.U.N2', $last['text'] ?? ''); + $this->assertStringContainsString('推广 iframe', $last['text'] ?? ''); + + $markup = $last['reply_markup'] ?? null; + $this->assertIsArray($markup); + $row = $markup['inline_keyboard'][0][0] ?? null; + $this->assertIsArray($row); + $this->assertStringContainsString('推广代码', (string) ($row['text'] ?? '')); + $copy = (string) data_get($row, 'copy_text.text', ''); + $this->assertStringContainsString('