Skip to content

Commit

Permalink
Merge pull request #889 from m26dvd/master
Browse files Browse the repository at this point in the history
  • Loading branch information
robbrad authored Oct 16, 2024
2 parents 86f481b + 7892acb commit 552de27
Show file tree
Hide file tree
Showing 5 changed files with 1,265 additions and 184 deletions.
22 changes: 22 additions & 0 deletions uk_bin_collection/tests/input.json
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,14 @@
"wiki_name": "Lichfield District Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"LincolnCouncil": {
"url": "https://lincoln.gov.uk",
"wiki_command_url_override": "https://lincoln.gov.uk",
"uprn": "000235024846",
"postcode": "LN5 7SH",
"wiki_name": "Tunbridge Wells Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"LisburnCastlereaghCityCouncil": {
"house_number": "97",
"postcode": "BT28 1JN",
Expand Down Expand Up @@ -871,6 +879,13 @@
"wiki_name": "Oldham Council",
"wiki_note": "Replace UPRN in URL with your own UPRN."
},
"PerthAndKinrossCouncil": {
"url": "https://www.pkc.gov.uk",
"wiki_command_url_override": "https://www.pkc.gov.uk",
"uprn": "124032322",
"wiki_name": "Perth and Kinross Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"PortsmouthCityCouncil": {
"postcode": "PO4 0LE",
"skip_get_url": true,
Expand Down Expand Up @@ -1200,6 +1215,13 @@
"url": "https://collections-torridge.azurewebsites.net/WebService2.asmx",
"wiki_name": "Torridge District Council"
},
"TunbridgeWellsCouncil": {
"url": "https://tunbridgewells.gov.uk",
"wiki_command_url_override": "https://tunbridgewells.gov.uk",
"uprn": "10090058289",
"wiki_name": "Tunbridge Wells Council",
"wiki_note": "You will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search) to find the UPRN."
},
"UttlesfordDistrictCouncil": {
"house_number": "72, Birchanger Lane",
"postcode": "CM23 5QF",
Expand Down
96 changes: 96 additions & 0 deletions uk_bin_collection/uk_bin_collection/councils/LincolnCouncil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import time

import requests

from uk_bin_collection.uk_bin_collection.common import *
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass


# import the wonderful Beautiful Soup and the URL grabber
class CouncilClass(AbstractGetBinDataClass):
"""
Concrete classes have to implement all abstract operations of the
base class. They can also override some operations with a default
implementation.
"""

def parse_data(self, page: str, **kwargs) -> dict:

user_uprn = kwargs.get("uprn")
user_postcode = kwargs.get("postcode")
check_uprn(user_uprn)
check_postcode(user_postcode)
bindata = {"bins": []}

SESSION_URL = "https://contact.lincoln.gov.uk/authapi/isauthenticated?uri=https://contact.lincoln.gov.uk/AchieveForms/?mode=fill&consentMessage=yes&form_uri=sandbox-publish://AF-Process-503f9daf-4db9-4dd8-876a-6f2029f11196/AF-Stage-a1c0af0f-fec1-4419-80c0-0dd4e1d965c9/definition.json&process=1&process_uri=sandbox-processes://AF-Process-503f9daf-4db9-4dd8-876a-6f2029f11196&process_id=AF-Process-503f9daf-4db9-4dd8-876a-6f2029f11196&hostname=contact.lincoln.gov.uk&withCredentials=true"

API_URL = "https://contact.lincoln.gov.uk/apibroker/runLookup"

data = {
"formValues": {
"Section 1": {
"chooseaddress": {"value": user_uprn},
"postcode": {"value": user_postcode},
}
},
}

headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0",
"X-Requested-With": "XMLHttpRequest",
"Referer": "https://contact.lincoln.gov.uk/fillform/?iframe_id=fillform-frame-1&db_id=",
}
s = requests.session()
r = s.get(SESSION_URL)
r.raise_for_status()
session_data = r.json()
sid = session_data["auth-session"]
params = {
"id": "62aafd258f72c",
"repeat_against": "",
"noRetry": "false",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AF-Renderer::Self",
# unix_timestamp
"_": str(int(time.time() * 1000)),
"sid": sid,
}

r = s.post(API_URL, json=data, headers=headers, params=params)
r.raise_for_status()
data = r.json()
rows_data = data["integration"]["transformed"]["rows_data"]
if not isinstance(rows_data, dict):
raise ValueError("Invalid data returned from API")

BIN_TYPES = [
("refusenextdate", "Black Bin", "refuse_freq"),
("recyclenextdate", "Brown Bin", "recycle_freq"),
("gardennextdate", "Green Bin", "garden_freq"),
]

for uprn, data in rows_data.items():
if uprn != user_uprn:
continue
for key, bin_type, freq in BIN_TYPES:
if not data[key]:
continue
offsets = [0]
if data[freq] == "fortnightly":
offsets.extend(list(range(14, 30, 14)))
elif data[freq] == "weekly":
offsets.extend(list(range(7, 30, 7)))
date = datetime.strptime(data[key], "%Y-%m-%d").date()
for offset in offsets:
dict_data = {
"type": bin_type,
"collectionDate": (date + timedelta(days=offset)).strftime(
"%d/%m/%Y"
),
}
bindata["bins"].append(dict_data)

return bindata
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import time

import requests

from uk_bin_collection.uk_bin_collection.common import *
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass


# import the wonderful Beautiful Soup and the URL grabber
class CouncilClass(AbstractGetBinDataClass):
"""
Concrete classes have to implement all abstract operations of the
base class. They can also override some operations with a default
implementation.
"""

def parse_data(self, page: str, **kwargs) -> dict:

