#421 geo tag moderaion

This commit is contained in:
Hamid Reza Mohammadi 2026-09-25 15:04:19 +03:30
parent 13d493978a
commit 9872a4b772
3 changed files with 129 additions and 0 deletions

View File

@ -2,6 +2,7 @@
@model GanjooRazor.Areas.Admin.Pages.ReviewEditsModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using DNTPersianUtils.Core
@using RMuseum.Models.Ganjoor
@{
Layout = "_AdminLayout";
ViewData["Title"] = "بازبینی ویرایش‌ها";
@ -38,6 +39,13 @@
}
}
function toggleGeoTagNewLocationFields(geoIndex) {
var select = document.getElementById('geotag' + geoIndex + '_location_select');
var fields = document.getElementById('geotag' + geoIndex + '_new_location_fields');
if (!select || !fields) return;
fields.style.display = (select.value === '0') ? '' : 'none';
}
function moderatePoemCorrections(verseCount, correctionId, geoTagCount) {
$('#moderatecorrections').hide();
@ -135,12 +143,22 @@
var geoTagReviewResult = [];
var geoTagReviewNotes = [];
var geoTagLocationId = [];
var geoTagLocationName = [];
var geoTagLatitude = [];
var geoTagLongitude = [];
for (var g = 0; g < (geoTagCount || 0); g++) {
var geoElementId = '#geotag' + (g + 1).toString() + '_review_result_Approved';
if ($(geoElementId).length > 0) {
var geoElementName = 'geotag' + (g + 1).toString() + '_review_result';
geoTagReviewResult.push($('input[name=' + geoElementName + ']:checked').val())
geoTagReviewNotes.push($('#geotag' + (g + 1).toString() + '_review_note').val())
var geoLocationSelect = $('#geotag' + (g + 1).toString() + '_location_select');
geoTagLocationId.push(geoLocationSelect.length > 0 ? geoLocationSelect.val() : '0');
geoTagLocationName.push($('#geotag' + (g + 1).toString() + '_location_name').val() || null);
geoTagLatitude.push($('#geotag' + (g + 1).toString() + '_latitude').val() || null);
geoTagLongitude.push($('#geotag' + (g + 1).toString() + '_longitude').val() || null);
}
}
@ -164,6 +182,10 @@
pms.poemformatReviewNote= $('#poemformat_review_note') == null ? null : $('#poemformat_review_note').val();
pms.geoTagReviewResult= geoTagReviewResult;
pms.geoTagReviewNotes= geoTagReviewNotes;
pms.geoTagLocationId= geoTagLocationId;
pms.geoTagLocationName= geoTagLocationName;
pms.geoTagLatitude= geoTagLatitude;
pms.geoTagLongitude= geoTagLongitude;
$.ajax({
type: "POST",
@ -852,6 +874,41 @@ else
}
</td>
</tr>
<tr>
<td colspan="2">
<p class="up-hint">
اگر کاربر در نام مکان یا مختصات آن اشتباه کرده اما پیشنهادش در اصل ارزش تأیید دارد، به‌جای رد کردن می‌توانید همین‌جا آن را اصلاح کنید:
</p>
<label for="geotag@(geoIndex)_location_select">اتصال به مکان موجود در فهرست (در صورت وجود اشتباه در تشخیص مکان):</label>
<select id="geotag@(geoIndex)_location_select" name="geotag@(geoIndex)_location_select" onchange="toggleGeoTagNewLocationFields(@geoIndex)">
<option value="0">-- بدون تغییر / پیشنهاد به‌عنوان مکان جدید --</option>
@foreach (var loc in (Model.Locations ?? new List<GanjoorGeoLocation>()))
{
if (loc.Id == 0) continue;
if (geoTag.LocationId == loc.Id)
{
<option value="@loc.Id" selected="selected">@loc.Name (@loc.Latitude, @loc.Longitude)</option>
}
else
{
<option value="@loc.Id">@loc.Name (@loc.Latitude, @loc.Longitude)</option>
}
}
</select>
@if (geoTag.LocationId == null)
{
<div id="geotag@(geoIndex)_new_location_fields">
<br>
<label for="geotag@(geoIndex)_location_name">نام اصلاح‌شدهٔ مکان:</label>
<input type="text" id="geotag@(geoIndex)_location_name" name="geotag@(geoIndex)_location_name" value="@geoTag.SuggestedLocationName" size="30" />
<label for="geotag@(geoIndex)_latitude">عرض جغرافیایی اصلاح‌شده:</label>
<input type="text" id="geotag@(geoIndex)_latitude" name="geotag@(geoIndex)_latitude" value="@geoTag.SuggestedLatitude" size="12" />
<label for="geotag@(geoIndex)_longitude">طول جغرافیایی اصلاح‌شده:</label>
<input type="text" id="geotag@(geoIndex)_longitude" name="geotag@(geoIndex)_longitude" value="@geoTag.SuggestedLongitude" size="12" />
</div>
}
</td>
</tr>
}
<tr>
<td colspan="2">

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Text;
@ -61,6 +63,12 @@ namespace GanjooRazor.Areas.Admin.Pages
/// </summary>
public Tuple<int, string>[] Couplets { get; set; }
/// <summary>
/// full location catalog, offered as an alternative to a user's new-location suggestion so the
/// moderator can correct a mistyped/duplicate name by linking it to the existing entry instead
/// </summary>
public List<GanjoorGeoLocation> Locations { get; set; }
/// <summary>
/// groups verses into couplets - same logic as SuggestQuoted.cshtml.cs's/Editor.cshtml.cs's GetCouplets,
/// duplicated here rather than shared, so this page doesn't take on a cross-file dependency on those
@ -175,6 +183,19 @@ namespace GanjooRazor.Areas.Admin.Pages
Couplets = GetCouplets(PageInformation.Poem.Verses);
if (Correction.GeoDateTags != null && Correction.GeoDateTags.Any())
{
var responseLocations = await secureClient.GetAsync($"{APIRoot.Url}/api/locations");
if (!responseLocations.IsSuccessStatusCode)
{
FatalError = JsonConvert.DeserializeObject<string>(await responseLocations.Content.ReadAsStringAsync());
return Page();
}
Locations = new List<GanjoorGeoLocation>();
Locations.Add(new GanjoorGeoLocation() { Id = 0, Latitude = 0, Longitude = 0, Name = "" });
Locations.AddRange(JsonConvert.DeserializeObject<GanjoorGeoLocation[]>(await responseLocations.Content.ReadAsStringAsync()));
}
if (PageInformation.Poem.Sections.Where(s => s.SectionType == PoemSectionType.WholePoem && !string.IsNullOrEmpty(s.RhymeLetters)).Any())
{
RhymeLetters = PageInformation.Poem.Sections.Where(s => s.SectionType == PoemSectionType.WholePoem && !string.IsNullOrEmpty(s.RhymeLetters)).OrderBy(s => s.VerseType).First().RhymeLetters;
@ -390,6 +411,43 @@ namespace GanjooRazor.Areas.Admin.Pages
{
return new BadRequestObjectResult("لطفاً تکلیف بررسی تمام برچسب‌های جغرافیایی/تاریخی پیشنهادی را مشخص کنید.");
}
if (!Correction.GeoDateTags[i].MarkForDelete)
{
// let the moderator fix a mistyped location name / wrong coordinates, or link to an
// existing catalog location, before the tag is approved - rather than only being able
// to approve the user's suggestion as-is or reject it outright
string correctedLocationIdText = (pms.geoTagLocationId != null && i < pms.geoTagLocationId.Length) ? pms.geoTagLocationId[i] : null;
if (!string.IsNullOrWhiteSpace(correctedLocationIdText) && int.TryParse(correctedLocationIdText, out int correctedLocationId) && correctedLocationId > 0)
{
Correction.GeoDateTags[i].LocationId = correctedLocationId;
Correction.GeoDateTags[i].SuggestedLocationName = null;
Correction.GeoDateTags[i].SuggestedLatitude = null;
Correction.GeoDateTags[i].SuggestedLongitude = null;
}
else if (Correction.GeoDateTags[i].LocationId == null)
{
string correctedName = (pms.geoTagLocationName != null && i < pms.geoTagLocationName.Length) ? pms.geoTagLocationName[i] : null;
string correctedLatText = (pms.geoTagLatitude != null && i < pms.geoTagLatitude.Length) ? pms.geoTagLatitude[i] : null;
string correctedLngText = (pms.geoTagLongitude != null && i < pms.geoTagLongitude.Length) ? pms.geoTagLongitude[i] : null;
if (!string.IsNullOrWhiteSpace(correctedName))
{
Correction.GeoDateTags[i].SuggestedLocationName = correctedName.Trim();
}
if (!string.IsNullOrWhiteSpace(correctedLatText) && !string.IsNullOrWhiteSpace(correctedLngText))
{
if (!double.TryParse(correctedLatText, NumberStyles.Float, CultureInfo.InvariantCulture, out double correctedLat)
|| !double.TryParse(correctedLngText, NumberStyles.Float, CultureInfo.InvariantCulture, out double correctedLng)
|| correctedLat < -90 || correctedLat > 90 || correctedLng < -180 || correctedLng > 180)
{
return new BadRequestObjectResult("مقدار اصلاح‌شدهٔ عرض/طول جغرافیایی نامعتبر است.");
}
Correction.GeoDateTags[i].SuggestedLatitude = correctedLat;
Correction.GeoDateTags[i].SuggestedLongitude = correctedLng;
}
}
}
Correction.GeoDateTags[i].Result = (CorrectionReviewResult)Enum.Parse(typeof(CorrectionReviewResult), pms.geoTagReviewResult[i]);
Correction.GeoDateTags[i].ReviewNote = (pms.geoTagReviewNotes != null && i < pms.geoTagReviewNotes.Length) ? pms.geoTagReviewNotes[i] : null;
}

View File

@ -18,5 +18,19 @@
public string poemformatReviewNote { get; set; }
public string[] geoTagReviewResult { get; set; }
public string[] geoTagReviewNotes { get; set; }
/// <summary>
/// moderator's corrected location for each geo tag, if they picked an existing catalog location
/// instead of what the user suggested (empty/"0" means no change to LocationId)
/// </summary>
public string[] geoTagLocationId { get; set; }
/// <summary>
/// moderator's corrected new-location name (fixes a typo in the user's suggestion), if any
/// </summary>
public string[] geoTagLocationName { get; set; }
/// <summary>
/// moderator's corrected new-location latitude/longitude (fixes wrong coordinates), if any
/// </summary>
public string[] geoTagLatitude { get; set; }
public string[] geoTagLongitude { get; set; }
}
}