[Gruppo-web] [Git][ubuntu-it-web/www][develop] 20 commits: rm downloads.toml and added in gitignore

Mattia Rizzolo gitlab a code.ubuntu-it.org
Lun 6 Nov 2023 11:18:00 GMT



Mattia Rizzolo pushed to branch develop at Gruppo Web / Nuovo sito


Commits:
4a7cc433 by Mattia at 2023-10-25T14:06:22+02:00
rm downloads.toml and added in gitignore

- - - - -
ae454aa7 by Mattia at 2023-10-25T14:06:22+02:00
added debug param to dont create downloads.cache

Fixes: #15

init _mirrors and _sha256sums in Downloads() to fix inspector warning

- - - - -
898c0feb by Mattia at 2023-10-25T14:06:22+02:00
added src folder

added costants.json with the list of with the desired distros and relative descriptions

added compile_download to compile downloads.toml in './data/'

Fixes: #14

- - - - -
73dfc935 by Mattia at 2023-10-25T14:06:22+02:00
added compile_download.CompileVersion() in init command to compile to compile downloads.toml

added debug option in init command to not write downloads.cache

added debug in uitwww.create_app() in run command

- - - - -
e13f65da by Mattia at 2023-11-02T22:42:36+01:00
replaced old 'self.config[releases]' with new 'self.config[distros][distro][archs][arch]'
to get determinate dict with all the required keys due to the latest changes in downloads.toml

replaced md5 with sha256 and http with https

Fixes: #16

- - - - -
077430d8 by Mattia at 2023-11-02T22:42:37+01:00
reformat html

- - - - -
19be065b by Mattia at 2023-11-02T22:42:37+01:00
added UbuntuRelease() to get list of all versions

replaced CompileVersion().get_list_version with self.list_version

- - - - -
eaf902ee by Mattia at 2023-11-02T22:42:37+01:00
mv downloads.toml in data/

- - - - -
b63d5225 by Mattia at 2023-11-02T22:42:37+01:00
replaced 'POWER' with 'PowerPC64'

- - - - -
7a31eb04 by Mattia at 2023-11-03T08:55:25+01:00
split init_data_directory() in:
    - init_data_directory to create data dir
    - init_data_downloads to populate download page

- - - - -
b1eee15e by Mattia at 2023-11-04T15:38:15+01:00
replaced UITWWW_DIR with data_path in Downloads().__init__

replaced BASE_DIR with data_path in main.init

- - - - -
02b48162 by Mattia at 2023-11-04T22:00:29+01:00
rename row_list() with get_table_rows() to get all table rows

now get_list_version() return sort list

- - - - -
b087bec5 by Mattia at 2023-11-04T22:01:20+01:00
replaced ignore_lts and ignore_interim with ignore_version

- - - - -
d0dd48b2 by Mattia at 2023-11-04T22:04:20+01:00
reformat to get a one-time distro

- - - - -
2de0af53 by Mattia at 2023-11-04T22:05:29+01:00
mv ARM64 and PPC64EL in 'add_archs' key in costants.json

- - - - -
d5a1f850 by Mattia at 2023-11-04T22:09:49+01:00
replaced ver_interim with ver_latest to get the latest version

now ver_interim_list and ver_lts_list get up all versions and take relative interim and LTS

- - - - -
4b18761e by Mattia at 2023-11-04T22:15:28+01:00
populate_archs_releases() populate 'latest' key and if it's not a LTS get up latest LTS version

mv populate_archs_releases() before get_releases()

- - - - -
910cd692 by Mattia at 2023-11-04T22:16:31+01:00
added typology in get_releases() return

added get_releases() docs param

- - - - -
8bfb2ec0 by Mattia at 2023-11-04T22:16:51+01:00
quick docs

- - - - -
5fe66770 by Mattia Rizzolo at 2023-11-06T13:17:26+02:00
Merge remote-tracking branch 'origin/dev-shadmod-01-debug-downloads-versions' into develop

MR: https://code.ubuntu-it.org/ubuntu-it-web/www/-/merge_requests/48
Signed-off-by: Mattia Rizzolo <mapreri a ubuntu.com>

- - - - -


9 changed files:

- uitwww/__init__.py
- − uitwww/data/downloads.toml
- uitwww/download.py
- uitwww/main.py
- + uitwww/src/__init__.py
- + uitwww/src/download/__init__.py
- + uitwww/src/download/assets/constants.json
- + uitwww/src/download/compile_download.py
- uitwww/templates/download/thanks.html


Changes:

=====================================
uitwww/__init__.py
=====================================
@@ -1,5 +1,6 @@
 # Source code of the Ubuntu-it website
 # Copyright (C) 2015-2018  Pietro Albini <pietroalbini a ubuntu.com>
