sharepoint-v1-api 0.2.2__py3-none-any.whl
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_api/SharePointAPI.py +1101 -0
- sharepoint_api/SharePointList.py +202 -0
- sharepoint_api/SharePointListItem.py +196 -0
- sharepoint_api/SharePointLists.py +59 -0
- sharepoint_api/SharePointTimeRegistration.py +53 -0
- sharepoint_api/SharePointUser.py +33 -0
- sharepoint_api/SharePointUserList.py +36 -0
- sharepoint_api/__init__.py +21 -0
- sharepoint_v1_api-0.2.2.dist-info/METADATA +187 -0
- sharepoint_v1_api-0.2.2.dist-info/RECORD +13 -0
- sharepoint_v1_api-0.2.2.dist-info/WHEEL +5 -0
- sharepoint_v1_api-0.2.2.dist-info/licenses/LICENSE +19 -0
- sharepoint_v1_api-0.2.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# from .SharePointAPI import SharePointAPI as SP
|
|
2
|
+
from sharepoint_api.SharePointTimeRegistration import TimeRegistration
|
|
3
|
+
from .SharePointListItem import SharePointListItem, SharepointSiteCase
|
|
4
|
+
from typing import List
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SharePointList:
|
|
9
|
+
"""
|
|
10
|
+
Base class representing a SharePoint list.
|
|
11
|
+
|
|
12
|
+
Provides common functionality for handling list items, including
|
|
13
|
+
retrieval, addition, and serialization to JSON. Subclasses such as
|
|
14
|
+
:class:`CasesList` and :class:`TimeRegistrationList` extend this
|
|
15
|
+
class with domain‑specific behavior.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
settings = None
|
|
19
|
+
_items = None
|
|
20
|
+
_fields = None
|
|
21
|
+
sharepoint_site = None
|
|
22
|
+
SPItem = SharePointListItem
|
|
23
|
+
|
|
24
|
+
CHANGE_DETECTED = False
|
|
25
|
+
SAVE_ON_CHANGE = False
|
|
26
|
+
JSON_FILENAME = None
|
|
27
|
+
|
|
28
|
+
def __init__(self, sp, sharepoint_site, settings: dict = None, items: List[SPItem] = None):
|
|
29
|
+
self.sp = sp
|
|
30
|
+
self.sharepoint_site = sharepoint_site
|
|
31
|
+
self.settings = settings
|
|
32
|
+
self.append_items(items)
|
|
33
|
+
|
|
34
|
+
def __str__(self):
|
|
35
|
+
items = ''
|
|
36
|
+
for _, _item in self.all_items.items():
|
|
37
|
+
items = items+str(_item.Title)+'\n'
|
|
38
|
+
return items
|
|
39
|
+
|
|
40
|
+
def __del__(self):
|
|
41
|
+
if self.CHANGE_DETECTED and self.SAVE_ON_CHANGE and self.JSON_FILENAME is not None:
|
|
42
|
+
print('Change was definiteley detected')
|
|
43
|
+
print('Saving items')
|
|
44
|
+
self.save_as_json(self.JSON_FILENAME)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def all_items(self) -> dict[int, SPItem]:
|
|
48
|
+
'''
|
|
49
|
+
Get list of all SharePointListItem objects
|
|
50
|
+
'''
|
|
51
|
+
if self._items is None:
|
|
52
|
+
self._items = {}
|
|
53
|
+
return self._items
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def list_all_items(self) -> List[SPItem]:
|
|
57
|
+
'''
|
|
58
|
+
Get list of all SharePointListItem objects
|
|
59
|
+
'''
|
|
60
|
+
if self._items is None:
|
|
61
|
+
self._items = {}
|
|
62
|
+
return list(self._items.values())
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def Title(self) -> str:
|
|
66
|
+
return self.settings['Title']
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def guid(self):
|
|
70
|
+
return self.settings['Id']
|
|
71
|
+
|
|
72
|
+
def append_items(self, items):
|
|
73
|
+
"""
|
|
74
|
+
Append a collection of items to the list.
|
|
75
|
+
|
|
76
|
+
Parameters
|
|
77
|
+
----------
|
|
78
|
+
items : list or SharePointListItem
|
|
79
|
+
A list of :class:`SharePointListItem` instances or a single
|
|
80
|
+
instance to be added to the internal ``_items`` dictionary.
|
|
81
|
+
"""
|
|
82
|
+
if self._items is None:
|
|
83
|
+
self._items = {}
|
|
84
|
+
|
|
85
|
+
if isinstance(items, list):
|
|
86
|
+
for item in items:
|
|
87
|
+
item._list = self
|
|
88
|
+
self._items[item.Id] = item
|
|
89
|
+
|
|
90
|
+
elif isinstance(items, self.SPItem):
|
|
91
|
+
items._list = self
|
|
92
|
+
self.all_items[items.Id] = items
|
|
93
|
+
|
|
94
|
+
def create_item(self, data):
|
|
95
|
+
self.sp.create_item(self.sharepoint_site, self, data)
|
|
96
|
+
|
|
97
|
+
def get_item_by_name(self, name):
|
|
98
|
+
"""
|
|
99
|
+
Retrieve items from the list that match a given title.
|
|
100
|
+
|
|
101
|
+
Parameters
|
|
102
|
+
----------
|
|
103
|
+
name : str
|
|
104
|
+
The title of the item to search for.
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
dict[int, SharePointListItem]
|
|
109
|
+
A dictionary of matching items keyed by their IDs.
|
|
110
|
+
"""
|
|
111
|
+
'''
|
|
112
|
+
'''
|
|
113
|
+
items = {}
|
|
114
|
+
for item_id, item in self._items.items():
|
|
115
|
+
if name == item.Title:
|
|
116
|
+
items[item_id] = item
|
|
117
|
+
return items
|
|
118
|
+
|
|
119
|
+
def get_item_by_id(self, id):
|
|
120
|
+
'''
|
|
121
|
+
'''
|
|
122
|
+
if id in self._items:
|
|
123
|
+
return self._items[id]
|
|
124
|
+
else:
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def fields(self) -> dict:
|
|
129
|
+
"""
|
|
130
|
+
Retrieve all fields from the SharePoint list.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
dict: Field definitions keyed by Title, cached for subsequent calls
|
|
134
|
+
|
|
135
|
+
Raises:
|
|
136
|
+
ConnectionError: If API request fails
|
|
137
|
+
"""
|
|
138
|
+
if not self._fields:
|
|
139
|
+
try:
|
|
140
|
+
response = self.sp._api_get_call(
|
|
141
|
+
f"{self.sp.sharepoint_url}/cases/{self.sharepoint_site}/_api/Web/Lists(guid'{self.guid}')/Fields"
|
|
142
|
+
)
|
|
143
|
+
response.raise_for_status()
|
|
144
|
+
self._fields = {field["Title"]: field for field in response.json().get(
|
|
145
|
+
'd', {}).get('results', [])}
|
|
146
|
+
except Exception as e:
|
|
147
|
+
print(f"Failed to fetch fields: {str(e)}")
|
|
148
|
+
raise ConnectionError("Field retrieval failed") from e
|
|
149
|
+
return self._fields
|
|
150
|
+
|
|
151
|
+
def get_items_by_assigned_id(self, id) -> List[SPItem]:
|
|
152
|
+
'''
|
|
153
|
+
'''
|
|
154
|
+
items = {}
|
|
155
|
+
for item_id, item in self._items.items():
|
|
156
|
+
if id == item.ResponsibleId:
|
|
157
|
+
items[item_id] = item
|
|
158
|
+
return items
|
|
159
|
+
|
|
160
|
+
def save_as_json(self, file_name):
|
|
161
|
+
"""
|
|
162
|
+
Serialize the list to a JSON file.
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
file_name : str
|
|
167
|
+
Path to the output JSON file.
|
|
168
|
+
|
|
169
|
+
The resulting JSON contains the SharePoint site identifier, the list GUID,
|
|
170
|
+
settings, and all case items with their settings and version information.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
out_dict = {
|
|
174
|
+
'sharepoint_site': self.sharepoint_site,
|
|
175
|
+
'GUID': self.guid,
|
|
176
|
+
'Settings': self.settings,
|
|
177
|
+
"cases": [{'settings': case.settings, 'versions': case._versions} for _, case in self.all_items.items()]
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
with open(file_name, 'w') as fp:
|
|
181
|
+
json.dump(out_dict, fp)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class CasesList(SharePointList):
|
|
185
|
+
"""
|
|
186
|
+
Specialized list representing a collection of case items.
|
|
187
|
+
|
|
188
|
+
Inherits all functionality from :class:`SharePointList` and sets the
|
|
189
|
+
``SPItem`` attribute to :class:`SharepointSiteCase` for proper item
|
|
190
|
+
instantiation.
|
|
191
|
+
"""
|
|
192
|
+
SPItem = SharepointSiteCase
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class TimeRegistrationList(SharePointList):
|
|
196
|
+
"""
|
|
197
|
+
Specialized list for time‑registration entries.
|
|
198
|
+
|
|
199
|
+
Inherits from :class:`SharePointList` and sets ``SPItem`` to the
|
|
200
|
+
:class:`TimeRegistration` class.
|
|
201
|
+
"""
|
|
202
|
+
SPItem = TimeRegistration
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
# from .SharePointAPI import SharePointAPI as SP
|
|
3
|
+
|
|
4
|
+
class SharePointListItem:
|
|
5
|
+
"""
|
|
6
|
+
Represents a generic item in a SharePoint list.
|
|
7
|
+
|
|
8
|
+
Provides access to common fields such as ``Id``, ``Title``, ``Created`` and
|
|
9
|
+
``Modified`` and handles lazy loading of related list data and version
|
|
10
|
+
history. Sub‑classes (e.g. :class:`SharepointSiteCase` or
|
|
11
|
+
:class:`TimeRegistration`) extend this base with domain‑specific properties.
|
|
12
|
+
"""
|
|
13
|
+
'''
|
|
14
|
+
'''
|
|
15
|
+
settings = {}
|
|
16
|
+
|
|
17
|
+
def __init__(self, sp, sharepoint_site, list_guid, settings: dict = None, versions: list = None):
|
|
18
|
+
self.sp = sp
|
|
19
|
+
self.sharepoint_site = sharepoint_site
|
|
20
|
+
self.list_guid = list_guid
|
|
21
|
+
self._list = None
|
|
22
|
+
self._versions = versions
|
|
23
|
+
self.settings = settings
|
|
24
|
+
|
|
25
|
+
def __str__(self):
|
|
26
|
+
return self.Title
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def list(self):
|
|
30
|
+
if not self._list:
|
|
31
|
+
self._list = self.sp.get_list(self.sharepoint_site, self.list_guid)
|
|
32
|
+
return self._list
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def versions(self) -> list:
|
|
36
|
+
if not self._versions:
|
|
37
|
+
self._versions = self.sp.get_item_versions(self.sharepoint_site, self.list_guid, self.Id)
|
|
38
|
+
if self._list is not None:
|
|
39
|
+
self._list.CHANGE_DETECTED = True
|
|
40
|
+
return self._versions
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def Id(self) -> str:
|
|
45
|
+
"""Unique identifier of the list item."""
|
|
46
|
+
return self.settings['Id']
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def Title(self) -> str:
|
|
50
|
+
"""Title of the list item."""
|
|
51
|
+
return self.settings['Title']
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def Created(self) -> datetime:
|
|
55
|
+
"""
|
|
56
|
+
Timestamp of when the item was created.
|
|
57
|
+
|
|
58
|
+
Returns ``None`` if the ``Created`` field is missing or null.
|
|
59
|
+
"""
|
|
60
|
+
if 'Created' not in self.settings:
|
|
61
|
+
return None
|
|
62
|
+
elif self.settings['Created'] is None:
|
|
63
|
+
return None
|
|
64
|
+
else:
|
|
65
|
+
return datetime.strptime(self.settings['Created'], '%Y-%m-%dT%H:%M:%SZ')
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def Modified(self) -> datetime:
|
|
69
|
+
"""
|
|
70
|
+
Timestamp of when the item was modified.
|
|
71
|
+
|
|
72
|
+
Returns ``None`` if the ``Modified`` field is missing or null.
|
|
73
|
+
"""
|
|
74
|
+
if 'Modified' not in self.settings:
|
|
75
|
+
return None
|
|
76
|
+
elif self.settings['Modified'] is None:
|
|
77
|
+
return None
|
|
78
|
+
else:
|
|
79
|
+
return datetime.strptime(self.settings['Modified'], '%Y-%m-%dT%H:%M:%SZ')
|
|
80
|
+
|
|
81
|
+
def attach_item(self, file_name, file_path):
|
|
82
|
+
"""
|
|
83
|
+
Attach a file to this list item.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
file_name : str
|
|
88
|
+
The name of the file as it should appear in SharePoint.
|
|
89
|
+
file_path : str
|
|
90
|
+
Local path to the file to be uploaded.
|
|
91
|
+
|
|
92
|
+
The method reads the file content and uses :meth:`SharePointAPI.attach_file`
|
|
93
|
+
to upload it to the corresponding SharePoint list item.
|
|
94
|
+
"""
|
|
95
|
+
with open(file_path, 'r') as f:
|
|
96
|
+
file_content = f.read()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
self.sp.attach_file(self.sharepoint_site, self.list, self, file_name, file_content)
|
|
100
|
+
|
|
101
|
+
def versions_select_fields(self, select_fields=[]) -> list:
|
|
102
|
+
if not self._versions:
|
|
103
|
+
self._versions = self.sp.get_item_versions(self.sharepoint_site, self.list_guid, self.Id, select_fields)
|
|
104
|
+
return self._versions
|
|
105
|
+
|
|
106
|
+
def update_fields(self, data):
|
|
107
|
+
self.sp.update_item(self.sharepoint_site,
|
|
108
|
+
self.list_guid, self.Id, data)
|
|
109
|
+
|
|
110
|
+
class SharepointSiteCase(SharePointListItem):
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def AssignmentType(self) -> str:
|
|
114
|
+
return self.settings['AssignmentType']
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def CaseClosedTimestamp(self) -> datetime:
|
|
118
|
+
'Timestamp of when the case was closed'
|
|
119
|
+
if 'CaseClosed' not in self.settings:
|
|
120
|
+
return None
|
|
121
|
+
elif self.settings['CaseClosed'] is None:
|
|
122
|
+
return None
|
|
123
|
+
else:
|
|
124
|
+
return datetime.strptime(self.settings['CaseClosed'], '%Y-%m-%dT%H:%M:%SZ')
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def Due(self) -> datetime:
|
|
128
|
+
'Timestamp of when the case is due'
|
|
129
|
+
if 'DueDate' not in self.settings:
|
|
130
|
+
return None
|
|
131
|
+
elif self.settings['DueDate'] is None:
|
|
132
|
+
return None
|
|
133
|
+
else:
|
|
134
|
+
return datetime.strptime(self.settings['DueDate'], '%Y-%m-%dT%H:%M:%SZ')
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def Priority(self) -> str:
|
|
138
|
+
return self.settings['Priority']
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def ResponsibleId(self) -> str:
|
|
142
|
+
return self.settings['AssignedToId']
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def Status(self) -> str:
|
|
146
|
+
return self.settings['Status']
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def SolvedInTime(self) -> bool:
|
|
150
|
+
'Bool indicating whether work was solved in time'
|
|
151
|
+
solved_in_time = False
|
|
152
|
+
if self.Due:
|
|
153
|
+
if not self.CaseClosedTimestamp:
|
|
154
|
+
solved_in_time = True
|
|
155
|
+
elif self.CaseClosedTimestamp <= self.Due:
|
|
156
|
+
solved_in_time = True
|
|
157
|
+
else:
|
|
158
|
+
solved_in_time = True
|
|
159
|
+
|
|
160
|
+
return solved_in_time
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def WorkBegunTimestamp(self) -> datetime:
|
|
164
|
+
'Timestamp of when work was started on the case'
|
|
165
|
+
if 'WorkBegun' not in self.settings:
|
|
166
|
+
return None
|
|
167
|
+
elif self.settings['WorkBegun'] is None:
|
|
168
|
+
return None
|
|
169
|
+
else:
|
|
170
|
+
return datetime.strptime(self.settings['WorkBegun'], '%Y-%m-%dT%H:%M:%SZ')
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def DeadlineWorkTimestamp(self) -> datetime:
|
|
174
|
+
'Timestamp of when work should start on the case'
|
|
175
|
+
if 'DeadlineWork' not in self.settings:
|
|
176
|
+
return None
|
|
177
|
+
elif self.settings['DeadlineWork'] is None:
|
|
178
|
+
return None
|
|
179
|
+
else:
|
|
180
|
+
return datetime.strptime(self.settings['DeadlineWork'], '%Y-%m-%dT%H:%M:%SZ')
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def ReactedInTime(self) -> bool:
|
|
184
|
+
'Bool indicating whether work was started in time'
|
|
185
|
+
reacted_in_time = False
|
|
186
|
+
if self.DeadlineWorkTimestamp:
|
|
187
|
+
if not self.WorkBegunTimestamp:
|
|
188
|
+
reacted_in_time = True
|
|
189
|
+
elif self.WorkBegunTimestamp <= self.DeadlineWorkTimestamp:
|
|
190
|
+
reacted_in_time = True
|
|
191
|
+
else:
|
|
192
|
+
reacted_in_time = True
|
|
193
|
+
return reacted_in_time
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from .SharePointList import SharePointList, CasesList
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
class SharePointLists:
|
|
5
|
+
|
|
6
|
+
_lists = None
|
|
7
|
+
|
|
8
|
+
def __init__(self, lists):
|
|
9
|
+
self._lists = lists
|
|
10
|
+
|
|
11
|
+
def __str__(self):
|
|
12
|
+
lists = ''
|
|
13
|
+
for _list in self.all_lists:
|
|
14
|
+
lists = lists+str(_list.Title)+'\n'
|
|
15
|
+
return lists
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def all_lists(self) -> List[SharePointList]:
|
|
19
|
+
'''
|
|
20
|
+
Get list of all SharePointList objects
|
|
21
|
+
'''
|
|
22
|
+
if self._lists is None:
|
|
23
|
+
self._lists = []
|
|
24
|
+
return self._lists
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def all_list_titles(self) -> str:
|
|
28
|
+
'''
|
|
29
|
+
Get list of all SharePointList objects
|
|
30
|
+
'''
|
|
31
|
+
|
|
32
|
+
return [_list.Title for _list in self.all_lists]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_list(self, key, SPListType: SharePointList=SharePointList) -> SharePointList:
|
|
36
|
+
'''
|
|
37
|
+
Get SharePointList by:
|
|
38
|
+
- Index: int
|
|
39
|
+
- List title: str
|
|
40
|
+
'''
|
|
41
|
+
if isinstance(key, int):
|
|
42
|
+
return self.all_lists[key]
|
|
43
|
+
elif isinstance(key, str):
|
|
44
|
+
for list_object in self.all_lists:
|
|
45
|
+
if list_object.Title == key:
|
|
46
|
+
return list_object
|
|
47
|
+
raise KeyError("No list with title '{0}'".format(key))
|
|
48
|
+
raise KeyError
|
|
49
|
+
|
|
50
|
+
def get_cases_list(self, key) -> CasesList:
|
|
51
|
+
'''
|
|
52
|
+
Get SharePointList by:
|
|
53
|
+
- Index: int
|
|
54
|
+
- List title: str
|
|
55
|
+
'''
|
|
56
|
+
|
|
57
|
+
list_object = self.get_list(key, SPListType=CasesList)
|
|
58
|
+
|
|
59
|
+
return CasesList(list_object.sharepoint_site, list_object.settings)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
from sharepoint_api.SharePointListItem import SharePointListItem
|
|
4
|
+
# from .SharePointAPI import SharePointAPI as SP
|
|
5
|
+
|
|
6
|
+
class TimeRegistration(SharePointListItem):
|
|
7
|
+
"""
|
|
8
|
+
Represents a time‑registration entry associated with a SharePoint list item.
|
|
9
|
+
|
|
10
|
+
Extends :class:`SharePointListItem` with fields specific to time tracking,
|
|
11
|
+
such as ``Hours``, ``DoneBy`` and related timestamps. Provides lazy loading of the
|
|
12
|
+
``DoneBy`` user via the :meth:`SharePointAPI.get_users` call.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
_DoneBy = None
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def Created(self) -> datetime:
|
|
19
|
+
'Timestamp of when the item was created'
|
|
20
|
+
if 'DoneDate' not in self.settings:
|
|
21
|
+
return None
|
|
22
|
+
elif self.settings['DoneDate'] is None:
|
|
23
|
+
return None
|
|
24
|
+
else:
|
|
25
|
+
return datetime.strptime(self.settings['DoneDate'], '%Y-%m-%dT%H:%M:%SZ')
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def Hours(self) -> str:
|
|
29
|
+
return self.settings['Hours']
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def DoneById(self) -> str:
|
|
33
|
+
return self.settings['DoneById']
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def DoneBy(self) -> str:
|
|
37
|
+
if not self._DoneBy:
|
|
38
|
+
user_list = self.sp.get_users(self.sharepoint_site)
|
|
39
|
+
self._DoneBy = user_list.get_user_by_id(self.DoneById)
|
|
40
|
+
return self._DoneBy
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def DoneUsername(self) -> str:
|
|
44
|
+
return self.DoneBy.UserName
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def CaseId(self) -> str:
|
|
48
|
+
return self.settings['CaseId']
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def WorkPackageId(self) -> str:
|
|
52
|
+
return self.settings['WorkPackageId']
|
|
53
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
class SharePointUser:
|
|
2
|
+
|
|
3
|
+
settings = None
|
|
4
|
+
_users = None
|
|
5
|
+
sharepoint_site = None
|
|
6
|
+
|
|
7
|
+
def __init__(self, settings: dict = None):
|
|
8
|
+
self.settings = settings
|
|
9
|
+
|
|
10
|
+
@property
|
|
11
|
+
def Id(self):
|
|
12
|
+
if self.settings is None:
|
|
13
|
+
return None
|
|
14
|
+
return self.settings['Id']
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def Title(self):
|
|
18
|
+
if self.settings is None:
|
|
19
|
+
return None
|
|
20
|
+
return self.settings['Title']
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def UserName(self):
|
|
24
|
+
if self.settings is None:
|
|
25
|
+
return None
|
|
26
|
+
return self.settings['Email'].split('@')[0].lower()
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def Email(self):
|
|
30
|
+
if self.settings is None:
|
|
31
|
+
return None
|
|
32
|
+
return self.settings['Email']
|
|
33
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class SharePointUserList:
|
|
2
|
+
"""
|
|
3
|
+
Container for SharePoint user objects.
|
|
4
|
+
|
|
5
|
+
Holds a list of :class:`SharePointUser` instances retrieved from a
|
|
6
|
+
SharePoint site and provides helper methods to look up users by
|
|
7
|
+
username or ID. The ``sharepoint_site`` attribute records the site
|
|
8
|
+
from which the users were fetched.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
_users = []
|
|
12
|
+
sharepoint_site = ''
|
|
13
|
+
|
|
14
|
+
def __init__(self, sharepoint_site, users):
|
|
15
|
+
self._users = users
|
|
16
|
+
self.sharepoint_site = sharepoint_site
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
n_users = len(self._users)
|
|
20
|
+
if n_users == 1:
|
|
21
|
+
return 'A list of 1 user'
|
|
22
|
+
|
|
23
|
+
return f'A list of {n_users} users'
|
|
24
|
+
|
|
25
|
+
def get_user_by_username(self, name):
|
|
26
|
+
for user in self._users:
|
|
27
|
+
if name == user.UserName:
|
|
28
|
+
return user
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
def get_user_by_id(self, user_id):
|
|
32
|
+
for user in self._users:
|
|
33
|
+
if user_id == user.Id:
|
|
34
|
+
return user
|
|
35
|
+
return
|
|
36
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""sharepoint_api package
|
|
2
|
+
|
|
3
|
+
Provides a high‑level Python client for interacting with SharePoint sites via the
|
|
4
|
+
`SharePointAPI` class. The package includes helpers for working with lists,
|
|
5
|
+
list items, users, and time registrations.
|
|
6
|
+
|
|
7
|
+
Typical usage:
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
from sharepoint_api import SharePointAPI
|
|
11
|
+
|
|
12
|
+
creds = {
|
|
13
|
+
"username": "my_user",
|
|
14
|
+
"password": "my_pass",
|
|
15
|
+
"sharepoint_url": "https://my.sharepoint.com"
|
|
16
|
+
}
|
|
17
|
+
api = SharePointAPI._compact_init(creds)
|
|
18
|
+
```
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from .SharePointAPI import SharePointAPI
|