Skip to content

Commit

Permalink
SharePoint API: get_user_effective_permissions method fix and example (
Browse files Browse the repository at this point in the history
…#407) File and Folder properties
  • Loading branch information
vgrem committed Sep 5, 2021
1 parent 2838678 commit d254f9a
Show file tree
Hide file tree
Showing 12 changed files with 246 additions and 44 deletions.
19 changes: 19 additions & 0 deletions examples/sharepoint/files/print_file_permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pprint import pprint

from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.permissions.permission_kind import PermissionKind
from tests import test_team_site_url, test_user_principal_name_alt, test_user_credentials

client = ClientContext(test_team_site_url).with_credentials(test_user_credentials)
file_url = "/sites/team/Shared Documents/report #123.csv"

# user = client.web.site_users.get_by_email(test_user_principal_name_alt).get().execute_query()
target_user = client.web.site_users.get_by_email(test_user_principal_name_alt)
target_file = client.web.get_file_by_server_relative_path(file_url)
result = target_file.listItemAllFields.get_user_effective_permissions(target_user).execute_query()
pprint(result.value.permission_levels) # print all permission levels

# verify whether user has Reader role to a file
if result.value.has(PermissionKind.OpenItems):
print("User has access to read a file")

4 changes: 2 additions & 2 deletions office365/sharepoint/contenttypes/content_type_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ def add_available_content_type(self, contentTypeId):
self.context.add_query(qry)
return ct

def add_existing_content_type(self, contentType):
def add_existing_content_type(self, content_type):
"""Adds an existing content type to the collection. The name of the given content type MUST NOT be the same
as any of the content types in the collection. A reference to the SP.ContentType that was added is returned.
:param ContentType contentType: Specifies the content type to be added to the collection
:param ContentType content_type: Specifies the content type to be added to the collection
"""
pass
108 changes: 107 additions & 1 deletion office365/sharepoint/files/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
from office365.runtime.queries.service_operation_query import ServiceOperationQuery
from office365.runtime.resource_path import ResourcePath
from office365.runtime.resource_path_service_operation import ResourcePathServiceOperation
from office365.sharepoint.base_entity_collection import BaseEntityCollection
from office365.sharepoint.files.file_version_event import FileVersionEvent
from office365.sharepoint.internal.download_file import create_download_file_query
from office365.sharepoint.base_entity import BaseEntity
from office365.sharepoint.directory.user import User
from office365.sharepoint.files.file_version_collection import FileVersionCollection
from office365.sharepoint.listitems.listitem import ListItem
from office365.sharepoint.permissions.information_rights_management_settings import InformationRightsManagementSettings
from office365.sharepoint.webparts.limited_webpart_manager import LimitedWebPartManager
from office365.sharepoint.types.resource_path import ResourcePath as SPResPath

Expand Down Expand Up @@ -48,6 +51,38 @@ def from_url(abs_url):
file = ctx.web.get_file_by_server_relative_url(file_relative_url)
return file

def get_image_preview_uri(self, width, height, client_type=None):
"""
:param int width:
:param int height:
:param str client_type:
"""
result = ClientResult(self.context)
payload = {
"width": width,
"height": height,
"clientType": client_type
}
qry = ServiceOperationQuery(self, "GetImagePreviewUri", None, payload, None, result)
self.context.add_query(qry)
return result

def get_image_preview_url(self, width, height, client_type=None):
"""
:param int width:
:param int height:
:param str client_type:
"""
result = ClientResult(self.context)
payload = {
"width": width,
"height": height,
"clientType": client_type
}
qry = ServiceOperationQuery(self, "GetImagePreviewUrl", None, payload, None, result)
self.context.add_query(qry)
return result

def recycle(self):
"""Moves the file to the Recycle Bin and returns the identifier of the new Recycle Bin item."""

Expand Down Expand Up @@ -201,6 +236,51 @@ def get_limited_webpart_manager(self, scope):
self.resource_path
))

def open_binary_stream(self):
"""Opens the file as a stream."""
return_stream = ClientResult(self.context)
qry = ServiceOperationQuery(self, "OpenBinaryStream", None, None, None, return_stream)
self.context.add_query(qry)
return return_stream

def save_binary_stream(self, stream):
"""Saves the file."""
qry = ServiceOperationQuery(self, "SaveBinaryStream", None, {"file": stream})
self.context.add_query(qry)
return self

