From 161846ee3b2a3f0c9f053f20347d0a4d3c3bcae7 Mon Sep 17 00:00:00 2001 From: Moley-Bot Date: Mon, 26 Jan 2026 10:53:44 +0000 Subject: [PATCH 1/5] Add collector for BroxtoweBoroughCouncil Closes #107 Generated with Codex CLI by Moley-Bot --- .../Councils/BroxtoweBoroughCouncil.cs | 443 ++++++++++++++++++ .../Councils/BroxtoweBoroughCouncilTests.cs | 36 ++ 2 files changed, 479 insertions(+) create mode 100644 BinDays.Api.Collectors/Collectors/Councils/BroxtoweBoroughCouncil.cs create mode 100644 BinDays.Api.IntegrationTests/Collectors/Councils/BroxtoweBoroughCouncilTests.cs diff --git a/BinDays.Api.Collectors/Collectors/Councils/BroxtoweBoroughCouncil.cs b/BinDays.Api.Collectors/Collectors/Councils/BroxtoweBoroughCouncil.cs new file mode 100644 index 0000000..da08d89 --- /dev/null +++ b/BinDays.Api.Collectors/Collectors/Councils/BroxtoweBoroughCouncil.cs @@ -0,0 +1,443 @@ +namespace BinDays.Api.Collectors.Collectors.Councils; + +using BinDays.Api.Collectors.Models; +using BinDays.Api.Collectors.Utilities; +using BinDays.Api.Collectors.Collectors.Vendors; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Text.RegularExpressions; + +/// +/// Collector implementation for Broxtowe Borough Council. +/// +internal sealed partial class BroxtoweBoroughCouncil : GovUkCollectorBase, ICollector +{ + /// + public string Name => "Broxtowe Borough Council"; + + /// + public Uri WebsiteUrl => new("https://www.broxtowe.gov.uk/"); + + /// + public override string GovUkId => "broxtowe"; + + /// + /// The list of bin types for this collector. + /// + private readonly IReadOnlyCollection _binTypes = + [ + new() + { + Name = "Mixed Dry Recycling", + Colour = BinColour.Green, + Keys = [ "GREEN 240L" ], + }, + new() + { + Name = "Glass Recycling", + Colour = BinColour.Green, + Keys = [ "GLASS BAG" ], + Type = BinType.Bag, + }, + new() + { + Name = "Garden Waste", + Colour = BinColour.Brown, + Keys = [ "BROWN 240L" ], + }, + new() + { + Name = "General Waste", + Colour = BinColour.Black, + Keys = [ "BLACK 240L" ], + }, + ]; + + private const string _formUrl = "https://selfservice.broxtowe.gov.uk/renderform.aspx?t=217&k=9D2EF214E144EE796430597FB475C3892C43C528"; + private const string _scriptManagerTarget = "ctl00$ContentPlaceHolder1$APUP_5683"; + private const string _searchEventTarget = "ctl00$ContentPlaceHolder1$FF5683BTN"; + private const string _addressEventTarget = "ctl00$ContentPlaceHolder1$FF5683DDL"; + private const string _submitEventTarget = "ctl00$ContentPlaceHolder1$btnSubmit"; + + /// + /// Regex for parsing hidden fields from AJAX responses. + /// + [GeneratedRegex(@"hiddenField\|(?__VIEWSTATEGENERATOR|__EVENTVALIDATION|__VIEWSTATE)\|(?[^|]+)")] + private static partial Regex AjaxHiddenFieldRegex(); + + /// + /// Regex for parsing hidden fields from HTML responses. + /// + [GeneratedRegex(@"name=""(?__VIEWSTATEGENERATOR|__EVENTVALIDATION|__VIEWSTATE)""[^>]+value=""(?[^""]+)""")] + private static partial Regex HtmlHiddenFieldRegex(); + + /// + /// Regex for parsing address options. + /// + [GeneratedRegex(@"