bfabric-web-apps 0.1.0__py3-none-any.whl → 0.1.1__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.
@@ -1,6 +1,36 @@
1
- from objects import (
2
- BfabricInterface,
3
- Logger
4
- )
1
+ # Export objects and classes
2
+ from bfabric_web_apps.objects import BfabricInterface, Logger
5
3
 
6
- from layouts.layouts import *
4
+ # Export components
5
+ from .utils.components import *
6
+
7
+ # Export layouts
8
+ from .layouts.layouts import get_static_layout
9
+
10
+ # Export app initialization utilities
11
+ from .utils.app_init import create_app
12
+ from .utils.app_config import load_config
13
+ from .utils.get_logger import get_logger
14
+ from .utils.get_power_user_wrapper import get_power_user_wrapper
15
+
16
+ # Export callbacks
17
+ from .utils.callbacks import process_url_and_token, submit_bug_report
18
+
19
+ HOST = '0.0.0.0'
20
+ PORT = 8050
21
+ DEV = False
22
+ CONFIG_FILE_PATH = "~/.bfabricpy.yml"
23
+
24
+ # Define __all__ for controlled imports
25
+ __all__ = [
26
+ "BfabricInterface",
27
+ "Logger",
28
+ "components",
29
+ "get_static_layout",
30
+ "create_app",
31
+ "load_config",
32
+ "process_url_and_token",
33
+ "submit_bug_report",
34
+ 'get_logger',
35
+ 'get_power_user_wrapper'
36
+ ]
@@ -1,13 +1,205 @@
1
+ from dash import html, dcc
2
+ import dash_bootstrap_components as dbc
1
3
 
4
+ def get_static_layout(base_title = None, main_content = None, documentation_content = None):
5
+ """
6
+ Returns a layout with static tabs for Main, Documentation, and Report a Bug.
7
+ The main content is customizable, while the other tabs are generic.
8
+ """
9
+ return html.Div(
10
+ children=[
11
+ dcc.Location(id='url', refresh=False),
12
+ dcc.Store(id='token', storage_type='session'),
13
+ dcc.Store(id='entity', storage_type='session'),
14
+ dcc.Store(id='token_data', storage_type='session'),
15
+ dbc.Container(
16
+ children=[
17
+ # Banner
18
+ dbc.Row(
19
+ dbc.Col(
20
+ html.Div(
21
+ className="banner",
22
+ children=[
23
+ html.Div(
24
+ children=[
25
+ html.P(
26
+ base_title,
27
+ style={
28
+ 'color': '#ffffff',
29
+ 'margin-top': '15px',
30
+ 'height': '80px',
31
+ 'width': '100%',
32
+ 'font-size': '40px',
33
+ 'margin-left': '20px'
34
+ }
35
+ )
36
+ ],
37
+ style={"background-color": "#000000", "border-radius": "10px"}
38
+ )
39
+ ],
40
+ ),
41
+ ),
42
+ ),
43
+ # Page Title
44
+ dbc.Row(
45
+ dbc.Col(
46
+ [
47
+ html.Div(
48
+ children=[
49
+ html.P(
50
+ id="page-title",
51
+ children=[str(" ")],
52
+ style={"font-size": "40px", "margin-left": "20px", "margin-top": "10px"}
53
+ )
54
+ ],
55
+ style={
56
+ "margin-top": "0px",
57
+ "min-height": "80px",
58
+ "height": "6vh",
59
+ "border-bottom": "2px solid #d4d7d9"
60
+ }
61
+ ),
62
+ dbc.Alert(
63
+ "Your bug report has been submitted. Thanks for helping us improve!",
64
+ id="alert-fade-bug-success",
65
+ dismissable=True,
66
+ is_open=False,
67
+ color="info",
68
+ style={
69
+ "max-width": "50vw",
70
+ "margin-left": "10px",
71
+ "margin-top": "10px",
72
+ }
73
+ ),
74
+ dbc.Alert(
75
+ "Failed to submit bug report! Please email the developers directly at the email below!",
76
+ id="alert-fade-bug-fail",
77
+ dismissable=True,
78
+ is_open=False,
79
+ color="danger",
80
+ style={
81
+ "max-width": "50vw",
82
+ "margin-left": "10px",
83
+ "margin-top": "10px",
84
+ }
85
+ ),
86
+ ]
87
+ )
88
+ ),
89
+ # Tabs
90
+ dbc.Tabs(
91
+ [
92
+ dbc.Tab(main_content, label="Main", tab_id="main"),
93
+ dbc.Tab(get_documentation_tab(documentation_content), label="Documentation", tab_id="documentation"),
94
+ dbc.Tab(get_report_bug_tab(), label="Report a Bug", tab_id="report-bug"),
95
+ ],
96
+ id="tabs",
97
+ active_tab="main",
98
+ ),
99
+ ],
100
+ fluid=True,
101
+ style={"width": "100vw"}
102
+ )
103
+ ],
104
+ style={"width": "100vw", "overflow-x": "hidden", "overflow-y": "scroll"}
105
+ )
2
106
 
