Skip to content

Commit ae30fe8

Browse files
committed
Introduced support for SharePoint 2010 list data service, added methods/properties for Field/List resources
1 parent 1ac835f commit ae30fe8

14 files changed

+234
-49
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ python:
99
# optionally set up exclusions and allowed failures in the matrix
1010
matrix:
1111
allow_failures:
12-
- python: "3.3"
12+
- python: "3.3"
1313

1414
# command to run tests
1515
script: python setup.py test
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<AppPermissionRequests AllowAppOnlyPolicy="true">
2+
<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="Read"/>
3+
</AppPermissionRequests>

examples/sharepoint/file_operations.py

+58-7
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
import os
33

44
from office365.runtime.client_request import ClientRequest
5+
from office365.runtime.utilities.http_method import HttpMethod
56
from office365.runtime.utilities.request_options import RequestOptions
67
from office365.sharepoint.caml_query import CamlQuery
8+
from office365.sharepoint.list_data_service import ListDataService
79
from settings import settings
810
from office365.runtime.auth.authentication_context import AuthenticationContext
911
from office365.sharepoint.client_context import ClientContext
@@ -43,27 +45,27 @@ def read_folder_and_files(context, list_title):
4345
print("Folder name: {0}".format(folder.properties["Name"]))
4446

4547

46-
def upload_file_into_library(target_library, name, content):
47-
context = target_library.context
48+
def upload_file_alt(target_folder, name, content):
49+
context = target_folder.context
4850
info = FileCreationInformation()
4951
info.content = content
5052
info.url = name
5153
info.overwrite = True
52-
target_file = target_library.root_folder.files.add(info)
54+
target_file = target_folder.files.add(info)
5355
context.execute_query()
5456
return target_file
5557

5658

5759
def upload_file(context):
58-
upload_into_library = False
60+
upload_into_library = True
5961
path = "../tests/data/SharePoint User Guide.docx"
6062
with open(path, 'rb') as content_file:
6163
file_content = content_file.read()
6264

6365
if upload_into_library:
6466
list_title = "Documents"
65-
library = context.web.lists.get_by_title(list_title)
66-
file = upload_file_into_library(library, os.path.basename(path), file_content)
67+
target_folder = context.web.lists.get_by_title(list_title).root_folder
68+
file = upload_file_alt(target_folder, os.path.basename(path), file_content)
6769
print("File url: {0}".format(file.properties["ServerRelativeUrl"]))
6870
else:
6971
target_url = "/Shared Documents/{0}".format(os.path.basename(path))
@@ -77,7 +79,7 @@ def download_file(context):
7779

7880

7981
if __name__ == '__main__':
80-
site_url = 'https://mediadev8.sharepoint.com/sites/Team123'
82+
site_url = 'https://mediadev8.sharepoint.com/'
8183

