people tags #387

This commit is contained in:
Hamid Reza Mohammadi 2026-09-30 19:14:17 +03:30
parent 6db7c1ec77
commit 800857aadc
5 changed files with 114 additions and 6 deletions

View File

@ -2,6 +2,7 @@
@model GanjooRazor.Areas.User.Pages.EditsModel @model GanjooRazor.Areas.User.Pages.EditsModel
@using DNTPersianUtils.Core @using DNTPersianUtils.Core
@using RMuseum.Models.Ganjoor @using RMuseum.Models.Ganjoor
@using GanjooRazor.Utils
@{ @{
Layout = "_UserPanelLayout"; Layout = "_UserPanelLayout";
ViewData["Title"] = "ویرایش‌های من"; ViewData["Title"] = "ویرایش‌های من";
@ -279,7 +280,7 @@ else
{ {
<tr> <tr>
<td colspan="3"> <td colspan="3">
برچسب جغرافیایی/تاریخی - @(GeoDateTagCorrectionDisplay.IsPersonTag(geoTag) ? "شخصیت" : "برچسب جغرافیایی/تاریخی") -
@if (geoTag.CoupletIndex == null) @if (geoTag.CoupletIndex == null)
{ {
<text>کل شعر</text> <text>کل شعر</text>
@ -304,6 +305,30 @@ else
</td> </td>
</tr> </tr>
} }
else if (GeoDateTagCorrectionDisplay.IsPersonTag(geoTag))
{
<tr>
<td>
<p style="color:red">-</p>
</td>
<td>
<p style="color:green">
@if (geoTag.PersonId != null)
{
<a href="javascript:void(0)" onclick="PersonWindow.open(@geoTag.PersonId)">@(geoTag.Person != null ? geoTag.Person.Name : $"شخصیت #{geoTag.PersonId}")</a>
}
else
{
var suggestedPersonName = GeoDateTagCorrectionDisplay.GetSuggestedPersonName(geoTag.SuggestedPersonGraphJson);
<text>شخصیت جدید@(string.IsNullOrEmpty(suggestedPersonName) ? "" : $": {suggestedPersonName}")</text>
}
</p>
</td>
<td>
<partial name="_ReviewResultBadge" model="geoTag.Result" />
</td>
</tr>
}
else else
{ {
<tr> <tr>

View File

@ -287,6 +287,11 @@ namespace GanjooRazor.Areas.User.Pages
var geoDateTagsRollback = new List<GanjoorPoemGeoDateTagCorrection>(); var geoDateTagsRollback = new List<GanjoorPoemGeoDateTagCorrection>();
foreach (var geoTag in currentCorrection.GeoDateTags.Where(g => g.Result == CorrectionReviewResult.Approved)) foreach (var geoTag in currentCorrection.GeoDateTags.Where(g => g.Result == CorrectionReviewResult.Approved))
{ {
// PersonId (if the deleted tag was a person tag) is part of what got snapshotted
// onto this same record when the delete request was approved, so it's already
// available here for GeoDateTagCorrectionDisplay.IsPersonTag to tell the two kinds
// of tag apart for the note text below.
var geoTagLabel = GeoDateTagCorrectionDisplay.IsPersonTag(geoTag) ? "شخصیت" : "برچسب جغرافیایی/تاریخی";
if (geoTag.MarkForDelete) if (geoTag.MarkForDelete)
{ {
// the original request deleted an existing tag - undo that by re-adding a tag with // the original request deleted an existing tag - undo that by re-adding a tag with
@ -302,7 +307,7 @@ namespace GanjooRazor.Areas.User.Pages
LunarDay = geoTag.LunarDay, LunarDay = geoTag.LunarDay,
PersonId = geoTag.PersonId, PersonId = geoTag.PersonId,
IgnoreInCategory = geoTag.IgnoreInCategory, IgnoreInCategory = geoTag.IgnoreInCategory,
SuggestionNote = $"برگشت حذف برچسب جغرافیایی/تاریخی با کد {correctionId}" SuggestionNote = $"برگشت حذف {geoTagLabel} با کد {correctionId}"
}); });
} }
else if (geoTag.ExistingTagId != null) else if (geoTag.ExistingTagId != null)
@ -314,7 +319,7 @@ namespace GanjooRazor.Areas.User.Pages
CoupletIndex = geoTag.CoupletIndex, CoupletIndex = geoTag.CoupletIndex,
MarkForDelete = true, MarkForDelete = true,
ExistingTagId = geoTag.ExistingTagId, ExistingTagId = geoTag.ExistingTagId,
SuggestionNote = $"برگشت افزودن برچسب جغرافیایی/تاریخی با کد {correctionId}" SuggestionNote = $"برگشت افزودن {geoTagLabel} با کد {correctionId}"
}); });
} }
} }

View File

