Skip to content

Commit 8e1e468

Browse files
committed
Manually merge PR176: Minimal per-user account page
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6193 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent 8bbd13c commit 8e1e468

File tree

6 files changed

+235
-13
lines changed

6 files changed

+235
-13
lines changed

README

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ additional web apps and OpenID on CentOS:
716716
--signup_methods="extoid migoid migcert extoidc" \
717717
--login_methods="extoid migoid migcert extoidc" \
718718
--distro=centos --skin=migrid-basic \
719-
--default_menu="home files submitjob jobs vgrids settings setup logout" \
719+
--default_menu="home files submitjob jobs vgrids account settings setup logout" \
720720
--user_menu="sharelinks people cloud crontab transfers runtimeenvs resources peers downloads docs dashboard migadmin" \
721721
--wsgi_procs=25 --sftp_subsys_auth_procs=20 \
722722
--sftp_max_sessions=16 \
@@ -820,7 +820,7 @@ local OpenID login and added Jupyter+cloud integration for data analysis:
820820
--davs_port=8020 --openid_port=8001 \
821821
--wsgi_procs=100 --sftp_subsys_auth_procs=50 \
822822
--sftp_max_sessions=16 \
823-
--default_menu="home files vgrids archives jupyter settings setup logout" \
823+
--default_menu="home files vgrids archives jupyter account settings setup logout" \
824824
--user_menu="sharelinks seafile crontab transfers cloud people downloads peers docs migadmin" \
825825
--collaboration_links="default advanced" \
826826
--default_vgrid_links="files web" \
@@ -908,7 +908,7 @@ local OpenID login and support for legacy sftp clients:
908908
--wsgi_procs=25 --sftp_subsys_auth_procs=25 \
909909
--sftp_max_sessions=16 \
910910
--davs_port=8020 --openid_port=8001 \
911-
--default_menu="home files submitjob jobs vgrids jupyter settings setup logout" \
911+
--default_menu="home files submitjob jobs vgrids jupyter account settings setup logout" \
912912
--user_menu="sharelinks people cloud crontab transfers runtimeenvs resources downloads peers docs migadmin" \
913913
--collaboration_links="default advanced" \
914914
--default_vgrid_links="files web" \

mig/assets/css/V3/nav.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@
475475
.popup-container {
476476
position: fixed;
477477
width: 270px;
478-
height: 300px;
478+
height: 340px;
479479
background-color: #FFF;
480480
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
481481
border-radius: 8px;
@@ -504,7 +504,7 @@
504504
}
505505

