Commit 993be001 authored by Pietro Albini's avatar Pietro Albini

Initial commit

parents
# Building stuff
/uitwww.egg-info
/build
/node_modules
# Python stuff
__pycache__
.py[co]
# Compiled assets
/uitwww/static/website.css
/uitwww/static/website.js
This diff is collapsed.
recursive-include uitwww/templates *
recursive-include uitwww/static *
include uitwww/navbar.json
# Il sito web di Ubuntu-it
Questo repository contiene tutto il codice sorgente del [sito web][1] di
ubuntu-it. Il tutto è rilasciato sotto licenza GNU-AGPL v3+.
Il sito è realizzato con [flask](http://flask.pocoo.org) e Python 3.
## Esecuzione del sito in locale
Per eseguire il sito in locale, è possibile eseguire questo comando (una volta
dentro il virtualenv o con il sito installato globalmente):
```
$ uitwww run -d -p 8000
```
Esso avvierà un'istanza in debug-mode (*da non eseguire in produzione!!!*), che
ascolta su `localhost:8000`. Se si vuole attivare anche la cache statica,
bisogna aggiungere come argomento il path della directory che la dovrà
contenere:
```
$ uitwww run -d -p 8000 path/to/cache
```
## Generazione di una build
Per creare una build dell'intero sito, è necessario disporre di Python 3,
[virtualenv][2], [pyinvoke][3] e nodejs. Dopo averli installati si può crearla
con il seguente comando:
```
$ invoke build
```
Esso scaricherà tutte le dipendenze da internet (la prima volta), compilerà gli
assets e genererà il pacchetto, salvandolo in ``build/packages``. È possibile
rimuovere tutti i file creati dal processo con il comando:
```
$ invoke clean
```
## Hacking
Per preparare l'ambiente di sviluppo è necessario disporre di Python 3,
[virtualenv][2], [pyinvoke][3] e nodejs. Dopo averli installati si può
generarlo con il seguente comando:
```
$ invoke devel
```
Esso scaricherà tutte le dipendenze da internet (la prima volta), compilerà gli
assets e creerà un virtualenv con dentro installato il sito (in modalità
modificabile). Per attivare il virtualenv, bisogna dare in ogni sessione di
terminale il seguente comando:
```
$ source build/envs/devel/bin/activate
```
Se si modificano gli assets è necessario ricompilarli. Lo si può effettuare con
il seguente comando:
```
$ invoke assets
```
In caso si facciano modifiche frequenti, può risultare conveniente l'aggiunta
della flag `-w` al comando, che ricompila gli assets quando sono rilevate
modifiche.
[1]: http://www.ubuntu-it.org
[2]: https://virtualenv.pypa.io
[3]: http://www.pyinvoke.org
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="141.732px" height="141.732px" viewBox="70.866 70.866 141.732 141.732"
enable-background="new 70.866 70.866 141.732 141.732" xml:space="preserve">
<path fill="#DD4814" d="M141.733,85.039c-31.262,0-56.693,25.432-56.693,56.692c0,31.262,25.432,56.695,56.693,56.695
c31.259,0,56.692-25.433,56.692-56.695C198.425,110.471,172.992,85.039,141.733,85.039z M161.588,153.334l-17.345,17.346
c-1.384,1.383-3.625,1.383-5.01,0l-17.172-17.174c-0.75-0.65-1.223-1.607-1.223-2.678c0-1.956,1.586-3.544,3.544-3.544h0.013h10.25
v-0.001v-28.446c0-3.914,3.174-7.086,7.086-7.086c3.914,0,7.087,3.172,7.087,7.086v28.447h10.264c1.432,0,2.725,0.862,3.271,2.188
C162.904,150.797,162.6,152.322,161.588,153.334z"/>
</svg>
This diff is collapsed.
// Override default text selection color
::selection {
background: lighten($ubuntu-orange, 10%);
color: #fff;
}
a {
&::selection,
& *::selection {
background: $warm-grey;
color: #fff;
}
}
// Remove unwanted "x"es from search box (webkit and ie)
input[type=text]::-ms-clear { display: none; width: 0; height: 0; }
input[type=text]::-ms-reveal { display: none; width: 0; height: 0; }
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration { display: none; }
// Fix some paddings
div.row {
padding: 40px 40px 20px 40px;
&:last-child {
@extend .no-border;
}
&.row-quote blockquote {
padding-top: 20px;
}
}
div.inner-wrapper {
padding-bottom: 0;
}
a {
color: #dd4814;
}
// Define backgrounds
body {
background-image: url("images/background-paper.png");
&.community-page {
background: url("images/background-dotted.png") repeat scroll 0 0 #F5F6F7;
}
}
header.banner {
margin-bottom: 0;
nav {
overflow: visible !important;
height: 44px;
ul li a {
line-height: 17px;
font-weight: 400 !important;
}
}
nav.nav-primary {
ul li a {
border-left: 1px solid lighten($ubuntu-orange, 10%) !important;
&:hover {
background: #e1662f !important;
}
&:active, &.active {
background: #b83a10 !important;
}
}
div.logo {
top: 0;
height: 44px;
margin-left: 0;
a {
font-size: 1.4em;
font-weight: 500;
color: #fff;
&:hover, &:active, &:focus {
text-decoration: none;
}
}
}
}
&.inverted {
background: $light-grey;
margin-bottom: 20px;
z-index: 0 !important;
nav {
height: 45px;
}
.nav-primary {
ul {
border-color: lighten($light-grey, 10%);
margin-top: 1px;
li {
&, &:last-child {
border-color: darken($light-grey, 5%);
}
a {
&:link,
&:visited {
border-color: lighten($light-grey, 7%) !important;
color: darken($warm-grey, 10%);
}
&:hover {
background: #fff !important;
color: lighten($cool-grey, 7%) !important;
}
}
}
}
a.active, a:active {
border-color:darken($light-grey, 5%);
background:darken($light-grey, 5%) !important;
}
}
}
}
div.logo {
overflow: visible !important;
div.website-selector {
position: absolute;
display: none;
width: 250px;
z-index: 3;
top: 44px;
left: -30px;
background: rgba(0, 0, 0, 0);
ol {
padding: 0.4em 0;
width: 100%;
background: #fff;
border: 1px solid #d5d5d5;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
font-size: 15px !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
li {
margin: 0;
font-size: 15px;
padding: 0 1.2em;
a {
width: 100%;
display: block;
padding: 0.3em 0;
color: #333 !important;
font-size: 15px !important;
&:hover, &.active {
color: #dd4814 !important;
}
}
&.website-selector-footer {
text-align: center;
a.social {
background-image: url("images/common/social.png");
height: 18px;
width: 18px;
padding: 0;
margin: 10px 6px;
display: inline-block;
&.facebook {
background-position: 0 0;
&:hover {
background-position: 0 36px;
}
}
&.twitter {
background-position: 54px 0;
&:hover {
background-position: 54px 36px;
}
}
&.gplus {
background-position: 36px 0;
&:hover {
background-position: 36px 36px;
}
}
&.youtube {
background-position: 18px 0;
&:hover {
background-position: 18px 36px;
}
}
}
}
}
&:before {
height: 10px;
width: 100%;
background: #000;
}
}
}
&:hover div.website-selector {
display: block;
}
}
nav.nav-secondary {
border-left: none;
border-right: none;
border-color: #dfdcd9;
ul {
li a {
margin-top: 8px;
&.active {
color: #dd4814 !important;
font-weight: 300 !important;
}
}
&.breadcrumb li {
margin: 0;
a.breadcrumb-link {
margin-right: 0 !important;
&:after {
content: "›";
margin-left: 3px;
}
}
}
}
}
nav.nav-footer {
width: 984px;
margin: auto;
display: flex;
& > div {
flex: 1;
padding: 0 10px;
border-left: 1px dotted #333;
h2 {
padding-bottom: 0;
}
ul li {
margin-bottom: 0;
line-height: 17px;
a {
font-size: 0.75em;
color: #333;
}
}
&:first-child {
padding-left: 0;
border-left: 0;
}
&:last-child {
padding-right: 0;
}
}
}
footer {
background: #ececec !important;
hr {
border: 0;
border-bottom: 1px solid #d8d8d8;
margin: 1.5em 0;
}
}
// Responsiveness
@media all and (max-width: $site-max-width) {
div.wrapper {
width: 100% !important;
}
}
.inner-wrapper {
box-shadow: 0 2px 3px #c9c9c9;
}
// A bit of style for buttons
a.button--primary, a.button--secondary {
margin: 0 0 0.75em 0;
font-size: 1.1em;
padding: 8px 17px !important;
border-radius: 3px;
}
// Import Vanilla Framework
@import "../../node_modules/vanilla-framework/scss/build.scss";
@import "../../node_modules/ubuntu-vanilla-theme/scss/theme";
@include ubuntu-vanilla-theme;
// Import backports from web-style-guide
@import "wsg-backports.scss";
// Import Ubuntu-it common customizations
@import "ubuntuit.scss";
// Import Ubuntu-it website's customizations
@import "www.scss";
@charset 'UTF-8';
.row.row-image-centered,
div.box-image-centered,
div.row-image-centered,
div.row.row-image-centered {
padding: 20px 10px 0;
}
.row-box.row-image-centered {
padding-top: 20px;
padding-bottom: 20px;
}
.row.row-image-centered {
padding-top: 40px;
padding-bottom: 40px;
}
.row-hero.row-image-centered {
padding-top: 0;
}
div.row-image-centered,
div.box-image-centered,
div.row.row-image-centered {
//display: block;
div,
span {
//display: block;
float: none;
}
span {
width: 100%;
img {
height: auto;
max-width: 100%;
display: block;
padding: 0;
margin: 0 auto;
margin-bottom: 20px;
}
}
p,
h2,
h3 {
float: none;
}
}
@media only screen and (min-width : 768px) {
div.row-image-centered,
div.row.row-image-centered,
div.box-image-centered {
box-sizing: border-box;
padding-bottom: 20px;
display: table;
div {
float: none;
display: table-cell;
position: relative;
p,
h2,
h3 {
display: block;
width: 100%;
float: left;
}
+ span img { // if image is on the right hand side
padding-right: 0;
margin-bottom: 20px;
}
}
span {
display: table-cell;
float: none;
position: relative;
text-align: center;
top: 0;
vertical-align: middle;
width: auto;
img {
padding-right: 20px; // if image is on the left hand side
}
}
}
/*
alternative to row-image-centered
requires equal-height class on row
add align-vertically to the div containing the image
http://caniuse.com/transforms2d
*/
.js .align-vertically {
-moz-transform-style: preserve-3d;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
img,
div {
-ms-transform: translateY(-50%); // for IE9
-webkit-transform: translateY(-50%);
position: relative;
top: 50%;
transform: translateY(-50%);
}
}
} //@media only screen and (min-width : 768px)
div.box-image-centered {
padding-top: 20px;
}
@media only screen and (min-width : 768px) {
.row.row-image-centered,
div.box-image-centered,
div.row-image-centered,
div.row.row-image-centered {
padding: 30px;
}
div.box-image-centered div + span img,
div.row-image-centered div + span img,
div.row.row-image-centered div + span img,
div.box-image-centered span img.priority-0,
div.row-image-centered span img.priority-0,
div.row.row-image-centered span img.priority-0 {
margin-right: auto;
display: table-cell;
margin-bottom: 0;
}
} // @media only screen and (min-width : 768px)
@media only screen and (min-width: 984px) {
.row.row-image-centered,
div.row-image-centered,
div.row.row-image-centered,
div.box-image-centered {
box-sizing: border-box;
padding: 40px;
display: table;
div {
float: none;
display: table-cell;
position: relative;
p,
h2,
h3 {
display: block;
width: 100%;
float: left;
}
+ span img { // if image is on the right hand side
padding-right: 0;
//margin-bottom: 20px;
}
}
span {
display: table-cell;
float: none;
position: relative;
text-align: center;
top: 0;
vertical-align: middle;
width: auto;
img {
padding-right: 20px; // if image is on the left hand side
}
}
}
} // end @media only screen and (min-width: 984px)
.background-wallpaper {
@extend .no-border;
color: #fff;
.box {
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2) inset;
background-color: rgba(0, 0, 0, 0.25);
border: 0;
}
a.button--secondary {
border: 0;
}
&.ubuntu {
background: url(images/wallpapers/ubuntu.jpg) 100% 70%;
}
}
var gulp = require("gulp");
var postcss = require("gulp-postcss");
var autoprefixer = require("autoprefixer");
var sass = require("gulp-sass");
var concat = require("gulp-concat");
var uglify = require("gulp-uglify");
gulp.task("sass", function() {
return gulp.src("assets/sass/website.scss")
.pipe(sass().on('error', sass.logError))
.pipe(postcss([autoprefixer()]))
.pipe(gulp.dest("uitwww/static"));
});
gulp.task("js", function() {
return gulp.src(["assets/js/vendor/*.js",
"node_modules/vanilla-framework/js/core.js",
"assets/js/*.js"])
.pipe(concat("website.js"))
.pipe(uglify())
.pipe(gulp.dest("uitwww/static"));
});
gulp.task("watch", function() {
gulp.start("sass");
gulp.start("js");
gulp.watch("assets/sass/**/*.scss", ["sass"]);
gulp.watch("assets/js/**/*.js", ["js"]);
});
gulp.task("default", function() {
gulp.start("sass");
gulp.start("js");
});
# Ubuntu-it website source code
# Copyright (C) 2015 Pietro Albini
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU 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; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import setuptools
setuptools.setup(
name = "uitwww",
version = "1",
url = "http://www.ubuntu-it.org",
license = "GNU-GPL v3",
author = "Ubuntu-it website team",
author_email = "gruppo-web@liste.ubuntu-it.org",
description = "Source code of the ubuntu-it website",
install_requires = [
"flask",
"click",
"gunicorn",
],
packages = [
"uitwww",
],
entry_points = {
"console_scripts": [
"uitwww = uitwww.__main__:cli",
],
},
include_package_data = True,
zip_safe = False,
classifiers = [
"Not on PyPI"
],
)
# Ubuntu-it's website
# Copyright (C) 2015 Pietro Albini
#
# 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; without 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 os
import shutil
import glob
import re
import invoke
BASE = os.path.dirname(__file__)
PYTHON = "python3"
PROJECT = "uitwww"
def create_env(name, requirements=False, self=False, force=False):
"""Create a new virtual environment"""
path = os.path.join(BASE, "build", "envs", name)
# Don't re-create the environment if force is False
if os.path.exists(path):
if force:
shutil.rmtree(path)
else:
return path
invoke.run("virtualenv -p %s %s" % (PYTHON, path))
if requirements:
invoke.run("%s/bin/pip install -r requirements-%s.txt" % (path, name))
if self:
invoke.run("%s/bin/pip install -e ." % path)
return path
@invoke.task
def clean():
"""Clean all the build things"""
for dir in "build", "%s.egg-info" % PROJECT:
path = os.path.join(BASE, dir)
if not os.path.exists(path):
continue
shutil.rmtree(path)
exclude = ["%s/.git" % BASE, "%s/build" % BASE]
remove_files = [
re.compile(r'.py[co]$'), re.compile(r'.mo$'),
"%s/uitwww/static/website.css" % BASE,
"%s/uitwww/static/website.js" % BASE,
]
remove_dirs = [
re.compile('__pycache__'),
"%s/node_modules" % BASE,
]
# Remove all the unwanted things
for root, dirs, files in os.walk(BASE, topdown=False):
# Skip excluded directories
skip = False
for one in exclude:
if one == root or (root != BASE and one.startswith(root)):
skip = True
break
if skip:
continue
# Remove all the unwanted files
for file in files:
file = os.path.join(root, file)
for regex in remove_files:
if type(regex) == str:
if file != regex:
continue
elif not regex.search(file):
continue
os.remove(file)
# Remove all the unwanted directories
for dir in dirs:
dir = os.path.join(root, dir)
for regex in remove_dirs:
if type(regex) == str:
if dir != regex:
continue
elif not regex.search(dir):
continue
shutil.rmtree(dir)
@invoke.task
def assets(watch=False):
"""Build the assets"""
# Be sure to have all the dependencies installed
if not os.path.exists("%s/node_modules" % BASE):
invoke.run("npm install", pty=True)
if watch:
try:
invoke.run("gulp watch", pty=True)
except KeyboardInterrupt:
pass
else:
invoke.run("gulp", pty=True)
@invoke.task(pre=[assets])
def devel():
"""Setup the development environment"""
create_env("devel", self=True, force=True)
@invoke.task(pre=[assets])
def build():
"""Create a new build"""
env = create_env("build", requirements=True)
out = os.path.join(BASE, "build", "packages")
if os.path.exists(out):
for file in glob.glob(os.path.join(out, "*")):
os.remove(file)
for type in "sdist", "bdist_wheel":
invoke.run("%s/bin/python setup.py %s -d %s" % (env, type, out))
# 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/>.
import flask
from uitwww import pages
def create_app(cache_path=None):
"""Create a new instance of the application"""
app = flask.Flask(__name__, static_url_path="/+assets")
# Apply the static cache thing
if cache_path is not None:
app.config["CACHE_PATH"] = cache_path
cache.install_cache(app)
app.register_blueprint(pages.prepare_blueprint(app))
pages.prepare_navbar(app)
return app
# 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/>.
import os
import click
import uitwww
from uitwww import utils
@click.group()
def cli():
""" Ubuntu-it website's command line utility """
pass
@cli.command("run")
@click.argument("cache", required=False, default=None)
@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(cache, gunicorn_config, port, public, workers, debug):
# Create the application instance
app = uitwww.create_app(cache)
host = "127.0.0.1"
if public:
host = "0.0.0.0"
# In debug mode, run the flask builtin webserver
if debug:
extra_files = [
os.path.join(os.path.dirname(__file__), "navbar.json"),
]
app.run(debug=True, port=port, host=host, extra_files=extra_files)
# Else run the application with gunicorn
else:
options = {
"bind": host+":"+str(port),
"workers": workers,
"accesslog": "-",
"errorlog": "-",
}
server = utils.GunicornInstance(gunicorn_config, options)
server.app = app
try:
server.run()
except SystemExit:
pass
# 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/>.
import os
import shutil
import flask
def enable(func):
"""This decorator will cache the view"""
func.use_cache = True
return func
def remove(path, recursive=False):
"""Remove a path from the cache"""
app = flask.current_app
path = os.path.join(app.cache_path, path)
try:
if os.path.isdir(path):
if recursive:
shutil.rmtree(path)
return
path = os.path.join(path, "index.html")
os.remove(path)
except IOError:
# If a file wasn't found, we're ok right?
pass
def after_request(response):
"""Hook meant to be executed after a request"""
app = flask.current_app
# Get the function for the current app
func = app.view_functions[flask.request.endpoint]
# Do nothing if no cache is enabled either for the app
# or for the endpoint
if "CACHE_PATH" not in app.config or not hasattr(func, "use_cache"):
return response
else:
cache_path = os.path.realpath(app.config["CACHE_PATH"])
url = flask.request.path
method = flask.request.method
status = response.status_code
content = response.get_data(as_text=True)
# Do dome filtering
if status != 200 or method != "GET":
return result
# Normalize the page url
if url.endswith("/"):
url += "index.html"
else:
url += ".html"
if url.startswith("/"):
url = url[1:] # Remove / at the start
path = os.path.join(cache_path, url)
os.makedirs(path.rsplit("/", 1)[0], exist_ok=True)
with open(path, "w") as f:
f.write(content)
return response
def before_request():
"""Hook meant to be executed before a request"""
# TODO: implement the cache
pass
def install_cache(app):
"""Install the cache on a specific app"""
app.before_request(before_request)
app.after_request(after_request)
[
{
"name": "Home page",
"endpoint": "pages.index",
"subs": [
{
"name": "Download",
"endpoint": "pages.download_index"
}
]
},
{
"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"
}
]
}
]
# 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/>.
import os
import json
import flask
import pkg_resources
from uitwww import cache
def get_pages_list(app, base=None, level=0):
"""Get the list of the pages, froma a directory"""
root = os.path.join(app.root_path, app.template_folder)
if base is None:
base = os.path.join(root, "pages")
pages = {}
# Iterate over all templates
for file in os.listdir(base):
tmplpath = os.path.join(base, file)
# Recursively scan sub-directories
if os.path.isdir(tmplpath):
pages.update(get_pages_list(app, tmplpath))
continue
url = tmplpath
# Remove templates folder from the tmplpath
if tmplpath.startswith(root):
tmplpath = tmplpath[len(root)+1:]
# Remove templates folder + pages folder from the url
pagesdir = os.path.join(root, "pages")
if url.startswith(pagesdir):
url = url[len(pagesdir):]
# Don't index hidden files
if any(one.startswith(".") for one in url.split("/")):
continue
# Remove any index.html
if url.endswith("index.html"):
url = url[:-len("index.html")]
# Remove any .html suffix
if url.endswith(".html"):
url = url[:-len(".html")]
# Remove trailing slashes
if len(url) > 1 and url.endswith("/"):
url = url[:-1]
pages[url] = tmplpath
return pages
def prepare_blueprint(app):
"""Prepare a blueprint with all the pages"""
bp = flask.Blueprint("pages", __name__)
# Dynamically generate all the pages
for url, tmpl in get_pages_list(app).items():
endpoint = tmpl[len("pages_"):-len(".html")].replace("/", "_")
@bp.route(url, endpoint=endpoint)
@cache.enable
def _(_tmpl=tmpl):
return flask.render_template(_tmpl)
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}
../../assets/images
\ No newline at end of file
{# 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 extra_body %}class="community-page"{% 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/>.
#}
{% from "macros.html" import nav_item with context %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{% block title %}Senza titolo{% endblock %} - Ubuntu-it</title>
<link rel="stylesheet" href="{{ url_for("static", filename="website.css") }}" />
<script type="text/javascript" src="{{ url_for("static", filename="website.js") }}"></script>
</head>
<body {% block extra_body %}{% endblock %}>
<header class="banner global" role="banner">
<nav role="navigation" class="nav-primary nav-right" id="nav">
<span id="main-navigation-link"><a href="#main-navigation">Jump to site nav</a></span>
<div class="logo">
<a href="/">ubuntu-it</a>
{# Used <ol> so it won't be styled #}
<div class="website-selector">
<ol>
<li><a href="http://www.ubuntu-it.org" class="active">Sito web</a></li>
<li><a href="http://wiki.ubuntu-it.org">Documentazione e wiki</a></li>
<li><a href="http://forum.ubuntu-it.org">Forum</a></li>
<li><a href="http://chiedi.ubuntu-it.org">Domande e risposte</a></li>
<li><a href="http://chat.ubuntu-it.org">Chat IRC</a></li>
<li><a href="http://cerca.ubuntu-it.org">Ricerca</a></li>
<li><a href="http://planet.ubuntu-it.org">Planet della comunità</a></li>
<li class="website-selector-footer">
<a class="social facebook" href="https://www.facebook.com/ubuntu.it"></a>
<a class="social twitter" href="https://twitter.com/ubuntuit"></a>
<a class="social gplus" href="https://plus.google.com/+ubuntuit"></a>
<a class="social youtube" href="https://www.youtube.com/ubuntuitpromozione"></a>
</li>
</ol>
</div>
</div>
<ul>
{% for item in _navbar[0] %}
{{ nav_item(item) }}
{% endfor %}
</ul>
</nav>
<div class="nav-toggle">
<a href="#nav" class="nav-toggle__link open"></a>
<a href="#" class="nav-toggle__link close"></a>
</div>
</header>
<header class="banner inverted">
<nav role="navigation" class="nav-primary nav-right" id="subnav">
<ul>
{% for item in _navbar[1] %}
{{ nav_item(item) }}
{% endfor %}
</ul>
</nav>
</header>
<div class="wrapper">
<div id="main-content" class="inner-wrapper">
{% if _navbar|length >= 3 %}
<nav class="nav-secondary clearfix">
<ul class="breadcrumb">
<li>
<a href="{{ url_for(_navbar_active[1].endpoint) }}"
class="breadcrumb-link">
{{ _navbar_active[1].name }}
</a>
</li>
</ul>
<ul class="second-level-nav">
{% for item in _navbar[2] %}
{{ nav_item(item) }}
{% endfor %}
</ul>
</nav>
{% endif %}
{% block content %}{% endblock %}
</div>
</div>
<footer class="global clearfix no-global">
<nav class="nav-footer">
{% for category in _navbar[0] %}
<div>
<h2><a href="{{ url_for(category.endpoint) }}">{{ category.name }}</a></h2>
{% if "subs" in category %}
<ul>
{% for item in category.subs %}
{{ nav_item(item) }}
{% endfor %}
</ul>
{% endif %}
</div>
{% endfor %}
</nav>
<hr>
<nav id="main-navigation" role="navigation" class="clearfix">
<div class="legal clearfix">
<p class="twelve-col">
Ubuntu e Canonical sono marchi registrati da Canonical Ltd.<br>
Sito realizzato con &#9829; dal Gruppo Web di Ubuntu-it, con
<a href="https://www.python.org/">Python</a>,
<a href="http://flask.pocoo.org/">Flask</a> e
<a href="http://www.postgresql.org/">PostgreSQL</a>.
</p>
<ul class="inline-list clear">
<li><a href="{{ url_for("pages.cookies") }}"><small>Informativa sui cookie</small></a></li>
<li><a href="http://code.ubuntu-it.org/ubuntu-it-web/www/issues">
<small>Segnala un errore</small>
</a></li>
<li><a href="http://code.ubuntu-it.org/ubuntu-it-web/www">
<small>Scarica il codice</small>
</a></li>
<li><a href="http://wiki.ubuntu-it.org/GruppoWeb">
<small>Collabora con noi</small>
</a></li>
</ul>
<span class="accessibility-aid"><a href="#">Got to the top of the page</a></span>
</div>
</nav>
</footer>
</body>
</html>
{# 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/>.
#}
{% 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 %}
{# 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 %}Informativa sui cookie{% endblock %}
{% block content %}
<div class="row">
<div class="eight-col">
<h1>Informativa sui cookie</h1>
<p class="intro">Valida per tutti i portali di Ubuntu-it</p>
</div>
</div>
{% endblock %}
{% 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="row row-hero no-border">
<div class="nine-col">
<h1>Scarica Ubuntu</h1>
<p class="intro">Entra subito nel mondo Ubuntu. Scaricalo ora!</p>
<p>
<a class="button--primary" href="{{ url_for("pages.download_desktop") }}">Desktop e portatili</a>
<a class="button--primary" href="#">Server</a>
<a class="button--primary" href="#">Prova una derivata</a>
</p>
</div>
<div class="three-col last-col">
<span class="not-for-small">
<img src="{{ url_for("static", filename="images/pictograms/download.svg")}}">
</span>
</div>
</div>
<div class="row background-wallpaper ubuntu">
<div class="six-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="button--secondary smaller" href="#">Ottieni supporto</a>
</div>
<div class="six-col last-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="button--primary" href="#">Richiedi un DVD</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="six-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="button--primary smaller" href="http://wiki.ubuntu-it.org/Installazione/RequisitiDiSistema">
Leggi i requisiti
</a>
</div>
<div class="six-col last-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="button--primary smaller" href="#">Inizia subito a contribuire</a>
</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 %}Home page{% endblock %}
{% block content %}
<div class="row row-hero no-border" style="padding-bottom: 20px;">
<p>
Questo sito contiene la versione in fase di sviluppo del sito web
di ubuntu-it.<br>
Non è ancora completo, e potrebbe subire modifiche sostanziali,
oltre a contenere errori.
</p>
<p>
Se volete contribuire siete i benvenuti!
<a href="http://wiki.ubuntu-it.org/GruppoWeb/Contribuire">
Scopri come aiutarci</a>!
</p>
<p><b>Il Gruppo Web di ubuntu-it</b></p>
</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-community.html" %}
{% block title %}Supporto{% endblock %}
{% block content %}
<div class="row row-hero">
<h1 class="text-center">Supporto</h1>
<p class="intro text-center">Hai bisogno di aiuto oppure hai qualche curiosità da soddisfare? Guarda qui.</p>
</div>
<div class="row row-image-centered">
<div class="nine-col">
<h2>Documentazione</h2>
<p>
La documentazione fornita da Ubuntu-it è il primo posto dove cercare per risolvere i problemi o per avere informazioni utli.
Puoi trovare le guide e le schede tecniche create dalla comunità per aiutarti ad entrare nel mondo Ubuntu, oppure consultare
i manuali d'uso ufficiali.
</p>
<div>
<a class="button--primary" href="http://help.ubuntu-it.org/">Manuali d'uso</a>
<a class="button--primary" href="http://wiki.ubuntu-it.org/Documentazione/Indice">Guide della comunità</a>
</div>
</div>
<span>
<img src="http://design.ubuntu.com/wp-content/uploads/pictogram-articles-orange-hex.svg" class="not-for-small">
</span>
</div>
<div class="row">
<div class="six-col">
<h2>Domande e risposte</h2>
<p>
<a href="http://chiedi.ubuntu-it.org/">Chiedi</a> è il portale di Ubuntu-it specifico per domande e risposte.
In esso puoi fare domande o rispondere ad quelle di altre persone in modo semplice e veloce.
</p>
<div>
<a class="button--primary" href="http://chiedi.ubuntu-it.org/">Entra su Chiedi</a>
</div>
</div>
<div class="six-col last-col">
<h2>Forum della comunità</h2>
<p>
Il <a href="http://forum.ubuntu-it.org/">forum</a> di Ubuntu-it è uno strumento di supporto che pone più enfasi
nella conversazione fra gli utenti, adatto per confrontarsi o discutere di soluzioni alternative.
</p>
<div>
<a class="button--primary" href="http://forum.ubuntu-it.org/">Entra sul forum</a>
</div>
</div>
</div>
<div class="row row-image-centered no-border">
<div class="nine-col">
<h2>Canale di chat</h2>
<p>
Ubuntu-it dispone di un canale di chat IRC, per ottenere un supporto in tempo reale, veloce ed efficace.
Puoi trovarlo su freenode come <i>#ubuntu-it</i>, o accederci direttamente da
<a href="http://chat.ubuntu-it.org/#ubuntu-it">qui</a>.
</p>
<div>
<a class="button--primary" href="http://chat.ubuntu-it.org/#ubuntu-it">Entra subito in chat</a>
</div>
</div>
<span>
<img src="http://design.ubuntu.com/wp-content/uploads/pictogram-discussion-orange-hex.svg" class="not-for-small">
</span>
</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/>.
import gunicorn.app.base as baseapp
class GunicornInstance(baseapp.BaseApplication):
"""A gunicorn instance which runs the app we want"""
def __init__(self, config_file=None, options=None):
# Initialize the classs
self.options = options if options is not None else {}
self.config_file = config_file
self.app = None
super(GunicornInstance, self).__init__()
def load_config(self):
"""Apply the configuration to this gunicorn instance"""
config = self.options.copy()
# First of all, load from the configuration file
if self.config_file is not None:
from_file = baseapp.Application.get_config_from_filename(
object(), self.config_file)
config.update(from_file)
for key, value in config.items():
# Some cleanup
if key not in self.cfg.settings or value is None:
continue
self.cfg.set(key.lower(), value)
def load(self):
"""Load the application"""
if self.app is None:
raise RuntimeError("Application object not set")
return self.app
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