v1.3.0 Restructure Saxonite workspace and upgrade to .NET 10 (#1)
Move Saxonite’s projects into a dedicated `Workspace` folder and align the solution with .NET 10 and the current Common workspace. Update encryption integration, test project structure and coverage, and repository guidance and upgrade notes. - Relocate application and library projects while retaining Git rename history. - Split tests into Admin, Online, and Shared projects; add representative behavioral and serialization tests. - Update Common integration, application version, and repository documentation. Application version: 1.3.0 Reviewed-on: #1 Co-authored-by: andy <andy@sarand.com>
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs.Data
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Object to persist upload file after request has terminated, and the Form File has been disposed.
|
||||
/// <para>- Too allow async processes to access the file after request completed.</para>
|
||||
/// </summary>
|
||||
public class UploadFileData
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public UploadFileData(IFormFile dataFile)
|
||||
{
|
||||
ContentDisposition = dataFile.ContentDisposition;
|
||||
ContentType = dataFile.ContentType;
|
||||
FileName = dataFile.FileName;
|
||||
Length = dataFile.Length;
|
||||
Name = dataFile.Name;
|
||||
foreach (var header in dataFile.Headers)
|
||||
Headers.Add(header.Key, header.Value.ToString());
|
||||
// Load file data.
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
dataFile.CopyTo(stream);
|
||||
FileData = stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
/// <summary>Gets the raw Content-Disposition header of the uploaded file.</summary>
|
||||
public String ContentDisposition { get; }
|
||||
|
||||
/// <summary>Gets the raw Content-Type header of the uploaded file.</summary>
|
||||
public String ContentType { get; }
|
||||
|
||||
/// <summary>Gets the file name from the Content-Disposition header.</summary>
|
||||
public String FileName { get; }
|
||||
|
||||
/// <summary>Gets the header dictionary of the uploaded file.</summary>
|
||||
public Dictionary<String, String> Headers { get; } = new Dictionary<String, String>();
|
||||
|
||||
/// <summary>Gets the file length in bytes.</summary>
|
||||
public long Length { get; }
|
||||
|
||||
/// <summary>Gets the form field name from the Content-Disposition header.</summary>
|
||||
public String Name { get; }
|
||||
|
||||
/// <summary>File data.</summary>
|
||||
public byte[] FileData { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
||||
using DocumentFormat.OpenXml.Office2016.Excel;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Tasks;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs
|
||||
{
|
||||
//=======================================================================
|
||||
partial class SaxGolfUsgaDataLookup
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
private class ScheduledUsgaDataLookupControlData
|
||||
{
|
||||
public DateTime CountriesLastLookedUp { get; set; } = DateTime.Now;
|
||||
}
|
||||
private static ScheduledUsgaDataLookupControlData usgaDataLookupControl { get; } = new ScheduledUsgaDataLookupControlData();
|
||||
|
||||
/// <summary>
|
||||
/// Determine which USGA data population process to run.
|
||||
/// <para>- Method is invoked periodically (every 20 mins) by the Admin Hosted Service Console.</para>
|
||||
/// <para>- 1. Populate countries if not already done or not done for a while (eg. 24 hours).</para>
|
||||
/// <para>- 2. Populate provinces for a Country that has none or occasionally refresh one that has.</para>
|
||||
/// <para>- 3. Populate Courses for a Province that has none or occasionally refresh one that has.</para>
|
||||
/// <para>- 4. Populate Markers for a Course that has none or occasionally refresh one that has.</para>
|
||||
/// </summary>
|
||||
public static void ExecuteScheduledUsgaDataLookup(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo, SacsTaskData taskData)
|
||||
{
|
||||
SaLogger.Debug($"{SysUtil.Fn}");
|
||||
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
SaxInternals internals = new SaxInternals(sessionContext);
|
||||
disposableItems.Add(internals);
|
||||
|
||||
// Configure process.
|
||||
SaxGolfUsgaDataLookup.Config courseLookupConfig = new SaxGolfUsgaDataLookup.Config(sessionContext, dbUpdateInfo);
|
||||
SaxGolfUsgaDataLookup usgaDataLookup = new SaxGolfUsgaDataLookup(courseLookupConfig);
|
||||
|
||||
if (taskData.IsCancellationRequested) return;
|
||||
|
||||
// Determine which process to run.
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 1. Countries.
|
||||
{
|
||||
// Check USGA country population.
|
||||
List<SaxGolfUsgaCountry> usgaCountries = internals.ReferenceGolfMgr.GetUsgaCountryList(new SaxGolfUsgaCountry.Params());
|
||||
if (!usgaCountries.Any() || (DateTime.Now - usgaDataLookupControl.CountriesLastLookedUp).TotalHours > MathUtil.Constrain(Sax.Config.Admin.Processes.Scheduled.UsgaGolfDataLookup.HoursBetweenCountryLookup, 1, 24 * 7))
|
||||
{
|
||||
// No countries currently found or long enough since last lookup.
|
||||
// Lookup USGA countries.
|
||||
List<SaxGolfUsgaDataLookup.CountryData> countriesData = usgaDataLookup.LookupUsgaCountries();
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Countries populated: {countriesData.Count}.", true);
|
||||
usgaDataLookupControl.CountriesLastLookedUp = DateTime.Now;
|
||||
return;
|
||||
}
|
||||
if (taskData.IsCancellationRequested) return;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 2. Provinces.
|
||||
|
||||
// 2a. Population of active priority Country with no Provinces.
|
||||
{
|
||||
bool populatePriorityCountryNoProvinces = SacsRandomHelper.GetInt32(1, 5) == 1;
|
||||
if (populatePriorityCountryNoProvinces)
|
||||
{
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
prmCountry.ResultsPaging.Set(1, 4);
|
||||
prmCountry.RandomOrder = true;
|
||||
List<SaxGolfUsgaCountry> countriesNoProvinces = internals.ReferenceGolfMgr.GetUsgaCountryList(prmCountry).Randomise();
|
||||
disposableItems.AddRange(countriesNoProvinces);
|
||||
if (countriesNoProvinces.Any())
|
||||
{
|
||||
SaxGolfUsgaCountry usgaCountry = countriesNoProvinces[0];
|
||||
List<SaxGolfUsgaDataLookup.ProvinceData> provincesData = usgaDataLookup.LookupUsgaProvincesForCountry(usgaCountry.CountryCode);
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Provinces populated for {usgaCountry.CountryCode} {usgaCountry.CountryName}" + (usgaCountry.Priority ? " [Priority]" : "") + $": {provincesData.Count}.", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2b. Refresh active priority Country with Provinces.
|
||||
{
|
||||
bool refreshPriorityCountryWithProvinces = SacsRandomHelper.GetInt32(1, 25) == 1;
|
||||
if (refreshPriorityCountryWithProvinces)
|
||||
{
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
prmCountry.ResultsPaging.Set(1, 4);
|
||||
prmCountry.RandomOrder = true;
|
||||
List<SaxGolfUsgaCountry> countriesWithProvinces = internals.ReferenceGolfMgr.GetUsgaCountryList(prmCountry).Randomise();
|
||||
disposableItems.AddRange(countriesWithProvinces);
|
||||
if (countriesWithProvinces.Any())
|
||||
{
|
||||
SaxGolfUsgaCountry usgaCountry = countriesWithProvinces[0];
|
||||
List<SaxGolfUsgaDataLookup.ProvinceData> provincesData = usgaDataLookup.LookupUsgaProvincesForCountry(usgaCountry.CountryCode);
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Provinces refreshed for {usgaCountry.CountryCode} {usgaCountry.CountryName}" + (usgaCountry.Priority ? " [Priority]" : "") + $": {provincesData.Count}.", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 3. Courses.
|
||||
|
||||
// 3a. Populate active priority Province with no Facilities (Courses).
|
||||
{
|
||||
bool populatePriorityProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 4) == 1;
|
||||
if (populatePriorityProvinceNoFacilities)
|
||||
{
|
||||
// Active priority Provinces with no Facilities.
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
prmProvince.ResultsPaging.Set(1, 4);
|
||||
prmProvince.RandomOrder = true;
|
||||
List<SaxGolfUsgaProvince> provincesNoFacilities = internals.ReferenceGolfMgr.GetUsgaProvinceList(prmProvince).Randomise();
|
||||
disposableItems.AddRange(provincesNoFacilities);
|
||||
if (provincesNoFacilities.Any())
|
||||
{
|
||||
// Province has no Facilities - populate courses.
|
||||
SaxGolfUsgaProvince usgaProvince = provincesNoFacilities[0];
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = LookupUsgaCourses(internals, usgaDataLookup, usgaProvince, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3b. Refresh active priority Province with Facilities (courses).
|
||||
{
|
||||
bool refreshProvinceWithFacilities = SacsRandomHelper.GetInt32(1, 21) == 1;
|
||||
if (refreshProvinceWithFacilities)
|
||||
{
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
prmProvince.ResultsPaging.Set(1, 4);
|
||||
prmProvince.RandomOrder = true;
|
||||
List<SaxGolfUsgaProvince> provincesWithFacilities = internals.ReferenceGolfMgr.GetUsgaProvinceList(prmProvince).Randomise();
|
||||
disposableItems.AddRange(provincesWithFacilities);
|
||||
if (provincesWithFacilities.Any())
|
||||
{
|
||||
SaxGolfUsgaProvince usgaProvince = provincesWithFacilities[0];
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = LookupUsgaCourses(internals, usgaDataLookup, usgaProvince, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 4. Markers.
|
||||
|
||||
// 4a. Populate active priority Course with no Markers.
|
||||
{
|
||||
bool populatePriorityCourseNoMarkers = SacsRandomHelper.GetInt32(1, 2) == 1;
|
||||
if (populatePriorityCourseNoMarkers)
|
||||
{
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
prmCourse.ResultsPaging.Set(1, 4);
|
||||
prmCourse.RandomOrder = true;
|
||||
List<SaxGolfUsgaCourse> coursesNoMarkers = internals.ReferenceGolfMgr.GetUsgaCourseList(prmCourse).Randomise();
|
||||
disposableItems.AddRange(coursesNoMarkers);
|
||||
if (coursesNoMarkers.Any())
|
||||
{
|
||||
SaxGolfUsgaCourse usgaCourse = coursesNoMarkers[0];
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = LookupUsgaMarkers(internals, usgaDataLookup, usgaCourse, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4b. Refresh active priority Course with Markers.
|
||||
{
|
||||
bool refreshPriorityCourseWithMarkers = SacsRandomHelper.GetInt32(1, 17) == 1;
|
||||
if (refreshPriorityCourseWithMarkers)
|
||||
{
|
||||
// Active priority Course with no Markers.
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
prmCourse.ResultsPaging.Set(1, 4);
|
||||
prmCourse.RandomOrder = true;
|
||||
List<SaxGolfUsgaCourse> coursesWithMarkers = internals.ReferenceGolfMgr.GetUsgaCourseList(prmCourse).Randomise();
|
||||
disposableItems.AddRange(coursesWithMarkers);
|
||||
if (coursesWithMarkers.Any())
|
||||
{
|
||||
// Refresh first Course with Markers.
|
||||
SaxGolfUsgaCourse usgaCourse = coursesWithMarkers[0];
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = LookupUsgaMarkers(internals, usgaDataLookup, usgaCourse, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 5. Fallback population.
|
||||
|
||||
// 5a. Active Country with no Provinces.
|
||||
{
|
||||
bool populateCountryNoProvinces = SacsRandomHelper.GetInt32(1, 17) == 1;
|
||||
if (populateCountryNoProvinces)
|
||||
{
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
prmCountry.ResultsPaging.Set(1,4);
|
||||
prmCountry.RandomOrder = true;
|
||||
List<SaxGolfUsgaCountry> countriesNoProvinces = internals.ReferenceGolfMgr.GetUsgaCountryList(prmCountry).Randomise();
|
||||
disposableItems.AddRange(countriesNoProvinces);
|
||||
if (countriesNoProvinces.Any())
|
||||
{
|
||||
SaxGolfUsgaCountry usgaCountry = countriesNoProvinces[0];
|
||||
List<SaxGolfUsgaDataLookup.ProvinceData> provincesData = usgaDataLookup.LookupUsgaProvincesForCountry(usgaCountry.CountryCode);
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Provinces populated for {usgaCountry.CountryCode} {usgaCountry.CountryName} [Fallback]: {provincesData.Count}.", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5b. Active Province with no Facilities (courses).
|
||||
{
|
||||
bool populateProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 3) == 1;
|
||||
if (populateProvinceNoFacilities)
|
||||
{
|
||||
// Active Provinces with no Facilities.
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
prmProvince.ResultsPaging.Set(1, 4);
|
||||
prmProvince.RandomOrder = true;
|
||||
List<SaxGolfUsgaProvince> provincesNoFacilities = internals.ReferenceGolfMgr.GetUsgaProvinceList(prmProvince).Randomise();
|
||||
disposableItems.AddRange(provincesNoFacilities);
|
||||
if (provincesNoFacilities.Any())
|
||||
{
|
||||
// Province has no Facilities - populate courses.
|
||||
SaxGolfUsgaProvince usgaProvince = provincesNoFacilities[0];
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = LookupUsgaCourses(internals, usgaDataLookup, usgaProvince, false, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5c. Populate active Course with no Markers.
|
||||
{
|
||||
bool populateCourseNoMarkers = SacsRandomHelper.GetInt32(1, 2) == 1;
|
||||
if (populateCourseNoMarkers)
|
||||
{
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
prmCourse.ResultsPaging.Set(1, 4);
|
||||
prmCourse.RandomOrder = true;
|
||||
List<SaxGolfUsgaCourse> coursesNoMarkers = internals.ReferenceGolfMgr.GetUsgaCourseList(prmCourse).Randomise();
|
||||
disposableItems.AddRange(coursesNoMarkers);
|
||||
if (coursesNoMarkers.Any())
|
||||
{
|
||||
SaxGolfUsgaCourse usgaCourse = coursesNoMarkers[0];
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = LookupUsgaMarkers(internals, usgaDataLookup, usgaCourse, false, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
SaLogger.Warn($"{SysUtil.Fn} No data population task found to execute.");
|
||||
|
||||
//-----------------------------------------------------------
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private static List<SaxGolfUsgaDataLookup.CourseData> LookupUsgaCourses(SaxInternals internals, SaxGolfUsgaDataLookup usgaDataLookup, SaxGolfUsgaProvince usgaProvince, bool refresh, bool fallback = false)
|
||||
{
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = new List<CourseData>();
|
||||
SaxGolfUsgaCountry usgaCountry = internals.ReferenceGolfMgr.GetUsgaCountryById(usgaProvince.CountryId);
|
||||
if (usgaCountry != null)
|
||||
{
|
||||
coursesData = usgaDataLookup.LookupUsgaCoursesForCountryAndProvince(usgaCountry.CountryCode, usgaProvince.ProvinceCode);
|
||||
List<String> annotations = new List<string>();
|
||||
if (usgaProvince.Priority) annotations.Add("Priority");
|
||||
if (fallback) annotations.Add("Fallback");
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Courses refreshed for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName}" + (annotations.Any() ? $" [{annotations.Concat(", ")}]" : "") + $": {coursesData.Count}.", true);
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} USGA Country not found for Id {usgaProvince.CountryId} for Province {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName}.");
|
||||
return coursesData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private static List<SaxGolfUsgaDataLookup.MarkerData> LookupUsgaMarkers(SaxInternals internals, SaxGolfUsgaDataLookup usgaDataLookup, SaxGolfUsgaCourse usgaCourse, bool refresh, bool fallback = false)
|
||||
{
|
||||
SaxGolfUsgaFacility usgaFacility = internals.ReferenceGolfMgr.GetUsgaFacilityById(usgaCourse.FacilityId);
|
||||
SaxGolfUsgaProvince usgaProvince = internals.ReferenceGolfMgr.GetUsgaProvinceById(usgaFacility?.ProvinceId);
|
||||
SaxGolfUsgaCountry usgaCountry = internals.ReferenceGolfMgr.GetUsgaCountryById(usgaProvince?.CountryId);
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = new List<MarkerData>();
|
||||
if (usgaFacility != null)
|
||||
{
|
||||
if (usgaProvince != null)
|
||||
{
|
||||
if (usgaCountry != null)
|
||||
{
|
||||
markersData = usgaDataLookup.LookupUsgaMarkersForCourse(usgaCourse.UsgaCourseId);
|
||||
List<String> annotations = new List<string>();
|
||||
if (usgaCourse.Priority) annotations.Add("Priority");
|
||||
if (fallback) annotations.Add("Fallback");
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Markers " + (refresh ? "refreshed" : "populated") + $" for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName} - {usgaCourse.Caption} [Id: {usgaCourse.UsgaCourseId}" + (annotations.Any() ? $"{annotations.Concat("", ", ")}" : "") + $"]: {markersData.Count}.", true);
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} Missing Country for Province {usgaProvince.ProvinceName}. Country Id: {usgaProvince.CountryId}.");
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} Missing Province for Facility {usgaFacility.FacilityName}. Province Id: {usgaFacility.ProvinceId}.");
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} Missing Facility for Course {usgaCourse.FullName}. Facility Id: {usgaCourse.FacilityId}.");
|
||||
return markersData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,178 @@
|
||||
using DocumentFormat.OpenXml.InkML;
|
||||
using HtmlAgilityPack;
|
||||
using MailKit;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Net;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using Saxonite.Net.Standard.Base.Mgr.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs
|
||||
{
|
||||
//======================================================================
|
||||
public partial class SaxOrganisationEventsLookup : SaxProcess_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public enum Task
|
||||
{
|
||||
LookupEvents
|
||||
}
|
||||
|
||||
public new class Config : SaxProcess_Web.Config
|
||||
{
|
||||
public Config(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo) : base(sessionContext, dbUpdateInfo)
|
||||
{ }
|
||||
/// <summary>Organisations.</summary>
|
||||
public HashSet<SysId> OrganisationIdsIncluded { get; } = new HashSet<SysId>();
|
||||
/// <summary>Tasks to be run under this instance of the USGA Data Lookup process.</summary>
|
||||
public HashSet<Task> Tasks { get; } = new HashSet<Task>();
|
||||
}
|
||||
|
||||
private class EventData
|
||||
{
|
||||
public DateTime EventAt { get; set; }
|
||||
public String Caption { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxOrganisationEventsLookup(Config config) : base(config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
public override string ProcessDescription => "Organisation Events Lookup";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Run the process.
|
||||
protected override bool Run()
|
||||
{
|
||||
// Execute selected tasks.
|
||||
foreach (Task task in config.Tasks)
|
||||
{
|
||||
switch (task)
|
||||
{
|
||||
case Task.LookupEvents:
|
||||
LookupEventsForOrganisations();
|
||||
break;
|
||||
}
|
||||
if (!OK) break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Event lookup.
|
||||
//------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Organisation event lookup.
|
||||
/// </summary>
|
||||
private bool LookupEventsForOrganisations()
|
||||
{
|
||||
if (!OK) return false;
|
||||
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
foreach (SysId organisationId in config.OrganisationIdsIncluded)
|
||||
{
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
if (organisation == null)
|
||||
{
|
||||
AddWarningMessage($"Organisation not found for Id: {organisationId}.");
|
||||
continue;
|
||||
}
|
||||
LookupOrganisationEvents(organisation);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Organisation event lookup.
|
||||
/// </summary>
|
||||
private bool LookupOrganisationEvents(SaxOrganisation organisation)
|
||||
{
|
||||
List<EventData> eventsData = new List<EventData>();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// Query Countries on USGA website.
|
||||
CancellationToken cancelToken = new CancellationToken();
|
||||
SacsHttpRequestData request = new SacsHttpRequestData(cancelToken) { Url = "https://ncrdb.usga.org/" };
|
||||
SacsHttpResponseData response = SacsHttpClient.DoRequest(request).Result;
|
||||
String data = response.Data;
|
||||
|
||||
if (!StringUtil.IsBlank(response.Data))
|
||||
{
|
||||
// Parse HTML.
|
||||
HtmlDocument htmlDoc = new HtmlDocument();
|
||||
htmlDoc.LoadHtml(response.Data);
|
||||
|
||||
// Identify type of event schedule on page.
|
||||
HtmlNode mobiscrollEventCalendarNode = htmlDoc.GetElementbyId("mobiscroll-event-calendar");
|
||||
if (mobiscrollEventCalendarNode != null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (eventsData.Any())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, "querying organisation events", 8)}");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Organisation event lookup by MobiScroll calendar.
|
||||
/// </summary>
|
||||
private bool LookupOrganisationEvents_MobiScrollCalendar(SaxOrganisation organisation, List<EventData> eventsData, HtmlNode calendarNode)
|
||||
{
|
||||
|
||||
HtmlNode headerNode = calendarNode.Descendants("div").First(node => node.HasClass("mbsc-calendar-header"));
|
||||
if (headerNode != null)
|
||||
{
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
}
|
||||
//======================================================================
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Proc.Excel;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Procs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxProcess_Web : SaxProcess_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public new class Config : SaxProcess_Base.Config
|
||||
{
|
||||
protected Config(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo) : base(sessionContext, dbUpdateInfo)
|
||||
{ }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SaxProcess_Web(Config config) : base(config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Excel Spreadsheet utilities.
|
||||
//-------------------------------------------------------------------
|
||||
protected override SaMsExcelColumnHeading_Config GetExcelColumnHeadingConfig()
|
||||
{
|
||||
SaMsExcelColumnHeading_Config configHeading = base.GetExcelColumnHeadingConfig();
|
||||
return configHeading;
|
||||
}
|
||||
|
||||
protected override SaMsExcelStyleAttr GetExcelDefaultWorkbookStyle()
|
||||
{
|
||||
SaMsExcelStyleAttr styleAttr = base.GetExcelDefaultWorkbookStyle();
|
||||
return styleAttr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
Reference in New Issue
Block a user