From 6e44e4dec170e5fece94790c6a96b337e2a2ec03 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 14 Aug 2026 20:23:11 +0330 Subject: [PATCH] #498 ui for public data generation --- .../Areas/Admin/Pages/ModifyPage.cshtml | 1 + .../Areas/Admin/Pages/ModifyPage.cshtml.cs | 22 ++++++++++++ GanjooRazor/Pages/Shared/_AdminLayout.cshtml | 19 ++++++++++ GanjooRazor/appsettings.json | 4 +-- RMuseum/RMuseum.xml | 36 ++++++++++++++++++- 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml b/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml index 7a73a9f9..578c5a9a 100644 --- a/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml +++ b/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml @@ -231,6 +231,7 @@ بازسازی صفحات آمار و اوزان عروضی بازسازی صفحات استقبالها بازسازی آمار منابع دیجیتال + بازسازی دادهٔ عمومی برگردان تاجیکی diff --git a/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml.cs b/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml.cs index 63bd2b90..cf48d3b4 100644 --- a/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml.cs +++ b/GanjooRazor/Areas/Admin/Pages/ModifyPage.cshtml.cs @@ -339,6 +339,28 @@ namespace GanjooRazor.Areas.Admin.Pages return new OkObjectResult(false); } + /// + /// (re)generate the public git-tracked data export (poets/categories/poems as JSON, + /// pushed to the configured git remote) — runs as a background job, same as the other + /// rebuild/regenerate tools on this page; check the Jobs page for progress + /// + public async Task OnPostRegeneratePublicDataAsync() + { + using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) + { + if (await GanjoorSessionChecker.PrepareClient(secureClient, Request, Response)) + { + HttpResponseMessage response = await secureClient.PostAsync($"{APIRoot.Url}/api/ganjoor/publicdata/batchexport", null); + if (!response.IsSuccessStatusCode) + { + return BadRequest(JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync())); + } + return new OkObjectResult(true); + } + } + return new OkObjectResult(false); + } + public async Task OnPostRefillSectionsCoupletCountsAsync() { diff --git a/GanjooRazor/Pages/Shared/_AdminLayout.cshtml b/GanjooRazor/Pages/Shared/_AdminLayout.cshtml index 7dee9723..f88f405b 100644 --- a/GanjooRazor/Pages/Shared/_AdminLayout.cshtml +++ b/GanjooRazor/Pages/Shared/_AdminLayout.cshtml @@ -186,6 +186,25 @@ }); } + async function regeneratePublicData() { + var ok = await upConfirm('آیا از بازسازی و ارسال دادهٔ عمومی گنجور (مخزن گیت) اطمینان دارید؟ ممکن است مدتی طول بکشد.'); + if (!ok) return; + + var url = '?handler=RegeneratePublicData'; + + $.ajax({ + type: "POST", + url: url, + error: function () { + upToast('خطا رخ داد.', 'error'); + }, + success: function () { + upToast('فرایند بازسازی دادهٔ عمومی در پس‌زمینه شروع شد.', 'success'); + }, + + }); + } + async function refillCoupletCounts() { diff --git a/GanjooRazor/appsettings.json b/GanjooRazor/appsettings.json index 1a1fbe5e..2f676f05 100644 --- a/GanjooRazor/appsettings.json +++ b/GanjooRazor/appsettings.json @@ -8,8 +8,8 @@ }, "AllowedHosts": "*", "TrackingScript": "", - "APIRoot": "http://localhost:3439", - "GlobalAPIRoot": "http://localhost:3439", + "APIRoot": "https://api.ganjoor.net", + "GlobalAPIRoot": "https://api.ganjoor.net", "SiteUrl": "http://localhost:33081", "MockSpotify": "False", "Spotify": { diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml index b60db1d6..f4b4deac 100644 --- a/RMuseum/RMuseum.xml +++ b/RMuseum/RMuseum.xml @@ -20601,6 +20601,15 @@ + + + same as , but against an explicitly-passed + context instead of the injected — needed so background jobs + that construct their own short-lived (because the + request-scoped may already be disposed by the time a background + job runs) can call this too, e.g. right after a public-data import finishes. + + like / dislike / clear rating for a comment @@ -21150,7 +21159,18 @@ of what actually gets written. - + + + Batch-loads this poet's entire sections/verses in two queries (instead of the + two-per-poem queries the old per-poem approach ran), then walks the poet's category + tree writing everything from memory. This is the fix for the export consistently + taking about as long on every run regardless of how much content changed — the + "skip unchanged files" logic in DeterministicJsonWriter only ever saved disk writes, + never the DB round-trips, which were the actual dominant cost (roughly 3 sequential + queries per poem — tens of thousands of round-trips for the full corpus, every run). + + + recursively writes _cat.json for and every poem directly under it, then recurses into child categories. Returns the number of poems written @@ -21161,6 +21181,12 @@ either; every category/poem under a published poet is exported. + + + Pure in-memory write — no DB access. Sections/verses/metre are pre-loaded by the caller + (see ) instead of queried per poem. + + generates the repo-root API.md every run, so the docs can never drift out of sync with @@ -21168,6 +21194,14 @@ prose, add it here, not in the generated file. + + + generates the repo-root README.md every run — the landing document GitHub shows by + default, so this is where a first-time visitor's "where do I even start?" question + needs to be answered in the first few lines, before they'd ever think to look for + API.md. + + Category (and root-poet) pages don't carry a real production page id in the public