diff --git a/examples/directory/users/update.py b/examples/directory/users/update.py index 449644cdb..7af0a3d49 100644 --- a/examples/directory/users/update.py +++ b/examples/directory/users/update.py @@ -10,7 +10,12 @@ client = GraphClient.with_username_and_password( test_tenant, test_client_id, test_username, test_password ) -users = client.users.get().filter("startswith(displayName, 'testuser')").top(1).execute_query() +users = ( + client.users.get() + .filter("startswith(displayName, 'testuser')") + .top(1) + .execute_query() +) for u in users: - u.set_property('officeLocation', "18/2111").update().execute_query() + u.set_property("officeLocation", "18/2111").update().execute_query() diff --git a/examples/directory/users/update_batch.py b/examples/directory/users/update_batch.py index 4ffb218e6..3c4186678 100644 --- a/examples/directory/users/update_batch.py +++ b/examples/directory/users/update_batch.py @@ -10,11 +10,14 @@ client = GraphClient.with_username_and_password( test_tenant, test_client_id, test_username, test_password ) -users = client.users.get().filter("startswith(displayName, 'testuser')").top(50).execute_query() +users = ( + client.users.get() + .filter("startswith(displayName, 'testuser')") + .top(50) + .execute_query() +) for u in users: - u.set_property('officeLocation', "18/2111").update() + u.set_property("officeLocation", "18/2111").update() client.execute_batch() - - diff --git a/examples/sharepoint/tenant/get_my_sites.py b/examples/sharepoint/tenant/get_my_sites.py index a9bb452d1..99ba3dc91 100644 --- a/examples/sharepoint/tenant/get_my_sites.py +++ b/examples/sharepoint/tenant/get_my_sites.py @@ -1,33 +1,14 @@ -from office365.runtime.client_request_exception import ClientRequestException -from office365.sharepoint.client_context import ClientContext -from office365.sharepoint.tenant.administration.tenant import Tenant -from tests import test_admin_credentials, test_admin_site_url, test_user_principal_name - -admin_client = ClientContext(test_admin_site_url).with_credentials( - test_admin_credentials -) -tenant = Tenant(admin_client) -result = tenant.get_site_properties_from_sharepoint_by_filters("").execute_query() +""" +Gets my sites +""" +from office365.sharepoint.client_context import ClientContext +from tests import test_site_url, test_user_credentials -def try_get_user_permissions(site_url, user_name): - ctx = ClientContext(site_url).with_credentials(test_admin_credentials) - try: - ctx.web.get_user_effective_permissions(user_name).execute_query() - # todo: determine user permissions from result - return True - except ClientRequestException as e: - if e.response.status_code == 404: - return False - else: - raise ValueError(e.response.text) - +client = ClientContext(test_site_url).with_credentials(test_user_credentials) -for siteProps in result: - print("Current site url: {0}".format(siteProps.url)) - if try_get_user_permissions(siteProps.url, test_user_principal_name) is True: - print( - "Site url {0} {1} user has access to".format( - siteProps.url, test_user_principal_name - ) - ) +result = client.search.query("contentclass:STS_Site").execute_query() +results = result.value.PrimaryQueryResult.RelevantResults +for row in results.Table.Rows: + site_url = row.Cells["Path"] + print(site_url) diff --git a/office365/sharepoint/apps/access_requests.py b/office365/sharepoint/apps/access_requests.py new file mode 100644 index 000000000..4aec66ad5 --- /dev/null +++ b/office365/sharepoint/apps/access_requests.py @@ -0,0 +1,5 @@ +from office365.sharepoint.entity import Entity + + +class AccessRequests(Entity): + """ """ diff --git a/office365/sharepoint/lists/list.py b/office365/sharepoint/lists/list.py index 37d47eddf..afc506e40 100644 --- a/office365/sharepoint/lists/list.py +++ b/office365/sharepoint/lists/list.py @@ -45,6 +45,7 @@ from office365.sharepoint.lists.creatables_info import CreatablesInfo from office365.sharepoint.lists.data_source import ListDataSource from office365.sharepoint.lists.rule import SPListRule +from office365.sharepoint.lists.version_policy_manager import VersionPolicyManager from office365.sharepoint.navigation.configured_metadata_items import ( ConfiguredMetadataNavigationItemCollection, ) @@ -131,8 +132,8 @@ def _save_schema(): "FileSystemObjectType", ] ) - # .expand(["File", "Folder"]) - .get().paged(page_loaded=_export_items) + .get() + .paged(page_loaded=_export_items) ) self.ensure_properties(["SchemaXml", "RootFolder"], _save_schema) @@ -1128,6 +1129,16 @@ def user_custom_actions(self): ), ) + @property + def version_policies(self): + """ """ + return self.properties.get( + "VersionPolicies", + VersionPolicyManager( + self.context, ResourcePath("VersionPolicies", self.resource_path) + ), + ) + @property def custom_action_elements(self): return self.properties.get( @@ -1408,6 +1419,7 @@ def get_property(self, name, default_value=None): "RootFolder": self.root_folder, "TitleResource": self.title_resource, "UserCustomActions": self.user_custom_actions, + "VersionPolicies": self.version_policies, } default_value = property_mapping.get(name, None) return super(List, self).get_property(name, default_value) @@ -1420,4 +1432,8 @@ def set_property(self, name, value, persist_changes=True): self._resource_path = self.parent_collection.get_by_id( value ).resource_path + elif name == "Url": + self._resource_path = ServiceOperationPath( + "getList", [value], self.context.web.resource_path + ) return self diff --git a/office365/sharepoint/lists/version_policy_manager.py b/office365/sharepoint/lists/version_policy_manager.py new file mode 100644 index 000000000..22af97379 --- /dev/null +++ b/office365/sharepoint/lists/version_policy_manager.py @@ -0,0 +1,5 @@ +from office365.sharepoint.entity import Entity + + +class VersionPolicyManager(Entity): + """ """ diff --git a/office365/sharepoint/portal/userprofiles/documents_shared_with_group.py b/office365/sharepoint/portal/userprofiles/documents_shared_with_group.py index 2700d578f..da1b829d3 100644 --- a/office365/sharepoint/portal/userprofiles/documents_shared_with_group.py +++ b/office365/sharepoint/portal/userprofiles/documents_shared_with_group.py @@ -1,4 +1,7 @@ +from office365.runtime.queries.service_operation import ServiceOperationQuery from office365.sharepoint.entity import Entity +from office365.sharepoint.entity_collection import EntityCollection +from office365.sharepoint.userprofiles.sharedwithme.document import SharedWithMeDocument class DocumentsSharedWithGroup(Entity): @@ -6,6 +9,28 @@ class DocumentsSharedWithGroup(Entity): Provides methods for working with a list that shares documents with a SharePoint Group on the user's personal site. """ + @staticmethod + def get_shared_with_group_docs(context, group_id=None): + """ + Gets a shared documents for a group. + + :param office365.sharepoint.client_context.ClientContext context: SharePoint context + :param str group_id: + """ + return_type = EntityCollection(context, SharedWithMeDocument) + payload = {"groupId": group_id} + qry = ServiceOperationQuery( + DocumentsSharedWithGroup(context), + "GetSharedWithGroupDocs", + None, + payload, + None, + return_type, + True, + ) + context.add_query(qry) + return return_type + @property def entity_type_name(self): - return "Microsoft.SharePoint.Portal.UserProfiles.DocumentsSharedWithGroup" + return "Microsoft.SharePoint.Portal.UserProfiles.group_id" diff --git a/office365/sharepoint/publishing/pages/coauth_state.py b/office365/sharepoint/publishing/pages/coauth_state.py new file mode 100644 index 000000000..6ee5d444c --- /dev/null +++ b/office365/sharepoint/publishing/pages/coauth_state.py @@ -0,0 +1,8 @@ +from office365.runtime.client_value import ClientValue + + +class SitePageCoAuthState(ClientValue): + + @property + def entity_type_name(self): + return "SP.Publishing.SitePageCoAuthState" diff --git a/office365/sharepoint/publishing/pages/page.py b/office365/sharepoint/publishing/pages/page.py index 54ba2fc1f..05bee7185 100644 --- a/office365/sharepoint/publishing/pages/page.py +++ b/office365/sharepoint/publishing/pages/page.py @@ -5,6 +5,7 @@ from office365.runtime.paths.resource_path import ResourcePath from office365.runtime.queries.service_operation import ServiceOperationQuery from office365.runtime.types.collections import StringCollection +from office365.sharepoint.publishing.pages.coauth_state import SitePageCoAuthState from office365.sharepoint.publishing.pages.fields_data import SitePageFieldsData from office365.sharepoint.publishing.pages.metadata import SitePageMetadata from office365.sharepoint.translation.status_collection import ( @@ -135,6 +136,16 @@ def save_page_as_template(self): self.context.add_query(qry) return return_type + def save_page_co_auth(self, page_stream): + """ """ + return_type = ClientResult(self.context, SitePageCoAuthState()) + payload = {"pageStream": page_stream} + qry = ServiceOperationQuery( + self, "SavePageCoAuth", None, payload, None, return_type + ) + self.context.add_query(qry) + return return_type + def demote_from_news(self): """ Updates the promoted state of the site page to 0. On success MUST return true. diff --git a/office365/sharepoint/publishing/pages/stream_content.py b/office365/sharepoint/publishing/pages/stream_content.py new file mode 100644 index 000000000..f4d63f288 --- /dev/null +++ b/office365/sharepoint/publishing/pages/stream_content.py @@ -0,0 +1,9 @@ +from office365.runtime.client_value import ClientValue + + +class SitePageStreamContent(ClientValue): + """ """ + + @property + def entity_type_name(self): + return "SP.Publishing.SitePageStreamContent" diff --git a/office365/sharepoint/publishing/pages/stream_data.py b/office365/sharepoint/publishing/pages/stream_data.py new file mode 100644 index 000000000..0db9c4270 --- /dev/null +++ b/office365/sharepoint/publishing/pages/stream_data.py @@ -0,0 +1,8 @@ +from office365.runtime.client_value import ClientValue + + +class SitePageStreamData(ClientValue): + + @property + def entity_type_name(self): + return "SP.Publishing.SitePageStreamData" diff --git a/office365/sharepoint/quotamanagement/consumer/non_quota_backfill_api.py b/office365/sharepoint/quotamanagement/consumer/non_quota_backfill_api.py new file mode 100644 index 000000000..868646e12 --- /dev/null +++ b/office365/sharepoint/quotamanagement/consumer/non_quota_backfill_api.py @@ -0,0 +1,8 @@ +from office365.sharepoint.entity import Entity + + +class NonQuotaBackfillApi(Entity): + + @property + def entity_type_name(self): + return "Microsoft.SharePoint.QuotaManagement.Consumer.NonQuotaBackfillApi" diff --git a/office365/sharepoint/search/administration/site_content_processing_info_provider.py b/office365/sharepoint/search/administration/site_content_processing_info_provider.py index e262d5a45..fc0bc2edf 100644 --- a/office365/sharepoint/search/administration/site_content_processing_info_provider.py +++ b/office365/sharepoint/search/administration/site_content_processing_info_provider.py @@ -1,7 +1,18 @@ +from office365.runtime.client_result import ClientResult +from office365.runtime.queries.service_operation import ServiceOperationQuery from office365.sharepoint.entity import Entity class SiteContentProcessingInfoProvider(Entity): + + def get_azure_container_token(self): + return_type = ClientResult(self.context, str()) + qry = ServiceOperationQuery( + self, "GetAzureContainerToken", None, None, None, return_type + ) + self.context.add_query(qry) + return return_type + @property def entity_type_name(self): return "Microsoft.SharePoint.Client.Search.Administration.SiteContentProcessingInfoProvider" diff --git a/office365/sharepoint/search/ranking_labeling.py b/office365/sharepoint/search/ranking_labeling.py index e92a9717a..a77f51244 100644 --- a/office365/sharepoint/search/ranking_labeling.py +++ b/office365/sharepoint/search/ranking_labeling.py @@ -28,6 +28,7 @@ def add_judgment(self, user_query, url, label_id): return self def normalize_result_url(self, url): + # type: (str) -> ClientResult[str] """ A URL string after normalization. The input and output URL strings MUST resolve to the same document. diff --git a/office365/sharepoint/search/reports/abandonedqueries/__init__.py b/office365/sharepoint/search/reports/abandonedqueries/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/search/reports/abandonedqueries/data.py b/office365/sharepoint/search/reports/abandonedqueries/data.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/search/reports/abandonedqueries/item.py b/office365/sharepoint/search/reports/abandonedqueries/item.py new file mode 100644 index 000000000..60e4e832a --- /dev/null +++ b/office365/sharepoint/search/reports/abandonedqueries/item.py @@ -0,0 +1,5 @@ +from office365.runtime.client_value import ClientValue + + +class ReportAbandonedQueriesItem(ClientValue): + pass diff --git a/office365/sharepoint/search/reports/noresult/__init__.py b/office365/sharepoint/search/reports/noresult/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/search/reports/numberofqueries/__init__.py b/office365/sharepoint/search/reports/numberofqueries/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/search/reports/top_queries.py b/office365/sharepoint/search/reports/top_queries.py index fba960d7d..854a484c1 100644 --- a/office365/sharepoint/search/reports/top_queries.py +++ b/office365/sharepoint/search/reports/top_queries.py @@ -1,7 +1,14 @@ +from office365.runtime.client_value_collection import ClientValueCollection from office365.sharepoint.search.reports.base import ReportBase +from office365.sharepoint.search.reports.topqueries.item import ReportTopQueriesItem class ReportTopQueries(ReportBase): + + def __init__(self, reports=None): + super(ReportTopQueries, self).__init__() + self.Reports = ClientValueCollection(ReportTopQueriesItem, reports) + @property def entity_type_name(self): return "Microsoft.Office.Server.Search.REST.ReportTopQueries" diff --git a/office365/sharepoint/search/reports/topqueries/__init__.py b/office365/sharepoint/search/reports/topqueries/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/search/reports/topqueries/data.py b/office365/sharepoint/search/reports/topqueries/data.py new file mode 100644 index 000000000..c4ac36583 --- /dev/null +++ b/office365/sharepoint/search/reports/topqueries/data.py @@ -0,0 +1,9 @@ +from office365.runtime.client_value import ClientValue + + +class ReportTopQueriesData(ClientValue): + """ """ + + @property + def entity_type_name(self): + return "Microsoft.Office.Server.Search.REST.ReportTopQueriesData" diff --git a/office365/sharepoint/search/reports/topqueries/item.py b/office365/sharepoint/search/reports/topqueries/item.py new file mode 100644 index 000000000..e5b7b10ee --- /dev/null +++ b/office365/sharepoint/search/reports/topqueries/item.py @@ -0,0 +1,15 @@ +from office365.runtime.client_value import ClientValue +from office365.runtime.client_value_collection import ClientValueCollection +from office365.sharepoint.search.reports.topqueries.data import ReportTopQueriesData + + +class ReportTopQueriesItem(ClientValue): + """ """ + + def __init__(self, date=None, report=None): + self.Date = date + self.Report = ClientValueCollection(ReportTopQueriesData, report) + + @property + def entity_type_name(self): + return "Microsoft.Office.Server.Search.REST.ReportTopQueriesItem" diff --git a/office365/sharepoint/search/scs_endpoint.py b/office365/sharepoint/search/scs_endpoint.py new file mode 100644 index 000000000..fec9f9a36 --- /dev/null +++ b/office365/sharepoint/search/scs_endpoint.py @@ -0,0 +1,9 @@ +from office365.runtime.client_value import ClientValue + + +class ScsEndpoint(ClientValue): + """ """ + + @property + def entity_type_name(self): + return "Microsoft.Office.Server.Search.REST.ScsEndpoint" diff --git a/office365/sharepoint/sites/version_policy_manager.py b/office365/sharepoint/sites/version_policy_manager.py index 9964c30b0..3110866be 100644 --- a/office365/sharepoint/sites/version_policy_manager.py +++ b/office365/sharepoint/sites/version_policy_manager.py @@ -1,7 +1,9 @@ from typing import Optional +from office365.runtime.paths.resource_path import ResourcePath from office365.runtime.queries.service_operation import ServiceOperationQuery from office365.sharepoint.entity import Entity +from office365.sharepoint.lists.version_policy_manager import VersionPolicyManager class SiteVersionPolicyManager(Entity): @@ -13,8 +15,31 @@ def major_version_limit(self): """ """ return self.properties.get("MajorVersionLimit", None) + @property + def version_policies(self): + return self.properties.get( + "VersionPolicies", + VersionPolicyManager( + self.context, ResourcePath("VersionPolicies", self.resource_path) + ), + ) + + def inherit_tenant_settings(self): + """ """ + qry = ServiceOperationQuery(self, "InheritTenantSettings") + self.context.add_query(qry) + return self + def set_auto_expiration(self): """""" qry = ServiceOperationQuery(self, "SetAutoExpiration") self.context.add_query(qry) return self + + def get_property(self, name, default_value=None): + if default_value is None: + property_mapping = { + "VersionPolicies": self.version_policies, + } + default_value = property_mapping.get(name, None) + return super(SiteVersionPolicyManager, self).get_property(name, default_value) diff --git a/office365/sharepoint/sitescripts/utility.py b/office365/sharepoint/sitescripts/utility.py index 0f9df1fa5..a4176aa43 100644 --- a/office365/sharepoint/sitescripts/utility.py +++ b/office365/sharepoint/sitescripts/utility.py @@ -42,6 +42,23 @@ def create_list_design(context, info): context.add_query(qry) return return_type + @staticmethod + def get_list_designs(context, store=None): + """ + Gets a list designs. + + :param office365.sharepoint.client_context.ClientContext context: SharePoint context + :param str store: + """ + return_type = ClientResult(context, SiteDesignMetadata()) + utility = SiteScriptUtility(context) + payload = {"store": store} + qry = ServiceOperationQuery( + utility, "GetListDesigns", None, payload, None, return_type, True + ) + context.add_query(qry) + return return_type + @staticmethod def add_site_design_task(context, web_url, site_design_id): """ diff --git a/office365/sharepoint/tenant/administration/internal/aad/__init__.py b/office365/sharepoint/tenant/administration/internal/aad/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/tenant/administration/internal/aad/permission_grant.py b/office365/sharepoint/tenant/administration/internal/aad/permission_grant.py new file mode 100644 index 000000000..2727367f0 --- /dev/null +++ b/office365/sharepoint/tenant/administration/internal/aad/permission_grant.py @@ -0,0 +1,32 @@ +from typing_extensions import Self + +from office365.runtime.queries.service_operation import ServiceOperationQuery +from office365.sharepoint.entity import Entity +from office365.sharepoint.entity_collection import EntityCollection + + +class SPO3rdPartyAADPermissionGrant(Entity): + @property + def entity_type_name(self): + return "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPO3rdPartyAADPermissionGrant" + + +class SPO3rdPartyAADPermissionGrantCollection( + EntityCollection[SPO3rdPartyAADPermissionGrant] +): + + def __init__(self, context, resource_path=None): + super(SPO3rdPartyAADPermissionGrantCollection, self).__init__( + context, SPO3rdPartyAADPermissionGrant, resource_path + ) + + def add(self, service_principal_id, resource, scope): + # type: (str, str, str) -> Self + payload = { + "servicePrincipalId": service_principal_id, + "resource": resource, + "scope": scope, + } + qry = ServiceOperationQuery(self, "Add", None, payload) + self.context.add_query(qry) + return self diff --git a/office365/sharepoint/tenant/administration/internal/appservice/__init__.py b/office365/sharepoint/tenant/administration/internal/appservice/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/office365/sharepoint/tenant/administration/internal/appservice/permission_grant.py b/office365/sharepoint/tenant/administration/internal/appservice/permission_grant.py new file mode 100644 index 000000000..262ba6884 --- /dev/null +++ b/office365/sharepoint/tenant/administration/internal/appservice/permission_grant.py @@ -0,0 +1,5 @@ +from office365.sharepoint.entity import Entity + + +class SPOWebAppServicePrincipalPermissionGrant(Entity): + """""" diff --git a/office365/sharepoint/tenant/administration/internal/permission_grant.py b/office365/sharepoint/tenant/administration/internal/appservice/permission_request.py similarity index 55% rename from office365/sharepoint/tenant/administration/internal/permission_grant.py rename to office365/sharepoint/tenant/administration/internal/appservice/permission_request.py index c0bc861be..bdc515b83 100644 --- a/office365/sharepoint/tenant/administration/internal/permission_grant.py +++ b/office365/sharepoint/tenant/administration/internal/appservice/permission_request.py @@ -1,7 +1,9 @@ from office365.sharepoint.entity import Entity -class SPO3rdPartyAADPermissionGrant(Entity): +class SPOWebAppServicePrincipalPermissionRequest(Entity): + """ """ + @property def entity_type_name(self): - return "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPO3rdPartyAADPermissionGrant" + return "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPOWebAppServicePrincipalPermissionRequest" diff --git a/office365/sharepoint/tenant/administration/internal/appservice/principal.py b/office365/sharepoint/tenant/administration/internal/appservice/principal.py new file mode 100644 index 000000000..277cbbe58 --- /dev/null +++ b/office365/sharepoint/tenant/administration/internal/appservice/principal.py @@ -0,0 +1,104 @@ +from typing import Optional + +from office365.runtime.paths.resource_path import ResourcePath +from office365.runtime.queries.service_operation import ServiceOperationQuery +from office365.runtime.types.collections import StringCollection +from office365.sharepoint.entity import Entity +from office365.sharepoint.entity_collection import EntityCollection +from office365.sharepoint.tenant.administration.internal.aad.permission_grant import ( + SPO3rdPartyAADPermissionGrantCollection, +) +from office365.sharepoint.tenant.administration.internal.appservice.permission_grant import ( + SPOWebAppServicePrincipalPermissionGrant, +) +from office365.sharepoint.tenant.administration.internal.appservice.permission_request import ( + SPOWebAppServicePrincipalPermissionRequest, +) + + +class SPOWebAppServicePrincipal(Entity): + def __init__(self, context): + stat_path = ResourcePath( + "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPOWebAppServicePrincipal" + ) + super(SPOWebAppServicePrincipal, self).__init__(context, stat_path) + + def update_spfx_client_secret(self, secret_value): + """ + :param str secret_value: + """ + payload = {"secretValue": secret_value} + qry = ServiceOperationQuery(self, "UpdateSpfxClientSecret", None, payload) + self.context.add_query(qry) + return self + + def update_spfx_third_party_app_id(self, app_id): + payload = {"appId": app_id} + qry = ServiceOperationQuery(self, "UpdateSpfxThirdPartyAppId", None, payload) + self.context.add_query(qry) + return self + + @property + def account_enabled(self): + # type: () -> Optional[bool] + """ """ + return self.properties.get("AccountEnabled", False) + + @property + def app_id(self): + # type: () -> Optional[str] + """ """ + return self.properties.get("AppId", False) + + @property + def reply_urls(self): + # type: () -> StringCollection + """ """ + return self.properties.get("ReplyUrls", StringCollection()) + + @property + def grant_manager(self): + return self.properties.get( + "GrantManager", + SPO3rdPartyAADPermissionGrantCollection( + self.context, + ResourcePath("GrantManager", self.resource_path), + ), + ) + + @property + def permission_grants(self): + return self.properties.get( + "PermissionGrants", + EntityCollection( + self.context, + SPOWebAppServicePrincipalPermissionGrant, + ResourcePath("PermissionGrants", self.resource_path), + ), + ) + + @property + def permission_requests(self): + return self.properties.get( + "PermissionRequests", + EntityCollection( + self.context, + SPOWebAppServicePrincipalPermissionRequest, + ResourcePath("PermissionRequests", self.resource_path), + ), + ) + + @property + def entity_type_name(self): + return "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPOWebAppServicePrincipal" + + def get_property(self, name, default_value=None): + if default_value is None: + property_mapping = { + "GrantManager": self.grant_manager, + "PermissionRequests": self.permission_requests, + "PermissionGrants": self.permission_grants, + "ReplyUrls": self.reply_urls, + } + default_value = property_mapping.get(name, None) + return super(SPOWebAppServicePrincipal, self).get_property(name, default_value) diff --git a/office365/sharepoint/tenant/administration/internal/web_appservice_principal.py b/office365/sharepoint/tenant/administration/internal/web_appservice_principal.py deleted file mode 100644 index 616f13ab5..000000000 --- a/office365/sharepoint/tenant/administration/internal/web_appservice_principal.py +++ /dev/null @@ -1,23 +0,0 @@ -from office365.runtime.paths.resource_path import ResourcePath -from office365.runtime.queries.service_operation import ServiceOperationQuery -from office365.sharepoint.entity import Entity - - -class SPOWebAppServicePrincipal(Entity): - def __init__(self, context): - stat_path = ResourcePath( - "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPOWebAppServicePrincipal" - ) - super(SPOWebAppServicePrincipal, self).__init__(context, stat_path) - - def update_spfx_client_secret(self, secret_value): - """ - :param str secret_value: - """ - payload = {"secretValue": secret_value} - qry = ServiceOperationQuery(self, "UpdateSpfxClientSecret", None, payload) - self.context.add_query(qry) - - @property - def entity_type_name(self): - return "Microsoft.Online.SharePoint.TenantAdministration.Internal.SPOWebAppServicePrincipal" diff --git a/office365/sharepoint/tenant/administration/tenant.py b/office365/sharepoint/tenant/administration/tenant.py index 88e7f9c19..c584ea9f3 100644 --- a/office365/sharepoint/tenant/administration/tenant.py +++ b/office365/sharepoint/tenant/administration/tenant.py @@ -749,6 +749,41 @@ def default_content_center_site(self): """""" return self.properties.get("DefaultContentCenterSite", SiteInfoForSitePicker()) + @property + def no_access_redirect_url(self): + # type: () -> Optional[bool] + """Specifies the URL of the redirected site for those site collections which have the locked state "NoAccess""" + return self.properties.get("NoAccessRedirectUrl", None) + + @property + def notifications_in_share_point_enabled(self): + # type: () -> Optional[bool] + """Enables or disables notifications in SharePoint.""" + return self.properties.get("NotificationsInSharePointEnabled", None) + + @property + def notify_owners_when_invitations_accepted(self): + # type: () -> Optional[bool] + """When this parameter is set to true and when an external user accepts an invitation to a resource + in a user's OneDrive for Business, the OneDrive for Business owner is notified by e-mail. + """ + return self.properties.get("NotifyOwnersWhenInvitationsAccepted", None) + + @property + def one_drive_storage_quota(self): + # type: () -> Optional[int] + """Gets a default OneDrive for Business storage quota for the tenant. It will be used for new OneDrive + for Business sites created.""" + return self.properties.get("OneDriveStorageQuota", None) + + @property + def notify_owners_when_items_reshared(self): + # type: () -> Optional[bool] + """When is set to true and another user re-shares a document from a + user's OneDrive for Business, the OneDrive for Business owner is notified by e-mail. + """ + return self.properties.get("NotifyOwnersWhenItemsReshared", None) + @property def root_site_url(self): # type: () -> Optional[str] diff --git a/office365/sharepoint/tenant/cdn_api.py b/office365/sharepoint/tenant/cdn_api.py index 2829cd4dc..5e2689cb1 100644 --- a/office365/sharepoint/tenant/cdn_api.py +++ b/office365/sharepoint/tenant/cdn_api.py @@ -13,7 +13,9 @@ def __init__(self, context): ) def get_cdn_urls(self, items=None): - """""" + """ + :param list[str] items: + """ payload = { "items": items, } diff --git a/office365/sharepoint/tenant/management/office365_tenant.py b/office365/sharepoint/tenant/management/office365_tenant.py index 4704d0b73..c2180ced3 100644 --- a/office365/sharepoint/tenant/management/office365_tenant.py +++ b/office365/sharepoint/tenant/management/office365_tenant.py @@ -205,6 +205,8 @@ def revoke_all_user_sessions(self, user): def _revoke_all_user_sessions(login_name): """ + Logouts a user's sessions across all their devices + :type login_name: str """ qry = ServiceOperationQuery( diff --git a/office365/sharepoint/tenant/settings.py b/office365/sharepoint/tenant/settings.py index 3da013bdc..ba008ab0d 100644 --- a/office365/sharepoint/tenant/settings.py +++ b/office365/sharepoint/tenant/settings.py @@ -1,5 +1,6 @@ from typing import Optional +from office365.runtime.client_result import ClientResult from office365.runtime.paths.resource_path import ResourcePath from office365.runtime.queries.service_operation import ServiceOperationQuery from office365.sharepoint.entity import Entity @@ -16,6 +17,15 @@ def clear_corporate_catalog(self): self.context.add_query(qry) return self + def get_data_access_governance_report_config(self): + """ """ + return_type = ClientResult(self.context, str()) + qry = ServiceOperationQuery( + self, "GetDataAccessGovernanceReportConfig", None, None, None, return_type + ) + self.context.add_query(qry) + return return_type + def set_corporate_catalog(self, url): """ :param str url: diff --git a/office365/sharepoint/utilities/utility.py b/office365/sharepoint/utilities/utility.py index 664b5b890..45aef8f8b 100644 --- a/office365/sharepoint/utilities/utility.py +++ b/office365/sharepoint/utilities/utility.py @@ -1,3 +1,5 @@ +from typing import TYPE_CHECKING + from office365.runtime.client_result import ClientResult from office365.runtime.client_value_collection import ClientValueCollection from office365.runtime.paths.resource_path import ResourcePath @@ -8,6 +10,9 @@ from office365.sharepoint.types.resource_path import ResourcePath as SPResPath from office365.sharepoint.utilities.principal_info import PrincipalInfo +if TYPE_CHECKING: + from office365.sharepoint.client_context import ClientContext + class Utility(Entity): """ @@ -161,6 +166,7 @@ def expand_groups_to_principals(context, inputs, max_count=None, return_type=Non @staticmethod def log_custom_app_error(context, error): + # type: (ClientContext, str) -> ClientResult[int] """ Logs an error from a SharePoint Add-in. The return value indicates the success or failure of this operation. These errors are of interest to administrators who monitor such apps (2). diff --git a/office365/sharepoint/viva/connections_page.py b/office365/sharepoint/viva/connections_page.py new file mode 100644 index 000000000..48b024925 --- /dev/null +++ b/office365/sharepoint/viva/connections_page.py @@ -0,0 +1,8 @@ +from office365.sharepoint.entity import Entity + + +class VivaConnectionsPage(Entity): + + @property + def entity_type_name(self): + return "Microsoft.SharePoint.EmployeeEngagement.VivaConnectionsPage" diff --git a/office365/sharepoint/viva/dashboard_configuration.py b/office365/sharepoint/viva/dashboard_configuration.py new file mode 100644 index 000000000..6e03d313e --- /dev/null +++ b/office365/sharepoint/viva/dashboard_configuration.py @@ -0,0 +1,8 @@ +from office365.runtime.client_value import ClientValue + + +class DashboardConfiguration(ClientValue): + + @property + def entity_type_name(self): + return "Microsoft.SharePoint.EmployeeEngagement.DashboardConfiguration" diff --git a/office365/sharepoint/viva/employee_engagement.py b/office365/sharepoint/viva/employee_engagement.py index 971158537..1a8aa8c8b 100644 --- a/office365/sharepoint/viva/employee_engagement.py +++ b/office365/sharepoint/viva/employee_engagement.py @@ -4,6 +4,8 @@ from office365.runtime.queries.service_operation import ServiceOperationQuery from office365.sharepoint.entity import Entity from office365.sharepoint.viva.app_configuration import AppConfiguration +from office365.sharepoint.viva.connections_page import VivaConnectionsPage +from office365.sharepoint.viva.dashboard_configuration import DashboardConfiguration from office365.sharepoint.viva.home import VivaHome @@ -18,13 +20,31 @@ def dashboard_content(self, override_language_code=None): :param str override_language_code: """ return_type = ClientResult(self.context, str()) - payload = {"return return_type": override_language_code} + payload = {"override_language_code": override_language_code} qry = ServiceOperationQuery( self, "DashboardContent", None, payload, None, return_type ) self.context.add_query(qry) return return_type + def full_dashboard_content( + self, canvas_as_json=None, include_personalization_data=None + ): + """ + :param bool canvas_as_json: + :param bool include_personalization_data: + """ + return_type = ClientResult(self.context, DashboardConfiguration()) + payload = { + "canvasAsJson": canvas_as_json, + "includePersonalizationData": include_personalization_data, + } + qry = ServiceOperationQuery( + self, "FullDashboardContent", None, payload, None, return_type + ) + self.context.add_query(qry) + return return_type + def viva_home_configuration(self): return_type = ClientResult(self.context, {}) qry = FunctionQuery(self, "VivaHomeConfiguration", None, return_type) @@ -45,3 +65,21 @@ def app_configuration(self): self.context, ResourcePath("AppConfiguration", self.resource_path) ), ) + + @property + def viva_connections_page(self): + return self.properties.get( + "VivaConnectionsPage", + VivaConnectionsPage( + self.context, ResourcePath("VivaConnectionsPage", self.resource_path) + ), + ) + + def get_property(self, name, default_value=None): + if default_value is None: + property_mapping = { + "AppConfiguration": self.app_configuration, + "VivaConnectionsPage": self.viva_connections_page, + } + default_value = property_mapping.get(name, None) + return super(EmployeeEngagement, self).get_property(name, default_value) diff --git a/office365/sharepoint/viva/resource_get_endpoint.py b/office365/sharepoint/viva/resource_get_endpoint.py new file mode 100644 index 000000000..37cf74b58 --- /dev/null +++ b/office365/sharepoint/viva/resource_get_endpoint.py @@ -0,0 +1,8 @@ +from office365.sharepoint.entity import Entity + + +class VivaResourceGetEndpoint(Entity): + + @property + def entity_type_name(self): + return "Microsoft.SharePoint.EmployeeEngagement.VivaResourceGetEndpoint" diff --git a/office365/sharepoint/viva/resource_link.py b/office365/sharepoint/viva/resource_link.py new file mode 100644 index 000000000..d2968215c --- /dev/null +++ b/office365/sharepoint/viva/resource_link.py @@ -0,0 +1,8 @@ +from office365.runtime.client_value import ClientValue + + +class VivaResourceLink(ClientValue): + + @property + def entity_type_name(self): + return "Microsoft.SharePoint.EmployeeEngagement.ResourceLink" diff --git a/office365/sharepoint/webs/information.py b/office365/sharepoint/webs/information.py index 2517d6c8a..e636eea9e 100644 --- a/office365/sharepoint/webs/information.py +++ b/office365/sharepoint/webs/information.py @@ -1,7 +1,72 @@ +from datetime import datetime +from typing import Optional + from office365.sharepoint.entity import Entity class WebInformation(Entity): """Specifies metadata about a site""" - pass + def __repr__(self): + return self.server_relative_url or self.entity_type_name + + @property + def configuration(self): + # type: () -> Optional[str] + """Specifies the identifier (ID) of the site definition configuration that was used to create the site""" + return self.properties.get("Configuration", None) + + @property + def created(self): + # type: () -> Optional[datetime] + """Specifies when the site (2) was created.""" + return self.properties.get("Created", datetime.min) + + @property + def description(self): + # type: () -> Optional[str] + """Specifies the description for the site""" + return self.properties.get("Description", None) + + @property + def id(self): + # type: () -> Optional[str] + """Specifies the site identifier for the site""" + return self.properties.get("Id", None) + + @property + def language(self): + # type: () -> Optional[int] + """Specifies the language code identifier (LCID) for the language that is used on the site""" + return self.properties.get("Language", None) + + @property + def last_item_modified_date(self): + # type: () -> Optional[datetime] + """Gets the date and time that an item was last modified in the site by a non-system update. + A non-system update is a change to a list item that is visible to end users.""" + return self.properties.get("LastItemModifiedDate", datetime.min) + + @property + def server_relative_url(self): + # type: () -> Optional[str] + """Specifies the server-relative URL of the site""" + return self.properties.get("ServerRelativeUrl", None) + + @property + def title(self): + # type: () -> Optional[str] + """Specifies the title for the site. Its length MUST be equal to or less than 255.""" + return self.properties.get("Title", None) + + @property + def web_template(self): + # type: () -> Optional[str] + """Specifies the name of the site template that was used to create the site.""" + return self.properties.get("WebTemplate", None) + + @property + def web_template_id(self): + # type: () -> Optional[int] + """Specifies the identifier of the site template that was used to create the site""" + return self.properties.get("WebTemplateId", None) diff --git a/office365/sharepoint/webs/regional_settings.py b/office365/sharepoint/webs/regional_settings.py index 81e05c2c2..ed130727e 100644 --- a/office365/sharepoint/webs/regional_settings.py +++ b/office365/sharepoint/webs/regional_settings.py @@ -108,6 +108,38 @@ def negative_sign(self): """ """ return self.properties.get("NegativeSign", None) + @property + def neg_number_mode(self): + # type: () -> Optional[int] + """Specifies the negative number mode that is used for displaying negative numbers in calculated fields + based on the locale of the server.""" + return self.properties.get("NegNumberMode", None) + + @property + def pm(self): + # type: () -> Optional[str] + """Specifies the string that is used to represent time after noon on the site""" + return self.properties.get("PM", None) + + @property + def positive_sign(self): + # type: () -> Optional[str] + """Specifies the symbol that is used to represent a positive number on the site""" + return self.properties.get("PositiveSign", None) + + @property + def show_weeks(self): + # type: () -> Optional[bool] + """Specifies whether to display the week number in day or week views of a calendar.""" + return self.properties.get("ShowWeeks", None) + + @property + def thousand_separator(self): + # type: () -> Optional[str] + """Specifies the symbol that is used to separate thousands for numbers on the site. For example, + if the symbol is "," the number 123456789 would appear as "123,456,789".""" + return self.properties.get("ThousandSeparator", None) + @property def work_days(self): # type: () -> Optional[int] diff --git a/office365/sharepoint/webs/web.py b/office365/sharepoint/webs/web.py index 94d6913c6..256f66917 100644 --- a/office365/sharepoint/webs/web.py +++ b/office365/sharepoint/webs/web.py @@ -170,6 +170,17 @@ def add_cross_farm_message(self, message): self.context.add_query(qry) return return_type + def get_access_request_list(self): + """ """ + return_type = List(self.context) + self.lists.add_child(return_type) + + def _get_access_request_list(): + return_type.set_property("Url", self.access_request_list_url) + + self.ensure_properties(["AccessRequestListUrl"], _get_access_request_list) + return return_type + def get_site_script( self, include_branding=True, @@ -1932,6 +1943,7 @@ def access_requests_list(self): @property def access_request_list_url(self): # type: () -> Optional[str] + """Gets the URL of the access request list to the current site""" return self.properties.get("AccessRequestListUrl", None) @property diff --git a/office365/sharepoint/workflow/task.py b/office365/sharepoint/workflow/task.py new file mode 100644 index 000000000..8fc1cb3ee --- /dev/null +++ b/office365/sharepoint/workflow/task.py @@ -0,0 +1,5 @@ +from office365.sharepoint.listitems.listitem import ListItem + + +class SPWorkflowTask(ListItem): + """ """ diff --git a/tests/sharepoint/test_app.py b/tests/sharepoint/test_app.py index 0177bb699..0b180616a 100644 --- a/tests/sharepoint/test_app.py +++ b/tests/sharepoint/test_app.py @@ -23,7 +23,7 @@ def test_1_load_tenant_app_catalog(self): self.assertIsNotNone(result.resource_path) def test_2_get_corporate_catalog_site(self): - site = self.admin_client.tenant.get_corporate_catalog_site() + site = self.admin_client.tenant.get_corporate_catalog_site().execute_query() self.assertIsNotNone(site.resource_path) def test_3_list_apps(self): diff --git a/tests/sharepoint/test_search.py b/tests/sharepoint/test_search.py index 43f0048c8..7c17df934 100644 --- a/tests/sharepoint/test_search.py +++ b/tests/sharepoint/test_search.py @@ -79,6 +79,7 @@ def test_11_get_promoted_result_query_rules(self): self.assertIsNotNone(result.value) # def test7_get_crawled_urls(self): + # from office365.sharepoint.search.administration.document_crawl_log import DocumentCrawlLog # doc_crawl_log = DocumentCrawlLog(self.client) # result = doc_crawl_log.get_crawled_urls().execute_query() # self.assertIsNotNone(result.value) diff --git a/tests/sharepoint/test_tenant.py b/tests/sharepoint/test_tenant.py index b2ca329e7..2f03df5a1 100644 --- a/tests/sharepoint/test_tenant.py +++ b/tests/sharepoint/test_tenant.py @@ -189,11 +189,23 @@ def test_25_get_power_apps_environments(self): # result = self.tenant.get_ransomware_activities().execute_query() # self.assertIsNotNone(result.value) - def test_27_get_get_spo_all_web_templates(self): + def test_27_get_spo_all_web_templates(self): result = self.tenant.get_spo_all_web_templates().execute_query() self.assertIsNotNone(result) - def test_28_get_get_collaboration_insights_data(self): + def test_28_get_collaboration_insights_data(self): # Note: You need a SharePoint Advanced Management license to perform this action result = self.tenant.get_collaboration_insights_data().execute_query() self.assertIsNotNone(result.value) + + def test_29_get_app_service_principal(self): + from office365.sharepoint.tenant.administration.internal.appservice.principal import ( + SPOWebAppServicePrincipal, + ) + + result = SPOWebAppServicePrincipal(self.client).get().execute_query() + self.assertIsNotNone(result.resource_path) + + def test_30_get_cdn_urls(self): + result = self.tenant.cdn_api.get_cdn_urls([test_team_site_url]).execute_query() + self.assertIsNotNone(result.value) diff --git a/tests/sharepoint/test_viva.py b/tests/sharepoint/test_viva.py index 7de84c711..4083c940b 100644 --- a/tests/sharepoint/test_viva.py +++ b/tests/sharepoint/test_viva.py @@ -10,11 +10,15 @@ def test1_get_app_configuration(self): # return_type = self.client.ee.viva_home().execute_query() # self.assertIsNotNone(return_type.resource_path) - # def test3_get_dashboard_content(self): - # return_type = self.client.ee.dashboard_content().execute_query() - # self.assertIsNotNone(return_type.value) + def test3_get_dashboard_content(self): + return_type = self.client.ee.dashboard_content().execute_query() + self.assertIsNotNone(return_type.value) - # def test4_get_working_set_files(self): + def test4_get_full_dashboard_content(self): + return_type = self.client.ee.full_dashboard_content().execute_query() + self.assertIsNotNone(return_type.value) + + # def test5_get_working_set_files(self): # from office365.sharepoint.copilot.file_collection import CopilotFileCollection # return_type = CopilotFileCollection.get_working_set_files(self.client, 10).execute_query() # self.assertIsNotNone(return_type.resource_path) diff --git a/tests/sharepoint/test_web.py b/tests/sharepoint/test_web.py index dcd52d260..f64a0f5c6 100644 --- a/tests/sharepoint/test_web.py +++ b/tests/sharepoint/test_web.py @@ -197,3 +197,11 @@ def test_27_ensure_tenant_app_catalog(self): # def test_29_ensure_edu_class_setup(self): # result = self.client.web.ensure_edu_class_setup(True).execute_query() # self.assertIsNotNone(result.value) + + # def test_30_get_acs_service_principals(self): + # result = self.client.web.get_acs_service_principals().execute_query() + # self.assertIsNotNone(result.value) + + def test_31_get_access_request_list(self): + result = self.client.web.get_access_request_list().get().execute_query() + self.assertIsNotNone(result.resource_path)