From ee50257b4460493b335f881913cdc4ddfe05e3e6 Mon Sep 17 00:00:00 2001 From: Moley-Bot Date: Sun, 11 Jan 2026 16:04:59 +0000 Subject: [PATCH 1/4] Add collector for BrecklandCouncil Closes #97 Generated with Codex CLI by Moley-Bot --- .../Collectors/Councils/BrecklandCouncil.cs | 244 ++++++++++++++++++ .../Councils/BrecklandCouncilTests.cs | 36 +++ 2 files changed, 280 insertions(+) create mode 100644 BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs create mode 100644 BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs diff --git a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs new file mode 100644 index 00000000..a7951d41 --- /dev/null +++ b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs @@ -0,0 +1,244 @@ +namespace BinDays.Api.Collectors.Collectors.Councils; + +using BinDays.Api.Collectors.Collectors.Vendors; +using BinDays.Api.Collectors.Models; +using BinDays.Api.Collectors.Utilities; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.Json; + +/// +/// Collector implementation for Breckland Council. +/// +internal sealed class BrecklandCouncil : GovUkCollectorBase, ICollector +{ + /// + public string Name => "Breckland Council"; + + /// + public Uri WebsiteUrl => new("https://www.breckland.gov.uk/"); + + /// + public override string GovUkId => "breckland"; + + /// + /// The list of bin types for this collector. + /// + private readonly IReadOnlyCollection _binTypes = [ + new() + { + Name = "General Waste", + Colour = BinColour.Black, + Keys = [ "Refuse Collection Service", "Refuse" ], + Type = BinType.Bin, + }, + new() + { + Name = "Recycling", + Colour = BinColour.Green, + Keys = [ "Recycling Collection Service", "Recycling" ], + Type = BinType.Bin, + }, + new() + { + Name = "Garden Waste", + Colour = BinColour.Brown, + Keys = [ "Garden Waste Collection Service", "Garden Waste" ], + Type = BinType.Sack, + }, + new() + { + Name = "Food Waste", + Colour = BinColour.Grey, + Keys = [ "Food Waste Collection Service", "Food Waste" ], + Type = BinType.Caddy, + }, + ]; + + /// + public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? clientSideResponse) + { + // Prepare client-side request for getting addresses + if (clientSideResponse == null) + { + var requestBody = JsonSerializer.Serialize(new + { + jsonrpc = "2.0", + id = "1", + method = "Breckland.Whitespace.JointWasteAPI.GetSiteIDsByPostcode", + @params = new + { + postcode, + environment = "live", + }, + }); + + var clientSideRequest = new ClientSideRequest + { + RequestId = 1, + Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", + Method = "POST", + Headers = new Dictionary + { + { "Content-Type", "application/json" }, + { "X-Requested-With", "XMLHttpRequest" }, + { "User-Agent", Constants.UserAgent }, + }, + Body = requestBody, + }; + + return new GetAddressesResponse + { + NextClientSideRequest = clientSideRequest + }; + } + // Process addresses from response + else if (clientSideResponse.RequestId == 1) + { + using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); + + var addresses = new List
(); + foreach (var addressElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) + { + var propertyParts = new List(); + + var number = addressElement.GetProperty("number").GetString(); + if (!string.IsNullOrWhiteSpace(number)) + { + propertyParts.Add(number); + } + + var name = addressElement.GetProperty("name").GetString(); + if (!string.IsNullOrWhiteSpace(name)) + { + propertyParts.Add(name); + } + + var address1 = addressElement.GetProperty("address1").GetString(); + if (!string.IsNullOrWhiteSpace(address1)) + { + propertyParts.Add(address1); + } + + var address2 = addressElement.GetProperty("address2").GetString(); + if (!string.IsNullOrWhiteSpace(address2)) + { + propertyParts.Add(address2); + } + + var town = addressElement.GetProperty("town").GetString(); + if (!string.IsNullOrWhiteSpace(town)) + { + propertyParts.Add(town); + } + + var county = addressElement.GetProperty("county").GetString(); + if (!string.IsNullOrWhiteSpace(county)) + { + propertyParts.Add(county); + } + + var postcodeResult = addressElement.GetProperty("postcode").GetString(); + if (!string.IsNullOrWhiteSpace(postcodeResult)) + { + propertyParts.Add(postcodeResult); + } + + var address = new Address + { + Property = string.Join(", ", propertyParts), + Postcode = postcodeResult ?? postcode, + Uid = addressElement.GetProperty("uprn").GetString()!, + }; + + addresses.Add(address); + } + + return new GetAddressesResponse + { + Addresses = [.. addresses], + }; + } + + // Throw exception for invalid request + throw new InvalidOperationException("Invalid client-side request."); + } + + /// + public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? clientSideResponse) + { + // Prepare client-side request for getting bin days + if (clientSideResponse == null) + { + var requestBody = JsonSerializer.Serialize(new + { + jsonrpc = "2.0", + id = "1", + method = "Breckland.Whitespace.JointWasteAPI.GetBinCollectionsByUprn", + @params = new + { + uprn = address.Uid, + environment = "live", + }, + }); + + var clientSideRequest = new ClientSideRequest + { + RequestId = 1, + Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", + Method = "POST", + Headers = new Dictionary + { + { "Content-Type", "application/json" }, + { "X-Requested-With", "XMLHttpRequest" }, + { "User-Agent", Constants.UserAgent }, + }, + Body = requestBody, + }; + + return new GetBinDaysResponse + { + NextClientSideRequest = clientSideRequest + }; + } + // Process bin days from response + else if (clientSideResponse.RequestId == 1) + { + using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); + + var binDays = new List(); + foreach (var binDayElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) + { + var binType = binDayElement.GetProperty("collectiontype").GetString()!; + var collectionDate = binDayElement.GetProperty("nextcollection").GetString()!; + + var parsedDate = DateTime.ParseExact( + collectionDate, + "dd/MM/yyyy HH:mm:ss", + CultureInfo.InvariantCulture, + DateTimeStyles.None + ); + + var matchedBins = ProcessingUtilities.GetMatchingBins(_binTypes, binType); + + var binDay = new BinDay + { + Date = DateOnly.FromDateTime(parsedDate), + Address = address, + Bins = matchedBins, + }; + + binDays.Add(binDay); + } + + return new GetBinDaysResponse + { + BinDays = ProcessingUtilities.ProcessBinDays(binDays), + }; + } + + // Throw exception for invalid request + throw new InvalidOperationException("Invalid client-side request."); + } +} diff --git a/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs b/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs new file mode 100644 index 00000000..a209b4cc --- /dev/null +++ b/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs @@ -0,0 +1,36 @@ +namespace BinDays.Api.IntegrationTests.Collectors.Councils; + +using BinDays.Api.Collectors.Collectors; +using BinDays.Api.Collectors.Collectors.Councils; +using BinDays.Api.Collectors.Services; +using BinDays.Api.IntegrationTests.Helpers; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +public class BrecklandCouncilTests +{ + private readonly IntegrationTestClient _client; + private static readonly ICollector _collector = new BrecklandCouncil(); + private readonly CollectorService _collectorService = new([_collector]); + private readonly ITestOutputHelper _outputHelper; + + public BrecklandCouncilTests(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + _client = new IntegrationTestClient(outputHelper); + } + + [Theory] + [InlineData("NR172BJ")] + public async Task GetBinDaysTest(string postcode) + { + await TestSteps.EndToEnd( + _client, + _collectorService, + _collector, + postcode, + _outputHelper + ); + } +} From 35120d605e053ba102fceee48fc0ab417ce7f323 Mon Sep 17 00:00:00 2001 From: Moley-Bot Date: Sun, 11 Jan 2026 16:05:38 +0000 Subject: [PATCH 2/4] Auto-format code with dotnet format Formatted by Moley-Bot --- .../Collectors/Councils/BrecklandCouncil.cs | 488 +++++++++--------- .../Councils/BrecklandCouncilTests.cs | 72 +-- 2 files changed, 280 insertions(+), 280 deletions(-) diff --git a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs index a7951d41..ce4261c8 100644 --- a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs +++ b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs @@ -1,244 +1,244 @@ -namespace BinDays.Api.Collectors.Collectors.Councils; - -using BinDays.Api.Collectors.Collectors.Vendors; -using BinDays.Api.Collectors.Models; -using BinDays.Api.Collectors.Utilities; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text.Json; - -/// -/// Collector implementation for Breckland Council. -/// -internal sealed class BrecklandCouncil : GovUkCollectorBase, ICollector -{ - /// - public string Name => "Breckland Council"; - - /// - public Uri WebsiteUrl => new("https://www.breckland.gov.uk/"); - - /// - public override string GovUkId => "breckland"; - - /// - /// The list of bin types for this collector. - /// - private readonly IReadOnlyCollection _binTypes = [ - new() - { - Name = "General Waste", - Colour = BinColour.Black, - Keys = [ "Refuse Collection Service", "Refuse" ], - Type = BinType.Bin, - }, - new() - { - Name = "Recycling", - Colour = BinColour.Green, - Keys = [ "Recycling Collection Service", "Recycling" ], - Type = BinType.Bin, - }, - new() - { - Name = "Garden Waste", - Colour = BinColour.Brown, - Keys = [ "Garden Waste Collection Service", "Garden Waste" ], - Type = BinType.Sack, - }, - new() - { - Name = "Food Waste", - Colour = BinColour.Grey, - Keys = [ "Food Waste Collection Service", "Food Waste" ], - Type = BinType.Caddy, - }, - ]; - - /// - public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? clientSideResponse) - { - // Prepare client-side request for getting addresses - if (clientSideResponse == null) - { - var requestBody = JsonSerializer.Serialize(new - { - jsonrpc = "2.0", - id = "1", - method = "Breckland.Whitespace.JointWasteAPI.GetSiteIDsByPostcode", - @params = new - { - postcode, - environment = "live", - }, - }); - - var clientSideRequest = new ClientSideRequest - { - RequestId = 1, - Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", - Method = "POST", - Headers = new Dictionary - { - { "Content-Type", "application/json" }, - { "X-Requested-With", "XMLHttpRequest" }, - { "User-Agent", Constants.UserAgent }, - }, - Body = requestBody, - }; - - return new GetAddressesResponse - { - NextClientSideRequest = clientSideRequest - }; - } - // Process addresses from response - else if (clientSideResponse.RequestId == 1) - { - using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); - - var addresses = new List
(); - foreach (var addressElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) - { - var propertyParts = new List(); - - var number = addressElement.GetProperty("number").GetString(); - if (!string.IsNullOrWhiteSpace(number)) - { - propertyParts.Add(number); - } - - var name = addressElement.GetProperty("name").GetString(); - if (!string.IsNullOrWhiteSpace(name)) - { - propertyParts.Add(name); - } - - var address1 = addressElement.GetProperty("address1").GetString(); - if (!string.IsNullOrWhiteSpace(address1)) - { - propertyParts.Add(address1); - } - - var address2 = addressElement.GetProperty("address2").GetString(); - if (!string.IsNullOrWhiteSpace(address2)) - { - propertyParts.Add(address2); - } - - var town = addressElement.GetProperty("town").GetString(); - if (!string.IsNullOrWhiteSpace(town)) - { - propertyParts.Add(town); - } - - var county = addressElement.GetProperty("county").GetString(); - if (!string.IsNullOrWhiteSpace(county)) - { - propertyParts.Add(county); - } - - var postcodeResult = addressElement.GetProperty("postcode").GetString(); - if (!string.IsNullOrWhiteSpace(postcodeResult)) - { - propertyParts.Add(postcodeResult); - } - - var address = new Address - { - Property = string.Join(", ", propertyParts), - Postcode = postcodeResult ?? postcode, - Uid = addressElement.GetProperty("uprn").GetString()!, - }; - - addresses.Add(address); - } - - return new GetAddressesResponse - { - Addresses = [.. addresses], - }; - } - - // Throw exception for invalid request - throw new InvalidOperationException("Invalid client-side request."); - } - - /// - public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? clientSideResponse) - { - // Prepare client-side request for getting bin days - if (clientSideResponse == null) - { - var requestBody = JsonSerializer.Serialize(new - { - jsonrpc = "2.0", - id = "1", - method = "Breckland.Whitespace.JointWasteAPI.GetBinCollectionsByUprn", - @params = new - { - uprn = address.Uid, - environment = "live", - }, - }); - - var clientSideRequest = new ClientSideRequest - { - RequestId = 1, - Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", - Method = "POST", - Headers = new Dictionary - { - { "Content-Type", "application/json" }, - { "X-Requested-With", "XMLHttpRequest" }, - { "User-Agent", Constants.UserAgent }, - }, - Body = requestBody, - }; - - return new GetBinDaysResponse - { - NextClientSideRequest = clientSideRequest - }; - } - // Process bin days from response - else if (clientSideResponse.RequestId == 1) - { - using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); - - var binDays = new List(); - foreach (var binDayElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) - { - var binType = binDayElement.GetProperty("collectiontype").GetString()!; - var collectionDate = binDayElement.GetProperty("nextcollection").GetString()!; - - var parsedDate = DateTime.ParseExact( - collectionDate, - "dd/MM/yyyy HH:mm:ss", - CultureInfo.InvariantCulture, - DateTimeStyles.None - ); - - var matchedBins = ProcessingUtilities.GetMatchingBins(_binTypes, binType); - - var binDay = new BinDay - { - Date = DateOnly.FromDateTime(parsedDate), - Address = address, - Bins = matchedBins, - }; - - binDays.Add(binDay); - } - - return new GetBinDaysResponse - { - BinDays = ProcessingUtilities.ProcessBinDays(binDays), - }; - } - - // Throw exception for invalid request - throw new InvalidOperationException("Invalid client-side request."); - } -} +namespace BinDays.Api.Collectors.Collectors.Councils; + +using BinDays.Api.Collectors.Collectors.Vendors; +using BinDays.Api.Collectors.Models; +using BinDays.Api.Collectors.Utilities; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.Json; + +/// +/// Collector implementation for Breckland Council. +/// +internal sealed class BrecklandCouncil : GovUkCollectorBase, ICollector +{ + /// + public string Name => "Breckland Council"; + + /// + public Uri WebsiteUrl => new("https://www.breckland.gov.uk/"); + + /// + public override string GovUkId => "breckland"; + + /// + /// The list of bin types for this collector. + /// + private readonly IReadOnlyCollection _binTypes = [ + new() + { + Name = "General Waste", + Colour = BinColour.Black, + Keys = [ "Refuse Collection Service", "Refuse" ], + Type = BinType.Bin, + }, + new() + { + Name = "Recycling", + Colour = BinColour.Green, + Keys = [ "Recycling Collection Service", "Recycling" ], + Type = BinType.Bin, + }, + new() + { + Name = "Garden Waste", + Colour = BinColour.Brown, + Keys = [ "Garden Waste Collection Service", "Garden Waste" ], + Type = BinType.Sack, + }, + new() + { + Name = "Food Waste", + Colour = BinColour.Grey, + Keys = [ "Food Waste Collection Service", "Food Waste" ], + Type = BinType.Caddy, + }, + ]; + + /// + public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? clientSideResponse) + { + // Prepare client-side request for getting addresses + if (clientSideResponse == null) + { + var requestBody = JsonSerializer.Serialize(new + { + jsonrpc = "2.0", + id = "1", + method = "Breckland.Whitespace.JointWasteAPI.GetSiteIDsByPostcode", + @params = new + { + postcode, + environment = "live", + }, + }); + + var clientSideRequest = new ClientSideRequest + { + RequestId = 1, + Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", + Method = "POST", + Headers = new Dictionary + { + { "Content-Type", "application/json" }, + { "X-Requested-With", "XMLHttpRequest" }, + { "User-Agent", Constants.UserAgent }, + }, + Body = requestBody, + }; + + return new GetAddressesResponse + { + NextClientSideRequest = clientSideRequest + }; + } + // Process addresses from response + else if (clientSideResponse.RequestId == 1) + { + using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); + + var addresses = new List
(); + foreach (var addressElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) + { + var propertyParts = new List(); + + var number = addressElement.GetProperty("number").GetString(); + if (!string.IsNullOrWhiteSpace(number)) + { + propertyParts.Add(number); + } + + var name = addressElement.GetProperty("name").GetString(); + if (!string.IsNullOrWhiteSpace(name)) + { + propertyParts.Add(name); + } + + var address1 = addressElement.GetProperty("address1").GetString(); + if (!string.IsNullOrWhiteSpace(address1)) + { + propertyParts.Add(address1); + } + + var address2 = addressElement.GetProperty("address2").GetString(); + if (!string.IsNullOrWhiteSpace(address2)) + { + propertyParts.Add(address2); + } + + var town = addressElement.GetProperty("town").GetString(); + if (!string.IsNullOrWhiteSpace(town)) + { + propertyParts.Add(town); + } + + var county = addressElement.GetProperty("county").GetString(); + if (!string.IsNullOrWhiteSpace(county)) + { + propertyParts.Add(county); + } + + var postcodeResult = addressElement.GetProperty("postcode").GetString(); + if (!string.IsNullOrWhiteSpace(postcodeResult)) + { + propertyParts.Add(postcodeResult); + } + + var address = new Address + { + Property = string.Join(", ", propertyParts), + Postcode = postcodeResult ?? postcode, + Uid = addressElement.GetProperty("uprn").GetString()!, + }; + + addresses.Add(address); + } + + return new GetAddressesResponse + { + Addresses = [.. addresses], + }; + } + + // Throw exception for invalid request + throw new InvalidOperationException("Invalid client-side request."); + } + + /// + public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? clientSideResponse) + { + // Prepare client-side request for getting bin days + if (clientSideResponse == null) + { + var requestBody = JsonSerializer.Serialize(new + { + jsonrpc = "2.0", + id = "1", + method = "Breckland.Whitespace.JointWasteAPI.GetBinCollectionsByUprn", + @params = new + { + uprn = address.Uid, + environment = "live", + }, + }); + + var clientSideRequest = new ClientSideRequest + { + RequestId = 1, + Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", + Method = "POST", + Headers = new Dictionary + { + { "Content-Type", "application/json" }, + { "X-Requested-With", "XMLHttpRequest" }, + { "User-Agent", Constants.UserAgent }, + }, + Body = requestBody, + }; + + return new GetBinDaysResponse + { + NextClientSideRequest = clientSideRequest + }; + } + // Process bin days from response + else if (clientSideResponse.RequestId == 1) + { + using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); + + var binDays = new List(); + foreach (var binDayElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) + { + var binType = binDayElement.GetProperty("collectiontype").GetString()!; + var collectionDate = binDayElement.GetProperty("nextcollection").GetString()!; + + var parsedDate = DateTime.ParseExact( + collectionDate, + "dd/MM/yyyy HH:mm:ss", + CultureInfo.InvariantCulture, + DateTimeStyles.None + ); + + var matchedBins = ProcessingUtilities.GetMatchingBins(_binTypes, binType); + + var binDay = new BinDay + { + Date = DateOnly.FromDateTime(parsedDate), + Address = address, + Bins = matchedBins, + }; + + binDays.Add(binDay); + } + + return new GetBinDaysResponse + { + BinDays = ProcessingUtilities.ProcessBinDays(binDays), + }; + } + + // Throw exception for invalid request + throw new InvalidOperationException("Invalid client-side request."); + } +} diff --git a/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs b/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs index a209b4cc..971b7ff6 100644 --- a/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs +++ b/BinDays.Api.IntegrationTests/Collectors/Councils/BrecklandCouncilTests.cs @@ -1,36 +1,36 @@ -namespace BinDays.Api.IntegrationTests.Collectors.Councils; - -using BinDays.Api.Collectors.Collectors; -using BinDays.Api.Collectors.Collectors.Councils; -using BinDays.Api.Collectors.Services; -using BinDays.Api.IntegrationTests.Helpers; -using System.Threading.Tasks; -using Xunit; -using Xunit.Abstractions; - -public class BrecklandCouncilTests -{ - private readonly IntegrationTestClient _client; - private static readonly ICollector _collector = new BrecklandCouncil(); - private readonly CollectorService _collectorService = new([_collector]); - private readonly ITestOutputHelper _outputHelper; - - public BrecklandCouncilTests(ITestOutputHelper outputHelper) - { - _outputHelper = outputHelper; - _client = new IntegrationTestClient(outputHelper); - } - - [Theory] - [InlineData("NR172BJ")] - public async Task GetBinDaysTest(string postcode) - { - await TestSteps.EndToEnd( - _client, - _collectorService, - _collector, - postcode, - _outputHelper - ); - } -} +namespace BinDays.Api.IntegrationTests.Collectors.Councils; + +using BinDays.Api.Collectors.Collectors; +using BinDays.Api.Collectors.Collectors.Councils; +using BinDays.Api.Collectors.Services; +using BinDays.Api.IntegrationTests.Helpers; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +public class BrecklandCouncilTests +{ + private readonly IntegrationTestClient _client; + private static readonly ICollector _collector = new BrecklandCouncil(); + private readonly CollectorService _collectorService = new([_collector]); + private readonly ITestOutputHelper _outputHelper; + + public BrecklandCouncilTests(ITestOutputHelper outputHelper) + { + _outputHelper = outputHelper; + _client = new IntegrationTestClient(outputHelper); + } + + [Theory] + [InlineData("NR172BJ")] + public async Task GetBinDaysTest(string postcode) + { + await TestSteps.EndToEnd( + _client, + _collectorService, + _collector, + postcode, + _outputHelper + ); + } +} From 43895d7ce876f4bfb9ad36a6f593b332606f81f5 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:38:49 +0000 Subject: [PATCH 3/4] Address PR review comments for Breckland Council collector - Remove duplicate keys from bin types - Remove explicit Type = BinType.Bin (default value) - Replace if-statement address formatting with LINQ - Add .Trim() to all external strings - Use target-typed new() for dictionaries - Add trailing commas to object initializers - Add iteration comments before foreach loops - Add using System.Linq Co-authored-by: Andrew Riggs --- .../Collectors/Councils/BrecklandCouncil.cs | 78 ++++++------------- 1 file changed, 23 insertions(+), 55 deletions(-) diff --git a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs index ce4261c8..1109255a 100644 --- a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs +++ b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs @@ -6,6 +6,7 @@ namespace BinDays.Api.Collectors.Collectors.Councils; using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text.Json; /// @@ -30,28 +31,26 @@ internal sealed class BrecklandCouncil : GovUkCollectorBase, ICollector { Name = "General Waste", Colour = BinColour.Black, - Keys = [ "Refuse Collection Service", "Refuse" ], - Type = BinType.Bin, + Keys = [ "Refuse Collection Service" ], }, new() { Name = "Recycling", Colour = BinColour.Green, - Keys = [ "Recycling Collection Service", "Recycling" ], - Type = BinType.Bin, + Keys = [ "Recycling Collection Service" ], }, new() { Name = "Garden Waste", Colour = BinColour.Brown, - Keys = [ "Garden Waste Collection Service", "Garden Waste" ], + Keys = [ "Garden Waste Collection Service" ], Type = BinType.Sack, }, new() { Name = "Food Waste", Colour = BinColour.Grey, - Keys = [ "Food Waste Collection Service", "Food Waste" ], + Keys = [ "Food Waste Collection Service" ], Type = BinType.Caddy, }, ]; @@ -79,7 +78,7 @@ public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? cl RequestId = 1, Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", Method = "POST", - Headers = new Dictionary + Headers = new() { { "Content-Type", "application/json" }, { "X-Requested-With", "XMLHttpRequest" }, @@ -90,7 +89,7 @@ public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? cl return new GetAddressesResponse { - NextClientSideRequest = clientSideRequest + NextClientSideRequest = clientSideRequest, }; } // Process addresses from response @@ -98,58 +97,26 @@ public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? cl { using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); + // Iterate through each address, and create a new address object var addresses = new List
(); foreach (var addressElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) { - var propertyParts = new List(); + var number = addressElement.GetProperty("number").GetString()?.Trim(); + var name = addressElement.GetProperty("name").GetString()?.Trim(); + var address1 = addressElement.GetProperty("address1").GetString()?.Trim(); + var address2 = addressElement.GetProperty("address2").GetString()?.Trim(); + var town = addressElement.GetProperty("town").GetString()?.Trim(); + var county = addressElement.GetProperty("county").GetString()?.Trim(); + var postcodeResult = addressElement.GetProperty("postcode").GetString()?.Trim(); - var number = addressElement.GetProperty("number").GetString(); - if (!string.IsNullOrWhiteSpace(number)) - { - propertyParts.Add(number); - } - - var name = addressElement.GetProperty("name").GetString(); - if (!string.IsNullOrWhiteSpace(name)) - { - propertyParts.Add(name); - } - - var address1 = addressElement.GetProperty("address1").GetString(); - if (!string.IsNullOrWhiteSpace(address1)) - { - propertyParts.Add(address1); - } - - var address2 = addressElement.GetProperty("address2").GetString(); - if (!string.IsNullOrWhiteSpace(address2)) - { - propertyParts.Add(address2); - } - - var town = addressElement.GetProperty("town").GetString(); - if (!string.IsNullOrWhiteSpace(town)) - { - propertyParts.Add(town); - } - - var county = addressElement.GetProperty("county").GetString(); - if (!string.IsNullOrWhiteSpace(county)) - { - propertyParts.Add(county); - } - - var postcodeResult = addressElement.GetProperty("postcode").GetString(); - if (!string.IsNullOrWhiteSpace(postcodeResult)) - { - propertyParts.Add(postcodeResult); - } + var propertyParts = new[] { number, name, address1, address2, town, county, postcodeResult } + .Where(part => !string.IsNullOrWhiteSpace(part)); var address = new Address { Property = string.Join(", ", propertyParts), Postcode = postcodeResult ?? postcode, - Uid = addressElement.GetProperty("uprn").GetString()!, + Uid = addressElement.GetProperty("uprn").GetString()!.Trim(), }; addresses.Add(address); @@ -188,7 +155,7 @@ public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? client RequestId = 1, Url = "https://www.breckland.gov.uk/apiserver/ajaxlibrary", Method = "POST", - Headers = new Dictionary + Headers = new() { { "Content-Type", "application/json" }, { "X-Requested-With", "XMLHttpRequest" }, @@ -199,7 +166,7 @@ public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? client return new GetBinDaysResponse { - NextClientSideRequest = clientSideRequest + NextClientSideRequest = clientSideRequest, }; } // Process bin days from response @@ -207,11 +174,12 @@ public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? client { using var jsonDoc = JsonDocument.Parse(clientSideResponse.Content); + // Iterate through each bin day, and create a new bin day object var binDays = new List(); foreach (var binDayElement in jsonDoc.RootElement.GetProperty("result").EnumerateArray()) { - var binType = binDayElement.GetProperty("collectiontype").GetString()!; - var collectionDate = binDayElement.GetProperty("nextcollection").GetString()!; + var binType = binDayElement.GetProperty("collectiontype").GetString()!.Trim(); + var collectionDate = binDayElement.GetProperty("nextcollection").GetString()!.Trim(); var parsedDate = DateTime.ParseExact( collectionDate, From 1e9f370c075e316ce801f9002c295f3bc678c5f7 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 23:50:52 +0000 Subject: [PATCH 4/4] Address outstanding PR review comments - Remove unnecessary postcode fetch from response data (line 110) - Use separate variable declarations for response objects instead of inline returns - Remove postcodeResult variable as we already have postcode from parameter Co-authored-by: Andrew Riggs --- .../Collectors/Councils/BrecklandCouncil.cs | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs index 1109255a..6cc1a03e 100644 --- a/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs +++ b/BinDays.Api.Collectors/Collectors/Councils/BrecklandCouncil.cs @@ -87,10 +87,12 @@ public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? cl Body = requestBody, }; - return new GetAddressesResponse + var response = new GetAddressesResponse { NextClientSideRequest = clientSideRequest, }; + + return response; } // Process addresses from response else if (clientSideResponse.RequestId == 1) @@ -107,25 +109,26 @@ public GetAddressesResponse GetAddresses(string postcode, ClientSideResponse? cl var address2 = addressElement.GetProperty("address2").GetString()?.Trim(); var town = addressElement.GetProperty("town").GetString()?.Trim(); var county = addressElement.GetProperty("county").GetString()?.Trim(); - var postcodeResult = addressElement.GetProperty("postcode").GetString()?.Trim(); - var propertyParts = new[] { number, name, address1, address2, town, county, postcodeResult } + var propertyParts = new[] { number, name, address1, address2, town, county } .Where(part => !string.IsNullOrWhiteSpace(part)); var address = new Address { Property = string.Join(", ", propertyParts), - Postcode = postcodeResult ?? postcode, + Postcode = postcode, Uid = addressElement.GetProperty("uprn").GetString()!.Trim(), }; addresses.Add(address); } - return new GetAddressesResponse + var response = new GetAddressesResponse { Addresses = [.. addresses], }; + + return response; } // Throw exception for invalid request @@ -164,10 +167,12 @@ public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? client Body = requestBody, }; - return new GetBinDaysResponse + var response = new GetBinDaysResponse { NextClientSideRequest = clientSideRequest, }; + + return response; } // Process bin days from response else if (clientSideResponse.RequestId == 1) @@ -200,10 +205,12 @@ public GetBinDaysResponse GetBinDays(Address address, ClientSideResponse? client binDays.Add(binDay); } - return new GetBinDaysResponse + var response = new GetBinDaysResponse { BinDays = ProcessingUtilities.ProcessBinDays(binDays), }; + + return response; } // Throw exception for invalid request