506506
.popup-middle {
507-
height: 180px;
507+
height: 220px;
508508
width: 100%;
509509
border-bottom: 1px solid #EEE;
510510
padding: 10px;

mig/cgi-bin/account.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# --- BEGIN_HEADER ---
5+
#
6+
# account - account page front end
7+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
8+
#
9+
# This file is part of MiG.
10+
#
11+
# MiG is free software: you can redistribute it and/or modify
12+
# it under the terms of the GNU General Public License as published by
13+
# the Free Software Foundation; either version 2 of the License, or
14+
# (at your option) any later version.
15+
#
16+
# MiG is distributed in the hope that it will be useful,
17+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
# GNU General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; if not, write to the Free Software
23+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24+
#
25+
# -- END_HEADER ---
26+
#
27+
28+
from __future__ import absolute_import
29+
import cgi
30+
31+
from mig.shared.functionality.account import main
32+
from mig.shared.cgiscriptstub import run_cgi_script_possibly_with_cert
33+
34+
run_cgi_script_possibly_with_cert(main)

mig/shared/configuration.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,10 +1921,10 @@ def reload_config(self, verbose, skip_log=False, disable_auth_log=False,
19211921
req = config.get('SITE', 'default_menu').split()
19221922
self.site_default_menu = [i for i in req if i in menu_items]
19231923
else:
1924-
self.site_default_menu = ['home', 'files', 'submitjob',
1925-
'jobs', 'resources', 'vgrids',
1926-
'downloads', 'runtimeenvs', 'people',
1927-
'settings', 'crontab', 'docs', 'logout']
1924+
self.site_default_menu = ['home', 'files', 'submitjob', 'jobs',
1925+
'resources', 'vgrids', 'downloads',
1926+
'runtimeenvs', 'people', 'settings',
1927+
'crontab', 'account', 'docs', 'logout']
19281928
if config.has_option('SITE', 'simple_menu'):
19291929
req = config.get('SITE', 'simple_menu').split()
19301930
self.site_simple_menu = [i for i in req if i in menu_items]

mig/shared/functionality/account.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# --- BEGIN_HEADER ---
5+
#
6+
# account - account page with info and account management options
7+
# Copyright (C) 2003-2024 The MiG Project by the Science HPC Center at UCPH
8+
#
9+
# This file is part of MiG.
10+
#
11+
# MiG is free software: you can redistribute it and/or modify
12+
# it under the terms of the GNU General Public License as published by
13+
# the Free Software Foundation; either version 2 of the License, or
14+
# (at your option) any later version.
15+
#
16+
# MiG is distributed in the hope that it will be useful,
17+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
# GNU General Public License for more details.
20+
#
21+
# You should have received a copy of the GNU General Public License
22+
# along with this program; if not, write to the Free Software
23+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24+
#
25+
# -- END_HEADER ---
26+
#
27+
28+
29+
"""Account page with user details and account management options"""
30+
31+
from __future__ import absolute_import
32+
33+
import datetime
34+
import os
35+
36+
from mig.shared import returnvalues
37+
from mig.shared.functional import validate_input_and_cert
38+
from mig.shared.init import initialize_main_variables, find_entry
39+
from mig.shared.htmlgen import html_user_messages, man_base_html, man_base_js
40+
from mig.shared.useradm import get_full_user_map
41+
42+
_account_field_order = [('full_name', 'Full Name'),
43+
('organization', 'Organization'),
44+
('email', 'Email Address'),
45+
('country', 'Country'),
46+
('role', 'Role'),
47+
('status', 'Account Status'),
48+
('expire', 'Expire'),
49+
('peers_full_name', 'Peer Full Name(s)'),
50+
('peers_email', 'Peer Email Address(es)'),
51+
]
52+
53+
54+
def html_tmpl(configuration, client_id, environ, title_entry):
55+
"""HTML page base: some account and manage actions depend on configuration
56+
and environ.
57+
"""
58+
59+
user_msg, show_user_msg = '', 'hidden'
60+
if configuration.site_enable_user_messages:
61+
user_msg = html_user_messages(configuration, client_id)
62+
show_user_msg = ''
63+
user_map = get_full_user_map(configuration)
64+
user_dict = user_map.get(client_id, None)
65+
user_account = ''
66+
if user_dict:
67+
user_account += '''
68+
<h3>Account Details</h3>
69+
<p class="sub-title">Your account has the following information
70+
registered:
71+
</p>
72+
'''
73+
for (field, label) in _account_field_order:
74+
if not user_dict.get(field, False):
75+
continue
76+
if field == 'expire':
77+
# NOTE: translate epoch to proper datetime string
78+
expire_dt = datetime.datetime.fromtimestamp(user_dict[field])
79+
user_dict[field] = expire_dt
80+
user_account += '''%s: %s<br/>
81+
''' % (label, user_dict[field])
82+
# NOTE: ID token is only available for openid connect
83+
claim_dump, user_token = '', ''
84+
for (key, val) in os.environ.items():
85+
if key.startswith('OIDC_CLAIM_'):
86+
claim_dump += "%s: %s<br/>" % (key, val)
87+
if claim_dump:
88+
user_token = '''
89+
<h3>ID Token</h3>
90+
<p class="sub-title">Your current login session provides the following
91+
additional information:
92+
</p>'''
93+
user_token += claim_dump
94+
fill_helpers = {'short_title': configuration.short_title,
95+
'user_msg': user_msg, 'show_user_msg': show_user_msg,
96+
'user_account': user_account,
97+
'user_token': user_token}
98+
99+
html = '''
100+
<!-- CONTENT -->
101+
<div class="container">
102+
<div id="account-container" class="row">
103+
''' % fill_helpers
104+
html += '''
105+
<div id="user-account-container" class="col-12 invert-theme">
106+
<div id="user-account-content" class="user-account-placeholder">
107+
%(user_account)s
108+
</div>
109+
<div id="user-token-content" class="user-token-placeholder">
110+
%(user_token)s
111+
</div>
112+
<div id="user-data-content" class="user-data-placeholder">
113+
<p>Details are from your sign up and/or any updates provided
114+
through your login. Please contact support if something is
115+
incorrect or has significantly changed.
116+
</p>
117+
</div>
118+
</div>
119+
''' % fill_helpers
120+
html += '''
121+
<div id="user-msg-container" class="col-12 invert-theme %(show_user_msg)s">
122+
<div id="user-msg-content" class="user-msg-placeholder">
123+
%(user_msg)s
124+
</div>
125+
</div>
126+
''' % fill_helpers
127+
html += '''
128+
<div class="col-lg-12 vertical-spacer"></div>
129+
</div>
130+
'''
131+
132+
# TODO: add account management actions
133+
134+
return html
135+
136+
137+
def signature():
138+
"""Signature of the main function"""
139+
140+
defaults = {}
141+
return ['text', defaults]
142+
143+
144+
def main(client_id, user_arguments_dict, environ=None):
145+
"""Main function used by front end"""
146+
147+
if environ is None:
148+
environ = os.environ
149+
150+
(configuration, logger, output_objects, op_name) = \
151+
initialize_main_variables(client_id, op_header=False,
152+
op_menu=client_id)
153+
defaults = signature()[1]
154+
(validate_status, accepted) = validate_input_and_cert(
155+
user_arguments_dict,
156+
defaults,
157+
output_objects,
158+
client_id,
159+
configuration,
160+
allow_rejects=False,
161+
)
162+
if not validate_status:
163+
return (accepted, returnvalues.CLIENT_ERROR)
164+
165+
# Generate and insert the page HTML
166+
title_entry = find_entry(output_objects, 'title')
167+
title_entry['text'] = '%s Profile' % configuration.short_title
168+
169+
# jquery support for AJAX saving
170+
171+
(add_import, add_init, add_ready) = man_base_js(configuration, [])
172+
add_init += '''
173+
'''
174+
add_ready += '''
175+
init_user_msg();
176+
'''
177+
title_entry['script']['advanced'] += add_import
178+
title_entry['script']['init'] += add_init
179+
title_entry['script']['ready'] += add_ready
180+
181+
html = html_tmpl(configuration, client_id, environ, title_entry)
182+
output_objects.append({'object_type': 'html_form', 'text': html})
183+
184+
return (output_objects, returnvalues.OK)

mig/shared/htmlgen.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,15 @@
7171
menu_items['archives'] = {'class': 'archives fas fa-archive', 'url': 'freezedb.py',
7272
'title': 'Archives',
7373
'hover': 'Frozen archives: write-once file archives'}
74+
menu_items['account'] = {'class': 'account fas fa-account', 'url': 'account.py',
75+
'legacy_only': True, 'title': 'Account',
76+
'hover': 'Account info and management'}
7477
menu_items['settings'] = {'class': 'settings fas fa-user', 'url': 'settings.py',
7578
'legacy_only': True, 'title': 'Settings',
7679
'hover': 'Your personal settings for these pages'}
7780
menu_items['setup'] = {'class': 'setup fas fa-user-cog', 'url': 'setup.py',
7881
'legacy_only': True, 'title': 'Setup',
79-
'hover': 'Your client access settings for this site'}
82+
'hover': 'Your client access setup for this site'}
8083
menu_items['transfers'] = {'class': 'transfers fas fa-datatransfer', 'url': 'datatransfer.py',
8184
'title': 'Data Transfers',
8285
'hover': 'For background batch transfers of data'}
@@ -2061,7 +2064,7 @@ def get_xgi_html_header(
20612064
for user_entry in ['logout', 'help']:
20622065
profile_helper['disable%s' % user_entry] = ''
20632066
# Disable any other entries missing from base and user menu
2064-
for user_entry in ['home', 'settings', 'setup']:
2067+
for user_entry in ['home', 'account', 'settings', 'setup']:
20652068
profile_helper['disable%s' % user_entry] = ''
20662069
if not user_entry in base_menu + user_menu:
20672070
profile_helper['disable%s' %
@@ -2085,9 +2088,10 @@ def get_xgi_html_header(
20852088
</div>
20862089
<div class="popup-middle col-12">
20872090
<a class="user-menu__item link-home %(disablehome)s" href="home.py">Home</a>
2091+
<a class="user-menu__item link-account %(disableaccount)s" href="account.py">Account</a>
20882092
<a class="user-menu__item link-settings %(disablesettings)s" href="settings.py">Settings</a>
2089-
<a class="user-menu__item link-setup %(disablesetup)s " href="setup.py">Setup</a>
2090-
<a class="user-menu__item link-help %(disablehelp)s " href="%(help_url)s">Help</a>
2093+
<a class="user-menu__item link-setup %(disablesetup)s" href="setup.py">Setup</a>
2094+
<a class="user-menu__item link-help %(disablehelp)s" href="%(help_url)s">Help</a>
20912095
</div>
20922096
<div class="popup-footer col-12">
20932097
<a class="user-menu__item link-logout %(disablelogout)s " href="logout.py">Sign Out</a>

0 commit comments

Comments
 (0)