user_uprn = kwargs.get("uprn")
check_uprn(user_uprn)
bindata = {"bins": []}

SESSION_URL = "https://pkc-self.achieveservice.com/authapi/isauthenticated?uri=https%253A%252F%252Fpkc-self.achieveservice.com%252Fen%252FAchieveForms%252F%253Fform_uri%253Dsandbox-publish%253A%252F%252FAF-Process-de9223b1-a7c6-408f-aaa3-aee33fd7f7fa%252FAF-Stage-9fa33e2e-4c1b-4963-babf-4348ab8154bc%252Fdefinition.json%2526redirectlink%253D%25252Fen%2526cancelRedirectLink%253D%25252Fen%2526consentMessage%253Dyes&hostname=pkc-self.achieveservice.com&withCredentials=true"

API_URL = "https://pkc-self.achieveservice.com/apibroker/runLookup"

data = {
"formValues": {
"Bin collections": {"propertyUPRNQuery": {"value": user_uprn}}
},
}

headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0",
"X-Requested-With": "XMLHttpRequest",
"Referer": "https://pkc-self.achieveservice.com/fillform/?iframe_id=fillform-frame-1&db_id=",
}
s = requests.session()
r = s.get(SESSION_URL)
r.raise_for_status()
session_data = r.json()
sid = session_data["auth-session"]
params = {
"id": "5c9267cee5efe",
"repeat_against": "",
"noRetry": "true",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AF-Renderer::Self",
# unix_timestamp
"_": str(int(time.time() * 1000)),
"sid": sid,
}

r = s.post(API_URL, json=data, headers=headers, params=params)
r.raise_for_status()

data = r.json()
rows_data = data["integration"]["transformed"]["rows_data"]["0"]
if not isinstance(rows_data, dict):
raise ValueError("Invalid data returned from API")

schedule = {
"Green Bin": [
rows_data.get("nextGeneralWasteCollectionDate"),
rows_data.get("nextGeneralWasteCollectionDate2nd"),
],
"Blue Bin": [
rows_data.get("nextBlueCollectionDate"),
rows_data.get("nextBlueWasteCollectionDate2nd"),
],
"Grey Bin": [
rows_data.get("nextGreyWasteCollectionDate"),
rows_data.get("nextGreyWasteCollectionDate2nd"),
],
"Brown Bin": [
rows_data.get("nextGardenandFoodWasteCollectionDate"),
rows_data.get("nextGardenandFoodWasteCollectionDate2nd"),
],
"Paper Waste": [
rows_data.get("nextPaperWasteCollectionDate"),
rows_data.get("nextPaperWasteCollectionDate2nd"),
],
}

# Format and output the schedule
for bin_type, dates in schedule.items():
if any(dates):
for date in dates:
dict_data = {"type": bin_type, "collectionDate": date}
bindata["bins"].append(dict_data)

return bindata
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import time

import requests

from uk_bin_collection.uk_bin_collection.common import *
from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass


# import the wonderful Beautiful Soup and the URL grabber
class CouncilClass(AbstractGetBinDataClass):
"""
Concrete classes have to implement all abstract operations of the
base class. They can also override some operations with a default
implementation.
"""

def parse_data(self, page: str, **kwargs) -> dict:

user_uprn = kwargs.get("uprn")
check_uprn(user_uprn)
bindata = {"bins": []}

SESSION_URL = "https://mytwbc.tunbridgewells.gov.uk/authapi/isauthenticated?uri=https%3A%2F%2Fmytwbc.tunbridgewells.gov.uk%2FAchieveForms%2F%3Fmode%3Dfill%26consentMessage%3Dyes%26form_uri%3Dsandbox-publish%3A%2F%2FAF-Process-e01af4d4-eb0f-4cfe-a5ac-c47b63f017ed%2FAF-Stage-88caf66c-378f-4082-ad1d-07b7a850af38%2Fdefinition.json%26process%3D1%26process_uri%3Dsandbox-processes%3A%2F%2FAF-Process-e01af4d4-eb0f-4cfe-a5ac-c47b63f017ed%26process_id%3DAF-Process-e01af4d4-eb0f-4cfe-a5ac-c47b63f017ed&hostname=mytwbc.tunbridgewells.gov.uk&withCredentials=true"

API_URL = "https://mytwbc.tunbridgewells.gov.uk/apibroker/runLookup"

data = {
"formValues": {"Property": {"siteReference": {"value": user_uprn}}},
}

headers = {
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "Mozilla/5.0",
"X-Requested-With": "XMLHttpRequest",
"Referer": "https://mytwbc.tunbridgewells.gov.uk/fillform/?iframe_id=fillform-frame-1&db_id=",
}
s = requests.session()
r = s.get(SESSION_URL)
r.raise_for_status()
session_data = r.json()
sid = session_data["auth-session"]
params = {
"id": "6314720683f30",
"repeat_against": "",
"noRetry": "false",
"getOnlyTokens": "undefined",
"log_id": "",
"app_name": "AF-Renderer::Self",
# unix_timestamp
"_": str(int(time.time() * 1000)),
"sid": sid,
}

r = s.post(API_URL, json=data, headers=headers, params=params)
r.raise_for_status()

data = r.json()
rows_data = data["integration"]["transformed"]["rows_data"]
if not isinstance(rows_data, dict):
raise ValueError("Invalid data returned from API")

for _, item in rows_data.items():
bin_type = item["collectionType"]
date = datetime.strptime(item["nextDateUnformatted"], "%d/%m/%Y").strftime(
"%d/%m/%Y"
)
dict_data = {"type": bin_type, "collectionDate": date}
bindata["bins"].append(dict_data)

return bindata
Loading

0 comments on commit 552de27

Please sign in to comment.