From d392153fcc1cacdbce300a11e7022ddafb516d10 Mon Sep 17 00:00:00 2001 From: Tim DiLauro Date: Mon, 4 Nov 2024 09:10:57 -0500 Subject: [PATCH 1/4] Add configuration settings for collections subscriptions. --- src/palace/manager/api/circulation.py | 27 ++++++++++++++++++++++ src/palace/manager/integration/settings.py | 1 + tests/manager/api/admin/test_form_data.py | 20 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/src/palace/manager/api/circulation.py b/src/palace/manager/api/circulation.py index d33bf41362..605419c771 100644 --- a/src/palace/manager/api/circulation.py +++ b/src/palace/manager/api/circulation.py @@ -564,6 +564,33 @@ class BaseCirculationApiSettings(BaseSettings): ) } + subscription_activation_date: str | None = FormField( + default=None, + form=ConfigurationFormItem( + label=_("Collection Subscription Activation Date"), + type=ConfigurationFormItemType.DATE, + description=( + "A date before which this collection is considered inactive. Associated libraries" + " will not be considered to be subscribed until this date). If not specified," + " it will not restrict any associated library's subscription status." + ), + required=False, + ), + ) + subscription_expiration_date: str | None = FormField( + default=None, + form=ConfigurationFormItem( + label=_("Collection Subscription Expiration Date"), + type=ConfigurationFormItemType.DATE, + description=( + "A date after which this collection is considered inactive. Associated libraries" + " will not be considered to be subscribed beyond this date). If not specified," + " it will not restrict any associated library's subscription status." + ), + required=False, + ), + ) + SettingsType = TypeVar("SettingsType", bound=BaseCirculationApiSettings, covariant=True) LibrarySettingsType = TypeVar("LibrarySettingsType", bound=BaseSettings, covariant=True) diff --git a/src/palace/manager/integration/settings.py b/src/palace/manager/integration/settings.py index 3e6f1ec8ec..38c8494ebd 100644 --- a/src/palace/manager/integration/settings.py +++ b/src/palace/manager/integration/settings.py @@ -178,6 +178,7 @@ class ConfigurationFormItemType(Enum): """Enumeration of configuration setting types""" TEXT = None + DATE = "date-picker" TEXTAREA = "textarea" SELECT = "select" LIST = "list" diff --git a/tests/manager/api/admin/test_form_data.py b/tests/manager/api/admin/test_form_data.py index ada73e4f9e..1c1a020232 100644 --- a/tests/manager/api/admin/test_form_data.py +++ b/tests/manager/api/admin/test_form_data.py @@ -30,6 +30,22 @@ class MockSettings(BaseSettings): label="Field 3", ), ) + field4: str | None = FormField( + None, + form=ConfigurationFormItem( + label="Date field", + type=ConfigurationFormItemType.DATE, + description="A date.", + ), + ) + field5: str | None = FormField( + None, + form=ConfigurationFormItem( + label="Another date field", + type=ConfigurationFormItemType.DATE, + description="Another date.", + ), + ) def test_get_settings(): @@ -41,9 +57,13 @@ def test_get_settings(): ("field2_value3", "blah blah"), ("field2_value4", "blah blah blah"), ("field3", "value5"), + ("field4", "2024-10-23"), + ("field5", ""), ] ) settings = ProcessFormData.get_settings(MockSettings, data) assert settings.field1 == ["value1", "value2"] assert settings.field2 == ["value3", "value4"] assert settings.field3 == "value5" + assert settings.field4 == "2024-10-23" + assert settings.field5 is None From b79d98c6cb957f6da2dee07fb5e1750e0275640d Mon Sep 17 00:00:00 2001 From: Tim DiLauro Date: Fri, 13 Dec 2024 14:08:41 -0500 Subject: [PATCH 2/4] Use `datetime`, instead of string, for subscription dates. --- .pre-commit-config.yaml | 3 +++ src/palace/manager/api/circulation.py | 8 +++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 304a3c440c..99dd3f0f8c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,6 +20,9 @@ repos: rev: v3.17.0 hooks: - id: pyupgrade + # TODO: Remove when Pydantic supports `datetime.date | None` type annotation. + # Otherwise, `pyupgrade` will rewrite from `Optional[datetime.date]`. + exclude: ^src/palace/manager/api/circulation.py args: - --py310-plus diff --git a/src/palace/manager/api/circulation.py b/src/palace/manager/api/circulation.py index 605419c771..6952e080e9 100644 --- a/src/palace/manager/api/circulation.py +++ b/src/palace/manager/api/circulation.py @@ -5,7 +5,7 @@ import logging from abc import ABC, abstractmethod from collections.abc import Iterable, Mapping -from typing import Literal, TypeVar +from typing import Literal, Optional, TypeVar import flask import requests @@ -564,7 +564,9 @@ class BaseCirculationApiSettings(BaseSettings): ) } - subscription_activation_date: str | None = FormField( + # TODO: Using `Optional[datetime.date]` here because Pydantic does not + # currently handle the annotation of `datetime.date | None` properly. + subscription_activation_date: Optional[datetime.date] = FormField( default=None, form=ConfigurationFormItem( label=_("Collection Subscription Activation Date"), @@ -577,7 +579,7 @@ class BaseCirculationApiSettings(BaseSettings): required=False, ), ) - subscription_expiration_date: str | None = FormField( + subscription_expiration_date: Optional[datetime.date] = FormField( default=None, form=ConfigurationFormItem( label=_("Collection Subscription Expiration Date"), From f4948a7dfa24098496a59e52a7d3d9c5c3ff0ad1 Mon Sep 17 00:00:00 2001 From: Tim DiLauro Date: Thu, 16 Jan 2025 11:07:50 -0500 Subject: [PATCH 3/4] Code review feedback. --- .pre-commit-config.yaml | 3 --- src/palace/manager/api/circulation.py | 8 +++----- tests/manager/api/admin/test_form_data.py | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 99dd3f0f8c..304a3c440c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,9 +20,6 @@ repos: rev: v3.17.0 hooks: - id: pyupgrade - # TODO: Remove when Pydantic supports `datetime.date | None` type annotation. - # Otherwise, `pyupgrade` will rewrite from `Optional[datetime.date]`. - exclude: ^src/palace/manager/api/circulation.py args: - --py310-plus diff --git a/src/palace/manager/api/circulation.py b/src/palace/manager/api/circulation.py index 6952e080e9..f15eabffa7 100644 --- a/src/palace/manager/api/circulation.py +++ b/src/palace/manager/api/circulation.py @@ -5,7 +5,7 @@ import logging from abc import ABC, abstractmethod from collections.abc import Iterable, Mapping -from typing import Literal, Optional, TypeVar +from typing import Literal, TypeVar import flask import requests @@ -564,9 +564,7 @@ class BaseCirculationApiSettings(BaseSettings): ) } - # TODO: Using `Optional[datetime.date]` here because Pydantic does not - # currently handle the annotation of `datetime.date | None` properly. - subscription_activation_date: Optional[datetime.date] = FormField( + subscription_activation_date: datetime.date | None = FormField( default=None, form=ConfigurationFormItem( label=_("Collection Subscription Activation Date"), @@ -579,7 +577,7 @@ class BaseCirculationApiSettings(BaseSettings): required=False, ), ) - subscription_expiration_date: Optional[datetime.date] = FormField( + subscription_expiration_date: datetime.date | None = FormField( default=None, form=ConfigurationFormItem( label=_("Collection Subscription Expiration Date"), diff --git a/tests/manager/api/admin/test_form_data.py b/tests/manager/api/admin/test_form_data.py index 1c1a020232..d4a8ad2201 100644 --- a/tests/manager/api/admin/test_form_data.py +++ b/tests/manager/api/admin/test_form_data.py @@ -1,3 +1,5 @@ +import datetime + from werkzeug.datastructures import ImmutableMultiDict from palace.manager.api.admin.form_data import ProcessFormData @@ -46,6 +48,22 @@ class MockSettings(BaseSettings): description="Another date.", ), ) + field6: datetime.date | None = FormField( + None, + form=ConfigurationFormItem( + label="Another date field with a date type", + type=ConfigurationFormItemType.DATE, + description="A python date.", + ), + ) + field7: datetime.date | None = FormField( + None, + form=ConfigurationFormItem( + label="Another date field with a date type", + type=ConfigurationFormItemType.DATE, + description="A python date.", + ), + ) def test_get_settings(): @@ -59,6 +77,8 @@ def test_get_settings(): ("field3", "value5"), ("field4", "2024-10-23"), ("field5", ""), + ("field6", "2024-10-23"), + ("field7", ""), ] ) settings = ProcessFormData.get_settings(MockSettings, data) @@ -67,3 +87,5 @@ def test_get_settings(): assert settings.field3 == "value5" assert settings.field4 == "2024-10-23" assert settings.field5 is None + assert settings.field6 == datetime.date(2024, 10, 23) + assert settings.field7 is None From 83e1fcb49f51fc6f0610a28be3e4ad2f115add2b Mon Sep 17 00:00:00 2001 From: Tim DiLauro Date: Thu, 16 Jan 2025 11:29:00 -0500 Subject: [PATCH 4/4] Clean out obsolete test cases. --- tests/manager/api/admin/test_form_data.py | 26 +++-------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/tests/manager/api/admin/test_form_data.py b/tests/manager/api/admin/test_form_data.py index d4a8ad2201..9edd845ba4 100644 --- a/tests/manager/api/admin/test_form_data.py +++ b/tests/manager/api/admin/test_form_data.py @@ -32,23 +32,7 @@ class MockSettings(BaseSettings): label="Field 3", ), ) - field4: str | None = FormField( - None, - form=ConfigurationFormItem( - label="Date field", - type=ConfigurationFormItemType.DATE, - description="A date.", - ), - ) - field5: str | None = FormField( - None, - form=ConfigurationFormItem( - label="Another date field", - type=ConfigurationFormItemType.DATE, - description="Another date.", - ), - ) - field6: datetime.date | None = FormField( + field4: datetime.date | None = FormField( None, form=ConfigurationFormItem( label="Another date field with a date type", @@ -56,7 +40,7 @@ class MockSettings(BaseSettings): description="A python date.", ), ) - field7: datetime.date | None = FormField( + field5: datetime.date | None = FormField( None, form=ConfigurationFormItem( label="Another date field with a date type", @@ -77,15 +61,11 @@ def test_get_settings(): ("field3", "value5"), ("field4", "2024-10-23"), ("field5", ""), - ("field6", "2024-10-23"), - ("field7", ""), ] ) settings = ProcessFormData.get_settings(MockSettings, data) assert settings.field1 == ["value1", "value2"] assert settings.field2 == ["value3", "value4"] assert settings.field3 == "value5" - assert settings.field4 == "2024-10-23" + assert settings.field4 == datetime.date(2024, 10, 23) assert settings.field5 is None - assert settings.field6 == datetime.date(2024, 10, 23) - assert settings.field7 is None