Skip to content

Commit 43b287a

Browse files
committed
SharePoint API enhancements: features, sharing and social namespaces
1 parent e178726 commit 43b287a

32 files changed

+567
-86
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from office365.sharepoint.client_context import ClientContext
22
from office365.sharepoint.features.definitions.scope import FeatureDefinitionScope
3+
from office365.sharepoint.features.known_list import KnownFeaturesList
34
from tests import test_team_site_url, test_client_credentials
45

56
ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
6-
feature_id = "b50e3104-6812-424f-a011-cc90e6327318"
7-
f = ctx.site.features.add(feature_id, False, FeatureDefinitionScope.Farm).execute_query()
7+
f = ctx.site.features.add(KnownFeaturesList.DocId, False, FeatureDefinitionScope.Farm).execute_query()
88
print("Feature {0} has been activated.", f.display_name)
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
from office365.sharepoint.client_context import ClientContext
22
from office365.sharepoint.features.definitions.scope import FeatureDefinitionScope
3+
from office365.sharepoint.features.known_list import KnownFeaturesList
34
from tests import test_client_credentials, test_site_url
45

5-
feature_id = "9a447926-5937-44cb-857a-d3829301c73b"
6-
76
ctx = ClientContext(test_site_url).with_credentials(test_client_credentials)
8-
f = ctx.site.features.add(feature_id, False, FeatureDefinitionScope.Farm).execute_query()
7+
f = ctx.site.features.add(KnownFeaturesList.ContentTypeHub, False, FeatureDefinitionScope.Farm, True).execute_query()
98
print("Feature {0} has been activated.", f.display_name)

examples/sharepoint/files/download_file.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66

77
ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
88
# file_url = '/sites/team/Shared Documents/big_buck_bunny.mp4'
9-
file_url = "/sites/team/Shared Documents/report #123.csv"
9+
file_url = "/sites/team/Shared Documents/!2022/Financial Sample.xlsx"
1010
download_path = os.path.join(tempfile.mkdtemp(), os.path.basename(file_url))
1111
with open(download_path, "wb") as local_file:
12-
file = ctx.web.get_file_by_server_relative_path(file_url).download(local_file).execute_query()
12+
file = ctx.web.get_file_by_server_relative_url(file_url).download(local_file).execute_query()
1313
#file = ctx.web.get_file_by_server_relative_url(file_url).download(local_file).execute_query()
1414
print("[Ok] file has been downloaded into: {0}".format(download_path))

examples/sharepoint/tenant/get_all_sites.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
admin_client = ClientContext(test_admin_site_url).with_credentials(test_client_credentials)
77
tenant = Tenant(admin_client)
8-
result = tenant.get_site_properties_from_sharepoint_by_filters("", 0).execute_query()
9-
for siteProps in result: # type: SiteProperties
10-
print(siteProps.url)
8+
result = tenant.get_site_properties_from_sharepoint_by_filters("").execute_query()
9+
for i, siteProps in enumerate(result): # type: SiteProperties
10+
print("({0} of {1}) {2}".format(i, len(result), siteProps.url))

examples/sharepoint/lists/enable_doc_id.py renamed to examples/sharepoint/webs/enable_doc_id.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
from tests import test_client_credentials, test_team_site_url
33

44
ctx = ClientContext(test_team_site_url).with_credentials(test_client_credentials)
5-
6-
w = ctx.web.assign_document_id("MEDIADEVDOC").execute_query()
5+
ctx.web.assign_document_id("MEDIADEVDOC").execute_query()
76
print("Document IDs has been assigned")

generator/metadata/SharePoint.xml

+204
Large diffs are not rendered by default.

office365/runtime/odata/request.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from office365.runtime.http.http_method import HttpMethod
88
from office365.runtime.http.request_options import RequestOptions
99
from office365.runtime.odata.v3.json_light_format import JsonLightFormat
10+
from office365.runtime.paths.service_operation import ServiceOperationPath
1011
from office365.runtime.queries.create_entity import CreateEntityQuery
1112
from office365.runtime.queries.delete_entity import DeleteEntityQuery
1213
from office365.runtime.queries.service_operation import ServiceOperationQuery
@@ -61,15 +62,18 @@ def process_response(self, response, query):
6162
if isinstance(return_type, ClientResult):
6263
return_type.set_property("__value", response.content)
6364
else:
64-
if isinstance(query, ServiceOperationQuery) and isinstance(json_format, JsonLightFormat):
65-
json_format.function = query.method_name
65+
if isinstance(json_format, JsonLightFormat):
66+
if isinstance(query, ServiceOperationQuery):
67+
json_format.function = query.method_name
68+
elif isinstance(return_type.resource_path, ServiceOperationPath):
69+
json_format.function = return_type.resource_path.name
6670

6771
self.map_json(response.json(), return_type, json_format)
6872

6973
def map_json(self, json, return_type, json_format=None):
7074
"""
7175
:type json: any
72-
:type return_type: ClientValue or ClientResult or ClientObject
76+
:type return_type: ClientValue or ClientResult or ClientObject
7377
:type json_format: office365.runtime.odata.json_format.ODataJsonFormat
7478
"""
7579
if json_format is None:
@@ -81,16 +85,14 @@ def map_json(self, json, return_type, json_format=None):
8185

8286
def _next_property(self, json, json_format):
8387
"""
84-
:type json: any
88+
:type json: Any
8589
:type json_format: office365.runtime.odata.json_format.ODataJsonFormat
8690
"""
8791
if isinstance(json_format, JsonLightFormat):
8892
json = json.get(json_format.security, json)
8993
json = json.get(json_format.function, json)
9094

91-
if not isinstance(json, dict):
92-
yield "__value", json
93-
else:
95+
if isinstance(json, dict):
9496
next_link_url = json.get(json_format.collection_next, None)
9597
json = json.get(json_format.collection, json)
9698
if next_link_url:
@@ -114,13 +116,16 @@ def _next_property(self, json, json_format):
114116
yield name, value
115117
else:
116118
yield "__value", json
119+
elif json is not None:
120+
yield "__value", json
117121

118122
def _build_payload(self, query):
119123
"""
120124
Normalizes OData request payload
121125
122126
:type query: office365.runtime.queries.client_query.ClientQuery
123127
"""
128+
124129
def _normalize_payload(payload):
125130
if isinstance(payload, ClientObject) or isinstance(payload, ClientValue):
126131
return payload.to_json(self._default_json_format)
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,42 @@
1+
from office365.runtime.client_result import ClientResult
2+
from office365.runtime.client_value_collection import ClientValueCollection
3+
from office365.runtime.queries.service_operation import ServiceOperationQuery
4+
from office365.runtime.types.collections import StringCollection
15
from office365.sharepoint.base_entity import BaseEntity
6+
from office365.sharepoint.compliance.tag import ComplianceTag
27

38

49
class SPPolicyStoreProxy(BaseEntity):
510

11+
@staticmethod
12+
def get_available_tags_for_site(context, site_url, return_type=None):
13+
"""
14+
:param office365.sharepoint.client_context.ClientContext context: SharePoint client context
15+
:param str site_url:
16+
:param ClientResult return_type:
17+
"""
18+
if return_type is None:
19+
return_type = ClientResult(context, ClientValueCollection(ComplianceTag))
20+
payload = {
21+
"siteUrl": site_url
22+
}
23+
qry = ServiceOperationQuery(SPPolicyStoreProxy(context), "GetAvailableTagsForSite", None, payload,
24+
None, return_type, True)
25+
context.add_query(qry)
26+
return return_type
27+
28+
def get_dynamic_scope_binding_by_site_id(self, site_id):
29+
"""
30+
:param str site_id:
31+
"""
32+
return_type = ClientResult(self.context, StringCollection())
33+
payload = {
34+
"siteId": site_id
35+
}
36+
qry = ServiceOperationQuery(self, "GetDynamicScopeBindingBySiteId", None, payload, None, return_type)
37+
self.context.add_query(qry)
38+
return return_type
39+
640
@property
741
def entity_type_name(self):
842
return "SP.CompliancePolicy.SPPolicyStoreProxy"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from office365.runtime.client_value import ClientValue
2+
3+
4+
class MachineLearningSampleMeta(ClientValue):
5+
6+
@property
7+
def entity_type_name(self):
8+
return "SP.MachineLearningSampleMeta"