def get_upload_status(self, upload_id):
payload = {
"uploadId": upload_id,
}
qry = ServiceOperationQuery(self, "GetUploadStatus", None, payload)
self.context.add_query(qry)
return self

def upload_with_checksum(self, upload_id, checksum, stream):
"""
:param str upload_id:
:param str checksum:
:param bytes stream:
"""
return_type = File(self.context)
payload = {
"uploadId": upload_id,
"checksum": checksum,
"stream": stream
}
qry = ServiceOperationQuery(self, "UploadWithChecksum", None, payload, None, return_type)
self.context.add_query(qry)
return return_type

def cancel_upload(self, upload_id):
payload = {
"uploadId": upload_id,
}
qry = ServiceOperationQuery(self, "CancelUpload", None, payload)
self.context.add_query(qry)
return self

def start_upload(self, upload_id, content):
"""Starts a new chunk upload session and uploads the first fragment.
Expand Down Expand Up @@ -324,6 +404,7 @@ def _construct_download_request(request):
"""
request.stream = True
request.method = HttpMethod.Get

self.context.before_execute(_construct_download_request)

def _process_download_response(response):
Expand All @@ -337,13 +418,35 @@ def _process_download_response(response):
if callable(chunk_downloaded):
chunk_downloaded(bytes_read)
file_object.write(chunk)

self.context.after_execute(_process_download_response)

self.context.add_query(qry)

self.ensure_property("ServerRelativeUrl", _download_as_stream)
return self

@property
def checked_out_by_user(self):
"""Gets an object that represents the user who has checked out the file."""
return self.properties.get('CheckedOutByUser',
User(self.context, ResourcePath("CheckedOutByUser", self.resource_path)))

@property
def version_events(self):
return self.properties.get("VersionEvents",
BaseEntityCollection(self.context,
FileVersionEvent,
ResourcePath("VersionEvents", self.resource_path)))

@property
def information_rights_management_settings(self):
return self.properties.get('InformationRightsManagementSettings',
InformationRightsManagementSettings(self.context,
ResourcePath(
"InformationRightsManagementSettings",
self.resource_path)))

@property
def listItemAllFields(self):
"""Gets a value that specifies the list item fields values for the list item corresponding to the file."""
Expand Down Expand Up @@ -387,7 +490,7 @@ def server_relative_path(self):
"""Gets the server-relative Path of the list folder.
:rtype: SPResPath or None
"""
return self.properties.get("ServerRelativePath", SPResPath(None))
return self.properties.get("ServerRelativePath", SPResPath())

@property
def length(self):
Expand Down Expand Up @@ -482,6 +585,9 @@ def unique_id(self):
def get_property(self, name, default_value=None):
if default_value is None:
property_mapping = {
"CheckedOutByUser": self.checked_out_by_user,
"VersionEvents": self.version_events,
"InformationRightsManagementSettings": self.information_rights_management_settings,
"LockedByUser": self.locked_by_user,
"ModifiedBy": self.modified_by
}
Expand Down
6 changes: 6 additions & 0 deletions office365/sharepoint/files/file_version_event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from office365.sharepoint.base_entity import BaseEntity


class FileVersionEvent(BaseEntity):
""""""
pass
13 changes: 12 additions & 1 deletion office365/sharepoint/folders/folder.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def _move_folder():

@property
def storage_metrics(self):
""""""
return self.properties.get("StorageMetrics",
StorageMetrics(self.context, ResourcePath("StorageMetrics", self.resource_path)))

Expand Down Expand Up @@ -227,6 +228,15 @@ def name(self):
"""
return self.properties.get("Name", None)

@property
def is_wopi_enabled(self):
return self.properties.get("IsWOPIEnabled", None)

@property
def prog_id(self):
"""Gets the identifier (ID) of the application in which the folder was created."""
return self.properties.get("ProgID", None)

@property
def unique_id(self):
"""Gets the unique ID of the folder.
Expand Down Expand Up @@ -293,7 +303,8 @@ def get_property(self, name, default_value=None):
"UniqueContentTypeOrder": self.unique_content_type_order,
"ListItemAllFields": self.list_item_all_fields,
"ParentFolder": self.parent_folder,
"ServerRelativePath": self.server_relative_path
"ServerRelativePath": self.server_relative_path,
"StorageMetrics": self.storage_metrics
}
default_value = property_mapping.get(name, None)
return super(Folder, self).get_property(name, default_value)
Expand Down
18 changes: 18 additions & 0 deletions office365/sharepoint/forms/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,21 @@

