mbu-dev-shared-components 0.4.2__tar.gz → 0.4.4__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 (46) hide show
  1. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/PKG-INFO +1 -1
  2. mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/database/constants.py +131 -0
  3. mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/database/logging.py +86 -0
  4. mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/database/utility.py +44 -0
  5. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/getorganized/objects.py +8 -1
  6. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/msoffice365/sharepoint_api/files.py +38 -0
  7. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/solteqtand/app_handler.py +2 -2
  8. mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/utils/__init__.py +0 -0
  9. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components.egg-info/PKG-INFO +1 -1
  10. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components.egg-info/SOURCES.txt +4 -0
  11. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/pyproject.toml +1 -1
  12. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/LICENSE +0 -0
  13. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/README.md +0 -0
  14. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/getorganized → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/database}/__init__.py +0 -0
  15. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/google → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/getorganized}/__init__.py +0 -0
  16. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/getorganized/auth.py +0 -0
  17. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/getorganized/cases.py +0 -0
  18. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/getorganized/contacts.py +0 -0
  19. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/getorganized/documents.py +0 -0
  20. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/google/api → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/google}/__init__.py +0 -0
  21. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/google/workspace → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/google/api}/__init__.py +0 -0
  22. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/google/api/auth.py +0 -0
  23. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/msoffice365 → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/google/workspace}/__init__.py +0 -0
  24. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/google/workspace/alerts.py +0 -0
  25. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/msoffice365/excel → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/msoffice365}/__init__.py +0 -0
  26. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/msoffice365/sharepoint_api → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/msoffice365/excel}/__init__.py +0 -0
  27. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/msoffice365/excel/excel_reader.py +0 -0
  28. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/os2forms → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/msoffice365/sharepoint_api}/__init__.py +0 -0
  29. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/romexis → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/os2forms}/__init__.py +0 -0
  30. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/os2forms/documents.py +0 -0
  31. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/os2forms/forms.py +0 -0
  32. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/sap → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/romexis}/__init__.py +0 -0
  33. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/romexis/db_handler.py +0 -0
  34. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/solteqtand → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/sap}/__init__.py +0 -0
  35. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/sap/create_invoice.py +0 -0
  36. {mbu_dev_shared_components-0.4.2/mbu_dev_shared_components/utils → mbu_dev_shared_components-0.4.4/mbu_dev_shared_components/solteqtand}/__init__.py +0 -0
  37. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/solteqtand/db_handler.py +0 -0
  38. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/solteqtand/helper_functions.py +0 -0
  39. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/utils/db_stored_procedure_executor.py +0 -0
  40. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/utils/fernet_encryptor.py +0 -0
  41. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/utils/file_handler.py +0 -0
  42. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components/utils/json_handler.py +0 -0
  43. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components.egg-info/dependency_links.txt +0 -0
  44. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components.egg-info/requires.txt +0 -0
  45. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/mbu_dev_shared_components.egg-info/top_level.txt +0 -0
  46. {mbu_dev_shared_components-0.4.2 → mbu_dev_shared_components-0.4.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mbu_dev_shared_components
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: Shared components to use in RPA projects
5
5
  Author-email: MBU <rpa@mbu.aarhus.dk>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -0,0 +1,131 @@
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
+
@@ -0,0 +1,86 @@
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
+ )
@@ -0,0 +1,44 @@
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'")
@@ -73,7 +73,14 @@ class CaseDataJson:
73
73
  }
74
74
 
75
75
  if case_title is not None:
