Repository: freedomofpress/securedrop

Issue:
Add list of supported languages to the metadata API
Whether or not a SecureDrop is available in one of the [supported languages](https://docs.securedrop.org/en/latest/admin.html#configuring-localization-for-the-source-interface-and-the-journalist-interface) is public information enumerated at the bottom of the source interface, but it's not currently exposed in the metadata API.

Returning the list of supported languages along with the other instance metadata would be useful, including for the envisioned source interface scanner integrated with securedrop.org. 

# User Stories

As a translator, I want to know which languages are currently used by SecureDrop users, so I know if and where my translations have real world impact.

As a SecureDrop support team member, I want to know at a glance whether news organizations have configured supported languages, so I can point out to them if/when translations relevant to them are available.

As a SecureDrop.org visitor, I'd like to know if a SecureDrop instance is available in the language I speak, so that I know if I can navigate it with confidence, and that it is likely to accept submissions in my language.


Discussion:
hey @camfassett - are you interested in picking up a SecureDrop issue? This is a good first issue.

The place you'd want to add the supported languages is [this API endpoint](https://github.com/freedomofpress/securedrop/blob/develop/securedrop/source_app/api.py#L12). You'll want to expose the value of `config.SUPPORTED_LOCALES` there. You should get something like:

```
{"supported_languages": ["ar", "de_DE", "es_ES", "en_US", "el", "fr_FR", "it_IT", "nb_NO", "nl", "pt_BR", "tr", "zh_Hant"], 
 "server_os": "16.04", 
 "sd_version": "0.12.1", 
 "gpg_fpr": "65A1B5FF195B56353CC63DFFCC40EF1228271441"}
```

To check that the endpoint is working as expected, you'd also want to add asserts to the existing `/metadata` unit test in [this file](https://github.com/freedomofpress/securedrop/blob/develop/securedrop/tests/test_source.py#L527), or write a new unit test.
Thanks, @redshiftzero! I won't have time to look at this until next week, but I'd like to work on this issue.
Hey @eloquence, I would like to work on this issue. Let me know if I can pick this up?

Resolving patch:
diff --git a/securedrop/source_app/api.py b/securedrop/source_app/api.py
--- a/securedrop/source_app/api.py
+++ b/securedrop/source_app/api.py
@@ -11,10 +11,12 @@ def make_blueprint(config):
 
     @view.route('/metadata')
     def metadata():
-        meta = {'gpg_fpr': config.JOURNALIST_KEY,
-                'sd_version': version.__version__,
-                'server_os': platform.linux_distribution()[1],
-                }
+        meta = {
+            'gpg_fpr': config.JOURNALIST_KEY,
+            'sd_version': version.__version__,
+            'server_os': platform.linux_distribution()[1],
+            'supported_languages': config.SUPPORTED_LOCALES
+        }
         resp = make_response(json.dumps(meta))
         resp.headers['Content-Type'] = 'application/json'
         return resp


Test patch:
diff --git a/securedrop/tests/test_source.py b/securedrop/tests/test_source.py
--- a/securedrop/tests/test_source.py
+++ b/securedrop/tests/test_source.py
@@ -545,7 +545,7 @@ def test_why_journalist_key(source_app):
         assert "Why download the journalist's public key?" in text
 
 
-def test_metadata_route(source_app):
+def test_metadata_route(config, source_app):
     with patch.object(source_app_api.platform, "linux_distribution") as mocked_platform:
         mocked_platform.return_value = ("Ubuntu", "16.04", "xenial")
         with source_app.test_client() as app:
@@ -554,6 +554,8 @@ def test_metadata_route(source_app):
             assert resp.headers.get('Content-Type') == 'application/json'
             assert resp.json.get('sd_version') == version.__version__
             assert resp.json.get('server_os') == '16.04'
+            assert resp.json.get('supported_languages') ==\
+                config.SUPPORTED_LOCALES
 
 
 def test_login_with_overly_long_codename(source_app):