bfabric-web-apps 0.1.0__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
- bfabric_web_apps/__init__.py +96 -5
- bfabric_web_apps/layouts/layouts.py +254 -8
- bfabric_web_apps/objects/BfabricInterface.py +278 -9
- bfabric_web_apps/objects/Logger.py +55 -12
- bfabric_web_apps/utils/app_init.py +11 -0
- bfabric_web_apps/utils/callbacks.py +170 -0
- bfabric_web_apps/utils/components.py +22 -0
- bfabric_web_apps/utils/create_app_in_bfabric.py +86 -0
- bfabric_web_apps/utils/defaults.py +11 -0
- bfabric_web_apps/utils/get_logger.py +14 -0
- bfabric_web_apps/utils/get_power_user_wrapper.py +27 -0
- bfabric_web_apps-0.1.2.dist-info/LICENSE +21 -0
- {bfabric_web_apps-0.1.0.dist-info → bfabric_web_apps-0.1.2.dist-info}/METADATA +4 -3
- bfabric_web_apps-0.1.2.dist-info/RECORD +15 -0
- {bfabric_web_apps-0.1.0.dist-info → bfabric_web_apps-0.1.2.dist-info}/WHEEL +1 -1
- bfabric_web_apps/objects/__init__.py +0 -0
- bfabric_web_apps-0.1.0.dist-info/RECORD +0 -8
bfabric_web_apps/__init__.py
CHANGED
@@ -1,6 +1,97 @@
|
|
1
|
-
|
2
|
-
BfabricInterface,
|
3
|
-
Logger
|
4
|
-
)
|
1
|
+
import os
|
5
2
|
|
6
|
-
|
3
|
+
# Export objects and classes
|
4
|
+
from bfabric_web_apps.objects import BfabricInterface, Logger
|
5
|
+
|
6
|
+
# Export components
|
7
|
+
from .utils import components
|
8
|
+
|
9
|
+
# Export layouts
|
10
|
+
from .layouts.layouts import get_static_layout
|
11
|
+
|
12
|
+
# Export app initialization utilities
|
13
|
+
from .utils.app_init import create_app
|
14
|
+
from .utils.get_logger import get_logger
|
15
|
+
from .utils.get_power_user_wrapper import get_power_user_wrapper
|
16
|
+
from .utils.create_app_in_bfabric import create_app_in_bfabric
|
17
|
+
|
18
|
+
# Export callbacks
|
19
|
+
from .utils.callbacks import process_url_and_token, submit_bug_report
|
20
|
+
|
21
|
+
from .utils import defaults
|
22
|
+
|
23
|
+
HOST = os.getenv("HOST", defaults.HOST)
|
24
|
+
PORT = int(os.getenv("PORT", defaults.PORT)) # Convert to int since env variables are strings
|
25
|
+
DEV = os.getenv("DEV", str(defaults.DEV)).lower() in ["true", "1", "yes"] # Convert to bool
|
26
|
+
CONFIG_FILE_PATH = os.getenv("CONFIG_FILE_PATH", defaults.CONFIG_FILE_PATH)
|
27
|
+
|
28
|
+
DEVELOPER_EMAIL_ADDRESS = os.getenv("DEVELOPER_EMAIL_ADDRESS", defaults.DEVELOPER_EMAIL_ADDRESS)
|
29
|
+
BUG_REPORT_EMAIL_ADDRESS = os.getenv("BUG_REPORT_EMAIL_ADDRESS", defaults.BUG_REPORT_EMAIL_ADDRESS)
|
30
|
+
|
31
|
+
|
32
|
+
# Define __all__ for controlled imports
|
33
|
+
__all__ = [
|
34
|
+
"BfabricInterface",
|
35
|
+
"Logger",
|
36
|
+
"components",
|
37
|
+
"get_static_layout",
|
38
|
+
"create_app",
|
39
|
+
"process_url_and_token",
|
40
|
+
"submit_bug_report",
|
41
|
+
'get_logger',
|
42
|
+
'get_power_user_wrapper',
|
43
|
+
'HOST',
|
44
|
+
'PORT',
|
45
|
+
'DEV',
|
46
|
+
'CONFIG_FILE_PATH',
|
47
|
+
'DEVELOPER_EMAIL_ADDRESS',
|
48
|
+
'BUG_REPORT_EMAIL_ADDRESS',
|
49
|
+
'create_app_in_bfabric'
|
50
|
+
]
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
'''
|
55
|
+
import os
|
56
|
+
from .utils import defaults
|
57
|
+
|
58
|
+
# Private variable for CONFIG_FILE_PATH
|
59
|
+
_CONFIG_FILE_PATH = os.getenv("CONFIG_FILE_PATH", defaults.CONFIG_FILE_PATH)
|
60
|
+
|
61
|
+
def set_config_file_path(path):
|
62
|
+
"""
|
63
|
+
Setter for the CONFIG_FILE_PATH variable.
|
64
|
+
"""
|
65
|
+
global _CONFIG_FILE_PATH
|
66
|
+
if not isinstance(path, str):
|
67
|
+
raise ValueError("CONFIG_FILE_PATH must be a string.")
|
68
|
+
_CONFIG_FILE_PATH = path
|
69
|
+
|
70
|
+
def get_config_file_path():
|
71
|
+
"""
|
72
|
+
Getter for the CONFIG_FILE_PATH variable.
|
73
|
+
"""
|
74
|
+
return _CONFIG_FILE_PATH
|
75
|
+
|
76
|
+
# Expose CONFIG_FILE_PATH as a read-only property
|
77
|
+
class Config:
|
78
|
+
@property
|
79
|
+
def CONFIG_FILE_PATH(self):
|
80
|
+
return get_config_file_path()
|
81
|
+
|
82
|
+
config = Config()
|
83
|
+
|
84
|
+
'''
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
'''
|
89
|
+
from bfabric import config
|
90
|
+
|
91
|
+
config.CONFIG_FILE_PATH
|
92
|
+
'''
|
93
|
+
|
94
|
+
'''
|
95
|
+
from bfabric import set_config_file_path
|
96
|
+
set_config_file_path("new/path/to/config.json")
|
97
|
+
'''
|
@@ -1,13 +1,259 @@
|
|
1
|
+
from dash import html, dcc
|
2
|
+
import dash_bootstrap_components as dbc
|
3
|
+
import bfabric_web_apps
|
1
4
|
|
5
|
+
def get_static_layout(base_title=None, main_content=None, documentation_content=None):
|
6
|
+
"""
|
7
|
+
Returns a layout with static tabs for Main, Documentation, and Report a Bug.
|
8
|
+
The main content is customizable, while the other tabs are generic.
|
2
9
|
|
3
|
-
|
10
|
+
Args:
|
11
|
+
base_title (str): The main title to be displayed in the banner.
|
12
|
+
main_content (html.Div): Content to be displayed in the "Main" tab.
|
13
|
+
documentation_content (html.Div): Content for the "Documentation" tab.
|
4
14
|
|
5
|
-
|
15
|
+
Returns:
|
16
|
+
html.Div: The complete static layout of the web app.
|
17
|
+
"""
|
18
|
+
return html.Div(
|
19
|
+
children=[
|
20
|
+
dcc.Location(id='url', refresh=False),
|
21
|
+
dcc.Store(id='token', storage_type='session'),
|
22
|
+
dcc.Store(id='entity', storage_type='session'),
|
23
|
+
dcc.Store(id='app_data', storage_type='session'),
|
24
|
+
dcc.Store(id='token_data', storage_type='session'),
|
25
|
+
dcc.Store(id='dynamic-link-store', storage_type='session'), # Store for dynamic job link
|
6
26
|
|
7
|
-
|
8
|
-
|
9
|
-
|
27
|
+
dbc.Container(
|
28
|
+
children=[
|
29
|
+
# Banner Section
|
30
|
+
dbc.Row(
|
31
|
+
dbc.Col(
|
32
|
+
html.Div(
|
33
|
+
className="banner",
|
34
|
+
children=[
|
35
|
+
# Title
|
36
|
+
html.Div(
|
37
|
+
children=[
|
38
|
+
html.P(
|
39
|
+
base_title,
|
40
|
+
style={
|
41
|
+
'color': '#ffffff',
|
42
|
+
'margin-top': '15px',
|
43
|
+
'height': '80px',
|
44
|
+
'width': '100%',
|
45
|
+
'font-size': '40px',
|
46
|
+
'margin-left': '20px'
|
47
|
+
}
|
48
|
+
)
|
49
|
+
],
|
50
|
+
style={"background-color": "#000000", "border-radius": "10px"}
|
51
|
+
),
|
52
|
+
],
|
53
|
+
style={"position": "relative", "padding": "10px"}
|
54
|
+
),
|
55
|
+
),
|
56
|
+
),
|
10
57
|
|
11
|
-
|
12
|
-
|
13
|
-
|
58
|
+
# Page Title Section + View Logs Button (Aligned Right)
|
59
|
+
dbc.Row(
|
60
|
+
dbc.Col(
|
61
|
+
html.Div(
|
62
|
+
children=[
|
63
|
+
# Page Title (Aligned Left)
|
64
|
+
html.P(
|
65
|
+
id="page-title",
|
66
|
+
children=[str(" ")],
|
67
|
+
style={"font-size": "40px", "margin-left": "20px", "margin-top": "10px"}
|
68
|
+
),
|
69
|
+
|
70
|
+
# View Logs Button (Aligned Right)
|
71
|
+
html.Div(
|
72
|
+
children=[
|
73
|
+
html.A(
|
74
|
+
dbc.Button(
|
75
|
+
"View Logs",
|
76
|
+
id="dynamic-link-button",
|
77
|
+
color="secondary", # Greyish color
|
78
|
+
style={
|
79
|
+
"font-size": "18px",
|
80
|
+
"padding": "10px 20px",
|
81
|
+
"border-radius": "8px"
|
82
|
+
}
|
83
|
+
),
|
84
|
+
id="dynamic-link",
|
85
|
+
href="#", # Will be dynamically set in the callback
|
86
|
+
target="_blank"
|
87
|
+
)
|
88
|
+
],
|
89
|
+
style={
|
90
|
+
"position": "absolute",
|
91
|
+
"right": "20px",
|
92
|
+
"top": "10px", # Aligns with title
|
93
|
+
}
|
94
|
+
),
|
95
|
+
],
|
96
|
+
style={
|
97
|
+
"position": "relative", # Ensures absolute positioning works
|
98
|
+
"margin-top": "0px",
|
99
|
+
"min-height": "80px",
|
100
|
+
"height": "6vh",
|
101
|
+
"border-bottom": "2px solid #d4d7d9",
|
102
|
+
"display": "flex",
|
103
|
+
"align-items": "center",
|
104
|
+
"justify-content": "space-between", # Title left, button right
|
105
|
+
"padding-right": "20px" # Space between button & right edge
|
106
|
+
}
|
107
|
+
),
|
108
|
+
),
|
109
|
+
),
|
110
|
+
|
111
|
+
# Bug Report Alerts (Restored)
|
112
|
+
dbc.Row(
|
113
|
+
dbc.Col(
|
114
|
+
[
|
115
|
+
dbc.Alert(
|
116
|
+
"Your bug report has been submitted. Thanks for helping us improve!",
|
117
|
+
id="alert-fade-bug-success",
|
118
|
+
dismissable=True,
|
119
|
+
is_open=False,
|
120
|
+
color="info",
|
121
|
+
style={
|
122
|
+
"max-width": "50vw",
|
123
|
+
"margin-left": "10px",
|
124
|
+
"margin-top": "10px",
|
125
|
+
}
|
126
|
+
),
|
127
|
+
dbc.Alert(
|
128
|
+
"Failed to submit bug report! Please email the developers directly at the email below!",
|
129
|
+
id="alert-fade-bug-fail",
|
130
|
+
dismissable=True,
|
131
|
+
is_open=False,
|
132
|
+
color="danger",
|
133
|
+
style={
|
134
|
+
"max-width": "50vw",
|
135
|
+
"margin-left": "10px",
|
136
|
+
"margin-top": "10px",
|
137
|
+
}
|
138
|
+
),
|
139
|
+
]
|
140
|
+
)
|
141
|
+
),
|
142
|
+
|
143
|
+
# Tabs Section
|
144
|
+
dbc.Tabs(
|
145
|
+
[
|
146
|
+
dbc.Tab(main_content, label="Main", tab_id="main"),
|
147
|
+
dbc.Tab(get_documentation_tab(documentation_content), label="Documentation", tab_id="documentation"),
|
148
|
+
dbc.Tab(get_report_bug_tab(), label="Report a Bug", tab_id="report-bug"),
|
149
|
+
],
|
150
|
+
id="tabs",
|
151
|
+
active_tab="main",
|
152
|
+
),
|
153
|
+
],
|
154
|
+
fluid=True,
|
155
|
+
style={"width": "100vw"}
|
156
|
+
)
|
157
|
+
],
|
158
|
+
style={"width": "100vw", "overflow-x": "hidden", "overflow-y": "scroll"}
|
159
|
+
)
|
160
|
+
|
161
|
+
|
162
|
+
def get_documentation_tab(documentation_content):
|
163
|
+
"""
|
164
|
+
Returns the content for the Documentation tab with the upgraded layout.
|
165
|
+
"""
|
166
|
+
return dbc.Row(
|
167
|
+
id="page-content-docs",
|
168
|
+
children=[
|
169
|
+
dbc.Col(
|
170
|
+
html.Div(
|
171
|
+
id="sidebar_docs",
|
172
|
+
children=[],
|
173
|
+
style={
|
174
|
+
"border-right": "2px solid #d4d7d9",
|
175
|
+
"height": "100%",
|
176
|
+
"padding": "20px",
|
177
|
+
"font-size": "20px",
|
178
|
+
},
|
179
|
+
),
|
180
|
+
width=3,
|
181
|
+
),
|
182
|
+
dbc.Col(
|
183
|
+
html.Div(
|
184
|
+
id="page-content-docs-children",
|
185
|
+
children= documentation_content,
|
186
|
+
style={"margin-top":"2vh", "margin-left":"2vw", "font-size":"20px", "padding-right":"40px", "overflow-y": "scroll", "max-height": "60vh"},
|
187
|
+
),
|
188
|
+
width=9,
|
189
|
+
),
|
190
|
+
],
|
191
|
+
style={"margin-top": "0px", "min-height": "40vh"},
|
192
|
+
)
|
193
|
+
|
194
|
+
|
195
|
+
def get_report_bug_tab():
|
196
|
+
"""
|
197
|
+
Returns the content for the Report a Bug tab with the upgraded layout.
|
198
|
+
"""
|
199
|
+
return dbc.Row(
|
200
|
+
id="page-content-bug-report",
|
201
|
+
children=[
|
202
|
+
dbc.Col(
|
203
|
+
html.Div(
|
204
|
+
id="sidebar_bug_report",
|
205
|
+
children=[], # Optional: Add sidebar content here if needed
|
206
|
+
style={
|
207
|
+
"border-right": "2px solid #d4d7d9",
|
208
|
+
"height": "100%",
|
209
|
+
"padding": "20px",
|
210
|
+
"font-size": "20px",
|
211
|
+
},
|
212
|
+
),
|
213
|
+
width=3,
|
214
|
+
),
|
215
|
+
dbc.Col(
|
216
|
+
html.Div(
|
217
|
+
id="page-content-bug-report-children",
|
218
|
+
children=[
|
219
|
+
html.H2("Report a Bug"),
|
220
|
+
html.P(
|
221
|
+
[
|
222
|
+
"Please use the form below to report a bug. If you have any questions, please email the developer at ",
|
223
|
+
html.A(
|
224
|
+
bfabric_web_apps.DEVELOPER_EMAIL_ADDRESS,
|
225
|
+
href=f"mailto:{bfabric_web_apps.DEVELOPER_EMAIL_ADDRESS}",
|
226
|
+
),
|
227
|
+
]
|
228
|
+
),
|
229
|
+
html.Br(),
|
230
|
+
html.H4("Session Details: "),
|
231
|
+
html.Br(),
|
232
|
+
html.P(id="session-details", children="No Active Session"),
|
233
|
+
html.Br(),
|
234
|
+
html.H4("Bug Description"),
|
235
|
+
dbc.Textarea(
|
236
|
+
id="bug-description",
|
237
|
+
placeholder="Please describe the bug you encountered here.",
|
238
|
+
style={"width": "100%"},
|
239
|
+
),
|
240
|
+
html.Br(),
|
241
|
+
dbc.Button(
|
242
|
+
"Submit Bug Report",
|
243
|
+
id="submit-bug-report",
|
244
|
+
n_clicks=0,
|
245
|
+
style={"margin-bottom": "60px"},
|
246
|
+
),
|
247
|
+
],
|
248
|
+
style={
|
249
|
+
"margin-top": "2vh",
|
250
|
+
"margin-left": "2vw",
|
251
|
+
"font-size": "20px",
|
252
|
+
"padding-right": "40px",
|
253
|
+
},
|
254
|
+
),
|
255
|
+
width=9,
|
256
|
+
),
|
257
|
+
],
|
258
|
+
style={"margin-top": "0px", "min-height": "40vh"},
|
259
|
+
)
|
@@ -1,16 +1,285 @@
|
|
1
|
-
from bfabric import Bfabric
|
1
|
+
from bfabric import Bfabric
|
2
|
+
import requests
|
3
|
+
import json
|
4
|
+
import datetime
|
5
|
+
import bfabric
|
6
|
+
from bfabric import BfabricAuth
|
7
|
+
from bfabric import BfabricClientConfig
|
8
|
+
from bfabric_web_apps.utils.get_logger import get_logger
|
9
|
+
import os
|
10
|
+
import bfabric_web_apps
|
2
11
|
|
3
|
-
class BfabricInterface( Bfabric ):
|
4
12
|
|
5
|
-
def __init__():
|
6
|
-
pass
|
7
13
|
|
8
|
-
|
9
|
-
|
14
|
+
VALIDATION_URL = "https://fgcz-bfabric.uzh.ch/bfabric/rest/token/validate?token="
|
15
|
+
HOST = "fgcz-bfabric.uzh.ch"
|
10
16
|
|
11
|
-
def token_response_to_bfabric(self, token_response):
|
12
|
-
pass
|
13
17
|
|
14
|
-
|
18
|
+
class BfabricInterface( Bfabric ):
|
19
|
+
"""
|
20
|
+
A class to interface with the Bfabric API, providing methods to validate tokens,
|
21
|
+
retrieve data, and send bug reports.
|
22
|
+
"""
|
23
|
+
|
24
|
+
def __init__(self):
|
25
|
+
"""
|
26
|
+
Initializes an instance of BfabricInterface.
|
27
|
+
"""
|
15
28
|
pass
|
16
29
|
|
30
|
+
def token_to_data(self, token):
|
31
|
+
"""
|
32
|
+
Validates the given token and retrieves its associated data.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
token (str): The token to validate.
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
str: A JSON string containing token data if valid.
|
39
|
+
str: "EXPIRED" if the token is expired.
|
40
|
+
None: If the token is invalid or validation fails.
|
41
|
+
"""
|
42
|
+
|
43
|
+
if not token:
|
44
|
+
return None
|
45
|
+
|
46
|
+
validation_url = VALIDATION_URL + token
|
47
|
+
res = requests.get(validation_url, headers={"Host": HOST})
|
48
|
+
|
49
|
+
if res.status_code != 200:
|
50
|
+
res = requests.get(validation_url)
|
51
|
+
|
52
|
+
if res.status_code != 200:
|
53
|
+
return None
|
54
|
+
try:
|
55
|
+
master_data = json.loads(res.text)
|
56
|
+
except:
|
57
|
+
return None
|
58
|
+
|
59
|
+
if True:
|
60
|
+
|
61
|
+
userinfo = json.loads(res.text)
|
62
|
+
expiry_time = userinfo['expiryDateTime']
|
63
|
+
current_time = datetime.datetime.now()
|
64
|
+
five_minutes_later = current_time + datetime.timedelta(minutes=5)
|
65
|
+
|
66
|
+
# Comparing the parsed expiry time with the five minutes later time
|
67
|
+
|
68
|
+
if not five_minutes_later <= datetime.datetime.strptime(expiry_time, "%Y-%m-%d %H:%M:%S"):
|
69
|
+
return "EXPIRED"
|
70
|
+
|
71
|
+
environment_dict = {"Production":"https://fgcz-bfabric.uzh.ch/bfabric","Test":"https://fgcz-bfabric-test.uzh.ch/bfabric"}
|
72
|
+
|
73
|
+
token_data = dict(
|
74
|
+
environment = userinfo['environment'],
|
75
|
+
user_data = userinfo['user'],
|
76
|
+
token_expires = expiry_time,
|
77
|
+
entity_id_data = userinfo['entityId'],
|
78
|
+
entityClass_data = userinfo['entityClassName'],
|
79
|
+
webbase_data = environment_dict.get(userinfo['environment'], None),
|
80
|
+
application_params_data = {},
|
81
|
+
application_data = str(userinfo['applicationId']),
|
82
|
+
userWsPassword = userinfo['userWsPassword'],
|
83
|
+
jobId = userinfo['jobId']
|
84
|
+
)
|
85
|
+
|
86
|
+
return json.dumps(token_data)
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
def token_response_to_bfabric(self, token_response):
|
91
|
+
|
92
|
+
"""
|
93
|
+
Converts token response data into a Bfabric object for further interactions.
|
94
|
+
|
95
|
+
Args:
|
96
|
+
token_response (dict): The token response data.
|
97
|
+
|
98
|
+
Returns:
|
99
|
+
Bfabric: An authenticated Bfabric instance.
|
100
|
+
"""
|
101
|
+
|
102
|
+
bfabric_auth = BfabricAuth(login=token_response.get('user_data'), password=token_response.get('userWsPassword'))
|
103
|
+
bfabric_client_config = BfabricClientConfig(base_url=token_response.get('webbase_data'))
|
104
|
+
|
105
|
+
bfabric_wrapper = bfabric.Bfabric(config=bfabric_client_config, auth=bfabric_auth)
|
106
|
+
|
107
|
+
return bfabric_wrapper
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
def entity_data(self, token_data: dict) -> str:
|
113
|
+
"""
|
114
|
+
Retrieves entity data associated with the provided token.
|
115
|
+
|
116
|
+
Args:
|
117
|
+
token_data (dict): The token data.
|
118
|
+
|
119
|
+
Returns:
|
120
|
+
str: A JSON string containing entity data.
|
121
|
+
{}: If the retrieval fails or token_data is invalid.
|
122
|
+
"""
|
123
|
+
|
124
|
+
entity_class_map = {
|
125
|
+
"Run": "run",
|
126
|
+
"Sample": "sample",
|
127
|
+
"Project": "container",
|
128
|
+
"Order": "container",
|
129
|
+
"Container": "container",
|
130
|
+
"Plate": "plate"
|
131
|
+
}
|
132
|
+
|
133
|
+
if not token_data:
|
134
|
+
return json.dumps({})
|
135
|
+
|
136
|
+
wrapper = self.token_response_to_bfabric(token_data)
|
137
|
+
entity_class = token_data.get('entityClass_data', None)
|
138
|
+
endpoint = entity_class_map.get(entity_class, None)
|
139
|
+
entity_id = token_data.get('entity_id_data', None)
|
140
|
+
jobId = token_data.get('jobId', None)
|
141
|
+
username = token_data.get("user_data", "None")
|
142
|
+
environment = token_data.get("environment", "None")
|
143
|
+
|
144
|
+
if wrapper and entity_class and endpoint and entity_id and jobId:
|
145
|
+
L = get_logger(token_data)
|
146
|
+
|
147
|
+
# Log the read operation directly using Logger L
|
148
|
+
entity_data_dict = L.logthis(
|
149
|
+
api_call=wrapper.read,
|
150
|
+
endpoint=endpoint,
|
151
|
+
obj={"id": entity_id},
|
152
|
+
max_results=None,
|
153
|
+
params=None,
|
154
|
+
flush_logs=True
|
155
|
+
)[0]
|
156
|
+
|
157
|
+
|
158
|
+
if entity_data_dict:
|
159
|
+
json_data = json.dumps({
|
160
|
+
"name": entity_data_dict.get("name", ""),
|
161
|
+
"createdby": entity_data_dict.get("createdby"),
|
162
|
+
"created": entity_data_dict.get("created"),
|
163
|
+
"modified": entity_data_dict.get("modified"),
|
164
|
+
})
|
165
|
+
return json_data
|
166
|
+
else:
|
167
|
+
L.log_operation(
|
168
|
+
operation="entity_data",
|
169
|
+
message="Entity data retrieval failed or returned None.",
|
170
|
+
params=None,
|
171
|
+
flush_logs=True
|
172
|
+
)
|
173
|
+
print("entity_data_dict is empty or None")
|
174
|
+
return json.dumps({})
|
175
|
+
|
176
|
+
else:
|
177
|
+
print("Invalid input or entity information")
|
178
|
+
return json.dumps({})
|
179
|
+
|
180
|
+
|
181
|
+
def app_data(self, token_data: dict) -> str:
|
182
|
+
"""
|
183
|
+
Retrieves application data (App Name and Description) associated with the provided token.
|
184
|
+
|
185
|
+
Args:
|
186
|
+
token_data (dict): The token data.
|
187
|
+
|
188
|
+
Returns:
|
189
|
+
str: A JSON string containing application data.
|
190
|
+
{}: If retrieval fails or token_data is invalid.
|
191
|
+
"""
|
192
|
+
|
193
|
+
if not token_data:
|
194
|
+
return json.dumps({}) # Return empty JSON if no token data
|
195
|
+
|
196
|
+
# Extract App ID from token
|
197
|
+
app_data_raw = token_data.get("application_data", None)
|
198
|
+
|
199
|
+
try:
|
200
|
+
app_id = int(app_data_raw)
|
201
|
+
except:
|
202
|
+
print("Invalid application_data format in token_data")
|
203
|
+
return json.dumps({}) # Return empty JSON if app_id is invalid
|
204
|
+
|
205
|
+
# Define API endpoint
|
206
|
+
endpoint = "application"
|
207
|
+
|
208
|
+
# Initialize Logger
|
209
|
+
L = get_logger(token_data)
|
210
|
+
|
211
|
+
# Get API wrapper
|
212
|
+
wrapper = self.token_response_to_bfabric(token_data) # Same as entity_data
|
213
|
+
if not wrapper:
|
214
|
+
print("Failed to get Bfabric API wrapper")
|
215
|
+
return json.dumps({})
|
216
|
+
|
217
|
+
# Make API Call
|
218
|
+
app_data_dict = L.logthis(
|
219
|
+
api_call=wrapper.read,
|
220
|
+
endpoint=endpoint,
|
221
|
+
obj={"id": app_id}, # Query using the App ID
|
222
|
+
max_results=None,
|
223
|
+
params=None,
|
224
|
+
flush_logs=True
|
225
|
+
)
|
226
|
+
|
227
|
+
# If API call fails, return empty JSON
|
228
|
+
if not app_data_dict or len(app_data_dict) == 0:
|
229
|
+
L.log_operation(
|
230
|
+
operation="app_data",
|
231
|
+
message=f"Failed to retrieve application data for App ID {app_id}",
|
232
|
+
params=None,
|
233
|
+
flush_logs=True
|
234
|
+
)
|
235
|
+
return json.dumps({})
|
236
|
+
|
237
|
+
# Extract Name and Description
|
238
|
+
app_info = app_data_dict[0] # First (and only) result
|
239
|
+
json_data = json.dumps({
|
240
|
+
"name": app_info.get("name", "Unknown"),
|
241
|
+
"description": app_info.get("description", "No description available")
|
242
|
+
})
|
243
|
+
|
244
|
+
return json_data
|
245
|
+
|
246
|
+
|
247
|
+
def send_bug_report(self, token_data = None, entity_data = None, description = None):
|
248
|
+
"""
|
249
|
+
Sends a bug report via email.
|
250
|
+
|
251
|
+
Args:
|
252
|
+
token_data (dict): Token data to include in the report.
|
253
|
+
entity_data (dict): Entity data to include in the report.
|
254
|
+
description (str): A description of the bug.
|
255
|
+
|
256
|
+
Returns:
|
257
|
+
bool: True if the report is sent successfully, False otherwise.
|
258
|
+
"""
|
259
|
+
|
260
|
+
mail_string = f"""
|
261
|
+
BUG REPORT FROM QC-UPLOADER
|
262
|
+
\n\n
|
263
|
+
token_data: {token_data} \n\n
|
264
|
+
entity_data: {entity_data} \n\n
|
265
|
+
description: {description} \n\n
|
266
|
+
sent_at: {datetime.datetime.now()} \n\n
|
267
|
+
"""
|
268
|
+
|
269
|
+
mail = f"""
|
270
|
+
echo "{mail_string}" | mail -s "Bug Report" {bfabric_web_apps.BUG_REPORT_EMAIL_ADDRESS}
|
271
|
+
"""
|
272
|
+
|
273
|
+
print("MAIL STRING:")
|
274
|
+
print(mail_string)
|
275
|
+
|
276
|
+
print("MAIL:")
|
277
|
+
print(mail)
|
278
|
+
|
279
|
+
os.system(mail)
|
280
|
+
|
281
|
+
return True
|
282
|
+
|
283
|
+
|
284
|
+
|
285
|
+
|
@@ -1,47 +1,80 @@
|
|
1
1
|
import os
|
2
2
|
import pickle
|
3
|
+
from typing import List
|
3
4
|
from bfabric import Bfabric
|
4
5
|
from datetime import datetime as dt
|
5
6
|
import base64
|
6
|
-
|
7
|
-
try:
|
8
|
-
from PARAMS import CONFIG_FILE_PATH
|
9
|
-
except ImportError:
|
10
|
-
CONFIG_FILE_PATH = "~/.bfabricpy.yml"
|
7
|
+
import bfabric_web_apps
|
11
8
|
|
12
9
|
|
13
10
|
class Logger:
|
14
11
|
"""
|
15
12
|
A Logger class to manage and batch API call logs locally and flush them to the backend when needed.
|
16
13
|
"""
|
17
|
-
def __init__(self, jobid: int, username: str):
|
14
|
+
def __init__(self, jobid: int, username: str, environment: str):
|
15
|
+
"""
|
16
|
+
Initializes the Logger with a job ID, username, and environment.
|
17
|
+
|
18
|
+
Args:
|
19
|
+
jobid (int): The ID of the current job.
|
20
|
+
username (str): The name of the user performing the operations.
|
21
|
+
environment (str): The environment (e.g., Production, Test).
|
22
|
+
"""
|
18
23
|
self.jobid = jobid
|
19
24
|
self.username = username
|
20
|
-
self.
|
25
|
+
self.config_file_path = bfabric_web_apps.CONFIG_FILE_PATH
|
26
|
+
self.power_user_wrapper = self._get_power_user_wrapper(environment)
|
21
27
|
self.logs = []
|
22
28
|
|
23
|
-
def _get_power_user_wrapper(self) -> Bfabric:
|
29
|
+
def _get_power_user_wrapper(self, environment) -> Bfabric:
|
24
30
|
"""
|
25
31
|
Initializes a B-Fabric wrapper using the power user's credentials.
|
32
|
+
|
33
|
+
Args:
|
34
|
+
environment (str): The environment in which to initialize the wrapper.
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
Bfabric: An authenticated Bfabric instance.
|
26
38
|
"""
|
27
39
|
power_user_wrapper = Bfabric.from_config(
|
28
|
-
config_path=os.path.expanduser(
|
40
|
+
config_path = os.path.expanduser(self.config_file_path),
|
41
|
+
config_env = environment.upper()
|
29
42
|
)
|
30
43
|
return power_user_wrapper
|
31
44
|
|
32
45
|
def to_pickle(self):
|
46
|
+
"""
|
47
|
+
Serializes the Logger object and encodes it as a base64 string.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
dict: A dictionary containing the base64-encoded pickle string.
|
51
|
+
"""
|
33
52
|
# Pickle the object and then encode it as a base64 string
|
34
53
|
return {"data": base64.b64encode(pickle.dumps(self)).decode('utf-8')}
|
35
54
|
|
36
55
|
@classmethod
|
37
56
|
def from_pickle(cls, pickle_object):
|
57
|
+
"""
|
58
|
+
Deserializes a Logger object from a base64-encoded pickle string.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
pickle_object (dict): A dictionary containing the base64-encoded pickle string.
|
62
|
+
|
63
|
+
Returns:
|
64
|
+
Logger: The deserialized Logger object.
|
65
|
+
"""
|
38
66
|
# Decode the base64 string back to bytes and then unpickle
|
39
67
|
return pickle.loads(base64.b64decode(pickle_object.get("data").encode('utf-8')))
|
40
68
|
|
41
69
|
def log_operation(self, operation: str, message: str, params = None, flush_logs: bool = True):
|
42
70
|
"""
|
43
|
-
|
44
|
-
|
71
|
+
Logs an operation locally or flushes it to the backend.
|
72
|
+
|
73
|
+
Args:
|
74
|
+
operation (str): The name of the operation being logged.
|
75
|
+
message (str): A detailed message about the operation.
|
76
|
+
params (dict, optional): Additional parameters to log. Defaults to None.
|
77
|
+
flush_logs (bool, optional): Whether to immediately flush the logs to the backend. Defaults to True.
|
45
78
|
"""
|
46
79
|
# Define the timestamp format
|
47
80
|
timestamp = dt.now().strftime('%Y-%m-%d %H:%M:%S')
|
@@ -83,7 +116,17 @@ class Logger:
|
|
83
116
|
|
84
117
|
def logthis(self, api_call: callable, *args, params=None , flush_logs: bool = True, **kwargs) -> any:
|
85
118
|
"""
|
86
|
-
|
119
|
+
Wraps an API call with logging functionality.
|
120
|
+
|
121
|
+
Args:
|
122
|
+
api_call (callable): The API call to be logged and executed.
|
123
|
+
*args: Positional arguments to pass to the API call.
|
124
|
+
params (dict, optional): Additional parameters to log. Defaults to None.
|
125
|
+
flush_logs (bool, optional): Whether to flush logs immediately. Defaults to True.
|
126
|
+
**kwargs: Keyword arguments to pass to the API call.
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
any: The result of the API call.
|
87
130
|
"""
|
88
131
|
# Construct a message describing the API call
|
89
132
|
call_args = ', '.join([repr(arg) for arg in args])
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from dash import Dash
|
2
|
+
import dash_bootstrap_components as dbc
|
3
|
+
|
4
|
+
def create_app():
|
5
|
+
"""Initialize and return a Dash app instance with suppressed callback exceptions."""
|
6
|
+
return Dash(
|
7
|
+
__name__,
|
8
|
+
suppress_callback_exceptions=True, # Allow dynamic callbacks
|
9
|
+
external_stylesheets=[dbc.themes.BOOTSTRAP],
|
10
|
+
meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1.0"}],
|
11
|
+
)
|
@@ -0,0 +1,170 @@
|
|
1
|
+
from dash import Input, Output, State, html, dcc
|
2
|
+
from bfabric_web_apps.objects.BfabricInterface import BfabricInterface
|
3
|
+
import json
|
4
|
+
import dash_bootstrap_components as dbc
|
5
|
+
from datetime import datetime as dt
|
6
|
+
from bfabric_web_apps.utils.get_logger import get_logger
|
7
|
+
|
8
|
+
def process_url_and_token(url_params):
|
9
|
+
"""
|
10
|
+
Processes URL parameters to extract the token, validates it, and retrieves the corresponding data.
|
11
|
+
Additionally, it constructs a dynamic job link based on the environment and job ID.
|
12
|
+
|
13
|
+
Args:
|
14
|
+
url_params (str): The URL parameters containing the token.
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
tuple: A tuple containing:
|
18
|
+
- token (str): Authentication token.
|
19
|
+
- token_data (dict): Token metadata.
|
20
|
+
- entity_data (dict): Retrieved entity information.
|
21
|
+
- page_title (str): Title for the page header.
|
22
|
+
- session_details (list): HTML-formatted session details.
|
23
|
+
- job_link (str): Dynamically generated link to the job page.
|
24
|
+
"""
|
25
|
+
base_title = " "
|
26
|
+
|
27
|
+
if not url_params:
|
28
|
+
return None, None, None, None, base_title, None, None
|
29
|
+
|
30
|
+
token = "".join(url_params.split('token=')[1:])
|
31
|
+
bfabric_interface = BfabricInterface()
|
32
|
+
tdata_raw = bfabric_interface.token_to_data(token)
|
33
|
+
|
34
|
+
if tdata_raw:
|
35
|
+
if tdata_raw == "EXPIRED":
|
36
|
+
return None, None, None, None, base_title, None, None
|
37
|
+
else:
|
38
|
+
tdata = json.loads(tdata_raw)
|
39
|
+
else:
|
40
|
+
return None, None, None, None, base_title, None, None
|
41
|
+
|
42
|
+
if tdata:
|
43
|
+
entity_data_json = bfabric_interface.entity_data(tdata)
|
44
|
+
app_data_json = bfabric_interface.app_data(tdata)
|
45
|
+
entity_data = json.loads(entity_data_json)
|
46
|
+
app_data = json.loads(app_data_json)
|
47
|
+
page_title = (
|
48
|
+
f"{tdata.get('entityClass_data', 'Unknown')} - {entity_data.get('name', 'Unknown')} "
|
49
|
+
f"({tdata.get('environment', 'Unknown')} System)"
|
50
|
+
) if tdata else "Bfabric App Interface"
|
51
|
+
|
52
|
+
environment = tdata.get("environment", "").strip().lower() # 'test' or 'prod'
|
53
|
+
job_id = tdata.get("jobId", None) # Extract job ID
|
54
|
+
|
55
|
+
job_link = None
|
56
|
+
if job_id:
|
57
|
+
if "test" in environment:
|
58
|
+
job_link = f"https://fgcz-bfabric-test.uzh.ch/bfabric/job/show.html?id={job_id}&tab=details"
|
59
|
+
else:
|
60
|
+
job_link = f"https://fgcz-bfabric.uzh.ch/bfabric/job/show.html?id={job_id}&tab=details"
|
61
|
+
|
62
|
+
session_details = [
|
63
|
+
html.P([
|
64
|
+
html.B("Entity Name: "), entity_data.get('name', 'Unknown'),
|
65
|
+
html.Br(),
|
66
|
+
html.B("Entity Class: "), tdata.get('entityClass_data', 'Unknown'),
|
67
|
+
html.Br(),
|
68
|
+
html.B("Environment: "), tdata.get('environment', 'Unknown'),
|
69
|
+
html.Br(),
|
70
|
+
html.B("Entity ID: "), tdata.get('entity_id_data', 'Unknown'),
|
71
|
+
html.Br(),
|
72
|
+
html.B("Job ID: "), job_id if job_id else "Unknown",
|
73
|
+
html.Br(),
|
74
|
+
html.B("User Name: "), tdata.get('user_data', 'Unknown'),
|
75
|
+
html.Br(),
|
76
|
+
html.B("Session Expires: "), tdata.get('token_expires', 'Unknown'),
|
77
|
+
html.Br(),
|
78
|
+
html.B("App Name: "), app_data.get("name", "Unknown"),
|
79
|
+
html.Br(),
|
80
|
+
html.B("App Description: "), app_data.get("description", "No description available"),
|
81
|
+
html.Br(),
|
82
|
+
html.B("Current Time: "), str(dt.now().strftime("%Y-%m-%d %H:%M:%S"))
|
83
|
+
])
|
84
|
+
]
|
85
|
+
|
86
|
+
return token, tdata, entity_data, app_data, page_title, session_details, job_link
|
87
|
+
else:
|
88
|
+
return None, None, None, None, base_title, None, None
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
def submit_bug_report(n_clicks, bug_description, token, entity_data):
|
93
|
+
"""
|
94
|
+
Submits a bug report based on user input, token, and entity data.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
n_clicks (int): The number of times the submit button has been clicked.
|
98
|
+
bug_description (str): The description of the bug provided by the user.
|
99
|
+
token (str): The authentication token.
|
100
|
+
entity_data (dict): The data related to the current entity.
|
101
|
+
|
102
|
+
Returns:
|
103
|
+
tuple: A tuple containing two boolean values indicating success and failure status of the submission.
|
104
|
+
(is_open_success, is_open_failure)
|
105
|
+
"""
|
106
|
+
bfabric_interface = BfabricInterface()
|
107
|
+
print("submit bug report", token)
|
108
|
+
|
109
|
+
# Parse token data if token is provided, otherwise set it to an empty dictionary
|
110
|
+
if token:
|
111
|
+
token_data = json.loads(bfabric_interface.token_to_data(token))
|
112
|
+
else:
|
113
|
+
token_data = {}
|
114
|
+
|
115
|
+
print(token_data)
|
116
|
+
|
117
|
+
# Extract logging-related information from token_data, with defaults for missing values
|
118
|
+
jobId = token_data.get('jobId', None)
|
119
|
+
username = token_data.get("user_data", "None")
|
120
|
+
environment = token_data.get("environment", "None")
|
121
|
+
|
122
|
+
# Initialize the logger only if token_data is available
|
123
|
+
L = None
|
124
|
+
if token_data:
|
125
|
+
L = get_logger(token_data)
|
126
|
+
|
127
|
+
if n_clicks:
|
128
|
+
# Log the operation only if the logger is initialized
|
129
|
+
if L:
|
130
|
+
L.log_operation(
|
131
|
+
"bug report",
|
132
|
+
"Initiating bug report submission process.",
|
133
|
+
params=None,
|
134
|
+
flush_logs=False,
|
135
|
+
)
|
136
|
+
try:
|
137
|
+
sending_result = bfabric_interface.send_bug_report(
|
138
|
+
token_data, entity_data, bug_description
|
139
|
+
)
|
140
|
+
|
141
|
+
if sending_result:
|
142
|
+
if L:
|
143
|
+
L.log_operation(
|
144
|
+
"bug report",
|
145
|
+
f"Bug report successfully submitted. | DESCRIPTION: {bug_description}",
|
146
|
+
params=None,
|
147
|
+
flush_logs=True,
|
148
|
+
)
|
149
|
+
return True, False
|
150
|
+
else:
|
151
|
+
if L:
|
152
|
+
L.log_operation(
|
153
|
+
"bug report",
|
154
|
+
"Failed to submit bug report!",
|
155
|
+
params=None,
|
156
|
+
flush_logs=True,
|
157
|
+
)
|
158
|
+
return False, True
|
159
|
+
except Exception as e:
|
160
|
+
if L:
|
161
|
+
L.log_operation(
|
162
|
+
"bug report",
|
163
|
+
f"Failed to submit bug report! Error: {str(e)}",
|
164
|
+
params=None,
|
165
|
+
flush_logs=True,
|
166
|
+
)
|
167
|
+
return False, True
|
168
|
+
|
169
|
+
return False, False
|
170
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from dash import html
|
2
|
+
|
3
|
+
DEVELOPER_EMAIL = "gwhite@fgcz.ethz.ch"
|
4
|
+
|
5
|
+
expired = [
|
6
|
+
html.P("Your session has expired. Please log into bfabric to continue:"),
|
7
|
+
html.A('Login to Bfabric', href='https://fgcz-bfabric.uzh.ch/bfabric/')
|
8
|
+
]
|
9
|
+
|
10
|
+
no_entity = [
|
11
|
+
html.P("There was an error fetching the data for your entity. Please try accessing the applicaiton again from bfabric:"),
|
12
|
+
html.A('Login to Bfabric', href='https://fgcz-bfabric.uzh.ch/bfabric/')
|
13
|
+
]
|
14
|
+
|
15
|
+
dev = [html.P("This page is under development. Please check back later."),html.Br(),html.A("email the developer for more details",href="mailto:"+DEVELOPER_EMAIL)]
|
16
|
+
|
17
|
+
auth = [html.Div(id="auth-div")]
|
18
|
+
|
19
|
+
no_auth = [
|
20
|
+
html.P("You are not currently logged into an active session. Please log into bfabric to continue:"),
|
21
|
+
html.A('Login to Bfabric', href='https://fgcz-bfabric.uzh.ch/bfabric/')
|
22
|
+
]
|
@@ -0,0 +1,86 @@
|
|
1
|
+
from bfabric import Bfabric
|
2
|
+
|
3
|
+
def get_user_input():
|
4
|
+
"""Prompt user for necessary inputs."""
|
5
|
+
|
6
|
+
systems = {"TEST": "TEST", "PROD": "PRODUCTION"}
|
7
|
+
|
8
|
+
technologies = {
|
9
|
+
"TEST": {
|
10
|
+
"1": "Genomics / Transcriptomics",
|
11
|
+
"2": "Proteomics",
|
12
|
+
"4": "Metabolomics / Biophysics",
|
13
|
+
"6": "General",
|
14
|
+
"10": "New Tech"
|
15
|
+
},
|
16
|
+
"PRODUCTION": {
|
17
|
+
"1": "Genomics / Transcriptomics",
|
18
|
+
"2": "Proteomics",
|
19
|
+
"4": "Metabolomics / Biophysics",
|
20
|
+
"6": "General",
|
21
|
+
"10": "Bioinformatics"
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
# Get system input
|
26
|
+
system = input("In which system do you want to create the app? (Type 'TEST' for the test system or 'PROD' for the production system): ").strip().upper()
|
27
|
+
|
28
|
+
while system not in systems:
|
29
|
+
print("Invalid input! Please enter 'TEST' or 'PROD'.")
|
30
|
+
system = input("Enter system (TEST/PROD): ").strip().upper()
|
31
|
+
|
32
|
+
selected_system = systems[system] # Map input to full system name
|
33
|
+
|
34
|
+
# Display technology options based on selected system
|
35
|
+
print("\nAvailable Technologies:")
|
36
|
+
for key, value in technologies[selected_system].items():
|
37
|
+
print(f"{key}: {value}")
|
38
|
+
|
39
|
+
# Get technology ID from user
|
40
|
+
technologyid = input("\nEnter the number corresponding to your chosen application type: ").strip()
|
41
|
+
|
42
|
+
while technologyid not in technologies[selected_system]:
|
43
|
+
print("Invalid technology ID! Please select a valid number from the list.")
|
44
|
+
technologyid = input("Enter a valid technology ID: ").strip()
|
45
|
+
|
46
|
+
# Get remaining inputs
|
47
|
+
name = input("Enter app name: ")
|
48
|
+
weburl = input("Enter web URL: ")
|
49
|
+
description = input("Enter description: ")
|
50
|
+
|
51
|
+
return {
|
52
|
+
"system": selected_system,
|
53
|
+
"name": name,
|
54
|
+
"weburl": weburl,
|
55
|
+
"type": "WebApp",
|
56
|
+
"technologyid": technologyid,
|
57
|
+
"supervisorid": "2446",
|
58
|
+
"enabled": True,
|
59
|
+
"valid": True,
|
60
|
+
"hidden": False,
|
61
|
+
"description": description
|
62
|
+
}
|
63
|
+
|
64
|
+
def create_app_in_bfabric():
|
65
|
+
"""Create an app in B-Fabric using user inputs."""
|
66
|
+
# Get user input for parameters
|
67
|
+
user_input = get_user_input()
|
68
|
+
|
69
|
+
# Determine configuration environment based on user input
|
70
|
+
config_env = user_input.pop("system")
|
71
|
+
|
72
|
+
# Initialize Bfabric instance
|
73
|
+
bfabric = Bfabric.from_config(config_env=config_env)
|
74
|
+
|
75
|
+
# Set endpoint for app creation
|
76
|
+
endpoint = "application"
|
77
|
+
|
78
|
+
# Make API call to save the app
|
79
|
+
try:
|
80
|
+
result = bfabric.save(endpoint=endpoint, obj=user_input)
|
81
|
+
print("App created successfully:", result)
|
82
|
+
except Exception as e:
|
83
|
+
print("Failed to create app:", str(e))
|
84
|
+
|
85
|
+
if __name__ == "__main__":
|
86
|
+
create_app_in_bfabric()
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# defaults.py
|
2
|
+
CONFIG_FILE_PATH = "~/.bfabricpy.yml"
|
3
|
+
|
4
|
+
# Default values for application settings
|
5
|
+
HOST = "0.0.0.0"
|
6
|
+
PORT = 8050
|
7
|
+
DEV = False
|
8
|
+
|
9
|
+
# Developer and bug report email addresses
|
10
|
+
DEVELOPER_EMAIL_ADDRESS = "griffin@gwcustom.com"
|
11
|
+
BUG_REPORT_EMAIL_ADDRESS = "gwtools@fgcz.system"
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from bfabric_web_apps.objects.Logger import Logger
|
2
|
+
|
3
|
+
def get_logger(token_data):
|
4
|
+
|
5
|
+
""" Extract logging-related information from token_data, with defaults for missing values """
|
6
|
+
jobId = token_data.get('jobId', None)
|
7
|
+
username = token_data.get("user_data", "None")
|
8
|
+
environment = token_data.get("environment", "None")
|
9
|
+
|
10
|
+
return Logger(
|
11
|
+
jobid=jobId,
|
12
|
+
username=username,
|
13
|
+
environment=environment,
|
14
|
+
)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import os
|
2
|
+
from bfabric import Bfabric
|
3
|
+
import bfabric_web_apps
|
4
|
+
|
5
|
+
def get_power_user_wrapper(token_data):
|
6
|
+
"""
|
7
|
+
Initializes and returns a Bfabric power user instance configured for a specific environment.
|
8
|
+
|
9
|
+
This function retrieves the environment information from the provided `token_data`
|
10
|
+
and uses it to initialize a Bfabric instance. The configuration file path is
|
11
|
+
determined by the `CONFIG_FILE_PATH` from the application's configuration.
|
12
|
+
|
13
|
+
Args:
|
14
|
+
token_data (dict): A dictionary containing token information
|
15
|
+
The key "environment" is used to determine the environment
|
16
|
+
(default is "None" if not specified).
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
Bfabric: A Bfabric instance initialized with the configuration
|
20
|
+
corresponding to the specified environment.
|
21
|
+
"""
|
22
|
+
environment = token_data.get("environment", "None")
|
23
|
+
|
24
|
+
return Bfabric.from_config(
|
25
|
+
config_path = os.path.expanduser(bfabric_web_apps.CONFIG_FILE_PATH),
|
26
|
+
config_env = environment.upper()
|
27
|
+
)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 GWC GmbH
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -1,10 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: bfabric-web-apps
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: A package containing handy boilerplate utilities for developing bfabric web-applications
|
5
|
-
Author:
|
5
|
+
Author: Marc Zuber, Griffin White, GWC GmbH
|
6
6
|
Requires-Python: >=3.8,<4.0
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
8
|
-
Classifier: Programming Language :: Python :: 3.10
|
9
8
|
Classifier: Programming Language :: Python :: 3.8
|
10
9
|
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
@@ -0,0 +1,15 @@
|
|
1
|
+
bfabric_web_apps/__init__.py,sha256=zZvM0CQPkiu0y9xOZos-d2hK-h6erc8K_nov7vD1bdE,2362
|
2
|
+
bfabric_web_apps/layouts/layouts.py,sha256=XoSLcQPcgMBhQz2VfxkUzNL23FLBXFRFvbCL2mNLfnk,11636
|
3
|
+
bfabric_web_apps/objects/BfabricInterface.py,sha256=nRdU_cYLW2_xp2x1cvP9b30gQ5blavbOz66B-Hi6UZQ,8980
|
4
|
+
bfabric_web_apps/objects/Logger.py,sha256=62LC94xhm7YG5LUw3yH46NqvJQsAX7wnc9D4zbY16rA,5224
|
5
|
+
bfabric_web_apps/utils/app_init.py,sha256=RCdpCXp19cF74bouYJLPe-KSETZ0Vwqtd02Ta2VXEF8,428
|
6
|
+
bfabric_web_apps/utils/callbacks.py,sha256=PiP1ZJ-QxdrOAZ-Mt-MN-g9wJLSOoLkWkXwPq_TLqDI,6472
|
7
|
+
bfabric_web_apps/utils/components.py,sha256=V7ECGmF2XYy5O9ciDJVH1nofJYP2a_ELQF3z3X_ADbo,844
|
8
|
+
bfabric_web_apps/utils/create_app_in_bfabric.py,sha256=eVk3cQDXxW-yo9b9n_zzGO6kLg_SLxYbIDECyvEPJXU,2752
|
9
|
+
bfabric_web_apps/utils/defaults.py,sha256=B82j3JEbysLEU9JDZgoDBTX7WGvW3Hn5YMZaWAcjZew,278
|
10
|
+
bfabric_web_apps/utils/get_logger.py,sha256=0Y3SrXW93--eglS0_ZOc34NOriAt6buFPik5n0ltzRA,434
|
11
|
+
bfabric_web_apps/utils/get_power_user_wrapper.py,sha256=T33z64XjmJ0KSlmfEmrEP8eYpbpINCVD6Xld_V7PR2g,1027
|
12
|
+
bfabric_web_apps-0.1.2.dist-info/LICENSE,sha256=k0O_i2k13i9e35aO-j7FerJafAqzzu8x0kkBs0OWF3c,1065
|
13
|
+
bfabric_web_apps-0.1.2.dist-info/METADATA,sha256=tvvoNH4-tMyPbWJdoe_pVgC_cDzQpDzdGtqd49vt9QI,480
|
14
|
+
bfabric_web_apps-0.1.2.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
|
15
|
+
bfabric_web_apps-0.1.2.dist-info/RECORD,,
|
File without changes
|
@@ -1,8 +0,0 @@
|
|
1
|
-
bfabric_web_apps/__init__.py,sha256=6IFMcIq8biYvtMafM-gELPRBq19k5kHRlEYmRTsXlYI,87
|
2
|
-
bfabric_web_apps/layouts/layouts.py,sha256=6b5_wk2fk1ZLyWhhhKfz2EnsSdZtlPx8aR-pMfPC1t0,135
|
3
|
-
bfabric_web_apps/objects/BfabricInterface.py,sha256=IU1D1Q6ZdAR0oo64Fpcru9LWVj-3Ydmlti6Vy_-VSj4,275
|
4
|
-
bfabric_web_apps/objects/Logger.py,sha256=Sikkqfbkp7NGqEkFZ4cHKtjGX1Bu9Y8sf1PWDLOOjco,3467
|
5
|
-
bfabric_web_apps/objects/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
bfabric_web_apps-0.1.0.dist-info/WHEEL,sha256=y3eDiaFVSNTPbgzfNn0nYn5tEn1cX6WrdetDlQM4xWw,83
|
7
|
-
bfabric_web_apps-0.1.0.dist-info/METADATA,sha256=9GcQM9qWxhYBDHgmq0r0Gu9mAmvvn0Lxy0YJrfFCiPc,429
|
8
|
-
bfabric_web_apps-0.1.0.dist-info/RECORD,,
|