@ -4,6 +4,7 @@
@using RMuseum.Models.Ganjoor @using RMuseum.Models.Ganjoor
@using RMuseum.Services.Implementation @using RMuseum.Services.Implementation
@using DNTPersianUtils.Core; @using DNTPersianUtils.Core;
@using GanjooRazor.Utils
@{ @{
Layout = "_UserPanelLayout"; Layout = "_UserPanelLayout";
ViewData["Title"] = "سوابق ویرایش"; ViewData["Title"] = "سوابق ویرایش";
@ -173,7 +174,7 @@ else
{ {
<tr> <tr>
<td colspan="2"> <td colspan="2">
برچسب جغرافیایی/تاریخی - @(GeoDateTagCorrectionDisplay.IsPersonTag(geoTag) ? "شخصیت" : "برچسب جغرافیایی/تاریخی") -
@if (geoTag.CoupletIndex == null) @if (geoTag.CoupletIndex == null)
{ {
<text>کل شعر</text> <text>کل شعر</text>
@ -195,6 +196,27 @@ else
</td> </td>
</tr> </tr>
} }
else if (GeoDateTagCorrectionDisplay.IsPersonTag(geoTag))
{
<tr>
<td>
<p class="red-color">-</p>
</td>
<td>
<p class="green-color">
@if (geoTag.PersonId != null)
{
<a href="javascript:void(0)" onclick="PersonWindow.open(@geoTag.PersonId)">@(geoTag.Person != null ? geoTag.Person.Name : $"شخصیت #{geoTag.PersonId}")</a>
}
else
{
var suggestedPersonName = GeoDateTagCorrectionDisplay.GetSuggestedPersonName(geoTag.SuggestedPersonGraphJson);
<text>شخصیت جدید@(string.IsNullOrEmpty(suggestedPersonName) ? "" : $": {suggestedPersonName}")</text>
}
</p>
</td>
</tr>
}
else else
{ {
<tr> <tr>

View File

@ -247,6 +247,11 @@ namespace GanjooRazor.Areas.User.Pages
var geoDateTagsRollback = new List<GanjoorPoemGeoDateTagCorrection>(); var geoDateTagsRollback = new List<GanjoorPoemGeoDateTagCorrection>();
foreach (var geoTag in currentCorrection.GeoDateTags.Where(g => g.Result == CorrectionReviewResult.Approved)) foreach (var geoTag in currentCorrection.GeoDateTags.Where(g => g.Result == CorrectionReviewResult.Approved))
{ {
// PersonId (if the deleted tag was a person tag) is part of what got snapshotted
// onto this same record when the delete request was approved, so it's already
// available here for GeoDateTagCorrectionDisplay.IsPersonTag to tell the two kinds
// of tag apart for the note text below.
var geoTagLabel = GeoDateTagCorrectionDisplay.IsPersonTag(geoTag) ? "شخصیت" : "برچسب جغرافیایی/تاریخی";
if (geoTag.MarkForDelete) if (geoTag.MarkForDelete)
{ {
// the original request deleted an existing tag - undo that by re-adding a tag with // the original request deleted an existing tag - undo that by re-adding a tag with
@ -262,7 +267,7 @@ namespace GanjooRazor.Areas.User.Pages
LunarDay = geoTag.LunarDay, LunarDay = geoTag.LunarDay,
PersonId = geoTag.PersonId, PersonId = geoTag.PersonId,
IgnoreInCategory = geoTag.IgnoreInCategory, IgnoreInCategory = geoTag.IgnoreInCategory,
SuggestionNote = $"برگشت حذف برچسب جغرافیایی/تاریخی با کد {correctionId}" SuggestionNote = $"برگشت حذف {geoTagLabel} با کد {correctionId}"
}); });
} }
else if (geoTag.ExistingTagId != null) else if (geoTag.ExistingTagId != null)
@ -274,7 +279,7 @@ namespace GanjooRazor.Areas.User.Pages
CoupletIndex = geoTag.CoupletIndex, CoupletIndex = geoTag.CoupletIndex,
MarkForDelete = true, MarkForDelete = true,
ExistingTagId = geoTag.ExistingTagId, ExistingTagId = geoTag.ExistingTagId,
SuggestionNote = $"برگشت افزودن برچسب جغرافیایی/تاریخی با کد {correctionId}" SuggestionNote = $"برگشت افزودن {geoTagLabel} با کد {correctionId}"
}); });
} }
} }

View File

@ -0,0 +1,51 @@
using Newtonsoft.Json;
using RMuseum.Models.Ganjoor;
using RMuseum.Models.Ganjoor.ViewModels;
namespace GanjooRazor.Utils
{
/// <summary>
/// GanjoorPoemGeoDateTagCorrection (Editor.cshtml's combined geo/date/person tag suggestion row)
/// carries both kinds of tag in one flat shape - see that class's own doc comment for why. The
/// review-history pages (Edits.cshtml, PoemCorrectionsHistory.cshtml) need to tell the two kinds
/// apart to render each sensibly (a place+date vs. a person's name), so that little bit of shared
/// logic lives here once instead of being duplicated - and previously drifting out of sync - in
/// both .cshtml files.
/// </summary>
public static class GeoDateTagCorrectionDisplay
{
/// <summary>
/// true if this suggestion is a person (شخصیت) tag rather than a geo/date tag - mirrors the
/// client-side _getSuggestionUiKind() helper in Editor.cshtml's script block, but only for the
/// "adding a new tag" case: a MarkForDelete row carries neither PersonId nor a location, so its
/// kind can't be recovered from the correction alone (the callers fall back to the generic
/// "برچسب موجود" wording for those, same as before this helper existed).
/// </summary>
public static bool IsPersonTag(GanjoorPoemGeoDateTagCorrection tag)
{
if (tag == null) return false;
return tag.PersonId != null || !string.IsNullOrEmpty(tag.SuggestedPersonGraphJson);
}
/// <summary>
/// best-effort display name for a brand-new person suggested via SuggestedPersonGraphJson -
/// just the name typed into the "new person" panel, ignoring any relatives/relations also
/// carried in that JSON (those aren't relevant to a one-line history row). Returns null if the
/// JSON is missing, malformed, or (defensively) has no person node.
/// </summary>
public static string GetSuggestedPersonName(string suggestedPersonGraphJson)
{
if (string.IsNullOrEmpty(suggestedPersonGraphJson)) return null;
try
{
var suggestion = JsonConvert.DeserializeObject<PersonGraphSuggestion>(suggestedPersonGraphJson);
return suggestion?.Person?.Name;
}
catch (JsonException)
{
// malformed JSON shouldn't blow up a history page - just fall back to no name
return null;
}
}
}
}