from typing import Dict
from typing import Optional

from typing import Type

import config as _config
from typing import List


class SDConfig:
    def __init__(self) -> None:
        self.JOURNALIST_APP_FLASK_CONFIG_CLS = \
            _config.JournalistInterfaceFlaskConfig  # type: Type

        self.SOURCE_APP_FLASK_CONFIG_CLS = \
            _config.SourceInterfaceFlaskConfig  # type: Type

        self.DATABASE_ENGINE = _config.DATABASE_ENGINE  # type: str
        self.DATABASE_FILE = _config.DATABASE_FILE  # type: str

        self.DATABASE_USERNAME = getattr(_config, "DATABASE_USERNAME", None)  # type: Optional[str]
        self.DATABASE_PASSWORD = getattr(_config, "DATABASE_PASSWORD", None)  # type: Optional[str]
        self.DATABASE_HOST = getattr(_config, "DATABASE_HOST", None)  # type: Optional[str]
        self.DATABASE_NAME = getattr(_config, "DATABASE_NAME", None)  # type: Optional[str]

        self.ADJECTIVES = _config.ADJECTIVES  # type: str
        self.NOUNS = _config.NOUNS  # type: str
        self.WORD_LIST = _config.WORD_LIST  # type: str

        self.DEFAULT_LOCALE = _config.DEFAULT_LOCALE  # type: str
        self.SUPPORTED_LOCALES = getattr(
            _config, "SUPPORTED_LOCALES", [self.DEFAULT_LOCALE]
        )  # type: List[str]

        self.GPG_KEY_DIR = _config.GPG_KEY_DIR  # type: str

        self.JOURNALIST_KEY = _config.JOURNALIST_KEY  # type: str
        self.JOURNALIST_TEMPLATES_DIR = _config.JOURNALIST_TEMPLATES_DIR  # type: str

        self.SCRYPT_GPG_PEPPER = _config.SCRYPT_GPG_PEPPER  # type: str
        self.SCRYPT_ID_PEPPER = _config.SCRYPT_ID_PEPPER  # type: str
        self.SCRYPT_PARAMS = _config.SCRYPT_PARAMS  # type: Dict[str, int]

        self.SECUREDROP_DATA_ROOT = _config.SECUREDROP_DATA_ROOT  # type: str
        self.SECUREDROP_ROOT = _config.SECUREDROP_ROOT  # type: str

        self.SESSION_EXPIRATION_MINUTES = _config.SESSION_EXPIRATION_MINUTES  # type: int

        self.SOURCE_TEMPLATES_DIR = _config.SOURCE_TEMPLATES_DIR  # type: str
        self.TEMP_DIR = _config.TEMP_DIR  # type: str
        self.STORE_DIR = _config.STORE_DIR  # type: str
        self.TRANSLATION_DIRS = getattr(_config, "TRANSLATION_DIRS", None)  # type: Optional[str]

        self.WORKER_PIDFILE = _config.WORKER_PIDFILE  # type: str

        if _config.env == 'test':
            self.RQ_WORKER_NAME = 'test'  # type: str
        else:
            self.RQ_WORKER_NAME = 'default'

    @property
    def DATABASE_URI(self) -> str:
        if self.DATABASE_ENGINE == "sqlite":
            db_uri = (self.DATABASE_ENGINE + ":///" +
                      self.DATABASE_FILE)
        else:
            if self.DATABASE_USERNAME is None:
                raise RuntimeError("Missing DATABASE_USERNAME entry from config.py")
            if self.DATABASE_PASSWORD is None:
                raise RuntimeError("Missing DATABASE_PASSWORD entry from config.py")
            if self.DATABASE_HOST is None:
                raise RuntimeError("Missing DATABASE_HOST entry from config.py")
            if self.DATABASE_NAME is None:
                raise RuntimeError("Missing DATABASE_NAME entry from config.py")

            db_uri = (
                self.DATABASE_ENGINE + '://' +
                self.DATABASE_USERNAME + ':' +
                self.DATABASE_PASSWORD + '@' +
                self.DATABASE_HOST + '/' +
                self.DATABASE_NAME
            )
        return db_uri


config = SDConfig()  # type: SDConfig

securedrop/sdconfig.py
from typing import Dict
from typing import Optional

from typing import Type

import config as _config
from typing import List