76
- # Optionally add case_title to your search criteria
76
+ # Change the value of the existing case category to "Standard"
77
+ for field in search_case_folder_data["FieldProperties"]:
78
+ if field["InternalName"] == "ows_CaseCategory":
79
+ field["Value"] = "Standard"
80
+
81
+ break
82
+
83
+ # Optionally add the case title property
77
84
  search_case_folder_data["FieldProperties"].append({
78
85
  "InternalName": "ows_CaseTitle",
79
86
  "Value": case_title,
@@ -35,6 +35,8 @@ import os
35
35
  from office365.runtime.auth.user_credential import UserCredential
36
36
  from office365.sharepoint.client_context import ClientContext
37
37
 
38
+ from office365.sharepoint.files.file import File
39
+
38
40
 
39
41
  class Sharepoint:
40
42
  """
@@ -124,6 +126,22 @@ class Sharepoint:
124
126
  return None
125
127
  return None
126
128
 
129
+ def fetch_file_using_open_binary(self, file_name: str, folder_name: str) -> Optional[bytes]:
130
+ """
131
+ Downloads a file using the open_binary method from SharePoint.
132
+ """
133
+ if self.ctx:
134
+ try:
135
+ file_url = f"/teams/{self.site_name}/{self.document_library}/{folder_name}/{file_name}"
136
+ file_content = File.open_binary(self.ctx, file_url)
137
+ return file_content.content
138
+ except Exception:
139
+ import traceback
140
+ print("Failed to download file:")
141
+ traceback.print_exc()
142
+ return None
143
+ return None
144
+
127
145
  def _write_file(self, folder_destination: str, file_name: str, file_content: bytes):
128
146
  """
129
147
  Saves the binary content of a file to a specified local destination.
@@ -211,3 +229,23 @@ class Sharepoint:
211
229
  self.upload_file(folder_name, file_path, file_name)
212
230
  except Exception as e:
213
231
  print(f"Failed to upload file '{file_path}': {e}")
232
+
233
+ def upload_file_from_bytes(self, binary_content: bytes, file_name: str, folder_name: str):
234
+ """
235
+ Uploads a file to SharePoint directly from a bytes object.
236
+
237
+ Args:
238
+ binary_content (bytes): The binary content of the file.
239
+ file_name (str): The name to give the file in SharePoint.
240
+ folder_name (str): The folder in the document library where the file will be uploaded.
241
+ """
242
+
243
+ if self.ctx:
244
+ try:
245
+ folder_url = f"/teams/{self.site_name}/{self.document_library}/{folder_name}"
246
+ target_folder = self.ctx.web.get_folder_by_server_relative_url(folder_url)
247
+
248
+ target_folder.upload_file(file_name, binary_content).execute_query()
249
+ print(f"File '{file_name}' uploaded successfully to '{folder_url}'.")
250
+ except Exception as e:
251
+ print(f"Failed to upload file '{file_name}': {e}")
@@ -805,7 +805,7 @@ class SolteqTandApp:
805
805
  # End with raise error where resulting dates are printed
806
806
  print("Dates after insert not matching input")
807
807
  print((
808
- f"'From' input: {from_date.strftime(format="%d. %B %Y")} " +
808
+ f"'From' input: {from_date.strftime(format='%d. %B %Y')} " +
809
809
  f"Current value: {dt_picker_from.Name}"))
810
810
 
811
811
  dt_picker_to = self.wait_for_control(
@@ -831,7 +831,7 @@ class SolteqTandApp:
831
831
  except Exception:
832
832
  print("Dates after insert not matching input")
833
833
  print((
834
- f"'To' input: {to_date.strftime(format="%d. %B %Y")} " +
834
+ f"'To' input: {to_date.strftime(format='%d. %B %Y')} " +
835
835
  f"Current value: {dt_picker_to.Name}"))
836
836
 
837
837
  def pick_appointment_types_aftalebog(self, appointment_types: str | list):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mbu_dev_shared_components
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: Shared components to use in RPA projects
5
5
  Author-email: MBU <rpa@mbu.aarhus.dk>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -6,6 +6,10 @@ mbu_dev_shared_components.egg-info/SOURCES.txt
6
6
  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
+ mbu_dev_shared_components/database/__init__.py
10
+ mbu_dev_shared_components/database/constants.py
11
+ mbu_dev_shared_components/database/logging.py
12
+ mbu_dev_shared_components/database/utility.py
9
13
  mbu_dev_shared_components/getorganized/__init__.py
10
14
  mbu_dev_shared_components/getorganized/auth.py
11
15
  mbu_dev_shared_components/getorganized/cases.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mbu_dev_shared_components"
7
- version = "0.4.2" # Specify the version manually here
7
+ version = "0.4.4" # Specify the version manually here
8
8
  authors = [
9
9
  { name="MBU", email="rpa@mbu.aarhus.dk" },
10
10
  ]