office365/sharepoint/features/collection.py

+24-8
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,39 @@ class FeatureCollection(BaseEntityCollection):
1010
def __init__(self, context, resource_path=None, parent=None):
1111
super(FeatureCollection, self).__init__(context, Feature, resource_path, parent)
1212

13-
def add(self, feature_id, force, featdef_scope):
13+
def add(self, feature_id, force, featdef_scope, verify_if_activated=False):
1414
"""
1515
Adds the feature to the collection of activated features and returns the added feature.
1616
1717
:param str feature_id: The feature identifier of the feature to be added.
1818
:param bool force: Specifies whether to continue with the operation even if there are errors.
1919
:param int featdef_scope: The feature scope for this feature.
20+
:param bool verify_if_activated: Verify if activated first to avoid System.Data.DuplicateNameException exception
2021
"""
2122
return_type = Feature(self.context)
22-
payload = {
23-
"featureId": feature_id,
24-
"force": force,
25-
"featdefScope": featdef_scope
26-
}
2723
self.add_child(return_type)
28-
qry = ServiceOperationQuery(self, "Add", None, payload, None, return_type)
29-
self.context.add_query(qry)
24+
25+
def _create_query():
26+
payload = {
27+
"featureId": feature_id,
28+
"force": force,
29+
"featdefScope": featdef_scope
30+
}
31+
return ServiceOperationQuery(self, "Add", None, payload, None, return_type)
32+
33+
def _create_if_not_activated(f):
34+
"""
35+
:type f: Feature
36+
"""
37+
if not f.properties:
38+
self.context.add_query(_create_query())
39+
40+
if verify_if_activated:
41+
feature = self.get_by_id(feature_id)
42+
self.context.load(feature, after_loaded=_create_if_not_activated)
43+
else:
44+
self.context.add_query(_create_query())
45+
3046
return return_type
3147

3248
def get_by_id(self, feature_id):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class KnownFeaturesList:
2+
3+
PushNotifications = "41e1d4bf-b1a2-47f7-ab80-d5d6cbba3092"
4+
5+
ContentTypeHub = "9a447926-5937-44cb-857a-d3829301c73b"
6+
7+
DocId = "b50e3104-6812-424f-a011-cc90e6327318"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from office365.runtime.client_value import ClientValue
2+
3+
4+
class ListCollectionPosition(ClientValue):
5+
6+
def __init__(self, paging_info=None):
7+
"""
8+
:param str paging_info:
9+
"""
10+
self.PagingInfo = paging_info
11+
12+
@property
13+
def entity_type_name(self):
14+
return "SP.ListCollectionPosition"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from office365.runtime.client_value import ClientValue
2+
from office365.sharepoint.lists.collection_position import ListCollectionPosition
3+
4+
5+
class GetListsParameters(ClientValue):
6+
7+
def __init__(self, position=ListCollectionPosition(), row_limit=100):
8+
"""
9+
:param ListCollectionPosition position:
10+
"""
11+
self.ListCollectionPosition = position
12+
self.RowLimit = row_limit
13+
14+
@property
15+
def entity_type_name(self):
16+
return "SP.GetListsParameters"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from office365.sharepoint.base_entity import BaseEntity
2+
3+
4+
class MetadataNavigationSettings(BaseEntity):
5+
6+
@property
7+
def entity_type_name(self):
8+
return "SP.MetadataNavigation.MetadataNavigationSettings"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from office365.runtime.paths.service_operation import ServiceOperationPath
2+
from office365.sharepoint.base_entity_collection import BaseEntityCollection
3+
from office365.sharepoint.pushnotifications.subscriber import PushNotificationSubscriber
4+
5+
6+
class PushNotificationSubscriberCollection(BaseEntityCollection):
7+
8+
def __init__(self, context, resource_path=None):
9+
super(PushNotificationSubscriberCollection, self).__init__(context, PushNotificationSubscriber, resource_path)
10+
11+
def get_by_store_id(self, _id):
12+
"""
13+
Returns the push notification subscriber from the specified store identifier.
14+
15+
:param str _id: Store identifier for the notification subscriber.
16+
"""
17+
return PushNotificationSubscriber(self.context, ServiceOperationPath("GetByStoreId", [_id], self.resource_path))
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from office365.runtime.client_value import ClientValue
2+
3+
4+
class SharingAbilities(ClientValue):
5+
"""
6+
Represents the matrix of possible sharing abilities for direct sharing and tokenized sharing links along
7+
with the state of each capability for the current user.
8+
"""
9+
10+
@property
11+
def entity_type_name(self):
12+
return "SP.Sharing.SharingAbilities"

