Repository: hedyorg/hedy

Issue:
[UI idea] Make public overview of all shared programs
Also related to #1573, make a public version here kids can browse all shared programs, like Scratch has:

![image](https://user-images.githubusercontent.com/1003685/147063787-37a9fa75-2b1e-4f28-9d71-15d32b048218.png)

Guess we have to think about if we also want thumbnails or just links (guess just links is totally fine for now)


Discussion:
I really like this idea! I think it is relatively easy to implement this in a dedicated "explore" page. We have one edge case to consider: A submitted program is also a shared program; but I assume it is undesirable that these are available on this page as well.
Yeah I like it too, I think one of our "big hairy goals" for 2022 should be to turn Hedy more into a community where kids can also learn from and get inspired by each other (fit also with your plan to make public user profiles!)
> I really like this idea! I think it is relatively easy to implement this in a dedicated "explore" page. We have one edge case to consider: A submitted program is also a shared program; but I assume it is undesirable that these are available on this page as well.

Ah interesting point! Guess we might not want to because then kids can "spiek" each others work (however, I guess they will find ways to share the programs via whatapp or email haha)

I am ok with not treating them as a special case for now to keep things simple.
It might be nice to align this with the public profile and public high score page? Will create quite a big issue, but we have to ask user consent for all of these anyway. Or are we already allowed to show all shared programs? In that case we can implement this one first and then take a look at the other possible public pages.

Resolving patch:
diff --git a/app.py b/app.py
--- a/app.py
+++ b/app.py
@@ -787,6 +787,7 @@ def get_log_results():
     return jsonify(response)
 
 
+
 def get_user_formatted_age(now, date):
     texts = TRANSLATIONS.get_translations(g.lang, 'Programs')
     program_age = now - date
@@ -1212,6 +1213,35 @@ def main_page(page):
                            content=main_page_translations)
 
 
+@app.route('/explore', methods=['GET'])
+def explore():
+    level = request.args.get('level', default=None, type=str)
+    adventure = request.args.get('adventure', default=None, type=str)
+
+    level = None if level == "null" else level
+    adventure = None if adventure == "null" else adventure
+
+    if level or adventure:
+        programs = DATABASE.get_filtered_explore_programs(level, adventure)
+    else:
+        programs = DATABASE.get_all_explore_programs()
+
+    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()
+
+    return render_template('explore.html', programs=programs,
+                           filtered_level=level,
+                           filtered_adventure=adventure,
+                           max_level=hedy.HEDY_MAX_LEVEL,
+                           adventures=adventures,
+                           page_title=hedyweb.get_page_title('explore'),
+                           current_page='explore')
+
+
 @app.route('/change_language', methods=['POST'])
 def change_language():
     body = request.json
diff --git a/website/database.py b/website/database.py
--- a/website/database.py
+++ b/website/database.py
@@ -191,6 +191,34 @@ def all_users(self):
         """Return all users."""
         return USERS.scan()
 
+    def get_all_explore_programs(self):
+        programs = PROGRAMS.scan()
+        public_programs = []
+        for program in programs:
+            if 'public' in program:
+                public_programs.append(program)
+        return public_programs
+
+    def get_filtered_explore_programs(self, level=None, adventure=None):
+        programs = PROGRAMS.scan()
+        result = []
+        for program in programs:
+            if 'public' in program:
+                result.append(program)
+        level_programs = []
+        if level:
+            for program in result:
+                if program['level'] == int(level):
+                    level_programs.append(program)
+            result = level_programs
+        adventure_programs = []
+        if adventure:
+            for program in result:
+                if 'adventure_name' in program and program['adventure_name'] == adventure:
+                    adventure_programs.append(program)
+            result = adventure_programs
+        return result
+
     def all_programs_count(self):
         """Return the total number of all programs."""
         return PROGRAMS.item_count()
@@ -320,7 +348,6 @@ def get_student_restrictions(self, all_adventures, user, level):
             restrictions['hide_level'] = False
             restrictions['hide_prev_level'] = False
             restrictions['hide_next_level'] = False
-
         return display_adventures, restrictions
 
     def progress_by_username(self, username):
@@ -404,4 +431,4 @@ def parse_date(self, d, default):
 
     def to_year_week(self, d):
         cal = d.isocalendar()
-        return f'{cal[0]}-{cal[1]}'
+        return f'{cal[0]}-{cal[1]}'
\ No newline at end of file


Test patch: