devpi-admin 1.1.1__tar.gz → 1.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/PKG-INFO +1 -1
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/_version.py +2 -2
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/main.py +16 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/static/css/style.css +19 -3
- devpi_admin-1.1.2/src/devpi_admin/static/favicon.svg +10 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/static/index.html +1 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/static/js/app.js +32 -1
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/.gitignore +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/LICENSE +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/README.md +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/pyproject.toml +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/__init__.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/static/js/api.js +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/static/js/marked.min.js +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/src/devpi_admin/static/js/theme.js +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/__init__.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_cached_versions.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_helpers.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_hooks.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_json_safe.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_package.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_tween.py +0 -0
- {devpi_admin-1.1.1 → devpi_admin-1.1.2}/tests/test_wants_html.py +0 -0
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.1.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 1,
|
|
21
|
+
__version__ = version = '1.1.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 1, 2)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -44,6 +44,14 @@ def devpiserver_pyramid_configure(config, pyramid_config):
|
|
|
44
44
|
lambda request: HTTPFound("/+admin/"),
|
|
45
45
|
route_name="devpi_admin_spa_noslash")
|
|
46
46
|
|
|
47
|
+
# Session validity check.
|
|
48
|
+
pyramid_config.add_route(
|
|
49
|
+
"devpi_admin_session",
|
|
50
|
+
"/+admin-api/session")
|
|
51
|
+
pyramid_config.add_view(
|
|
52
|
+
_session_view, route_name="devpi_admin_session",
|
|
53
|
+
request_method="GET")
|
|
54
|
+
|
|
47
55
|
# Cached packages API for mirror indexes.
|
|
48
56
|
pyramid_config.add_route(
|
|
49
57
|
"devpi_admin_cached",
|
|
@@ -82,6 +90,14 @@ def _serve_index(request):
|
|
|
82
90
|
content_type="text/html")
|
|
83
91
|
|
|
84
92
|
|
|
93
|
+
def _session_view(request):
|
|
94
|
+
"""Return whether the current request carries a valid authenticated session."""
|
|
95
|
+
user = request.authenticated_userid
|
|
96
|
+
if user:
|
|
97
|
+
return _json_response({"valid": True, "user": user})
|
|
98
|
+
raise HTTPForbidden(json_body={"valid": False, "error": "not authenticated"})
|
|
99
|
+
|
|
100
|
+
|
|
85
101
|
def _get_stage_or_404(xom, user, index):
|
|
86
102
|
"""Return stage object or raise HTTPNotFound."""
|
|
87
103
|
stage = xom.model.getstage(user, index)
|
|
@@ -196,14 +196,18 @@ body {
|
|
|
196
196
|
.user-btn-name {
|
|
197
197
|
padding: 4px 10px;
|
|
198
198
|
font-weight: 600;
|
|
199
|
-
color:
|
|
199
|
+
color: #22c55e;
|
|
200
200
|
background: var(--bg);
|
|
201
201
|
cursor: pointer;
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
.user-btn-name:hover {
|
|
205
205
|
background: var(--bg-alt);
|
|
206
|
-
|
|
206
|
+
opacity: 0.8;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.user-btn.is-root .user-btn-name {
|
|
210
|
+
color: #f59e0b;
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
.user-btn-sep {
|
|
@@ -366,7 +370,19 @@ body {
|
|
|
366
370
|
/* --- User cards --- */
|
|
367
371
|
|
|
368
372
|
.user-card {
|
|
369
|
-
border-left-color:
|
|
373
|
+
border-left-color: #22c55e;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.user-card.user-root {
|
|
377
|
+
border-left-color: #f59e0b;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.user-card .index-card-name {
|
|
381
|
+
color: #22c55e;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.user-card.user-root .index-card-name {
|
|
385
|
+
color: #f59e0b;
|
|
370
386
|
}
|
|
371
387
|
|
|
372
388
|
.user-card .kebab-menu {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
2
|
+
<!-- Box bottom face -->
|
|
3
|
+
<polygon points="16,18 2,11 16,4 30,11" fill="#4a9eff" opacity="0.85"/>
|
|
4
|
+
<!-- Box left face -->
|
|
5
|
+
<polygon points="2,11 2,23 16,30 16,18" fill="#2563eb"/>
|
|
6
|
+
<!-- Box right face -->
|
|
7
|
+
<polygon points="30,11 30,23 16,30 16,18" fill="#1d4ed8"/>
|
|
8
|
+
<!-- Highlight stripe on top face -->
|
|
9
|
+
<polygon points="16,6 26,10.5 16,15 6,10.5" fill="#93c5fd" opacity="0.4"/>
|
|
10
|
+
</svg>
|
|
@@ -463,6 +463,7 @@
|
|
|
463
463
|
logoutBtn.appendChild(el('span', {className: 'user-btn-action', textContent: 'Logout'}));
|
|
464
464
|
loginBtn.hidden = true;
|
|
465
465
|
logoutBtn.hidden = false;
|
|
466
|
+
logoutBtn.classList.toggle('is-root', user === 'root');
|
|
466
467
|
navUsers.hidden = user !== 'root';
|
|
467
468
|
document.body.classList.add('authenticated');
|
|
468
469
|
} else {
|
|
@@ -543,6 +544,18 @@
|
|
|
543
544
|
});
|
|
544
545
|
}
|
|
545
546
|
|
|
547
|
+
// Reload current view when clicking an already-active nav link
|
|
548
|
+
document.getElementById('main-nav').addEventListener('click', function (e) {
|
|
549
|
+
if (e.target.tagName === 'A') {
|
|
550
|
+
var href = e.target.getAttribute('href') || '#';
|
|
551
|
+
var current = window.location.hash || '#';
|
|
552
|
+
if (href === current) {
|
|
553
|
+
e.preventDefault();
|
|
554
|
+
navigate();
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
|
|
546
559
|
logoutBtn.addEventListener('click', function (e) {
|
|
547
560
|
// Clicking the username part opens change-password modal
|
|
548
561
|
if (e.target.classList.contains('user-btn-name')) {
|
|
@@ -634,7 +647,7 @@
|
|
|
634
647
|
var currentUser = Api.getUser();
|
|
635
648
|
var canEdit = currentUser === name || currentUser === 'root';
|
|
636
649
|
|
|
637
|
-
var card = el('div', {className: 'index-card user-card'});
|
|
650
|
+
var card = el('div', {className: 'index-card user-card' + (name === 'root' ? ' user-root' : '')});
|
|
638
651
|
|
|
639
652
|
// Card head: username + kebab menu
|
|
640
653
|
var cardHead = el('div', {className: 'index-card-head'});
|
|
@@ -1981,4 +1994,22 @@
|
|
|
1981
1994
|
updateAuthUI();
|
|
1982
1995
|
updateNav();
|
|
1983
1996
|
navigate();
|
|
1997
|
+
|
|
1998
|
+
var _sessionCheckReady = false;
|
|
1999
|
+
setTimeout(function () { _sessionCheckReady = true; }, 2000);
|
|
2000
|
+
|
|
2001
|
+
function checkSession() {
|
|
2002
|
+
if (!_sessionCheckReady || !Api.getUser()) return;
|
|
2003
|
+
Api.get('/+admin-api/session').catch(function (err) {
|
|
2004
|
+
if (err.status === 403 || err.status === 401) {
|
|
2005
|
+
Api.logout();
|
|
2006
|
+
updateAuthUI();
|
|
2007
|
+
showError(new Error('Session expired. Please log in again.'));
|
|
2008
|
+
}
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
document.addEventListener('visibilitychange', function () {
|
|
2012
|
+
if (document.visibilityState === 'visible') checkSession();
|
|
2013
|
+
});
|
|
2014
|
+
window.addEventListener('focus', checkSession);
|
|
1984
2015
|
})();
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|