Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b642afe2d |
No files matched your search
@@ -3,6 +3,7 @@
|
|||||||
@inject PreciseLocationService LocationService
|
@inject PreciseLocationService LocationService
|
||||||
@inject CadastralCatalogService CatalogService
|
@inject CadastralCatalogService CatalogService
|
||||||
@inject OfficialCadastreService OfficialCadastreService
|
@inject OfficialCadastreService OfficialCadastreService
|
||||||
|
@inject FiducialPointService FiducialPointService
|
||||||
@inject LocationSearchService LocationSearchService
|
@inject LocationSearchService LocationSearchService
|
||||||
@inject NetworkLocationService NetworkLocationService
|
@inject NetworkLocationService NetworkLocationService
|
||||||
@inject AzureMapsService AzureMapsService
|
@inject AzureMapsService AzureMapsService
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
<button @onclick='() => SelectTab("map")'>@L("menu.map")</button>
|
<button @onclick='() => SelectTab("map")'>@L("menu.map")</button>
|
||||||
<button @onclick='() => SelectTab("search")'>@L("menu.search")</button>
|
<button @onclick='() => SelectTab("search")'>@L("menu.search")</button>
|
||||||
<button @onclick='() => SelectTab("cadastre")'>@L("menu.cadastre")</button>
|
<button @onclick='() => SelectTab("cadastre")'>@L("menu.cadastre")</button>
|
||||||
|
<button @onclick='() => SelectTab("fiducials")'>Punti fiduciali</button>
|
||||||
<button @onclick='() => SelectTab("data")'>@L("menu.data")</button>
|
<button @onclick='() => SelectTab("data")'>@L("menu.data")</button>
|
||||||
<button @onclick='() => SelectTab("projects")'>@L("menu.projects")</button>
|
<button @onclick='() => SelectTab("projects")'>@L("menu.projects")</button>
|
||||||
<button @onclick='() => SelectTab("save")'>@L("menu.export")</button>
|
<button @onclick='() => SelectTab("save")'>@L("menu.export")</button>
|
||||||
@@ -201,6 +203,84 @@
|
|||||||
<MenuHelp Topic="cadastre" />
|
<MenuHelp Topic="cadastre" />
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
|
else if (ActiveTab == "fiducials")
|
||||||
|
{
|
||||||
|
<section class="panel-content">
|
||||||
|
@if (!CanUse(AppFeatures.FiducialPoints))
|
||||||
|
{
|
||||||
|
<div class="service-note protected-service">
|
||||||
|
<strong>Funzione LME Pro</strong>
|
||||||
|
<p>La ricerca dei Punti Fiduciali e delle monografie ufficiali è disponibile con abbonamento Pro o chiave manuale valida.</p>
|
||||||
|
<button class="primary-command" @onclick='() => SelectTab("settings")'>Apri abbonamento Pro</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<label>
|
||||||
|
Provincia
|
||||||
|
<select value="@SelectedFiducialProvinceCode" @onchange="OnFiducialProvinceChanged" disabled="@FiducialBusy">
|
||||||
|
<option value="">Seleziona provincia</option>
|
||||||
|
@foreach (var province in FiducialProvinces)
|
||||||
|
{
|
||||||
|
<option value="@province.Code">@province.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
Comune catastale
|
||||||
|
<select value="@SelectedFiducialMunicipalityCode" @onchange="OnFiducialMunicipalityChanged" disabled="@(FiducialMunicipalities.Count == 0 || FiducialBusy)">
|
||||||
|
<option value="">Seleziona comune</option>
|
||||||
|
@foreach (var municipality in FiducialMunicipalities)
|
||||||
|
{
|
||||||
|
<option value="@municipality.Code">@municipality.Name (@municipality.Code)</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
Foglio
|
||||||
|
<select @bind="SelectedFiducialSheet" disabled="@(FiducialSheets.Count == 0 || FiducialBusy)">
|
||||||
|
<option value="">Seleziona foglio</option>
|
||||||
|
@foreach (var sheet in FiducialSheets)
|
||||||
|
{
|
||||||
|
<option value="@sheet.Code">@sheet.Name</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<button class="primary-command" @onclick="SearchFiducials" disabled="@(string.IsNullOrWhiteSpace(SelectedFiducialSheet) || FiducialBusy)">
|
||||||
|
@(FiducialBusy ? "Ricerca..." : "Cerca Punti Fiduciali")
|
||||||
|
</button>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrWhiteSpace(FiducialMessage))
|
||||||
|
{
|
||||||
|
<div class="catalog-progress"><span>@FiducialMessage</span></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (FiducialPoints.Count > 0)
|
||||||
|
{
|
||||||
|
<section class="panel-section">
|
||||||
|
<h2>Punti trovati (@FiducialPoints.Count)</h2>
|
||||||
|
<div class="fiducial-list">
|
||||||
|
@foreach (var point in FiducialPoints)
|
||||||
|
{
|
||||||
|
<article class="fiducial-item">
|
||||||
|
<strong>@point.Identifier</strong>
|
||||||
|
<button class="secondary-command" @onclick="() => DownloadFiducialMonograph(point)">Scarica PDF monografia</button>
|
||||||
|
</article>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="service-note">
|
||||||
|
<strong>Fonte ufficiale Agenzia delle Entrate</strong>
|
||||||
|
<p>L'elenco e i PDF arrivano dal servizio pubblico delle monografie. Il layer sulla mappa sarà abilitato soltanto quando sono disponibili coordinate geografiche trasformate e verificabili.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</section>
|
||||||
|
}
|
||||||
else if (ActiveTab == "data")
|
else if (ActiveTab == "data")
|
||||||
{
|
{
|
||||||
<section class="panel-content">
|
<section class="panel-content">
|
||||||
@@ -745,6 +825,11 @@
|
|||||||
private string MonthlyPrice { get; set; } = string.Empty;
|
private string MonthlyPrice { get; set; } = string.Empty;
|
||||||
private string YearlyPrice { get; set; } = string.Empty;
|
private string YearlyPrice { get; set; } = string.Empty;
|
||||||
private bool BillingBusy { get; set; }
|
private bool BillingBusy { get; set; }
|
||||||
|
private bool FiducialBusy { get; set; }
|
||||||
|
private string SelectedFiducialProvinceCode { get; set; } = string.Empty;
|
||||||
|
private string SelectedFiducialMunicipalityCode { get; set; } = string.Empty;
|
||||||
|
private string SelectedFiducialSheet { get; set; } = string.Empty;
|
||||||
|
private string FiducialMessage { get; set; } = string.Empty;
|
||||||
private string Status { get; set; } = "online";
|
private string Status { get; set; } = "online";
|
||||||
private string SelectedBaseLayer { get; set; } = "satellite";
|
private string SelectedBaseLayer { get; set; } = "satellite";
|
||||||
private string GoogleMapsApiKey { get; set; } = string.Empty;
|
private string GoogleMapsApiKey { get; set; } = string.Empty;
|
||||||
@@ -821,6 +906,10 @@
|
|||||||
private IReadOnlyList<MunicipalityOption> Municipalities { get; set; } = [];
|
private IReadOnlyList<MunicipalityOption> Municipalities { get; set; } = [];
|
||||||
private IReadOnlyList<string> Sheets { get; set; } = [];
|
private IReadOnlyList<string> Sheets { get; set; } = [];
|
||||||
private IReadOnlyList<ParcelOption> Parcels { get; set; } = [];
|
private IReadOnlyList<ParcelOption> Parcels { get; set; } = [];
|
||||||
|
private IReadOnlyList<FiducialAreaOption> FiducialProvinces { get; set; } = [];
|
||||||
|
private IReadOnlyList<FiducialAreaOption> FiducialMunicipalities { get; set; } = [];
|
||||||
|
private IReadOnlyList<FiducialAreaOption> FiducialSheets { get; set; } = [];
|
||||||
|
private IReadOnlyList<FiducialPointEntry> FiducialPoints { get; set; } = [];
|
||||||
private IReadOnlyList<MapProjectSummary> Projects { get; set; } = [];
|
private IReadOnlyList<MapProjectSummary> Projects { get; set; } = [];
|
||||||
private IReadOnlyList<MapProjectVersion> ProjectVersions { get; set; } = [];
|
private IReadOnlyList<MapProjectVersion> ProjectVersions { get; set; } = [];
|
||||||
private MapProjectSummary? SelectedProject => Projects.FirstOrDefault(item => item.Id == SelectedProjectId);
|
private MapProjectSummary? SelectedProject => Projects.FirstOrDefault(item => item.Id == SelectedProjectId);
|
||||||
@@ -834,6 +923,7 @@
|
|||||||
private string PanelTitle => ActiveTab switch
|
private string PanelTitle => ActiveTab switch
|
||||||
{
|
{
|
||||||
"cadastre" => "Ricerca catastale",
|
"cadastre" => "Ricerca catastale",
|
||||||
|
"fiducials" => "Punti fiduciali",
|
||||||
"data" => "Dati e disegni",
|
"data" => "Dati e disegni",
|
||||||
"projects" => "Archivio progetti",
|
"projects" => "Archivio progetti",
|
||||||
"save" => "Salvataggio ed esportazione",
|
"save" => "Salvataggio ed esportazione",
|
||||||
@@ -845,6 +935,7 @@
|
|||||||
private string PanelEyebrow => ActiveTab switch
|
private string PanelEyebrow => ActiveTab switch
|
||||||
{
|
{
|
||||||
"cadastre" => "Regione, Comune, Foglio, Particella",
|
"cadastre" => "Regione, Comune, Foglio, Particella",
|
||||||
|
"fiducials" => "Monografie ufficiali AdE",
|
||||||
"data" => "File GIS, misure e POI",
|
"data" => "File GIS, misure e POI",
|
||||||
"projects" => "Salva, apri e visualizza i tuoi lavori",
|
"projects" => "Salva, apri e visualizza i tuoi lavori",
|
||||||
"save" => "Esporta file GIS",
|
"save" => "Esporta file GIS",
|
||||||
@@ -1056,6 +1147,10 @@
|
|||||||
{
|
{
|
||||||
await RefreshProjectsAsync();
|
await RefreshProjectsAsync();
|
||||||
}
|
}
|
||||||
|
if (tab == "fiducials" && CanUse(AppFeatures.FiducialPoints) && FiducialProvinces.Count == 0)
|
||||||
|
{
|
||||||
|
await LoadFiducialProvincesAsync();
|
||||||
|
}
|
||||||
await Task.Delay(30);
|
await Task.Delay(30);
|
||||||
await JS.InvokeVoidAsync("lmeMap.resize");
|
await JS.InvokeVoidAsync("lmeMap.resize");
|
||||||
if (LayerPanelOpen)
|
if (LayerPanelOpen)
|
||||||
@@ -1135,6 +1230,132 @@
|
|||||||
: await CatalogService.GetMunicipalitiesAsync(SelectedRegionFile);
|
: await CatalogService.GetMunicipalitiesAsync(SelectedRegionFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LoadFiducialProvincesAsync()
|
||||||
|
{
|
||||||
|
FiducialBusy = true;
|
||||||
|
FiducialMessage = "Carico l'elenco delle province...";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FiducialProvinces = await FiducialPointService.GetProvincesAsync();
|
||||||
|
FiducialMessage = string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
FiducialMessage = $"Servizio monografie non disponibile: {error.GetBaseException().Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FiducialBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnFiducialProvinceChanged(ChangeEventArgs args)
|
||||||
|
{
|
||||||
|
SelectedFiducialProvinceCode = args.Value?.ToString() ?? string.Empty;
|
||||||
|
SelectedFiducialMunicipalityCode = string.Empty;
|
||||||
|
SelectedFiducialSheet = string.Empty;
|
||||||
|
FiducialMunicipalities = [];
|
||||||
|
FiducialSheets = [];
|
||||||
|
FiducialPoints = [];
|
||||||
|
if (string.IsNullOrWhiteSpace(SelectedFiducialProvinceCode))
|
||||||
|
{
|
||||||
|
FiducialMessage = string.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FiducialBusy = true;
|
||||||
|
FiducialMessage = "Carico i Comuni catastali...";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FiducialMunicipalities = await FiducialPointService.GetMunicipalitiesAsync(SelectedFiducialProvinceCode);
|
||||||
|
FiducialMessage = string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
FiducialMessage = $"Comuni non disponibili: {error.GetBaseException().Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FiducialBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnFiducialMunicipalityChanged(ChangeEventArgs args)
|
||||||
|
{
|
||||||
|
SelectedFiducialMunicipalityCode = args.Value?.ToString() ?? string.Empty;
|
||||||
|
SelectedFiducialSheet = string.Empty;
|
||||||
|
FiducialSheets = [];
|
||||||
|
FiducialPoints = [];
|
||||||
|
if (string.IsNullOrWhiteSpace(SelectedFiducialMunicipalityCode))
|
||||||
|
{
|
||||||
|
FiducialMessage = string.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FiducialBusy = true;
|
||||||
|
FiducialMessage = "Carico i fogli disponibili...";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FiducialSheets = await FiducialPointService.GetSheetsAsync(
|
||||||
|
SelectedFiducialProvinceCode,
|
||||||
|
SelectedFiducialMunicipalityCode);
|
||||||
|
FiducialMessage = string.Empty;
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
FiducialMessage = $"Fogli non disponibili: {error.GetBaseException().Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FiducialBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SearchFiducials()
|
||||||
|
{
|
||||||
|
var province = FiducialProvinces.FirstOrDefault(item => item.Code == SelectedFiducialProvinceCode);
|
||||||
|
var municipality = FiducialMunicipalities.FirstOrDefault(item => item.Code == SelectedFiducialMunicipalityCode);
|
||||||
|
if (province is null || municipality is null || string.IsNullOrWhiteSpace(SelectedFiducialSheet))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FiducialBusy = true;
|
||||||
|
FiducialPoints = [];
|
||||||
|
FiducialMessage = "Interrogo il servizio ufficiale delle monografie...";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FiducialPoints = await FiducialPointService.GetFiducialsAsync(
|
||||||
|
province.Name,
|
||||||
|
municipality.Name,
|
||||||
|
municipality.Code,
|
||||||
|
SelectedFiducialSheet);
|
||||||
|
FiducialMessage = FiducialPoints.Count == 0
|
||||||
|
? "Nessun Punto Fiduciale pubblicato per il foglio selezionato."
|
||||||
|
: $"Trovati {FiducialPoints.Count} Punti Fiduciali.";
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
FiducialMessage = $"Ricerca PF non riuscita: {error.GetBaseException().Message}";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FiducialBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DownloadFiducialMonograph(FiducialPointEntry point)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Launcher.Default.OpenAsync(new Uri(point.MonographUrl));
|
||||||
|
}
|
||||||
|
catch (Exception error)
|
||||||
|
{
|
||||||
|
FiducialMessage = $"Impossibile aprire la monografia: {error.GetBaseException().Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task OnMunicipalityChanged(ChangeEventArgs args)
|
private async Task OnMunicipalityChanged(ChangeEventArgs args)
|
||||||
{
|
{
|
||||||
SelectedMunicipalityCode = args.Value?.ToString() ?? string.Empty;
|
SelectedMunicipalityCode = args.Value?.ToString() ?? string.Empty;
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
<ApplicationId>it.liviomerola.lmemappecatastali.pro</ApplicationId>
|
<ApplicationId>it.liviomerola.lmemappecatastali.pro</ApplicationId>
|
||||||
|
|
||||||
<!-- Versions -->
|
<!-- Versions -->
|
||||||
<ApplicationDisplayVersion>1.0.11</ApplicationDisplayVersion>
|
<ApplicationDisplayVersion>1.0.12</ApplicationDisplayVersion>
|
||||||
<ApplicationVersion>111</ApplicationVersion>
|
<ApplicationVersion>112</ApplicationVersion>
|
||||||
<Version>$(ApplicationDisplayVersion)</Version>
|
<Version>$(ApplicationDisplayVersion)</Version>
|
||||||
|
|
||||||
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ public static class MauiProgram
|
|||||||
builder.Services.AddSingleton<PreciseLocationService>();
|
builder.Services.AddSingleton<PreciseLocationService>();
|
||||||
builder.Services.AddSingleton<CadastralCatalogService>();
|
builder.Services.AddSingleton<CadastralCatalogService>();
|
||||||
builder.Services.AddSingleton<OfficialCadastreService>();
|
builder.Services.AddSingleton<OfficialCadastreService>();
|
||||||
|
builder.Services.AddSingleton<FiducialPointService>();
|
||||||
builder.Services.AddSingleton<LocationSearchService>();
|
builder.Services.AddSingleton<LocationSearchService>();
|
||||||
builder.Services.AddSingleton<NetworkLocationService>();
|
builder.Services.AddSingleton<NetworkLocationService>();
|
||||||
builder.Services.AddSingleton<AzureMapsService>();
|
builder.Services.AddSingleton<AzureMapsService>();
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ public sealed class EntitlementService(
|
|||||||
AppFeatures.CloudSync,
|
AppFeatures.CloudSync,
|
||||||
AppFeatures.OfflineMaps,
|
AppFeatures.OfflineMaps,
|
||||||
AppFeatures.AdvancedGeometry,
|
AppFeatures.AdvancedGeometry,
|
||||||
AppFeatures.GpsTrail
|
AppFeatures.GpsTrail,
|
||||||
|
AppFeatures.FiducialPoints
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool IsGoogleProActive { get; private set; }
|
public bool IsGoogleProActive { get; private set; }
|
||||||
@@ -185,4 +186,5 @@ public static class AppFeatures
|
|||||||
public const string OfflineMaps = "offline-maps";
|
public const string OfflineMaps = "offline-maps";
|
||||||
public const string AdvancedGeometry = "advanced-geometry";
|
public const string AdvancedGeometry = "advanced-geometry";
|
||||||
public const string GpsTrail = "gps-trail";
|
public const string GpsTrail = "gps-trail";
|
||||||
|
public const string FiducialPoints = "fiducial-points";
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace LMEMappeCatastaliApp.Services;
|
||||||
|
|
||||||
|
public sealed partial class FiducialPointService
|
||||||
|
{
|
||||||
|
private const string ServiceBaseUrl = "https://www1.agenziaentrate.gov.it/servizi/Monografie/";
|
||||||
|
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(30) };
|
||||||
|
|
||||||
|
public FiducialPointService()
|
||||||
|
{
|
||||||
|
_httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("LMEMappeCatastali/1.0 (Android)");
|
||||||
|
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<FiducialAreaOption>> GetProvincesAsync(
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var html = await GetHtmlAsync("ricerca.php", cancellationToken);
|
||||||
|
return ParseOptions(html, "provincia");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<FiducialAreaOption>> GetMunicipalitiesAsync(
|
||||||
|
string provinceCode,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var code = NormalizeCode(provinceCode);
|
||||||
|
var html = await GetHtmlAsync($"ricerca.php?level=1&prov={Uri.EscapeDataString(code)}", cancellationToken);
|
||||||
|
return ParseOptions(html, "co");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<FiducialAreaOption>> GetSheetsAsync(
|
||||||
|
string provinceCode,
|
||||||
|
string municipalityCode,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var province = NormalizeCode(provinceCode);
|
||||||
|
var municipality = NormalizeCode(municipalityCode);
|
||||||
|
var path = $"ricerca.php?level=2&prov={Uri.EscapeDataString(province)}";
|
||||||
|
var html = await PostFormAsync(path, new Dictionary<string, string> { ["co"] = municipality }, cancellationToken);
|
||||||
|
return ParseOptions(html, "foglio");
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<FiducialPointEntry>> GetFiducialsAsync(
|
||||||
|
string provinceName,
|
||||||
|
string municipalityName,
|
||||||
|
string municipalityCode,
|
||||||
|
string sheet,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var code = NormalizeCode(municipalityCode);
|
||||||
|
var normalizedSheet = sheet.Trim();
|
||||||
|
var query = string.Join("&",
|
||||||
|
[
|
||||||
|
$"provincia={Uri.EscapeDataString(provinceName.Trim())}",
|
||||||
|
$"comune={Uri.EscapeDataString(municipalityName.Trim())}",
|
||||||
|
$"co={Uri.EscapeDataString(code)}"
|
||||||
|
]);
|
||||||
|
var html = await PostFormAsync(
|
||||||
|
$"risultato.php?{query}",
|
||||||
|
new Dictionary<string, string> { ["foglio"] = normalizedSheet },
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return DownloadLinkRegex().Matches(html)
|
||||||
|
.Select(match =>
|
||||||
|
{
|
||||||
|
var relativeUrl = WebUtility.HtmlDecode(match.Groups["url"].Value);
|
||||||
|
var fileName = WebUtility.HtmlDecode(match.Groups["name"].Value);
|
||||||
|
return new FiducialPointEntry(
|
||||||
|
FormatIdentifier(fileName),
|
||||||
|
new Uri(new Uri(ServiceBaseUrl), relativeUrl).AbsoluteUri);
|
||||||
|
})
|
||||||
|
.DistinctBy(item => item.Identifier, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.OrderBy(item => item.Identifier, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> GetHtmlAsync(string relativeUrl, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
using var response = await _httpClient.GetAsync(ServiceBaseUrl + relativeUrl, cancellationToken);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
return await response.Content.ReadAsStringAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> PostFormAsync(
|
||||||
|
string relativeUrl,
|
||||||
|
IReadOnlyDictionary<string, string> values,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
using var content = new FormUrlEncodedContent(values);
|
||||||
|
using var response = await _httpClient.PostAsync(ServiceBaseUrl + relativeUrl, content, cancellationToken);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
return await response.Content.ReadAsStringAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<FiducialAreaOption> ParseOptions(string html, string selectId)
|
||||||
|
{
|
||||||
|
var select = SelectRegex().Matches(html)
|
||||||
|
.LastOrDefault(match => string.Equals(match.Groups["id"].Value, selectId, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (select is null)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return OptionRegex().Matches(select.Groups["body"].Value)
|
||||||
|
.Select(match => new FiducialAreaOption(
|
||||||
|
WebUtility.HtmlDecode(match.Groups["value"].Value).Trim(),
|
||||||
|
WebUtility.HtmlDecode(StripTagsRegex().Replace(match.Groups["label"].Value, string.Empty)).Trim()))
|
||||||
|
.Where(item => !string.IsNullOrWhiteSpace(item.Code) && !string.IsNullOrWhiteSpace(item.Name))
|
||||||
|
.DistinctBy(item => item.Code, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string NormalizeCode(string value)
|
||||||
|
{
|
||||||
|
var normalized = value.Trim().ToUpperInvariant();
|
||||||
|
if (normalized.Length is < 2 or > 4 || normalized.Any(character => !char.IsLetterOrDigit(character)))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Codice territoriale non valido.", nameof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatIdentifier(string fileName)
|
||||||
|
{
|
||||||
|
var parts = fileName.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
return parts.Length == 3 ? $"PF{parts[2]}/{parts[1]}/{parts[0]}" : fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex("<select\\b[^>]*(?:id|name)=[\\\"'](?<id>[^\\\"']+)[\\\"'][^>]*>(?<body>[\\s\\S]*?)</select>", RegexOptions.IgnoreCase, matchTimeoutMilliseconds: 2000)]
|
||||||
|
private static partial Regex SelectRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex("<option\\b[^>]*value=[\\\"'](?<value>[^\\\"']*)[\\\"'][^>]*>(?<label>[\\s\\S]*?)</option>", RegexOptions.IgnoreCase, matchTimeoutMilliseconds: 2000)]
|
||||||
|
private static partial Regex OptionRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex("href=[\\\"'](?<url>download\\.php\\?[^\\\"']*namefile=(?<name>[A-Z0-9-]+))[^\\\"']*[\\\"']", RegexOptions.IgnoreCase, matchTimeoutMilliseconds: 2000)]
|
||||||
|
private static partial Regex DownloadLinkRegex();
|
||||||
|
|
||||||
|
[GeneratedRegex("<[^>]+>", RegexOptions.None, 2000)]
|
||||||
|
private static partial Regex StripTagsRegex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed record FiducialAreaOption(string Code, string Name);
|
||||||
|
|
||||||
|
public sealed record FiducialPointEntry(string Identifier, string MonographUrl);
|
||||||
@@ -1247,6 +1247,9 @@ input[type="checkbox"] {
|
|||||||
|
|
||||||
.gps-overlay.is-collapsed {
|
.gps-overlay.is-collapsed {
|
||||||
grid-template-columns: auto;
|
grid-template-columns: auto;
|
||||||
|
right: auto;
|
||||||
|
width: 48px;
|
||||||
|
max-width: 48px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1255,6 +1258,28 @@ input[type="checkbox"] {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fiducial-list {
|
||||||
|
display: grid;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fiducial-item {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(0, 1fr) auto;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid #d9e0e3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fiducial-item strong {
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fiducial-item .secondary-command {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.gps-overlay.search-open {
|
.gps-overlay.search-open {
|
||||||
top: 140px;
|
top: 140px;
|
||||||
}
|
}
|
||||||
@@ -1881,6 +1906,12 @@ footer {
|
|||||||
top: 136px;
|
top: 136px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gps-overlay.is-collapsed {
|
||||||
|
right: auto;
|
||||||
|
width: 48px;
|
||||||
|
max-width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
.leaflet-top.leaflet-right {
|
.leaflet-top.leaflet-right {
|
||||||
top: 174px;
|
top: 174px;
|
||||||
right: 0;
|
right: 0;
|
||||||
@@ -1936,6 +1967,17 @@ footer {
|
|||||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gps-overlay.is-collapsed {
|
||||||
|
grid-template-columns: auto;
|
||||||
|
right: auto;
|
||||||
|
width: 48px;
|
||||||
|
max-width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fiducial-item {
|
||||||
|
grid-template-columns: minmax(0, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
.gps-main,
|
.gps-main,
|
||||||
.gps-center {
|
.gps-center {
|
||||||
min-width: 86px;
|
min-width: 86px;
|
||||||
|
|||||||
Reference in new issue
Block a user