Repository: hedyorg/hedy

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`.




Discussion:

Resolving patch:
diff --git a/website/teacher.py b/website/teacher.py
--- a/website/teacher.py
+++ b/website/teacher.py
@@ -21,7 +21,7 @@ def get_classes (user):
             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 @@ def leave_class (user, class_id, student_id):
 
         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):


Test patch:
diff --git a/e2e_tests.py b/e2e_tests.py
--- a/e2e_tests.py
+++ b/e2e_tests.py
@@ -456,11 +456,11 @@ def suite (username):
         invalidMap ('create class', 'post', '/class', ['', [], {}, {'name': 1}, {'name': ['foobar']}]),
         ['create class', 'post', '/class', {}, {'name': 'class1'}, 200],
         ['get classes after creating a class', 'get', '/classes', {}, {}, 200, getTeacherClasses2],
-        ['get empty class', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass1],
+        ['get empty class', 'get', lambda state: '/for-teachers/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass1],
         invalidMap ('update class', 'put', lambda state: '/class/' + state ['classes'] [0] ['id'], ['', [], {}, {'name': 1}, {'name': ['foobar']}]),
         ['update class', 'put', lambda state: '/class/' + state ['classes'] [0] ['id'], {}, {'name': 'class_renamed'}, 200],
         ['get classes after renaming a class', 'get', '/classes', {}, {}, 200, getTeacherClasses3],
-        ['get renamed class', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass2],
+        ['get renamed class', 'get', lambda state: '/for-teachers/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass2],
         ['join class as non-logged in user', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'] + '/join/' + state ['classes'] [0] ['link'], lambda state: {'cookie': 'foo'}, {}, 403],
         ['login as student', 'post', '/auth/login', {}, {'username': 'student-' + username, 'password': 'foobar'}, 200],
         ['join class that does not exist', 'get', lambda state: '/class/foo' + '/join/' + state ['classes'] [0] ['link'], {}, {}, 404],
@@ -470,19 +470,19 @@ def suite (username):
         ['join class again (idempotent call)', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'] + '/join/' + state ['classes'] [0] ['link'], {}, {}, 302, redirectAfterJoin1],
         ['get profile after joining class', 'get', '/profile', {}, {}, 200, getStudentClasses1],
         ['login as teacher', 'post', '/auth/login', {}, {'username': 'teacher-' + username, 'password': 'foobar'}, 200],
-        ['get class with a student', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass3],
+        ['get class with a student', 'get', lambda state: '/for-teachers/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass3],
         ['get student programs', 'get', lambda state: '/programs?user=' + state ['student'] ['username'], {}, {}, 200],
         ['login as student', 'post', '/auth/login', {}, {'username': 'student-' + username, 'password': 'foobar'}, 200],
         ['create public program (not shared yet)', 'post', '/programs', {}, {'code': 'print Hello world', 'name': 'Public program 1', 'level': 1}, 200, createPublicProgram],
         ['share public program', 'post', '/programs/share', {}, lambda state: {'id': state ['public_program'], 'public': True}, 200],
         ['create private program after public program', 'post', '/programs', {}, {'code': 'print Hello world', 'name': 'Private program 1', 'level': 1}, 200],
         ['login as teacher', 'post', '/auth/login', {}, {'username': 'teacher-' + username, 'password': 'foobar'}, 200],
-        ['get class with a student with a shared program', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass4],
+        ['get class with a student with a shared program', 'get', lambda state: '/for-teachers/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass4],
         ['get classes after student shared a program', 'get', '/classes', {}, {}, 200, getTeacherClasses4],
         ['remove non-existing student from class', 'delete', lambda state: '/class/' + state ['classes'] [0] ['id'] + '/student/' + 'foo', {}, {}, 200],
         ['remove student from class', 'delete', lambda state: '/class/' + state ['classes'] [0] ['id'] + '/student/' + 'student-' + username, {}, {}, 200],
         ['remove student from class again (idempotent call)', 'delete', lambda state: '/class/' + state ['classes'] [0] ['id'] + '/student/' + 'student-' + username, {}, {}, 200],
-        ['get class that is now again empty', 'get', lambda state: '/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass2],
+        ['get class that is now again empty', 'get', lambda state: '/for-teachers/class/' + state ['classes'] [0] ['id'], {}, {}, 200, getClass2],
         ['get student programs if student is no longer in teacher\'s class', 'get', lambda state: '/programs?user=' + state ['student'] ['username'], {}, {}, 403],
         ['login as student', 'post', '/auth/login', {}, {'username': 'student-' + username, 'password': 'foobar'}, 200],
         ['get profile after being removed from class', 'get', '/profile', {}, {}, 200, getStudentClasses2],