3
- def get_empty_layout():
4
107
 
5
- pass
108
+ def get_documentation_tab(documentation_content):
109
+ """
110
+ Returns the content for the Documentation tab with the upgraded layout.
111
+ """
112
+ return dbc.Row(
113
+ id="page-content-docs",
114
+ children=[
115
+ dbc.Col(
116
+ html.Div(
117
+ id="sidebar_docs",
118
+ children=[],
119
+ style={
120
+ "border-right": "2px solid #d4d7d9",
121
+ "height": "100%",
122
+ "padding": "20px",
123
+ "font-size": "20px",
124
+ },
125
+ ),
126
+ width=3,
127
+ ),
128
+ dbc.Col(
129
+ html.Div(
130
+ id="page-content-docs-children",
131
+ children= documentation_content,
132
+ style={"margin-top":"2vh", "margin-left":"2vw", "font-size":"20px", "padding-right":"40px", "overflow-y": "scroll", "max-height": "60vh"},
133
+ ),
134
+ width=9,
135
+ ),
136
+ ],
137
+ style={"margin-top": "0px", "min-height": "40vh"},
138
+ )
6
139
 
7
- def get_layout_with_sidebar():
8
-
9
- pass
10
140
 
11
- def get_layout_without_sidebar():
12
-
13
- pass
141
+ def get_report_bug_tab():
142
+ """
143
+ Returns the content for the Report a Bug tab with the upgraded layout.
144
+ """
145
+ return dbc.Row(
146
+ id="page-content-bug-report",
147
+ children=[
148
+ dbc.Col(
149
+ html.Div(
150
+ id="sidebar_bug_report",
151
+ children=[], # Optional: Add sidebar content here if needed
152
+ style={
153
+ "border-right": "2px solid #d4d7d9",
154
+ "height": "100%",
155
+ "padding": "20px",
156
+ "font-size": "20px",
157
+ },
158
+ ),
159
+ width=3,
160
+ ),
161
+ dbc.Col(
162
+ html.Div(
163
+ id="page-content-bug-report-children",
164
+ children=[
165
+ html.H2("Report a Bug"),
166
+ html.P(
167
+ [
168
+ "Please use the form below to report a bug. If you have any questions, please email the developer at ",
169
+ html.A(
170
+ "griffin@gwcustom.com",
171
+ href="mailto:griffin@gwcustom.com",
172
+ ),
173
+ ]
174
+ ),
175
+ html.Br(),
176
+ html.H4("Session Details: "),
177
+ html.Br(),
178
+ html.P(id="session-details", children="No Active Session"),
179
+ html.Br(),
180
+ html.H4("Bug Description"),
181
+ dbc.Textarea(
182
+ id="bug-description",
183
+ placeholder="Please describe the bug you encountered here.",
184
+ style={"width": "100%"},
185
+ ),
186
+ html.Br(),
187
+ dbc.Button(
188
+ "Submit Bug Report",
189
+ id="submit-bug-report",
190
+ n_clicks=0,
191
+ style={"margin-bottom": "60px"},
192
+ ),
193
+ ],
194
+ style={
195
+ "margin-top": "2vh",
196
+ "margin-left": "2vw",
197
+ "font-size": "20px",
198
+ "padding-right": "40px",
199
+ },
200
+ ),
201
+ width=9,
202
+ ),
203
+ ],
204
+ style={"margin-top": "0px", "min-height": "40vh"},
205
+ )
@@ -1,16 +1,222 @@
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 dash import html
9
+ import dash_bootstrap_components as dbc
10
+ from bfabric_web_apps.objects.Logger import Logger
11
+ import os
2
12
 
