Repository: CTFd/CTFd
Pull request #880 (2019-02-10 05:47:51)

Fix for hidden teams being visible on the team listing page and score…
* Fix for hidden teams being visible on the team listing page and scoreboard endpoints


codecov[bot]: # [Codecov](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=h1) Report
> Merging [#880](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=desc) into [master](https://codecov.io/gh/CTFd/CTFd/commit/b4da3b464bd51104df67f41a3d19755cf8e64ac7?src=pr&el=desc) will **decrease** coverage by `1.73%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/CTFd/CTFd/pull/880/graphs/tree.svg?width=650&token=IfPqkWkt9A&height=150&src=pr)](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #880      +/-   ##
==========================================
- Coverage   86.72%   84.99%   -1.74%     
==========================================
  Files          91       91              
  Lines        4604     4604              
==========================================
- Hits         3993     3913      -80     
- Misses        611      691      +80
```


| [Impacted Files](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [CTFd/api/v1/teams.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC9hcGkvdjEvdGVhbXMucHk=) | `91.03% <100%> (ø)` | :arrow_up: |
| [CTFd/teams.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC90ZWFtcy5weQ==) | `97.72% <100%> (ø)` | :arrow_up: |
| [CTFd/utils/exports/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy9leHBvcnRzL19faW5pdF9fLnB5) | `17.74% <0%> (-62.1%)` | :arrow_down: |
| [CTFd/utils/migrations/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy9taWdyYXRpb25zL19faW5pdF9fLnB5) | `53.33% <0%> (-26.67%)` | :arrow_down: |
| [CTFd/utils/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy9fX2luaXRfXy5weQ==) | `95.65% <0%> (-4.35%)` | :arrow_down: |
| [CTFd/utils/uploads/uploaders.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy91cGxvYWRzL3VwbG9hZGVycy5weQ==) | `81.72% <0%> (-1.08%)` | :arrow_down: |
| [CTFd/views.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC92aWV3cy5weQ==) | `83.03% <0%> (-0.9%)` | :arrow_down: |
| [CTFd/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC9fX2luaXRfXy5weQ==) | `87.5% <0%> (-0.79%)` | :arrow_down: |
| [CTFd/utils/updates/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy91cGRhdGVzL19faW5pdF9fLnB5) | `86.84% <0%> (ø)` | :arrow_up: |
| [CTFd/schemas/teams.py](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree#diff-Q1RGZC9zY2hlbWFzL3RlYW1zLnB5) | `78.48% <0%> (+1.26%)` | :arrow_up: |
| ... and [1 more](https://codecov.io/gh/CTFd/CTFd/pull/880/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=footer). Last update [b4da3b4...9b448a3](https://codecov.io/gh/CTFd/CTFd/pull/880?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CTFd/api/v1/teams.py b/CTFd/api/v1/teams.py
index 691682ed..ff16f748 100644
--- a/CTFd/api/v1/teams.py
+++ b/CTFd/api/v1/teams.py
@@ -28,7 +28,7 @@ teams_namespace = Namespace('teams', description="Endpoint to retrieve Teams")
 class TeamList(Resource):
     @check_account_visibility
     def get(self):
-        teams = Teams.query.filter_by(banned=False)
+        teams = Teams.query.filter_by(hidden=False, banned=False)
         view = copy.deepcopy(TeamSchema.views.get(
             session.get('type', 'user')
         ))
diff --git a/CTFd/teams.py b/CTFd/teams.py
index cdb0bf8b..2dd2555c 100644
--- a/CTFd/teams.py
+++ b/CTFd/teams.py
@@ -28,8 +28,8 @@ def listing():
     #     count = Teams.query.filter_by(verified=True, banned=False).count()
     #     teams = Teams.query.filter_by(verified=True, banned=False).slice(page_start, page_end).all()
     # else:
-    count = Teams.query.filter_by(banned=False).count()
-    teams = Teams.query.filter_by(banned=False).slice(page_start, page_end).all()
+    count = Teams.query.filter_by(hidden=False, banned=False).count()
+    teams = Teams.query.filter_by(hidden=False, banned=False).slice(page_start, page_end).all()
 
     pages = int(count / results_per_page) + (count % results_per_page > 0)
     return render_template('teams/teams.html', teams=teams, pages=pages, curr_page=page)


Test patch:
diff --git a/tests/teams/test_teams.py b/tests/teams/test_teams.py
index 2fd0c8aa..a2ed5915 100644
--- a/tests/teams/test_teams.py
+++ b/tests/teams/test_teams.py
@@ -22,6 +22,58 @@ def test_teams_get():
     destroy_ctfd(app)
 
 
+def test_hidden_teams_visibility():
+    """Hidden teams should not show up on /teams or /api/v1/teams or /api/v1/scoreboard"""
+    app = create_ctfd(user_mode="teams")
+    with app.app_context():
+        register_user(app)
+        with login_as_user(app) as client:
+            user = Users.query.filter_by(id=2).first()
+            team = gen_team(app.db, name='visible_team', hidden=True)
+            team.members.append(user)
+            user.team_id = team.id
+            app.db.session.commit()
+
+            r = client.get('/teams')
+            response = r.get_data(as_text=True)
+            assert team.name not in response
+
+            r = client.get('/api/v1/teams')
+            response = r.get_json()
+            assert team.name not in response
+
+            gen_award(app.db, user.id, team_id=team.id)
+
+            r = client.get('/scoreboard')
+            response = r.get_data(as_text=True)
+            assert team.name not in response
+
+            r = client.get('/api/v1/scoreboard')
+            response = r.get_json()
+            assert team.name not in response
+
+            # Team should re-appear after disabling hiding
+            # Use an API call to cause a cache clear
+            with login_as_user(app, name='admin') as admin:
+                r = admin.patch('/api/v1/teams/1', json={
+                    "hidden": False,
+                })
+                assert r.status_code == 200
+
+            r = client.get('/teams')
+            response = r.get_data(as_text=True)
+            assert team.name in response
+
+            r = client.get('/api/v1/teams')
+            response = r.get_data(as_text=True)
+            assert team.name in response
+
+            r = client.get('/api/v1/scoreboard')
+            response = r.get_data(as_text=True)
+            assert team.name in response
+    destroy_ctfd(app)
+
+
 def test_teams_get_user_mode():
     """Can a user get /teams if user mode"""
     app = create_ctfd(user_mode="users")
diff --git a/tests/users/test_users.py b/tests/users/test_users.py
index e69de29b..acbfac94 100644
--- a/tests/users/test_users.py
+++ b/tests/users/test_users.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from tests.helpers import *
+
+
+def test_hidden_user_visibility():
+    """Hidden users should not show up on /users or /api/v1/users or /api/v1/scoreboard"""
+    app = create_ctfd()
+    with app.app_context():
+        register_user(app, name="hidden_user")
+
+        with login_as_user(app, name="hidden_user") as client:
+            user = Users.query.filter_by(id=2).first()
+            user_name = user.name
+            user.hidden = True
+            app.db.session.commit()
+
+            r = client.get('/users')
+            response = r.get_data(as_text=True)
+            assert user_name not in response
+
+            r = client.get('/api/v1/users')
+            response = r.get_json()
+            assert user_name not in response
+
+            gen_award(app.db, user.id)
+
+            r = client.get('/scoreboard')
+            response = r.get_data(as_text=True)
+            assert user_name not in response
+
+            r = client.get('/api/v1/scoreboard')
+            response = r.get_json()
+            assert user_name not in response
+
+            # User should re-appear after disabling hiding
+            # Use an API call to cause a cache clear
+            with login_as_user(app, name='admin') as admin:
+                r = admin.patch('/api/v1/users/2', json={
+                    "hidden": False,
+                })
+                assert r.status_code == 200
+
+            r = client.get('/users')
+            response = r.get_data(as_text=True)
+            assert user_name in response
+
+            r = client.get('/api/v1/users')
+            response = r.get_data(as_text=True)
+            assert user_name in response
+
+            r = client.get('/api/v1/scoreboard')
+            response = r.get_data(as_text=True)
+            assert user_name in response
+    destroy_ctfd(app)