bfabric-web-apps 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,,