class Form(BaseEntity):
"""A form provides a display and editing interface for a single list item."""

@property
def form_type(self):
"""
Gets the type of the form.
:rtype: str or None
"""
return self.properties.get("FormType", None)

@property
def server_relative_url(self):
"""
Gets the server-relative URL of the form.
:rtype: str or None
"""
return self.properties.get("ServerRelativeUrl", None)
9 changes: 7 additions & 2 deletions office365/sharepoint/forms/form_collection.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from office365.runtime.resource_path_service_operation import ResourcePathServiceOperation
from office365.sharepoint.base_entity_collection import BaseEntityCollection
from office365.sharepoint.forms.form import Form

Expand All @@ -7,5 +8,9 @@ class FormCollection(BaseEntityCollection):
def __init__(self, context, resource_path=None):
super(FormCollection, self).__init__(context, Form, resource_path)

def get_by_page_type(self):
pass
def get_by_id(self, _id):
"""Gets the form with the specified ID."""
return Form(self.context, ResourcePathServiceOperation("GetById", [_id], self.resource_path))

def get_by_page_type(self, form_type):
return Form(self.context, ResourcePathServiceOperation("GetByPageType", [form_type], self.resource_path))
35 changes: 17 additions & 18 deletions office365/sharepoint/lists/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,33 +176,33 @@ def get_list_item_changes_since_token(self, query):
self.context.add_query(qry)
return result

def save_as_template(self, fileName, name, description, saveData):
def save_as_template(self, file_name, name, description, save_data):
"""
Saves the list as a template in the list template gallery and includes the option of saving with or
without the data that is contained in the current list.
:param bool saveData: true to save the data of the original list along with the list template; otherwise, false.
:param bool save_data: true to save the data of the original list along with the list template; otherwise, false.
:param str description: A string that contains the description for the list template.
:param str name: A string that contains the title for the list template.
:param str fileName: A string that contains the file name for the list template with an .stp extension.
:param str file_name: A string that contains the file name for the list template with an .stp extension.
:return:
"""
payload = {
"strFileName": fileName,
"strFileName": file_name,
"strName": name,
"strDescription": description,
"bSaveData": saveData
"bSaveData": save_data
}
qry = ServiceOperationQuery(self, "saveAsTemplate", None, payload, None, None)
self.context.add_query(qry)
return self

def get_item_by_unique_id(self, uniqueId):
def get_item_by_unique_id(self, unique_id):
"""
Returns the list item with the specified ID.
:param str uniqueId:"""
item = ListItem(self.context, ResourcePathServiceOperation("getItemByUniqueId", [uniqueId], self.resource_path))
:param str unique_id:"""
item = ListItem(self.context, ResourcePathServiceOperation("getItemByUniqueId", [unique_id], self.resource_path))
return item

def get_web_dav_url(self, source_url):
Expand Down Expand Up @@ -478,16 +478,15 @@ def parent_web_path(self):
return self.properties.get('ParentWebPath', None)

def get_property(self, name, default_value=None):
if name == "UserCustomActions":
default_value = self.user_custom_actions
elif name == "ParentWeb":
default_value = self.parent_web
elif name == "RootFolder":
default_value = self.root_folder
elif name == "ContentTypes":
default_value = self.content_types
elif name == "DefaultView":
default_value = self.default_view
if default_value is None:
property_mapping = {
"ContentTypes": self.content_types,
"DefaultView": self.default_view,
"ParentWeb": self.parent_web,
"RootFolder": self.root_folder,
"UserCustomActions": self.user_custom_actions
}
default_value = property_mapping.get(name, None)
return super(List, self).get_property(name, default_value)

def set_property(self, name, value, persist_changes=True):
Expand Down
3 changes: 1 addition & 2 deletions office365/sharepoint/permissions/base_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def set(self, perm):

def has(self, perm):
"""Determines whether the current instance has the specified permission.
"""
if perm == PermissionKind.EmptyMask:
return True
Expand All @@ -56,7 +55,7 @@ def clear_all(self):
self.Low = 0
self.High = 0

def to_json(self):
def to_json(self, json_format=None):
return {'Low': str(self.High), 'High': str(self.Low)}

@property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


class InformationRightsManagementSettings(BaseEntity):
"""Represents the Information Rights Management (IRM) settings of a list in Microsoft SharePoint Foundation."""

@property
def policy_title(self):
Expand Down
Loading

0 comments on commit d254f9a

Please sign in to comment.