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

Commit

Permalink
FS-4219 Enabling assessment view (#574)
Browse files Browse the repository at this point in the history
* pre-commit

* tidy up
  • Loading branch information
srh-sloan authored Feb 27, 2024
1 parent d3c264f commit cab975b
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 33 deletions.
13 changes: 5 additions & 8 deletions app/blueprints/assessments/models/fund_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
import pytz
from app.blueprints.authentication.validation import AssessmentAccessController
from app.blueprints.authentication.validation import get_countries_from_roles
from app.blueprints.authentication.validation import (
has_devolved_authority_validation,
)
from app.blueprints.authentication.validation import has_assessment_opened
from app.blueprints.authentication.validation import has_devolved_authority_validation
from app.blueprints.services.data_services import get_application_stats
from app.blueprints.services.data_services import get_assessments_stats
from app.blueprints.services.data_services import get_rounds
Expand Down Expand Up @@ -109,13 +108,14 @@ def create_round_summaries(fund: Fund, filters: LandingFilters) -> list[RoundSum
else ""
)

assessment_active = has_assessment_opened(round=round)
application_stats = None # populated later, with a bulk request

if _round_not_yet_open := current_datetime_before_given_iso_string(round.opens): # noqa
current_app.logger.info(
f"Round {fund.short_name} - {round.short_name} is not yet open (opens: {round.opens})"
)
application_stats = None
sorting_date = round.assessment_deadline
assessment_active = False
round_open = False
not_yet_open = True

Expand All @@ -137,9 +137,7 @@ def create_round_summaries(fund: Fund, filters: LandingFilters) -> list[RoundSum
f" open (opens: {round.opens}, closes: {round.deadline})"
)
live_rounds.append(round)
application_stats = None
sorting_date = round.deadline
assessment_active = False
round_open = True
not_yet_open = False
else:
Expand All @@ -162,7 +160,6 @@ def create_round_summaries(fund: Fund, filters: LandingFilters) -> list[RoundSum
not_yet_open = False
round_ids_to_fetch_assessment_stats.add(round.id)
sorting_date = round.assessment_deadline
application_stats = None # populated later, with a bulk request

summary = RoundSummary(
is_assessment_active_status=assessment_active,
Expand Down
49 changes: 37 additions & 12 deletions app/blueprints/authentication/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,21 +93,46 @@ def has_access_to_fund(short_name: str) -> bool:
return any(role in all_roles for role in access_roles)


def is_assessment_active(fund_id, round_id):
def has_assessment_opened(fund_id=None, round_id=None, round=None) -> bool:
"""Determines whether assessment has opened in the past. Overriden by
`Config.FORCE_OPEN_ALL_LIVE_ASSESSMENT_ROUNDS` in test envs.
Does not use `assessment_end_date`. If there is an `assessment_starts` present, uses that, otherwise
uses the `deadline` for applications in this round.
Args:
fund_id (_type_, optional): ID of the fund for the round to determine the status for. Defaults to None.
round_id (_type_, optional): ID of the round to determine the status for. Defaults to None.
round (_type_, optional): A round object - can be provided instead of IDs if already retrieved.
Defaults to None.
Returns:
bool: Whether or not this assessment round has opened.
"""
from datetime import datetime

# Check if the application is in a live round
round_information = get_round(
fund_id,
round_id,
ttl_hash=get_ttl_hash(Config.LRU_CACHE_TIME),
)
if not round:
round = get_round(
fund_id,
round_id,
ttl_hash=get_ttl_hash(Config.LRU_CACHE_TIME),
)

deadline = datetime.strptime(round_information.deadline, "%Y-%m-%dT%H:%M:%S")
if datetime.now() > deadline or Config.FORCE_OPEN_ALL_LIVE_ASSESSMENT_ROUNDS:
# Used in test envs to access open rounds
if Config.FORCE_OPEN_ALL_LIVE_ASSESSMENT_ROUNDS:
return True

deadline = datetime.strptime(round.deadline, "%Y-%m-%dT%H:%M:%S")
assessment_start = (
datetime.strptime(round.assessment_start, "%Y-%m-%dT%H:%M:%S") if round.assessment_start else None
)

# Not all rounds have an assessment_start specified. If they do not, use the application closing date instead

if assessment_start:
return datetime.now() > assessment_start
else:
return False
return datetime.now() > deadline


def check_access_application_id(func: Callable = None, roles_required: List[str] = []) -> Callable:
Expand All @@ -132,7 +157,7 @@ def decorated_function(*args, **kwargs):
ttl_hash=get_ttl_hash(Config.LRU_CACHE_TIME),
).short_name

assessment_open = is_assessment_active(application_metadata["fund_id"], application_metadata["round_id"])
assessment_open = has_assessment_opened(application_metadata["fund_id"], application_metadata["round_id"])
if not assessment_open:
abort(403, "This assessment is not yet live.")

Expand Down Expand Up @@ -184,7 +209,7 @@ def decorated_function(*args, **kwargs):
)

round_details = get_round(fund_value, round_value, using_short_name)
assessment_open = is_assessment_active(round_details.fund_id, round_details.id)
assessment_open = has_assessment_opened(round_details.fund_id, round_details.id)
if not assessment_open:
abort(403, "This assessment is not yet live.")

Expand Down
46 changes: 33 additions & 13 deletions tests/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
from app.blueprints.authentication.validation import get_countries_from_roles
from app.blueprints.authentication.validation import get_valid_country_roles
from app.blueprints.authentication.validation import has_access_to_fund
from app.blueprints.authentication.validation import has_assessment_opened
from app.blueprints.authentication.validation import (
has_devolved_authority_validation,
)
from app.blueprints.authentication.validation import has_relevant_country_role
from app.blueprints.authentication.validation import is_assessment_active
from app.blueprints.services.models.fund import Fund
from werkzeug.exceptions import HTTPException

Expand Down Expand Up @@ -200,7 +200,7 @@ def test_check_access_application_id_cant_access_application_when_no_country_rol
},
)
monkeypatch.setattr(
"app.blueprints.authentication.validation.is_assessment_active",
"app.blueprints.authentication.validation.has_assessment_opened",
lambda *args, **kwargs: True,
)
monkeypatch.setattr(
Expand Down Expand Up @@ -247,7 +247,7 @@ def test_check_access_application_id_can_access_application_when_has_country_rol
},
)
monkeypatch.setattr(
"app.blueprints.authentication.validation.is_assessment_active",
"app.blueprints.authentication.validation.has_assessment_opened",
lambda *args, **kwargs: True,
)
monkeypatch.setattr(
Expand Down Expand Up @@ -296,7 +296,7 @@ def test_check_access_application_id_can_access_application_when_fund_has_no_dev
},
)
monkeypatch.setattr(
"app.blueprints.authentication.validation.is_assessment_active",
"app.blueprints.authentication.validation.has_assessment_opened",
lambda *args, **kwargs: True,
)
monkeypatch.setattr(
Expand Down Expand Up @@ -335,7 +335,7 @@ def test_check_access_application_id_cant_access_application_when_no_relevant_fu
},
)
monkeypatch.setattr(
"app.blueprints.authentication.validation.is_assessment_active",
"app.blueprints.authentication.validation.has_assessment_opened",
lambda *args, **kwargs: True,
)
monkeypatch.setattr(
Expand Down Expand Up @@ -406,7 +406,7 @@ def test_check_access_fund_short_name_round_sn_can_access(monkeypatch, mock_get_
lambda _: "cof",
)
monkeypatch.setattr(
"app.blueprints.authentication.validation.is_assessment_active",
"app.blueprints.authentication.validation.has_assessment_opened",
lambda *args, **kwargs: True,
)
monkeypatch.setattr(
Expand All @@ -424,14 +424,32 @@ def test__get_roles_by_fund_short_name():
]


IN_THE_PAST = "2004-01-01T12:00:00"
IN_THE_FUTURE = "2124-01-01T12:00:00"


@pytest.mark.parametrize(
"datetime_offset, show_live_rounds_flag,truthy_result",
[(1, True, True), (1, False, False), (-1, True, True), (-1, False, True)],
"deadline, assessment_start,show_live_rounds_flag,truthy_result",
[
(IN_THE_FUTURE, None, True, True),
(IN_THE_FUTURE, None, False, False),
(IN_THE_PAST, None, True, True),
(IN_THE_PAST, None, False, True),
(IN_THE_PAST, IN_THE_FUTURE, True, True),
(IN_THE_PAST, IN_THE_FUTURE, False, False),
(IN_THE_PAST, IN_THE_PAST, True, True),
(IN_THE_PAST, IN_THE_PAST, False, True),
(IN_THE_FUTURE, IN_THE_FUTURE, True, True),
(IN_THE_FUTURE, IN_THE_FUTURE, False, False),
(IN_THE_FUTURE, IN_THE_PAST, True, True),
(IN_THE_FUTURE, IN_THE_PAST, False, True),
],
)
def test_is_assessment_active_validation(
mocker,
flask_test_client,
datetime_offset,
deadline,
assessment_start,
show_live_rounds_flag,
truthy_result,
):
Expand All @@ -443,12 +461,10 @@ def test_is_assessment_active_validation(
)
mocker.patch(
"app.blueprints.authentication.validation.get_round",
return_value=MagicMock(
deadline=(datetime.now() + timedelta(days=datetime_offset)).strftime("%Y-%m-%dT%H:%M:%S")
),
return_value=MagicMock(deadline=deadline, assessment_start=assessment_start),
)

result = is_assessment_active("test_fund_id", "test_round_id")
result = has_assessment_opened("test_fund_id", "test_round_id")
assert result == truthy_result


Expand All @@ -460,6 +476,10 @@ def test_check_access_application_id_decorator_returns_403_for_inactive_assessme
"app.blueprints.authentication.validation.get_value_from_request",
return_value="test",
)
mocker.patch(
"app.blueprints.authentication.validation.has_assessment_opened",
return_value=False,
)
mocker.patch(
"app.blueprints.authentication.validation.Config.FORCE_OPEN_ALL_LIVE_ASSESSMENT_ROUNDS",
new=False,
Expand Down

0 comments on commit cab975b

Please sign in to comment.