config_defaults.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. """
  2. Our configuration requirements and defaults
  3. This can be adjusted per environment here.
  4. Anything confidential should be handled outside of source control (e.g. a SECRET KEY file is generated on first install,
  5. and confidential settings can be set via the <app-env>-conf.py file.
  6. """
  7. from __future__ import annotations
  8. from datetime import timedelta
  9. import logging
  10. class Config(object):
  11. """
  12. If there is a useful default value, set it here.
  13. Otherwise, set to None, so that it can be set either by subclasses or the env-specific config script.
  14. """
  15. DEBUG: bool = False
  16. LOGGING_LEVEL: int = logging.WARNING
  17. SECRET_KEY: str | None = None
  18. FLEXMEASURES_ENV_DEFAULT = "production"
  19. SQLALCHEMY_DATABASE_URI: str | None = None
  20. # https://stackoverflow.com/questions/33738467/how-do-i-know-if-i-can-disable-sqlalchemy-track-modifications
  21. SQLALCHEMY_TRACK_MODIFICATIONS: bool = False
  22. SQLALCHEMY_ENGINE_OPTIONS: dict = {
  23. "pool_recycle": 299, # https://www.pythonanywhere.com/forums/topic/2599/
  24. "pool_size": 5, # 5 is SQLAlchemy's default for the maximum number of permanent connections to keep
  25. "max_overflow": 10, # 10 is SQLAlchemy's default for temporarily exceeding the pool_size if no connections are available
  26. # "pool_timeout": 20,
  27. "pool_pre_ping": True, # https://docs.sqlalchemy.org/en/13/core/pooling.html#disconnect-handling-pessimistic
  28. "connect_args": {
  29. "options": "-c timezone=utc"
  30. }, # https://stackoverflow.com/a/59932909/13775459
  31. }
  32. MAIL_SERVER: str | None = "localhost"
  33. MAIL_PORT: int | None = 25
  34. MAIL_USE_TLS: bool | None = False
  35. MAIL_USE_SSL: bool | None = False
  36. MAIL_USERNAME: str | None = None
  37. MAIL_DEFAULT_SENDER = (
  38. "FlexMeasures",
  39. "no-reply@example.com",
  40. ) # tuple of name and email address
  41. MAIL_PASSWORD: str | None = None
  42. SECURITY_REGISTERABLE: bool = False
  43. SECURITY_LOGIN_USER_TEMPLATE: str = "admin/login_user.html"
  44. SECURITY_EMAIL_SUBJECT_PASSWORD_RESET: str = (
  45. "Password reset instructions for your FlexMeasures account."
  46. )
  47. SECURITY_EMAIL_SUBJECT_PASSWORD_NOTICE: str = (
  48. "Your FlexMeasures password has been reset."
  49. )
  50. SECURITY_FORGOT_PASSWORD_TEMPLATE: str = "admin/forgot_password.html"
  51. SECURITY_RECOVERABLE: bool = True
  52. SECURITY_RESET_PASSWORD_TEMPLATE: str = "admin/reset_password.html"
  53. SECURITY_TOKEN_AUTHENTICATION_HEADER: str = "Authorization"
  54. SECURITY_TOKEN_MAX_AGE: int = 60 * 60 * 6 # six hours
  55. SECURITY_TRACKABLE: bool = False # this is more in line with modern privacy law
  56. SECURITY_PASSWORD_SALT: str | None = None
  57. # Allowed cross-origins. Set to "*" to allow all. For development (e.g. javascript on localhost) you might use "null" here
  58. CORS_ORIGINS: list[str] | str = []
  59. # this can be a dict with all possible options as value per regex, see https://flask-cors.readthedocs.io/en/latest/configuration.html
  60. CORS_RESOURCES: dict | list | str = [r"/api/*"]
  61. CORS_SUPPORTS_CREDENTIALS: bool = True
  62. MAPBOX_ACCESS_TOKEN: str | None = None
  63. RQ_DASHBOARD_POLL_INTERVAL: int = (
  64. 3000 # Web interface poll period for updates in ms
  65. )
  66. SENTRY_DSN: str | None = None
  67. # Place additional Sentry config here.
  68. # traces_sample_rate is for performance monitoring across all transactions,
  69. # you probably want to adjust this.
  70. FLEXMEASURES_SENTRY_CONFIG: dict = dict(traces_sample_rate=0.33)
  71. FLEXMEASURES_MONITORING_MAIL_RECIPIENTS: list[str] = []
  72. FLEXMEASURES_PLATFORM_NAME: str | list[str | tuple[str, list[str]]] = "FlexMeasures"
  73. FLEXMEASURES_MODE: str = ""
  74. FLEXMEASURES_ALLOW_DATA_OVERWRITE: bool = False
  75. FLEXMEASURES_TIMEZONE: str = "Asia/Seoul"
  76. FLEXMEASURES_HIDE_NAN_IN_UI: bool = False
  77. FLEXMEASURES_PUBLIC_DEMO_CREDENTIALS: tuple | None = None
  78. # Configuration used for entity addressing:
  79. # This setting contains the domain on which FlexMeasures runs
  80. # and the first month when the domain was under the current owner's administration
  81. FLEXMEASURES_HOSTS_AND_AUTH_START: dict[str, str] = {"flexmeasures.io": "2021-01"}
  82. FLEXMEASURES_PLUGINS: list[str] | str = [] # str will be checked for commas
  83. FLEXMEASURES_PROFILE_REQUESTS: bool = False
  84. FLEXMEASURES_DB_BACKUP_PATH: str = "migrations/dumps"
  85. FLEXMEASURES_MENU_LOGO_PATH: str = ""
  86. FLEXMEASURES_EXTRA_CSS_PATH: str = ""
  87. FLEXMEASURES_ROOT_VIEW: str | list[str | tuple[str, list[str]]] = []
  88. FLEXMEASURES_MENU_LISTED_VIEWS: list[str | tuple[str, list[str]]] = [
  89. "dashboard",
  90. ]
  91. FLEXMEASURES_MENU_LISTED_VIEW_ICONS: dict[str, str] = {}
  92. FLEXMEASURES_MENU_LISTED_VIEW_TITLES: dict[str, str] = {}
  93. FLEXMEASURES_ASSET_TYPE_GROUPS = {
  94. "renewables": ["solar", "wind"],
  95. "EVSE": ["one-way_evse", "two-way_evse"],
  96. } # how to group assets by asset types
  97. FLEXMEASURES_LP_SOLVER: str = "appsi_highs"
  98. FLEXMEASURES_JOB_TTL: timedelta = timedelta(days=1)
  99. FLEXMEASURES_PLANNING_HORIZON: timedelta = timedelta(days=2)
  100. FLEXMEASURES_MAX_PLANNING_HORIZON: timedelta | int | None = (
  101. 2520 # smallest number divisible by 1-10, which yields pleasant-looking durations for common sensor resolutions
  102. )
  103. FLEXMEASURES_PLANNING_TTL: timedelta = timedelta(
  104. days=7
  105. ) # Time to live for UDI event ids of successful scheduling jobs. Set a negative timedelta to persist forever.
  106. FLEXMEASURES_DEFAULT_DATASOURCE: str = "FlexMeasures"
  107. FLEXMEASURES_JOB_CACHE_TTL: int = (
  108. 3600 # Time to live for the job caching keys in seconds. Set a negative timedelta to persist forever.
  109. )
  110. FLEXMEASURES_TASK_CHECK_AUTH_TOKEN: str | None = None
  111. FLEXMEASURES_REDIS_URL: str = "localhost"
  112. FLEXMEASURES_REDIS_PORT: int = 6379
  113. FLEXMEASURES_REDIS_DB_NR: int = 0 # Redis per default has 16 databases, [0-15]
  114. FLEXMEASURES_REDIS_PASSWORD: str | None = None
  115. FLEXMEASURES_JS_VERSIONS: dict = dict(
  116. vega="5.22.1",
  117. vegaembed="6.21.0",
  118. vegalite="5.5.0", # "5.6.0" has a problematic bar chart: see our sensor page and https://github.com/vega/vega-lite/issues/8496
  119. currencysymbolmap="5.1.0",
  120. leaflet="1.9.4",
  121. leafletmarkercluster="1.5.3",
  122. leafletmarkerclusterlayersupport="2.0.1",
  123. # todo: expand with other js versions used in FlexMeasures
  124. )
  125. FLEXMEASURES_JSON_COMPACT = False
  126. JSON_SORT_KEYS = False
  127. FLEXMEASURES_FALLBACK_REDIRECT: bool = False
  128. # Custom sunset switches
  129. FLEXMEASURES_API_SUNSET_ACTIVE: bool = (
  130. False # if True, sunset endpoints return 410 (Gone) responses; if False, they return 404 (Not Found) responses or will work as before, depending on whether the current FlexMeasures version still contains the endpoint logic
  131. )
  132. FLEXMEASURES_API_SUNSET_DATE: str | None = None # e.g. 2023-05-01
  133. FLEXMEASURES_API_SUNSET_LINK: str | None = (
  134. None # e.g. https://flexmeasures.readthedocs.io/en/latest/api/introduction.html#deprecation-and-sunset
  135. )
  136. # if True, all requests are forced to be via HTTPS.
  137. FLEXMEASURES_FORCE_HTTPS: bool = False
  138. # if True, the content could be accessed via HTTPS.
  139. FLEXMEASURES_ENFORCE_SECURE_CONTENT_POLICY: bool = False
  140. # names of settings which cannot be None
  141. # SECRET_KEY is also required but utils.app_utils.set_secret_key takes care of this better.
  142. required: list[str] = ["SQLALCHEMY_DATABASE_URI"]
  143. # settings whose absence should trigger a warning
  144. mail_warning = "Without complete mail settings, FlexMeasures will not be able to send mails to users, e.g. for password resets!"
  145. redis_warning = "Without complete redis connection settings, FlexMeasures will not be able to run forecasting and scheduling job queues."
  146. warnable: dict[str, str] = {
  147. "MAIL_SERVER": mail_warning,
  148. "MAIL_PORT": mail_warning,
  149. "MAIL_USE_TLS": mail_warning,
  150. "MAIL_USE_SSL": mail_warning,
  151. "MAIL_USERNAME": mail_warning,
  152. "MAIL_DEFAULT_SENDER": mail_warning,
  153. "MAIL_PASSWORD": mail_warning,
  154. "FLEXMEASURES_REDIS_URL": redis_warning,
  155. "FLEXMEASURES_REDIS_PORT": redis_warning,
  156. "FLEXMEASURES_REDIS_DB_NR": redis_warning,
  157. "FLEXMEASURES_REDIS_PASSWORD": redis_warning,
  158. }
  159. class ProductionConfig(Config):
  160. DEBUG: bool = False
  161. LOGGING_LEVEL: int = logging.ERROR
  162. class StagingConfig(Config):
  163. DEBUG: bool = False
  164. LOGGING_LEVEL: int = logging.WARNING
  165. class DevelopmentConfig(Config):
  166. DEBUG: bool = True
  167. LOGGING_LEVEL: int = logging.DEBUG
  168. SQLALCHEMY_ECHO: bool = False
  169. PROPAGATE_EXCEPTIONS: bool = True
  170. # PRESERVE_CONTEXT_ON_EXCEPTION: bool = False # might need this to make our transaction handling work in debug mode
  171. FLEXMEASURES_MODE: str = "development"
  172. FLEXMEASURES_PROFILE_REQUESTS: bool = True
  173. class TestingConfig(Config):
  174. DEBUG: bool = True # this seems to be important for logging in, not sure why
  175. LOGGING_LEVEL: int = logging.INFO
  176. WTF_CSRF_ENABLED: bool = False # also necessary for logging in during tests
  177. SECRET_KEY: str = "dummy-key-for-testing"
  178. SECURITY_PASSWORD_SALT: str = "$2b$19$abcdefghijklmnopqrstuv"
  179. SQLALCHEMY_DATABASE_URI: str = (
  180. "postgresql://flexmeasures_test:flexmeasures_test@localhost/flexmeasures_test"
  181. )
  182. # SQLALCHEMY_ECHO = True
  183. FLEXMEASURES_TASK_CHECK_AUTH_TOKEN: str = "test-task-check-token"
  184. # These can speed up tests due to less hashing work (I saw ~165s -> ~100s)
  185. # (via https://github.com/mattupstate/flask-security/issues/731#issuecomment-362186021)
  186. SECURITY_HASHING_SCHEMES: list[str] = ["hex_md5"]
  187. SECURITY_DEPRECATED_HASHING_SCHEMES: list[str] = []
  188. FLEXMEASURES_MODE: str = "test"
  189. FLEXMEASURES_PLANNING_HORIZON: timedelta = timedelta(
  190. hours=2 * 24
  191. ) # if more than 2 days, consider setting up more days of price data for tests
  192. class DocumentationConfig(Config):
  193. SECRET_KEY: str = "dummy-key-for-documentation"
  194. SQLALCHEMY_DATABASE_URI: str = "postgresql://dummy:uri@for/documentation"