Repository: beetbox/beets

Issue:
web: GET /album/<n> hides artpath even when INCLUDE_PATHS is set
### Problem

`beet web` provides GET operations to fetch track items and albums. By default this removes paths
from the returned data, but the config setting INCLUDE_PATHS should allow the paths to be returned.

This works correctly for GET /item/... but not GET /album/... In the album case, the artpath is unconditionally deleted from the results.

### Setup

Add to config file:

web:
    include_paths: true

Use `beet web` to make a webserver available and do a GET /album/N, where N is the album id of an album in the database which has a cover art set. The JSON result should include the 'artpath' value but does not.

* OS: Linux (Debian Testing)
* Python version: 3.9.1-1
* beets version: 1.4.9-7
* Turning off plugins made problem go away (yes/no): bug in web plugin

Note this is a small issue, although I have hit it. I have a fix (and a regression test) which I will submit as a small PR once my first PR has been finished (so I can learn from the mistakes I made in that!).

Discussion:

Patch:
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 2a8b3a784..ecb7e03dd 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -6,7 +6,7 @@ jobs:
     strategy:
       matrix:
         platform: [ubuntu-latest]
-        python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9]
+        python-version: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9-dev]
 
     env:
       PY_COLORS: 1
@@ -25,17 +25,17 @@ jobs:
           python -m pip install tox sphinx
 
       - name: Test with tox
-        if: matrix.python-version != '3.9'
+        if: matrix.python-version != '3.8'
         run: |
           tox -e py-test
 
       - name: Test with tox and get coverage
-        if: matrix.python-version == '3.9'
+        if: matrix.python-version == '3.8'
         run: |
           tox -vv -e py-cov
-
+        
       - name: Upload code coverage
-        if: matrix.python-version == '3.9'
+        if: matrix.python-version == '3.8'
         run: |
           pip install codecov || true
           codecov || true
@@ -49,10 +49,10 @@ jobs:
     steps:
       - uses: actions/checkout@v2
 
-      - name: Set up Python 3.9
+      - name: Set up Python 2.7
         uses: actions/setup-python@v2
         with:
-          python-version: 3.9
+          python-version: 2.7
 
       - name: Install base dependencies
         run: |
@@ -71,10 +71,10 @@ jobs:
     steps:
       - uses: actions/checkout@v2
 
-      - name: Set up Python 3.9
+      - name: Set up Python 3.8
         uses: actions/setup-python@v2
         with:
-          python-version: 3.9
+          python-version: 3.8
 
       - name: Install base dependencies
         run: |
diff --git a/beetsplug/web/__init__.py b/beetsplug/web/__init__.py
index a982809c4..e80c8c29e 100644
--- a/beetsplug/web/__init__.py
+++ b/beetsplug/web/__init__.py
@@ -59,7 +59,10 @@ def _rep(obj, expand=False):
         return out
 
     elif isinstance(obj, beets.library.Album):
-        del out['artpath']
+        if app.config.get('INCLUDE_PATHS', False):
+            out['artpath'] = util.displayable_path(out['artpath'])
+        else:
+            del out['artpath']
         if expand:
             out['items'] = [_rep(item) for item in obj.items()]
         return out
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 2f31ecfe3..b9020621b 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -186,6 +186,9 @@ New features:
 
 Fixes:
 
+* :bug:`/plugins/web`: Fixed a small bug which caused album artpath to be
+  redacted even when ``include_paths`` option is set.
+  :bug:`3866`
 * :bug:`/plugins/discogs`: Fixed a bug with ``index_tracks`` options that
   sometimes caused the index to be discarded. Also remove the extra semicolon
   that was added when there is no index track.
diff --git a/docs/plugins/web.rst b/docs/plugins/web.rst
index 4b069a944..16dd43174 100644
--- a/docs/plugins/web.rst
+++ b/docs/plugins/web.rst
@@ -261,6 +261,8 @@ For albums, the following endpoints are provided:
 
 * ``GET /album/5``
 
+* ``GET /album/5/art``
+
 * ``DELETE /album/5``
 
 * ``GET /album/5,7``
diff --git a/tox.ini b/tox.ini
index 64acf1402..69308235d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -23,7 +23,7 @@ commands =
     lint: python -m flake8 {posargs} {[_lint]files}
 
 [testenv:docs]
-basepython = python3.9
+basepython = python2.7
 deps = sphinx
 commands = sphinx-build -W -q -b html docs {envtmpdir}/html {posargs}
 


Test patch:
diff --git a/test/test_web.py b/test/test_web.py
index e9ca028d9..88be31365 100644
--- a/test/test_web.py
+++ b/test/test_web.py
@@ -31,7 +31,7 @@ class WebPluginTest(_common.LibTestCase):
         self.lib.add(Item(title=u'and a third'))
         # The following adds will create albums #1 and #2
         self.lib.add(Album(album=u'album'))
-        self.lib.add(Album(album=u'other album'))
+        self.lib.add(Album(album=u'other album', artpath='/art_path_2'))
 
         web.app.config['TESTING'] = True
         web.app.config['lib'] = self.lib
@@ -46,6 +46,14 @@ class WebPluginTest(_common.LibTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertEqual(res_json['path'], u'/path_1')
 
+    def test_config_include_artpaths_true(self):
+        web.app.config['INCLUDE_PATHS'] = True
+        response = self.client.get('/album/2')
+        res_json = json.loads(response.data.decode('utf-8'))
+
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(res_json['artpath'], u'/art_path_2')
+
     def test_config_include_paths_false(self):
         web.app.config['INCLUDE_PATHS'] = False
         response = self.client.get('/item/1')
@@ -54,6 +62,14 @@ class WebPluginTest(_common.LibTestCase):
         self.assertEqual(response.status_code, 200)
         self.assertNotIn('path', res_json)
 
+    def test_config_include_artpaths_false(self):
+        web.app.config['INCLUDE_PATHS'] = False
+        response = self.client.get('/album/2')
+        res_json = json.loads(response.data.decode('utf-8'))
+
+        self.assertEqual(response.status_code, 200)
+        self.assertNotIn('artpath', res_json)
+
     def test_get_all_items(self):
         response = self.client.get('/item/')
         res_json = json.loads(response.data.decode('utf-8'))