3
- class BfabricInterface( Bfabric ):
4
13
 
5
- def __init__():
6
- pass
14
+ VALIDATION_URL = "https://fgcz-bfabric.uzh.ch/bfabric/rest/token/validate?token="
15
+ HOST = "fgcz-bfabric.uzh.ch"
7
16
 
8
- def token_to_data(self, token):
9
- pass
10
17
 
11
- def token_response_to_bfabric(self, token_response):
12
- pass
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
+ """
13
23
 
14
- def entity_data(self, entity):
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
+ """
115
+ Retrieves entity data associated with the provided token.
116
+
117
+ Args:
118
+ token_data (dict): The token data.
119
+
120
+ Returns:
121
+ str: A JSON string containing entity data.
122
+ None: If the retrieval fails.
123
+ """
124
+
125
+ entity_class_map = {
126
+ "Run": "run",
127
+ "Sample": "sample",
128
+ "Project": "container",
129
+ "Order": "container",
130
+ "Container": "container",
131
+ "Plate": "plate"
132
+ }
133
+
134
+ if not token_data:
135
+ return None
136
+
137
+ wrapper = self.token_response_to_bfabric(token_data)
138
+ entity_class = token_data.get('entityClass_data', None)
139
+ endpoint = entity_class_map.get(entity_class, None)
140
+ entity_id = token_data.get('entity_id_data', None)
141
+ jobId = token_data.get('jobId', None)
142
+ username = token_data.get("user_data", "None")
143
+ environment= token_data.get("environment", "None")
144
+
145
+
146
+ if wrapper and entity_class and endpoint and entity_id and jobId:
147
+
148
+ L = Logger(
149
+ jobid = jobId,
150
+ username= username,
151
+ environment= environment
152
+ )
153
+
154
+ # Log the read operation directly using Logger L
155
+ entity_data_dict = L.logthis(
156
+ api_call=wrapper.read,
157
+ endpoint=endpoint,
158
+ obj={"id": entity_id},
159
+ max_results=None,
160
+ params = None,
161
+ flush_logs = True
162
+ )[0]
163
+
164
+ if entity_data_dict:
165
+ json_data = json.dumps({
166
+ "name": entity_data_dict.get("name", ""),
167
+ "createdby": entity_data_dict.get("createdby"),
168
+ "created": entity_data_dict.get("created"),
169
+ "modified": entity_data_dict.get("modified"),
170
+ })
171
+ return json_data
172
+ else:
173
+ L.log_operation(
174
+ operation= "entity_data",
175
+ message= "Entity data retrieval failed or returned None.",
176
+ params=None,
177
+ flush_logs=True
178
+ )
179
+ print("entity_data_dict is empty or None")
180
+ return None
181
+
182
+ else:
183
+ print("Invalid input or entity information")
184
+ return None
185
+
186
+
187
+ def send_bug_report(self, token_data = None, entity_data = None, description = None):
188
+ """
189
+ Sends a bug report via email.
190
+
191
+ Args:
192
+ token_data (dict): Token data to include in the report.
193
+ entity_data (dict): Entity data to include in the report.
194
+ description (str): A description of the bug.
195
+
196
+ Returns:
197
+ bool: True if the report is sent successfully, False otherwise.
198
+ """
199
+
200
+ mail_string = f"""
201
+ BUG REPORT FROM QC-UPLOADER
202
+ \n\n
203
+ token_data: {token_data} \n\n
204
+ entity_data: {entity_data} \n\n
205
+ description: {description} \n\n
206
+ sent_at: {datetime.datetime.now()} \n\n
207
+ """
208
+
209
+ mail = f"""
210
+ echo "{mail_string}" | mail -s "Bug Report" gwtools@fgcz.system
211
+ """
212
+
213
+ print("MAIL STRING:")
214
+ print(mail_string)
215
+
216
+ print("MAIL:")
217
+ print(mail)
218
+
219
+ os.system(mail)
220
+
221
+ return True
222
+
@@ -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
7
+ from ..utils.app_config import load_config
6
8
 
7
- try:
8
- from PARAMS import CONFIG_FILE_PATH
9
- except ImportError:
10
- CONFIG_FILE_PATH = "~/.bfabricpy.yml"
11
-
9
+ CONFIG_FILE_PATH = load_config()["CONFIG_FILE_PATH"]
12
10
 
13
11
  class Logger:
14
12
  """
15
13
  A Logger class to manage and batch API call logs locally and flush them to the backend when needed.
16
14
  """
17
- def __init__(self, jobid: int, username: str):
15
+ def __init__(self, jobid: int, username: str, environment: str):
16
+ """
17
+ Initializes the Logger with a job ID, username, and environment.
18
+
19
+ Args:
20
+ jobid (int): The ID of the current job.
21
+ username (str): The name of the user performing the operations.
22
+ environment (str): The environment (e.g., Production, Test).
23
+ """
18
24
  self.jobid = jobid
19
25
  self.username = username
20
- self.power_user_wrapper = self._get_power_user_wrapper()
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(CONFIG_FILE_PATH)
40
+ config_path = os.path.expanduser(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
- Log an operation either locally (if flush_logs=False) or flush to the backend.
44
- Creates well-structured, readable log entries.
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
- Generic logging function to wrap any API call using a Logger instance.
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,27 @@
1
+ import os
2
+ import importlib.util
3
+
4
+ def load_config(params_path="./PARAMS.py"):
5
+ """Load configuration for the Dash app."""
6
+ if os.path.exists(params_path):
7
+ try:
8
+ # Dynamically import the PARAMS module
9
+ spec = importlib.util.spec_from_file_location("PARAMS", params_path)
10
+ params_module = importlib.util.module_from_spec(spec)
11
+ spec.loader.exec_module(params_module)
12
+
13
+ # Retrieve values with defaults
14
+ PORT = getattr(params_module, "PORT", 8050)
15
+ HOST = getattr(params_module, "HOST", "localhost")
16
+ DEV = getattr(params_module, "DEV", True)
17
+ CONFIG_FILE_PATH = getattr(params_module, "CONFIG_FILE_PATH", "~/.bfabricpy.yml")
18
+ except ImportError:
19
+ # Fallback to default values in case of import errors
20
+ PORT, HOST, DEV = 8050, 'localhost', True
21
+ CONFIG_FILE_PATH = "~/.bfabricpy.yml"
22
+ else:
23
+ # Fallback to default values if PARAMS.py is not found
24
+ PORT, HOST, DEV = 8050, 'localhost', True
25
+ CONFIG_FILE_PATH = "~/.bfabricpy.yml"
26
+
27
+ return {"PORT": PORT, "HOST": HOST, "DEV": DEV, "CONFIG_FILE_PATH": CONFIG_FILE_PATH}
@@ -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,152 @@
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 bfabric_web_apps.objects.Logger import Logger
6
+ from datetime import datetime as dt
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
+
12
+ Args:
13
+ url_params (str): The URL parameters containing the token.
14
+ base_title (str): The base title of the page.
15
+
16
+ Returns:
17
+ tuple: A tuple containing token data, entity data, and the page content.
18
+ (token, token_data, entity_data, page_content, page_title)
19
+ """
20
+ base_title = " "
21
+
22
+ if not url_params:
23
+ return None, None, None, base_title, None
24
+
25
+ token = "".join(url_params.split('token=')[1:])
26
+ bfabric_interface = BfabricInterface()
27
+ tdata_raw = bfabric_interface.token_to_data(token)
28
+
29
+ if tdata_raw:
30
+ if tdata_raw == "EXPIRED":
31
+ return None, None, None, base_title, None
32
+ else:
33
+ tdata = json.loads(tdata_raw)
34
+ else:
35
+ return None, None, None, base_title, None
36
+
37
+ if tdata:
38
+ entity_data_json = bfabric_interface.entity_data(tdata)
39
+ entity_data = json.loads(entity_data_json)
40
+ page_title = (
41
+ f"{tdata['entityClass_data']} - {entity_data['name']} "
42
+ f"({tdata['environment']} System)"
43
+ ) if tdata else "Bfabric App Interface"
44
+
45
+ if not entity_data:
46
+ return token, tdata, None, page_title, None
47
+ else:
48
+ session_details = [
49
+ html.P([
50
+ html.B("Entity Name: "), entity_data['name'],
51
+ html.Br(),
52
+ html.B("Entity Class: "), tdata['entityClass_data'],
53
+ html.Br(),
54
+ html.B("Environment: "), tdata['environment'],
55
+ html.Br(),
56
+ html.B("Entity ID: "), tdata['entity_id_data'],
57
+ html.Br(),
58
+ html.B("User Name: "), tdata['user_data'],
59
+ html.Br(),
60
+ html.B("Session Expires: "), tdata['token_expires'],
61
+ html.Br(),
62
+ html.B("Current Time: "), str(dt.now().strftime("%Y-%m-%d %H:%M:%S"))
63
+ ])
64
+ ]
65
+ return token, tdata, entity_data, page_title, session_details
66
+ else:
67
+ return None, None, None, base_title, None
68
+
69
+
70
+ def submit_bug_report(n_clicks, bug_description, token, entity_data):
71
+ """
72
+ Submits a bug report based on user input, token, and entity data.
73
+
74
+ Args:
75
+ n_clicks (int): The number of times the submit button has been clicked.
76
+ bug_description (str): The description of the bug provided by the user.
77
+ token (str): The authentication token.
78
+ entity_data (dict): The data related to the current entity.
79
+
80
+ Returns:
81
+ tuple: A tuple containing two boolean values indicating success and failure status of the submission.
82
+ (is_open_success, is_open_failure)
83
+ """
84
+ bfabric_interface = BfabricInterface()
85
+ print("submit bug report", token)
86
+
87
+ # Parse token data if token is provided, otherwise set it to an empty dictionary
88
+ if token:
89
+ token_data = json.loads(bfabric_interface.token_to_data(token))
90
+ else:
91
+ token_data = {}
92
+
93
+ print(token_data)
94
+
95
+ # Extract logging-related information from token_data, with defaults for missing values
96
+ jobId = token_data.get('jobId', None)
97
+ username = token_data.get("user_data", "None")
98
+ environment = token_data.get("environment", "None")
99
+
100
+ # Initialize the logger only if token_data is available
101
+ L = None
102
+ if token_data:
103
+ L = Logger(
104
+ jobid=jobId,
105
+ username=username,
106
+ environment=environment
107
+ )
108
+
109
+ if n_clicks:
110
+ # Log the operation only if the logger is initialized
111
+ if L:
112
+ L.log_operation(
113
+ "bug report",
114
+ "Initiating bug report submission process.",
115
+ params=None,
116
+ flush_logs=False,
117
+ )
118
+ try:
119
+ sending_result = bfabric_interface.send_bug_report(
120
+ token_data, entity_data, bug_description
121
+ )
122
+
123
+ if sending_result:
124
+ if L:
125
+ L.log_operation(
126
+ "bug report",
127
+ f"Bug report successfully submitted. | DESCRIPTION: {bug_description}",
128
+ params=None,
129
+ flush_logs=True,
130
+ )
131
+ return True, False
132
+ else:
133
+ if L:
134
+ L.log_operation(
135
+ "bug report",
136
+ "Failed to submit bug report!",
137
+ params=None,
138
+ flush_logs=True,
139
+ )
140
+ return False, True
141
+ except Exception as e:
142
+ if L:
143
+ L.log_operation(
144
+ "bug report",
145
+ f"Failed to submit bug report! Error: {str(e)}",
146
+ params=None,
147
+ flush_logs=True,
148
+ )
149
+ return False, True
150
+
151
+ return False, False
152
+
@@ -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,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,29 @@
1
+ import os
2
+ from bfabric import Bfabric
3
+ from .app_config import load_config
4
+
5
+ CONFIG_FILE_PATH = load_config()["CONFIG_FILE_PATH"]
6
+
7
+ def get_power_user_wrapper(token_data):
8
+ """
9
+ Initializes and returns a Bfabric power user instance configured for a specific environment.
10
+
11
+ This function retrieves the environment information from the provided `token_data`
12
+ and uses it to initialize a Bfabric instance. The configuration file path is
13
+ determined by the `CONFIG_FILE_PATH` from the application's configuration.
14
+
15
+ Args:
16
+ token_data (dict): A dictionary containing token information.
17
+ The key "environment" is used to determine the environment
18
+ (default is "None" if not specified).
19
+
20
+ Returns:
21
+ Bfabric: A Bfabric instance initialized with the configuration
22
+ corresponding to the specified environment.
23
+ """
24
+ environment = token_data.get("environment", "None")
25
+
26
+ return Bfabric.from_config(
27
+ config_path = os.path.expanduser(CONFIG_FILE_PATH),
28
+ config_env = environment.upper()
29
+ )
@@ -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.0
3
+ Version: 0.1.1
4
4
  Summary: A package containing handy boilerplate utilities for developing bfabric web-applications
