sharepoint-v1-api 0.2.2__tar.gz → 0.2.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.
- sharepoint_v1_api-0.2.4/CHANGELOG.md +53 -0
- {sharepoint_v1_api-0.2.2/sharepoint_v1_api.egg-info → sharepoint_v1_api-0.2.4}/PKG-INFO +27 -3
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/setup.py +1 -1
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointAPI.py +123 -82
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointList.py +2 -2
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointListItem.py +22 -22
- sharepoint_v1_api-0.2.4/sharepoint_api/SharePointSite.py +188 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointTimeRegistration.py +6 -6
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/__init__.py +3 -2
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4/sharepoint_v1_api.egg-info}/PKG-INFO +27 -3
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_v1_api.egg-info/SOURCES.txt +1 -0
- sharepoint_v1_api-0.2.2/CHANGELOG.md +0 -29
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/AGENTS.md +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/LICENSE +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/MANIFEST.in +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/README.md +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/pyproject.toml +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/setup.cfg +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointLists.py +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointUser.py +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointUserList.py +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_v1_api.egg-info/dependency_links.txt +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_v1_api.egg-info/requires.txt +0 -0
- {sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_v1_api.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
## 0.2.4 – 2025-12-03
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- New high‑level `SharePointSite` object providing lazy‑loaded site metadata
|
|
6
|
+
|
|
7
|
+
## 0.2.3 – 2025-12-02
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- GUID validation for list identifiers with fallback to list title lookup via `GetByTitle`.
|
|
12
|
+
- New helper method `_is_valid_guid` in `SharePointAPI`.
|
|
13
|
+
- Centralized list resolution helper `_resolve_sp_list` for GUID, title, or `SharePointList` instances.
|
|
14
|
+
- New method `get_list_metadata` to fetch only list metadata without items.
|
|
15
|
+
- Type hint enhancements: added `Optional`, `Tuple` imports; updated method signatures (e.g., `get_item_versions` now uses `Optional[List[str]]`).
|
|
16
|
+
- Updated `get_list` to return the resolved `SharePointList` object after appending items.
|
|
17
|
+
- Refactored multiple methods (`get_item`, `create_item`, `update_item`, `attach_file`, `get_item_versions`, `get_case`) to use `_resolve_sp_list`, removing redundant GUID validation logic.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Cleaned up stray `else:` blocks and syntax errors.
|
|
22
|
+
- Improved consistency of return objects across list-related methods.
|
|
23
|
+
- Updated imports and docstrings accordingly.
|
|
24
|
+
|
|
25
|
+
## 0.2.2 – 2025-11-28
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `SharePointList.fields` property to retrieve list field definitions
|
|
30
|
+
|
|
31
|
+
## 0.2.1 – 2025-11-06
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Optional `select_fields` parameters to list retrieval methods for more efficient queries.
|
|
36
|
+
- New public API methods:
|
|
37
|
+
- `SharePointAPI.get_group_users` – fetch users of a SharePoint group.
|
|
38
|
+
- Improved error handling with explicit `TypeError` exceptions.
|
|
39
|
+
- Detailed docstrings for core classes and methods (enhances IDE support).
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- HTTP header handling unified; corrected `X-HTTP-Method: PUT` for full updates.
|
|
44
|
+
- Error handling improved: generic `sys.exit(1)` replaced with explicit `TypeError`/`ConnectionError` exceptions.
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
|
|
48
|
+
- Fixed incorrect PUT header that previously sent a MERGE header.
|
|
49
|
+
- Minor docstring formatting issues.
|
|
50
|
+
|
|
51
|
+
### Security
|
|
52
|
+
|
|
53
|
+
- Enforced NTLM authentication across all request helpers.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sharepoint_v1_api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Author: Aske Bluhme Klok
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: Sharepoint
|
|
@@ -156,13 +156,37 @@ for v in versions:
|
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
|
|
159
|
+
## 0.2.4 – 2025-12-03
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
|
|
163
|
+
- New high‑level `SharePointSite` object providing lazy‑loaded site metadata
|
|
164
|
+
|
|
165
|
+
## 0.2.3 – 2025-12-02
|
|
166
|
+
|
|
167
|
+
### Added
|
|
168
|
+
|
|
169
|
+
- GUID validation for list identifiers with fallback to list title lookup via `GetByTitle`.
|
|
170
|
+
- New helper method `_is_valid_guid` in `SharePointAPI`.
|
|
171
|
+
- Centralized list resolution helper `_resolve_sp_list` for GUID, title, or `SharePointList` instances.
|
|
172
|
+
- New method `get_list_metadata` to fetch only list metadata without items.
|
|
173
|
+
- Type hint enhancements: added `Optional`, `Tuple` imports; updated method signatures (e.g., `get_item_versions` now uses `Optional[List[str]]`).
|
|
174
|
+
- Updated `get_list` to return the resolved `SharePointList` object after appending items.
|
|
175
|
+
- Refactored multiple methods (`get_item`, `create_item`, `update_item`, `attach_file`, `get_item_versions`, `get_case`) to use `_resolve_sp_list`, removing redundant GUID validation logic.
|
|
176
|
+
|
|
177
|
+
### Changed
|
|
178
|
+
|
|
179
|
+
- Cleaned up stray `else:` blocks and syntax errors.
|
|
180
|
+
- Improved consistency of return objects across list-related methods.
|
|
181
|
+
- Updated imports and docstrings accordingly.
|
|
182
|
+
|
|
159
183
|
## 0.2.2 – 2025-11-28
|
|
160
184
|
|
|
161
185
|
### Added
|
|
162
186
|
|
|
163
187
|
- `SharePointList.fields` property to retrieve list field definitions
|
|
164
188
|
|
|
165
|
-
## 0.2.1 – 2025
|
|
189
|
+
## 0.2.1 – 2025-11-06
|
|
166
190
|
|
|
167
191
|
### Added
|
|
168
192
|
|
|
@@ -174,7 +198,7 @@ for v in versions:
|
|
|
174
198
|
|
|
175
199
|
### Changed
|
|
176
200
|
|
|
177
|
-
- HTTP header handling unified; corrected `X
|
|
201
|
+
- HTTP header handling unified; corrected `X-HTTP-Method: PUT` for full updates.
|
|
178
202
|
- Error handling improved: generic `sys.exit(1)` replaced with explicit `TypeError`/`ConnectionError` exceptions.
|
|
179
203
|
|
|
180
204
|
### Fixed
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
import os
|
|
3
|
-
import getpass
|
|
4
2
|
import json
|
|
3
|
+
from datetime import timezone
|
|
5
4
|
import requests
|
|
6
5
|
from requests_ntlm import HttpNtlmAuth
|
|
7
|
-
from typing import List
|
|
6
|
+
from typing import List, Optional, Tuple
|
|
7
|
+
import re
|
|
8
8
|
|
|
9
9
|
from .SharePointUser import SharePointUser
|
|
10
10
|
from .SharePointUserList import SharePointUserList
|
|
11
11
|
from .SharePointListItem import SharePointListItem, SharepointSiteCase
|
|
12
12
|
from .SharePointList import SharePointList, CasesList, TimeRegistrationList
|
|
13
13
|
from .SharePointLists import SharePointLists
|
|
14
|
+
from .SharePointSite import SharePointSite
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class SharePointAPI:
|
|
17
|
-
"""High
|
|
18
|
+
"""High-level client for interacting with SharePoint sites.
|
|
18
19
|
|
|
19
20
|
Provides methods for authentication, list management, file operations,
|
|
20
|
-
and time
|
|
21
|
+
and time-registration handling. All public interactions should be performed
|
|
21
22
|
through an instance created via :meth:`_compact_init`.
|
|
22
23
|
"""
|
|
23
24
|
|
|
@@ -35,7 +36,7 @@ class SharePointAPI:
|
|
|
35
36
|
Returns
|
|
36
37
|
-------
|
|
37
38
|
SharePointAPI
|
|
38
|
-
A fully
|
|
39
|
+
A fully-initialised ``SharePointAPI`` object ready for use.
|
|
39
40
|
|
|
40
41
|
Notes
|
|
41
42
|
-----
|
|
@@ -68,6 +69,43 @@ class SharePointAPI:
|
|
|
68
69
|
self.password = password
|
|
69
70
|
self.sharepoint_url = sharepoint_url
|
|
70
71
|
self.proxies = proxies
|
|
72
|
+
self.timezone = timezone.utc
|
|
73
|
+
|
|
74
|
+
def _is_valid_guid(self, guid: str) -> bool:
|
|
75
|
+
"""Validate that a string is a proper GUID."""
|
|
76
|
+
pattern = r'^[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$'
|
|
77
|
+
return bool(re.fullmatch(pattern, guid))
|
|
78
|
+
|
|
79
|
+
def _resolve_sp_list(self, sharepoint_site: str, sp_list, SPListType: SharePointList = SharePointList) -> Tuple[str, Optional[SharePointList]]:
|
|
80
|
+
"""
|
|
81
|
+
Resolve ``sp_list`` (GUID, title or ``SharePointList`` instance) to a GUID
|
|
82
|
+
and, when possible, a ``SharePointList`` object.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
tuple
|
|
87
|
+
(guid: str, list_obj: SharePointList | None)
|
|
88
|
+
"""
|
|
89
|
+
# Case 1: already a SharePointList instance
|
|
90
|
+
if isinstance(sp_list, SharePointList):
|
|
91
|
+
return sp_list.guid, sp_list
|
|
92
|
+
|
|
93
|
+
# Case 2: string – could be GUID or title
|
|
94
|
+
if isinstance(sp_list, str):
|
|
95
|
+
if self._is_valid_guid(sp_list):
|
|
96
|
+
guid = sp_list
|
|
97
|
+
# Fetch minimal list metadata to build a SharePointList object
|
|
98
|
+
r = self._api_get_call(
|
|
99
|
+
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')')
|
|
100
|
+
list_obj = SPListType(self, sharepoint_site, r.json()["d"])
|
|
101
|
+
return guid, list_obj
|
|
102
|
+
# Assume title – resolve via GetByTitle
|
|
103
|
+
list_obj = self.get_list_by_name(
|
|
104
|
+
sharepoint_site, sp_list, SPListType=SPListType)
|
|
105
|
+
return list_obj.guid, list_obj
|
|
106
|
+
|
|
107
|
+
raise TypeError(
|
|
108
|
+
'Invalid sp_list argument; expected SharePointList or str')
|
|
71
109
|
|
|
72
110
|
def _handle_response(self, response: requests.Response, success_codes: List[int]) -> requests.Response:
|
|
73
111
|
"""
|
|
@@ -140,7 +178,7 @@ class SharePointAPI:
|
|
|
140
178
|
Perform a POST request against the SharePoint REST API.
|
|
141
179
|
|
|
142
180
|
Enhanced error handling:
|
|
143
|
-
* Network
|
|
181
|
+
* Network-level errors (timeouts, DNS failures, etc.) are caught and re-raised as
|
|
144
182
|
``ConnectionError`` with a helpful message.
|
|
145
183
|
* HTTP error codes are reported with status, URL and response body when available.
|
|
146
184
|
* The method always returns a ``requests.Response`` on success (status 200, 201 or 204).
|
|
@@ -150,7 +188,7 @@ class SharePointAPI:
|
|
|
150
188
|
url : str
|
|
151
189
|
The full endpoint URL.
|
|
152
190
|
post_data : dict
|
|
153
|
-
JSON
|
|
191
|
+
JSON-serialisable payload to send.
|
|
154
192
|
form_digest_value : str | None, optional
|
|
155
193
|
FormDigest required for POST/PUT/MERGE operations.
|
|
156
194
|
merge : bool, optional
|
|
@@ -201,7 +239,7 @@ class SharePointAPI:
|
|
|
201
239
|
Perform a PUT request against the SharePoint REST API.
|
|
202
240
|
|
|
203
241
|
Enhanced error handling:
|
|
204
|
-
* Network
|
|
242
|
+
* Network-level errors (timeouts, DNS failures, etc.) are caught and re-raised as
|
|
205
243
|
``ConnectionError`` with a helpful message.
|
|
206
244
|
* HTTP error codes are reported with status, URL and response body when available.
|
|
207
245
|
* The method always returns a ``requests.Response`` on success (status 200, 201 or 204).
|
|
@@ -211,7 +249,7 @@ class SharePointAPI:
|
|
|
211
249
|
url : str
|
|
212
250
|
The full endpoint URL.
|
|
213
251
|
put_data : dict
|
|
214
|
-
JSON
|
|
252
|
+
JSON-serialisable payload to send.
|
|
215
253
|
form_digest_value : str | None, optional
|
|
216
254
|
FormDigest required for POST/PUT/MERGE operations.
|
|
217
255
|
merge : bool, optional
|
|
@@ -258,10 +296,10 @@ class SharePointAPI:
|
|
|
258
296
|
def _api_attachment_call(self, url: str, post_data: bytes | None = None, form_digest_value: str | None = None,
|
|
259
297
|
overwrite: bool = False, x_http_method: str | None = None) -> requests.Response:
|
|
260
298
|
"""
|
|
261
|
-
Perform an attachment
|
|
299
|
+
Perform an attachment-related request (POST, PUT, DELETE) against the SharePoint REST API.
|
|
262
300
|
|
|
263
301
|
Enhanced error handling:
|
|
264
|
-
* Network
|
|
302
|
+
* Network-level errors (timeouts, DNS failures, etc.) are caught and re-raised as
|
|
265
303
|
``ConnectionError`` with a helpful message.
|
|
266
304
|
* HTTP error codes are reported with status, URL and response body when available.
|
|
267
305
|
* The method always returns a ``requests.Response`` on success (status 200 or 204).
|
|
@@ -286,7 +324,7 @@ class SharePointAPI:
|
|
|
286
324
|
'X-RequestDigest': f'{form_digest_value}'
|
|
287
325
|
}
|
|
288
326
|
|
|
289
|
-
# Determine effective X
|
|
327
|
+
# Determine effective X-HTTP-Method
|
|
290
328
|
if overwrite:
|
|
291
329
|
headers['X-HTTP-Method'] = "PUT"
|
|
292
330
|
if x_http_method:
|
|
@@ -300,7 +338,7 @@ class SharePointAPI:
|
|
|
300
338
|
raise ConnectionError(
|
|
301
339
|
f'Unsupported X-HTTP-Method: {x_http_method}')
|
|
302
340
|
|
|
303
|
-
# Add Content
|
|
341
|
+
# Add Content-Length when payload present
|
|
304
342
|
if post_data is not None:
|
|
305
343
|
headers['Content-Length'] = str(len(post_data))
|
|
306
344
|
|
|
@@ -328,7 +366,7 @@ class SharePointAPI:
|
|
|
328
366
|
Perform a GET request against the SharePoint REST API.
|
|
329
367
|
|
|
330
368
|
Enhanced error handling:
|
|
331
|
-
* Network
|
|
369
|
+
* Network-level errors (timeouts, DNS failures, etc.) are caught and re-raised as
|
|
332
370
|
``ConnectionError`` with a helpful message.
|
|
333
371
|
* HTTP error codes are reported with status, URL and response body when available.
|
|
334
372
|
* The method always returns a ``requests.Response`` on success (status 200).
|
|
@@ -425,7 +463,7 @@ class SharePointAPI:
|
|
|
425
463
|
Returns
|
|
426
464
|
-------
|
|
427
465
|
SharePointUserList
|
|
428
|
-
A list
|
|
466
|
+
A list-like container with :class:`SharePointUser` objects for each member.
|
|
429
467
|
"""
|
|
430
468
|
# Build the request URL for the group's users.
|
|
431
469
|
# SharePoint REST endpoint: /_api/web/sitegroups/GetByName('<group_name>')/users
|
|
@@ -466,7 +504,7 @@ class SharePointAPI:
|
|
|
466
504
|
for user_settings in r.json()["d"]["results"]
|
|
467
505
|
]
|
|
468
506
|
|
|
469
|
-
# Return a ``SharePointUserList`` (consistent with other user
|
|
507
|
+
# Return a ``SharePointUserList`` (consistent with other user-retrieval methods).
|
|
470
508
|
return SharePointUserList(sharepoint_site, users)
|
|
471
509
|
|
|
472
510
|
def get_user(self, sharepoint_site, user_id, select_fields=None):
|
|
@@ -517,6 +555,40 @@ class SharePointAPI:
|
|
|
517
555
|
|
|
518
556
|
return SharePointLists(_lists)
|
|
519
557
|
|
|
558
|
+
def get_site_metadata(self, sharepoint_site: str) -> dict:
|
|
559
|
+
"""
|
|
560
|
+
Retrieve metadata of a SharePoint site.
|
|
561
|
+
|
|
562
|
+
Parameters
|
|
563
|
+
----------
|
|
564
|
+
sharepoint_site : str
|
|
565
|
+
Identifier of the SharePoint site (e.g., 'mySite').
|
|
566
|
+
|
|
567
|
+
Returns
|
|
568
|
+
-------
|
|
569
|
+
dict
|
|
570
|
+
Dictionary containing the site's metadata as returned by the SharePoint REST API.
|
|
571
|
+
"""
|
|
572
|
+
r = self._api_get_call(
|
|
573
|
+
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web')
|
|
574
|
+
return r.json()["d"]
|
|
575
|
+
|
|
576
|
+
def get_site(self, sharepoint_site: str) -> SharePointSite:
|
|
577
|
+
"""
|
|
578
|
+
Return a :class:`SharePointSite` object representing the given site.
|
|
579
|
+
|
|
580
|
+
Parameters
|
|
581
|
+
----------
|
|
582
|
+
sharepoint_site : str
|
|
583
|
+
Identifier of the SharePoint site (e.g., ``'mySite'``).
|
|
584
|
+
|
|
585
|
+
Returns
|
|
586
|
+
-------
|
|
587
|
+
SharePointSite
|
|
588
|
+
A high-level wrapper around site-wide operations.
|
|
589
|
+
"""
|
|
590
|
+
return SharePointSite(self, sharepoint_site)
|
|
591
|
+
|
|
520
592
|
def get_list(self, sharepoint_site, sp_list, filters=None, top=1000, view_path=None, select_fields=None, SPListType: SharePointList = SharePointList) -> SharePointList:
|
|
521
593
|
'''
|
|
522
594
|
Returns a list from a given sharepoint_site using its guid
|
|
@@ -530,21 +602,9 @@ class SharePointAPI:
|
|
|
530
602
|
returned for each list item via the ``$select`` OData query option.
|
|
531
603
|
'''
|
|
532
604
|
|
|
533
|
-
#
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
r = self._api_get_call(
|
|
537
|
-
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')')
|
|
538
|
-
sp_list = SPListType(self, sharepoint_site, r.json()["d"])
|
|
539
|
-
|
|
540
|
-
elif isinstance(sp_list, str):
|
|
541
|
-
guid = sp_list
|
|
542
|
-
r = self._api_get_call(
|
|
543
|
-
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')')
|
|
544
|
-
sp_list = SPListType(self, sharepoint_site, r.json()["d"])
|
|
545
|
-
else:
|
|
546
|
-
raise TypeError(
|
|
547
|
-
'Invalid sp_list argument; expected SharePointList or str')
|
|
605
|
+
# Resolve sp_list to GUID and (optionally) a SharePointList object
|
|
606
|
+
guid, sp_list_obj = self._resolve_sp_list(
|
|
607
|
+
sharepoint_site, sp_list, SPListType=SPListType)
|
|
548
608
|
|
|
549
609
|
arguments = []
|
|
550
610
|
|
|
@@ -578,8 +638,8 @@ class SharePointAPI:
|
|
|
578
638
|
|
|
579
639
|
items = [SPListType.SPItem(self, sharepoint_site, guid, item_settings)
|
|
580
640
|
for item_settings in r.json()["d"]["results"]]
|
|
581
|
-
|
|
582
|
-
return
|
|
641
|
+
sp_list_obj.append_items(items)
|
|
642
|
+
return sp_list_obj
|
|
583
643
|
|
|
584
644
|
def get_list_by_name(self, sharepoint_site, sp_list_name: str, filters=None, top=1000, view_path=None, select_fields=None, SPListType: SharePointList = SharePointList) -> SharePointList:
|
|
585
645
|
'''
|
|
@@ -668,6 +728,21 @@ class SharePointAPI:
|
|
|
668
728
|
|
|
669
729
|
# SP Item
|
|
670
730
|
|
|
731
|
+
def get_list_metadata(self, sharepoint_site, sp_list, SPListType: SharePointList = SharePointList) -> SharePointList:
|
|
732
|
+
"""
|
|
733
|
+
Retrieve only the metadata of a SharePoint list without fetching its items.
|
|
734
|
+
Useful when only list properties (e.g., title, guid) are needed.
|
|
735
|
+
"""
|
|
736
|
+
guid, list_obj = self._resolve_sp_list(
|
|
737
|
+
sharepoint_site, sp_list, SPListType=SPListType)
|
|
738
|
+
# If the list object was already resolved (e.g., via title lookup), reuse it.
|
|
739
|
+
if list_obj is not None:
|
|
740
|
+
return list_obj
|
|
741
|
+
# Otherwise, fetch minimal metadata using the GUID.
|
|
742
|
+
r = self._api_get_call(
|
|
743
|
+
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')')
|
|
744
|
+
return SPListType(self, sharepoint_site, r.json()["d"])
|
|
745
|
+
|
|
671
746
|
def get_item(self, sharepoint_site, sp_list, item_id, select_fields=None) -> SharePointListItem:
|
|
672
747
|
'''
|
|
673
748
|
Returns a single list item from a given sharepoint_site.
|
|
@@ -675,14 +750,8 @@ class SharePointAPI:
|
|
|
675
750
|
returned via the ``$select`` OData query option.
|
|
676
751
|
'''
|
|
677
752
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
elif isinstance(sp_list, str):
|
|
682
|
-
guid = sp_list
|
|
683
|
-
else:
|
|
684
|
-
raise TypeError(
|
|
685
|
-
'Invalid sp_list argument; expected SharePointList or str')
|
|
753
|
+
# Resolve sp_list to GUID (and list object if needed)
|
|
754
|
+
guid, _ = self._resolve_sp_list(sharepoint_site, sp_list)
|
|
686
755
|
|
|
687
756
|
# Build the request URL, adding $select if needed.
|
|
688
757
|
if select_fields is not None:
|
|
@@ -701,14 +770,8 @@ class SharePointAPI:
|
|
|
701
770
|
|
|
702
771
|
def create_item(self, sharepoint_site, sp_list, data) -> SharePointListItem:
|
|
703
772
|
# Uses either guid or SharePointList
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
elif isinstance(sp_list, str):
|
|
707
|
-
guid = sp_list
|
|
708
|
-
r = self._api_get_call(
|
|
709
|
-
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')')
|
|
710
|
-
sp_list = SharePointList(self,
|
|
711
|
-
sharepoint_site, r.json()["d"]["results"][0])
|
|
773
|
+
# Resolve sp_list to GUID (and list object if needed)
|
|
774
|
+
guid, _ = self._resolve_sp_list(sharepoint_site, sp_list)
|
|
712
775
|
|
|
713
776
|
r = self._api_post_call(
|
|
714
777
|
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/contextinfo', {})
|
|
@@ -731,13 +794,8 @@ class SharePointAPI:
|
|
|
731
794
|
item_id: The id of the item
|
|
732
795
|
data: Data to push to the item
|
|
733
796
|
'''
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
elif isinstance(sp_list, str):
|
|
737
|
-
guid = sp_list
|
|
738
|
-
else:
|
|
739
|
-
raise TypeError(
|
|
740
|
-
'Only "SharePointList" and "str" types are allowed')
|
|
797
|
+
# Resolve sp_list to GUID (and list object if needed)
|
|
798
|
+
guid, _ = self._resolve_sp_list(sharepoint_site, sp_list)
|
|
741
799
|
|
|
742
800
|
r = self._api_post_call(
|
|
743
801
|
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/contextinfo', {})
|
|
@@ -752,13 +810,8 @@ class SharePointAPI:
|
|
|
752
810
|
|
|
753
811
|
def attach_file(self, sharepoint_site, sp_list, item, file_name, file_content) -> dict:
|
|
754
812
|
# Uses either guid or SharePointList
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
elif isinstance(sp_list, str):
|
|
758
|
-
guid = sp_list
|
|
759
|
-
else:
|
|
760
|
-
raise TypeError(
|
|
761
|
-
'Only "SharePointList" and "str" types are allowed')
|
|
813
|
+
# Resolve sp_list to GUID (and list object if needed)
|
|
814
|
+
guid, _ = self._resolve_sp_list(sharepoint_site, sp_list)
|
|
762
815
|
|
|
763
816
|
r = self._api_post_call(
|
|
764
817
|
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/contextinfo', {})
|
|
@@ -766,23 +819,17 @@ class SharePointAPI:
|
|
|
766
819
|
)["d"]["GetContextWebInformation"]["FormDigestValue"]
|
|
767
820
|
|
|
768
821
|
r = self._api_attachment_call(
|
|
769
|
-
f"{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')/items({item.Id})/AttachmentFiles/
|
|
822
|
+
f"{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')/items({item.Id})/AttachmentFiles/add(FileName='{file_name}')", file_content, form_digest_value)
|
|
770
823
|
|
|
771
824
|
return r.json()
|
|
772
825
|
|
|
773
|
-
def get_item_versions(self, sharepoint_site, sp_list, item_id, select_fields
|
|
826
|
+
def get_item_versions(self, sharepoint_site, sp_list, item_id, select_fields: Optional[List[str]] = None) -> list:
|
|
774
827
|
'''
|
|
775
828
|
Returns a list of users from a given sharepoint_site
|
|
776
829
|
'''
|
|
777
830
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
elif isinstance(sp_list, str):
|
|
782
|
-
guid = sp_list
|
|
783
|
-
else:
|
|
784
|
-
raise TypeError(
|
|
785
|
-
'Invalid sp_list argument; expected SharePointList or str')
|
|
831
|
+
# Resolve sp_list to GUID (and list object if needed)
|
|
832
|
+
guid, _ = self._resolve_sp_list(sharepoint_site, sp_list)
|
|
786
833
|
|
|
787
834
|
if select_fields:
|
|
788
835
|
r = self._api_get_call(
|
|
@@ -836,14 +883,8 @@ class SharePointAPI:
|
|
|
836
883
|
Returns a list of users from a given sharepoint_site
|
|
837
884
|
'''
|
|
838
885
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
elif isinstance(sp_list, str):
|
|
843
|
-
guid = sp_list
|
|
844
|
-
else:
|
|
845
|
-
raise TypeError(
|
|
846
|
-
'Invalid sp_list argument; expected SharePointList or str')
|
|
886
|
+
# Resolve sp_list to GUID (and list object if needed)
|
|
887
|
+
guid, _ = self._resolve_sp_list(sharepoint_site, sp_list)
|
|
847
888
|
|
|
848
889
|
r = self._api_get_call(
|
|
849
890
|
f'{self.sharepoint_url}/cases/{sharepoint_site}/_api/Web/Lists(guid\'{guid}\')/items({item_id})')
|
|
@@ -12,7 +12,7 @@ class SharePointList:
|
|
|
12
12
|
Provides common functionality for handling list items, including
|
|
13
13
|
retrieval, addition, and serialization to JSON. Subclasses such as
|
|
14
14
|
:class:`CasesList` and :class:`TimeRegistrationList` extend this
|
|
15
|
-
class with domain
|
|
15
|
+
class with domain-specific behavior.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
settings = None
|
|
@@ -194,7 +194,7 @@ class CasesList(SharePointList):
|
|
|
194
194
|
|
|
195
195
|
class TimeRegistrationList(SharePointList):
|
|
196
196
|
"""
|
|
197
|
-
Specialized list for time
|
|
197
|
+
Specialized list for time-registration entries.
|
|
198
198
|
|
|
199
199
|
Inherits from :class:`SharePointList` and sets ``SPItem`` to the
|
|
200
200
|
:class:`TimeRegistration` class.
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
# from .SharePointAPI import SharePointAPI as SP
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
class SharePointListItem:
|
|
5
6
|
"""
|
|
6
7
|
Represents a generic item in a SharePoint list.
|
|
7
8
|
|
|
8
9
|
Provides access to common fields such as ``Id``, ``Title``, ``Created`` and
|
|
9
10
|
``Modified`` and handles lazy loading of related list data and version
|
|
10
|
-
history. Sub
|
|
11
|
-
:class:`TimeRegistration`) extend this base with domain
|
|
11
|
+
history. Sub-classes (e.g. :class:`SharepointSiteCase` or
|
|
12
|
+
:class:`TimeRegistration`) extend this base with domain-specific properties.
|
|
12
13
|
"""
|
|
13
14
|
'''
|
|
14
15
|
'''
|
|
@@ -34,12 +35,12 @@ class SharePointListItem:
|
|
|
34
35
|
@property
|
|
35
36
|
def versions(self) -> list:
|
|
36
37
|
if not self._versions:
|
|
37
|
-
self._versions = self.sp.get_item_versions(
|
|
38
|
+
self._versions = self.sp.get_item_versions(
|
|
39
|
+
self.sharepoint_site, self.list_guid, self.Id)
|
|
38
40
|
if self._list is not None:
|
|
39
41
|
self._list.CHANGE_DETECTED = True
|
|
40
|
-
return self._versions
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
return self._versions
|
|
43
|
+
|
|
43
44
|
@property
|
|
44
45
|
def Id(self) -> str:
|
|
45
46
|
"""Unique identifier of the list item."""
|
|
@@ -62,7 +63,7 @@ class SharePointListItem:
|
|
|
62
63
|
elif self.settings['Created'] is None:
|
|
63
64
|
return None
|
|
64
65
|
else:
|
|
65
|
-
return datetime.strptime(self.settings['Created'], '%Y-%m-%dT%H:%M:%SZ')
|
|
66
|
+
return datetime.strptime(self.settings['Created'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
66
67
|
|
|
67
68
|
@property
|
|
68
69
|
def Modified(self) -> datetime:
|
|
@@ -76,39 +77,41 @@ class SharePointListItem:
|
|
|
76
77
|
elif self.settings['Modified'] is None:
|
|
77
78
|
return None
|
|
78
79
|
else:
|
|
79
|
-
return datetime.strptime(self.settings['Modified'], '%Y-%m-%dT%H:%M:%SZ')
|
|
80
|
+
return datetime.strptime(self.settings['Modified'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
80
81
|
|
|
81
82
|
def attach_item(self, file_name, file_path):
|
|
82
83
|
"""
|
|
83
84
|
Attach a file to this list item.
|
|
84
|
-
|
|
85
|
+
|
|
85
86
|
Parameters
|
|
86
87
|
----------
|
|
87
88
|
file_name : str
|
|
88
89
|
The name of the file as it should appear in SharePoint.
|
|
89
90
|
file_path : str
|
|
90
91
|
Local path to the file to be uploaded.
|
|
91
|
-
|
|
92
|
+
|
|
92
93
|
The method reads the file content and uses :meth:`SharePointAPI.attach_file`
|
|
93
94
|
to upload it to the corresponding SharePoint list item.
|
|
94
95
|
"""
|
|
95
96
|
with open(file_path, 'r') as f:
|
|
96
97
|
file_content = f.read()
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
self.sp.attach_file(self.sharepoint_site, self.list,
|
|
100
|
+
self, file_name, file_content)
|
|
100
101
|
|
|
101
102
|
def versions_select_fields(self, select_fields=[]) -> list:
|
|
102
103
|
if not self._versions:
|
|
103
|
-
self._versions = self.sp.get_item_versions(
|
|
104
|
+
self._versions = self.sp.get_item_versions(
|
|
105
|
+
self.sharepoint_site, self.list_guid, self.Id, select_fields)
|
|
104
106
|
return self._versions
|
|
105
107
|
|
|
106
108
|
def update_fields(self, data):
|
|
107
109
|
self.sp.update_item(self.sharepoint_site,
|
|
108
110
|
self.list_guid, self.Id, data)
|
|
109
111
|
|
|
112
|
+
|
|
110
113
|
class SharepointSiteCase(SharePointListItem):
|
|
111
|
-
|
|
114
|
+
|
|
112
115
|
@property
|
|
113
116
|
def AssignmentType(self) -> str:
|
|
114
117
|
return self.settings['AssignmentType']
|
|
@@ -121,7 +124,7 @@ class SharepointSiteCase(SharePointListItem):
|
|
|
121
124
|
elif self.settings['CaseClosed'] is None:
|
|
122
125
|
return None
|
|
123
126
|
else:
|
|
124
|
-
return datetime.strptime(self.settings['CaseClosed'], '%Y-%m-%dT%H:%M:%SZ')
|
|
127
|
+
return datetime.strptime(self.settings['CaseClosed'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
125
128
|
|
|
126
129
|
@property
|
|
127
130
|
def Due(self) -> datetime:
|
|
@@ -131,7 +134,7 @@ class SharepointSiteCase(SharePointListItem):
|
|
|
131
134
|
elif self.settings['DueDate'] is None:
|
|
132
135
|
return None
|
|
133
136
|
else:
|
|
134
|
-
return datetime.strptime(self.settings['DueDate'], '%Y-%m-%dT%H:%M:%SZ')
|
|
137
|
+
return datetime.strptime(self.settings['DueDate'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
135
138
|
|
|
136
139
|
@property
|
|
137
140
|
def Priority(self) -> str:
|
|
@@ -156,7 +159,7 @@ class SharepointSiteCase(SharePointListItem):
|
|
|
156
159
|
solved_in_time = True
|
|
157
160
|
else:
|
|
158
161
|
solved_in_time = True
|
|
159
|
-
|
|
162
|
+
|
|
160
163
|
return solved_in_time
|
|
161
164
|
|
|
162
165
|
@property
|
|
@@ -167,7 +170,7 @@ class SharepointSiteCase(SharePointListItem):
|
|
|
167
170
|
elif self.settings['WorkBegun'] is None:
|
|
168
171
|
return None
|
|
169
172
|
else:
|
|
170
|
-
return datetime.strptime(self.settings['WorkBegun'], '%Y-%m-%dT%H:%M:%SZ')
|
|
173
|
+
return datetime.strptime(self.settings['WorkBegun'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
171
174
|
|
|
172
175
|
@property
|
|
173
176
|
def DeadlineWorkTimestamp(self) -> datetime:
|
|
@@ -177,7 +180,7 @@ class SharepointSiteCase(SharePointListItem):
|
|
|
177
180
|
elif self.settings['DeadlineWork'] is None:
|
|
178
181
|
return None
|
|
179
182
|
else:
|
|
180
|
-
return datetime.strptime(self.settings['DeadlineWork'], '%Y-%m-%dT%H:%M:%SZ')
|
|
183
|
+
return datetime.strptime(self.settings['DeadlineWork'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
181
184
|
|
|
182
185
|
@property
|
|
183
186
|
def ReactedInTime(self) -> bool:
|
|
@@ -191,6 +194,3 @@ class SharepointSiteCase(SharePointListItem):
|
|
|
191
194
|
else:
|
|
192
195
|
reacted_in_time = True
|
|
193
196
|
return reacted_in_time
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provides a high-level ``SharePointSite`` object that encapsulates site-wide
|
|
3
|
+
metadata and offers convenience wrappers around common ``SharePointAPI``
|
|
4
|
+
operations such as retrieving lists, users, and groups.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
|
|
10
|
+
from typing import List, Optional
|
|
11
|
+
import locale
|
|
12
|
+
|
|
13
|
+
from typing import TYPE_CHECKING
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
# Imported only for type checking to avoid circular imports at runtime
|
|
17
|
+
from .SharePointAPI import SharePointAPI
|
|
18
|
+
from .SharePointList import SharePointList
|
|
19
|
+
from .SharePointLists import SharePointLists
|
|
20
|
+
from .SharePointUser import SharePointUser
|
|
21
|
+
from .SharePointUserList import SharePointUserList
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SharePointSite:
|
|
25
|
+
"""
|
|
26
|
+
High-level representation of a SharePoint site.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
api : SharePointAPI
|
|
31
|
+
The low-level client used for HTTP calls.
|
|
32
|
+
site_id : str
|
|
33
|
+
Identifier of the SharePoint site (e.g. ``"mySite"``).
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, api: "SharePointAPI", site_id: str):
|
|
37
|
+
self._api = api
|
|
38
|
+
self.site_id = site_id
|
|
39
|
+
self._metadata: Optional[dict] = None
|
|
40
|
+
|
|
41
|
+
# -----------------------------------------------------------------
|
|
42
|
+
# Internal helpers
|
|
43
|
+
# -----------------------------------------------------------------
|
|
44
|
+
def _ensure_metadata(self) -> dict:
|
|
45
|
+
"""Fetch site metadata on first use and cache it."""
|
|
46
|
+
if self._metadata is None:
|
|
47
|
+
self._metadata = self._api.get_site_metadata(self.site_id)
|
|
48
|
+
return self._metadata
|
|
49
|
+
|
|
50
|
+
# -----------------------------------------------------------------
|
|
51
|
+
# Exposed properties (lazy-loaded)
|
|
52
|
+
# -----------------------------------------------------------------
|
|
53
|
+
@property
|
|
54
|
+
def title(self) -> str:
|
|
55
|
+
"""Site title."""
|
|
56
|
+
return self._ensure_metadata().get("Title", "")
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def url(self) -> str:
|
|
60
|
+
"""Absolute URL of the site."""
|
|
61
|
+
return self._ensure_metadata().get("Url", "")
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def description(self) -> str:
|
|
65
|
+
"""Site description, if present."""
|
|
66
|
+
return self._ensure_metadata().get("Description", "")
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def created(self) -> datetime | None:
|
|
70
|
+
"""
|
|
71
|
+
Creation date of the SharePoint site.
|
|
72
|
+
|
|
73
|
+
Returns a ``datetime`` object parsed from the ``Created`` metadata
|
|
74
|
+
field, or ``None`` if the field is missing or cannot be parsed.
|
|
75
|
+
"""
|
|
76
|
+
created_str = self._ensure_metadata().get("Created")
|
|
77
|
+
if not created_str:
|
|
78
|
+
return None
|
|
79
|
+
try:
|
|
80
|
+
# ``fromisoformat`` handles the ISO‑8601 format returned by SharePoint.
|
|
81
|
+
return datetime.fromisoformat(created_str)
|
|
82
|
+
except ValueError:
|
|
83
|
+
# Fallback: return None if parsing fails.
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def language_id(self) -> int:
|
|
88
|
+
"""Raw LCID value returned by SharePoint."""
|
|
89
|
+
return self._ensure_metadata().get("Language", 0)
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def language_name(self) -> str:
|
|
93
|
+
"""
|
|
94
|
+
Human-readable language name derived from the LCID using the
|
|
95
|
+
``locale`` module. If the LCID is unknown or the locale cannot be set,
|
|
96
|
+
a fallback string is returned.
|
|
97
|
+
"""
|
|
98
|
+
lcid = self.language_id
|
|
99
|
+
locale_code = locale.windows_locale.get(lcid)
|
|
100
|
+
if not locale_code:
|
|
101
|
+
return f"Unknown (LCID={lcid})"
|
|
102
|
+
try:
|
|
103
|
+
# Attempt to set the locale; may fail if not installed.
|
|
104
|
+
locale.setlocale(locale.LC_ALL, locale_code)
|
|
105
|
+
# locale.getlocale() returns a tuple like ('en_US', 'UTF-8')
|
|
106
|
+
loc = locale.getlocale()[0]
|
|
107
|
+
if loc:
|
|
108
|
+
# Return the locale identifier (e.g., 'en_US')
|
|
109
|
+
return loc
|
|
110
|
+
except locale.Error:
|
|
111
|
+
# Locale not available on the system; fall back to the code.
|
|
112
|
+
pass
|
|
113
|
+
# Fallback to the raw locale code string.
|
|
114
|
+
return locale_code
|
|
115
|
+
|
|
116
|
+
# -----------------------------------------------------------------
|
|
117
|
+
# Convenience wrappers around ``SharePointAPI`` methods
|
|
118
|
+
# -----------------------------------------------------------------
|
|
119
|
+
def get_lists(self) -> SharePointLists:
|
|
120
|
+
"""Return a ``SharePointLists`` collection for this site."""
|
|
121
|
+
return self._api.get_lists(self.site_id)
|
|
122
|
+
|
|
123
|
+
def get_users(
|
|
124
|
+
self,
|
|
125
|
+
filters: Optional[str] = None,
|
|
126
|
+
select_fields: Optional[List[str]] = None,
|
|
127
|
+
) -> SharePointUserList:
|
|
128
|
+
"""Retrieve users from the site."""
|
|
129
|
+
return self._api.get_users(self.site_id, filters=filters, select_fields=select_fields)
|
|
130
|
+
|
|
131
|
+
def get_group_users(
|
|
132
|
+
self,
|
|
133
|
+
group_name: str,
|
|
134
|
+
filters: Optional[str] = None,
|
|
135
|
+
select_fields: Optional[List[str]] = None,
|
|
136
|
+
) -> SharePointUserList:
|
|
137
|
+
"""Retrieve members of a SharePoint group."""
|
|
138
|
+
return self._api.get_group_users(
|
|
139
|
+
self.site_id, group_name, filters=filters, select_fields=select_fields
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def get_user(
|
|
143
|
+
self,
|
|
144
|
+
user_id: int,
|
|
145
|
+
select_fields: Optional[List[str]] = None,
|
|
146
|
+
) -> SharePointUser:
|
|
147
|
+
"""Retrieve a single user by ID."""
|
|
148
|
+
return self._api.get_user(self.site_id, user_id, select_fields=select_fields)
|
|
149
|
+
|
|
150
|
+
def get_list(
|
|
151
|
+
self,
|
|
152
|
+
sp_list,
|
|
153
|
+
filters=None,
|
|
154
|
+
top: int = 1000,
|
|
155
|
+
view_path=None,
|
|
156
|
+
select_fields=None,
|
|
157
|
+
SPListType: SharePointList = SharePointList,
|
|
158
|
+
) -> SharePointList:
|
|
159
|
+
"""Delegate to ``SharePointAPI.get_list`` for this site."""
|
|
160
|
+
return self._api.get_list(
|
|
161
|
+
self.site_id,
|
|
162
|
+
sp_list,
|
|
163
|
+
filters,
|
|
164
|
+
top,
|
|
165
|
+
view_path,
|
|
166
|
+
select_fields,
|
|
167
|
+
SPListType=SPListType,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def get_list_by_name(
|
|
171
|
+
self,
|
|
172
|
+
sp_list_name: str,
|
|
173
|
+
filters=None,
|
|
174
|
+
top: int = 1000,
|
|
175
|
+
view_path=None,
|
|
176
|
+
select_fields=None,
|
|
177
|
+
SPListType: SharePointList = SharePointList,
|
|
178
|
+
) -> SharePointList:
|
|
179
|
+
"""Delegate to ``SharePointAPI.get_list_by_name`` for this site."""
|
|
180
|
+
return self._api.get_list_by_name(
|
|
181
|
+
self.site_id,
|
|
182
|
+
sp_list_name,
|
|
183
|
+
filters,
|
|
184
|
+
top,
|
|
185
|
+
view_path,
|
|
186
|
+
select_fields,
|
|
187
|
+
SPListType=SPListType,
|
|
188
|
+
)
|
{sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_api/SharePointTimeRegistration.py
RENAMED
|
@@ -3,9 +3,10 @@ from datetime import datetime
|
|
|
3
3
|
from sharepoint_api.SharePointListItem import SharePointListItem
|
|
4
4
|
# from .SharePointAPI import SharePointAPI as SP
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
class TimeRegistration(SharePointListItem):
|
|
7
8
|
"""
|
|
8
|
-
Represents a time
|
|
9
|
+
Represents a time-registration entry associated with a SharePoint list item.
|
|
9
10
|
|
|
10
11
|
Extends :class:`SharePointListItem` with fields specific to time tracking,
|
|
11
12
|
such as ``Hours``, ``DoneBy`` and related timestamps. Provides lazy loading of the
|
|
@@ -22,8 +23,8 @@ class TimeRegistration(SharePointListItem):
|
|
|
22
23
|
elif self.settings['DoneDate'] is None:
|
|
23
24
|
return None
|
|
24
25
|
else:
|
|
25
|
-
return datetime.strptime(self.settings['DoneDate'], '%Y-%m-%dT%H:%M:%SZ')
|
|
26
|
-
|
|
26
|
+
return datetime.strptime(self.settings['DoneDate'], '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=self.sp.timezone)
|
|
27
|
+
|
|
27
28
|
@property
|
|
28
29
|
def Hours(self) -> str:
|
|
29
30
|
return self.settings['Hours']
|
|
@@ -38,7 +39,7 @@ class TimeRegistration(SharePointListItem):
|
|
|
38
39
|
user_list = self.sp.get_users(self.sharepoint_site)
|
|
39
40
|
self._DoneBy = user_list.get_user_by_id(self.DoneById)
|
|
40
41
|
return self._DoneBy
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
@property
|
|
43
44
|
def DoneUsername(self) -> str:
|
|
44
45
|
return self.DoneBy.UserName
|
|
@@ -46,8 +47,7 @@ class TimeRegistration(SharePointListItem):
|
|
|
46
47
|
@property
|
|
47
48
|
def CaseId(self) -> str:
|
|
48
49
|
return self.settings['CaseId']
|
|
49
|
-
|
|
50
|
+
|
|
50
51
|
@property
|
|
51
52
|
def WorkPackageId(self) -> str:
|
|
52
53
|
return self.settings['WorkPackageId']
|
|
53
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""sharepoint_api package
|
|
2
2
|
|
|
3
|
-
Provides a high
|
|
3
|
+
Provides a high-level Python client for interacting with SharePoint sites via the
|
|
4
4
|
`SharePointAPI` class. The package includes helpers for working with lists,
|
|
5
5
|
list items, users, and time registrations.
|
|
6
6
|
|
|
@@ -18,4 +18,5 @@ api = SharePointAPI._compact_init(creds)
|
|
|
18
18
|
```
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
from .SharePointAPI import SharePointAPI
|
|
21
|
+
from .SharePointAPI import SharePointAPI
|
|
22
|
+
from .SharePointSite import SharePointSite
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sharepoint_v1_api
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Author: Aske Bluhme Klok
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: Sharepoint
|
|
@@ -156,13 +156,37 @@ for v in versions:
|
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
|
|
159
|
+
## 0.2.4 – 2025-12-03
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
|
|
163
|
+
- New high‑level `SharePointSite` object providing lazy‑loaded site metadata
|
|
164
|
+
|
|
165
|
+
## 0.2.3 – 2025-12-02
|
|
166
|
+
|
|
167
|
+
### Added
|
|
168
|
+
|
|
169
|
+
- GUID validation for list identifiers with fallback to list title lookup via `GetByTitle`.
|
|
170
|
+
- New helper method `_is_valid_guid` in `SharePointAPI`.
|
|
171
|
+
- Centralized list resolution helper `_resolve_sp_list` for GUID, title, or `SharePointList` instances.
|
|
172
|
+
- New method `get_list_metadata` to fetch only list metadata without items.
|
|
173
|
+
- Type hint enhancements: added `Optional`, `Tuple` imports; updated method signatures (e.g., `get_item_versions` now uses `Optional[List[str]]`).
|
|
174
|
+
- Updated `get_list` to return the resolved `SharePointList` object after appending items.
|
|
175
|
+
- Refactored multiple methods (`get_item`, `create_item`, `update_item`, `attach_file`, `get_item_versions`, `get_case`) to use `_resolve_sp_list`, removing redundant GUID validation logic.
|
|
176
|
+
|
|
177
|
+
### Changed
|
|
178
|
+
|
|
179
|
+
- Cleaned up stray `else:` blocks and syntax errors.
|
|
180
|
+
- Improved consistency of return objects across list-related methods.
|
|
181
|
+
- Updated imports and docstrings accordingly.
|
|
182
|
+
|
|
159
183
|
## 0.2.2 – 2025-11-28
|
|
160
184
|
|
|
161
185
|
### Added
|
|
162
186
|
|
|
163
187
|
- `SharePointList.fields` property to retrieve list field definitions
|
|
164
188
|
|
|
165
|
-
## 0.2.1 – 2025
|
|
189
|
+
## 0.2.1 – 2025-11-06
|
|
166
190
|
|
|
167
191
|
### Added
|
|
168
192
|
|
|
@@ -174,7 +198,7 @@ for v in versions:
|
|
|
174
198
|
|
|
175
199
|
### Changed
|
|
176
200
|
|
|
177
|
-
- HTTP header handling unified; corrected `X
|
|
201
|
+
- HTTP header handling unified; corrected `X-HTTP-Method: PUT` for full updates.
|
|
178
202
|
- Error handling improved: generic `sys.exit(1)` replaced with explicit `TypeError`/`ConnectionError` exceptions.
|
|
179
203
|
|
|
180
204
|
### Fixed
|
|
@@ -9,6 +9,7 @@ sharepoint_api/SharePointAPI.py
|
|
|
9
9
|
sharepoint_api/SharePointList.py
|
|
10
10
|
sharepoint_api/SharePointListItem.py
|
|
11
11
|
sharepoint_api/SharePointLists.py
|
|
12
|
+
sharepoint_api/SharePointSite.py
|
|
12
13
|
sharepoint_api/SharePointTimeRegistration.py
|
|
13
14
|
sharepoint_api/SharePointUser.py
|
|
14
15
|
sharepoint_api/SharePointUserList.py
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
## 0.2.2 – 2025-11-28
|
|
2
|
-
|
|
3
|
-
### Added
|
|
4
|
-
|
|
5
|
-
- `SharePointList.fields` property to retrieve list field definitions
|
|
6
|
-
|
|
7
|
-
## 0.2.1 – 2025‑11‑06
|
|
8
|
-
|
|
9
|
-
### Added
|
|
10
|
-
|
|
11
|
-
- Optional `select_fields` parameters to list retrieval methods for more efficient queries.
|
|
12
|
-
- New public API methods:
|
|
13
|
-
- `SharePointAPI.get_group_users` – fetch users of a SharePoint group.
|
|
14
|
-
- Improved error handling with explicit `TypeError` exceptions.
|
|
15
|
-
- Detailed docstrings for core classes and methods (enhances IDE support).
|
|
16
|
-
|
|
17
|
-
### Changed
|
|
18
|
-
|
|
19
|
-
- HTTP header handling unified; corrected `X‑HTTP‑Method: PUT` for full updates.
|
|
20
|
-
- Error handling improved: generic `sys.exit(1)` replaced with explicit `TypeError`/`ConnectionError` exceptions.
|
|
21
|
-
|
|
22
|
-
### Fixed
|
|
23
|
-
|
|
24
|
-
- Fixed incorrect PUT header that previously sent a MERGE header.
|
|
25
|
-
- Minor docstring formatting issues.
|
|
26
|
-
|
|
27
|
-
### Security
|
|
28
|
-
|
|
29
|
-
- Enforced NTLM authentication across all request helpers.
|
|
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
|
{sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_v1_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
{sharepoint_v1_api-0.2.2 → sharepoint_v1_api-0.2.4}/sharepoint_v1_api.egg-info/top_level.txt
RENAMED
|
File without changes
|