+# Copyright (C) 2023       shadMod
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published
@@ -29,7 +30,7 @@ from . import redirects
 from . import utils
 
 
-def create_app(data_path):
+def create_app(data_path, debug=False):
     """Create a new instance of the application"""
     # Normalize the data path
     data_path = os.path.expanduser(os.path.abspath(data_path))
@@ -44,8 +45,8 @@ def create_app(data_path):
     init_data_directory(data_path)
 
     # Load the secret key
-    with open(os.path.join(data_path, "secret_key")) as f:
-        app.secret_key = f.read().strip()
+    with open(os.path.join(data_path, "secret_key")) as fn:
+        app.secret_key = fn.read().strip()
 
     # Initialize the database
     app.db = db.Database(os.path.join(data_path, "database.db"))
@@ -79,14 +80,14 @@ def create_app(data_path):
     return app
 
 
-def init_data_directory(data_path):
+def init_data_directory(data_path: str):
     """Initialize the data directory"""
     src_directory = os.path.dirname(os.path.abspath(__file__))
 
     # Create all the directories
     dirs = ["", "cache"]
-    for dir in dirs:
-        os.makedirs(os.path.join(data_path, dir), exist_ok=True)
+    for _dir in dirs:
+        os.makedirs(os.path.join(data_path, _dir), exist_ok=True)
 
     # Initialize the cache
     static_dirs = {"static": "+assets"}
@@ -105,6 +106,10 @@ def init_data_directory(data_path):
             f.write("%s\n" % utils.random_key(64))
         os.chmod(secret_key_path, 0o400)
 
+
+def init_data_downloads(data_path, debug=False):
     # Initialize the download files
-    download_inst = download.Downloads(data_path)
-    download_inst.store_cache_file()
+    download_inst = download.Downloads(data_path, debug=debug)
+    if debug is False:
+        # mk cache file
+        download_inst.store_cache_file()


=====================================
uitwww/data/downloads.toml deleted
=====================================
@@ -1,164 +0,0 @@
-# Configurazione delle release disponibili
-# Quando viene rilasciata una release o una point release è solamente
-# necessario aggiornare questa sezione.
-
-[releases.latest]
-version = "21.10"
-codename = "impish"
-lts = false
-
-[releases.lts]
-version = "22.04.3"
-codename = "jammy"
-lts = true
-
-
-
-# Distribuzioni disponibili per il download
-# Tutte le pagine in /download sono generate automaticamente da questa lista.
-#
-# name:               Il nome della distro
-# description:        Una breve descrizione della distro
-# lts-support-years:  Il numero di anni per cui la LTS è supportata
-# lts-only:           Se impostato a `true`, solo le LTS verranno offerte
-# releases:           Una lista di release da offrire -- viene filtrata da lts-only
-# archs:              Una tabella di architettura e sorgente delle ISO
-#
-# Se è necessario sovrascrivere la sorgente delle ISO per una singola coppia
-# release-architettura, è possibile aggiungere la chiave:
-#
-#    source-override-RELEASE-ARCH = "SOURCE"
-
-
-[distros.desktop]
-name = "Ubuntu"
-description = "L'originale, con GNOME"
-lts-support-years = 5
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "releases-ubuntu" }
-
-
-[distros.live-server]
-name = "Ubuntu Server"
-description = "Tutta la potenza di Ubuntu nel tuo server"
-lts-support-years = 5
-
-lts-only = true
-releases = ["lts", "latest"]  # Invertiti intenzionalmente
-
-# amd64 è su releases.u.c, mentre arm64 e ppc64el sono su cdimages.u.c
-archs = { amd64 = "releases-ubuntu", arm64 = "cdimages-ubuntu", ppc64el = "cdimages-ubuntu" }
-
-
-[distros.kubuntu]
-name = "Kubuntu"
-description = "L'esperienza Ubuntu con desktop KDE"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-derivatives" }
-
-
-[distros.lubuntu]
-name = "Lubuntu"
-description = "La derivata più leggera, con LXDE"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-derivatives" }
-
-
-[distros.ubuntu-budgie]
-name = "Ubuntu Budgie"
-description = "La potenza di Ubuntu e la leggerezza di Budgie"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-derivatives" }
-
-
-[distros.ubuntukylin]
-name = "Ubuntu Kylin"
-description = "La derivata di Ubuntu con desktop UKUI"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-derivatives" }
-
-
-[distros.ubuntu-mate]
-name = "Ubuntu MATE"
-description = "Ubuntu si unisce a MATE"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-derivatives" }
-
-
-[distros.ubuntustudio]
-name = "Ubuntu Studio"
-description = "La derivata di Ubuntu dedicata alla multimedialità"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-studio" }
-
-
-[distros.xubuntu]
-name = "Xubuntu"
-description = "La derivata di Ubuntu leggera ma personalizzabile, con desktop XFCE"
-lts-support-years = 3
-
-lts-only = true
-releases = ["latest", "lts"]
-archs = { amd64 = "cdimages-derivatives" }
-
-
-# Nomi delle architetture
-# Vengono usati per scegliere l'architettura da scaricare
-
-[archs]
-amd64 = "64bit"
-#i386 = "32bit (computer più datati)"
-arm64 = "ARM 64bit"
-ppc64el = "POWER"
-
-
-
-# Tabella delle sorgenti delle ISO
-# Le distro possono scegliere da quale sorgente prendere ogni architettura
-
-[sources.releases-ubuntu]
-http = "{mirror:ubuntu}/{codename}/ubuntu-{version}-{distro}-{arch}.iso"
-torrent = "{mirror:ubuntu}/{codename}/ubuntu-{version}-{distro}-{arch}.iso.torrent"
-
-[sources.cdimages-ubuntu]
-http = "http://cdimages.ubuntu.com/releases/{codename}/release/ubuntu-{version}-{distro}-{arch}.iso"
-torrent = "http://cdimages.ubuntu.com/releases/{codename}/release/ubuntu-{version}-{distro}-{arch}.iso.torrent"
-
-[sources.cdimages-derivatives]
-http = "http://cdimages.ubuntu.com/{distro}/releases/{codename}/release/{distro}-{version}-desktop-{arch}.iso"
-torrent = "http://cdimages.ubuntu.com/{distro}/releases/{codename}/release/{distro}-{version}-desktop-{arch}.iso.torrent"
-
-[sources.cdimages-studio]
-http = "http://cdimages.ubuntu.com/{distro}/releases/{codename}/release/{distro}-{version}-dvd-{arch}.iso"
-torrent = "http://cdimages.ubuntu.com/{distro}/releases/{codename}/release/{distro}-{version}-dvd-{arch}.iso.torrent"
-
-
-
-# Configurazione dei mirror
-# I mirror vengono caricati da Launchpad in automatico
-
-[mirrors]
-# apparentemente non ci sono più mirror ufficiali in Italia ☹
-country = "DE"
-for = ["ubuntu"]
-


