Repository: CTFd/CTFd
Pull request #766 (2018-11-29 10:59:38)

Fix issue loading update view in Python 3. Thanks to @mayoneko
* Fix `update.html` in Python 3

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

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

```diff
@@            Coverage Diff             @@
##           master     #766      +/-   ##
==========================================
+ Coverage      83%   83.44%   +0.43%     
==========================================
  Files          91       91              
  Lines        4902     4481     -421     
==========================================
- Hits         4069     3739     -330     
+ Misses        833      742      -91
```


| [Impacted Files](https://codecov.io/gh/CTFd/CTFd/pull/766?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [CTFd/admin/challenges.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9hZG1pbi9jaGFsbGVuZ2VzLnB5) | `100% <100%> (+34.21%)` | :arrow_up: |
| [CTFd/utils/exports/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy9leHBvcnRzL19faW5pdF9fLnB5) | `79.67% <0%> (-6.78%)` | :arrow_down: |
| [CTFd/utils/uploads/uploaders.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy91cGxvYWRzL3VwbG9hZGVycy5weQ==) | `52.74% <0%> (-3.86%)` | :arrow_down: |
| [CTFd/auth.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9hdXRoLnB5) | `63.71% <0%> (-3.71%)` | :arrow_down: |
| [CTFd/utils/updates/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC91dGlscy91cGRhdGVzL19faW5pdF9fLnB5) | `82.05% <0%> (-2.57%)` | :arrow_down: |
| [CTFd/challenges.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9jaGFsbGVuZ2VzLnB5) | `80% <0%> (-2.15%)` | :arrow_down: |
| [CTFd/admin/teams.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9hZG1pbi90ZWFtcy5weQ==) | `46.15% <0%> (-1.61%)` | :arrow_down: |
| [CTFd/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9fX2luaXRfXy5weQ==) | `87.8% <0%> (-1.49%)` | :arrow_down: |
| [CTFd/config.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9jb25maWcucHk=) | `87.3% <0%> (-0.94%)` | :arrow_down: |
| [CTFd/admin/\_\_init\_\_.py](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree#diff-Q1RGZC9hZG1pbi9fX2luaXRfXy5weQ==) | `56.19% <0%> (-0.65%)` | :arrow_down: |
| ... and [7 more](https://codecov.io/gh/CTFd/CTFd/pull/766/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/CTFd/CTFd/pull/766?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/766?src=pr&el=footer). Last update [825190b...31a6855](https://codecov.io/gh/CTFd/CTFd/pull/766?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CTFd/admin/challenges.py b/CTFd/admin/challenges.py
index 55de2811..37514563 100644
--- a/CTFd/admin/challenges.py
+++ b/CTFd/admin/challenges.py
@@ -1,9 +1,11 @@
 from flask import current_app as app, render_template, render_template_string, url_for
 from CTFd.utils.decorators import admins_only
+from CTFd.utils import binary_type
 from CTFd.models import Solves, Challenges, Flags
 from CTFd.plugins.challenges import get_chal_class
 from CTFd.admin import admin
 import os
+import six
 
 
 @admin.route('/admin/challenges')
@@ -22,9 +24,12 @@ def challenges_detail(challenge_id):
     flags = Flags.query.filter_by(challenge_id=challenge.id).all()
     challenge_class = get_chal_class(challenge.type)
 
-    with open(os.path.join(app.root_path, challenge_class.templates['update'].lstrip('/'))) as update:
+    with open(os.path.join(app.root_path, challenge_class.templates['update'].lstrip('/')), 'rb') as update:
+        tpl = update.read()
+        if six.PY3 and isinstance(tpl, binary_type):
+            tpl = tpl.decode('utf-8')
         update_j2 = render_template_string(
-            update.read().decode('utf-8'),
+            tpl,
             challenge=challenge
         )
 


Test patch:
diff --git a/tests/admin/test_challenges.py b/tests/admin/test_challenges.py
index 5832d57a..2df8119d 100644
--- a/tests/admin/test_challenges.py
+++ b/tests/admin/test_challenges.py
@@ -21,6 +21,32 @@ def test_get_admin_challenges_new():
     destroy_ctfd(app)
 
 
+def test_create_new_challenge():
+    """Test that an admin can create a challenge properly"""
+    app = create_ctfd()
+    with app.app_context():
+        register_user(app)
+        client = login_as_user(app, name="admin", password="password")
+
+        challenge_data = {
+            "name": "name",
+            "category": "category",
+            "description": "description",
+            "value": 100,
+            "state": "hidden",
+            "type": "standard"
+        }
+
+        r = client.post('/api/v1/challenges', json=challenge_data)
+        assert r.get_json().get('data')['id'] == 1
+        r = client.get('/admin/challenges/1')
+        assert r.status_code == 200
+        r = client.get('/api/v1/challenges/1')
+        assert r.get_json().get('data')['id'] == 1
+
+    destroy_ctfd(app)
+
+
 def test_hidden_challenge_is_reachable():
     """Test that hidden challenges are visible for admins"""
     app = create_ctfd()