Skip to content
This repository has been archived by the owner on Jul 25, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into 436-fe-list-of-financial-periods-covered-by-…
Browse files Browse the repository at this point in the history
…the-data
  • Loading branch information
DonShelly committed Jun 19, 2023
2 parents 0336e12 + f1f91c3 commit edb7427
Show file tree
Hide file tree
Showing 22 changed files with 445 additions and 162 deletions.
1 change: 1 addition & 0 deletions .flaskenv
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ FLASK_APP=app.py
FLASK_DEBUG=True
FLASK_RUN_PORT=5000
FLASK_ENV=development
DATA_STORE_API_HOST=http://localhost:5000
22 changes: 18 additions & 4 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@ on:
push:
branches:
- main
workflow_dispatch:
inputs:
environment:
description: Which AWS Account to use
type: choice
required: true
options:
- test
- production

jobs:
deployment:
permissions:
id-token: write # This is required for requesting the JWT
contents: read # This is required for actions/checkout
runs-on: ubuntu-latest
environment: test
environment: ${{ inputs.environment || 'test' }}
steps:
- name: Git clone the repository
uses: actions/checkout@v3
Expand All @@ -20,10 +29,15 @@ jobs:
run: |
./build.sh
- name: Get current date
id: currentdatetime
run: echo "::set-output name=datetime::$(date +'%Y%m%d%H%M%S')"

- name: configure aws credentials
uses: aws-actions/configure-aws-credentials@v1
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::012986738649:role/GitHubPushToECR
role-to-assume: arn:aws:iam::${{ secrets.AWS_ACCOUNT_NUMBER }}:role/GitHubPushToECR
role-session-name: POST_AWARD_DATA_FRONTEND_${{ steps.currentdatetime.outputs.datetime }}
aws-region: eu-west-2

- name: Install AWS Copilot CLI
Expand All @@ -32,4 +46,4 @@ jobs:
- name: Copilot deploy
run: |
copilot deploy
copilot deploy --env ${{ inputs.environment || 'test' }}
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ COPY . .
EXPOSE 8080

ENV FLASK_ENV=dev
ENV GUNICORN_CMD_ARGS="--workers=3"
ENV GUNICORN_CMD_ARGS="--timeout 60 --workers 3"

CMD ["gunicorn", "wsgi:app", "-c", "run/gunicorn/run.py"]
3 changes: 3 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from app import app # noqa

