We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[UI idea] Group customization pages within for-teachers url
**Idea incl level**
Currently the class customization page has a dedicated url at `/customize-class`. Due to the commit https://github.com/Felienne/hedy/commit/42ab2641d2c26a101a870371e7c16f0de8729439 we automatically extract the current page from the url and display this in the menu bar as active. As the `/customize-class` page has no own menu option no active page is shown. Because the page belongs conceptually to the `/for-teachers` section it would be nice to show this page as active. We can solve this issue by making it a sub url of `/for-teachers` such as `/for-teachers/customize-class`. A structure that can also be used for possible future page belonging to the teacher section such as `/customize-student`.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `website/teacher.py`
Content:
```
1 from website.auth import requires_login, is_teacher, current_user
2 import utils
3 import uuid
4 from flask import g, request, jsonify, redirect
5 from flask_helpers import render_template
6 import os
7 import hedyweb
8 import hedy_content
9 TRANSLATIONS = hedyweb.Translations ()
10 from config import config
11 cookie_name     = config ['session'] ['cookie_name']
12 
13 def routes (app, database):
14     global DATABASE
15     DATABASE = database
16 
17     @app.route('/classes', methods=['GET'])
18     @requires_login
19     def get_classes (user):
20         if not is_teacher(user):
21             return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))
22         return jsonify (DATABASE.get_teacher_classes (user ['username'], True))
23 
24     @app.route('/class/<class_id>', methods=['GET'])
25     @requires_login
26     def get_class (user, class_id):
27         app.logger.info('This is info output')
28         if not is_teacher(user):
29             return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))
30         Class = DATABASE.get_class (class_id)
31         if not Class or Class ['teacher'] != user ['username']:
32             return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('no_such_class'))
33         students = []
34         for student_username in Class.get ('students', []):
35             student = DATABASE.user_by_username (student_username)
36             programs = DATABASE.programs_for_user(student_username)
37             highest_level = max(program['level'] for program in programs) if len(programs) else 0
38             sorted_public_programs = list(sorted([program for program in programs if program.get ('public')], key=lambda p: p['date']))
39             if sorted_public_programs:
40                 latest_shared = sorted_public_programs[-1]
41                 latest_shared['link'] = os.getenv ('BASE_URL') + f"/hedy/{latest_shared['id']}/view"
42             else:
43                 latest_shared = None
44             students.append ({'username': student_username, 'last_login': utils.datetotimeordate (utils.mstoisostring (student ['last_login'])), 'programs': len (programs), 'highest_level': highest_level, 'latest_shared': latest_shared})
45 
46         if utils.is_testing_request (request):
47             return jsonify ({'students': students, 'link': Class ['link'], 'name': Class ['name'], 'id': Class ['id']})
48         return render_template ('class-overview.html', auth=TRANSLATIONS.get_translations (g.lang, 'Auth'), current_page='for-teachers', class_info={'students': students, 'link': os.getenv ('BASE_URL') + '/hedy/l/' + Class ['link'], 'name': Class ['name'], 'id': Class ['id']})
49 
50     @app.route('/class', methods=['POST'])
51     @requires_login
52     def create_class (user):
53         if not is_teacher(user):
54             return 'Only teachers can create classes', 403
55 
56         body = request.json
57         # Validations
58         if not isinstance(body, dict):
59             return 'body must be an object', 400
60         if not isinstance(body.get('name'), str):
61             return 'name must be a string', 400
62 
63         # We use this extra call to verify if the class name doesn't already exist, if so it's a duplicate
64         Classes = DATABASE.get_teacher_classes(user['username'], True)
65         for Class in Classes:
66             if Class['name'] == body['name']:
67                 return "duplicate", 200
68 
69         Class = {
70             'id': uuid.uuid4().hex,
71             'date': utils.timems (),
72             'teacher': user ['username'],
73             'link': utils.random_id_generator (7),
74             'name': body ['name']
75         }
76 
77         DATABASE.store_class (Class)
78 
79         return {'id': Class['id']}, 200
80 
81     @app.route('/class/<class_id>', methods=['PUT'])
82     @requires_login
83     def update_class (user, class_id):
84         if not is_teacher(user):
85             return 'Only teachers can update classes', 403
86 
87         body = request.json
88         # Validations
89         if not isinstance(body, dict):
90             return 'body must be an object', 400
91         if not isinstance(body.get('name'), str):
92             return 'name must be a string', 400
93 
94         Class = DATABASE.get_class (class_id)
95         if not Class or Class ['teacher'] != user ['username']:
96             return 'No such class', 404
97 
98         # We use this extra call to verify if the class name doesn't already exist, if so it's a duplicate
99         Classes = DATABASE.get_teacher_classes(user ['username'], True)
100         for Class in Classes:
101             if Class['name'] == body['name']:
102                 return "duplicate", 200
103 
104         Class = DATABASE.update_class (class_id, body ['name'])
105 
106         return {}, 200
107 
108     @app.route('/class/<class_id>', methods=['DELETE'])
109     @requires_login
110     def delete_class (user, class_id):
111         Class = DATABASE.get_class (class_id)
112         if not Class or Class ['teacher'] != user ['username']:
113             return 'No such class', 404
114 
115         DATABASE.delete_class (Class)
116 
117         return {}, 200
118 
119     @app.route('/class/<class_id>/prejoin/<link>', methods=['GET'])
120     def prejoin_class (class_id, link):
121         Class = DATABASE.get_class (class_id)
122         if not Class or Class ['link'] != link:
123             return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))
124         user = {}
125         if request.cookies.get (cookie_name):
126             token = DATABASE.get_token(request.cookies.get (cookie_name))
127             if token:
128                 if token ['username'] in Class.get ('students', []):
129                     return render_template ('class-already-joined.html', auth=TRANSLATIONS.get_translations (g.lang, 'Auth'), current_page='my-profile', class_info={'name': Class ['name']})
130                 user = DATABASE.user_by_username(token ['username'])
131 
132         return render_template ('class-prejoin.html',
133             auth=TRANSLATIONS.get_translations (g.lang, 'Auth'),
134             current_page='my-profile',
135             class_info={
136                 'link': os.getenv ('BASE_URL') + '/class/' + Class ['id'] + '/join/' + Class ['link'] + '?lang=' + g.lang,
137                 'name': Class ['name'],
138             })
139 
140     @app.route('/class/<class_id>/join/<link>', methods=['GET'])
141     @requires_login
142     def join_class (user, class_id, link):
143         Class = DATABASE.get_class (class_id)
144         if not Class or Class ['link'] != link:
145             return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))
146 
147         DATABASE.add_student_to_class (Class ['id'], user ['username'])
148 
149         return redirect(request.url.replace('/class/' + class_id + '/join/' + link, '/my-profile'), code=302)
150 
151     @app.route('/class/<class_id>/student/<student_id>', methods=['DELETE'])
152     @requires_login
153     def leave_class (user, class_id, student_id):
154 
155         Class = DATABASE.get_class (class_id)
156         if not Class or Class ['teacher'] != user ['username']:
157             return 'No such class', 404
158 
159         DATABASE.remove_student_from_class (Class ['id'], student_id)
160 
161         return {}, 200
162 
163     @app.route('/customize-class/<class_id>', methods=['GET'])
164     @requires_login
165     def get_class_info(user, class_id):
166         if not is_teacher(user):
167             return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))
168         Class = DATABASE.get_class(class_id)
169         if not Class or Class['teacher'] != user['username']:
170             return utils.page_404(TRANSLATIONS, current_user()['username'], g.lang,
171                                   TRANSLATIONS.get_translations(g.lang, 'ui').get('no_such_class'))
172 
173         if hedy_content.Adventures(g.lang).has_adventures():
174             adventures = hedy_content.Adventures(g.lang).get_adventure_keyname_name_levels()
175         else:
176             adventures = hedy_content.Adventures("en").get_adventure_keyname_name_levels()
177         levels = hedy_content.LevelDefaults(g.lang).levels
178         preferences = DATABASE.get_customizations_class(class_id)
179 
180         return render_template('customize-class.html', auth=TRANSLATIONS.get_translations(g.lang, 'Auth'),
181                                ui=TRANSLATIONS.get_translations(g.lang, 'ui'),
182                                class_info={'name': Class['name'], 'id': Class['id']}, levels=levels,
183                                adventures=adventures, preferences=preferences, current_page='for-teachers')
184 
185     @app.route('/customize-class/<class_id>', methods=['PUT'])
186     @requires_login
187     def update_level_preferences(user, class_id):
188         if not is_teacher(user):
189             return 'Only teachers can update class preferences', 403
190 
191         body = request.json
192         print(body)
193         # Validations
194         if not isinstance(body, dict):
195             return 'body must be an object', 400
196         if not isinstance(body.get('example_programs'), bool):
197             return 'amount of example programs must be an integer', 400
198         if not isinstance(body.get('hide_level'), bool):
199             return 'level switch must be a boolean', 400
200         if not isinstance(body.get('hide_prev_level'), bool):
201             return 'level switch must be a boolean', 400
202         if not isinstance(body.get('hide_next_level'), bool):
203             return 'level switch must be a boolean', 400
204         if not isinstance(int(body.get('level')), int):
205             return 'level must ben an integer', 400
206 
207         Class = DATABASE.get_class(class_id)
208         if not Class or Class['teacher'] != user['username']:
209             return 'No such class', 404
210 
211         customizations = {}
212         customizations['id'] = class_id
213         customizations['level'] = int(body.get('level'))
214         customizations['adventures'] = body.get('adventures')
215         customizations['example_programs'] = body.get('example_programs')
216         customizations['hide'] = body.get('hide_level')
217         customizations['hide_prev_level'] = body.get('hide_prev_level')
218         customizations['hide_next_level'] = body.get('hide_next_level')
219 
220 
221         Class = DATABASE.update_customizations_class(customizations)
222 
223         return {}, 200
224 
225     @app.route('/hedy/l/<link_id>', methods=['GET'])
226     def resolve_class_link (link_id):
227         Class = DATABASE.resolve_class_link (link_id)
228         if not Class:
229             return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))
230         return redirect(request.url.replace('/hedy/l/' + link_id, '/class/' + Class ['id'] + '/prejoin/' + link_id), code=302)
231
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/website/teacher.py b/website/teacher.py
--- a/website/teacher.py
+++ b/website/teacher.py
@@ -21,7 +21,7 @@
             return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))
         return jsonify (DATABASE.get_teacher_classes (user ['username'], True))
 
-    @app.route('/class/<class_id>', methods=['GET'])
+    @app.route('/for-teachers/class/<class_id>', methods=['GET'])
     @requires_login
     def get_class (user, class_id):
         app.logger.info('This is info output')
@@ -160,7 +160,7 @@
 
         return {}, 200
 
-    @app.route('/customize-class/<class_id>', methods=['GET'])
+    @app.route('/for-teachers/customize-class/<class_id>', methods=['GET'])
     @requires_login
     def get_class_info(user, class_id):
         if not is_teacher(user):

{"golden_diff": "diff --git a/website/teacher.py b/website/teacher.py\n--- a/website/teacher.py\n+++ b/website/teacher.py\n@@ -21,7 +21,7 @@\n             return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n         return jsonify (DATABASE.get_teacher_classes (user ['username'], True))\n \n-    @app.route('/class/<class_id>', methods=['GET'])\n+    @app.route('/for-teachers/class/<class_id>', methods=['GET'])\n     @requires_login\n     def get_class (user, class_id):\n         app.logger.info('This is info output')\n@@ -160,7 +160,7 @@\n \n         return {}, 200\n \n-    @app.route('/customize-class/<class_id>', methods=['GET'])\n+    @app.route('/for-teachers/customize-class/<class_id>', methods=['GET'])\n     @requires_login\n     def get_class_info(user, class_id):\n         if not is_teacher(user):\n", "issue": "[UI idea] Group customization pages within for-teachers url\n**Idea incl level**\r\nCurrently the class customization page has a dedicated url at `/customize-class`. Due to the commit https://github.com/Felienne/hedy/commit/42ab2641d2c26a101a870371e7c16f0de8729439 we automatically extract the current page from the url and display this in the menu bar as active. As the `/customize-class` page has no own menu option no active page is shown. Because the page belongs conceptually to the `/for-teachers` section it would be nice to show this page as active. We can solve this issue by making it a sub url of `/for-teachers` such as `/for-teachers/customize-class`. A structure that can also be used for possible future page belonging to the teacher section such as `/customize-student`.\r\n\r\n\n", "before_files": [{"content": "from website.auth import requires_login, is_teacher, current_user\nimport utils\nimport uuid\nfrom flask import g, request, jsonify, redirect\nfrom flask_helpers import render_template\nimport os\nimport hedyweb\nimport hedy_content\nTRANSLATIONS = hedyweb.Translations ()\nfrom config import config\ncookie_name     = config ['session'] ['cookie_name']\n\ndef routes (app, database):\n    global DATABASE\n    DATABASE = database\n\n    @app.route('/classes', methods=['GET'])\n    @requires_login\n    def get_classes (user):\n        if not is_teacher(user):\n            return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n        return jsonify (DATABASE.get_teacher_classes (user ['username'], True))\n\n    @app.route('/class/<class_id>', methods=['GET'])\n    @requires_login\n    def get_class (user, class_id):\n        app.logger.info('This is info output')\n        if not is_teacher(user):\n            return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('no_such_class'))\n        students = []\n        for student_username in Class.get ('students', []):\n            student = DATABASE.user_by_username (student_username)\n            programs = DATABASE.programs_for_user(student_username)\n            highest_level = max(program['level'] for program in programs) if len(programs) else 0\n            sorted_public_programs = list(sorted([program for program in programs if program.get ('public')], key=lambda p: p['date']))\n            if sorted_public_programs:\n                latest_shared = sorted_public_programs[-1]\n                latest_shared['link'] = os.getenv ('BASE_URL') + f\"/hedy/{latest_shared['id']}/view\"\n            else:\n                latest_shared = None\n            students.append ({'username': student_username, 'last_login': utils.datetotimeordate (utils.mstoisostring (student ['last_login'])), 'programs': len (programs), 'highest_level': highest_level, 'latest_shared': latest_shared})\n\n        if utils.is_testing_request (request):\n            return jsonify ({'students': students, 'link': Class ['link'], 'name': Class ['name'], 'id': Class ['id']})\n        return render_template ('class-overview.html', auth=TRANSLATIONS.get_translations (g.lang, 'Auth'), current_page='for-teachers', class_info={'students': students, 'link': os.getenv ('BASE_URL') + '/hedy/l/' + Class ['link'], 'name': Class ['name'], 'id': Class ['id']})\n\n    @app.route('/class', methods=['POST'])\n    @requires_login\n    def create_class (user):\n        if not is_teacher(user):\n            return 'Only teachers can create classes', 403\n\n        body = request.json\n        # Validations\n        if not isinstance(body, dict):\n            return 'body must be an object', 400\n        if not isinstance(body.get('name'), str):\n            return 'name must be a string', 400\n\n        # We use this extra call to verify if the class name doesn't already exist, if so it's a duplicate\n        Classes = DATABASE.get_teacher_classes(user['username'], True)\n        for Class in Classes:\n            if Class['name'] == body['name']:\n                return \"duplicate\", 200\n\n        Class = {\n            'id': uuid.uuid4().hex,\n            'date': utils.timems (),\n            'teacher': user ['username'],\n            'link': utils.random_id_generator (7),\n            'name': body ['name']\n        }\n\n        DATABASE.store_class (Class)\n\n        return {'id': Class['id']}, 200\n\n    @app.route('/class/<class_id>', methods=['PUT'])\n    @requires_login\n    def update_class (user, class_id):\n        if not is_teacher(user):\n            return 'Only teachers can update classes', 403\n\n        body = request.json\n        # Validations\n        if not isinstance(body, dict):\n            return 'body must be an object', 400\n        if not isinstance(body.get('name'), str):\n            return 'name must be a string', 400\n\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return 'No such class', 404\n\n        # We use this extra call to verify if the class name doesn't already exist, if so it's a duplicate\n        Classes = DATABASE.get_teacher_classes(user ['username'], True)\n        for Class in Classes:\n            if Class['name'] == body['name']:\n                return \"duplicate\", 200\n\n        Class = DATABASE.update_class (class_id, body ['name'])\n\n        return {}, 200\n\n    @app.route('/class/<class_id>', methods=['DELETE'])\n    @requires_login\n    def delete_class (user, class_id):\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return 'No such class', 404\n\n        DATABASE.delete_class (Class)\n\n        return {}, 200\n\n    @app.route('/class/<class_id>/prejoin/<link>', methods=['GET'])\n    def prejoin_class (class_id, link):\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['link'] != link:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))\n        user = {}\n        if request.cookies.get (cookie_name):\n            token = DATABASE.get_token(request.cookies.get (cookie_name))\n            if token:\n                if token ['username'] in Class.get ('students', []):\n                    return render_template ('class-already-joined.html', auth=TRANSLATIONS.get_translations (g.lang, 'Auth'), current_page='my-profile', class_info={'name': Class ['name']})\n                user = DATABASE.user_by_username(token ['username'])\n\n        return render_template ('class-prejoin.html',\n            auth=TRANSLATIONS.get_translations (g.lang, 'Auth'),\n            current_page='my-profile',\n            class_info={\n                'link': os.getenv ('BASE_URL') + '/class/' + Class ['id'] + '/join/' + Class ['link'] + '?lang=' + g.lang,\n                'name': Class ['name'],\n            })\n\n    @app.route('/class/<class_id>/join/<link>', methods=['GET'])\n    @requires_login\n    def join_class (user, class_id, link):\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['link'] != link:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))\n\n        DATABASE.add_student_to_class (Class ['id'], user ['username'])\n\n        return redirect(request.url.replace('/class/' + class_id + '/join/' + link, '/my-profile'), code=302)\n\n    @app.route('/class/<class_id>/student/<student_id>', methods=['DELETE'])\n    @requires_login\n    def leave_class (user, class_id, student_id):\n\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return 'No such class', 404\n\n        DATABASE.remove_student_from_class (Class ['id'], student_id)\n\n        return {}, 200\n\n    @app.route('/customize-class/<class_id>', methods=['GET'])\n    @requires_login\n    def get_class_info(user, class_id):\n        if not is_teacher(user):\n            return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n        Class = DATABASE.get_class(class_id)\n        if not Class or Class['teacher'] != user['username']:\n            return utils.page_404(TRANSLATIONS, current_user()['username'], g.lang,\n                                  TRANSLATIONS.get_translations(g.lang, 'ui').get('no_such_class'))\n\n        if hedy_content.Adventures(g.lang).has_adventures():\n            adventures = hedy_content.Adventures(g.lang).get_adventure_keyname_name_levels()\n        else:\n            adventures = hedy_content.Adventures(\"en\").get_adventure_keyname_name_levels()\n        levels = hedy_content.LevelDefaults(g.lang).levels\n        preferences = DATABASE.get_customizations_class(class_id)\n\n        return render_template('customize-class.html', auth=TRANSLATIONS.get_translations(g.lang, 'Auth'),\n                               ui=TRANSLATIONS.get_translations(g.lang, 'ui'),\n                               class_info={'name': Class['name'], 'id': Class['id']}, levels=levels,\n                               adventures=adventures, preferences=preferences, current_page='for-teachers')\n\n    @app.route('/customize-class/<class_id>', methods=['PUT'])\n    @requires_login\n    def update_level_preferences(user, class_id):\n        if not is_teacher(user):\n            return 'Only teachers can update class preferences', 403\n\n        body = request.json\n        print(body)\n        # Validations\n        if not isinstance(body, dict):\n            return 'body must be an object', 400\n        if not isinstance(body.get('example_programs'), bool):\n            return 'amount of example programs must be an integer', 400\n        if not isinstance(body.get('hide_level'), bool):\n            return 'level switch must be a boolean', 400\n        if not isinstance(body.get('hide_prev_level'), bool):\n            return 'level switch must be a boolean', 400\n        if not isinstance(body.get('hide_next_level'), bool):\n            return 'level switch must be a boolean', 400\n        if not isinstance(int(body.get('level')), int):\n            return 'level must ben an integer', 400\n\n        Class = DATABASE.get_class(class_id)\n        if not Class or Class['teacher'] != user['username']:\n            return 'No such class', 404\n\n        customizations = {}\n        customizations['id'] = class_id\n        customizations['level'] = int(body.get('level'))\n        customizations['adventures'] = body.get('adventures')\n        customizations['example_programs'] = body.get('example_programs')\n        customizations['hide'] = body.get('hide_level')\n        customizations['hide_prev_level'] = body.get('hide_prev_level')\n        customizations['hide_next_level'] = body.get('hide_next_level')\n\n\n        Class = DATABASE.update_customizations_class(customizations)\n\n        return {}, 200\n\n    @app.route('/hedy/l/<link_id>', methods=['GET'])\n    def resolve_class_link (link_id):\n        Class = DATABASE.resolve_class_link (link_id)\n        if not Class:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))\n        return redirect(request.url.replace('/hedy/l/' + link_id, '/class/' + Class ['id'] + '/prejoin/' + link_id), code=302)\n", "path": "website/teacher.py"}], "after_files": [{"content": "from website.auth import requires_login, is_teacher, current_user\nimport utils\nimport uuid\nfrom flask import g, request, jsonify, redirect\nfrom flask_helpers import render_template\nimport os\nimport hedyweb\nimport hedy_content\nTRANSLATIONS = hedyweb.Translations ()\nfrom config import config\ncookie_name     = config ['session'] ['cookie_name']\n\ndef routes (app, database):\n    global DATABASE\n    DATABASE = database\n\n    @app.route('/classes', methods=['GET'])\n    @requires_login\n    def get_classes (user):\n        if not is_teacher(user):\n            return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n        return jsonify (DATABASE.get_teacher_classes (user ['username'], True))\n\n    @app.route('/for-teachers/class/<class_id>', methods=['GET'])\n    @requires_login\n    def get_class (user, class_id):\n        app.logger.info('This is info output')\n        if not is_teacher(user):\n            return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('no_such_class'))\n        students = []\n        for student_username in Class.get ('students', []):\n            student = DATABASE.user_by_username (student_username)\n            programs = DATABASE.programs_for_user(student_username)\n            highest_level = max(program['level'] for program in programs) if len(programs) else 0\n            sorted_public_programs = list(sorted([program for program in programs if program.get ('public')], key=lambda p: p['date']))\n            if sorted_public_programs:\n                latest_shared = sorted_public_programs[-1]\n                latest_shared['link'] = os.getenv ('BASE_URL') + f\"/hedy/{latest_shared['id']}/view\"\n            else:\n                latest_shared = None\n            students.append ({'username': student_username, 'last_login': utils.datetotimeordate (utils.mstoisostring (student ['last_login'])), 'programs': len (programs), 'highest_level': highest_level, 'latest_shared': latest_shared})\n\n        if utils.is_testing_request (request):\n            return jsonify ({'students': students, 'link': Class ['link'], 'name': Class ['name'], 'id': Class ['id']})\n        return render_template ('class-overview.html', auth=TRANSLATIONS.get_translations (g.lang, 'Auth'), current_page='for-teachers', class_info={'students': students, 'link': os.getenv ('BASE_URL') + '/hedy/l/' + Class ['link'], 'name': Class ['name'], 'id': Class ['id']})\n\n    @app.route('/class', methods=['POST'])\n    @requires_login\n    def create_class (user):\n        if not is_teacher(user):\n            return 'Only teachers can create classes', 403\n\n        body = request.json\n        # Validations\n        if not isinstance(body, dict):\n            return 'body must be an object', 400\n        if not isinstance(body.get('name'), str):\n            return 'name must be a string', 400\n\n        # We use this extra call to verify if the class name doesn't already exist, if so it's a duplicate\n        Classes = DATABASE.get_teacher_classes(user['username'], True)\n        for Class in Classes:\n            if Class['name'] == body['name']:\n                return \"duplicate\", 200\n\n        Class = {\n            'id': uuid.uuid4().hex,\n            'date': utils.timems (),\n            'teacher': user ['username'],\n            'link': utils.random_id_generator (7),\n            'name': body ['name']\n        }\n\n        DATABASE.store_class (Class)\n\n        return {'id': Class['id']}, 200\n\n    @app.route('/class/<class_id>', methods=['PUT'])\n    @requires_login\n    def update_class (user, class_id):\n        if not is_teacher(user):\n            return 'Only teachers can update classes', 403\n\n        body = request.json\n        # Validations\n        if not isinstance(body, dict):\n            return 'body must be an object', 400\n        if not isinstance(body.get('name'), str):\n            return 'name must be a string', 400\n\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return 'No such class', 404\n\n        # We use this extra call to verify if the class name doesn't already exist, if so it's a duplicate\n        Classes = DATABASE.get_teacher_classes(user ['username'], True)\n        for Class in Classes:\n            if Class['name'] == body['name']:\n                return \"duplicate\", 200\n\n        Class = DATABASE.update_class (class_id, body ['name'])\n\n        return {}, 200\n\n    @app.route('/class/<class_id>', methods=['DELETE'])\n    @requires_login\n    def delete_class (user, class_id):\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return 'No such class', 404\n\n        DATABASE.delete_class (Class)\n\n        return {}, 200\n\n    @app.route('/class/<class_id>/prejoin/<link>', methods=['GET'])\n    def prejoin_class (class_id, link):\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['link'] != link:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))\n        user = {}\n        if request.cookies.get (cookie_name):\n            token = DATABASE.get_token(request.cookies.get (cookie_name))\n            if token:\n                if token ['username'] in Class.get ('students', []):\n                    return render_template ('class-already-joined.html', auth=TRANSLATIONS.get_translations (g.lang, 'Auth'), current_page='my-profile', class_info={'name': Class ['name']})\n                user = DATABASE.user_by_username(token ['username'])\n\n        return render_template ('class-prejoin.html',\n            auth=TRANSLATIONS.get_translations (g.lang, 'Auth'),\n            current_page='my-profile',\n            class_info={\n                'link': os.getenv ('BASE_URL') + '/class/' + Class ['id'] + '/join/' + Class ['link'] + '?lang=' + g.lang,\n                'name': Class ['name'],\n            })\n\n    @app.route('/class/<class_id>/join/<link>', methods=['GET'])\n    @requires_login\n    def join_class (user, class_id, link):\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['link'] != link:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))\n\n        DATABASE.add_student_to_class (Class ['id'], user ['username'])\n\n        return redirect(request.url.replace('/class/' + class_id + '/join/' + link, '/my-profile'), code=302)\n\n    @app.route('/class/<class_id>/student/<student_id>', methods=['DELETE'])\n    @requires_login\n    def leave_class (user, class_id, student_id):\n\n        Class = DATABASE.get_class (class_id)\n        if not Class or Class ['teacher'] != user ['username']:\n            return 'No such class', 404\n\n        DATABASE.remove_student_from_class (Class ['id'], student_id)\n\n        return {}, 200\n\n    @app.route('/for-teachers/customize-class/<class_id>', methods=['GET'])\n    @requires_login\n    def get_class_info(user, class_id):\n        if not is_teacher(user):\n            return utils.page_403 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations (g.lang, 'ui').get ('retrieve_class'))\n        Class = DATABASE.get_class(class_id)\n        if not Class or Class['teacher'] != user['username']:\n            return utils.page_404(TRANSLATIONS, current_user()['username'], g.lang,\n                                  TRANSLATIONS.get_translations(g.lang, 'ui').get('no_such_class'))\n\n        if hedy_content.Adventures(g.lang).has_adventures():\n            adventures = hedy_content.Adventures(g.lang).get_adventure_keyname_name_levels()\n        else:\n            adventures = hedy_content.Adventures(\"en\").get_adventure_keyname_name_levels()\n        levels = hedy_content.LevelDefaults(g.lang).levels\n        preferences = DATABASE.get_customizations_class(class_id)\n\n        return render_template('customize-class.html', auth=TRANSLATIONS.get_translations(g.lang, 'Auth'),\n                               ui=TRANSLATIONS.get_translations(g.lang, 'ui'),\n                               class_info={'name': Class['name'], 'id': Class['id']}, levels=levels,\n                               adventures=adventures, preferences=preferences, current_page='for-teachers')\n\n    @app.route('/customize-class/<class_id>', methods=['PUT'])\n    @requires_login\n    def update_level_preferences(user, class_id):\n        if not is_teacher(user):\n            return 'Only teachers can update class preferences', 403\n\n        body = request.json\n        print(body)\n        # Validations\n        if not isinstance(body, dict):\n            return 'body must be an object', 400\n        if not isinstance(body.get('example_programs'), bool):\n            return 'amount of example programs must be an integer', 400\n        if not isinstance(body.get('hide_level'), bool):\n            return 'level switch must be a boolean', 400\n        if not isinstance(body.get('hide_prev_level'), bool):\n            return 'level switch must be a boolean', 400\n        if not isinstance(body.get('hide_next_level'), bool):\n            return 'level switch must be a boolean', 400\n        if not isinstance(int(body.get('level')), int):\n            return 'level must ben an integer', 400\n\n        Class = DATABASE.get_class(class_id)\n        if not Class or Class['teacher'] != user['username']:\n            return 'No such class', 404\n\n        customizations = {}\n        customizations['id'] = class_id\n        customizations['level'] = int(body.get('level'))\n        customizations['adventures'] = body.get('adventures')\n        customizations['example_programs'] = body.get('example_programs')\n        customizations['hide'] = body.get('hide_level')\n        customizations['hide_prev_level'] = body.get('hide_prev_level')\n        customizations['hide_next_level'] = body.get('hide_next_level')\n\n\n        Class = DATABASE.update_customizations_class(customizations)\n\n        return {}, 200\n\n    @app.route('/hedy/l/<link_id>', methods=['GET'])\n    def resolve_class_link (link_id):\n        Class = DATABASE.resolve_class_link (link_id)\n        if not Class:\n            return utils.page_404 (TRANSLATIONS, current_user()['username'], g.lang, TRANSLATIONS.get_translations(g.lang, 'ui').get('invalid_class_link'))\n        return redirect(request.url.replace('/hedy/l/' + link_id, '/class/' + Class ['id'] + '/prejoin/' + link_id), code=302)\n", "path": "website/teacher.py"}]}