=====================================
uitwww/download.py
=====================================
@@ -1,5 +1,6 @@
 # Source code of the Ubuntu-it website
 # Copyright (C) 2016  Pietro Albini <pietroalbini a ubuntu.com>
+# Copyright (C) 2023  shadMod
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published
@@ -29,16 +30,20 @@ from . import cache
 from . import launchpad
 from .constants import UITWWW_DIR
 
-CONFIG_FILE = "/data/downloads.toml"
+DOWNLOAD_FILE = "downloads.toml"
 CACHE_FILE = "download-cache.json"
 CACHE_FILE_VERSION = 1
 
 
 class Downloads:
 
-    def __init__(self, data_path):
+    def __init__(self, data_path, debug: bool = False):
+        # init _mirrors and _sha256sums
+        self._mirrors = None
+        self._sha256sums = None
+
         # Load the configuration
-        path = UITWWW_DIR + CONFIG_FILE
+        path = os.path.join(data_path, DOWNLOAD_FILE)
         self.config = toml.load(
             path, _dict=collections.OrderedDict,
         )
@@ -49,7 +54,8 @@ class Downloads:
         with open(path, "rb") as raw:
             self._config_hash = "sha1=%s" % hashlib.sha1(raw.read()).hexdigest()
 
-        self._cache_file = os.path.join(data_path, CACHE_FILE)
+        if debug is False:
+            self._cache_file = os.path.join(data_path, CACHE_FILE)
 
     @property
     def _cache(self):  # Cacheception
@@ -61,7 +67,7 @@ class Downloads:
     @property
     def mirrors(self):
         """Get a list of CD mirrors needed by the website"""
-        if not hasattr(self, "_mirrors"):
+        if not hasattr(self, "_mirrors") or self._mirrors is None:
             if self._cache is not None:
                 self._mirrors = self._cache["mirrors"]
             else:
@@ -70,6 +76,8 @@ class Downloads:
                     found_mirrors = list(sorted(launchpad.get_cdimage_mirrors(
                         distro, self.config["mirrors"]["country"]
                     )))
+                    if "it1.mirror.vhosting-it.com" in found_mirrors[0]:
+                        found_mirrors = ["https://releases.ubuntu.com/"]
                     if found_mirrors:
                         self._mirrors[distro] = found_mirrors
                 if not self._mirrors:
@@ -80,14 +88,14 @@ class Downloads:
         return self._mirrors
 
     @property
