Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
Nuovo sito
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
16
Issues
16
List
Boards
Labels
Milestones
Merge Requests
2
Merge Requests
2
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gruppo Web
Nuovo sito
Commits
91fc90c4
Commit
91fc90c4
authored
Sep 06, 2018
by
Alessandro Viprati
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into 'scopri-ubuntu'
# Conflicts: # uitwww/data/downloads.toml
parents
c42184be
e6f5e7fe
Pipeline
#109
running with stage
Changes
11
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
322 additions
and
40 deletions
+322
-40
uitwww/__init__.py
uitwww/__init__.py
+6
-7
uitwww/actions.py
uitwww/actions.py
+108
-0
uitwww/auth.py
uitwww/auth.py
+51
-28
uitwww/data/downloads.toml
uitwww/data/downloads.toml
+3
-3
uitwww/data/permissions.yml
uitwww/data/permissions.yml
+1
-0
uitwww/db.py
uitwww/db.py
+12
-0
uitwww/templates/actions/macros.html
uitwww/templates/actions/macros.html
+70
-0
uitwww/templates/actions/show.html
uitwww/templates/actions/show.html
+32
-0
uitwww/templates/auth/session.html
uitwww/templates/auth/session.html
+32
-2
uitwww/templates/auth/sessions.html
uitwww/templates/auth/sessions.html
+2
-0
uitwww/templates/layout.html
uitwww/templates/layout.html
+5
-0
No files found.
uitwww/__init__.py
View file @
91fc90c4
...
...
@@ -18,13 +18,14 @@ import os
import
flask
from
.
import
actions
from
.
import
auth
from
.
import
cache
from
.
import
db
from
.
import
pages
from
.
import
utils
from
.
import
download
from
.
import
navbar
from
.
import
pages
from
.
import
utils
from
.
import
utils
...
...
@@ -55,12 +56,10 @@ def create_app(data_path):
utils
.
prepare_app
(
app
)
app
.
download
=
download
.
Downloads
(
data_path
)
app
.
register_blueprint
(
app
.
download
.
prepare_blueprint
(
app
),
url_prefix
=
"/download"
,
)
app
.
register_blueprint
(
auth
.
prepare_blueprint
(
app
),
url_prefix
=
"/+auth"
)
app
.
register_blueprint
(
app
.
download
.
prepare_blueprint
(
app
),
url_prefix
=
"/download"
)
app
.
register_blueprint
(
actions
.
prepare_blueprint
(
app
),
url_prefix
=
"/+actions"
)
app
.
register_blueprint
(
auth
.
prepare_blueprint
(
app
),
url_prefix
=
"/+auth"
)
app
.
register_blueprint
(
pages
.
prepare_blueprint
(
app
))
nav
=
navbar
.
Navbar
()
...
...
uitwww/actions.py
0 → 100644
View file @
91fc90c4
# 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
math
import
time
import
flask
from
uitwww
import
auth
ACTIONS_PER_PAGE
=
25
class
PageNotFoundError
(
BaseException
):
pass
def
log
(
message
,
session
=
None
):
"""Log an action into the database"""
date
=
int
(
time
.
time
())
if
session
is
None
:
session
=
flask
.
g
.
auth_id
flask
.
current_app
.
db
.
update
(
"INSERT INTO actions (session, date, message) VALUES (?, ?, ?);"
,
session
,
date
,
message
,
)
def
list_actions
(
page
=
None
,
session
=
None
):
"""List all the available actions"""
result
=
{
"actions"
:
[]
}
args
=
[]
where
=
""
if
session
is
not
None
:
where
=
"WHERE a.session = ?"
args
.
append
(
session
)
limit
=
""
if
page
is
not
None
:
page
=
page
-
1
total
=
flask
.
current_app
.
db
.
query
(
"SELECT COUNT(*) FROM actions %s;"
%
where
,
*
args
)[
0
][
0
]
if
page
<
0
or
page
>=
math
.
ceil
(
total
/
ACTIONS_PER_PAGE
):
raise
PageNotFoundError
result
[
"current_page"
]
=
page
+
1
result
[
"has_prev"
]
=
page
!=
0
result
[
"has_next"
]
=
page
+
1
<
math
.
ceil
(
total
/
ACTIONS_PER_PAGE
)
limit
=
"LIMIT ? OFFSET ?"
args
+=
[
ACTIONS_PER_PAGE
,
page
*
ACTIONS_PER_PAGE
]
rows
=
flask
.
current_app
.
db
.
query
(
"SELECT s.nickname, s.ip, s.id, a.date, a.message FROM actions AS a "
"INNER JOIN auth_sessions AS s ON (s.id = a.session) %s "
"ORDER BY date DESC %s;"
%
(
where
,
limit
),
*
args
)
for
row
in
rows
:
result
[
"actions"
].
append
({
"nickname"
:
row
[
0
],
"ip"
:
row
[
1
],
"session"
:
row
[
2
],
"date"
:
row
[
3
],
"message"
:
row
[
4
],
})
return
result
def
prepare_blueprint
(
app
):
"""Prepare the auth blueprint"""
bp
=
flask
.
Blueprint
(
"actions"
,
__name__
)
@
bp
.
route
(
"/"
)
@
bp
.
route
(
"/<int:page>"
)
@
auth
.
permission
(
"actions.show"
)
def
show
(
page
=
1
):
try
:
actions
=
list_actions
(
page
=
page
)
except
PageNotFoundError
:
return
flask
.
abort
(
404
)
return
flask
.
render_template
(
"actions/show.html"
,
actions
=
actions
,
)
return
bp
uitwww/auth.py
View file @
91fc90c4
...
...
@@ -43,18 +43,19 @@ class Sessions:
id
=
str
(
uuid
.
uuid4
())
ip
=
flask
.
request
.
remote_addr
now
=
int
(
time
.
time
())
self
.
db
.
update
(
"INSERT INTO auth_sessions (id, nickname, teams, ip,
expires_at)
"
"
VALUES (?, ?, ?, ?, ?)"
,
id
,
nickname
,
","
.
join
(
teams
),
ip
,
int
(
time
.
time
())
+
SESSION_EXPIRES_AFTER
,
"INSERT INTO auth_sessions (id, nickname, teams, ip,
created_at,
"
"
expires_at) VALUES (?, ?, ?, ?, ?, ?)"
,
id
,
nickname
,
","
.
join
(
teams
),
ip
,
now
,
now
+
SESSION_EXPIRES_AFTER
,
)
return
id
def
check
(
self
,
id
):
"""Check if a session is valid and return its data"""
data
=
self
.
db
.
query
(
"SELECT nickname, teams, ip, expires_at
FROM auth_sessions
"
"WHERE id = ?"
,
id
,
"SELECT nickname, teams, ip, expires_at
, created_at
"
"
FROM auth_sessions
WHERE id = ?"
,
id
,
)
if
not
data
:
raise
SessionError
(
"La tua sessione è scaduta, accedi di nuovo."
)
...
...
@@ -65,7 +66,6 @@ class Sessions:
expires_at
=
data
[
0
][
3
]
if
expires_at
is
None
or
expires_at
<
time
.
time
():
self
.
delete
(
id
)
raise
SessionError
(
"La tua sessione è scaduta, accedi di nuovo."
)
else
:
# Bump the session every time a new page is visited
...
...
@@ -82,50 +82,58 @@ class Sessions:
"teams"
:
data
[
0
][
1
].
split
(
","
),
}
def
delete
(
self
,
id
):
"""Delete a session"""
self
.
db
.
update
(
"DELETE FROM auth_sessions WHERE id = ?;"
,
id
)
def
disable
(
self
,
id
):
"""Disable a session"""
self
.
db
.
update
(
"UPDATE auth_sessions SET expires_at = ? WHERE id = ?;"
,
int
(
time
.
time
()),
id
,
)
def
delete_all
(
self
,
except_id
):
"""Delete every session except this one"""
self
.
db
.
update
(
"DELETE FROM auth_sessions WHERE id != ?;"
,
except_id
)
def
disable_all
(
self
,
except_id
):
"""Disable every active session except this one"""
now
=
int
(
time
.
time
())
self
.
db
.
update
(
"UPDATE auth_sessions SET expires_at = ? WHERE id != ? AND "
"expires_at IS NOT NULL AND expires_at >= ?;"
,
now
,
except_id
,
now
,
)
def
all
(
self
):
"""Return all the sessions"""
rows
=
self
.
db
.
query
(
"SELECT id, nickname, teams, ip, expires_at FROM auth_sessions;"
)
now
=
time
.
time
()
rows
=
self
.
db
.
query
(
"SELECT id, nickname, teams, ip, expires_at, created_at "
"FROM auth_sessions WHERE expires_at IS NOT NULL "
"AND expires_at >= ?;"
,
now
,
)
result
=
[]
for
row
in
rows
:
# Delete expired sessions
if
row
[
0
]
is
None
or
row
[
4
]
<
now
:
self
.
delete
(
row
[
0
])
continue
result
.
append
({
"id"
:
row
[
0
],
"nickname"
:
row
[
1
],
"teams"
:
row
[
2
].
split
(
","
),
"ip"
:
row
[
3
],
"expires_at"
:
row
[
4
],
"created_at"
:
row
[
5
],
})
return
result
def
get
(
self
,
id
):
"""Return details about a session"""
row
=
self
.
db
.
query
(
"SELECT nickname, teams, ip, expires_at FROM auth_sessions WHERE id = ?;"
,
id
)
row
=
self
.
db
.
query
(
"SELECT nickname, teams, ip, expires_at, created_at "
"FROM auth_sessions WHERE id = ?;"
,
id
,
)
if
row
:
# Delete expired sessions
if
row
[
0
][
3
]
is
None
or
row
[
0
][
3
]
<
time
.
time
():
self
.
delete
(
id
)
return
return
{
"id"
:
id
,
"nickname"
:
row
[
0
][
0
],
"teams"
:
row
[
0
][
1
].
split
(
","
),
"ip"
:
row
[
0
][
2
],
"expires_at"
:
row
[
0
][
3
],
"created_at"
:
row
[
0
][
4
],
"active"
:
row
[
0
][
3
]
>=
time
.
time
(),
}
def
count
(
self
):
...
...
@@ -197,6 +205,8 @@ def permission(perms):
def
prepare_blueprint
(
app
):
"""Prepare the auth blueprint"""
from
uitwww
import
actions
bp
=
flask
.
Blueprint
(
"auth"
,
__name__
)
oid
=
flask_openid
.
OpenID
(
...
...
@@ -238,6 +248,9 @@ def prepare_blueprint(app):
flask
.
session
[
"auth"
]
=
sessions
.
create
(
resp
.
nickname
,
teams
)
flask
.
flash
(
"Benvenuto %s!"
%
resp
.
nickname
,
"success"
)
actions
.
log
(
"Accesso effettuato"
,
session
=
flask
.
session
[
"auth"
])
return
flask
.
redirect
(
flask
.
url_for
(
"pages.index"
))
@
bp
.
route
(
"/login"
)
...
...
@@ -258,7 +271,7 @@ def prepare_blueprint(app):
@
bp
.
route
(
"/logout"
)
@
permission
(
"auth.logout"
)
def
logout
():
sessions
.
d
elet
e
(
flask
.
session
[
"auth"
])
sessions
.
d
isabl
e
(
flask
.
session
[
"auth"
])
del
flask
.
session
[
"auth"
]
flask
.
flash
(
"La sessione è stata terminata correttamente."
,
"success"
)
...
...
@@ -276,7 +289,8 @@ def prepare_blueprint(app):
@
bp
.
route
(
"/sessions/+all/revoke"
)
@
permission
(
"auth.sessions.manage"
)
def
sessions_revoke_all
():
sessions
.
delete_all
(
flask
.
g
.
auth_id
)
actions
.
log
(
"Disabilitate tutte le altre sessioni"
)
sessions
.
disable_all
(
flask
.
g
.
auth_id
)
return
flask
.
redirect
(
flask
.
url_for
(
".sessions_list"
))
@
bp
.
route
(
"/sessions/<id>"
)
...
...
@@ -296,10 +310,15 @@ def prepare_blueprint(app):
continue
others
.
append
(
session
)
user_actions
=
[]
if
app
.
permissions
.
check
(
"actions.show"
):
user_actions
=
actions
.
list_actions
(
session
=
id
)
return
flask
.
render_template
(
"auth/session.html"
,
session
=
data
,
others
=
others
,
actions
=
user_actions
,
)
@
bp
.
route
(
"/sessions/<id>/revoke"
)
...
...
@@ -308,7 +327,11 @@ def prepare_blueprint(app):
"auth.sessions.own"
:
lambda
id
:
flask
.
g
.
auth_id
==
id
,
})
def
sessions_revoke
(
id
):
sessions
.
delete
(
id
)
actions
.
log
(
'Disabilitata <a href="%s">una sessione</a>'
%
flask
.
url_for
(
"auth.sessions_show"
,
id
=
id
)
)
sessions
.
disable
(
id
)
return
flask
.
redirect
(
flask
.
url_for
(
".sessions_list"
))
return
bp
uitwww/data/downloads.toml
View file @
91fc90c4
...
...
@@ -114,9 +114,9 @@ archs = { amd64 = "cdimages-derivatives", i386 = "cdimages-derivatives" }
#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" }
lts-only
=
true
releases
=
[
"lts"]
archs
=
{
amd64
=
"cdimages-studio"
,
i386
=
"cdimages-studio"
}
...
...
uitwww/data/permissions.yml
View file @
91fc90c4
permissions
:
-
actions.show
-
auth.logout
-
auth.sessions.manage
-
auth.sessions.own
...
...
uitwww/db.py
View file @
91fc90c4
...
...
@@ -85,4 +85,16 @@ MIGRATIONS = [
(
"add_auth_sessions_expires_at_column"
,
"""
ALTER TABLE auth_sessions ADD COLUMN expires_at INTEGER;
"""
),
(
"add_auth_sessions_created_at_column"
,
"""
ALTER TABLE auth_sessions ADD COLUMN created_at INTEGER;
"""
),
(
"add_actions_table"
,
"""
CREATE TABLE actions (
session TEXT NOT NULL,
date INTEGER NOT NULL,
message TEXT NOT NULL
);
"""
),
]
uitwww/templates/actions/macros.html
0 → 100644
View file @
91fc90c4
{# 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
/>
.
#}
{% macro render_actions(actions, own=False) %}
<div
class=
"table"
>
<table>
<tr>
<th></th>
{% if not own %}
<th>
Nome utente
</th>
{% endif %}
<th>
Data e ora
</th>
{% if not own %}
<th>
Indirizzo IP
</th>
{% endif %}
</tr>
{% for action in actions.actions %}
<tr>
<td>
{{ action.message|safe }}
</td>
{% if not own %}
<td>
{{ action.nickname }}
</td>
{% endif %}
<td>
{{ action["date"]|format_timestamp }}
</td>
{% if not own %}
<td>
{% if (g.auth_name == action.nickname and permission("auth.sessions.own")) or permission("auth.sessions.manage") %}
<a
href=
"{{ url_for("
auth
.
sessions_show
",
id=
action.session)
}}"
>
{{ action.ip }}
</a>
{% else %}
{{ action.ip }}
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
<p
class=
"text-center"
>
{% if actions.current_page %}
{% if actions.has_prev %}
<a
href=
"{{ url_for(request.endpoint, page=actions.current_page - 1) }}"
>
Pagina precedente
</a>
-
{% endif %}
<b>
Pagina {{ actions.current_page }}
</b>
{% if actions.has_next %}
-
<a
href=
"{{ url_for(request.endpoint, page=actions.current_page + 1) }}"
>
Pagina successiva
</a>
{% endif %}
{% endif %}
</p>
{% endmacro %}
uitwww/templates/actions/show.html
0 → 100644
View file @
91fc90c4
{# 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
/>
.
#}
{% extends "layout.html" %}
{% from "actions/macros.html" import render_actions with context %}
{% block title %}Azioni recenti{% endblock %}
{% block content %}
<div
class=
"page"
>
<div
class=
"row"
>
<div
class=
"col"
>
<h1>
Azioni recenti
</h1>
{{ render_actions(actions) }}
</div>
</div>
</div>
{% endblock %}
uitwww/templates/auth/session.html
View file @
91fc90c4
...
...
@@ -16,6 +16,7 @@
#}
{% extends "layout.html" %}
{% from "actions/macros.html" import render_actions with context %}
{% block title %}Dettagli sessione{% endblock %}
...
...
@@ -31,12 +32,24 @@
<td>
Nome utente
</td>
<td><b>
{{ session.nickname }}
</b></td>
</tr>
<tr>
<td>
Stato
</td>
<td>
{% if session.active -%}
<span
class=
"text-green"
>
Attiva
</span>
{%- else -%}
<span
class=
"text-red"
>
Scaduta
</span>
{%- endif %}
</td>
</tr>
<tr>
<td>
Indirizzo IP
</td>
<td>
{{ session.ip }}
</td>
</tr>
<tr>
<td>
Scadenza
</td>
<td>
Inizio
</td>
<td>
{{ session.created_at|format_timestamp }}
</td>
</tr>
<tr>
<td>
{% if session.active %}Scadenza{% else %}Fine{% endif %}
</td>
<td>
{{ session.expires_at|format_timestamp }}
</td>
</tr>
<tr>
...
...
@@ -53,7 +66,7 @@
</table>
</div>
{% if g.auth_id != session.id %}
{% if g.auth_id != session.id
and session.active
%}
<a
class=
"btn"
href=
"{{ url_for("
.
sessions_revoke
",
id=
session.id)
}}"
>
Disabilita sessione
</a>
...
...
@@ -63,11 +76,16 @@
{% if others %}
<div
class=
"row"
>
<div
class=
"col"
>
{% if session.active %}
<h2>
Altre sessioni dell'utente
</h2>
{% else %}
<h2>
Sessioni correnti dell'utente
</h2>
{% endif %}
<div
class=
"table"
>
<table>
<tr>
<th>
Indirizzo IP
</th>
<th>
Inizio
</th>
<th>
Scadenza
</th>
<th></th>
<th></th>
...
...
@@ -75,6 +93,7 @@
{% for session in others %}
<tr>
<td>
{{ session.ip }}
</td>
<td>
{{ session.created_at|format_timestamp }}
<td>
{{ session.expires_at|format_timestamp }}
<td>
<a
href=
"{{ url_for("
.
sessions_show
",
id=
session.id)
}}"
>
...
...
@@ -98,4 +117,15 @@
</div>
{% endif %}
</div>
{% if permission("actions.show") and actions %}
<div
class=
"page"
>
<div
class=
"row"
>
<div
class=
"col"
>
<h2>
Azioni eseguite in questa sessione
</h2>
{{ render_actions(actions, own=True) }}
</div>
</div>
</div>
{% endif %}
{% endblock %}
uitwww/templates/auth/sessions.html
View file @
91fc90c4
...
...
@@ -40,6 +40,7 @@
<tr>
<th>
Nome utente
</th>
<th>
Indirizzo IP
</th>
<th>
Inizio
</th>
<th>
Scadenza
</th>
<th></th>
<th></th>
...
...
@@ -48,6 +49,7 @@
<tr>
<td>
{{ session.nickname }}
</td>
<td>
{{ session.ip }}
</td>
<td>
{{ session.created_at|format_timestamp }}
</td>
<td>
{{ session.expires_at|format_timestamp }}
</td>
<td>
<a
href=
"{{ url_for("
.
sessions_show
",
id=
session.id)
}}"
>
...
...
uitwww/templates/layout.html
View file @
91fc90c4
...
...
@@ -54,6 +54,11 @@
Sessioni attive: {{ g.auth_sessions_count }}
</a></li>
{% endif %}
{% if permission("actions.show") %}
<li><a
href=
"{{ url_for("
actions
.
show
")
}}"
>
Azioni recenti
</a></li>
{% endif %}
</ul>
<ul
class=
"right"
>
{% if permission("auth.sessions.own") %}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment