From 8e978dcf4d606272b093dec7eb4b46dd5a96ceed Mon Sep 17 00:00:00 2001
From: Alexandre Aubin <alex.aubin@mailoo.org>
Date: Fri, 1 Sep 2023 21:57:21 +0200
Subject: [PATCH] appstore: display unusual ram requirement, arch limitation,
 pre-install notes, emojis

---
 store/app.py              | 30 ++++++++++++++++++++++++++++--
 store/requirements.txt    |  1 +
 store/templates/app.html  | 23 +++++++++++++++++++----
 store/templates/base.html |  3 +++
 4 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/store/app.py b/store/app.py
index 364a9d1..e5b2210 100644
--- a/store/app.py
+++ b/store/app.py
@@ -13,6 +13,7 @@ import sys
 from slugify import slugify
 from flask import Flask, send_from_directory, render_template, session, redirect, request
 from github import Github, InputGitAuthor
+from emoji import emojize
 
 locale = "en"
 app = Flask(__name__, static_url_path='/assets', static_folder="assets")
@@ -72,6 +73,28 @@ wishlist = toml.load(open("../wishlist.toml"))
 app.secret_key = ''.join([str(random.randint(0, 9)) for i in range(99)])
 
 
+def human_to_binary(size: str) -> int:
+    symbols = ("K", "M", "G", "T", "P", "E", "Z", "Y")
+    factor = {}
+    for i, s in enumerate(symbols):
+        factor[s] = 1 << (i + 1) * 10
+
+    suffix = size[-1]
+    size = size[:-1]
+
+    if suffix not in symbols:
+        raise YunohostError(
+            f"Invalid size suffix '{suffix}', expected one of {symbols}"
+        )
+
+    try:
+        size_ = float(size)
+    except Exception:
+        raise YunohostError(f"Failed to convert size {size} to float")
+
+    return int(size_ * factor[suffix])
+
+
 @app.route('/favicon.ico')
 def favicon():
     return send_from_directory('assets', 'favicon.png')
@@ -138,7 +161,7 @@ def app_info(app_id):
         description_path = None
     if description_path:
         with open(description_path) as f:
-            infos["full_description_html"] = pycmarkgfm.gfm_to_html(f.read())
+            infos["full_description_html"] = emojize(pycmarkgfm.gfm_to_html(f.read()), language="alias")
     else:
         infos["full_description_html"] = infos['manifest']['description'][locale]
 
@@ -150,7 +173,7 @@ def app_info(app_id):
         pre_install_path = None
     if pre_install_path:
         with open(pre_install_path) as f:
-            infos["pre_install_html"] = pycmarkgfm.gfm_to_html(f.read())
+            infos["pre_install_html"] = emojize(pycmarkgfm.gfm_to_html(f.read()), language="alias")
 
     infos["screenshot"] = None
 
@@ -168,6 +191,9 @@ def app_info(app_id):
                         ] = f"data:image/{ext};charset=utf-8;base64,{data}"
                     break
 
+    ram_build_requirement = infos["manifest"]["integration"]["ram"]["build"]
+    infos["manifest"]["integration"]["ram"]["build_binary"] = human_to_binary(ram_build_requirement)
+
     return render_template("app.html", user=session.get('user', {}), app_id=app_id, infos=infos, catalog=catalog)
 
 
diff --git a/store/requirements.txt b/store/requirements.txt
index a982909..996af51 100644
--- a/store/requirements.txt
+++ b/store/requirements.txt
@@ -4,3 +4,4 @@ PyGithub
 toml
 pycmarkgfm
 gunicorn
+emoji
diff --git a/store/templates/app.html b/store/templates/app.html
index 78be075..a6c5420 100644
--- a/store/templates/app.html
+++ b/store/templates/app.html
@@ -62,16 +62,31 @@
     <div class="from-markdown">{{ infos["full_description_html"]|safe }}</div>
 
     {% if infos["screenshot"] %}
-    <img src="{{ infos["screenshot"] }}" />
+    <img class="my-3" src="{{ infos["screenshot"] }}" />
     {% endif %}
 
+    {% if infos["manifest"]["integration"]["architectures"] != "all" %}
+     <div class="my-3 rounded-md bg-orange-200 text-orange-800 px-5 py-2">
+         <i class="fa fa-exclamation-triangle fa-fw"></i> This app is only compatible with these specific architectures : {{ infos["manifest"]["integration"]["architectures"]|join(', ') }}
+    </div>
+    {% endif %}
 
-    <p>{{ infos["manifest"]["integration"] }}</p>
-    <div class="from-markdown">{{ infos["pre_install_html"] | safe }}</div>
+    {% if infos["manifest"]["integration"]["ram"]["build_binary"] >= 500 * 1024 * 1024 %}
+     <div class="my-3 rounded-md bg-orange-200 text-orange-800 px-5 py-2">
+         <i class="fa fa-exclamation-triangle fa-fw"></i> This app requires an unusual amount of RAM to build : {{ infos["manifest"]["integration"]["ram"]["build"] }}
+    </div>
+    {% endif %}
+
+    {% if infos["pre_install_html"] %}
+    <div class="my-3 rounded-md bg-blue-200 text-blue-800 px-5 py-2">
+        <h3 class="inline-block text-xl mb-2 font-semibold">Important infos before installing</h3>
+        <div class="from-markdown">{{ infos["pre_install_html"] | safe }}</div>
+    </div>
+    {% endif %}
 
     {% if infos["antifeatures"] %}
     <h3 class="inline-block text-xl mb-2 font-semibold">Anti-features</h3> <p class="inline-block text-sm">(This app has features you may not like)</p>
-    <div class="mb-3 rounded-md bg-red-200 text-red-800 px-5 py-2">
+    <div class="my-3 rounded-md bg-red-200 text-red-800 px-5 py-2">
         <ul>
         {% for antifeature in infos["antifeatures"] %}
             <li class="mb-1"><i class="fa fa-{{ catalog['antifeatures'][antifeature]['icon'] }} fa-fw" aria-hidden="true"></i> {{ catalog['antifeatures'][antifeature]['description'][locale] }}</li>
diff --git a/store/templates/base.html b/store/templates/base.html
index 20ed772..1f643e8 100644
--- a/store/templates/base.html
+++ b/store/templates/base.html
@@ -40,6 +40,9 @@
           padding: revert;
           list-style: disc;
       }
+      .from-markdown a {
+          @apply text-blue-600;
+      }
     }
     </style>
   </head>