diff --git a/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml b/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml index b0cc234f..55d48b99 100644 --- a/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml +++ b/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml @@ -4,8 +4,12 @@ @using RMuseum.Models.Ganjoor @{ Layout = "_UserPanelLayout"; - ViewData["Title"] = "پیشنهاد ویرایش نسبت خویشاوندی"; + bool isAffiliation = Model.Kind == PersonRelationSuggestionKind.Affiliation; + ViewData["Title"] = isAffiliation ? "پیشنهاد ویرایش وابستگی" : "پیشنهاد ویرایش نسبت خویشاوندی"; await GanjooRazor.Utils.GanjoorSessionChecker.ApplyPermissionsToViewData(Request, Response, ViewData); + string formAction = isAffiliation + ? $"/User/SuggestPersonRelationEdit?affiliationId={Model.Affiliation.Id}&Handler=SuggestEdit" + : $"/User/SuggestPersonRelationEdit?relationId={Model.Relation.Id}&Handler=SuggestEdit"; } @if (!string.IsNullOrEmpty(Model.LastError)) { @@ -15,10 +19,10 @@ else {

- پیشنهاد ویرایش نسبت: - @(Model.Relation.Person1 != null ? Model.Relation.Person1.Name : Model.Relation.Person1Id.ToString()) + @(isAffiliation ? "پیشنهاد ویرایش وابستگی:" : "پیشنهاد ویرایش نسبت:") + @Model.Person1Name و - @(Model.Relation.Person2 != null ? Model.Relation.Person2.Name : Model.Relation.Person2Id.ToString()) + @Model.Person2Name

@@ -32,9 +36,10 @@ else }
-
+ @Html.AntiForgeryToken() + @@ -42,29 +47,53 @@ else نوع درخواست: - +   - + - - نوع نسبت: - - - - - - - درجه (فقط برای نیا/نواده): -

مثلاً برای پدربزرگ/مادربزرگ عدد ۲ را وارد کنید. اگر نمی‌دانید خالی بگذارید.

- - - + @if (isAffiliation) + { + + نوع وابستگی: + + +

جهت وابستگی (کدام طرف زیردست/حامی/... است) قابل تغییر نیست؛ در صورت اشتباه بودن جهت، این وابستگی را حذف و یکی تازه پیشنهاد کنید.

+ + + } + else + { + + نوع نسبت: + + + + + + + درجه (فقط برای نیا/نواده): +

مثلاً برای پدربزرگ/مادربزرگ عدد ۲ را وارد کنید. اگر نمی‌دانید خالی بگذارید.

+ + + + } یادداشت (مستندسازی): diff --git a/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml.cs b/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml.cs index fde63ca2..8fca514e 100644 --- a/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml.cs +++ b/GanjooRazor/Areas/User/Pages/SuggestPersonRelationEdit.cshtml.cs @@ -12,10 +12,12 @@ using RMuseum.Models.Ganjoor; namespace GanjooRazor.Areas.User.Pages { /// - /// contributor-facing form for suggesting a change to, or removal of, an existing - /// GanjoorPersonRelation - the kinship-edge counterpart of SuggestPersonEdit.cshtml. Any - /// logged-in user may submit here; nothing is changed until a moderator approves it via - /// Admin/ReviewPersonRelationEdits. Reachable from a person's PersonWindow.open() modal. + /// contributor-facing form for suggesting a change to, or removal of, an existing edge between + /// two people - the kinship-edge/affiliation-edge counterpart of SuggestPersonEdit.cshtml. Covers + /// both kinds: pass relationId for a GanjoorPersonRelation (family), or affiliationId for a + /// GanjoorPersonAffiliation (non-family) - exactly one of the two is expected, matching which ✎ + /// link on PersonWindow the contributor came from. Any logged-in user may submit here; nothing is + /// changed until a moderator approves it via Admin/ReviewPersonRelationEdits. /// public class SuggestPersonRelationEditModel : LoginPartialEnabledPageModel { @@ -27,50 +29,116 @@ namespace GanjooRazor.Areas.User.Pages public string LastResult { get; set; } + /// + /// "family" when editing a GanjoorPersonRelation (Relation is populated), "affiliation" when + /// editing a GanjoorPersonAffiliation (Affiliation is populated) - decides which of the two + /// the view renders and which Suggestion.Existing*Id gets set on post + /// + public PersonRelationSuggestionKind Kind { get; set; } + public GanjoorPersonRelation Relation { get; set; } + public GanjoorPersonAffiliation Affiliation { get; set; } + + /// + /// whichever side (Relation.Person1/Person2 or Affiliation.Person1/Person2) is populated - + /// used by the view for the page heading/links without needing to branch on Kind there too + /// + public int Person1Id => Kind == PersonRelationSuggestionKind.Affiliation ? Affiliation.Person1Id : Relation.Person1Id; + public string Person1Name => Kind == PersonRelationSuggestionKind.Affiliation ? (Affiliation.Person1?.Name ?? Affiliation.Person1Id.ToString()) : (Relation.Person1?.Name ?? Relation.Person1Id.ToString()); + public int Person2Id => Kind == PersonRelationSuggestionKind.Affiliation ? Affiliation.Person2Id : Relation.Person2Id; + public string Person2Name => Kind == PersonRelationSuggestionKind.Affiliation ? (Affiliation.Person2?.Name ?? Affiliation.Person2Id.ToString()) : (Relation.Person2?.Name ?? Relation.Person2Id.ToString()); + [BindProperty] public GanjoorPersonRelationEditSuggestion Suggestion { get; set; } [BindProperty] public string Action { get; set; } // "Modify" or "Remove", from the posted radio buttons - private async Task PrepareRelationAsync(int relationId) + private async Task PrepareAsync(int? relationId, int? affiliationId) { - var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/people/relations/{relationId}"); - if (!response.IsSuccessStatusCode) + if (affiliationId == null && relationId == null) { - LastError = await ReadErrorMessageAsync(response); + LastError = "شناسهٔ نسبت یا وابستگی مشخص نشده است."; return false; } - Relation = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - if (Relation == null) + if (affiliationId != null) { - LastError = "نسبتی با این کد پیدا نشد."; - return false; - } + Kind = PersonRelationSuggestionKind.Affiliation; - return true; + var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/people/affiliations/{affiliationId.Value}"); + if (!response.IsSuccessStatusCode) + { + LastError = await ReadErrorMessageAsync(response); + return false; + } + + Affiliation = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + if (Affiliation == null) + { + LastError = "وابستگی‌ای با این کد پیدا نشد."; + return false; + } + + return true; + } + else + { + Kind = PersonRelationSuggestionKind.Family; + + var response = await _httpClient.GetAsync($"{APIRoot.Url}/api/people/relations/{relationId.Value}"); + if (!response.IsSuccessStatusCode) + { + LastError = await ReadErrorMessageAsync(response); + return false; + } + + Relation = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + if (Relation == null) + { + LastError = "نسبتی با این کد پیدا نشد."; + return false; + } + + return true; + } } - private void FillSuggestionFromCurrentRelation() + private void FillSuggestionFromCurrent() { - // pre-filled with the relation's CURRENT values, same convention as SuggestPersonEdit - + // pre-filled with the edge's CURRENT values, same convention as SuggestPersonEdit - // submitting a plain "Modify" without changing anything is a harmless no-op - Suggestion = new GanjoorPersonRelationEditSuggestion() + if (Kind == PersonRelationSuggestionKind.Affiliation) { - Action = PersonRelationSuggestionAction.Modify, - ExistingRelationId = Relation.Id, - Person1Id = Relation.Person1Id, - Person2Id = Relation.Person2Id, - SuggestedRelationType = Relation.RelationType, - SuggestedDegreeHint = Relation.DegreeHint, - SuggestedNote = Relation.Note, - }; + Suggestion = new GanjoorPersonRelationEditSuggestion() + { + Action = PersonRelationSuggestionAction.Modify, + Kind = PersonRelationSuggestionKind.Affiliation, + ExistingAffiliationId = Affiliation.Id, + Person1Id = Affiliation.Person1Id, + Person2Id = Affiliation.Person2Id, + SuggestedAffiliationType = Affiliation.AffiliationType, + SuggestedNote = Affiliation.Note, + }; + } + else + { + Suggestion = new GanjoorPersonRelationEditSuggestion() + { + Action = PersonRelationSuggestionAction.Modify, + Kind = PersonRelationSuggestionKind.Family, + ExistingRelationId = Relation.Id, + Person1Id = Relation.Person1Id, + Person2Id = Relation.Person2Id, + SuggestedRelationType = Relation.RelationType, + SuggestedDegreeHint = Relation.DegreeHint, + SuggestedNote = Relation.Note, + }; + } } - public async Task OnGetAsync(int relationId) + public async Task OnGetAsync(int? relationId, int? affiliationId) { InitializeCommonPageState(); @@ -79,17 +147,17 @@ namespace GanjooRazor.Areas.User.Pages return Redirect($"/login?redirect={Uri.EscapeDataString(Request.Path + Request.QueryString)}"); } - if (!await PrepareRelationAsync(relationId)) + if (!await PrepareAsync(relationId, affiliationId)) { return Page(); } - FillSuggestionFromCurrentRelation(); + FillSuggestionFromCurrent(); return Page(); } - public async Task OnPostSuggestEditAsync(int relationId) + public async Task OnPostSuggestEditAsync(int? relationId, int? affiliationId) { InitializeCommonPageState(); @@ -100,13 +168,23 @@ namespace GanjooRazor.Areas.User.Pages LastResult = ""; - if (!await PrepareRelationAsync(relationId)) + if (!await PrepareAsync(relationId, affiliationId)) { return Page(); } - Suggestion.ExistingRelationId = Relation.Id; + Suggestion.Kind = Kind; Suggestion.Action = Action == "Remove" ? PersonRelationSuggestionAction.Remove : PersonRelationSuggestionAction.Modify; + if (Kind == PersonRelationSuggestionKind.Affiliation) + { + Suggestion.ExistingAffiliationId = Affiliation.Id; + Suggestion.ExistingRelationId = null; + } + else + { + Suggestion.ExistingRelationId = Relation.Id; + Suggestion.ExistingAffiliationId = null; + } using (HttpClient secureClient = new HttpClient(new GanjoorReloginHandler(Request, Response))) { @@ -119,13 +197,13 @@ namespace GanjooRazor.Areas.User.Pages if (!response.IsSuccessStatusCode) { LastResult = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - FillSuggestionFromCurrentRelation(); + FillSuggestionFromCurrent(); return Page(); } - LastResult = $"پیشنهاد شما ثبت شد و پس از بررسی توسط مدیران اعمال خواهد شد. مشاهدهٔ اطلاعات این شخصیت"; + LastResult = $"پیشنهاد شما ثبت شد و پس از بررسی توسط مدیران اعمال خواهد شد. مشاهدهٔ اطلاعات این شخصیت"; - FillSuggestionFromCurrentRelation(); + FillSuggestionFromCurrent(); return Page(); } diff --git a/GanjooRazor/Pages/PersonWindow.cshtml b/GanjooRazor/Pages/PersonWindow.cshtml index 7407a713..28550d25 100644 --- a/GanjooRazor/Pages/PersonWindow.cshtml +++ b/GanjooRazor/Pages/PersonWindow.cshtml @@ -85,7 +85,13 @@ else @if (Model.AffiliationRows.Count > 0) { -

وابستگی‌های غیرخویشاوندی

+

+ وابستگی‌های غیرخویشاوندی + @if (Model.LoggedIn) + { + افزودن وابستگی جدید + } +

    @foreach (var row in Model.AffiliationRows) { @@ -95,10 +101,21 @@ else { (@row.Note) } + @if (Model.LoggedIn) + { + ✎ + } }
} + else if (Model.LoggedIn) + { +

+ وابستگی‌های غیرخویشاوندی + افزودن وابستگی جدید +

+ } @if (Model.Poems != null && Model.Poems.Length > 0) { diff --git a/GanjooRazor/Pages/PersonWindow.cshtml.cs b/GanjooRazor/Pages/PersonWindow.cshtml.cs index 095a1de0..425018b6 100644 --- a/GanjooRazor/Pages/PersonWindow.cshtml.cs +++ b/GanjooRazor/Pages/PersonWindow.cshtml.cs @@ -61,6 +61,13 @@ namespace GanjooRazor.Pages public class PersonAffiliationDisplayRow { + /// + /// the underlying GanjoorPersonAffiliation row's own id - used to link to + /// /User/SuggestPersonRelationEdit?affiliationId={AffiliationId} for suggesting a + /// change/removal of this edge, same role RelationId plays on PersonRelationDisplayRow + /// + public int AffiliationId { get; set; } + /// /// full Persian sentence with a "{0}" placeholder for where the other person's linked /// name goes (kept as a placeholder, rather than a pre-built string, so the .cshtml can @@ -156,6 +163,7 @@ namespace GanjooRazor.Pages bool subjectServes = a.SubjectIsPerson1 || IsSymmetricAffiliation(a.AffiliationType); AffiliationRows.Add(new PersonAffiliationDisplayRow() { + AffiliationId = a.Id, SentenceBeforeOtherName = subjectServes ? $"این شخصیت {roleWord} " : "", SentenceAfterOtherName = subjectServes ? " بود" : $" {roleWord} این شخصیت بود", OtherPersonId = a.OtherPersonId, diff --git a/RMuseum/Controllers/GanjoorRelatedPersonController.cs b/RMuseum/Controllers/GanjoorRelatedPersonController.cs index 0af6f51f..7f942e7e 100644 --- a/RMuseum/Controllers/GanjoorRelatedPersonController.cs +++ b/RMuseum/Controllers/GanjoorRelatedPersonController.cs @@ -245,6 +245,24 @@ namespace RMuseum.Controllers return Ok(res.Result); } + /// + /// get a single affiliation edge by its own id, with both sides' names resolved - used by + /// /SuggestPersonRelationEdit?affiliationId={affiliationId} to show what it's about + /// + /// + /// + [HttpGet("affiliations/{affiliationId:int}")] + [AllowAnonymous] + [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorPersonAffiliation))] + [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] + public async Task GetAffiliationByIdAsync(int affiliationId) + { + var res = await _personService.GetAffiliationByIdAsync(affiliationId); + if (!string.IsNullOrEmpty(res.ExceptionString)) + return BadRequest(res.ExceptionString); + return Ok(res.Result); + } + /// /// suggest an addition, change or removal of a kinship edge - any logged-in user, same as /// suggesting a person edit. Goes into the pending queue; does not change anything. diff --git a/RMuseum/Models/Ganjoor/ViewModels/GanjoorPersonRelationsViewModel.cs b/RMuseum/Models/Ganjoor/ViewModels/GanjoorPersonRelationsViewModel.cs index bfefdb8b..8a2be08c 100644 --- a/RMuseum/Models/Ganjoor/ViewModels/GanjoorPersonRelationsViewModel.cs +++ b/RMuseum/Models/Ganjoor/ViewModels/GanjoorPersonRelationsViewModel.cs @@ -74,6 +74,13 @@ namespace RMuseum.Models.Ganjoor.ViewModels /// public class GanjoorPersonAffiliationInfo { + /// + /// the underlying GanjoorPersonAffiliation row's own id - used to link to + /// /User/SuggestPersonRelationEdit?affiliationId={Id} for suggesting a change/removal of + /// this edge, same role RelationId plays on GanjoorPersonRelationInfo + /// + public int Id { get; set; } + /// /// the other person in this tie /// diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml index 371bc22a..ba112e7d 100644 --- a/RMuseum/RMuseum.xml +++ b/RMuseum/RMuseum.xml @@ -2929,6 +2929,14 @@ + + + get a single affiliation edge by its own id, with both sides' names resolved - used by + /SuggestPersonRelationEdit?affiliationId={affiliationId} to show what it's about + + + + suggest an addition, change or removal of a kinship edge - any logged-in user, same as @@ -13559,6 +13567,13 @@ as GanjoorPersonRelationInfo above, but for a non-family tie + + + the underlying GanjoorPersonAffiliation row's own id - used to link to + /User/SuggestPersonRelationEdit?affiliationId={Id} for suggesting a change/removal of + this edge, same role RelationId plays on GanjoorPersonRelationInfo + + the other person in this tie @@ -18422,6 +18437,14 @@ + + + get a single affiliation edge by its own id, with both sides' names resolved - used by + /User/SuggestPersonRelationEdit?affiliationId={affiliationId} to show what it's about + + + + submit a suggested addition, change or removal of a kinship edge - goes into the @@ -21997,6 +22020,15 @@ + + + get a single affiliation edge by its own id, with both sides' names resolved - the + Kind == Affiliation counterpart of GetRelationByIdAsync, used the same way by + /User/SuggestPersonRelationEdit?affiliationId={id} + + + + submit a suggested addition, change or removal of a kinship edge diff --git a/RMuseum/Services/IGanjoorRelatedPersonService.cs b/RMuseum/Services/IGanjoorRelatedPersonService.cs index 05ac066e..fb35811f 100644 --- a/RMuseum/Services/IGanjoorRelatedPersonService.cs +++ b/RMuseum/Services/IGanjoorRelatedPersonService.cs @@ -105,6 +105,14 @@ namespace RMuseum.Services /// Task> GetRelationByIdAsync(int relationId); + /// + /// get a single affiliation edge by its own id, with both sides' names resolved - used by + /// /User/SuggestPersonRelationEdit?affiliationId={affiliationId} to show what it's about + /// + /// + /// + Task> GetAffiliationByIdAsync(int affiliationId); + /// /// submit a suggested addition, change or removal of a kinship edge - goes into the /// pending queue, does not change anything until a moderator approves it diff --git a/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs b/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs index fc2d5a7f..a9648abf 100644 --- a/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs +++ b/RMuseum/Services/Implementation/GanjoorRelatedPersonService.cs @@ -123,6 +123,7 @@ namespace RMuseum.Services.Implementation var affiliations = affiliationRows.Select(a => new GanjoorPersonAffiliationInfo() { + Id = a.Id, OtherPersonId = a.Person1Id == id ? a.Person2Id : a.Person1Id, OtherPersonName = a.Person1Id == id ? a.Person2.Name : a.Person1.Name, AffiliationType = a.AffiliationType, @@ -540,6 +541,36 @@ namespace RMuseum.Services.Implementation } } + /// + /// get a single affiliation edge by its own id, with both sides' names resolved - the + /// Kind == Affiliation counterpart of GetRelationByIdAsync, used the same way by + /// /User/SuggestPersonRelationEdit?affiliationId={id} + /// + /// + /// + public async Task> GetAffiliationByIdAsync(int affiliationId) + { + try + { + var affiliation = await _context.GanjoorPersonAffiliations + .Include(a => a.Person1) + .Include(a => a.Person2) + .Where(a => a.Id == affiliationId) + .SingleOrDefaultAsync(); + + if (affiliation == null) + { + return new RServiceResult(null, "وابستگی پیدا نشد."); + } + + return new RServiceResult(affiliation); + } + catch (Exception exp) + { + return new RServiceResult(null, exp.ToString()); + } + } + /// /// submit a suggested addition, change or removal of a kinship edge ///