office365/sharepoint/sharing/information.py

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from office365.runtime.paths.resource_path import ResourcePath
22
from office365.sharepoint.base_entity import BaseEntity
3+
from office365.sharepoint.sharing.abilities import SharingAbilities
34
from office365.sharepoint.sharing.access_request_settings import AccessRequestSettings
45
from office365.sharepoint.sharing.links.default_templates_collection import SharingLinkDefaultTemplatesCollection
56
from office365.sharepoint.sharing.picker_settings import PickerSettings
@@ -24,6 +25,13 @@ def picker_settings(self):
2425
return self.properties.get('pickerSettings',
2526
PickerSettings(self.context, ResourcePath("pickerSettings", self.resource_path)))
2627

28+
@property
29+
def sharing_abilities(self):
30+
"""
31+
Matrix of possible sharing abilities per sharing type and the state of each capability for the current user
32+
on the list item."""
33+
return self.properties.get("sharingAbilities", SharingAbilities())
34+
2735
@property
2836
def sharing_link_templates(self):
2937
""""""
@@ -34,7 +42,12 @@ def get_property(self, name, default_value=None):
3442
property_mapping = {
3543
"accessRequestSettings": self.access_request_settings,
3644
"pickerSettings": self.picker_settings,
45+
"sharingAbilities": self.sharing_abilities,
3746
"sharingLinkTemplates": self.sharing_link_templates
3847
}
3948
default_value = property_mapping.get(name, None)
4049
return super(SharingInformation, self).get_property(name, default_value)
50+
51+
@property
52+
def entity_type_name(self):
53+
return "SP.Sharing.SharingInformation"

office365/sharepoint/sharing/object_sharing_information_user.py

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import typing
2+
13
from office365.runtime.paths.resource_path import ResourcePath
24
from office365.sharepoint.base_entity import BaseEntity
35
from office365.sharepoint.principal.principal import Principal
@@ -7,6 +9,22 @@
79
class ObjectSharingInformationUser(BaseEntity):
810
"""Contains information about a principal with whom a securable object is shared. It can be a user or a group."""
911

12+
@property
13+
def email(self):
14+
"""
15+
Specifies the email address for the user.
16+
17+
:rtype: str or None
18+
"""
19+
return self.properties.get("Email", None)
20+
21+
@property
22+
def login_name(self):
23+
"""
24+
Specifies the login name for the principal.
25+
"""
26+
return self.properties.get("LoginName", None)
27+
1028
def principal(self):
1129
"""
1230
The principal with whom a securable object is shared. It is either a user or a group.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from office365.runtime.queries.service_operation import ServiceOperationQuery
2+
from office365.sharepoint.base_entity import BaseEntity
3+
from office365.sharepoint.sharing.information import SharingInformation
4+
from office365.sharepoint.sharing.information_request import SharingInformationRequest
5+
6+
7+
class SecurableObjectExtensions(BaseEntity):
8+
9+
@staticmethod
10+
def get_sharing_information(context):
11+
"""
12+
Gets the sharing information for a list item.
13+
14+
:param office365.sharepoint.client_context.ClientContext context: Client context
15+
"""
16+
return_type = SharingInformation(context)
17+
request = SharingInformationRequest()
18+
binding_type = SecurableObjectExtensions(context)
19+
qry = ServiceOperationQuery(binding_type, "GetSharingInformation", None, request, None, return_type, True)
20+
context.add_query(qry)
21+
return return_type
22+
23+
@property
24+
def entity_type_name(self):
25+
return "SP.Sharing.SecurableObjectExtensions"

0 commit comments

Comments
 (0)