if __name__ == "__main__":
app.run()
7 changes: 5 additions & 2 deletions app/main/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ def get_response(hostname: str, endpoint: str, query_params: dict = None) -> Res
:return: The requests Response object containing the response from the remote server.
"""
request_url = (
hostname + endpoint + (f"?{urlencode(query_params)}" if query_params else "")
hostname
+ endpoint
+ ("?" + urlencode(query_params, doseq=True) if query_params else "")
)
response = requests.get(request_url)
if response.status_code == 200:
if response.status_code in [200, 404]:
return response

else:
current_app.logger.error(
f"Bad response: {request_url} returned {response.status_code}"
Expand Down
256 changes: 178 additions & 78 deletions app/main/download_data.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,142 @@
from datetime import datetime

fund = {
"name": "fund",
"items": [
{"text": "Towns Fund - Future High Streets Fund", "value": "high-streets"},
{"text": "Towns Fund - Town Deals", "value": "town-deals"},
],
}

area = {
"name": "area",
"items": [
{"text": "North East", "value": "TLC"},
{"text": "North West", "value": "TLD"},
{"text": "Yorkshire and the Humber", "value": "TLE"},
{"text": "East Midlands", "value": "TLF"},
{"text": "West Midlands", "value": "TLG"},
{"text": "East of England", "value": "TLH"},
{"text": "London", "value": "TLI"},
{"text": "South East", "value": "TLJ"},
{"text": "South West", "value": "TLK"},
{"text": "Scotland", "value": "TLM"},
{"text": "Wales", "value": "TLL"},
{"text": "Northern Ireland", "value": "TLN"},
],
}

fundedOrg = {
"name": "organisation",
"items": [
{"text": "Allerdale Borough Council", "value": "value1"},
{"text": "Amber Valley Borough Council", "value": "value2"},
{"text": "Ashfield District Council", "value": "value3"},
{"text": "Barnsley Metropolitan Borough Council", "value": "value1"},
{"text": "Bolton Metropolitan Borough Council", "value": "value2"},
{"text": "Calderdale Metropolitan Borough Council", "value": "value3"},
{"text": "Carlisle City Council", "value": "value1"},
{"text": "Cheshire East Council", "value": "value2"},
{"text": "Cheshire West and Chester Council", "value": "value3"},
{"text": "Cornwall Council", "value": "value1"},
{"text": "Derby City Council", "value": "value2"},
{"text": "Dover District Council", "value": "value3"},
{"text": "Dudley Metropolitan Borough Council", "value": "value1"},
],
}

outcomes = {
"name": "outcome",
"items": [
{"text": "Business", "value": "value1"},
{"text": "Culture", "value": "value2"},
{"text": "Economy", "value": "value3"},
{"text": "Education", "value": "value1"},
{"text": "Health & Wellbeing", "value": "value2"},
{"text": "Place", "value": "value3"},
{"text": "Regeneration", "value": "value1"},
{"text": "Transport", "value": "value2"},
],
}


def generate_financial_years(min_date: datetime, max_date: datetime):
from enum import StrEnum
from typing import Any

from app.main.data import get_response
from config import Config


def quarter_to_date(quarter, year):
# January-March is Q1, April-June is Q2, July-September is Q3, and October-December is Q4

start_year = year.split("/")[0]
quarter_mapping = {
"1": f"{start_year}-04-01T00:00:00Z",
"2": f"{start_year}-07-01T00:00:00Z",
"3": f"{start_year}-10-01T00:00:00Z",
"4": f"{start_year}-01-01T00:00:00Z",
}

return quarter_mapping.get(quarter)


class FormNames(StrEnum):
FUNDS = "funds"
ORGS = "orgs"
AREAS = "areas"
OUTCOMES = "outcomes"
RETURNS_PERIOD = "funds"


def get_checkbox_data(endpoint):
response = get_response(hostname=Config.DATA_STORE_API_HOST, endpoint=endpoint)

# If the API returns 404, use empty array
if response.status_code == 404:
return []

# Else, populate checkboxes with the response
elif response.status_code == 200:
return response.json()


def get_fund_checkboxes() -> dict[str, Any]:
"""Get checkbox data for the funds section.
Calls API to get fund data and formats to checkbox data format.
Example API data: [{"id": "FHSF", "name": "High Street Fund"}, {"id": "TFTD", "name": "Towns Fund - Town Deals"}]
:return: checkbox data for funds
"""
fund_data = get_checkbox_data("/funds")
fund_checkboxes = {
"name": FormNames.FUNDS,
"items": fund_data,
}
return fund_checkboxes


def get_area_checkboxes() -> dict[str, Any]:
"""Get checkbox data for the areas section.
This data is just hardcoded and covers all possible regions.
:return: checkbox data for areas
"""
area_data = [
{"name": "North East", "id": "TLC"},
{"name": "North West", "id": "TLD"},
{"name": "Yorkshire and the Humber", "id": "TLE"},
{"name": "East Midlands", "id": "TLF"},
{"name": "West Midlands", "id": "TLG"},
{"name": "East of England", "id": "TLH"},
{"name": "London", "id": "TLI"},
{"name": "South East", "id": "TLJ"},
{"name": "South West", "id": "TLK"},
{"name": "Scotland", "id": "TLM"},
{"name": "Wales", "id": "TLL"},
{"name": "Northern Ireland", "id": "TLN"},
]
area_checkboxes = {
"name": FormNames.AREAS,
"items": area_data,
}
return area_checkboxes


def get_org_checkboxes() -> dict[str, Any]:
"""Get checkbox data for the orgs section.
Calls API to get org data and formats to checkbox data format.
Example API data: [
{"id": "f5aa...64e", "name": "Dudley Metropolitan Borough Council"},
{"id": "c6da...2dd", "name": "Dover District Council"},
]
:return: checkbox data for orgs
"""
org_data = get_checkbox_data("/organisations")
org_checkboxes = {
"name": FormNames.ORGS,
"items": org_data,
}
return org_checkboxes


def get_outcome_checkboxes() -> dict[str, Any]:
"""Get checkbox data for the outcomes section.
Calls API to get outcome data and formats to checkbox data format.
Example API data: ["Business", "Culture"]
:return: checkbox data for outcomes
"""
outcome_data = get_checkbox_data("/outcome-categories")
outcome_checkboxes = {
"name": FormNames.OUTCOMES,
# display Other instead of Custom
"items": [
{"id": outcome, "name": outcome if outcome != "Custom" else "Other"}
for outcome in outcome_data
],
}
return outcome_checkboxes


def generate_financial_years(start_date, end_date):
"""Generate a list of financial years available based on the start and end dates provided by the db
Args:
start_date (datetime.date): The start date.
end_date (datetime.date): The end date.
Returns:
list: A list of financial years in the format 'YYYY/YYYY+1', representing the range
of dates. Each financial year is represented as a string.
"""

# Adjust the years for the financial year
min_year = min_date.year if min_date.month > 3 else min_date.year - 1
max_year = max_date.year if max_date.month > 3 else max_date.year - 1
min_year = start_date.year if start_date.month > 3 else start_date.year - 1
max_year = end_date.year if end_date.month > 3 else end_date.year - 1

# Generate the list of financial years
financial_years = [
Expand All @@ -73,19 +146,46 @@ def generate_financial_years(min_date: datetime, max_date: datetime):
return financial_years


def populate_financial_years():
# TODO: get dates from BE
# hardcoded values:
min_date = datetime(2019, 5, 1)
max_date = datetime(2023, 6, 1)
# TODO decide wether to implement this or leave all quarter options available
def generate_quarters(start_date, end_date):
"""Calculates which quarter the given min and max month resides in
Returns:
list: A list of quarters corresponding to the range of dates. Each quarter is
represented by an integer (1, 2, 3, or 4).
"""

start_quarter = (start_date.month - 1) // 3 + 1
end_quarter = (end_date.month - 1) // 3 + 1

quarter_options = [1, 2, 3, 4]

return quarter_options[min(start_quarter, end_quarter) - 1 :: 1]


def get_returns() -> dict[str, Any]:
"""Retrieves data from /returns API endpoint and generates a dictionary of return period options.
Returns:
dict: A dictionary containing lists of return period options.
"""
returns_data = get_checkbox_data("/reporting-period-range")

return generate_financial_years(min_date, max_date)
if not returns_data:
years = []
else:
start_date = datetime.strptime(
returns_data["start_date"].split("T")[0], "%Y-%m-%d"
)
end_date = datetime.strptime(returns_data["end_date"].split("T")[0], "%Y-%m-%d")
years = generate_financial_years(start_date, end_date)

returns_select = {
"name": FormNames.RETURNS_PERIOD,
"from-quarter": [1, 2, 3, 4],
"to-quarter": [1, 2, 3, 4],
"from-year": years,
"to-year": years,
}

returns = {
"name": "return_period",
# TODO: replace with validated quarters
"quarter": (1, 2, 3, 4),
# TODO: replace with validated years
"year": (populate_financial_years()),
}
return returns_select
Loading

0 comments on commit edb7427

Please sign in to comment.