-    def md5sums(self):
-        """Get a list of all the MD5SUMS"""
-        if not hasattr(self, "_md5sums"):
+    def sha256sums(self):
+        """Get a list of all the SHA256SUMS"""
+        if getattr(self, "_sha256sums") is None:
             if self._cache is not None:
-                self._md5sums = self._cache["md5sums"]
+                self._sha256sums = self._cache["sha256sums"]
             else:
-                self._md5sums = self._fetch_md5sums()
-        return self._md5sums
+                self._sha256sums = self._fetch_sha256sums()
+        return self._sha256sums
 
     def _strip_non_lts_releases(self):
         """Process the lts-only distro configuration"""
@@ -99,14 +107,14 @@ class Downloads:
                 if not self.config["releases"][release]["lts"]:
                     config["releases"].remove(release)
 
-    def _fetch_md5sums(self):
-        """Fetch all the needed MD5SUMS"""
+    def _fetch_sha256sums(self):
+        """Fetch all the needed SHA256SUMS"""
         result = {}
         files_content = {}
 
         for distro, config in self.config["distros"].items():
             for release in config["releases"]:
-                if config["lts-only"] and not self.config["releases"][release]["lts"]:
+                if config["lts-only"]:
                     continue
 
                 for arch in config["archs"].keys():
@@ -115,7 +123,7 @@ class Downloads:
 
                     # Fetch the file from the remote if it wasn't done already
                     if path not in files_content:
-                        md5s = {}
+                        sha_hash = {}
 
                         response = requests.get("%s/SHA256SUMS" % path)
                         if response.status_code == 404:
@@ -127,19 +135,19 @@ class Downloads:
                             if line.strip() == "":
                                 continue
 
-                            hash, name = line.split(" ", 1)
+                            _hash, name = line.split(" ", 1)
                             if name.startswith("*"):
                                 name = name[1:]
-                            md5s[name] = hash
-                        files_content[path] = md5s
+                            sha_hash[name] = _hash
+                        files_content[path] = sha_hash
 
-                    # Add the MD5 to the result if it was found
+                    # Add the SHA256 to the result if it was found
                     if file in files_content[path]:
                         key = "%s:%s:%s" % (distro, release, arch)
                         result[key] = files_content[path][file]
                     else:
                         print(files_content[path])
-                        raise RuntimeError("Missing MD5 for {}".format(file))
+                        raise RuntimeError("Missing SHA256SUMS for {}".format(file))
 
         return result
 
@@ -173,7 +181,7 @@ class Downloads:
                     "version": CACHE_FILE_VERSION,
                     "content": {
                         "mirrors": self.mirrors,
-                        "md5sums": self.md5sums,
+                        "sha256sums": self.sha256sums,
                     },
                 }, f, separators=(",", ":"))
 
@@ -183,12 +191,13 @@ class Downloads:
     def url_for(self, distro, release, arch, torrent=False, use_random=True):
         """Get the URL of a download file"""
         # Build the dict of keys to replace
+        data_rel = self.config["distros"][distro]["archs"][arch][release]
         replaces = {
             "distro": distro,
             "release": release,
             "arch": arch,
-            "version": self.config["releases"][release]["version"],
-            "codename": self.config["releases"][release]["codename"],
+            "version": data_rel["version"],
+            "codename": data_rel["codename"],
         }
 
         # Add mirrors to the replaces key
@@ -199,14 +208,14 @@ class Downloads:
                 replaces["mirror:%s" % name] = choices[0]
 
         # Get the right source
-        source_name = self.config["distros"][distro]["archs"][arch]
-        source = self.config["sources"][source_name]
+        host = data_rel["host"]
+        source = self.config["sources"][host]
 
         # Download URLs are different for torrent and HTTP
         if torrent:
             url = source["torrent"]
         else:
-            url = source["http"]
+            url = source["https"]
 
         for key, value in replaces.items():
             url = url.replace("{%s}" % key, value)
@@ -233,11 +242,12 @@ class Downloads:
             if distro not in self.config["distros"]:
                 flask.abort(404)
 
+            data = self.config["distros"][distro]
             return flask.render_template(
                 "download/landing.html",
                 distro_name=distro,
-                distro=self.config["distros"][distro],
-                releases=self.config["releases"],
+                distro=data,
+                releases=data["archs"]["amd64"],
                 archs=self.config["archs"],
             )
 
@@ -261,16 +271,19 @@ class Downloads:
 
             torrent = "torrent" in flask.request.form
 
