changed botfather avatar and fixed import
This commit is contained in:
parent
c436c7c773
commit
0a6c05404a
18 changed files with 318 additions and 108 deletions
|
|
@ -837,6 +837,7 @@ type importDefaultStarGiftAPIRequest struct {
|
|||
Reason string `json:"reason"`
|
||||
Confirm bool `json:"confirm"`
|
||||
ID int `json:"id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (s *server) handleImportDefaultStarGiftAPI(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -851,6 +852,7 @@ func (s *server) handleImportDefaultStarGiftAPI(w http.ResponseWriter, r *http.R
|
|||
req := admin.ImportDefaultStarGiftRequest{
|
||||
CommandMeta: s.commandMetaFromAPI(r, body.CommandID, body.Reason, body.Confirm, "import-default-gift"),
|
||||
ID: body.ID,
|
||||
Enabled: body.Enabled,
|
||||
}
|
||||
result, err := s.callAdminAPI(r.Context(), "/v1/default-gifts/import", req)
|
||||
writeCommandResultAPI(w, result, err)
|
||||
|
|
@ -860,6 +862,7 @@ type importAllDefaultStarGiftsAPIRequest struct {
|
|||
CommandID string `json:"command_id"`
|
||||
Reason string `json:"reason"`
|
||||
Confirm bool `json:"confirm"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (s *server) handleImportAllDefaultStarGiftsAPI(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -869,6 +872,7 @@ func (s *server) handleImportAllDefaultStarGiftsAPI(w http.ResponseWriter, r *ht
|
|||
}
|
||||
req := admin.ImportAllDefaultStarGiftsRequest{
|
||||
CommandMeta: s.commandMetaFromAPI(r, body.CommandID, body.Reason, body.Confirm, "import-all-default-gifts"),
|
||||
Enabled: body.Enabled,
|
||||
}
|
||||
result, err := s.callAdminAPI(r.Context(), "/v1/default-gifts/import-all", req)
|
||||
writeCommandResultAPI(w, result, err)
|
||||
|
|
@ -915,6 +919,7 @@ type importAllOfficialStarGiftsAPIRequest struct {
|
|||
CommandID string `json:"command_id"`
|
||||
Reason string `json:"reason"`
|
||||
Confirm bool `json:"confirm"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (s *server) handleImportAllOfficialStarGiftsAPI(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -924,6 +929,7 @@ func (s *server) handleImportAllOfficialStarGiftsAPI(w http.ResponseWriter, r *h
|
|||
}
|
||||
req := admin.ImportAllOfficialStarGiftsRequest{
|
||||
CommandMeta: s.commandMetaFromAPI(r, body.CommandID, body.Reason, body.Confirm, "import-all-official-gifts"),
|
||||
Enabled: body.Enabled,
|
||||
}
|
||||
result, err := s.callAdminAPI(r.Context(), "/v1/official-gifts/import-all", req)
|
||||
writeCommandResultAPI(w, result, err)
|
||||
|
|
|
|||
|
|
@ -110,13 +110,13 @@ func TestStarGiftRowJSONPreservesInt64AsDecimalStrings(t *testing.T) {
|
|||
|
||||
func TestDefaultGiftImportActionDecodes(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/actions/import-default-gift", strings.NewReader(`{
|
||||
"command_id":"c1","reason":"demo","confirm":true,"id":3
|
||||
"command_id":"c1","reason":"demo","confirm":true,"id":3,"enabled":true
|
||||
}`))
|
||||
var got importDefaultStarGiftAPIRequest
|
||||
if err := decodeJSON(req, &got); err != nil {
|
||||
t.Fatalf("decode default gift action: %v", err)
|
||||
}
|
||||
if got.ID != 3 || got.CommandID != "c1" || !got.Confirm {
|
||||
if got.ID != 3 || got.CommandID != "c1" || !got.Confirm || !got.Enabled {
|
||||
t.Fatalf("decoded default gift action = %+v", got)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
10
cmd/telesrv-admin/web/dist/assets/index-CBHSiG-t.js
vendored
Normal file
10
cmd/telesrv-admin/web/dist/assets/index-CBHSiG-t.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
cmd/telesrv-admin/web/dist/assets/index-cWo3_wIf.css
vendored
Normal file
1
cmd/telesrv-admin/web/dist/assets/index-cWo3_wIf.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
cmd/telesrv-admin/web/dist/index.html
vendored
4
cmd/telesrv-admin/web/dist/index.html
vendored
|
|
@ -5,8 +5,8 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/png" href="/logo.png" />
|
||||
<title>OwpenGram Admin</title>
|
||||
<script type="module" crossorigin src="/assets/index-6aaLOsAb.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-D2rrhA4q.css">
|
||||
<script type="module" crossorigin src="/assets/index-CBHSiG-t.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-cWo3_wIf.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
|
|
@ -273,6 +273,11 @@ const translations: Record<string, string> = {
|
|||
"gifts.officialUnnamed": "Unnamed official gift #{id}",
|
||||
"gifts.officialEmpty": "No official gifts match this category and search.",
|
||||
"gifts.includeCollectible": "Import the complete collectible pool, including crafted models",
|
||||
"gifts.importingProgress": "Importing {done} of {total}",
|
||||
"gifts.bulkImportCount": "{count} gifts available to import",
|
||||
"gifts.bulkImportDone": "Import complete",
|
||||
"gifts.bulkImportSummary": "Imported {imported}, skipped {skipped}, failed {failed}",
|
||||
"gifts.startBulkImport": "Start import",
|
||||
"gifts.limited": "Limited · {total}",
|
||||
"gifts.premium": "Premium only",
|
||||
"gifts.searchPlaceholder": "Search gift ID, title or format",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { CheckCircle2, ChevronLeft, ChevronRight, FileJson2, Gem, Loader2, Pause
|
|||
import lottie from "lottie-web/build/player/lottie_light_canvas";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { api, errorMessage } from "../api";
|
||||
import { api, APIError, errorMessage } from "../api";
|
||||
import { ActionButton } from "../components/ActionButton";
|
||||
import { Alert, Badge, EmptyRow, Metric, PageFrame, QueryPanel } from "../components/ui";
|
||||
import { useI18n } from "../i18n";
|
||||
|
|
@ -13,6 +13,11 @@ import { GiftCollectiblesModal } from "./GiftCollectiblesModal";
|
|||
type OfficialGiftCategory = "all" | "upgrade" | "craft" | "basic";
|
||||
type GiftPageSize = 10 | 20 | 50 | 100 | "all";
|
||||
|
||||
// The demo pool only has 3 placeholder gifts left after pruning to one per
|
||||
// capability tier (Spark/Star/Coin); hide the tab until real custom designs
|
||||
// replace them. Flip back to true to re-enable.
|
||||
const SHOW_DEFAULT_GIFTS_TAB = false;
|
||||
|
||||
function defaultGiftAttributeCount(gift: DefaultGiftRow) {
|
||||
return gift.model_count + gift.pattern_count + gift.backdrop_count;
|
||||
}
|
||||
|
|
@ -106,7 +111,7 @@ export function GiftsPage() {
|
|||
const [importOpen, setImportOpen] = useState(false);
|
||||
const [collectibleGift, setCollectibleGift] = useState<StarGiftRow | null>(null);
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const [importSource, setImportSource] = useState<"default" | "official" | "file">("default");
|
||||
const [importSource, setImportSource] = useState<"default" | "official" | "file">(SHOW_DEFAULT_GIFTS_TAB ? "default" : "official");
|
||||
const [defaultGifts, setDefaultGifts] = useState<DefaultGiftRow[]>([]);
|
||||
const [selectedDefaultID, setSelectedDefaultID] = useState(0);
|
||||
const [officialGifts, setOfficialGifts] = useState<OfficialStarGiftRow[]>([]);
|
||||
|
|
@ -128,6 +133,14 @@ export function GiftsPage() {
|
|||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [importError, setImportError] = useState("");
|
||||
const [bulkImportOpen, setBulkImportOpen] = useState<"default" | "official" | null>(null);
|
||||
const [bulkImportItems, setBulkImportItems] = useState<Array<DefaultGiftRow | OfficialStarGiftRow>>([]);
|
||||
const [bulkImportEnabled, setBulkImportEnabled] = useState(true);
|
||||
const [bulkImportReason, setBulkImportReason] = useState("");
|
||||
const [bulkImportBusy, setBulkImportBusy] = useState(false);
|
||||
const [bulkImportProgress, setBulkImportProgress] = useState({ done: 0, total: 0 });
|
||||
const [bulkImportError, setBulkImportError] = useState("");
|
||||
const [bulkImportResult, setBulkImportResult] = useState<{ imported: number; skipped: number; failed: number; errors: string[] } | null>(null);
|
||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||
const [bulkReason, setBulkReason] = useState("");
|
||||
const [bulkBusy, setBulkBusy] = useState(false);
|
||||
|
|
@ -301,6 +314,84 @@ export function GiftsPage() {
|
|||
setPreview(null);
|
||||
}
|
||||
|
||||
async function openBulkImport(source: "default" | "official") {
|
||||
setBulkImportOpen(source);
|
||||
setBulkImportItems([]);
|
||||
setBulkImportEnabled(true);
|
||||
setBulkImportReason("");
|
||||
setBulkImportBusy(false);
|
||||
setBulkImportProgress({ done: 0, total: 0 });
|
||||
setBulkImportError("");
|
||||
setBulkImportResult(null);
|
||||
try {
|
||||
if (source === "default") {
|
||||
const list = defaultGifts.length > 0 ? defaultGifts : (await api.defaultGifts()).gifts ?? [];
|
||||
setBulkImportItems(list);
|
||||
} else {
|
||||
const list = officialGifts.length > 0 ? officialGifts : (await api.officialGifts()).gifts ?? [];
|
||||
setBulkImportItems(list);
|
||||
}
|
||||
} catch (err) {
|
||||
setBulkImportError(errorMessage(err));
|
||||
}
|
||||
}
|
||||
|
||||
function closeBulkImport() {
|
||||
if (bulkImportBusy) return;
|
||||
setBulkImportOpen(null);
|
||||
}
|
||||
|
||||
async function runBulkImport() {
|
||||
if (!bulkImportOpen) return;
|
||||
if (!bulkImportReason.trim()) { setBulkImportError(t("action.reasonRequired")); return; }
|
||||
const source = bulkImportOpen;
|
||||
setBulkImportBusy(true); setBulkImportError(""); setBulkImportResult(null);
|
||||
setBulkImportProgress({ done: 0, total: bulkImportItems.length });
|
||||
let imported = 0, skipped = 0, failed = 0;
|
||||
const errors: string[] = [];
|
||||
for (const item of bulkImportItems) {
|
||||
const label = source === "default" ? (item as DefaultGiftRow).title : ((item as OfficialStarGiftRow).title || `#${(item as OfficialStarGiftRow).source_gift_id}`);
|
||||
try {
|
||||
// Stable per-gift command_id (mirrors the old server-side bulk
|
||||
// endpoint) so a gift already imported by a prior run is recognized
|
||||
// as a replay instead of creating a duplicate catalog entry -
|
||||
// CreateCatalogBundle has no unique constraint on title/source id to
|
||||
// fall back on. If this run's Enabled value differs from the run
|
||||
// that first created it, the server reports COMMAND_ID_CONFLICT
|
||||
// instead of silently re-importing; treat that as "skipped" too.
|
||||
const result = source === "default"
|
||||
? await api.importDefaultGift({
|
||||
command_id: `bulk-default-gift-${(item as DefaultGiftRow).id}`,
|
||||
reason: bulkImportReason.trim(),
|
||||
confirm: true,
|
||||
id: (item as DefaultGiftRow).id,
|
||||
enabled: bulkImportEnabled
|
||||
})
|
||||
: await api.importOfficialGift({
|
||||
command_id: `bulk-official-gift-${(item as OfficialStarGiftRow).source_gift_id}`,
|
||||
reason: bulkImportReason.trim(),
|
||||
confirm: true,
|
||||
source_gift_id: (item as OfficialStarGiftRow).source_gift_id,
|
||||
include_collectible: (item as OfficialStarGiftRow).can_upgrade,
|
||||
enabled: bulkImportEnabled
|
||||
});
|
||||
if (result.already_executed || result.details?.skipped) skipped++;
|
||||
else imported++;
|
||||
} catch (err) {
|
||||
if (err instanceof APIError && err.message === "COMMAND_ID_CONFLICT") {
|
||||
skipped++;
|
||||
} else {
|
||||
failed++;
|
||||
errors.push(`${label}: ${errorMessage(err)}`);
|
||||
}
|
||||
}
|
||||
setBulkImportProgress((prev) => ({ ...prev, done: prev.done + 1 }));
|
||||
}
|
||||
setBulkImportBusy(false);
|
||||
setBulkImportResult({ imported, skipped, failed, errors });
|
||||
await load();
|
||||
}
|
||||
|
||||
async function validateImport() {
|
||||
setBusy(true); setImportError(""); setPreview(null);
|
||||
try {
|
||||
|
|
@ -331,8 +422,10 @@ export function GiftsPage() {
|
|||
function startImport() {
|
||||
setGiftID("0"); setTitle(""); setStars("50"); setConvertStars("50"); setSortOrder("0");
|
||||
setEnabled(true); setReason(""); setFile(null); setPreview(null); setImportError("");
|
||||
setImportSource("default"); setSelectedDefaultID(0);
|
||||
setSourceGiftID(""); setOfficialQuery(""); setOfficialCategory("all"); setImportOpen(true);
|
||||
setImportSource(SHOW_DEFAULT_GIFTS_TAB ? "default" : "official"); setSelectedDefaultID(0);
|
||||
setSourceGiftID(""); setOfficialQuery(""); setOfficialCategory("all");
|
||||
setBulkImportBusy(false); setBulkImportProgress({ done: 0, total: 0 }); setBulkImportError("");
|
||||
setImportOpen(true);
|
||||
}
|
||||
|
||||
function startRevision(gift: StarGiftRow) {
|
||||
|
|
@ -434,22 +527,18 @@ export function GiftsPage() {
|
|||
<div className={`command-step ${preview ? "active" : ""}`}><span>3</span><strong>{t("gifts.stepImport")}</strong></div>
|
||||
</div>
|
||||
{giftID === "0" && <div className="gift-source-tabs">
|
||||
<button className={`btn ${importSource === "default" ? "primary" : ""}`} type="button" onClick={() => { setImportSource("default"); setPreview(null); }}>{t("gifts.defaultSource")}</button>
|
||||
{SHOW_DEFAULT_GIFTS_TAB && <button className={`btn ${importSource === "default" ? "primary" : ""}`} type="button" onClick={() => { setImportSource("default"); setPreview(null); }}>{t("gifts.defaultSource")}</button>}
|
||||
<button className={`btn ${importSource === "official" ? "primary" : ""}`} type="button" onClick={() => { setImportSource("official"); setPreview(null); }}>{t("gifts.officialSource")}</button>
|
||||
<button className={`btn ${importSource === "file" ? "primary" : ""}`} type="button" onClick={() => { setImportSource("file"); setPreview(null); }}>{t("gifts.fileSource")}</button>
|
||||
</div>}
|
||||
{importSource === "default" && giftID === "0" ? <section className="official-gift-picker">
|
||||
{importSource === "default" && giftID === "0" && SHOW_DEFAULT_GIFTS_TAB ? <section className="official-gift-picker">
|
||||
<div className="gift-import-note"><span>{t("gifts.defaultHint")}</span><div className="gift-format-chips"><span>{defaultGifts.length}</span><span>OwpenGram</span></div></div>
|
||||
<div className="official-gift-bulk-import">
|
||||
<ActionButton
|
||||
label={t("gifts.importAllDefault")}
|
||||
path="/api/actions/import-all-default-gifts"
|
||||
payload={() => ({})}
|
||||
tone="neutral"
|
||||
icon={<Upload size={14} />}
|
||||
onDone={() => void load()}
|
||||
/>
|
||||
<button className="btn" type="button" onClick={() => openBulkImport("default")}>
|
||||
<Upload size={14} /> {t("gifts.importAllDefault")}
|
||||
</button>
|
||||
</div>
|
||||
<label className="gift-switch"><input type="checkbox" checked={enabled} onChange={(e) => { setEnabled(e.target.checked); setPreview(null); }} /><span className="gift-switch-track" aria-hidden="true"><span /></span><span>{t("gifts.enableAfterImport")}</span></label>
|
||||
<div className="official-gift-list" role="listbox" aria-label={t("gifts.defaultSelect")}>
|
||||
{defaultGifts.map((gift) => {
|
||||
const isSelected = gift.id === selectedDefaultID;
|
||||
|
|
@ -479,14 +568,9 @@ export function GiftsPage() {
|
|||
</section> : importSource === "official" && giftID === "0" ? <section className="official-gift-picker">
|
||||
<div className="gift-import-note"><span>{t("gifts.officialHint")}</span><div className="gift-format-chips"><span>{officialGifts.length}</span><span>SHA-256</span></div></div>
|
||||
<div className="official-gift-bulk-import">
|
||||
<ActionButton
|
||||
label={t("gifts.importAllOfficial")}
|
||||
path="/api/actions/import-all-official-gifts"
|
||||
payload={() => ({})}
|
||||
tone="neutral"
|
||||
icon={<Upload size={14} />}
|
||||
onDone={() => void load()}
|
||||
/>
|
||||
<button className="btn" type="button" onClick={() => openBulkImport("official")}>
|
||||
<Upload size={14} /> {t("gifts.importAllOfficial")}
|
||||
</button>
|
||||
</div>
|
||||
<div className="official-gift-tools">
|
||||
<label className="searchbox"><Search size={15} /><input value={officialQuery} onChange={(e) => setOfficialQuery(e.target.value)} placeholder={t("gifts.officialSearch")} /></label>
|
||||
|
|
@ -569,6 +653,38 @@ export function GiftsPage() {
|
|||
</div>,
|
||||
document.body
|
||||
)}
|
||||
{bulkImportOpen && createPortal(
|
||||
<div className="modal-backdrop" role="presentation">
|
||||
<section className="modal command-modal gift-bulk-import-modal" role="dialog" aria-modal="true"
|
||||
aria-label={bulkImportOpen === "default" ? t("gifts.importAllDefault") : t("gifts.importAllOfficial")}>
|
||||
<div className="modal-head">
|
||||
<div><div className="eyebrow">{t("gifts.importEyebrow")}</div><h2>{bulkImportOpen === "default" ? t("gifts.importAllDefault") : t("gifts.importAllOfficial")}</h2></div>
|
||||
<button className="icon-btn" type="button" onClick={closeBulkImport} disabled={bulkImportBusy} aria-label={t("action.close")}><X size={15} /></button>
|
||||
</div>
|
||||
<div className="command-body">
|
||||
<div className="gift-import-note"><span>{t("gifts.bulkImportCount", { count: bulkImportItems.length })}</span></div>
|
||||
<label className="gift-switch"><input type="checkbox" checked={bulkImportEnabled} disabled={bulkImportBusy} onChange={(e) => setBulkImportEnabled(e.target.checked)} /><span className="gift-switch-track" aria-hidden="true"><span /></span><span>{t("gifts.enableAfterImport")}</span></label>
|
||||
<label className="gift-reason-field"><span>{t("gifts.reason")}</span><input value={bulkImportReason} placeholder={t("gifts.reasonPlaceholder")} disabled={bulkImportBusy} onChange={(e) => setBulkImportReason(e.target.value)} /></label>
|
||||
{bulkImportBusy && <div className="gift-bulk-import-progress">
|
||||
<div className="gift-bulk-import-progress-bar"><div style={{ width: `${bulkImportProgress.total ? Math.round((bulkImportProgress.done / bulkImportProgress.total) * 100) : 0}%` }} /></div>
|
||||
<span>{t("gifts.importingProgress", { done: bulkImportProgress.done, total: bulkImportProgress.total })}</span>
|
||||
</div>}
|
||||
{bulkImportError && <Alert>{bulkImportError}</Alert>}
|
||||
{bulkImportResult && <div className="gift-validation">
|
||||
<div className="gift-validation-head"><CheckCircle2 size={17} /><div><strong>{t("gifts.bulkImportDone")}</strong><span>{t("gifts.bulkImportSummary", { imported: bulkImportResult.imported, skipped: bulkImportResult.skipped, failed: bulkImportResult.failed })}</span></div></div>
|
||||
{bulkImportResult.errors.length > 0 && <pre>{bulkImportResult.errors.join("\n")}</pre>}
|
||||
</div>}
|
||||
</div>
|
||||
<div className="modal-actions">
|
||||
<button className="btn" type="button" onClick={closeBulkImport} disabled={bulkImportBusy}>{t("common.close")}</button>
|
||||
<button className="btn primary" type="button" onClick={runBulkImport} disabled={bulkImportBusy || bulkImportItems.length === 0}>
|
||||
{bulkImportBusy ? <Loader2 className="spin" size={15} /> : <Upload size={15} />} {t("gifts.startBulkImport")}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</div>,
|
||||
document.body
|
||||
)}
|
||||
{collectibleGift && <GiftCollectiblesModal gift={collectibleGift} onClose={() => setCollectibleGift(null)} onPublished={() => void load()} />}
|
||||
</PageFrame>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -275,9 +275,18 @@
|
|||
.gift-list-summary { margin-left: auto; color: var(--muted); font-size: 11px; font-weight: 700; }
|
||||
|
||||
.gift-import-modal { width: min(860px, 100%); }
|
||||
.gift-bulk-import-modal { width: min(480px, 100%); }
|
||||
.gift-bulk-import-modal .command-body { display: grid; gap: 14px; padding: 16px 18px; }
|
||||
.gift-import-modal-body { gap: 14px; }
|
||||
.gift-source-tabs { display: flex; gap: 8px; }
|
||||
.official-gift-picker { display: grid; min-width: 0; gap: 12px; }
|
||||
.official-gift-bulk-import { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
|
||||
.gift-bulk-import-progress { display: flex; align-items: center; gap: 8px; min-width: 180px; }
|
||||
.gift-bulk-import-progress-bar {
|
||||
flex: 1 1 auto; width: 120px; height: 6px; overflow: hidden; background: #e3e8ef; border-radius: 999px;
|
||||
}
|
||||
.gift-bulk-import-progress-bar > div { height: 100%; background: var(--brand); border-radius: 999px; transition: width .2s ease; }
|
||||
.gift-bulk-import-progress span { color: var(--muted); font-size: 11px; font-weight: 700; white-space: nowrap; }
|
||||
.official-gift-tools { display: flex; align-items: center; gap: 12px; }
|
||||
.official-gift-tools .searchbox { width: 100%; }
|
||||
.official-gift-tools > span { flex: 0 0 auto; color: var(--muted); font-size: 11px; font-weight: 750; }
|
||||
|
|
|
|||
|
|
@ -453,6 +453,11 @@ func run(logger *zap.Logger) error {
|
|||
} else if seeded {
|
||||
logger.Info("官方系统账号头像种子导入完成", zap.Int64("photo_id", domain.OfficialSystemUserPhotoID))
|
||||
}
|
||||
if seeded, err := filesService.SeedBotFatherAvatar(ctx); err != nil {
|
||||
return fmt.Errorf("seed botfather avatar: %w", err)
|
||||
} else if seeded {
|
||||
logger.Info("BotFather 头像种子导入完成", zap.Int64("photo_id", domain.BotFatherUserPhotoID))
|
||||
}
|
||||
if stats, err := filesService.WarmCaches(ctx); err != nil {
|
||||
logger.Warn("媒体资源缓存预热失败", zap.Error(err))
|
||||
} else if stats.StickerSets > 0 || stats.Documents > 0 || stats.Blobs > 0 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue