Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EL-1909 single cat search page #380

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ fala/static
.python-version

# VSCode
.vscode
.vscode
fala/apps/adviser/fala.code-workspace
137 changes: 136 additions & 1 deletion fala/apps/adviser/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from django.utils.translation import gettext_lazy as _
from django.utils.safestring import mark_safe
from django.conf import settings

import laalaa.api as laalaa
import requests
from requests.adapters import HTTPAdapter
Expand Down Expand Up @@ -193,3 +192,139 @@ def search(self):
return {}
else:
return {}


class SingleCategorySearchForm(forms.Form):
postcode = CapitalisedPostcodeField(
label=_("Postcode"),
max_length=30,
required=True, # Postcode is required in this form
widget=FalaTextInput(attrs={"class": "govuk-input govuk-!-width-two-thirds"}),
)

def __init__(self, categories=None, *args, **kwargs):
super().__init__(*args, **kwargs)
# Ensure categories is a list and assign it to self.categories
self.categories = categories if categories is not None else []
self._region = None
self._country_from_valid_postcode = None

def clean_postcode(self):
postcode = self.cleaned_data.get("postcode")
if not postcode:
raise forms.ValidationError(_("Enter a valid postcode"))
return postcode

def clean(self):
cleaned_data = super().clean()
postcode = cleaned_data.get("postcode")
categories = self.data.get("category")

# Validate postcode and set `_country_from_valid_postcode`
if postcode:
valid_postcode = self.validate_postcode_and_return_country(postcode)
if not valid_postcode:
self.add_error("postcode", _("Enter a valid postcode"))
else:
self._country_from_valid_postcode = valid_postcode # This is used by the `region` property

# Check if categories are provided
if not categories:
self.add_error("categories", _("Category is required."))
else:
self.categories = [categories]

return cleaned_data

@property
def region(self):
# retrieve the api call variables
country_from_valid_postcode = getattr(self, "_country_from_valid_postcode", None)

# Return `Region.ENGLAND_OR_WALES` from `clean` if set
if not country_from_valid_postcode:
region = getattr(self, "_region", None)
return region

# for Guernsey & Jersey the country comes back as 'Channel Islands', we are using `nhs_ha` key to distinguish between them
country, nhs_ha = country_from_valid_postcode

if country == "Northern Ireland":
return Region.NI
elif country == "Isle of Man":
return Region.IOM
elif country == "Channel Islands" and nhs_ha == "Jersey Health Authority":
return Region.JERSEY
elif country == "Channel Islands" and nhs_ha == "Guernsey Health Authority":
return Region.GUERNSEY
elif country == "Scotland":
return Region.SCOTLAND
elif country in ["England", "Wales"]:
return Region.ENGLAND_OR_WALES
else:
self.add_error("postcode", _("This service is only available for England and Wales"))
return None

@property
def current_page(self):
page = self.cleaned_data.get("page", 1)
return page

def validate_postcode_and_return_country(self, postcode):
try:
if not isinstance(postcode, str) or not postcode.strip():
return False

session = requests.Session()
retry_strategy = Retry(total=5, backoff_factor=0.1)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)

url = settings.POSTCODE_IO_URL + f"{postcode}"
response = session.get(url, timeout=5)

if response.status_code != 200:
return False

data = response.json()

if not data.get("result"):
return False

first_result_in_list = data["result"][0]
country = first_result_in_list.get("country")
nhs_ha = first_result_in_list.get("nhs_ha")

if country and nhs_ha:
return country, nhs_ha
else:
return False

except requests.RequestException:
self.add_error("postcode", _("Error looking up legal advisers. Please try again later."))
return False

def search(self):
if self.is_valid():
try:
postcode = self.cleaned_data.get("postcode")
categories = self.categories

# Call the API
data = laalaa.find(postcode=postcode, categories=categories, page=1)

# Check for errors in the response
if "error" in data:
self.add_error("postcode", data["error"])
return []

# Extract only the 'results' key
# this may be where the problem is with the display of the results
# i remove everythng but the results but I think the template wants a
# block called 'data' within which exists `results`` so data.results cntains the search results
results = data.get("results", [])
return results
except laalaa.LaaLaaError:
self.add_error("postcode", _("Error looking up legal advisers. Please try again later."))
return []
return []
155 changes: 155 additions & 0 deletions fala/apps/adviser/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from django.db import models
from django.utils import timezone
from .regions import Region
from .laa_laa_paginator import LaaLaaPaginator
import urllib
from django.conf import settings
import logging


class SatisfactionFeedback(models.Model):
Expand All @@ -10,3 +15,153 @@ class SatisfactionFeedback(models.Model):

def __str__(self):
return f"Feedback {self.id}"


logger = logging.getLogger(__name__)


class EnglandOrWalesState(object):
def __init__(self, form):
self._form = form
self._data = form.search()

@property
def template_name(self):
return "adviser/results.html"

def get_queryset(self):
if isinstance(self._data, list): # Ensure it is a list before returning
return self._data
else:
logger.error("Unexpected data format: %s", self._data)
return [] # Return an empty list if data is not valid

def get_context_data(self):
pages = LaaLaaPaginator(self._data["count"], 10, 3, self._form.current_page)
logger.debug("343434Validating pages: %s", pages)
current_page = pages.current_page()
params = {
"postcode": self._form.cleaned_data["postcode"],
"name": self._form.cleaned_data["name"],
}
categories = self._form.cleaned_data["categories"]

# create list of tuples which can be passed to urlencode for pagination links
category_tuples = [("categories", c) for c in categories]

def item_for(page_num):
if len(categories) > 0:
page_params = {"page": page_num}
href = (
"/search?"
+ urllib.parse.urlencode({**page_params, **params})
+ "&"
+ urllib.parse.urlencode(category_tuples)
)
else:
page_params = {"page": page_num}
href = "/search?" + urllib.parse.urlencode({**page_params, **params})

return {"number": page_num, "current": self._form.current_page == page_num, "href": href}

pagination = {"items": [item_for(page_num) for page_num in pages.page_range]}

if current_page.has_previous():
if len(categories) > 0:
page_params = {"page": current_page.previous_page_number()}
prev_link = (
"/search?"
+ urllib.parse.urlencode({**page_params, **params})
+ "&"
+ urllib.parse.urlencode(category_tuples)
)
else:
page_params = {"page": current_page.previous_page_number()}
prev_link = "/search?" + urllib.parse.urlencode({**page_params, **params})
pagination["previous"] = {"href": prev_link}

if current_page.has_next():
if len(categories) > 0:
page_params = {"page": current_page.next_page_number()}
href = (
"/search?"
+ urllib.parse.urlencode({**page_params, **params})
+ "&"
+ urllib.parse.urlencode(category_tuples)
)
else:
page_params = {"page": current_page.next_page_number()}
href = "/search?" + urllib.parse.urlencode({**page_params, **params})
pagination["next"] = {"href": href}

return {
"form": self._form,
"data": self._data,
"params": params,
"FEATURE_FLAG_SURVEY_MONKEY": settings.FEATURE_FLAG_SURVEY_MONKEY,
"pagination": pagination,
}


class OtherJurisdictionState(object):
REGION_TO_LINK = {
Region.NI: {
"link": "https://www.nidirect.gov.uk/articles/legal-aid-schemes",
"region": "Northern Ireland",
},
Region.IOM: {
"link": "https://www.gov.im/categories/benefits-and-financial-support/legal-aid/",
"region": "the Isle of Man",
},
Region.JERSEY: {
"link": "https://www.legalaid.je/",
"region": "Jersey",
},
Region.GUERNSEY: {
"link": "https://www.gov.gg/legalaid",
"region": "Guernsey",
},
}

def __init__(self, region, postcode):
self._region = region
self._postcode = postcode

def get_queryset(self):
return []

@property
def template_name(self):
return "adviser/other_region.html"

def get_context_data(self):
region_data = self.REGION_TO_LINK[self._region]
return {
"postcode": self._postcode,
"link": region_data["link"],
"region": region_data["region"],
}


class ErrorState(object):
def __init__(self, form):
self._form = form

@property
def template_name(self):
return "search.html"

def get_queryset(self):
return []

def get_context_data(self):
errorList = []
for field, error in self._form.errors.items():
# choose the first field is the error in form-wide
if field == "__all__":
item = {"text": error[0], "href": "#id_postcode"}
else:
item = {"text": error[0], "href": f"#id_{field}"}
errorList.append(item)

return {"form": self._form, "data": {}, "errorList": errorList}
46 changes: 46 additions & 0 deletions fala/apps/adviser/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# utils.py

CATEGORY_TRANSLATIONS = {
"aap": "claims-against-public-authorities",
"med": "clinical-negligence",
"com": "community-care",
"crm": "crime",
"deb": "debt",
"disc": "discrimination",
"edu": "education",
"mat": "family",
"fmed": "family-mediation",
"hou": "housing",
"hlpas": "hlpas",
"immas": "immigration-asylum",
"mhe": "mental-health",
"mosl": "modern-slavery",
"pl": "prison-law",
"pub": "public-law",
"wb": "welfare-benefits",
}

SLUG_TO_CODE = {v: k for k, v in CATEGORY_TRANSLATIONS.items()}


def get_category_code_from_slug(slug):
return SLUG_TO_CODE.get(slug)


def get_category_display_name(category_code):
return CATEGORY_TRANSLATIONS.get(category_code)


CATEGORY_MESSAGES = {
"hlpas": "Tell the adviser your home is at risk and you want advice through the Housing Loss Prevention Advice Service.",
"welfare-benefits": (
"Legal aid for advice about welfare benefits is only available if you are appealing a decision made by the social security tribunal. "
"This appeal must be in the Upper Tribunal, Court of Appeal or Supreme Court.\n\n"
"For any other benefits issue, ask the legal adviser if you can get free legal advice or if you will have to pay for it."
),
"clinical-negligence": "Legal aid for advice about clinical negligence is usually only available if you have a child that suffered a brain injury during pregnancy, birth or the first 8 weeks of life.",
}

CATEGORY_DISPLAY_NAMES = {
"hlpas": "Housing Loss Prevention Advice Service",
}
Loading
Loading