Commit 45a28f05 authored by Pietro Albini's avatar Pietro Albini

Merge branch 'download' into develop

parents 09aec50b e485a662
Pipeline #71 passed with stage
in 0 seconds
recursive-include uitwww/templates * recursive-include uitwww/templates *
recursive-include uitwww/static * recursive-include uitwww/static *
include uitwww/navbar.json recursive-include uitwww/data *
assets/images/wallpapers/ubuntu.jpg

27.6 KB | W: | H:

assets/images/wallpapers/ubuntu.jpg

34.4 KB | W: | H:

assets/images/wallpapers/ubuntu.jpg
assets/images/wallpapers/ubuntu.jpg
assets/images/wallpapers/ubuntu.jpg
assets/images/wallpapers/ubuntu.jpg
  • 2-up
  • Swipe
  • Onion skin
div.page div.row.background-wallpaper { div.page div.row.background-wallpaper {
.box {
background: rgba(255, 255, 255, 0.5);
}
background: url("images/wallpapers/dotted.png") no-repeat 130% 10%;
@media all and (max-width: 60rem) {
background: transparent;
}
&.ubuntu, &.desktop, &.kubuntu, &.lubuntu, &.xubuntu, &.ubuntu-mate,
&.ubuntu-budgie, &.ubuntustudio {
color: #fff; color: #fff;
border-top: 0;
border-top: 0;
& + div.row { & + div.row {
border-top: 0; border-top: 0;
} }
a {
color: rgba(255, 255, 255, 0.5);
}
a.btn {
color: #fff;
}
.box { .box {
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2) inset; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2) inset;
background-color: rgba(0, 0, 0, 0.25); background: rgba(0, 0, 0, 0.25);
border: 0; border: 0;
} }
}
&.ubuntu, &.desktop {
background: url("images/wallpapers/ubuntu.jpg") 100% 0%;
}
&.kubuntu {
background: url("images/wallpapers/kubuntu.jpg") 100% 50%;
}
&.xubuntu {
background:
linear-gradient(rgba(100, 100, 100, 0.3), rgba(100, 100, 100, 0.3)),
url("images/wallpapers/xubuntu.jpg") 100% 50%;
}
&.lubuntu {
background: url("images/wallpapers/lubuntu.jpg") 100% 50%;
}
&.ubuntu-mate {
background:
linear-gradient(rgba(85, 85, 85, 0.3), rgba(85, 85, 85, 0.3)),
url("images/wallpapers/ubuntu-mate.jpg") 100% 50%;
}
&.ubuntu { &.ubuntu-budgie {
background: url("images/wallpapers/ubuntu.jpg") 100% 70%; background:
linear-gradient(rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.3)),
url("images/wallpapers/ubuntu-budgie.jpg") 100% 50%;
}
&.ubuntustudio {
background: url("images/wallpapers/ubuntustudio.jpg") 100% 50%;
.box {
background: rgba(100, 100, 100, 0.25);
}
}
}
div.page div.row.download-index-distro {
@media all and (min-width: 60rem) {
div.col.col-center {
text-align: right;
}
}
@media all and (max-width: 60rem) {
text-align: center;
div.col {
margin-top: 1em;
&:first-child {
margin-top: 0;
}
}
}
}
div.download-form {
padding: 0.5em 1.5em;
div.download-form-group {
margin: 1em 0;
}
div.download-form-buttons {
margin: 1em 0;
.btn {
display: block;
text-align: center;
width: 100%;
}
} }
} }
......
...@@ -34,6 +34,10 @@ setuptools.setup( ...@@ -34,6 +34,10 @@ setuptools.setup(
"flask", "flask",
"click", "click",
"gunicorn", "gunicorn",
"requests",
"itsdangerous",
"toml",
"pyyaml",
], ],
packages = [ packages = [
......
...@@ -21,6 +21,8 @@ import flask ...@@ -21,6 +21,8 @@ import flask
from . import pages from . import pages
from . import cache from . import cache
from . import utils from . import utils
from . import download
from . import navbar
def create_app(data_path): def create_app(data_path):
...@@ -43,8 +45,17 @@ def create_app(data_path): ...@@ -43,8 +45,17 @@ def create_app(data_path):
app.config["CACHE_PATH"] = os.path.join(data_path, "cache") app.config["CACHE_PATH"] = os.path.join(data_path, "cache")
cache.install_cache(app) cache.install_cache(app)
app.download = download.Downloads(data_path)
app.register_blueprint(
app.download.prepare_blueprint(app),
url_prefix="/download",
)
app.register_blueprint(pages.prepare_blueprint(app)) app.register_blueprint(pages.prepare_blueprint(app))
pages.prepare_navbar(app)
nav = navbar.Navbar()
nav.add_generator("download-distros", app.download.generate_navbar)
nav.install(app)
@app.errorhandler(404) @app.errorhandler(404)
def not_found(error): def not_found(error):
...@@ -78,3 +89,7 @@ def init_data_directory(data_path): ...@@ -78,3 +89,7 @@ def init_data_directory(data_path):
with open(secret_key_path, "w") as f: with open(secret_key_path, "w") as f:
f.write("%s\n" % utils.random_key(64)) f.write("%s\n" % utils.random_key(64))
os.chmod(secret_key_path, 0o400) os.chmod(secret_key_path, 0o400)
# Initialize the download files
download_inst = download.Downloads(data_path)
download_inst.store_cache_file()
...@@ -50,7 +50,7 @@ def run(data, gunicorn_config, port, public, workers, debug): ...@@ -50,7 +50,7 @@ def run(data, gunicorn_config, port, public, workers, debug):
# In debug mode, run the flask builtin webserver # In debug mode, run the flask builtin webserver
if debug: if debug:
extra_files = [ extra_files = [
os.path.join(src_directory, "navbar.json"), os.path.join(src_directory, "data/navbar.yml"),
] ]
app.run(debug=True, port=port, host=host, extra_files=extra_files) app.run(debug=True, port=port, host=host, extra_files=extra_files)
......
...@@ -68,7 +68,7 @@ def after_request(response): ...@@ -68,7 +68,7 @@ def after_request(response):
# Do dome filtering # Do dome filtering
if status != 200 or method != "GET": if status != 200 or method != "GET":
return result return response
if url.endswith("/"): if url.endswith("/"):
url += "index.html" url += "index.html"
......
# Configurazione delle release disponibili
# Quando viene rilasciata una release o una point release è solamente
# necessario aggiornare questa sezione.
[releases.latest]
version = "18.04"
codename = "bionic"
lts = true
[releases.lts]
version = "16.04.4"
codename = "xenial"
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 = false
releases = ["latest", "lts"]
archs = { amd64 = "releases-ubuntu" }
[distros.server]
name = "Ubuntu Server"
description = "Tutta la potenza di Ubuntu nel tuo server"
lts-support-years = 5
lts-only = false
releases = ["lts", "latest"] # Invertiti intenzionalmente
# La live di 18.04 LTS su releases.u.c usa un installer che non supporta una
# valanga di sistemi, quindi faccio scaricare l'alternate
source-override-latest-amd64 = "cdimages-ubuntu"
# amd64 è su releases.u.c, mentre arm64 e ppc64el sono su cdimages.u.c
[distros.server.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 = false
releases = ["latest", "lts"]
archs = { amd64 = "cdimages-derivatives", i386 = "cdimages-derivatives" }
[distros.xubuntu]
name = "Xubuntu"
description = "La derivata di Ubuntu leggera ma personalizzabile, con desktop XFCE"
lts-support-years = 3
lts-only = false
releases = ["latest", "lts"]
archs = { amd64 = "cdimages-derivatives", i386 = "cdimages-derivatives" }
[distros.lubuntu]
name = "Lubuntu"
description = "La derivata più leggera, con LXDE"
lts-support-years = 3
lts-only = false
releases = ["latest", "lts"]
archs = { amd64 = "cdimages-derivatives", i386 = "cdimages-derivatives" }
[distros.ubuntu-mate]
name = "Ubuntu MATE"
description = "Ubuntu si unisce a MATE"
lts-support-years = 3
lts-only = false
releases = ["latest", "lts"]
archs = { amd64 = "cdimages-derivatives", i386 = "cdimages-derivatives" }
[distros.ubuntu-budgie]
name = "Ubuntu Budgie"
description = "La potenza di Ubuntu e la leggerezza di Budgie"
lts-support-years = 3
lts-only = false
releases = ["latest"]
archs = { amd64 = "cdimages-derivatives", i386 = "cdimages-derivatives" }
[distros.ubuntustudio]
name = "Ubuntu Studio"
description = "Ubuntu con tutti i programmi per lavorare con audio, video e immagini"
lts-support-years = 3
lts-only = true
releases = ["latest", "lts"]
archs = { amd64 = "cdimages-studio", i386 = "cdimages-studio" }
# 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]
country = "IT"
for = ["ubuntu"]
- name: Download
endpoint: download.index
# Evidenzia anche la pagina di ringraziamento sotto questo menu
also-match:
download.thanks: null
# Le sottopagine sono generate automaticamente dalla lista di distro
generate-subs: download-distros
- name: Scopri Ubuntu
endpoint: pages.scopri-ubuntu_index
- name: Supporto
endpoint: pages.supporto
subs:
- name: Documentazione
external: https://wiki.ubuntu-it.org
- name: Forum
external: https://forum.ubuntu-it.org
- name: Domande e risposte
external: https://chat.ubuntu-it.org
- name: Chat
external: https://chat.ubuntu-it.org
- name: Comunità
endpoint: pages.comunita_index
- name: Eventi
endpoint: pages.eventi_index
- name: Contribuisci
endpoint: pages.contribuisci_index
- name: Progetto
endpoint: pages.progetto_index
- name: Contatti
endpoint: pages.contatti_index
# Source code of the Ubuntu-it website
# Copyright (C) 2016 Pietro Albini <pietroalbini@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/>.
import hashlib
import json
import toml
import os
import random
import collections
import flask
import itsdangerous
import requests
import pkg_resources
from . import cache
from . import launchpad
CONFIG_FILE = "data/downloads.toml"
CACHE_FILE = "download-cache.json"
CACHE_FILE_VERSION = 1
class Downloads:
def __init__(self, data_path):
# Load the configuration
raw = pkg_resources.resource_string("uitwww", CONFIG_FILE)
self.config = toml.loads(
raw.decode("utf-8"),
_dict=collections.OrderedDict,
)
self._strip_non_lts_releases()
# Save the hash of the configuration
self._config_hash = "sha1=%s" % hashlib.sha1(raw).hexdigest()
self._cache_file = os.path.join(data_path, CACHE_FILE)
@property
def _cache(self): # Cacheception
"""Get the cache from the data directory"""
if not hasattr(self, "_cache_cache"): # Naming things is hard
self._cache_cache = self._cache_content()
return self._cache_cache
@property
def mirrors(self):
"""Get a list of CD mirrors needed by the website"""
if not hasattr(self, "_mirrors"):
if self._cache is not None:
self._mirrors = self._cache["mirrors"]
else:
self._mirrors = {
distro: list(sorted(launchpad.get_cdimage_mirrors(
distro, self.config["mirrors"]["country"]
))) for distro in self.config["mirrors"]["for"]
}
return self._mirrors
@property
def md5sums(self):
"""Get a list of all the MD5SUMS"""
if not hasattr(self, "_md5sums"):
if self._cache is not None:
self._md5sums = self._cache["md5sums"]
else:
self._md5sums = self._fetch_md5sums()
return self._md5sums
def _strip_non_lts_releases(self):
"""Process the lts-only distro configuration"""
for config in self.config["distros"].values():
if not config["lts-only"]:
continue
for release in config["releases"][:]:
if not self.config["releases"][release]["lts"]:
config["releases"].remove(release)
def _fetch_md5sums(self):
"""Fetch all the needed MD5SUMS"""
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"]:
continue
for arch in config["archs"].keys():
url = self.url_for(distro, release, arch, use_random=False)
path, file = url.rsplit("/", 1)
# Fetch the file from the remote if it wasn't done already
if path not in files_content:
md5s = {}
response = requests.get("%s/MD5SUMS" % path)
if response.status_code == 404:
raise RuntimeError(
"Missing {} {} on {}".format(distro, release, source),
)
for line in response.text.split("\n"):
if line.strip() == "":
continue
hash, name = line.split(" ", 1)
if name.startswith("*"):
name = name[1:]
md5s[name] = hash
files_content[path] = md5s
# Add the MD5 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))
return result
def _cache_content(self):
"""Get the content of the cache in the data directory"""
# The cache is returned if the file exists, the download configuration
# didn't change, the file is valid JSON and the version is correct
if not os.path.exists(self._cache_file):
return None
try:
with open(self._cache_file) as f:
content = json.load(
f,
object_pairs_hook=collections.OrderedDict,
)
except ValueError:
return None
if content["config-hash"] != self._config_hash:
return None
if content["version"] != CACHE_FILE_VERSION:
return None
return content["content"]
def store_cache_file(self):
"""Store the cache file in the data directory"""
# Store only if the cache isn't available
if self._cache is None:
with open(self._cache_file, "w") as f:
json.dump({
"config-hash": self._config_hash,
"version": CACHE_FILE_VERSION,
"content": {
"mirrors": self.mirrors,
"md5sums": self.md5sums,
},
}, f, separators=(",", ":"))
# Invalidate the cache in this instance
delattr(self, "_cache_cache")
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
replaces = {
"distro": distro,
"release": release,
"arch": arch,
"version": self.config["releases"][release]["version"],
"codename": self.config["releases"][release]["codename"],
}
# Add mirrors to the replaces key
for name, choices in self.mirrors.items():
if use_random:
replaces["mirror:%s" % name] = random.choice(choices)
else:
replaces["mirror:%s" % name] = choices[0]
# Get the right source
override_key = "source-override-%s-%s" % (release, arch)
if override_key in self.config["distros"][distro]:
source_name = self.config["distros"][distro][override_key]
else:
source_name = self.config["distros"][distro]["archs"][arch]
source = self.config["sources"][source_name]
# Download URLs are different for torrent and HTTP
if torrent:
url = source["torrent"]
else:
url = source["http"]
for key, value in replaces.items():
url = url.replace("{%s}" % key, value)
return url
def prepare_blueprint(self, app):
"""Prepare a blueprint with the download pages"""
signer = itsdangerous.URLSafeSerializer(app.secret_key)
bp = flask.Blueprint("download", __name__)
@bp.route("/")
@cache.enable
def index():
return flask.render_template(
"download/index.html",
distros = self.config["distros"],
)
@bp.route("/<distro>")
@cache.enable
def landing(distro):
if distro not in self.config["distros"]:
flask.abort(404)
return flask.render_template(
"download/landing.html",
distro_name = distro,
distro = self.config["distros"][distro],
releases = self.config["releases"],
archs = self.config["archs"],
)
@bp.route("/+redirect", methods=["POST"])
def redirect():
# Return a Bad Request if not all the fields are present
try:
distro = flask.request.form["distro"]
release = flask.request.form["release"]
arch = flask.request.form["arch"]
except KeyError:
flask.abort(400)
# Validate the input
if distro not in self.config["distros"]:
flask.abort(400)
if release not in self.config["distros"][distro]["releases"]:
flask.abort(400)
if arch not in self.config["distros"][distro]["archs"]:
flask.abort(400)
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,
})
return flask.redirect(flask.url_for(".thanks", payload=payload))
@bp.route("/grazie/<payload>")
def thanks(payload):
try:
content = signer.loads(payload)
except itsdangerous.BadSignature:
return flask.redirect(flask.url_for("pages.download_index"))
return flask.render_template("download/thanks.html", **content)
return bp
def generate_navbar(self):
"""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},
})
return result
# Source code of the Ubuntu-it website
# Copyright (C) 2016 Pietro Albini <pietroalbini@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/>.
import requests
BASE = "https://api.launchpad.net/devel"
def fetch_paginated(initial):
"""Fetch paginated data"""
next_url = initial
while True:
data = requests.get(next_url).json()
for entry in data["entries"]:
yield entry
if "next_collection_link" not in data:
break
next_url = data["next_collection_link"]
def get_cdimage_mirrors(distro, country):
"""Get a list of cdimage mirrors"""
result = []
for mirror in fetch_paginated("%s/%s/cdimage_mirrors" % (BASE, distro)):
# Ensure we get only CD Image mirrors
if mirror["content"] != "CD Image":
continue
# Only get Official mirrors, please
if mirror["status"] != "Official":
continue
# Only get mirrors of the specific country
if not mirror["country_link"].endswith("/+countries/%s" % country):
continue
if mirror["http_base_url"] is None:
continue
url = mirror["http_base_url"]
if url.endswith("/"):
url = url[:-1]
result.append(url)
return result
[
{
"name": "Download",
"endpoint": "pages.download_index",
"subs": []
},
{
"name": "Scopri Ubuntu",
"endpoint": "pages.scopri-ubuntu_index",
"subs": []
},
{
"name": "Supporto",
"endpoint": "pages.supporto",
"subs": [
{
"name": "Documentazione",
"external": "http://wiki.ubuntu-it.org"
},
{
"name": "Forum",
"external": "http://forum.ubuntu-it.org"
},
{
"name": "Domande e risposte",
"external": "http://chiedi.ubuntu-it.org"
},
{
"name": "Chat",
"external": "http://chat.ubuntu-it.org"
}
]
},
{
"name": "Comunità",
"endpoint": "pages.comunita_index",
"subs": []
},
{
"name": "Eventi",
"endpoint": "pages.eventi_index",
"subs": []
},
{
"name": "Contribuisci",
"endpoint": "pages.contribuisci_index",
"subs": []
},
{
"name": "Progetto",
"endpoint": "pages.progetto_index",
"subs": []
},
{
"name": "Contatti",
"endpoint": "pages.contatti_index",
"subs": []
}
]
# Source code of the Ubuntu-it website
# Copyright (C) 2018 Pietro Albini <pietroalbini@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/>.
import flask
import json
import pkg_resources
import yaml
class Navbar:
def __init__(self):
self.navbars = []
self.match = {}
self.generators = {}
def add_generator(self, name, generator):
"""Add a subpages generator"""
self.generators[name] = generator
def current_navbars(self):
"""Get the list of current navbars"""
if flask.request.endpoint is not None:
matcher = (flask.request.endpoint, tuple(flask.request.view_args.items()))
if matcher in self.match:
return self._return_navbars(self.match[matcher])
elif flask.request.endpoint in self.match:
return self._return_navbars(self.match[flask.request.endpoint])
return self._return_navbars([(0, -1)])
def _return_navbars(self, navbars):
"""Return a list of navbars"""
result = []
for bar_id, active_id in navbars:
bar = []
for i, item in enumerate(self.navbars[bar_id]):
bar.append((item[0], item[1](), i == active_id))
result.append(bar)
return result
def install(self, app):
"""Install this navbar on the app"""
raw = pkg_resources.resource_string("uitwww", "data/navbar.yml")
config = yaml.load(raw.decode("utf-8"))
self._prepare_navbar_cache(config, [])
# Add the _navbars variable to the templates
@app.context_processor
def inject_navbar():
return {
"_navbars": self.current_navbars(),
}
def _prepare_navbar_cache(self, bar, parents):
"""Add the bar to the cache"""
bar_id = len(self.navbars)
self.navbars.append([])
for item in bar:
item.setdefault("endpoint-args", None)
# Load the list of subs dynamically if requested
if "generate-subs" in item:
item["subs"] = self.generators[item["generate-subs"]]()
# Add hte item to the navbar
item_id = len(self.navbars[bar_id])
self.navbars[bar_id].append((item["name"], self._url_of(item)))
# Load sub-navbars recursively
sub_id = None
if "subs" in item:
sub_id = self._prepare_navbar_cache(item["subs"], parents + [(bar_id, item_id)])
if "endpoint" in item:
# Generate the list of navbars to show for this match
# If this item has childs the childs are shown
navbars = parents + [(bar_id, item_id)]
if sub_id is not None:
navbars.append((sub_id, -1))
# Add a match for each endpoint pointing to the list of navbars
match = {item["endpoint"]: item["endpoint-args"]}
if "also-match" in item:
match.update(item["also-match"])
for endpoint, args in match.items():
if args is None:
self.match[endpoint] = navbars
else:
self.match[(endpoint, tuple(args.items()))] = navbars
return bar_id
def _url_of(self, item):
"""Lazily the URL of an item"""
if "external" in item:
return lambda: item["external"]
# This function return lambdas because flask.url_for is only available
# during requests
if item["endpoint-args"] is not None:
return lambda: flask.url_for(item["endpoint"], **item["endpoint-args"])
else:
return lambda: flask.url_for(item["endpoint"])
...@@ -87,65 +87,3 @@ def prepare_blueprint(app): ...@@ -87,65 +87,3 @@ def prepare_blueprint(app):
return flask.render_template(_tmpl) return flask.render_template(_tmpl)
return bp return bp
def prepare_navbar(app):
"""Prepare the context processor which will provide navbar informations"""
# This will load the navbar.json file, and parse it as json
navbar_raw = pkg_resources.resource_string("uitwww", "navbar.json")
navbar = json.loads(navbar_raw.decode("utf-8"))
def calculate_menu(current, recursive=True, _final=True):
# This will process only a level of the result
active = False
active_i = None
# Make all items non-active by default
for item in current:
item["active"] = False
for i, item in enumerate(current):
active = False
# An item should be considered active if either is the current
# one, or one of its childs is active
endpoint = flask.request.endpoint
if "endpoint" in item and item["endpoint"] == endpoint:
active = True
elif "subs" in item and recursive:
active = calculate_menu(item["subs"], _final=False) is not None
# Break the loop if this item is active
if active:
item["active"] = True
active_i = i
break
if active or _final:
return current, active_i
# else None is returned
@app.context_processor
def add_menu():
result = []
result_active = []
# Get all the possible navbar levels
next_to_calculate = navbar
while True:
calculated, next_i = calculate_menu(next_to_calculate)
result.append(calculated)
if next_i is not None:
result_active.append(calculated[next_i])
if next_i is not None and "subs" in calculated[next_i]:
next_to_calculate = calculated[next_i]["subs"]
else:
break
# Force something in the second navbar
if len(result) == 1:
result.append(result[0][0]["subs"])
return {"_navbar": result, "_navbar_active": result_active}
{# Source code of the Ubuntu-it website
# Copyright (C) 2015 Pietro Albini <pietroalbini@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/>.
#}
{% extends "layout.html" %}
{% block title %}Download{% endblock %}
{% block content %}
<div class="page">
<div class="row">
<div class="col text-center">
<h1>Scarica Ubuntu</h1>
<p class="intro">Entra subito nel mondo Ubuntu. Scaricalo ora!</p>
</div>
</div>
</div>
<div class="page">
{% for name, data in distros.items() %}
<div class="row download-index-distro background-wallpaper {{ name }}">
<div class="col">
<h2>{{ data["name"] }}</h2>
<p>{{ data["description"] }}</p>
</div>
<div class="col col-center col-quarter">
<a class="btn" href="{{ url_for("download.landing", distro = name) }}">
Scaricala ora
</a>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{# Source code of the Ubuntu-it website
# Copyright (C) 2016 Pietro Albini <pietroalbini@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/>.
#}
{% extends "layout.html" %}
{% block title %}Scarica {{ distro["name"] }}{% endblock %}
{% block content %}
<div class="page">
{% for release in distro["releases"] %}
<div class="row {% if loop.index == 1 %}background-wallpaper {{ distro_name }}{% endif %}">
<div class="col">
<h2>
{{ distro["name"] }}
{{ releases[release]["version"] }}
{% if releases[release]["lts"] %}LTS{% endif %}
</h2>
{% if release == "latest" %}
<p>
{{ distro["name"] }} {{ releases[release]["version"] }} {% if releases[release]["lts"] %}LTS{% endif %}
è l'ultimo rilascio di {{ distro["name"] }}, con
tutte le ultime novità ed aggiornamenti.
Il periodo di supporto, con aggiornamenti di sicurezza,
è di
{% if releases[release]["lts"] -%}
{{ distro["lts-support-years"] }} anni
{%- else -%}
9 mesi
{%- endif -%}.
</p>
{% elif release == "lts" %}
<p>
{{ distro["name"] }} {{ releases[release]["version"] }} {% if releases[release]["lts"] %}LTS{% endif %}
è il rilascio stabile di {{ distro["name"] }},
con aggiornamenti di sicurezza garantiti per {{ distro["lts-support-years"] }} anni.
{% endif %}
</div>
<div class="col">
<div class="box download-form">
<form action="{{ url_for(".redirect") }}" method="post">
<input type="hidden" name="distro" value="{{ distro_name }}">
<input type="hidden" name="release" value="{{ release }}">
{% if distro["archs"]|length > 1 %}
<div class="download-form-group">
{% for arch in distro["archs"].keys() %}
<div>
<input id="arch-{{ release }}-{{ arch }}" type="radio" name="arch" value="{{ arch }}" {% if loop.index == 1 %}checked{% endif %}>
<label for="arch-{{ release }}-{{ arch }}">
Architettura {{ archs[arch] }}
</label>
</div>
{% endfor %}
</div>
{% else %}
<input type="hidden" name="arch" value="{{ distro["archs"].keys()|first }}">
{% endif %}
<div class="download-form-group">
<input id="torrent-{{ release }}" type="checkbox" name="torrent" value="1">
<label for="torrent-{{ release }}">
Scarica tramite torrent
</label>
</div>
<div class="download-form-buttons">
<button class="btn" type="submit">Download</button>
</div>
</form>
</div>
</div>
</div>
{% endfor %}
</div>
<div class="page">
<div class="row">
<div class="col">
<h3>Requisiti di sistema</h3>
<p>
Se non sei sicuro che il tuo computer possa reggere
{{ distro["name"] }} ti consigliamo di controllare di
requisiti di sistema minimi. Nel caso disponessi di un
vecchio computer, puoi sempre provare una derivata più leggera!
</p>
<a class="btn" href="https://wiki.ubuntu-it.org/Installazione/RequisitiDiSistema">
Leggi i requisiti
</a>
</div>
<div class="col">
<h3>La comunità</h3>
<p>
{{ distro["name"] }} è creato e supportato da
volontari che dedicano il loro tempo a sviluppare un
sistema operativo migliore. Cosa aspetti a contribuire ed
aiutarci a realizzare qualcosa di innovativo? È facile!
</p>
<a class="btn" href="{{ url_for("pages.contribuisci_index") }}">
Inizia subito a contribuire
</a>
</div>
</div>
</div>
{% endblock %}
{# Source code of the Ubuntu-it website
# Copyright (C) 2016 Pietro Albini <pietroalbini@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/>.
#}
{% extends "layout.html" %}
{% block title %}Grazie per aver scaricato {{ name }}{% endblock %}
{% block extra_header %}
<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">
<div class="col">
<h3>Come installare Ubuntu?</h3>
<p>
È la prima volta che installi Ubuntu o non ti 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">
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>
{% endblock %}
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
<link rel="stylesheet" href="https://static.ubuntu-it.org/fonts/ubuntu/include.min.css"> <link rel="stylesheet" href="https://static.ubuntu-it.org/fonts/ubuntu/include.min.css">
<link rel="stylesheet" href="https://static.ubuntu-it.org/themes/italy/theme.min.css"> <link rel="stylesheet" href="https://static.ubuntu-it.org/themes/italy/theme.min.css">
<link rel="stylesheet" href="{{ url_for("static", filename="website.css") }}" /> <link rel="stylesheet" href="{{ url_for("static", filename="website.css") }}" />
{% block extra_header %}{% endblock %}
</head> </head>
<body {% block extra_body %}{% endblock %}> <body {% block extra_body %}{% endblock %}>
...@@ -54,37 +56,32 @@ ...@@ -54,37 +56,32 @@
<li><a href="https://planet.ubuntu-it.org">Planet</a></li> <li><a href="https://planet.ubuntu-it.org">Planet</a></li>
</ul> </ul>
<ul class="right"> <ul class="right">
<li><a href="https://telegram.me/ubuntuit">Telegram</a></li>
<li><a href="https://www.youtube.com/ubuntuitpromozione">YouTube</a></li>
<li><a href="https://plus.google.com/+ubuntuit">Google+</a></li>
<li<a href="https://twitter.com/ubuntuit">Twitter</a></li>
<li><a href="https://www.facebook.com/ubuntu.it">Facebook</a></li> <li><a href="https://www.facebook.com/ubuntu.it">Facebook</a></li>
<li><a href="https://twitter.com/ubuntuit">Twitter</a></li>
<li><a href="https://plus.google.com/+ubuntuit">Google+</a></li>
<li><a href="https://www.youtube.com/ubuntuitpromozione">YouTube</a></li>
<li><a href="https://telegram.me/ubuntuit">Telegram</a></li>
</ul> </ul>
</div> </div>
</nav> </nav>
<nav class="main-navbar"> {% for navbar in _navbars %}
<nav {%- if loop.index == 1 %} class="main-navbar"{% endif %}>
<div class="container"> <div class="container">
<ul> <ul>
{% if loop.index == 1 %}
<li class="site-name"><a href="{{ url_for("pages.index") }}">ubuntu-it</a></li> <li class="site-name"><a href="{{ url_for("pages.index") }}">ubuntu-it</a></li>
{% for item in _navbar[0] %} {% endif -%}
{{ nav_item(item) }}
{% endfor %}
</ul>
</div>
</nav>
{% if _navbar[1] %} {%- for name, url, active in navbar %}
<nav> <li>
<div class="container"> <a {%- if active %} class="active"{% endif %} href="{{ url }}">{{ name }}</a>
<ul> </li>
{% for item in _navbar[1] %}
{{ nav_item(item) }}
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
</nav> </nav>
{% endif %} {% endfor %}
<div class="container"> <div class="container">
{% block content %}{% endblock %} {% block content %}{% endblock %}
......
...@@ -14,15 +14,3 @@ ...@@ -14,15 +14,3 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
#} #}
{% macro nav_item(item) %}
<li>
{% if "external" in item %}
<a href="{{ item.external }}">{{ item.name }}</a>
{% elif item.active %}
<a href="{{ url_for(item.endpoint) }}" class="active">{{ item.name }}</a>
{% else %}
<a href="{{ url_for(item.endpoint) }}">{{ item.name }}</a>
{% endif %}
</li>
{% endmacro %}
{% extends "layout.html" %}
{% block title %}Desktop e server{% endblock %}
{% block content %}
<div class="row row-hero">
<div class="twelve-col last-col">
<p>
Questa pagina non è ancora stata creata.<br>
Se sei un membro del gruppo e vuoi lavorarci su, assegnati a te stesso
l'issue su GitLab e inizia subito!
</p>
<p>
Se non sei un membro ma desideri contribuire, cosa aspetti?
<a href="http://wiki.ubuntu-it.org/GruppoWeb/Contribuire">Scopri come aiutarci</a>!
<p><b>Il Gruppo Web di ubuntu-it</b></p>
</div>
</div>
{% endblock %}
{# Source code of the Ubuntu-it website
# Copyright (C) 2015 Pietro Albini <pietroalbini@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/>.
#}
{% extends "layout.html" %}
{% block title %}Download{% endblock %}
{% block content %}
<div class="page">
<div class="row">
<div class="col">
<h1>Scarica Ubuntu</h1>
<p class="intro">Entra subito nel mondo Ubuntu. Scaricalo ora!</p>
<p>
<a class="btn" href="{{ url_for("pages.download_desktop") }}">Desktop e portatili</a>
<a class="btn" href="#">Server</a>
<a class="btn" href="#">Prova una derivata</a>
</p>
</div>
<div class="col col-quarter col-center">
<img class="pictogram" src="https://static.ubuntu-it.org/pictograms/download.svg">
</div>
</div>
<div class="row background-wallpaper ubuntu">
<div class="col">
<h3>Necessiti di supporto?</h3>
<p>
Se hai difficoltà ad installare Ubuntu, oppure si sono verificati
problemi durante e dopo l'installazione, non preoccuparti!<br />
La comunità italiana di Ubuntu offre molteplici strumenti di supporto,
per aiutarti nel miglior modo possibile.
</p>
<a class="btn btn-inverse" href="{{ url_for("pages.supporto") }}">Ottieni supporto</a>
</div>
<div class="col">
<div class="box">
<h3 class="muted-heading">Hai difficoltà a scaricare Ubuntu?</h3>
<p>
In caso non riuscissi a scaricare Ubuntu, la comunità italiana è
disponibile ad inviarti un DVD direttamente a casa tua! Basta chiedere.
</p>
<div class="align-center">
<a class="btn" href="#">Richiedi un DVD</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<h3>Requisiti di sistema</h3>
<p>
Se non sei sicuro che il tuo computer possa reggere Ubuntu ti
consigliamo di controllare di requisiti di sistema minimi.<br />
Ed in caso disponessi di un vecchio computer, puoi sempre
provare una derivata più leggera!
</p>
<a class="btn" href="https://wiki.ubuntu-it.org/Installazione/RequisitiDiSistema">
Leggi i requisiti
</a>
</div>
<div class="col">
<h3>La comunità</h3>
<p>
Ubuntu è creato e supportato da volontari che dedicano il loro
tempo a sviluppare un sistema operativo migliore.<br />
Cosa aspetti a contribuire ed aiutarci a realizzare qualcosa di innovativo? È facile!
</p>
<a class="btn" href="#">Inizia subito a contribuire</a>
</div>
</div>
</div>
{% endblock %}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment