From 39c866f4c7f1f918caee1aeea02ea1efa6df2c14 Mon Sep 17 00:00:00 2001 From: "soroush.asadi" Date: Tue, 23 Jun 2026 11:50:21 +0330 Subject: [PATCH] Fix useless bare-divar.ir links + hide empty homepage shifts section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Divar listings with no extractable post token were given SourceUrl «https://divar.ir» — a link that just opens Divar''s homepage, not the ad. Store null instead, and guard the contact-modal fallback to require a real path (so existing bare-domain links stop being offered too). - Homepage «جدیدترین شیفت‌ها»: only render when there are real open shifts. Almost all aggregated ads are ongoing hiring (jobs), not dated shifts, so the section was showing a fabricated shift date (the «۱۸ خرداد» on the welcome page). Now it hides when empty. Co-Authored-By: Claude Opus 4.8 --- src/JobsMedical.Web/Pages/Index.cshtml | 28 +++++++++---------- src/JobsMedical.Web/Program.cs | 6 ++-- .../Services/Scraping/DivarListingSource.cs | 4 ++- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/JobsMedical.Web/Pages/Index.cshtml b/src/JobsMedical.Web/Pages/Index.cshtml index 8375681..2eaedcf 100644 --- a/src/JobsMedical.Web/Pages/Index.cshtml +++ b/src/JobsMedical.Web/Pages/Index.cshtml @@ -53,27 +53,25 @@ -
-
-
-

جدیدترین شیفت‌ها

- مشاهده همه ← -
- @if (Model.LatestShifts.Count == 0) - { -
فعلاً شیفت بازی ثبت نشده است.
- } - else - { +@* Shifts are rare for aggregated content (most ads are ongoing hiring, not dated shifts) — only + show the section when there are real open shifts, so we never display a fabricated/empty date. *@ +@if (Model.LatestShifts.Count > 0) +{ +
+
+
+

جدیدترین شیفت‌ها

+ مشاهده همه ← +
@foreach (var s in Model.LatestShifts) { }
- } -
-
+
+
+} @if (Model.LatestJobs.Count > 0) { diff --git a/src/JobsMedical.Web/Program.cs b/src/JobsMedical.Web/Program.cs index c67d4ef..ab475d2 100644 --- a/src/JobsMedical.Web/Program.cs +++ b/src/JobsMedical.Web/Program.cs @@ -426,7 +426,7 @@ app.MapGet("/contact", async (string? type, int id, AppDbContext db, InterestSer if (!string.IsNullOrWhiteSpace(s.Facility!.BaleId)) items.Add(Item(ContactType.Bale, s.Facility.BaleId!)); } if (items.Count == 0 && !string.IsNullOrWhiteSpace(s.SourceUrl) - && Uri.TryCreate(s.SourceUrl, UriKind.Absolute, out var ss)) + && Uri.TryCreate(s.SourceUrl, UriKind.Absolute, out var ss) && ss.AbsolutePath.Trim('/').Length > 0) { fallbackUrl = s.SourceUrl; fallbackLabel = ss.Host.Contains("divar") ? "مشاهده شماره در دیوار ↗" : "مشاهده آگهی در منبع ↗"; } await interest.LogAsync(InterestEventType.Apply, id); break; @@ -444,7 +444,7 @@ app.MapGet("/contact", async (string? type, int id, AppDbContext db, InterestSer if (!string.IsNullOrWhiteSpace(j.Facility!.BaleId)) items.Add(Item(ContactType.Bale, j.Facility.BaleId!)); } if (items.Count == 0 && !string.IsNullOrWhiteSpace(j.SourceUrl) - && Uri.TryCreate(j.SourceUrl, UriKind.Absolute, out var js)) + && Uri.TryCreate(j.SourceUrl, UriKind.Absolute, out var js) && js.AbsolutePath.Trim('/').Length > 0) { fallbackUrl = j.SourceUrl; fallbackLabel = js.Host.Contains("divar") ? "مشاهده شماره در دیوار ↗" : "مشاهده آگهی در منبع ↗"; } await interest.LogJobAsync(InterestEventType.Apply, id); break; @@ -458,7 +458,7 @@ app.MapGet("/contact", async (string? type, int id, AppDbContext db, InterestSer items.AddRange(t.Contacts.OrderBy(c => c.SortOrder).Select(c => Item(c.Type, c.Value))); if (items.Count == 0 && !string.IsNullOrWhiteSpace(t.Phone)) items.Add(Item(ContactType.Mobile, t.Phone!)); if (items.Count == 0 && !string.IsNullOrWhiteSpace(t.SourceUrl) - && Uri.TryCreate(t.SourceUrl, UriKind.Absolute, out var su)) + && Uri.TryCreate(t.SourceUrl, UriKind.Absolute, out var su) && su.AbsolutePath.Trim('/').Length > 0) { fallbackUrl = t.SourceUrl; fallbackLabel = su.Host.Contains("divar") ? "مشاهده شماره در دیوار ↗" : "مشاهده آگهی در منبع ↗"; } break; } diff --git a/src/JobsMedical.Web/Services/Scraping/DivarListingSource.cs b/src/JobsMedical.Web/Services/Scraping/DivarListingSource.cs index a4dcde6..a1e676f 100644 --- a/src/JobsMedical.Web/Services/Scraping/DivarListingSource.cs +++ b/src/JobsMedical.Web/Services/Scraping/DivarListingSource.cs @@ -62,7 +62,9 @@ public class DivarListingSource : IListingSource var cityLabel = CityLabel(s.DivarCity); // every result is from the city we searched foreach (var (text, token) in Harvest(doc.RootElement).Take(25)) { - var url = token is not null ? $"https://divar.ir/v/{token}" : "https://divar.ir"; + // Only a real post token gives a usable deep link. Without one, leave SourceUrl null — + // a bare «https://divar.ir» just opens Divar's homepage, which is useless to the user. + var url = token is not null ? $"https://divar.ir/v/{token}" : null; var itemText = text; // Stamp the city so the parser/AI always resolve a location (Divar's own location // line isn't always in the search row; the searched city is authoritative).