-            payload = signer.dumps({
-                "url": self.url_for(distro, release, arch, torrent),
-                "md5": self.md5sums["%s:%s:%s" % (distro, release, arch)],
-                "name": "%s %s%s" % (
-                    self.config["distros"][distro]["name"],
-                    self.config["releases"][release]["version"],
-                    " LTS" if self.config["releases"][release]["lts"] else "",
-                ),
-                "theme": distro,
-            })
+            data_rel = self.config["distros"][distro]["archs"][arch][release]
+            payload = signer.dumps(
+                {
+                    "url": self.url_for(distro, release, arch, torrent),
+                    "sha256": self.sha256sums[f"{distro}:{release}:{arch}"],
+                    "name": "%s %s%s" % (
+                        self.config["distros"][distro]["name"],
+                        data_rel["version"],
+                        " LTS" if data_rel["lts"] else "",
+                    ),
+                    "theme": distro,
+                }
+            )
             return flask.redirect(flask.url_for(".thanks", payload=payload))
 
         @bp.route("/grazie/<payload>")
@@ -288,10 +301,11 @@ class Downloads:
         """Generate the sub-navbar for /download"""
         result = []
         for name, distro in self.config["distros"].items():
-            result.append({
-                "name": distro["name"],
-                "endpoint": "download.landing",
-                "endpoint-args": {"distro": name},
-            })
-
+            result.append(
+                {
+                    "name": distro["name"],
+                    "endpoint": "download.landing",
+                    "endpoint-args": {"distro": name},
+                }
+            )
         return result


=====================================
uitwww/main.py
=====================================
@@ -1,5 +1,6 @@
 # Source code of the Ubuntu-it website
 # Copyright (C) 2015-2016  Pietro Albini <pietroalbini a ubuntu.com>
+# Copyright (C) 2023  shadMod
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU Affero General Public License as published
@@ -19,28 +20,31 @@ import os
 import click
 import uitwww
 
+from scss.compiler import compile_file
+
 from .constants import UITWWW_DIR, BASE_DIR
 from .utils import ReverseProxied, GunicornInstance
-from scss.compiler import compile_file
+from .src.download.compile_download import CompileVersion
 
 
 @click.group()
 def cli():
-    """ Ubuntu-it website's command line utility """
+    """Ubuntu-it website's command line utility"""
     pass
 
 
 @cli.command("run")
 @click.argument("data")
- a click.option("-g", "--gunicorn-config", default=None, help="Path to a"
-                                                            "gunicorn config file")
+ a click.option(
+    "-g", "--gunicorn-config", default=None, help="Path to a gunicorn config file"
+)
 @click.option("-p", "--port", default=8000, help="Bind that port")
 @click.option("--public", help="Make available to the public", is_flag=True)
 @click.option("-w", "--workers", help="Number of workers to start", default=3)
 @click.option("-d", "--debug", help="Enable debug mode", is_flag=True)
 def run(data, gunicorn_config, port, public, workers, debug):
     """Run the application"""
-    app = uitwww.create_app(data)
+    app = uitwww.create_app(data, debug)
     app.wsgi_app = ReverseProxied(app.wsgi_app)
 
     host = "127.0.0.1"
@@ -76,11 +80,21 @@ def run(data, gunicorn_config, port, public, workers, debug):
 
 @cli.command("init")
 @click.argument("data")
-def init(data):
+ a click.option("-d", "--debug", help="Enable debug mode", is_flag=True)
+def init(data, debug):
     """Initialize the data directory"""
-    print("Initializing data directory:", data)
     data_path = os.path.expanduser(os.path.abspath(data))
+    print("Initializing data directory:", data)
     uitwww.init_data_directory(data_path)
+    print("Created data directory:", data)
+    compiler = CompileVersion(
+        path_out=data_path + "/downloads.toml",
+        constants=UITWWW_DIR + "/src/download/assets/constants.json",
+    )
+    compiler.compile_download()
+    print("Compile download file")
+    uitwww.init_data_downloads(data_path, debug)
+    print("Populate data download:", data)
 
 
 @cli.command("build_scss")


=====================================
uitwww/src/__init__.py
=====================================
@@ -0,0 +1,15 @@
+# Source code of the Ubuntu-it website
+# Copyright (C) 2023 shadMod
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; witout even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.


=====================================
uitwww/src/download/__init__.py
=====================================
@@ -0,0 +1,15 @@
+# Source code of the Ubuntu-it website
+# Copyright (C) 2023 shadMod
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; witout even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.


=====================================
uitwww/src/download/assets/constants.json
=====================================
@@ -0,0 +1,55 @@
+{
+	"archs": {
+		"amd64": "64bit",
+		"arm64": "ARM 64bit",
+		"ppc64el": "PowerPC64"
+	},
+	"mirrors": {
+		"country": "IT",
+		"for": [
+			"ubuntu"
+		]
+	},
+	"distros": {
+		"desktop": {
+			"name": "Ubuntu",
+			"description": "L'originale, con GNOME"
+		},
+		"live-server": {
+			"name": "Ubuntu Server",
+			"description": "Tutta la potenza di Ubuntu nel tuo server",
+			"add_archs": [
+				"arm64",
+				"ppc64el"
+			]
+		},
+		"kubuntu": {
+			"name": "Kubuntu",
+			"description": "L'esperienza Ubuntu con desktop KDE"
+		},
+		"lubuntu": {
+			"name": "Lubuntu",
+			"description": "La derivata pi\u00f9 leggera, con LXDE"
+		},
+		"ubuntu-budgie": {
+			"name": "Ubuntu Budgie",
+			"description": "La potenza di Ubuntu e la leggerezza di Budgie"
+		},
+		"ubuntukylin": {
+			"name": "Ubuntu Kylin",
+			"description": "La derivata di Ubuntu con desktop UKUI"
+		},
+		"ubuntu-mate": {
+			"name": "Ubuntu MATE",
+			"description": "Ubuntu si unisce a MATE"
+		},
+		"ubuntustudio": {
+			"name": "Ubuntu Studio",
+			"description": "La derivata di Ubuntu dedicata alla multimedialit\u00e0"
+		},
+		"xubuntu": {
+			"name": "Xubuntu",
+			"description": "La derivata di Ubuntu leggera ma personalizzabile, con desktop XFCE"
+		}
+	}
+}