5
- Author: Mark Zuber, Griffin White, GWC GmbH
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,14 @@
1
+ bfabric_web_apps/__init__.py,sha256=XDzAg0boEE3nj3RXGB85YbVc0KgEeRNOcQfrSkJoV-0,880
2
+ bfabric_web_apps/layouts/layouts.py,sha256=oQHfT65PdoFU5js8JkEJqFhxfgNjwU0GRvD1xbkfYD4,8758
3
+ bfabric_web_apps/objects/BfabricInterface.py,sha256=pHse1UgC_XFD-PsYqOs0Ho3xTRMDRCvtRgsILVYy-0k,6919
4
+ bfabric_web_apps/objects/Logger.py,sha256=ikMJJZYDPhJZEmgCY63_htGmPvXv1ItSmfb_xiFFZMQ,5225
5
+ bfabric_web_apps/utils/app_config.py,sha256=u7lz8sonf9CSkJsVK0nhTzIls227FksGCOb_SzYE_fE,1204
6
+ bfabric_web_apps/utils/app_init.py,sha256=RCdpCXp19cF74bouYJLPe-KSETZ0Vwqtd02Ta2VXEF8,428
7
+ bfabric_web_apps/utils/callbacks.py,sha256=OlNelwAJUKsEtnaJ4OuTdrgyu9PhEgm4uqCde4NNKHA,5270
8
+ bfabric_web_apps/utils/components.py,sha256=V7ECGmF2XYy5O9ciDJVH1nofJYP2a_ELQF3z3X_ADbo,844
9
+ bfabric_web_apps/utils/get_logger.py,sha256=_cn0en-itaGEeeCDtws-nw2ubd36w2xc6VfDNoBMFu4,433
10
+ bfabric_web_apps/utils/get_power_user_wrapper.py,sha256=ZUrv-xNLEXtMVeFEpAwmPbPFUmcAxu3hITIuPY2dhF8,1078
11
+ bfabric_web_apps-0.1.1.dist-info/LICENSE,sha256=k0O_i2k13i9e35aO-j7FerJafAqzzu8x0kkBs0OWF3c,1065
12
+ bfabric_web_apps-0.1.1.dist-info/METADATA,sha256=R1zgL1bVK18CV4uPQc1vUABgBnOn6us0YBbcC6yqy0g,480
13
+ bfabric_web_apps-0.1.1.dist-info/WHEEL,sha256=d2fvjOD7sXsVzChCqf0Ty0JbHKBaLYwDbGQDwQTnJ50,88
14
+ bfabric_web_apps-0.1.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry 1.0.7
2
+ Generator: poetry-core 1.7.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
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,,