From 011e04761969d3df332a20680aebe6ac9f75d6c1 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Fri, 14 Aug 2026 16:20:36 +0330 Subject: [PATCH] #498 import public data --- GanjooRazor/Pages/Auth/Login.cshtml | 2 +- GanjooRazor/Pages/Auth/Login.cshtml.cs | 7 ++++++ GanjooRazor/Pages/Index.cshtml.cs | 23 +++++++++++++++++++ .../Pages/LoginPartialEnabledPageModel.cs | 21 ++++++++++++++++- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/GanjooRazor/Pages/Auth/Login.cshtml b/GanjooRazor/Pages/Auth/Login.cshtml index 3cf6d7af..731268f7 100644 --- a/GanjooRazor/Pages/Auth/Login.cshtml +++ b/GanjooRazor/Pages/Auth/Login.cshtml @@ -44,7 +44,7 @@ } else { -
+
diff --git a/GanjooRazor/Pages/Auth/Login.cshtml.cs b/GanjooRazor/Pages/Auth/Login.cshtml.cs index 93975c62..a5034d3b 100644 --- a/GanjooRazor/Pages/Auth/Login.cshtml.cs +++ b/GanjooRazor/Pages/Auth/Login.cshtml.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; +using System; using System.Net.Http; namespace GanjooRazor.Pages @@ -15,6 +16,12 @@ namespace GanjooRazor.Pages public string RedirectUrl { get; set; } + /// + /// , URL-encoded for embedding directly in the login form's + /// action attribute + /// + public string RedirectUrlEncoded => Uri.EscapeDataString(RedirectUrl); + public void OnGet() { UserFriendlyName = Request.Cookies["Name"]; diff --git a/GanjooRazor/Pages/Index.cshtml.cs b/GanjooRazor/Pages/Index.cshtml.cs index 9114df57..5e4977fe 100644 --- a/GanjooRazor/Pages/Index.cshtml.cs +++ b/GanjooRazor/Pages/Index.cshtml.cs @@ -5,6 +5,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using RMuseum.Models.Ganjoor.ViewModels; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading.Tasks; @@ -139,11 +140,33 @@ namespace GanjooRazor.Pages return Page(); } + // A fresh/forked install has an empty (or nearly empty) database: no poets, or no + // century grouping yet. The view below assumes at least the "popular poets" group + // (Id == 0) exists — PoetGroups.Where(g => g.Id == 0).Single() — and throws on an + // empty database instead of rendering something useful. Steer the visitor toward + // fixing that instead of letting them hit an unhandled exception: log in first if + // needed, then straight to the admin page that can seed real content. + if (IsDatabaseEffectivelyEmpty()) + { + const string targetUrl = "/Admin/PublicDataImport"; + return LoggedIn ? Redirect(targetUrl) : Redirect($"/login?redirect={targetUrl}"); + } + ViewData["Title"] = "گنجور"; return Page(); } + /// + /// true if there's nothing meaningful to show on the home page yet — no poets at all, or + /// no century grouping (the "popular poets" group with Id == 0 that the view relies on). + /// + private bool IsDatabaseEffectivelyEmpty() + { + return Poets == null || Poets.Count == 0 + || PoetGroups == null || !PoetGroups.Any(g => g.Id == 0); + } + public async Task OnGetPoetInformationAsync(int id) { if (id == 0) diff --git a/GanjooRazor/Pages/LoginPartialEnabledPageModel.cs b/GanjooRazor/Pages/LoginPartialEnabledPageModel.cs index 19b9eb41..3f274706 100644 --- a/GanjooRazor/Pages/LoginPartialEnabledPageModel.cs +++ b/GanjooRazor/Pages/LoginPartialEnabledPageModel.cs @@ -208,8 +208,27 @@ namespace GanjooRazor.Pages } Response.Cookies.Append("CanTranslate", canTranlate.ToString(), cookieOption); + return Redirect(GetSafeRedirectTarget()); + } - return Redirect(Request.Path); + /// + /// Resolves where to send the visitor after a successful login. Prefers the "redirect" + /// query string value (set by 's form action so a login triggered + /// from /login?redirect=X lands on X afterward) over the previous default of always using + /// Request.Path, which just bounced back to the login page itself when login was posted + /// from there. Only accepts a local, root-relative path ("/..." and not "//..." or a + /// scheme — those are how open-redirect payloads look) to avoid the visitor's own + /// "redirect" query value being used to send them somewhere else entirely; anything else + /// falls back to the old behavior. + /// + private string GetSafeRedirectTarget() + { + string redirect = Request.Query["redirect"]; + if (!string.IsNullOrEmpty(redirect) && redirect.StartsWith("/") && !redirect.StartsWith("//")) + { + return redirect; + } + return Request.Path; } public Task OnGetCheckIfHasNotificationsAsync()