=====================================
uitwww/src/download/compile_download.py
=====================================
@@ -0,0 +1,244 @@
+# Source code of the Ubuntu-it website
+# Copyright (C) 2023 shadMod
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; witout even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+import toml
+import json
+import requests
+
+from lxml import html
+from urllib.request import urlopen
+from urllib.error import HTTPError
+
+
+class UbuntuRelease:
+    def __init__(self, path_url=None, ignore_version=None):
+        self.path_url = path_url
+        self.ignore_version = ignore_version
+
+    def get_table_rows(self, only_data: bool = True):
+        """
+        :param only_data:   to check you want to ignore the table header
+        """
+
+        # get requests
+        res = requests.get(self.path_url)
+        # check requests status code
+        status = res.status_code
+        if status != 200:
+            raise Exception(f"Error requests - status: {status}")
+        # get all table rows
+        table_rows = html.fromstring(res.content).xpath('//pre//text()')
+        # if only_data is True ignore table header
+        if only_data is True:
+            return table_rows[8:]
+        # else get all table
+        return table_rows
+
+    @property
+    def get_list_version(self) -> list:
+        # init clean row and row_list
+        row = []
+        row_list = []
+        # get table_rows without header
+        for val in self.get_table_rows():
+            val = val.strip()
+            if val:
+                if 'Ubuntu ' not in val:
+                    row.append(val.replace("/", ""))
+                else:
+                    row.append(val)
+
+            if len(row) == 2:
+                if not row[0].split(".")[0].isnumeric():
+                    continue
+
+                if 'LTS' in row[1]:
+                    typology = "LTS"
+                else:
+                    typology = "interim"
+
+                name = row[1].split("(")[1].replace(")", "")
+                short = name.split()[0].lower()
+                row_list.append((row[0], short, name, typology))
+                row = []
+
+        # the lambda is just out of scruple
+        return sorted(row_list, key=lambda x: x[0], reverse=True)
+
+
+class CompileVersion:
+    """
+    :param SUPPORT_5:       set distro with 5 years support (else are 3 years)
+    :param INVERT_RELEASES: set if you want invert releases in template render
+
+    :param path_url:        url to get version list
+    :param path_out:        path where the toml file will be written
+    :param constants:       constants path
+    :param ignore_version:  list of tags versions to be ignored
+    """
+
+    SUPPORT_5 = ["desktop", "live-server"]
+    INVERT_RELEASES = ["live-server"]
+
+    def __init__(
+            self,
+            path_url: str = "https://releases.ubuntu.com/",
+            path_out: str = "../../data/downloads.toml",
+            constants: str = "./assets/costants.json",
+            ignore_version: list = None,
+    ):
+        self.path_url = path_url
+        self.path_out = path_out
+        self.constants = constants
+        self.ignore_version = ignore_version if ignore_version else []
+
+        self.list_version = UbuntuRelease(
+            path_url=self.path_url,
+            ignore_version=self.ignore_version,
+        ).get_list_version
+
+    @property
+    def data_sources(self) -> list:
+        return [
+            (
+                "releases-ubuntu",
+                "https://releases.ubuntu.com/{codename}/ubuntu-{version}-{distro}-{arch}.iso",
+            ),
+            (
+                "cdimages-ubuntu",
+                "https://cdimages.ubuntu.com/releases/{codename}/release/ubuntu-{version}-{distro}-{arch}.iso",
+            ),
+            (
+                "cdimages-derivatives",
+                "https://cdimages.ubuntu.com/{distro}/releases/{codename}/release/{distro}-{version}-desktop-{arch}.iso",
+            ),
+            (
+                "cdimages-studio",
+                "https://cdimages.ubuntu.com/{distro}/releases/{codename}/release/{distro}-{version}-dvd-{arch}.iso",
+            ),
+        ]
+
+    @property
+    def ver_latest(self) -> tuple:
+        return max(self.list_version)
+
+    @property
+    def ver_latest_lts(self) -> tuple:
+        return max(self.ver_lts_list)
+
+    @property
+    def ver_interim_list(self) -> list:
+        return [x for x in self.list_version if x[3] == 'interim']
+
+    @property
+    def ver_lts_list(self) -> list:
+        return [x for x in self.list_version if x[3] == 'LTS']
+
+    def compile_download(self) -> None:
+        # init data with all costants
+        with open(self.constants, "r") as fn:
+            data = json.load(fn)
+
+        # write all distros and relative archs
+        for key in data["distros"]:
+            # get single distro
+            distro = data["distros"][key]
+            # set up key lts-only with default False
+            distro["lts-only"] = False
+            # set up the support years of the LTS
+            distro["lts-support-years"] = (
+                5 if key in self.SUPPORT_5 else 3
+            )
+            # define releases and relative ordering
+            distro["releases"] = (
+                ["latest", "lts"]
+                if key not in self.INVERT_RELEASES
+                else ["lts", "latest"]
+            )
+            # put default arch: 'amd64'
+            releases = {
+                "amd64": self.populate_archs_releases(key, "amd64")
+            }
+            # check and adding any other archs
+            add_archs = distro.get("add_archs")
+            if add_archs:
+                for _arch in add_archs:
+                    releases[_arch] = self.populate_archs_releases(key, _arch)
+            # put all releases in archs key
+            distro["archs"] = releases
+
+        # write sources
+        data["sources"] = {}
+        for key, path in self.data_sources:
+            data["sources"][key] = {"https": path, "torrent": path + ".torrent"}
+
+        # write download.toml
+        with open(self.path_out, "w") as out:
+            toml.dump(data, out)
+
+    def populate_archs_releases(self, distro: str, arch: str) -> dict:
+        """
+        :param distro:  name of the distro
+        :param arch:    name of the architecture
+        """
+
+        rels = {}
+
+        res, typology = self.get_releases(self.list_version, distro, arch)
+        rels['latest'] = res
+
+        if typology == 'interim':
+            res, _ = self.get_releases(self.ver_lts_list, distro, arch)
+            rels['lts'] = res
+
+        if not rels:
+            raise Exception("No archs releases")
+        return rels
+
+    def get_releases(self, data: list, distro: str, arch: str) -> (dict, str):
+        """
+        :param data:    list of all versions
+        :param distro:  name of the distro
+        :param arch:    name of the architecture
+        """
+
+        host = None
+        for version, codename, name, typology in data:
+            host = None
+            for http, path in self.data_sources:
+                try:
+                    conn = urlopen(
+                        path.format(
+                            distro=distro, codename=codename, version=version, arch=arch
+                        )
+                    )
+                except HTTPError:
+                    pass
+                except ValueError:
+                    pass
+                else:
+                    host = http
+                    conn.close()
+                    break
+            if host:
+                return {
+                    "version": version,
+                    "codename": codename,
+                    "host": host,
+                    "lts": False if typology == "interim" else True,
+                }, typology
+
+        if host is None:
+            raise Exception("No correct host")


=====================================
uitwww/templates/download/thanks.html
=====================================
@@ -1,84 +1,92 @@
 {# Source code of the Ubuntu-it website
- # Copyright (C) 2016  Pietro Albini <pietroalbini a ubuntu.com>
- #
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU Affero General Public License as published
- # by the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; witout even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- # GNU Affero General Public License for more details.
- #
- # You should have received a copy of the GNU Affero General Public License
- # along with this program.  If not, see <http://www.gnu.org/licenses/>.
- #}
+# Copyright (C) 2016  Pietro Albini <pietroalbini a ubuntu.com>
+# Copyright (C) 2023  shadMod
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; witout even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#}
 
 {% extends "layout.html" %}
 
 {% block title %}Grazie per aver scaricato {{ name }}{% endblock %}
 
 {% block extra_header %}
-    <meta http-equiv="refresh" content="0; url={{ url }}">
+<meta http-equiv="refresh" content="0; url={{ url }}">
 {% endblock %}
 
 {% block content %}
-    <div class="page">
-        <div class="row background-wallpaper {{ theme }}">
-            <div class="col text-center">
-                <h2>Grazie per aver scaricato {{ name }}!</h2>
-                <p>
-                    Se il download non comincia entro pochi secondi <a href="{{ url }}">
-                    clicca qui</a>.
-                </p>
-            </div>
-        </div>
-    </div>
+<div class="page">
+	<div class="row background-wallpaper {{ theme }}">
+		<div class="col text-center">
+			<h2>
+				Grazie per aver scaricato {{ name }}!
+			</h2>
+			<p>
+				Se il download non comincia entro pochi secondi
+				<a href="{{ url }}">
+					clicca qui
+				</a>.
+			</p>
+		</div>
+	</div>
+</div>
 
-    <div class="page">
-        <div class="row">
-            <div class="col">
-                <h3>Come installare Ubuntu?</h3>
-                <p>
-                    È la prima volta che installi Ubuntu o non ricordi tutti
-                    i passaggi? Non ti preoccupare, Ubuntu-it dispone di una
-                    vasta documentazione con tutti i dettagli necessari!
-                </p>
-
-                <a class="btn" href="https://wiki.ubuntu-it.org/Installazione/InstallareUbuntu">
-                    Guida all'installazione
-                </a>
-            </div>
-            <div class="col">
-                <h3>Ottieni supporto</h3>
-                <p>
-                    Problemi durante l'installazione? La comunità di Ubuntu-it
-                    offre diversi strumenti di supporto, per aiutarti nel
-                    miglior modo possibile.
-                </p>
-
-                <a class="btn" href="{{ url_for("pages.supporto") }}">
-                    Strumenti di supporto
-                </a>
-            </div>
-        </div>
-        <div class="row">
-            <div class="col">
-                <h3>Controlla l'impronta</h3>
-                <p>
-                    Se vuoi verificare l'integrità e la provenienza del file
-                    scaricato, puoi controllare se l'impronta MD5 è la stessa
-                    mostrata qui a destra.
-                </p>
-
-                <a class="btn" href="https://wiki.ubuntu-it.org/Installazione/MD5Sum">
-                    Come controllare l'impronta
-                </a>
-            </div>
-            <div class="col col-center">
-                <pre>{{ md5 }}</pre>
-            </div>
-        </div>
-    </div>
+<div class="page">
+	<div class="row">
+		<div class="col">
+			<h3>
+				Come installare Ubuntu?
+			</h3>
+			<p>
+				È la prima volta che installi Ubuntu o non ricordi tutti
+				i passaggi? Non ti preoccupare, Ubuntu-it dispone di una
+				vasta documentazione con tutti i dettagli necessari!
+			</p>
+			<a class="btn" href="https://wiki.ubuntu-it.org/Installazione/InstallareUbuntu">
+				Guida all'installazione
+			</a>
+		</div>
+		<div class="col">
+			<h3>
+				Ottieni supporto
+			</h3>
+			<p>
+				Problemi durante l'installazione? La comunità di Ubuntu-it
+				offre diversi strumenti di supporto, per aiutarti nel
+				miglior modo possibile.
+			</p>
+			<a class="btn" href="{{ url_for('pages.supporto') }}">
+				Strumenti di supporto
+			</a>
+		</div>
+	</div>
+	<div class="row">
+		<div class="col">
+			<h3>
+				Controlla l'impronta
+			</h3>
+			<p>
+				Se vuoi verificare l'integrità e la provenienza del file
+				scaricato, puoi controllare se l'impronta SHA256 è la stessa
+				mostrata qui a destra.
+			</p>
+			<a class="btn" href="https://wiki.ubuntu-it.org/Installazione/SHA256Sum">
+				Come controllare l'impronta
+			</a>
+		</div>
+		<div class="col col-center">
+			<pre>{{ sha256 }}</pre>
+		</div>
+	</div>
+</div>
 {% endblock %}



View it on GitLab: http://code.ubuntu-it.org/ubuntu-it-web/www/-/compare/8d14fd3eee4496a7df6df734e8be043532135c47...5fe667702ef552ef646800e9247bbf010a272523

-- 
View it on GitLab: http://code.ubuntu-it.org/ubuntu-it-web/www/-/compare/8d14fd3eee4496a7df6df734e8be043532135c47...5fe667702ef552ef646800e9247bbf010a272523
You're receiving this email because of your account on code.ubuntu-it.org..


-------------- parte successiva --------------
Un allegato HTML è stato rimosso...
URL: <http://liste.ubuntu-it.org/pipermail/gruppo-web/attachments/20231106/5c229686/attachment-0001.htm>


Maggiori informazioni sulla lista Gruppo-web