mbu-dev-shared-components 2.4.8__tar.gz → 3.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/PKG-INFO +4 -1
  2. mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/database/__init__.py +4 -0
  3. mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/database/connection.py +49 -0
  4. mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/database/constants.py +54 -0
  5. mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/database/logging.py +139 -0
  6. mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/database/utility.py +109 -0
  7. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/document.py +0 -8
  8. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components.egg-info/PKG-INFO +4 -1
  9. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components.egg-info/SOURCES.txt +1 -0
  10. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components.egg-info/requires.txt +3 -0
  11. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/pyproject.toml +4 -5
  12. mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/database/constants.py +0 -131
  13. mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/database/logging.py +0 -86
  14. mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/database/utility.py +0 -44
  15. mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/utils/__init__.py +0 -0
  16. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/LICENSE +0 -0
  17. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/README.md +0 -0
  18. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/database → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/getorganized}/__init__.py +0 -0
  19. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/getorganized/auth.py +0 -0
  20. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/getorganized/cases.py +0 -0
  21. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/getorganized/contacts.py +0 -0
  22. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/getorganized/documents.py +0 -0
  23. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/getorganized/objects.py +0 -0
  24. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/getorganized → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/google}/__init__.py +0 -0
  25. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/google → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/google/api}/__init__.py +0 -0
  26. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/google/api/auth.py +0 -0
  27. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/google/api → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/google/workspace}/__init__.py +0 -0
  28. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/google/workspace/alerts.py +0 -0
  29. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/google/workspace → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/msoffice365}/__init__.py +0 -0
  30. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/msoffice365 → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/msoffice365/excel}/__init__.py +0 -0
  31. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/msoffice365/excel/excel_reader.py +0 -0
  32. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/msoffice365/excel → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/msoffice365/sharepoint_api}/__init__.py +0 -0
  33. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/msoffice365/sharepoint_api/files.py +0 -0
  34. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/msoffice365/sharepoint_api → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/os2forms}/__init__.py +0 -0
  35. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/os2forms/documents.py +0 -0
  36. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/os2forms/forms.py +0 -0
  37. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/os2forms → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/romexis}/__init__.py +0 -0
  38. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/romexis/db_handler.py +0 -0
  39. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/romexis/helper_functions.py +0 -0
  40. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/romexis → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/sap}/__init__.py +0 -0
  41. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/sap/create_invoice.py +0 -0
  42. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/__init__.py +0 -0
  43. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/__init__.py +0 -0
  44. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/app_handler.py +0 -0
  45. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/appointment.py +0 -0
  46. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/base_ui.py +0 -0
  47. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/clinic.py +0 -0
  48. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/edi_portal.py +0 -0
  49. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/event.py +0 -0
  50. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/exceptions.py +0 -0
  51. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/handler_base.py +0 -0
  52. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/journal_note.py +0 -0
  53. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/application/patient.py +0 -0
  54. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/database/__init__.py +0 -0
  55. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/solteqtand/database/db_handler.py +0 -0
  56. {mbu_dev_shared_components-2.4.8/mbu_dev_shared_components/sap → mbu_dev_shared_components-3.0.1/mbu_dev_shared_components/utils}/__init__.py +0 -0
  57. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/utils/db_stored_procedure_executor.py +0 -0
  58. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/utils/fernet_encryptor.py +0 -0
  59. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/utils/file_handler.py +0 -0
  60. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components/utils/json_handler.py +0 -0
  61. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components.egg-info/dependency_links.txt +0 -0
  62. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/mbu_dev_shared_components.egg-info/top_level.txt +0 -0
  63. {mbu_dev_shared_components-2.4.8 → mbu_dev_shared_components-3.0.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mbu_dev_shared_components
3
- Version: 2.4.8
3
+ Version: 3.0.1
4
4
  Summary: Shared components to use in RPA projects
5
5
  Author-email: MBU <rpa@mbu.aarhus.dk>
6
6
  License-Expression: MIT
@@ -22,6 +22,9 @@ Requires-Dist: docx2pdf
22
22
  Requires-Dist: pandas>=2.2.3
23
23
  Requires-Dist: rawpy
24
24
  Provides-Extra: dev
25
+ Requires-Dist: pylint; extra == "dev"
26
+ Requires-Dist: flake8; extra == "dev"
27
+ Requires-Dist: pytest-json-report; extra == "dev"
25
28
  Requires-Dist: pytest>=7.0; extra == "dev"
26
29
  Requires-Dist: pytest-dependency>=0.5.1; extra == "dev"
27
30
  Dynamic: license-file
@@ -0,0 +1,4 @@
1
+ # mbu_dev_shared_components/database/__init__.py
2
+ from .connection import RPAConnection
3
+
4
+ __all__ = ["RPAConnection"]
@@ -0,0 +1,49 @@
1
+ """Handles the RPA connection"""
2
+
3
+ from .constants import Constants
4
+ from .utility import Utility
5
+ from .logging import Log
6
+
7
+
8
+ class RPAConnection(
9
+ Constants,
10
+ Utility,
11
+ Log,
12
+ ):
13
+ """Class for running database related """
14
+ def __init__(self, db_env: str = "PROD", commit: bool | str = False):
15
+ Constants.__init__(self)
16
+ Utility.__init__(self)
17
+ Log.__init__(self)
18
+ self.db_env = db_env
19
+ self.commit = commit if isinstance(commit, bool) else commit == "True"
20
+ self.conn = None
21
+ self.cursor = None
22
+
23
+ def __enter__(self):
24
+ self.conn = self.connect_to_db(autocommit=False, db_env=self.db_env)
25
+ self.cursor = self.conn.cursor()
26
+
27
+ return self
28
+
29
+ def __exit__(self, exc_type, exc_val, exc_tb):
30
+ if self.commit:
31
+ print("Commiting transaction...")
32
+ self.conn.commit()
33
+ else:
34
+ print("Rolling back transaction....")
35
+ self.conn.rollback()
36
+ print("Closing conection...")
37
+ self.close()
38
+ print("Connection closed.")
39
+
40
+ def rollback(self):
41
+ """Rollback transaction on connection if autocommit is not enabled"""
42
+ if self.autocommit:
43
+ raise RuntimeError("Cannot rollback: autocommit is enabled.")
44
+ self.conn.rollback()
45
+
46
+ def close(self):
47
+ """Closes connection"""
48
+ self.cursor.close()
49
+ self.conn.close()
@@ -0,0 +1,54 @@
1
+ """This module handles generating and fetching constants and credentials from the database"""
2
+
3
+ from datetime import datetime
4
+
5
+ from mbu_dev_shared_components.utils.fernet_encryptor import Encryptor
6
+
7
+
8
+ class Constants:
9
+ """Base class for adding and collection constants and credentials"""
10
+
11
+ def add_constant(self, constant_name: str, value: str, changed_at: datetime = datetime.now()):
12
+ query = """
13
+ INSERT INTO [RPA].[rpa].[Constants] ([name], [value], [changed_at])
14
+ VALUES (?, ?, ?)
15
+ """
16
+ self.execute_query(query, [constant_name, value, changed_at])
17
+
18
+ def get_constant(self, constant_name: str) -> dict:
19
+ query = """
20
+ SELECT name, value FROM [RPA].[rpa].[Constants] WHERE name = ?
21
+ """
22
+ res = self.execute_query(query, [constant_name])
23
+ if res:
24
+ name, value = res[0]
25
+ return {"constant_name": name, "value": value}
26
+ raise ValueError(f"No constant found with name: {constant_name}")
27
+
28
+ def add_credential(self, credential_name: str, username: str, password: str,
29
+ changed_at: datetime = datetime.now()):
30
+ encryptor = Encryptor()
31
+ encrypted_password = encryptor.encrypt(password)
32
+ query = """
33
+ INSERT INTO [RPA].[rpa].[Credentials] ([name], [username], [password], [changed_at])
34
+ VALUES (?, ?, ?, ?)
35
+ """
36
+ self.execute_query(query, [credential_name, username, encrypted_password, changed_at])
37
+
38
+ def get_credential(self, credential_name: str) -> dict:
39
+ encryptor = Encryptor()
40
+ query = """
41
+ SELECT username, CAST(password AS varbinary(max))
42
+ FROM [RPA].[rpa].[Credentials]
43
+ WHERE name = ?
44
+ """
45
+ res = self.execute_query(query, [credential_name])
46
+ if res:
47
+ username, encrypted_password = res[0]
48
+ decrypted_password = encryptor.decrypt(encrypted_password)
49
+ return {
50
+ "username": username,
51
+ "decrypted_password": decrypted_password,
52
+ "encrypted_password": encrypted_password
53
+ }
54
+ raise ValueError(f"No credential found with name {credential_name}")
@@ -0,0 +1,139 @@
1
+ """This module handles logging in the RPA database"""
2
+
3
+ from datetime import datetime
4
+ import time
5
+ import socket
6
+
7
+
8
+ class Log:
9
+ """Base class for handling logging"""
10
+ def log_event(
11
+ self,
12
+ log_db: str,
13
+ level: str,
14
+ message: str,
15
+ context: str,
16
+ ):
17
+ """Logs the inputted parameters in """
18
+ created_at = datetime.now()
19
+ query = f"""
20
+ INSERT INTO RPA.{log_db}
21
+ ([level]
22
+ ,[message]
23
+ ,[created_at]
24
+ ,[context])
25
+ VALUES
26
+ (?
27
+ ,?
28
+ ,?
29
+ ,?)
30
+ """
31
+
32
+ params = [level, message, created_at, context]
33
+ self.execute_query(query=query, params=params)
34
+
35
+ def _get_log_event(
36
+ self,
37
+ log_db: str,
38
+ level: str,
39
+ message: str,
40
+ context: str,
41
+ ):
42
+ query = f"""
43
+ SELECT
44
+ ([level]
45
+ ,[message]
46
+ ,[created_at]
47
+ ,[context])
48
+ FROM
49
+ RPA.{log_db}
50
+ WHERE
51
+ level={level},
52
+ message={message},
53
+ context={context}
54
+ """
55
+
56
+ res = self.execute_query(query=query)
57
+ return res
58
+
59
+ def get_latest_log(
60
+ self,
61
+ log_db: str,
62
+ ):
63
+ """Retrieve latest log message from database"""
64
+ query = f"""
65
+ SELECT TOP (1)
66
+ [level]
67
+ ,[message]
68
+ ,[created_at]
69
+ ,[context]
70
+ FROM
71
+ RPA.{log_db}
72
+ ORDER BY
73
+ created_at desc
74
+ """
75
+
76
+ res = self.execute_query(query=query)
77
+ return res
78
+
79
+ def _send_heartbeat(
80
+ self,
81
+ servicename,
82
+ status,
83
+ details
84
+ ):
85
+ """Function to send heartbeat to database"""
86
+ hostname = socket.gethostname()
87
+ params = {
88
+ "ServiceName": (str, servicename),
89
+ "Status": (str, status),
90
+ "HostName": (str, hostname),
91
+ "Details": (str, details)
92
+ }
93
+ result = self.execute_stored_procedure(
94
+ stored_procedure='rpa.sp_UpdateHeartbeat',
95
+ params=params)
96
+ if result["success"] is not True:
97
+ print(result["error_message"])
98
+
99
+ def log_heartbeat(
100
+ self,
101
+ stop: str | bool,
102
+ servicename: str,
103
+ heartbeat_interval: int,
104
+ details: str = "",
105
+ ):
106
+ """Function to log heartbeat"""
107
+ # Update connection such that it autocommits
108
+ self.conn.autocommit = True # Sets class attribute
109
+ if isinstance(stop, str):
110
+ stop = stop == "True"
111
+ if not isinstance(heartbeat_interval, int):
112
+ heartbeat_interval = int(heartbeat_interval)
113
+ while not stop:
114
+ status = "RUNNING"
115
+ self._send_heartbeat(
116
+ servicename,
117
+ status,
118
+ details,
119
+ )
120
+ time.sleep(heartbeat_interval)
121
+ status = "STOPPED"
122
+ self._send_heartbeat(
123
+ servicename,
124
+ status,
125
+ details,
126
+ )
127
+
128
+ def get_heartbeat(self, service_name: str):
129
+ """Get hearbeats """
130
+ query = f"""
131
+ SELECT
132
+ *
133
+ FROM
134
+ [RPA].[rpa].[ServiceHeartbeat]
135
+ WHERE
136
+ ServiceName = '{service_name}'
137
+ """
138
+ res = self.execute_query(query)
139
+ return res
@@ -0,0 +1,109 @@
1
+ """This module handles general database connection and calls"""
2
+
3
+ import os
4
+ import json
5
+ from typing import Dict, Union, Tuple, Any
6
+ from dateutil import parser
7
+ import pyodbc
8
+
9
+
10
+ class Utility:
11
+ """Base class handling general utilities"""
12
+ def connect_to_db(self, autocommit=True, db_env="PROD") -> pyodbc.Connection:
13
+ """Establish connection to sql database
14
+
15
+ Returns:
16
+ rpa_conn (pyodbc.Connection): The connection object to the SQL database.
17
+ """
18
+ connection_env = self.fetch_env(db_env)
19
+ rpa_conn_string = os.getenv(connection_env)
20
+ rpa_conn = pyodbc.connect(rpa_conn_string, autocommit=autocommit)
21
+ return rpa_conn
22
+
23
+ def execute_query(self, query: str, params: list = None) -> pyodbc.Cursor:
24
+ """Execute SQL query with pyodbc"""
25
+ params = [] if not params else params
26
+ is_select = query.strip().upper().startswith('SELECT')
27
+ try:
28
+ res = self.cursor.execute(query, params)
29
+ if is_select:
30
+ res = self.cursor.fetchall()
31
+ if len(res) == 0:
32
+ print("No results from query")
33
+ return None
34
+ return res
35
+ else:
36
+ return None
37
+ except pyodbc.Error as e:
38
+ print(e)
39
+ print(query)
40
+ raise e
41
+
42
+ def fetch_env(self, db_env):
43
+ """Get env variable based on context, PROD or TEST"""
44
+ if db_env.upper() == "PROD":
45
+ connection_env = "DbConnectionString"
46
+ return connection_env
47
+ if db_env.upper() == "TEST":
48
+ connection_env = "DbConnectionStringTest"
49
+ return connection_env
50
+
51
+ raise ValueError(f"arg db_env is {db_env.upper()} but should be 'PROD' or 'TEST'")
52
+
53
+ def execute_stored_procedure(self, stored_procedure: str, params: Dict[str, Tuple[type, Any]] | None = None) -> Dict[str, Union[bool, str, Any]]:
54
+ """
55
+ Executes a stored procedure with the given parameters.
56
+
57
+ Args:
58
+ connection_string (str): The connection string to connect to the database.
59
+ stored_procedure (str): The name of the stored procedure to execute.
60
+ params (Dict[str, Tuple[type, Any]], optional): A dictionary of parameters to pass to the stored procedure.
61
+ Each value should be a tuple of (type, actual_value).
62
+
63
+ Returns:
64
+ Dict[str, Union[bool, str, Any]]: A dictionary containing the success status, an error message (if any),
65
+ number of affected rows, and additional data.
66
+ """
67
+ result = {
68
+ "success": False,
69
+ "error_message": None,
70
+ }
71
+
72
+ type_mapping = {
73
+ "str": str,
74
+ "int": int,
75
+ "float": float,
76
+ "datetime": parser.isoparse,
77
+ "json": lambda x: json.dumps(x, ensure_ascii=False)
78
+ }
79
+
80
+ try:
81
+ if params:
82
+ param_placeholders = ', '.join([f"@{key} = ?" for key in params.keys()])
83
+ param_values = []
84
+
85
+ for key, value in params.items():
86
+ if isinstance(value, tuple) and len(value) == 2:
87
+ value_type, actual_value = value
88
+ if value_type in type_mapping:
89
+ param_values.append(type_mapping[value_type](actual_value))
90
+ else:
91
+ param_values.append(actual_value)
92
+ else:
93
+ raise ValueError("Each parameter value must be a tuple of (type, actual_value).")
94
+
95
+ sql = f"EXEC {stored_procedure} {param_placeholders}"
96
+ rows_updated = self.cursor.execute(sql, tuple(param_values))
97
+ else:
98
+ sql = f"EXEC {stored_procedure}"
99
+ rows_updated = self.cursor.execute(sql)
100
+ result["success"] = True
101
+ result["rows_updated"] = rows_updated.rowcount
102
+ except pyodbc.Error as e:
103
+ result["error_message"] = f"Database error: {str(e)}"
104
+ except ValueError as e:
105
+ result["error_message"] = f"Value error: {str(e)}"
106
+ except Exception as e:
107
+ result["error_message"] = f"An unexpected error occurred: {str(e)}"
108
+
109
+ return result
@@ -126,14 +126,6 @@ class DocumentHandler(HandlerBase):
126
126
  first_booking = controls[0]
127
127
  first_booking.RightClick(simulateMove=False, waitTime=0)
128
128
 
129
- # list_bookings_group = self.wait_for_control(
130
- # auto.GroupControl,
131
- # {'AutomationId': 'GroupBoxView'},
132
- # search_depth=13,
133
- # )
134
- # group_bookings_list = list_bookings_group.GetChildren()[0].GetChildren()[1]
135
- # group_bookings_list.RightClick(simulateMove=False, waitTime=0)
136
-
137
129
  pop_up_right_click_menu = self.wait_for_control(
138
130
  auto.MenuControl,
139
131
  {'Name': 'Kontekst'},
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mbu_dev_shared_components
3
- Version: 2.4.8
3
+ Version: 3.0.1
4
4
  Summary: Shared components to use in RPA projects
5
5
  Author-email: MBU <rpa@mbu.aarhus.dk>
6
6
  License-Expression: MIT
@@ -22,6 +22,9 @@ Requires-Dist: docx2pdf
22
22
  Requires-Dist: pandas>=2.2.3
23
23
  Requires-Dist: rawpy
24
24
  Provides-Extra: dev
25
+ Requires-Dist: pylint; extra == "dev"
26
+ Requires-Dist: flake8; extra == "dev"
27
+ Requires-Dist: pytest-json-report; extra == "dev"
25
28
  Requires-Dist: pytest>=7.0; extra == "dev"
26
29
  Requires-Dist: pytest-dependency>=0.5.1; extra == "dev"
27
30
  Dynamic: license-file
@@ -7,6 +7,7 @@ mbu_dev_shared_components.egg-info/dependency_links.txt
7
7
  mbu_dev_shared_components.egg-info/requires.txt
8
8
  mbu_dev_shared_components.egg-info/top_level.txt
9
9
  mbu_dev_shared_components/database/__init__.py
10
+ mbu_dev_shared_components/database/connection.py
10
11
  mbu_dev_shared_components/database/constants.py
11
12
  mbu_dev_shared_components/database/logging.py
12
13
  mbu_dev_shared_components/database/utility.py
@@ -12,5 +12,8 @@ pandas>=2.2.3
12
12
  rawpy
13
13
 
14
14
  [dev]
15
+ pylint
16
+ flake8
17
+ pytest-json-report
15
18
  pytest>=7.0
16
19
  pytest-dependency>=0.5.1
@@ -2,13 +2,9 @@
2
2
  requires = ["setuptools>=65.0"]
3
3
  build-backend = "setuptools.build_meta"
4
4
 
5
- #[tool.setuptools]
6
- #package-dir = { "" = "." }
7
- #packages = ["mbu_dev_shared_components"]
8
-
9
5
  [project]
10
6
  name = "mbu_dev_shared_components"
11
- version = "2.4.8" # Specify the version manually here
7
+ version = "3.0.1" # Specify the version manually here
12
8
  authors = [
13
9
  { name="MBU", email="rpa@mbu.aarhus.dk" },
14
10
  ]
@@ -37,6 +33,9 @@ dependencies = [
37
33
 
38
34
  [project.optional-dependencies]
39
35
  dev = [
36
+ "pylint",
37
+ "flake8",
38
+ "pytest-json-report",
40
39
  "pytest >= 7.0",
41
40
  "pytest-dependency >= 0.5.1"
42
41
  ]
@@ -1,131 +0,0 @@
1
- """This module handles generating and fetching constants and credentials from the database"""
2
-
3
- import os
4
- import pyodbc
5
- from datetime import datetime
6
-
7
- from mbu_dev_shared_components.utils.fernet_encryptor import Encryptor
8
- from mbu_dev_shared_components.database.utility import connect_to_db, execute_query
9
-
10
-
11
- def add_credential(
12
- credential_name: str,
13
- username: str,
14
- password: str,
15
- changed_at: datetime = datetime.now(),
16
- db_env: str = "PROD"
17
- ):
18
- encryptor = Encryptor()
19
- encrypted_password = encryptor.encrypt(password)
20
-
21
- rpa_conn = connect_to_db(db_env=db_env)
22
- cursor = rpa_conn.cursor()
23
-
24
- query = """
25
- INSERT INTO [RPA].[rpa].[Credentials]
26
- ([name]
27
- ,[username]
28
- ,[password]
29
- ,[changed_at])
30
- VALUES
31
- (?
32
- ,?
33
- ,?
34
- ,?)
35
- """
36
- params = [credential_name, username, encrypted_password, changed_at]
37
- execute_query(query=query, cursor=cursor, params=params)
38
-
39
-
40
- def get_credential(
41
- credential_name: str,
42
- db_env: str = "PROD"
43
- ) -> dict:
44
-
45
- rpa_conn = connect_to_db(db_env=db_env)
46
- cursor = rpa_conn.cursor()
47
- encryptor = Encryptor()
48
-
49
- query = """
50
- SELECT
51
- Username
52
- ,cast(Password as varbinary(max))
53
- FROM [RPA].[rpa].[Credentials]
54
- WHERE
55
- name = ?
56
- """
57
-
58
- params = [credential_name]
59
-
60
- res = execute_query(query=query, cursor=cursor, params=params)
61
- if res is not None:
62
- res = res[0]
63
- username = res[0]
64
- encrypted_password = res[1]
65
-
66
- decrypted_password = encryptor.decrypt(encrypted_password)
67
-
68
- return {
69
- "username": username,
70
- "decrypted_password": decrypted_password,
71
- "encrypted_password": encrypted_password
72
- }
73
- else:
74
- print(f"No credential found with name {credential_name}")
75
-
76
- def get_constant(
77
- constant_name: str,
78
- db_env: str = "PROD"
79
- ) -> tuple:
80
-
81
- rpa_conn = connect_to_db(db_env=db_env)
82
- cursor = rpa_conn.cursor()
83
- encryptor = Encryptor()
84
-
85
- query = """
86
- SELECT
87
- name
88
- ,value
89
- FROM [RPA].[rpa].[Constants]
90
- WHERE
91
- name = ?
92
- """
93
-
94
- params = [constant_name]
95
-
96
- res = execute_query(query=query, cursor=cursor, params=params)
97
- if res is not None:
98
-
99
- returned_constant = res[0]
100
- constant_name = returned_constant[0]
101
- value = returned_constant[1]
102
-
103
- return {"constant_name": constant_name, "value": value}
104
- else:
105
- print(f"No constant found with name: {constant_name}")
106
-
107
-
108
- def add_constant(
109
- constant_name: str,
110
- value: str,
111
- changed_at: datetime = datetime.now(),
112
- db_env: str = "PROD"
113
- ):
114
- query = """
115
- INSERT INTO [RPA].[rpa].[Constants]
116
- ([name]
117
- ,[value]
118
- ,[changed_at])
119
- VALUES
120
- (?
121
- ,?
122
- ,?)
123
- """
124
-
125
- rpa_conn = connect_to_db(db_env=db_env)
126
- cursor = rpa_conn.cursor()
127
-
128
- params = [constant_name, value, changed_at]
129
- execute_query(query=query, cursor=cursor, params=params)
130
-
131
-
@@ -1,86 +0,0 @@
1
- """This module handles logging in the RPA database"""
2
-
3
- from datetime import datetime
4
- import time
5
- import os
6
- import socket
7
-
8
- from mbu_dev_shared_components.database.utility import execute_query, connect_to_db, fetch_env
9
- from mbu_dev_shared_components.utils.db_stored_procedure_executor import execute_stored_procedure
10
-
11
- def log_event(
12
- log_db: str,
13
- level: str,
14
- message: str,
15
- context: str,
16
- db_env="TEST"
17
- ):
18
- created_at = datetime.now()
19
- """Logs the inputted parameters in """
20
- query = f"""
21
- INSERT INTO RPA.{log_db}
22
- ([level]
23
- ,[message]
24
- ,[created_at]
25
- ,[context])
26
- VALUES
27
- (?
28
- ,?
29
- ,?
30
- ,?)
31
- """
32
- rpa_conn = connect_to_db(db_env=db_env)
33
- cursor = rpa_conn.cursor()
34
-
35
- params = [level, message, created_at, context]
36
- execute_query(query=query, cursor=cursor, params=params)
37
-
38
- def _send_heartbeat(
39
- servicename,
40
- status,
41
- details,
42
- db_env,
43
- ):
44
- conn_env = fetch_env(db_env=db_env)
45
- conn_str = os.getenv(conn_env)
46
- hostname = socket.gethostname()
47
- params = {
48
- "ServiceName": (str, servicename),
49
- "Status": (str, status),
50
- "HostName": (str, hostname),
51
- "Details": (str, details)
52
- }
53
- result = execute_stored_procedure(
54
- connection_string=conn_str,
55
- stored_procedure='rpa.sp_UpdateHeartbeat',
56
- params=params)
57
- if result["success"] is not True:
58
- print(result["error_message"])
59
-
60
- def log_heartbeat(
61
- stop: str|bool,
62
- servicename: str,
63
- heartbeat_interval: int,
64
- details: str = "",
65
- db_env: str = "PROD"
66
- ):
67
- if isinstance(stop,str):
68
- stop = stop == "True"
69
- if not isinstance(heartbeat_interval, int):
70
- heartbeat_interval = int(heartbeat_interval)
71
- while not stop:
72
- status = "RUNNING"
73
- _send_heartbeat(
74
- servicename,
75
- status,
76
- details,
77
- db_env,
78
- )
79
- time.sleep(heartbeat_interval)
80
- status = "STOPPED"
81
- _send_heartbeat(
82
- servicename,
83
- status,
84
- details,
85
- db_env,
86
- )
@@ -1,44 +0,0 @@
1
- """This module handles general database connection and calls"""
2
-
3
- import os
4
- import pyodbc
5
- from datetime import datetime
6
-
7
- def connect_to_db(autocommit=True, db_env="PROD") -> pyodbc.Connection:
8
- """Establish connection to sql database
9
-
10
- Returns:
11
- rpa_conn (pyodbc.Connection): The connection object to the SQL database.
12
- """
13
- connection_env = fetch_env(db_env)
14
- rpa_conn_string = os.getenv(connection_env)
15
- rpa_conn = pyodbc.connect(rpa_conn_string, autocommit=autocommit)
16
- return rpa_conn
17
-
18
- def execute_query(query: str, cursor: pyodbc.Cursor, params: list) -> pyodbc.Cursor:
19
- is_select = query.strip().upper().startswith('SELECT')
20
- try:
21
- res = cursor.execute(query, params)
22
- if is_select:
23
- res = cursor.fetchall()
24
- if len(res) == 0:
25
- print("No results from query")
26
- return None
27
- return res
28
- else:
29
- return None
30
- except pyodbc.Error as e:
31
- print(e)
32
- finally:
33
- cursor.close()
34
-
35
-
36
- def fetch_env(db_env):
37
- if db_env.upper() == "PROD":
38
- connection_env = "DbConnectionString"
39
- return connection_env
40
- if db_env.upper() == "TEST":
41
- connection_env = "DbConnectionStringTest"
42
- return connection_env
43
-
44
- raise ValueError(f"arg db_env is {db_env.upper()} but should be 'PROD' or 'TEST'")