mbu-dev-shared-components 0.0.48__tar.gz → 0.0.50__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.
- mbu_dev_shared_components-0.0.50/.github/workflows/pylint.yml +32 -0
- mbu_dev_shared_components-0.0.50/.pylintrc +8 -0
- {mbu_dev_shared_components-0.0.48/mbu_dev_shared_components.egg-info → mbu_dev_shared_components-0.0.50}/PKG-INFO +13 -2
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/README.md +10 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/getorganized/documents.py +32 -1
- mbu_dev_shared_components-0.0.50/mbu_dev_shared_components/office365/sharepoint_api/files.py +159 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/os2forms/documents.py +2 -2
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/sap/create_invoice.py +0 -3
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/utils/db_stored_procedure_executor.py +1 -1
- mbu_dev_shared_components-0.0.50/mbu_dev_shared_components/utils/fernet_encryptor.py +65 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50/mbu_dev_shared_components.egg-info}/PKG-INFO +13 -2
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components.egg-info/SOURCES.txt +3 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components.egg-info/requires.txt +2 -1
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/pyproject.toml +3 -2
- mbu_dev_shared_components-0.0.48/mbu_dev_shared_components/office365/sharepoint_api/files.py +0 -191
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/.gitignore +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/LICENSE +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/getorganized/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/getorganized/auth.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/getorganized/cases.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/getorganized/contacts.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/getorganized/objects.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/google/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/google/api/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/google/api/auth.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/google/workspace/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/google/workspace/alerts.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/office365/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/office365/excel/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/office365/excel/excel_reader.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/office365/sharepoint_api/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/os2forms/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/os2forms/forms.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/sap/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/utils/__init__.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components/utils/json_handler.py +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components.egg-info/dependency_links.txt +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/mbu_dev_shared_components.egg-info/top_level.txt +0 -0
- {mbu_dev_shared_components-0.0.48 → mbu_dev_shared_components-0.0.50}/setup.cfg +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Linting
|
|
2
|
+
|
|
3
|
+
on: [push]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: windows-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
python-version: ["3.11"]
|
|
11
|
+
fail-fast: false
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v3
|
|
14
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
15
|
+
uses: actions/setup-python@v3
|
|
16
|
+
with:
|
|
17
|
+
python-version: ${{ matrix.python-version }}
|
|
18
|
+
|
|
19
|
+
- name: Install dependencies
|
|
20
|
+
run: |
|
|
21
|
+
python -m pip install --upgrade pip
|
|
22
|
+
pip install pylint
|
|
23
|
+
pip install flake8
|
|
24
|
+
pip install .
|
|
25
|
+
|
|
26
|
+
- name: Analysing the code with pylint
|
|
27
|
+
run: |
|
|
28
|
+
pylint --rcfile=.pylintrc $(git ls-files '*.py')
|
|
29
|
+
|
|
30
|
+
- name: Analysing the code with flake8
|
|
31
|
+
run: |
|
|
32
|
+
flake8 --extend-ignore=E501,E251 $(git ls-files '*.py')
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
[pylint.messages_control]
|
|
2
|
+
disable =
|
|
3
|
+
C0301, # Line too long
|
|
4
|
+
I1101, E1101, # C-modules members
|
|
5
|
+
R0913, # Too many arguments
|
|
6
|
+
R0914, # Too many local variables
|
|
7
|
+
W0718, # Catching too general exception Exception (broad-exception-caught)
|
|
8
|
+
R0903, # Too few public methods
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mbu_dev_shared_components
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.50
|
|
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
|
|
@@ -9,11 +9,12 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
9
9
|
Requires-Python: >=3.7
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: shareplum
|
|
13
13
|
Requires-Dist: openpyxl>=3.1.2
|
|
14
14
|
Requires-Dist: pyodbc>=5.1.0
|
|
15
15
|
Requires-Dist: requests_ntlm>=1.2.0
|
|
16
16
|
Requires-Dist: python-dateutil==2.9.*
|
|
17
|
+
Requires-Dist: cryptography>=43.0.0
|
|
17
18
|
|
|
18
19
|
# mbu-dev-shared-components
|
|
19
20
|
|
|
@@ -75,3 +76,13 @@ converting lists associated with keys in a JSON object into dictionaries.
|
|
|
75
76
|
|
|
76
77
|
- Transform all lists
|
|
77
78
|
- Insert key value pairs
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
#### - Fernet Encryptor
|
|
82
|
+
This module provides a class for encrypting and decrypting data using the
|
|
83
|
+
Fernet symmetric encryption algorithm.
|
|
84
|
+
|
|
85
|
+
- Encrypts
|
|
86
|
+
- Decrypts
|
|
87
|
+
|
|
88
|
+
|
|
@@ -58,3 +58,13 @@ converting lists associated with keys in a JSON object into dictionaries.
|
|
|
58
58
|
|
|
59
59
|
- Transform all lists
|
|
60
60
|
- Insert key value pairs
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
#### - Fernet Encryptor
|
|
64
|
+
This module provides a class for encrypting and decrypting data using the
|
|
65
|
+
Fernet symmetric encryption algorithm.
|
|
66
|
+
|
|
67
|
+
- Encrypts
|
|
68
|
+
- Decrypts
|
|
69
|
+
|
|
70
|
+
|
|
@@ -46,7 +46,38 @@ def mark_file_as_case_record(documents_id: list, api_endpoint: str, api_username
|
|
|
46
46
|
"""
|
|
47
47
|
headers = {'Content-Type': 'application/json'}
|
|
48
48
|
payload = {"DocumentIds": documents_id}
|
|
49
|
-
|
|
49
|
+
|
|
50
|
+
response = requests.request(method='POST', url=api_endpoint, headers=headers, json=payload, auth=get_ntlm_go_api_credentials(api_username, api_password), timeout=60)
|
|
51
|
+
response.raise_for_status()
|
|
52
|
+
|
|
53
|
+
return response
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def finalize_file(documents_id: list, api_endpoint: str, api_username: str, api_password: str) -> requests.Response:
|
|
57
|
+
"""
|
|
58
|
+
Marks one or more documents by their IDs as finalized in the system via a POST request to a specific API endpoint.
|
|
59
|
+
This operation modifies the status of the documents to reflect their new role as finalized case records.
|
|
60
|
+
The function constructs the JSON payload by encapsulating the document IDs within a list under the 'DocumentIds' key.
|
|
61
|
+
|
|
62
|
+
Parameters:
|
|
63
|
+
documents_id (list): A list of integers representing document IDs that should be marked as case records.
|
|
64
|
+
api_endpoint (str): GetOrganized API endpoint.
|
|
65
|
+
api_username (str): The API username for GetOrganized API.
|
|
66
|
+
api_password (str): The API password for GetOrganized API.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
Dict[str, Any]: The JSON response from the API, which includes the status of the operation and potentially updated document details.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
requests.RequestException: If the HTTP request fails for any reason.
|
|
73
|
+
"""
|
|
74
|
+
headers = {'Content-Type': 'application/json'}
|
|
75
|
+
payload = {
|
|
76
|
+
"DocumentIds": documents_id,
|
|
77
|
+
"ShouldCloseOpenTasks": False
|
|
78
|
+
}
|
|
79
|
+
|
|
50
80
|
response = requests.request(method='POST', url=api_endpoint, headers=headers, json=payload, auth=get_ntlm_go_api_credentials(api_username, api_password), timeout=60)
|
|
81
|
+
response.raise_for_status()
|
|
51
82
|
|
|
52
83
|
return response
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines a Sharepoint class that facilitates interactions with a SharePoint site.
|
|
3
|
+
It provides methods for authenticating with the site, listing files in a specified document
|
|
4
|
+
library folder, downloading files, and saving them to a local directory. The class is designed
|
|
5
|
+
to encapsulate all necessary functionalities for handling files on a SharePoint site, making it
|
|
6
|
+
suitable for scripts or applications that require automated access to SharePoint resources.
|
|
7
|
+
|
|
8
|
+
The Sharepoint class uses the SharePlum library to communicate with SharePoint, handling common
|
|
9
|
+
tasks such as authentication, file retrieval, and file management. This includes methods to
|
|
10
|
+
authenticate users, fetch file lists from specific library folders, download individual files,
|
|
11
|
+
and save them locally. The class is initialized with user credentials and site details, which
|
|
12
|
+
are used throughout the class to manage SharePoint interactions.
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
After creating an instance of the Sharepoint class with the necessary credentials and site details,
|
|
16
|
+
users can call methods to list files in a folder, download a specific file, or retrieve and save
|
|
17
|
+
all files from a folder to a local directory. This makes it easy to integrate SharePoint file
|
|
18
|
+
management into automated workflows or systems.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
sharepoint_details = {
|
|
22
|
+
"username": "john@do.e",
|
|
23
|
+
"password": "johndoe",
|
|
24
|
+
"site_url": "https://site_url",
|
|
25
|
+
"site_name": "department123",
|
|
26
|
+
"document_library": "Shared documents"
|
|
27
|
+
}
|
|
28
|
+
sp = Sharepoint(**sharepoint_details)
|
|
29
|
+
sp.download_files("FolderName", "C:\\LocalPath")
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from pathlib import PurePath
|
|
33
|
+
from typing import Optional
|
|
34
|
+
from shareplum import Site, Office365
|
|
35
|
+
from shareplum.site import Version
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class Sharepoint:
|
|
39
|
+
"""
|
|
40
|
+
A class to interact with a SharePoint site, enabling authentication, file listing,
|
|
41
|
+
downloading, and saving functionalities within a specified SharePoint document library.
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
username (str): Username for authentication.
|
|
45
|
+
password (str): Password for authentication.
|
|
46
|
+
site_url (str): URL of the SharePoint site.
|
|
47
|
+
site_name (str): Name of the SharePoint site.
|
|
48
|
+
document_library (str): Document library path.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, username: str, password: str, site_url: str, site_name: str, document_library: str):
|
|
52
|
+
"""Initializes the Sharepoint class with credentials and site details."""
|
|
53
|
+
self.username = username
|
|
54
|
+
self.password = password
|
|
55
|
+
self.site_url = site_url
|
|
56
|
+
self.site_name = site_name
|
|
57
|
+
self.document_library = document_library
|
|
58
|
+
self.site = self._auth()
|
|
59
|
+
|
|
60
|
+
def _auth(self) -> Optional[Site]:
|
|
61
|
+
"""
|
|
62
|
+
Authenticates to the SharePoint site and returns the site object.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Optional[Site]: A SharePlum Site object for interacting with the SharePoint site if authentication is successful,
|
|
66
|
+
otherwise None.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
authcookie = Office365(self.site_url, username=self.username, password=self.password).GetCookies()
|
|
70
|
+
site = Site(f'{self.site_url}/sites/{self.site_name}', version=Version.v365, authcookie=authcookie)
|
|
71
|
+
return site
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f"Failed to authenticate: {e}")
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
def fetch_files_list(self, folder_name: str) -> Optional[list]:
|
|
77
|
+
"""
|
|
78
|
+
Retrieves a list of files from a specified folder within the document library.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
folder_name (str): The name of the folder within the document library.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
list: A list of file dictionaries in the specified folder, or an empty list if an error occurs or if the site is not authenticated.
|
|
85
|
+
"""
|
|
86
|
+
if self.site:
|
|
87
|
+
try:
|
|
88
|
+
folder = self.site.Folder(f'{self.document_library}/{folder_name}')
|
|
89
|
+
files = folder.files
|
|
90
|
+
return files
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print(f"Error retrieving files: {e}")
|
|
93
|
+
return None
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
def fetch_file_content(self, file_name: str, folder_name: str) -> Optional[bytes]:
|
|
97
|
+
"""
|
|
98
|
+
Downloads a file from a specified folder within the document library.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
file_name (str): The name of the file to be downloaded.
|
|
102
|
+
folder_name (str): The name of the folder where the file is located.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
bytes (Optional): The binary content of the file if successful, otherwise None.
|
|
106
|
+
"""
|
|
107
|
+
if self.site:
|
|
108
|
+
try:
|
|
109
|
+
folder = self.site.Folder(f'{self.document_library}/{folder_name}')
|
|
110
|
+
file_content = folder.get_file(file_name)
|
|
111
|
+
return file_content
|
|
112
|
+
except Exception as e:
|
|
113
|
+
print(f"Failed to download file: {e}")
|
|
114
|
+
return None
|
|
115
|
+
return None
|
|
116
|
+
|
|
117
|
+
def _write_file(self, folder_destination: str, file_name: str, file_content: bytes):
|
|
118
|
+
"""
|
|
119
|
+
Saves the binary content of a file to a specified local destination.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
folder_destination (str): The local folder path where the file will be saved.
|
|
123
|
+
file_name (str): The name of the file to be saved.
|
|
124
|
+
file_content (bytes): The binary content of the file.
|
|
125
|
+
"""
|
|
126
|
+
file_directory_path = PurePath(folder_destination, file_name)
|
|
127
|
+
with open(file_directory_path, 'wb') as file:
|
|
128
|
+
file.write(file_content)
|
|
129
|
+
|
|
130
|
+
def download_file(self, folder: str, filename: str, folder_destination: str):
|
|
131
|
+
"""
|
|
132
|
+
Downloads a specified file from a specified folder and saves it to a local destination.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
folder (str): The name of the folder in the document library containing the file.
|
|
136
|
+
filename (str): The name of the file to download.
|
|
137
|
+
folder_destination (str): The local folder path where the downloaded file will be saved.
|
|
138
|
+
"""
|
|
139
|
+
file_content = self.fetch_file_content(filename, folder)
|
|
140
|
+
if file_content:
|
|
141
|
+
self._write_file(folder_destination, filename, file_content)
|
|
142
|
+
else:
|
|
143
|
+
print(f"Failed to download {filename}")
|
|
144
|
+
|
|
145
|
+
def download_files(self, folder: str, folder_destination: str):
|
|
146
|
+
"""
|
|
147
|
+
Downloads all files from a specified folder and saves them to a local destination.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
folder (str): The name of the folder in the document library containing the files.
|
|
151
|
+
folder_destination (str): The local folder path where the downloaded files will be saved.
|
|
152
|
+
"""
|
|
153
|
+
files_list = self.fetch_files_list(folder)
|
|
154
|
+
for file in files_list:
|
|
155
|
+
file_content = self.fetch_file_content(file['Name'], folder)
|
|
156
|
+
if file_content:
|
|
157
|
+
self._write_file(folder_destination, file['Name'], file_content)
|
|
158
|
+
else:
|
|
159
|
+
print(f"Failed to download {file['Name']}")
|
|
@@ -17,8 +17,8 @@ def download_file_bytes(url: str, os2_api_key: str) -> bytes:
|
|
|
17
17
|
requests.RequestException: If the HTTP request fails for any reason.
|
|
18
18
|
"""
|
|
19
19
|
headers = {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
'Content-Type': 'application/json',
|
|
21
|
+
'api-key': f'{os2_api_key}'
|
|
22
22
|
}
|
|
23
23
|
response = requests.request(method='GET', url=url, headers=headers, timeout=60)
|
|
24
24
|
response.raise_for_status()
|
|
@@ -100,7 +100,6 @@ class InvoiceCreator:
|
|
|
100
100
|
name_person: str,
|
|
101
101
|
start_date: str,
|
|
102
102
|
end_date: str,
|
|
103
|
-
institution_number: str,
|
|
104
103
|
main_transaction_id: str,
|
|
105
104
|
main_transaction_amount: str,
|
|
106
105
|
sub_transaction_id: str,
|
|
@@ -128,8 +127,6 @@ class InvoiceCreator:
|
|
|
128
127
|
Start date of the transaction period.
|
|
129
128
|
end_date : str
|
|
130
129
|
End date of the transaction period.
|
|
131
|
-
institution_number : str
|
|
132
|
-
Institution number.
|
|
133
130
|
main_transaction_id : str
|
|
134
131
|
ID of the main transaction.
|
|
135
132
|
main_transaction_amount : str
|
|
@@ -32,7 +32,7 @@ def execute_stored_procedure(connection_string: str, stored_procedure: str, para
|
|
|
32
32
|
"str": str,
|
|
33
33
|
"int": int,
|
|
34
34
|
"float": float,
|
|
35
|
-
"datetime":
|
|
35
|
+
"datetime": parser.isoparse,
|
|
36
36
|
"json": lambda x: json.dumps(x, ensure_ascii=False)
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides a class for encrypting and decrypting data using the
|
|
3
|
+
Fernet symmetric encryption algorithm.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import base64
|
|
8
|
+
import hashlib
|
|
9
|
+
from cryptography.fernet import Fernet
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Encryptor:
|
|
13
|
+
"""
|
|
14
|
+
A class for encrypting and decrypting data using the Fernet symmetric encryption algorithm.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.key = os.getenv("OpenOrchestratorKey")
|
|
19
|
+
if not self.key:
|
|
20
|
+
raise ValueError("Environment variable 'OpenOrchestratorKey' is not set or is empty.")
|
|
21
|
+
self.cipher_suite = self.generate_cipher_suite()
|
|
22
|
+
|
|
23
|
+
def generate_cipher_suite(self) -> Fernet:
|
|
24
|
+
"""
|
|
25
|
+
Generates a Fernet cipher suite using a SHA-256 hash of the provided key.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Fernet: An instance of the Fernet cipher suite.
|
|
29
|
+
"""
|
|
30
|
+
hashed_key = hashlib.sha256(self.key.encode()).digest()
|
|
31
|
+
base64_key = base64.urlsafe_b64encode(hashed_key[:32])
|
|
32
|
+
return Fernet(base64_key)
|
|
33
|
+
|
|
34
|
+
def encrypt(self, data: str) -> bytes:
|
|
35
|
+
"""
|
|
36
|
+
Encrypts a string.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
data (str): The string to be encrypted.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
bytes: The encrypted data.
|
|
43
|
+
"""
|
|
44
|
+
if not isinstance(data, str):
|
|
45
|
+
raise TypeError("Data must be a string.")
|
|
46
|
+
encrypted_data = self.cipher_suite.encrypt(data.encode())
|
|
47
|
+
return encrypted_data
|
|
48
|
+
|
|
49
|
+
def decrypt(self, cipherdata: bytes) -> str:
|
|
50
|
+
"""
|
|
51
|
+
Decrypts data that was encrypted.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
cipherdata (bytes): The data to be decrypted.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
str: The decrypted plaintext string.
|
|
58
|
+
"""
|
|
59
|
+
if not isinstance(cipherdata, bytes):
|
|
60
|
+
raise TypeError("Cipherdata must be bytes.")
|
|
61
|
+
try:
|
|
62
|
+
decrypted_data = self.cipher_suite.decrypt(cipherdata).decode()
|
|
63
|
+
return decrypted_data
|
|
64
|
+
except Exception as e:
|
|
65
|
+
raise ValueError("Decryption failed. Ensure the cipherdata is valid.") from e
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mbu_dev_shared_components
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.50
|
|
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
|
|
@@ -9,11 +9,12 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
9
9
|
Requires-Python: >=3.7
|
|
10
10
|
Description-Content-Type: text/markdown
|
|
11
11
|
License-File: LICENSE
|
|
12
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: shareplum
|
|
13
13
|
Requires-Dist: openpyxl>=3.1.2
|
|
14
14
|
Requires-Dist: pyodbc>=5.1.0
|
|
15
15
|
Requires-Dist: requests_ntlm>=1.2.0
|
|
16
16
|
Requires-Dist: python-dateutil==2.9.*
|
|
17
|
+
Requires-Dist: cryptography>=43.0.0
|
|
17
18
|
|
|
18
19
|
# mbu-dev-shared-components
|
|
19
20
|
|
|
@@ -75,3 +76,13 @@ converting lists associated with keys in a JSON object into dictionaries.
|
|
|
75
76
|
|
|
76
77
|
- Transform all lists
|
|
77
78
|
- Insert key value pairs
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
#### - Fernet Encryptor
|
|
82
|
+
This module provides a class for encrypting and decrypting data using the
|
|
83
|
+
Fernet symmetric encryption algorithm.
|
|
84
|
+
|
|
85
|
+
- Encrypts
|
|
86
|
+
- Decrypts
|
|
87
|
+
|
|
88
|
+
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
.gitignore
|
|
2
|
+
.pylintrc
|
|
2
3
|
LICENSE
|
|
3
4
|
README.md
|
|
4
5
|
pyproject.toml
|
|
6
|
+
.github/workflows/pylint.yml
|
|
5
7
|
mbu_dev_shared_components.egg-info/PKG-INFO
|
|
6
8
|
mbu_dev_shared_components.egg-info/SOURCES.txt
|
|
7
9
|
mbu_dev_shared_components.egg-info/dependency_links.txt
|
|
@@ -30,4 +32,5 @@ mbu_dev_shared_components/sap/__init__.py
|
|
|
30
32
|
mbu_dev_shared_components/sap/create_invoice.py
|
|
31
33
|
mbu_dev_shared_components/utils/__init__.py
|
|
32
34
|
mbu_dev_shared_components/utils/db_stored_procedure_executor.py
|
|
35
|
+
mbu_dev_shared_components/utils/fernet_encryptor.py
|
|
33
36
|
mbu_dev_shared_components/utils/json_handler.py
|
|
@@ -17,11 +17,12 @@ classifiers = [
|
|
|
17
17
|
"Operating System :: Microsoft :: Windows",
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
|
-
"
|
|
20
|
+
"shareplum",
|
|
21
21
|
"openpyxl >= 3.1.2",
|
|
22
22
|
"pyodbc >= 5.1.0",
|
|
23
23
|
"requests_ntlm >= 1.2.0",
|
|
24
|
-
"python-dateutil == 2.9.*"
|
|
24
|
+
"python-dateutil == 2.9.*",
|
|
25
|
+
"cryptography >= 43.0.0"
|
|
25
26
|
]
|
|
26
27
|
|
|
27
28
|
[tool.setuptools_scm]
|
mbu_dev_shared_components-0.0.48/mbu_dev_shared_components/office365/sharepoint_api/files.py
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
"""This module defines a Sharepoint class that facilitates interactions with a SharePoint site.
|
|
2
|
-
It provides methods for authenticating with the site, listing files in a specified document
|
|
3
|
-
library folder, downloading files, and saving them to a local directory. The class is designed
|
|
4
|
-
to encapsulate all necessary functionalities for handling files on a SharePoint site, making it
|
|
5
|
-
suitable for scripts or applications that require automated access to SharePoint resources.
|
|
6
|
-
|
|
7
|
-
The Sharepoint class uses the Office365-REST-Python-Client library to communicate with SharePoint,
|
|
8
|
-
handling common tasks such as authentication, file retrieval, and file management. This includes
|
|
9
|
-
methods to authenticate users, fetch file lists from specific library folders, download individual
|
|
10
|
-
files, and save them locally. The class is initialized with user credentials and site details, which
|
|
11
|
-
are used throughout the class to manage SharePoint interactions.
|
|
12
|
-
|
|
13
|
-
Usage:
|
|
14
|
-
After creating an instance of the Sharepoint class with the necessary credentials and site details,
|
|
15
|
-
users can call methods to list files in a folder, download a specific file, or retrieve and save
|
|
16
|
-
all files from a folder to a local directory. This makes it easy to integrate SharePoint file
|
|
17
|
-
management into automated workflows or systems.
|
|
18
|
-
|
|
19
|
-
Example:
|
|
20
|
-
sharepoint_details = {
|
|
21
|
-
"username": "john@do.e",
|
|
22
|
-
"password": "johndoe",
|
|
23
|
-
"site_url": "https://site_url",
|
|
24
|
-
"site_name": "department123",
|
|
25
|
-
"document_library": "Shared documents"
|
|
26
|
-
}
|
|
27
|
-
sp = Sharepoint(**sharepoint_details)
|
|
28
|
-
sp.get_files(sp, "FolderName", "C:\\LocalPath")
|
|
29
|
-
|
|
30
|
-
This module requires the `office365.sharepoint.client_context`, `office365.runtime.auth.user_credential`,
|
|
31
|
-
and `office365.sharepoint.files.file` modules from Office365-REST-Python-Client.
|
|
32
|
-
"""
|
|
33
|
-
from pathlib import PurePath
|
|
34
|
-
from office365.sharepoint.client_context import ClientContext
|
|
35
|
-
from office365.runtime.auth.user_credential import UserCredential
|
|
36
|
-
from office365.sharepoint.files.file import File
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class Sharepoint:
|
|
40
|
-
"""
|
|
41
|
-
A class to interact with a SharePoint site, enabling authentication, file listing,
|
|
42
|
-
downloading, and saving functionalities within a specified SharePoint document library.
|
|
43
|
-
|
|
44
|
-
Attributes:
|
|
45
|
-
username (str): Username for authentication.
|
|
46
|
-
password (str): Password for authentication.
|
|
47
|
-
site_url (str): URL of the SharePoint site.
|
|
48
|
-
site_name (str): Name of the site.
|
|
49
|
-
document_library (str): Document library path.
|
|
50
|
-
"""
|
|
51
|
-
def __init__(self, username: str, password, site_url, site_name, document_library):
|
|
52
|
-
"""Initializes the Sharepoint class with credentials and site details.
|
|
53
|
-
"""
|
|
54
|
-
self.username = username
|
|
55
|
-
self.password = password
|
|
56
|
-
self.site_url = site_url
|
|
57
|
-
self.site_name = site_name
|
|
58
|
-
self.document_library = document_library
|
|
59
|
-
|
|
60
|
-
def _auth(self):
|
|
61
|
-
"""
|
|
62
|
-
Authenticates to the SharePoint site and returns the client context.
|
|
63
|
-
"""
|
|
64
|
-
try:
|
|
65
|
-
conn = ClientContext(self.site_url).with_credentials(
|
|
66
|
-
UserCredential(self.username, self.password)
|
|
67
|
-
)
|
|
68
|
-
return conn
|
|
69
|
-
except Exception as e:
|
|
70
|
-
print(f"Failed to authenticate: {e}")
|
|
71
|
-
return None
|
|
72
|
-
|
|
73
|
-
def fetch_files_list(self, folder_name: str) -> list:
|
|
74
|
-
"""
|
|
75
|
-
Retrieve a list of files from a specified folder within the document library.
|
|
76
|
-
|
|
77
|
-
This method authenticates the user and constructs the URL to the target folder using
|
|
78
|
-
the document library and folder name. It then attempts to retrieve and return the list
|
|
79
|
-
of files in the folder. If any errors occur during the process, an error message is
|
|
80
|
-
printed and an empty list is returned.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
folder_name (str): The name of the folder within the document library from which to retrieve files.
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
list: A list of file objects in the specified folder if the retrieval is successful, otherwise an empty list.
|
|
87
|
-
"""
|
|
88
|
-
conn = self._auth()
|
|
89
|
-
if conn:
|
|
90
|
-
try:
|
|
91
|
-
target_folder_url = f'{self.document_library}/{folder_name}'
|
|
92
|
-
root_folder = conn.web.get_folder_by_server_relative_url(target_folder_url)
|
|
93
|
-
root_folder.expand(["Files", "Folders"]).get().execute_query()
|
|
94
|
-
return root_folder.files
|
|
95
|
-
except Exception as e:
|
|
96
|
-
print(f"Error retrieving files: {e}")
|
|
97
|
-
return []
|
|
98
|
-
return []
|
|
99
|
-
|
|
100
|
-
def fetch_file_content(self, file_name: str, folder_name: str) -> bytes:
|
|
101
|
-
"""
|
|
102
|
-
Download a file from a specified folder within the document library of the current site.
|
|
103
|
-
|
|
104
|
-
This method authenticates the user, constructs the URL to the file using the site name,
|
|
105
|
-
document library, folder name, and file name. It then attempts to open and download
|
|
106
|
-
the file as binary. If successful, the binary content of the file is returned. If
|
|
107
|
-
any errors occur during the download process, an error message is printed and the
|
|
108
|
-
method returns None.
|
|
109
|
-
|
|
110
|
-
Args:
|
|
111
|
-
file_name (str): The name of the file to be downloaded.
|
|
112
|
-
folder_name (str): The folder name where the file is stored.
|
|
113
|
-
|
|
114
|
-
Returns:
|
|
115
|
-
bytes: The binary content of the file if the download is successful, otherwise None.
|
|
116
|
-
"""
|
|
117
|
-
conn = self._auth()
|
|
118
|
-
if conn:
|
|
119
|
-
try:
|
|
120
|
-
file_url = f'/sites/{self.site_name}/{self.document_library}/{folder_name}/{file_name}'
|
|
121
|
-
file_binary = File.open_binary(conn, file_url)
|
|
122
|
-
return file_binary.content
|
|
123
|
-
except Exception as e:
|
|
124
|
-
print(f"Failed to download file: {e}")
|
|
125
|
-
return None
|
|
126
|
-
|
|
127
|
-
def _write_file(self, folder_destination: str, file_name: str, file_content: bytes) -> None:
|
|
128
|
-
"""
|
|
129
|
-
Save the binary content of a file to a specified local destination.
|
|
130
|
-
|
|
131
|
-
This method takes the binary content of a file and writes it to a file in the specified
|
|
132
|
-
local destination folder. The full path to the file is constructed using the destination
|
|
133
|
-
folder and the file name.
|
|
134
|
-
|
|
135
|
-
Args:
|
|
136
|
-
folder_destination (str): The local folder path where the file will be saved.
|
|
137
|
-
file_name (str): The name of the file to be saved.
|
|
138
|
-
file_content (bytes): The binary content of the file to be written to disk.
|
|
139
|
-
|
|
140
|
-
Returns:
|
|
141
|
-
None
|
|
142
|
-
"""
|
|
143
|
-
file_directory_path = PurePath(folder_destination, file_name)
|
|
144
|
-
with open(file_directory_path, 'wb') as file:
|
|
145
|
-
file.write(file_content)
|
|
146
|
-
|
|
147
|
-
def download_file(self, folder: str, filename: str, folder_destination: str) -> None:
|
|
148
|
-
"""
|
|
149
|
-
Download a specified file from a specified folder and save it to a local destination.
|
|
150
|
-
|
|
151
|
-
This method retrieves the specified file from the folder in the document library,
|
|
152
|
-
attempts to download it, and saves it to the specified local destination folder.
|
|
153
|
-
If the file cannot be downloaded, an error message is printed.
|
|
154
|
-
|
|
155
|
-
Args:
|
|
156
|
-
folder (str): The name of the folder in the document library from which to download the file.
|
|
157
|
-
filename (str): The name of the file to download.
|
|
158
|
-
folder_destination (str): The local folder path where the downloaded file will be saved.
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
None
|
|
162
|
-
"""
|
|
163
|
-
file_content = self.fetch_file_content(filename, folder)
|
|
164
|
-
if file_content:
|
|
165
|
-
self._write_file(folder_destination, filename, file_content)
|
|
166
|
-
else:
|
|
167
|
-
print(f"Failed to download {filename}")
|
|
168
|
-
|
|
169
|
-
def download_files(self, folder: str, folder_destination: str) -> None:
|
|
170
|
-
"""
|
|
171
|
-
Download all files from a specified folder and save them to a local destination.
|
|
172
|
-
|
|
173
|
-
This method retrieves a list of files from the specified folder in the document library,
|
|
174
|
-
attempts to download each file, and saves it to the specified local destination folder.
|
|
175
|
-
If a file cannot be downloaded, an error message is printed, but the process continues
|
|
176
|
-
with the next file.
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
folder (str): The name of the folder in the document library from which to download files.
|
|
180
|
-
folder_destination (str): The local folder path where the downloaded files will be saved.
|
|
181
|
-
|
|
182
|
-
Returns:
|
|
183
|
-
None
|
|
184
|
-
"""
|
|
185
|
-
files_list = self.fetch_files_list(folder)
|
|
186
|
-
for file in files_list:
|
|
187
|
-
file_content = self.fetch_file_content(file.name, folder)
|
|
188
|
-
if file_content:
|
|
189
|
-
self._write_file(folder_destination, file.name, file_content)
|
|
190
|
-
else:
|
|
191
|
-
print(f"Failed to download {file.name}")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|