class SDConfig:
    def __init__(self) -> None:
        self.JOURNALIST_APP_FLASK_CONFIG_CLS = \
            _config.JournalistInterfaceFlaskConfig  # type: Type

        self.SOURCE_APP_FLASK_CONFIG_CLS = \
            _config.SourceInterfaceFlaskConfig  # type: Type

        self.DATABASE_ENGINE = _config.DATABASE_ENGINE  # type: str
        self.DATABASE_FILE = _config.DATABASE_FILE  # type: str

        self.DATABASE_USERNAME = getattr(_config, "DATABASE_USERNAME", None)  # type: Optional[str]
        self.DATABASE_PASSWORD = getattr(_config, "DATABASE_PASSWORD", None)  # type: Optional[str]
        self.DATABASE_HOST = getattr(_config, "DATABASE_HOST", None)  # type: Optional[str]
        self.DATABASE_NAME = getattr(_config, "DATABASE_NAME", None)  # type: Optional[str]

        self.ADJECTIVES = _config.ADJECTIVES  # type: str
        self.NOUNS = _config.NOUNS  # type: str
        self.WORD_LIST = _config.WORD_LIST  # type: str

        self.DEFAULT_LOCALE = _config.DEFAULT_LOCALE  # type: str
        self.SUPPORTED_LOCALES = getattr(
            _config, "SUPPORTED_LOCALES", [self.DEFAULT_LOCALE]
        )  # type: List[str]

        self.GPG_KEY_DIR = _config.GPG_KEY_DIR  # type: str

        self.JOURNALIST_KEY = _config.JOURNALIST_KEY  # type: str
        self.JOURNALIST_TEMPLATES_DIR = _config.JOURNALIST_TEMPLATES_DIR  # type: str

        self.SCRYPT_GPG_PEPPER = _config.SCRYPT_GPG_PEPPER  # type: str
        self.SCRYPT_ID_PEPPER = _config.SCRYPT_ID_PEPPER  # type: str
        self.SCRYPT_PARAMS = _config.SCRYPT_PARAMS  # type: Dict[str, int]

        self.SECUREDROP_DATA_ROOT = _config.SECUREDROP_DATA_ROOT  # type: str
        self.SECUREDROP_ROOT = _config.SECUREDROP_ROOT  # type: str

        self.SESSION_EXPIRATION_MINUTES = _config.SESSION_EXPIRATION_MINUTES  # type: int

        self.SOURCE_TEMPLATES_DIR = _config.SOURCE_TEMPLATES_DIR  # type: str
        self.TEMP_DIR = _config.TEMP_DIR  # type: str
        self.STORE_DIR = _config.STORE_DIR  # type: str
        self.TRANSLATION_DIRS = getattr(_config, "TRANSLATION_DIRS", None)  # type: Optional[str]

        self.WORKER_PIDFILE = _config.WORKER_PIDFILE  # type: str

        self.env = getattr(_config, 'env', 'prod')  # type: str
        if self.env == 'test':
            self.RQ_WORKER_NAME = 'test'  # type: str
        else:
            self.RQ_WORKER_NAME = 'default'

    @property
    def DATABASE_URI(self) -> str:
        if self.DATABASE_ENGINE == "sqlite":
            db_uri = (self.DATABASE_ENGINE + ":///" +
                      self.DATABASE_FILE)
        else:
            if self.DATABASE_USERNAME is None:
                raise RuntimeError("Missing DATABASE_USERNAME entry from config.py")
            if self.DATABASE_PASSWORD is None:
                raise RuntimeError("Missing DATABASE_PASSWORD entry from config.py")
            if self.DATABASE_HOST is None:
                raise RuntimeError("Missing DATABASE_HOST entry from config.py")
            if self.DATABASE_NAME is None:
                raise RuntimeError("Missing DATABASE_NAME entry from config.py")

            db_uri = (
                self.DATABASE_ENGINE + '://' +
                self.DATABASE_USERNAME + ':' +
                self.DATABASE_PASSWORD + '@' +
                self.DATABASE_HOST + '/' +
                self.DATABASE_NAME
            )
        return db_uri


config = SDConfig()  # type: SDConfig

securedrop/sdconfig.py
diff --git a/securedrop/sdconfig.py b/securedrop/sdconfig.py
index 1115f49f58..ed3453d3ac 100644
--- a/securedrop/sdconfig.py
+++ b/securedrop/sdconfig.py
@@ -53,7 +53,8 @@ def __init__(self) -> None:
 
         self.WORKER_PIDFILE = _config.WORKER_PIDFILE  # type: str
 
-        if _config.env == 'test':
+        self.env = getattr(_config, 'env', 'prod')  # type: str
+        if self.env == 'test':
             self.RQ_WORKER_NAME = 'test'  # type: str
         else:
             self.RQ_WORKER_NAME = 'default'

dev server hot reload has stopped working
## Description

In #5532 the `env` attribute was dropped from `SDConfig` in `sdconfig.py`. That value is checked in [`source.py`](https://github.com/freedomofpress/securedrop/blob/6246482157e31d0655a91c5e7284cc8550f2c289/securedrop/source.py#L11) and [`journalist.py`](https://github.com/freedomofpress/securedrop/blob/6246482157e31d0655a91c5e7284cc8550f2c289/securedrop/journalist.py#L26) to determine whether the Flask app will run in [debug](https://flask.palletsprojects.com/en/1.1.x/config/#DEBUG) mode. By default it will not, so the dev server has stopped responding to code changes.

Given the Flask documentation warnings about setting debug mode via code and not the `FLASK_DEBUG` environment variable, we may want to reevaluate all of this, but right now let's just get back to a properly functioning dev server.

## Steps to Reproduce

- Check out `develop` at a commit before the `sdconfig.py` change (eff931fa8a0e74d5c3be87e46c5d0f004f02e289).
- Run `make dev`.
- Change `securedrop/journalist_app/main.py` to trigger a reload, and confirm that the change is detected.
- Stop the dev server.
- Check out `develop` and run `make dev`.
- Change `securedrop/journalist_app/main.py` again, and observe that the change is not detected.

## Expected Behavior

That the dev server would notice code changes and reload to pick them up.

## Actual Behavior

It does not care one whit about your useless flailings. We are all `prod` now.

## Comments

Just need to restore `SDConfig.env`.

