internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: hedyorg/hedy

Issue:
[UI idea] Make logout button accesible from every page
**Idea incl level**
Currently there is a "login" button in the menubar, being accessible for every page on the website. However, when logged in this button is replaced by the "my programs" button. To logout we have to navigate to "my profile" and then use the logout button. I propose to implement a logout button within the menu-bar, making it clearly visible to the user.   I create a simple mock-up as example, which can be found in the screenshots below. However, it might be nice to do some menubar styling together with this button implementation.


**Additional context: Proposed new UI design**
![Schermafbeelding 2021-11-02 om 19 45 43](https://user-images.githubusercontent.com/38155424/139926025-d0214f2d-b223-4887-b778-926f403d385d.png)
![Schermafbeelding 2021-11-02 om 19 45 54](https://user-images.githubusercontent.com/38155424/139926037-7308b4eb-3232-475a-bb18-a4e2da6ca295.png)




Discussion:
It seems `app.ts` is not accessible on the homepage, making it impossible to logout. This should be looked at first before attempting to implement this UI change.
I thought about this a bit more and I like this idea but I think ultimately we want something more like all websites have where the login button changes into a button with a persons username linking to their profile. But updating that part of the site for now is not all that important.

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -1007,7 +1007,8 @@ def main_page(page):
             session.pop('welcome-teacher', None)
             teacher_classes = [] if not current_user()['username'] else DATABASE.get_teacher_classes(
                 current_user()['username'], True)
-            return render_template('for-teachers.html', page_title=hedyweb.get_page_title(page),
+            return render_template('for-teachers.html', current_page='my-profile',
+                                   page_title=hedyweb.get_page_title(page),
                                    content=for_teacher_translations, teacher_classes=teacher_classes,
                                    welcome_teacher=welcome_teacher)
         else:


Test patch:
Repository: hedyorg/hedy

Issue:
[BUG] Not equals does not support quoted text
**Describe the bug**
Quoted strings should be supported in comparisons (according to the grammar), but they generate invalid python code.

**Paste the Hedy code & level**
Level 14
```
if 'a' != 'b'
    print 'You are younger than me!'
else
    print 'You are older than me!'
```

**Add a screenshot (optional)**
![Screenshot 2021-12-15 at 11 54 03](https://user-images.githubusercontent.com/3010723/146164519-638149d3-9712-4520-a6b5-7eadfd61d6c3.png)


**Expected behavior**
The text 'You are younger than me!' is printed in the output screen :)

**What machine and browser you were using (optional)**
If the issue concerns things in the website, let us know:
- What computer you are using (Windows, Mac, Linux?)
- What browser you were using (Chrome, Edge, Safari)



Discussion:

Resolving patch:
diff --git a/hedy.py b/hedy.py
--- a/hedy.py
+++ b/hedy.py
@@ -919,6 +919,8 @@ def process_variable_for_fstring_padded(name, lookup):
         return f"str({hash_var(name)}).zfill(100)"
     elif is_float(name):
         return f"str({name}).zfill(100)"
+    elif is_quoted(name):
+        return f"{name}.zfill(100)"
     else:
         return f"'{name}'.zfill(100)"
 


Test patch:
diff --git a/tests/test_level_14.py b/tests/test_level_14.py
--- a/tests/test_level_14.py
+++ b/tests/test_level_14.py
@@ -97,6 +97,7 @@ def test_comparison_with_string_gives_type_error(self, comparison):
       exception=hedy.exceptions.InvalidArgumentTypeException
     )
 
+
   @parameterized.expand(HedyTester.number_comparisons_commands)
   def test_comparison_with_list_gives_type_error(self, comparison):
     code = textwrap.dedent(f"""\
diff --git a/tests/test_level_17.py b/tests/test_level_17.py
--- a/tests/test_level_17.py
+++ b/tests/test_level_17.py
@@ -287,6 +287,15 @@ def test_smaller_with_string_gives_type_error(self, comparison):
       exception=hedy.exceptions.InvalidArgumentTypeException
     )
 
+
+  def test_not_equal_string_literal(self):
+    code = textwrap.dedent(f"""\
+      if 'quoted' != 'string':
+        sleep 0""")
+    expected = textwrap.dedent(f"""\
+      if 'quoted'.zfill(100)!='string'.zfill(100):
+        time.sleep(0)""")
+
   @parameterized.expand(["'text'", '1', '1.3', '[1, 2]'])
   def test_not_equal(self, arg):
     code = textwrap.dedent(f"""\
Repository: hedyorg/hedy

Issue:
Check for duplicate grammar rules
In https://github.com/Felienne/hedy/pull/1556 I removed a duplicate grammar rule. Would be nice if we could check, while merging, whether an exact rule is there already and warn for that.


Discussion:
I'll take this one :)

Resolving patch:
diff --git a/hedy.py b/hedy.py
--- a/hedy.py
+++ b/hedy.py
@@ -5,6 +5,7 @@
 from lark import Tree, Transformer, visitors, v_args
 from os import path, environ
 
+import warnings
 import hedy
 import utils
 from collections import namedtuple
@@ -1709,7 +1710,7 @@ def input(self, args):
 
 
 
-def merge_grammars(grammar_text_1, grammar_text_2):
+def merge_grammars(grammar_text_1, grammar_text_2, level):
     # this function takes two grammar files and merges them into one
     # rules that are redefined in the second file are overridden
     # rule that are new in the second file are added (remaining_rules_grammar_2)
@@ -1733,6 +1734,9 @@ def merge_grammars(grammar_text_1, grammar_text_2):
             name_2, definition_2 = parts[0], ''.join(parts[1]) #get part before are after :
             if name_1 == name_2:
                 override_found = True
+                if definition_1.strip() == definition_2.strip():
+                    warn_message = f"The rule {name_1} is duplicated on level {level}. Please check!"
+                    warnings.warn(warn_message)
                 # Check if the rule is adding or substracting new rules                
                 has_add_op  = definition_2.startswith('+=') 
                 has_sub_op = has_add_op and '-='  in definition_2
@@ -1792,11 +1796,11 @@ def create_grammar(level, lang="en"):
     # start with creating the grammar for level 1
     result = get_full_grammar_for_level(1)
     keys = get_keywords_for_language(lang)
-    result = merge_grammars(result, keys)
+    result = merge_grammars(result, keys, 1)
     # then keep merging new grammars in
     for i in range(2, level+1):
         grammar_text_i = get_additional_rules_for_level(i)
-        result = merge_grammars(result, grammar_text_i)
+        result = merge_grammars(result, grammar_text_i, i)
 
     # ready? Save to file to ease debugging
     # this could also be done on each merge for performance reasons


Test patch:
Repository: hedyorg/hedy

Issue:
[BUG] Program doesn't correctly change visually when submitted
**Describe the bug**
Currently when we submit a program the user receives no feedback if their submission was successful. This issue might occur due to #1628 where we re-write the programs page structure to prevent re-loading to update user information. The program is correctly submitted in the back-end but not on the front-end (yet). With the additional issue that now the submitting achievements are not correctly shown to the user.

**Expected behavior**
When submitting a program the program box on the programs page should change visually and show the submission achievement if received.



Discussion:

Resolving patch:
diff --git a/website/achievements.py b/website/achievements.py
--- a/website/achievements.py
+++ b/website/achievements.py
@@ -109,7 +109,7 @@ def verify_save_achievements(self, username, adventure=None):
     def verify_submit_achievements(self, username):
         if not session['achieved']:
             self.initialize_user_data(username)
-        self.check_programs_submitted(session['submitted_programs'])
+        self.check_programs_submitted()
 
         if len(session['new_achieved']) > 0:
             self.DATABASE.add_achievements_to_username(username, session['new_achieved'])


Test patch:
Repository: hedyorg/hedy

Issue:
[BUG] wrong "go back to main page" redirect at quiz end  
**Describe the bug**
At the end of a quiz, the "go back to main page" button redirects inside the iframe and creates a nested page view.
When the quiz is empty (in the French version) the user directly lands on this page.

URL: https://www.hedycode.com/hedy#end

**Add a screenshot (optional)**
![Screenshot 2022-01-11 at 09 21 44](https://user-images.githubusercontent.com/22364279/148906542-78c9f3ea-9c51-4da6-b9bf-a9e4e541089f.png)
![Screenshot 2022-01-11 at 09 21 49](https://user-images.githubusercontent.com/22364279/148906557-3fc3e4b1-da53-4f6a-976e-a52b1626e78d.png)

**Expected behavior**
The main page should be reloaded instead of just the quiz subpage.


[BUG] wrong "go back to main page" redirect at quiz end  
**Describe the bug**
At the end of a quiz, the "go back to main page" button redirects inside the iframe and creates a nested page view.
When the quiz is empty (in the French version) the user directly lands on this page.

URL: https://www.hedycode.com/hedy#end

**Add a screenshot (optional)**
![Screenshot 2022-01-11 at 09 21 44](https://user-images.githubusercontent.com/22364279/148906542-78c9f3ea-9c51-4da6-b9bf-a9e4e541089f.png)
![Screenshot 2022-01-11 at 09 21 49](https://user-images.githubusercontent.com/22364279/148906557-3fc3e4b1-da53-4f6a-976e-a52b1626e78d.png)

**Expected behavior**
The main page should be reloaded instead of just the quiz subpage.




Discussion:

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -1016,11 +1016,11 @@ def is_quiz_enabled():
 
 
 def quiz_disabled_error():
-    return utils.page_404('Hedy quiz disabled!', menu=False)
+    return utils.page_404('Hedy quiz disabled!', menu=False, iframe=True)
 
 
 def no_quiz_data_error():
-    return utils.page_404('No quiz data found for this level', menu=False)
+    return utils.page_404('No quiz data found for this level', menu=False, iframe=True)
 
 
 # routing to index.html
diff --git a/utils.py b/utils.py
--- a/utils.py
+++ b/utils.py
@@ -203,8 +203,8 @@ def markdown_to_html_tags(markdown):
 def page_403(page_error=None, ui_message=None, menu=True):
     return render_template("403.html", menu=menu, page_error=page_error or g.ui_texts.get(ui_message) or ''), 403
 
-def page_404(page_error=None, ui_message=None, menu=True):
-    return render_template("404.html", menu=menu, page_error=page_error or g.ui_texts.get(ui_message) or ''), 404
+def page_404(page_error=None, ui_message=None, menu=True, iframe=None):
+    return render_template("404.html", menu=menu, iframe=iframe, page_error=page_error or g.ui_texts.get(ui_message) or ''), 404
 
 def page_500(page_error=None, ui_message=None, menu=True):
     return render_template("500.html", menu=menu, page_error=page_error or g.ui_texts.get(ui_message) or ''), 500


Test patch:
Repository: hedyorg/hedy

Issue:
[BUG] Achievements are stored double in the database
**Describe the bug**
For some unknown reason we store achievements double, resulting in duplicate values. The issue occurs when we achieve new achievements and within the same session achieve some new achievements. At the second point the first achievements are stored again resulting in duplicate values. The cause is currently unknown and the issue is temporary solved by parsing the achievements into a dict and back to a list to automatically remove duplicates. However, this is undesirable and a real fix should be found.

**Expected behavior**
When achieving new achievements we only store the currently achievement onces.



Discussion:

Resolving patch:
diff --git a/website/database.py b/website/database.py
--- a/website/database.py
+++ b/website/database.py
@@ -341,7 +341,6 @@ def add_achievement_to_username(self, username, achievement):
             user_achievements['achieved'] = []
         if achievement not in user_achievements['achieved']:
             user_achievements['achieved'].append(achievement)
-            user_achievements['achieved'] = list(dict.fromkeys(user_achievements['achieved']))
             ACHIEVEMENTS.put(user_achievements)
 
     def add_achievements_to_username(self, username, achievements):


Test patch:
Repository: hedyorg/hedy

Issue:
[BUG] Sleep gives error that the code takes too long to run
**Describe the bug**
If you use sleep for more than 2 seconds it says the program takes too long to run. It happens when using sleep 3 or two times sleep 2 etc. 

**Paste the Hedy code & level**
![image](https://user-images.githubusercontent.com/80678586/149292431-83e3e774-e66f-4693-a50e-518863d94fb1.png)




Discussion:
I know the cause of this! We have a check on the front-end to prevent programs that are too long from running indefinitely (and possibly crashing the browser). If I remember correctly this value I set to 3 seconds for textual programming and 20 seconds when using the turtle. Will take a look If we can implement it so to skip this check when using `sleep`.
@TiBiBa You also get a new compliment each time after the sleep command is executed, like you've made multiple codes. Not that that's bad, but it is kinda strange.

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -485,13 +485,16 @@ def parse():
                 response['Code'] = NORMAL_PREFIX_CODE + transpile_result.code
         except:
             pass
-
+        try:
+            if 'sleep' in hedy.all_commands(code, level, lang):
+                response['has_sleep'] = True
+        except:
+            pass
         try:
             if username and ACHIEVEMENTS.verify_run_achievements(username, code, level, response):
                 response['achievements'] = ACHIEVEMENTS.get_earned_achievements()
         except Exception as E:
             print(f"error determining achievements for {code} with {E}")
-
     except hedy.exceptions.HedyException as ex:
         traceback.print_exc()
         response = hedy_error_to_response(ex, hedy_errors)


Test patch:
Repository: hedyorg/hedy

Issue:
[UI idea] Support right-to-left languages on front-end
**Idea incl level**
This might be a challenging project, but the goal is to support a right-to-left view for languages that write/read from right-to-left. As mentioned by @Felienne there is a tailwind package that might be able to help a lot: https://www.npmjs.com/package/tailwindcss-rtl.


Discussion:

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -272,6 +272,13 @@ def setup_language():
         session['lang'] = request.accept_languages.best_match(ALL_LANGUAGES.keys(), 'en')
     g.lang = session['lang']
 
+    # Set the page direction -> automatically set it to "left-to-right"
+    # Switch to "right-to-left" if one of the language in the list is selected
+    # This is the only place to expand / shrink the list of RTL languages -> front-end is fixed based on this value
+    g.dir = "ltr"
+    if g.lang in ['ar', 'he', 'ur']:
+        g.dir = "rtl"
+
     # Check that requested language is supported, otherwise return 404
     if g.lang not in ALL_LANGUAGES.keys():
         return "Language " + g.lang + " not supported", 404


Test patch:
Repository: hedyorg/hedy

Issue:
[BUG] Teacher's link copied incompletely
**Describe the bug**
Link for teachers only copies second half of the link (f.e. /hedy/l/123456)





Discussion:

Resolving patch:
diff --git a/website/teacher.py b/website/teacher.py
--- a/website/teacher.py
+++ b/website/teacher.py
@@ -64,7 +64,7 @@ def get_class (user, class_id):
                                 page_title=hedyweb.get_page_title('class overview'),
                                 achievement=achievement,
                                 is_beta_teacher=is_beta_teacher,
-                                class_info={'students': students, 'link': '/hedy/l/' + Class ['link'],
+                                class_info={'students': students, 'link': os.getenv('BASE_URL') + '/hedy/l/' + Class ['link'],
                                             'name': Class ['name'], 'id': Class ['id']})
 
     @app.route('/class', methods=['POST'])


Test patch:
Repository: hedyorg/hedy

Issue:
[UI IDEA] Filter on email address in admin page
It'd also be really nice if we can filter on email addresses (f.e. all email addresses of "school5" with a simple string matching pattern)

_Originally posted by @Felienne in https://github.com/Felienne/hedy/issues/1740#issuecomment-1018567446_
[UI IDEA] Option to show all users in admin page


_Originally posted by @Felienne in https://github.com/Felienne/hedy/pull/1740#discussion_r789718334_


Discussion:

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -1193,15 +1193,18 @@ def get_admin_page():
         return 'unauthorized', 403
 
     category = request.args.get('filter', default=None, type=str)
+    category = None if category == "null" else category
+
+    substring = request.args.get('substring', default=None, type=str)
     start_date = request.args.get('start', default=None, type=str)
     end_date = request.args.get('end', default=None, type=str)
 
-    filter = None if category == "null" else category
+    substring = None if substring == "null" else substring
     start_date = None if start_date == "null" else start_date
     end_date = None if end_date == "null" else end_date
 
     filtering = False
-    if start_date or end_date:
+    if substring or start_date or end_date or category == "all":
         filtering = True
 
     # After hitting 1k users, it'd be wise to add pagination.
@@ -1214,12 +1217,15 @@ def get_admin_page():
         data['email_verified'] = not bool(data['verification_pending'])
         data['is_teacher'] = bool(data['is_teacher'])
         data['created'] = utils.datetotimeordate (utils.mstoisostring(data['created'])) if data['created'] else '?'
-        if filtering and filter == "created":
+        if filtering and category == "email":
+            if substring not in data['email']:
+                continue
+        if filtering and category == "created":
             if (start_date and utils.datetotimeordate(start_date) >= data['created']) or (end_date and utils.datetotimeordate(end_date) <= data['created']):
                 continue
         if data['last_login']:
             data['last_login'] = utils.datetotimeordate(utils.mstoisostring(data['last_login'])) if data['last_login'] else '?'
-            if filtering and filter == "last_login":
+            if filtering and category == "last_login":
                 if (start_date and utils.datetotimeordate(start_date) >= data['last_login']) or (end_date and utils.datetotimeordate(end_date) <= data['last_login']):
                     continue
         userdata.append(data)
@@ -1231,7 +1237,7 @@ def get_admin_page():
         counter = counter + 1
 
     return render_template('admin.html', users=userdata, page_title=hedyweb.get_page_title('admin'),
-                           filter=filter, start_date=start_date, end_date=end_date,
+                           filter=category, start_date=start_date, end_date=end_date, email_filter=substring,
                            program_count=DATABASE.all_programs_count(), user_count=DATABASE.all_users_count())
 
 


Test patch:
Repository: hedyorg/hedy

Issue:
[UI idea] Improve pre-join class UI
**Idea incl level**
Currently the pre-join page of a class is nothing more than plain-text with a link. It would be nice to improve the UI a bit to better align with the rest of the Hedy website. See the screenshot below for the current situation:

![Schermafbeelding 2022-01-24 om 13 22 28](https://user-images.githubusercontent.com/38155424/150782347-2c230948-6284-4396-bf97-a9d9b5ebc32b.png)


Discussion:

Resolving patch:
diff --git a/website/teacher.py b/website/teacher.py
--- a/website/teacher.py
+++ b/website/teacher.py
@@ -152,16 +152,18 @@ def prejoin_class (class_id, link):
             token = DATABASE.get_token(request.cookies.get (cookie_name))
             if token:
                 if token ['username'] in Class.get ('students', []):
-                    return render_template ('class-already-joined.html', page_title=hedyweb.get_page_title('join class'),
+                    return render_template ('class-prejoin.html', joined=True,
+                                            page_title=hedyweb.get_page_title('join class'),
                                             current_page='my-profile', class_info={'name': Class ['name']})
                 user = DATABASE.user_by_username(token ['username'])
 
-        return render_template ('class-prejoin.html', page_title=hedyweb.get_page_title('join class'),
-            current_page='my-profile',
-            class_info={
-                'id': Class ['id'],
-                'name': Class ['name'],
-            })
+        return render_template ('class-prejoin.html', joined=False,
+                                page_title=hedyweb.get_page_title('join class'),
+                                current_page='my-profile',
+                                class_info={
+                                    'id': Class ['id'],
+                                    'name': Class ['name'],
+                                })
 
     @app.route('/class/join', methods=['POST'])
     @requires_login


Test patch:
Repository: hedyorg/hedy

Issue:
[UI idea] Enable users to visit public profile by clicking username on explore page
**Idea incl level**
With the implementation of the explore page and the nearly finished public profiles it would be nice if we would link these together. Enabling users to visit public profile by clicking on the username when viewing a public program. It would be even better if this username is only clickable if there is a profile, otherwise not. Especially in the beginning most users won't have created a profile yet resulting in a lot of 404 re-directs.



Discussion:

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -1216,9 +1216,10 @@ def explore():
     for program in programs:
         program['code'] = "\n".join(program['code'].split("\n")[:4])
 
-    adventures = None
     if hedy_content.Adventures(session['lang']).has_adventures():
         adventures = hedy_content.Adventures(session['lang']).get_adventure_keyname_name_levels()
+    else:
+        adventures = hedy_content.Adventures("en").get_adventure_keyname_name_levels()
 
     return render_template('explore.html', programs=programs,
                            filtered_level=level,
@@ -1650,7 +1651,8 @@ def update_yaml():
 
 
 @app.route('/user/<username>')
-def public_user_page(username):
+@requires_login
+def public_user_page(user, username):
     user = DATABASE.user_by_username(username.lower())
     if not user:
         return utils.error_page(error=404, ui_message='user_not_private')
@@ -1669,6 +1671,8 @@ def public_user_page(username):
         if 'achieved' in user_achievements:
             last_achieved = user_achievements['achieved'][-1]
 
+        # Todo: TB -> In the near future: add achievement for user visiting their own profile
+
         return render_template('public-page.html', user_info=user_public_info,
                                favourite_program=favourite_program,
                                programs=user_programs,


Test patch: