feat: move timezone preference to config file (#2096)
BREAKING CHANGE: The timezone preference moved to the configuration file.
This commit is contained in:
parent
8ef82d798e
commit
9b3207b8a4
|
@ -6,7 +6,6 @@ ANALYZE "cc_pref";
|
||||||
INSERT INTO cc_live_log ("state", "start_time") VALUES ('S', now() at time zone 'UTC');
|
INSERT INTO cc_live_log ("state", "start_time") VALUES ('S', now() at time zone 'UTC');
|
||||||
|
|
||||||
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('import_timestamp', '0');
|
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('import_timestamp', '0');
|
||||||
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('timezone', 'UTC');
|
|
||||||
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('off_air_meta', 'LibreTime - offline');
|
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('off_air_meta', 'LibreTime - offline');
|
||||||
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('enable_replay_gain', 1);
|
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('enable_replay_gain', 1);
|
||||||
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('locale', 'en_US');
|
INSERT INTO cc_pref ("keystr", "valstr") VALUES ('locale', 'en_US');
|
||||||
|
|
|
@ -13,6 +13,11 @@ general:
|
||||||
# > default is []
|
# > default is []
|
||||||
allowed_cors_origins: []
|
allowed_cors_origins: []
|
||||||
|
|
||||||
|
# The server timezone, should be a lookup key in the IANA time zone database,
|
||||||
|
# for example Europe/Berlin.
|
||||||
|
# > default is UTC
|
||||||
|
timezone: UTC
|
||||||
|
|
||||||
# How many hours ahead Playout should cache scheduled media files.
|
# How many hours ahead Playout should cache scheduled media files.
|
||||||
# > default is 1
|
# > default is 1
|
||||||
cache_ahead_hours: 1
|
cache_ahead_hours: 1
|
||||||
|
|
|
@ -13,6 +13,11 @@ general:
|
||||||
# > default is []
|
# > default is []
|
||||||
allowed_cors_origins: []
|
allowed_cors_origins: []
|
||||||
|
|
||||||
|
# The server timezone, should be a lookup key in the IANA time zone database,
|
||||||
|
# for example Europe/Berlin.
|
||||||
|
# > default is UTC
|
||||||
|
timezone: UTC
|
||||||
|
|
||||||
# How many hours ahead Playout should cache scheduled media files.
|
# How many hours ahead Playout should cache scheduled media files.
|
||||||
# > default is 1
|
# > default is 1
|
||||||
cache_ahead_hours: 1
|
cache_ahead_hours: 1
|
||||||
|
|
|
@ -29,6 +29,11 @@ general:
|
||||||
# > default is []
|
# > default is []
|
||||||
allowed_cors_origins: []
|
allowed_cors_origins: []
|
||||||
|
|
||||||
|
# The server timezone, should be a lookup key in the IANA time zone database,
|
||||||
|
# for example Europe/Berlin.
|
||||||
|
# > default is UTC
|
||||||
|
timezone: UTC
|
||||||
|
|
||||||
# How many hours ahead Playout should cache scheduled media files.
|
# How many hours ahead Playout should cache scheduled media files.
|
||||||
# > default is 1
|
# > default is 1
|
||||||
cache_ahead_hours: 1
|
cache_ahead_hours: 1
|
||||||
|
|
|
@ -74,6 +74,20 @@ sudo -u libretime libretime-api dbshell --command="
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
### Timezone configuration
|
||||||
|
|
||||||
|
The timezone preference moved from the database to the [configuration](../admin-manual/setup/configuration.md#general) file. Make sure to save your existing timezone preference to the configuration file.
|
||||||
|
|
||||||
|
:::info
|
||||||
|
|
||||||
|
To prevent accidental data loss during upgrade, the timezone preference will only be removed from the database in future releases. You can view the data using the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo -u libretime libretime-api dbshell --command="SELECT * FROM cc_pref WHERE keystr = 'timezone'";
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
## :arrow_up: Upgrading
|
## :arrow_up: Upgrading
|
||||||
|
|
||||||
### Worker python package and service
|
### Worker python package and service
|
||||||
|
|
|
@ -13,6 +13,11 @@ general:
|
||||||
# > default is []
|
# > default is []
|
||||||
allowed_cors_origins: []
|
allowed_cors_origins: []
|
||||||
|
|
||||||
|
# The server timezone, should be a lookup key in the IANA time zone database,
|
||||||
|
# for example Europe/Berlin.
|
||||||
|
# > default is UTC
|
||||||
|
timezone: UTC
|
||||||
|
|
||||||
# How many hours ahead Playout should cache scheduled media files.
|
# How many hours ahead Playout should cache scheduled media files.
|
||||||
# > default is 1
|
# > default is 1
|
||||||
cache_ahead_hours: 1
|
cache_ahead_hours: 1
|
||||||
|
|
|
@ -36,6 +36,11 @@ class Schema implements ConfigurationInterface
|
||||||
/**/->scalarNode('public_url')->cannotBeEmpty()->end()
|
/**/->scalarNode('public_url')->cannotBeEmpty()->end()
|
||||||
/**/->scalarNode('api_key')->cannotBeEmpty()->end()
|
/**/->scalarNode('api_key')->cannotBeEmpty()->end()
|
||||||
/**/->arrayNode('allowed_cors_origins')->scalarPrototype()->defaultValue([])->end()->end()
|
/**/->arrayNode('allowed_cors_origins')->scalarPrototype()->defaultValue([])->end()->end()
|
||||||
|
/**/->scalarNode('timezone')->cannotBeEmpty()->defaultValue("UTC")
|
||||||
|
/* */->validate()->ifNotInArray(DateTimeZone::listIdentifiers())
|
||||||
|
/* */->thenInvalid('invalid general.timezone %s')
|
||||||
|
/* */->end()
|
||||||
|
/**/->end()
|
||||||
/**/->scalarNode('dev_env')->defaultValue('production')->end()
|
/**/->scalarNode('dev_env')->defaultValue('production')->end()
|
||||||
/**/->scalarNode('auth')->defaultValue('local')->end()
|
/**/->scalarNode('auth')->defaultValue('local')->end()
|
||||||
/**/->integerNode('cache_ahead_hours')->defaultValue(1)->end()
|
/**/->integerNode('cache_ahead_hours')->defaultValue(1)->end()
|
||||||
|
|
|
@ -50,7 +50,6 @@ class PreferenceController extends Zend_Controller_Action
|
||||||
Application_Model_Preference::SetAllow3rdPartyApi($values['thirdPartyApi']);
|
Application_Model_Preference::SetAllow3rdPartyApi($values['thirdPartyApi']);
|
||||||
Application_Model_Preference::SetAllowedCorsUrls($values['allowedCorsUrls']);
|
Application_Model_Preference::SetAllowedCorsUrls($values['allowedCorsUrls']);
|
||||||
Application_Model_Preference::SetDefaultLocale($values['locale']);
|
Application_Model_Preference::SetDefaultLocale($values['locale']);
|
||||||
Application_Model_Preference::SetDefaultTimezone($values['timezone']);
|
|
||||||
Application_Model_Preference::SetWeekStartDay($values['weekStartDay']);
|
Application_Model_Preference::SetWeekStartDay($values['weekStartDay']);
|
||||||
Application_Model_Preference::setRadioPageDisplayLoginButton($values['radioPageLoginButton']);
|
Application_Model_Preference::setRadioPageDisplayLoginButton($values['radioPageLoginButton']);
|
||||||
Application_Model_Preference::SetFeaturePreviewMode($values['featurePreviewMode']);
|
Application_Model_Preference::SetFeaturePreviewMode($values['featurePreviewMode']);
|
||||||
|
|
|
@ -25,7 +25,6 @@ class SetupController extends Zend_Controller_Action
|
||||||
$currentUserId = $currentUser->getDbId();
|
$currentUserId = $currentUser->getDbId();
|
||||||
|
|
||||||
Application_Model_Preference::SetUserTimezone($formData['setup_timezone'], $currentUserId);
|
Application_Model_Preference::SetUserTimezone($formData['setup_timezone'], $currentUserId);
|
||||||
Application_Model_Preference::SetDefaultTimezone($formData['setup_timezone']);
|
|
||||||
|
|
||||||
Application_Model_Preference::SetUserLocale($formData['setup_language'], $currentUserId);
|
Application_Model_Preference::SetUserLocale($formData['setup_language'], $currentUserId);
|
||||||
Application_Model_Preference::SetDefaultLocale($formData['setup_language']);
|
Application_Model_Preference::SetDefaultLocale($formData['setup_language']);
|
||||||
|
|
|
@ -187,6 +187,7 @@ class Application_Form_GeneralPreferences extends Zend_Form_SubForm
|
||||||
// Form Element for setting the Timezone
|
// Form Element for setting the Timezone
|
||||||
$timezone = new Zend_Form_Element_Select('timezone');
|
$timezone = new Zend_Form_Element_Select('timezone');
|
||||||
$timezone->setLabel(_('Station Timezone'));
|
$timezone->setLabel(_('Station Timezone'));
|
||||||
|
$timezone->setAttrib('disabled', 'true');
|
||||||
$timezone->setMultiOptions(Application_Common_Timezone::getTimezones());
|
$timezone->setMultiOptions(Application_Common_Timezone::getTimezones());
|
||||||
$timezone->setValue(Application_Model_Preference::GetDefaultTimezone());
|
$timezone->setValue(Application_Model_Preference::GetDefaultTimezone());
|
||||||
$this->addElement($timezone);
|
$this->addElement($timezone);
|
||||||
|
|
|
@ -536,21 +536,10 @@ class Application_Model_Preference
|
||||||
return sprintf(_('Powered by %s'), SAAS_PRODUCT_BRANDING_NAME);
|
return sprintf(_('Powered by %s'), SAAS_PRODUCT_BRANDING_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets station default timezone (from preferences)
|
|
||||||
public static function SetDefaultTimezone($timezone)
|
|
||||||
{
|
|
||||||
self::setValue('timezone', $timezone);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns station default timezone (from preferences)
|
// Returns station default timezone (from preferences)
|
||||||
public static function GetDefaultTimezone()
|
public static function GetDefaultTimezone()
|
||||||
{
|
{
|
||||||
$stationTimezone = self::getValue('timezone');
|
return Config::get('general.timezone');
|
||||||
if (is_null($stationTimezone) || $stationTimezone == '') {
|
|
||||||
$stationTimezone = 'UTC';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $stationTimezone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function SetUserTimezone($timezone = null)
|
public static function SetUserTimezone($timezone = null)
|
||||||
|
|
|
@ -5,6 +5,11 @@ from typing import TYPE_CHECKING, Any, List, Optional, Sequence, Union
|
||||||
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, validator
|
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, validator
|
||||||
from typing_extensions import Annotated, Literal
|
from typing_extensions import Annotated, Literal
|
||||||
|
|
||||||
|
try:
|
||||||
|
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||||
|
except ImportError:
|
||||||
|
from backports.zoneinfo import ZoneInfo, ZoneInfoNotFoundError # type: ignore
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from pydantic.typing import AnyClassMethod
|
from pydantic.typing import AnyClassMethod
|
||||||
|
|
||||||
|
@ -38,9 +43,21 @@ class GeneralConfig(BaseModel):
|
||||||
public_url: AnyHttpUrl
|
public_url: AnyHttpUrl
|
||||||
api_key: str
|
api_key: str
|
||||||
|
|
||||||
|
timezone: str = "UTC"
|
||||||
|
|
||||||
# Validators
|
# Validators
|
||||||
_public_url_no_trailing_slash = no_trailing_slash_validator("public_url")
|
_public_url_no_trailing_slash = no_trailing_slash_validator("public_url")
|
||||||
|
|
||||||
|
@validator("timezone")
|
||||||
|
@classmethod
|
||||||
|
def _validate_timezone(cls, value: str) -> str:
|
||||||
|
try:
|
||||||
|
ZoneInfo(value)
|
||||||
|
except ZoneInfoNotFoundError as exception:
|
||||||
|
raise ValueError(f"invalid timezone '{value}'") from exception
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
# StorageConfig
|
# StorageConfig
|
||||||
########################################################################################
|
########################################################################################
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# Please do not edit this file, edit the setup.py file!
|
# Please do not edit this file, edit the setup.py file!
|
||||||
# This file is auto-generated by tools/extract_requirements.py.
|
# This file is auto-generated by tools/extract_requirements.py.
|
||||||
|
backports.zoneinfo>=0.2.1,<0.3;python_version<'3.9'
|
||||||
click~=8.0.4
|
click~=8.0.4
|
||||||
loguru==0.6.0
|
loguru==0.6.0
|
||||||
pydantic>=1.7.4,<1.11
|
pydantic>=1.7.4,<1.11
|
||||||
|
|
|
@ -10,6 +10,7 @@ setup(
|
||||||
packages=find_packages(exclude=["*tests*", "*fixtures*"]),
|
packages=find_packages(exclude=["*tests*", "*fixtures*"]),
|
||||||
package_data={"": ["py.typed"]},
|
package_data={"": ["py.typed"]},
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
"backports.zoneinfo>=0.2.1,<0.3;python_version<'3.9'",
|
||||||
"click~=8.0.4",
|
"click~=8.0.4",
|
||||||
"loguru==0.6.0",
|
"loguru==0.6.0",
|
||||||
"pydantic>=1.7.4,<1.11",
|
"pydantic>=1.7.4,<1.11",
|
||||||
|
@ -17,6 +18,7 @@ setup(
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
"dev": [
|
"dev": [
|
||||||
|
"types-backports",
|
||||||
"types-pyyaml",
|
"types-pyyaml",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,10 +6,22 @@ from libretime_shared.config._models import (
|
||||||
AudioMP3,
|
AudioMP3,
|
||||||
AudioOGG,
|
AudioOGG,
|
||||||
AudioOpus,
|
AudioOpus,
|
||||||
|
GeneralConfig,
|
||||||
StreamConfig,
|
StreamConfig,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_general_config_timezone():
|
||||||
|
defaults = {
|
||||||
|
"public_url": "http://localhost:8080",
|
||||||
|
"api_key": "api_key",
|
||||||
|
}
|
||||||
|
GeneralConfig(**defaults, timezone="UTC")
|
||||||
|
GeneralConfig(**defaults, timezone="Europe/Berlin")
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
GeneralConfig(**defaults, timezone="Europe/Invalid")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"audio",
|
"audio",
|
||||||
[
|
[
|
||||||
|
|
Loading…
Reference in New Issue