diff --git a/its_on/admin/utils.py b/its_on/admin/utils.py index 5f1636c..b70d64a 100644 --- a/its_on/admin/utils.py +++ b/its_on/admin/utils.py @@ -1,4 +1,5 @@ -from typing import List +import datetime +from typing import List, Dict from aiohttp import web from aiopg.sa.result import RowProxy @@ -51,3 +52,11 @@ async def get_switch_history(request: web.Request, switch: switches) -> List[Row ).order_by(switch_history.c.changed_at.desc()) result = await conn.execute(query) return await result.fetchall() + + +def annotate_switch_with_expiration_date(switch: switches) -> Dict: + if switch.is_active: + expires_at = switch.updated_at + datetime.timedelta(days=switch.ttl) + else: + expires_at = None + return {**dict(switch), 'expires_at': expires_at} diff --git a/its_on/admin/views/switches.py b/its_on/admin/views/switches.py index 99bc7ba..578c5a8 100644 --- a/its_on/admin/views/switches.py +++ b/its_on/admin/views/switches.py @@ -1,4 +1,5 @@ import datetime +from typing import Any, Dict, List, Optional, Union import aiohttp_jinja2 import psycopg2 @@ -9,7 +10,6 @@ from marshmallow.exceptions import ValidationError from multidict import MultiDictProxy from sqlalchemy.sql import Select -from typing import Any, Dict, List, Optional, Union from auth.decorators import login_required from its_on.admin.mixins import CreateMixin, GetObjectMixin, UpdateMixin @@ -20,7 +20,11 @@ SwitchDetailAdminPostRequestSchema, SwitchListAdminRequestSchema, ) -from its_on.admin.utils import get_switch_history, save_switch_history +from its_on.admin.utils import ( + annotate_switch_with_expiration_date, + get_switch_history, + save_switch_history, +) from its_on.models import switches from its_on.schemes import RemoteSwitchesDataSchema from its_on.utils import get_switch_badge_svg, get_switch_markdown_badge, utc_now @@ -35,26 +39,21 @@ class SwitchListAdminView(web.View): async def get(self) -> Dict[str, Union[Optional[List[RowProxy]], bool]]: request_params = self.validator.load(data=self.request.query) flags = await self.get_response_data(request_params) - # Move to dict because it's Raw - flag_dicts = [] - for flag in flags: - flag_dicts.append({ - **dict(flag), - 'estimate_at': flag.created_at + datetime.timedelta(days=flag.ttl), - }) groups = await self.get_distinct_groups(request_params) return { 'active_group': request_params.get('group'), - 'flags': flag_dicts, + 'flags': flags, 'groups': groups, 'show_copy_button': bool(settings.SYNC_FROM_ITS_ON_URL), } - async def get_response_data(self, request_params: Dict[str, Any]) -> List: + async def get_response_data(self, request_params: Dict[str, Any]) -> List[Dict]: async with self.request.app['db'].acquire() as conn: queryset = self.filter_queryset(self.get_queryset(), request_params) result = await conn.execute(queryset) - return await result.fetchall() + flags = await result.fetchall() + + return [annotate_switch_with_expiration_date(switch=flag) for flag in flags] async def get_distinct_groups(self, request_params: Dict[str, Any]) -> List[str]: async with self.request.app['db'].acquire() as conn: diff --git a/its_on/templates/switches/index.html b/its_on/templates/switches/index.html index d64eeef..2494fbf 100644 --- a/its_on/templates/switches/index.html +++ b/its_on/templates/switches/index.html @@ -47,7 +47,7 @@

Switches list

TTL Created at Updated at - Estimated at + Expires at Deleted at @@ -83,8 +83,8 @@

Switches list

{% endif %} - {% if flag.estimate_at %} - {{ flag.estimate_at.strftime('%Y-%m-%d') }} + {% if flag.expires_at %} + {{ flag.expires_at.strftime('%Y-%m-%d') }} {% else %} - {% endif %} diff --git a/tests/test_utils.py b/tests/test_utils.py index f3393c4..a27eee5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -4,6 +4,7 @@ from aiohttp.test_utils import make_mocked_request from anybadge import Badge +from its_on.admin.utils import annotate_switch_with_expiration_date from its_on.constants import ( SVG_BADGE_BACKGROUND_COLOR, SWITCH_NOT_FOUND_SVG_BADGE_PREFIX, @@ -164,3 +165,48 @@ async def test_get_switch_markdown_badge(switch_factory, client): markdown_badge = get_switch_markdown_badge(request, switch) assert markdown_badge == expected_badge + + +@pytest.mark.parametrize( + ('name', 'is_active', 'ttl', 'updated_at', 'expected_result'), + [ + ( + 'inactive_switch', + False, + 14, + datetime.datetime(2020, 5, 1), + None, + ), + ( + 'active_switch', + True, + 14, + datetime.datetime(2020, 5, 1), + datetime.date(2020, 5, 15), + ), + ( + 'other_active_switch', + True, + 21, + datetime.datetime(2020, 5, 5), + datetime.date(2020, 5, 26), + ), + ], +) +@pytest.mark.usefixtures('setup_tables_and_data') +@pytest.mark.freeze_time(datetime.datetime(2020, 5, 1, tzinfo=datetime.timezone.utc)) +async def test_annotate_flag_with_expiration_date( + switch_factory, name, is_active, ttl, updated_at, expected_result, +): + switch = await switch_factory( + name=name, + is_active=is_active, + groups=('backend',), + ttl=ttl, + updated_at=updated_at, + deleted_at=None, + ) + + result = annotate_switch_with_expiration_date(switch=switch) + + assert (result['expires_at'] and result['expires_at'].date()) == expected_result