8284
ctx_auth = AuthenticationContext(url=site_url)
8385
if ctx_auth.acquire_token_for_user(username=settings['user_credentials']['username'],
@@ -89,5 +91,54 @@ def download_file(context):
8991
# read_folder_and_files_alt(ctx, "Documents")
9092
# upload_file(ctx)
9193
# download_file(ctx)
94+
95+
file = ctx.web.get_file_by_server_relative_url("/Shared Documents/SharePoint User Guide.docx")
96+
ctx.load(file)
97+
ctx.execute_query()
98+
99+
path = "../data/SharePoint User Guide.docx"
100+
# with open(path, 'rb') as content_file:
101+
# file_content = content_file.read()
102+
# list_title = "Documents"
103+
# target_list = ctx.web.lists.get_by_title(list_title)
104+
# file = upload_file_alt(target_list.root_folder, os.path.basename(path), file_content)
105+
106+
# find out user id
107+
user = ctx.web.site_users.get_by_email("[email protected]")
108+
ctx.load(user)
109+
ctx.execute_query()
110+
user_id = user.properties['Id']
111+
user_field_value = json.dumps([{'Key': user.properties['LoginName']}])
112+
113+
# set file metadata
114+
list_item = file.listitem_allfields # get associated listItem
115+
116+
field_editor = list_item.parent_list.fields.get_by_internal_name_or_title("Modified By")
117+
ctx.load(field_editor)
118+
ctx.execute_query()
119+
120+
if field_editor.properties['ReadOnlyField']:
121+
field_editor.set_property('ReadOnlyField', False)
122+
field_editor.update()
123+
ctx.execute_query()
124+
125+
list_item.set_property("EditorId", user_id) # update ModifiedBy field value
126+
# list_item.set_property("ModifiedById", user_id) # update ModifiedBy field value
127+
# list_item.set_property("Comment", 'some comment goes here212aaa..')
128+
129+
# field_values = [
130+
# {"FieldName": 'Editor', "FieldValue": user_field_value},
131+
# ]
132+
# list_item.system_update(field_values, True)
133+
134+
list_svc = ListDataService(site_url, ctx_auth)
135+
#field_values = {"Comment": "Some comment goes here"}
136+
field_values = {"ModifiedById": 11}
137+
138+
# list_item = list_svc.get_list_item("Documents", 4)
139+
# list_svc.load(list_item)
140+
list_svc.update_list_item("Documents", 4, field_values)
141+
list_svc.execute_query()
142+
print("Ok")
92143
else:
93144
print(ctx_auth.get_last_error())

examples/sharepoint/listitem_operations.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ def read_list_items():
1919
def filter_list_items():
2020
print("OData query against list items example...")
2121
list_object = ctx.web.lists.get_by_title(listTitle)
22-
items = list_object.get_items().top(1).select("Id,Title")
22+
# items = list_object.get_items().top(1).select("Id,Title")
23+
items = list_object.get_items().select("Id,Title").filter("AssignedTo ne null")
2324
ctx.load(items)
2425
ctx.execute_query()
2526

@@ -38,11 +39,11 @@ def create_list_item():
3839

3940
if __name__ == '__main__':
4041
ctxAuth = AuthenticationContext(url=settings['url'])
41-
if ctxAuth.acquire_token_for_user(username=settings['username'], password=settings['password']):
42+
if ctxAuth.acquire_token_for_user(username=settings['user_credentials']['username'], password=settings['user_credentials']['password']):
4243
ctx = ClientContext(settings['url'], ctxAuth)
4344

44-
read_list_items()
45-
create_list_item()
45+
# read_list_items()
46+
# create_list_item()
4647
filter_list_items()
4748

4849
else:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from office365.runtime.auth.authentication_context import AuthenticationContext
2+
from office365.sharepoint.client_context import ClientContext
3+
from settings import settings
4+
5+
url = 'https://mediadev8.sharepoint.com/NewsArchive'
6+
settings['client_credentials']['client_id'] = '82e32e70-f031-4978-9fcd-1233db95990f'
7+
settings['client_credentials']['client_secret'] = '6rpUpc7O3M8loDFKE5H4auunS2geYL4Vs/pXUdjDSU0='
8+
9+
if __name__ == '__main__':
10+
context_auth = AuthenticationContext(url=url)
11+
if context_auth.acquire_token_for_app(client_id=settings['client_credentials']['client_id'],
12+
client_secret=settings['client_credentials']['client_secret']):
13+
ctx = ClientContext(url, context_auth)
14+
web = ctx.web
15+
ctx.load(web)
16+
ctx.execute_query()
17+
print("Web title: {0}".format(web.properties['Title']))
18+
19+
else:
20+
print(context_auth.get_last_error())

examples/sharepoint/sharepoint_client_flow_auth.py

-34
This file was deleted.

office365/sharepoint/field.py

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
from office365.runtime.client_object import ClientObject
2+
from office365.runtime.client_query import ClientQuery
23

34

45
class Field(ClientObject):
56
"""Represents a field in a SharePoint Web site"""
7+
8+
def update(self):
9+
"""Update the field."""
10+
qry = ClientQuery.update_entry_query(self)
11+
self.context.add_query(qry)
12+
13+
def delete_object(self):
14+
"""Deletes the field."""
15+
qry = ClientQuery.delete_entry_query(self)
16+
self.context.add_query(qry)
17+
self.remove_from_parent_collection()
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
from office365.runtime.client_object_collection import ClientObjectCollection
2+
from office365.runtime.client_query import ClientQuery
3+
from office365.runtime.resource_path_service_operation import ResourcePathServiceOperation
4+
from office365.sharepoint.field import Field
5+
6+
7+
class FieldCollection(ClientObjectCollection):
8+
"""Represents a collection of Field resource."""
9+
10+
def __init__(self, context, resource_path=None):
11+
super(FieldCollection, self).__init__(context, Field, resource_path)
12+
13+
def add(self, field_creation_information):
14+
"""Adds a field to the field collection."""
15+
field = Field(self.context)
16+
qry = ClientQuery.create_entry_query(self, field_creation_information)
17+
self.context.add_query(qry, field)
18+
self.add_child(field)
19+
return field
20+
21+
def get_by_id(self, _id):
22+
"""Gets the field with the specified ID."""
23+
return Field(self.context, ResourcePathServiceOperation(self.context, self.resource_path, "getById", [_id]))
24+
25+
def get_by_internal_name_or_title(self, name_title):
26+
"""Returns the first Field object with the specified internal name or title from the collection."""
27+
return Field(self.context,
28+
ResourcePathServiceOperation(self.context,
29+
self.resource_path,
30+
"getByInternalNameOrTitle", [name_title]))
31+
32+
def get_by_title(self, title):
33+
"""Returns the first field object in the collection based on the title of the specified field."""
34+
return Field(self.context,
35+
ResourcePathServiceOperation(self.context, self.resource_path, "getByTitle", [title]))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from office365.runtime.client_value_object import ClientValueObject
2+
3+
4+
class FieldCreationInformation(ClientValueObject):
5+
"""Represents metadata about field creation."""

office365/sharepoint/list.py

+9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from office365.runtime.resource_path_entity import ResourcePathEntity
44
from office365.runtime.resource_path_service_operation import ResourcePathServiceOperation
55
from office365.sharepoint.content_type_collection import ContentTypeCollection
6+
from office365.sharepoint.field_collection import FieldCollection
67
from office365.sharepoint.folder import Folder
78
from office365.sharepoint.listitem import ListItem
89
from office365.sharepoint.listItem_collection import ListItemCollection
@@ -63,6 +64,14 @@ def root_folder(self):
6364
else:
6465
return Folder(self.context, ResourcePathEntity(self.context, self.resource_path, "RootFolder"))
6566

67+
@property
68+
def fields(self):
69+
"""Gets a value that specifies the collection of all fields in the list."""
70+
if self.is_property_available('Fields'):
71+
return self.properties['Fields']
72+
else:
73+
return FieldCollection(self.context, ResourcePathEntity(self.context, self.resource_path, "Fields"))
74+
6675
@property
6776
def views(self):
6877
"""Gets a value that specifies the collection of all public views on the list and personal views
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from office365.runtime.action_type import ActionType
2+
from office365.runtime.client_query import ClientQuery
3+
from office365.runtime.client_runtime_context import ClientRuntimeContext
4+
from office365.runtime.odata.json_light_format import JsonLightFormat
5+
from office365.runtime.odata.odata_metadata_level import ODataMetadataLevel
6+
from office365.runtime.resource_path_service_operation import ResourcePathServiceOperation
7+
from office365.sharepoint.listitem import ListItem
8+
9+
10+
class ListDataService(ClientRuntimeContext):
11+
"""SharePoint 2010 list data service"""
12+
13+
def __init__(self, base_url, auth_context):
14+
if base_url.endswith("/"):
15+
base_url = base_url[:len(base_url) - 1]
16+
super(ListDataService, self).__init__(base_url + "/_vti_bin/listdata.svc/", auth_context)
17+
self.json_format = JsonLightFormat(ODataMetadataLevel.Verbose)
18+
19+
def get_list_item(self, list_name, item_id):
20+
return ListItem(self,
21+
ResourcePathServiceOperation(self, None, list_name, [item_id]))
22+
23+
def delete_list_item(self, list_name, item_id):
24+
resource_url = self.service_root_url + list_name + "(" + str(item_id) + ")"
25+
qry = ClientQuery(resource_url, ActionType.DeleteEntity)
26+
self.add_query(qry)
27+
28+
def update_list_item(self, list_name, item_id, field_values):
29+
resource_url = self.service_root_url + list_name + "(" + str(item_id) + ")"
30+
qry = ClientQuery(resource_url, ActionType.UpdateEntity, field_values)
31+
self.add_query(qry)
32+
33+
34+
35+
36+

office365/sharepoint/listitem.py

+38-2
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,58 @@
1+
from office365.runtime.action_type import ActionType
12
from office365.runtime.client_query import ClientQuery
23
from office365.runtime.odata.odata_path_parser import ODataPathParser
34
from office365.runtime.resource_path_entity import ResourcePathEntity
45
from office365.sharepoint.securable_object import SecurableObject
56

67

78
class ListItem(SecurableObject):
8-
"""ListItem client object resource"""
9+
"""ListItem resource"""
910

1011
def update(self):
11-
"""Update the list."""
12+
"""Update the list item."""
1213
qry = ClientQuery.update_entry_query(self)
1314
self.context.add_query(qry)
1415

16+
def validate_update_listItem(self, form_values, new_document_update):
17+
"""Validates and sets the values of the specified collection of fields for the list item."""
18+
qry = ClientQuery.service_operation_query(self,
19+
ActionType.PostMethod,
20+
"validateUpdateListItem",
21+
None,
22+
{
23+
"formValues": form_values,
24+
"bNewDocumentUpdate": new_document_update,
25+
})
26+
self.context.add_query(qry)
27+
28+
def system_update(self):
29+
"""Update the list item."""
30+
qry = ClientQuery.service_operation_query(self,
31+
ActionType.PostMethod,
32+
"systemUpdate")
33+
self.context.add_query(qry)
34+
35+
def update_overwrite_version(self):
36+
"""Update the list item."""
37+
qry = ClientQuery.service_operation_query(self,
38+
ActionType.PostMethod,
39+
"updateOverwriteVersion")
40+
self.context.add_query(qry)
41+
1542
def delete_object(self):
1643
"""Deletes the list."""
1744
qry = ClientQuery.delete_entry_query(self)
1845
self.context.add_query(qry)
1946

47+
@property
48+
def parent_list(self):
49+
"""Get parent List"""
50+
if self.is_property_available("ParentList"):
51+
return self.properties["ParentList"]
52+
else:
53+
from office365.sharepoint.list import List
54+
return List(self.context, ResourcePathEntity(self.context, self.resource_path, "ParentList"))
55+
2056
@property
2157
def file(self):
2258
"""Get file"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from office365.runtime.client_object import ClientObject
2+
3+
4+
class ClientSidePage(ClientObject):
5+
"""Represents the data and methods associated with client side "modern" pages"""
6+
7+
@staticmethod
8+
def from_file(file):
9+
return None
10+
11+

0 commit comments

Comments
 (0)