Office365-REST-Python-Client 2.5.6__py3-none-any.whl → 2.5.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {Office365_REST_Python_Client-2.5.6.dist-info → Office365_REST_Python_Client-2.5.7.dist-info}/METADATA +5 -5
  2. {Office365_REST_Python_Client-2.5.6.dist-info → Office365_REST_Python_Client-2.5.7.dist-info}/RECORD +85 -58
  3. office365/directory/administrative_unit.py +9 -2
  4. office365/directory/applications/roles/collection.py +5 -1
  5. office365/directory/applications/roles/role.py +1 -1
  6. office365/directory/audit/provisioning/object_summary.py +30 -1
  7. office365/directory/authentication/methods/fido.py +8 -0
  8. office365/directory/authentication/methods/password.py +23 -0
  9. office365/directory/custom_security_attribute_definition.py +7 -0
  10. office365/directory/device_local_credential_info.py +6 -0
  11. office365/directory/directory.py +40 -12
  12. office365/directory/identitygovernance/appconsent/request_collection.py +1 -1
  13. office365/directory/identitygovernance/termsofuse/agreement_acceptance.py +8 -0
  14. office365/directory/identitygovernance/userconsent/request_collection.py +1 -1
  15. office365/directory/insights/resource_reference.py +1 -1
  16. office365/directory/policies/device_registration.py +6 -0
  17. office365/directory/policies/root.py +13 -0
  18. office365/directory/security/threatintelligence/article_indicator.py +7 -0
  19. office365/directory/serviceprincipals/service_principal.py +3 -8
  20. office365/directory/synchronization/schema.py +16 -0
  21. office365/directory/users/user.py +23 -0
  22. office365/onedrive/driveitems/driveItem.py +74 -6
  23. office365/onedrive/lists/list.py +1 -1
  24. office365/onedrive/sitepages/__init__.py +0 -0
  25. office365/onedrive/sitepages/base.py +29 -0
  26. office365/onedrive/sitepages/canvas_layout.py +43 -0
  27. office365/onedrive/sitepages/collection.py +32 -0
  28. office365/onedrive/sitepages/horizontal_section.py +23 -0
  29. office365/onedrive/sitepages/horizontal_section_column.py +27 -0
  30. office365/onedrive/sitepages/site_page.py +116 -0
  31. office365/onedrive/sitepages/title_area.py +13 -0
  32. office365/onedrive/sitepages/vertical_section.py +27 -0
  33. office365/onedrive/sitepages/web_part.py +5 -0
  34. office365/onedrive/sites/site.py +10 -0
  35. office365/onedrive/workbooks/charts/data_labels.py +13 -1
  36. office365/onedrive/workbooks/tables/sort.py +5 -0
  37. office365/onedrive/workbooks/tables/table.py +57 -0
  38. office365/onedrive/workbooks/worksheets/protection.py +20 -1
  39. office365/onedrive/workbooks/worksheets/protection_options.py +7 -0
  40. office365/outlook/calendar/calendar.py +1 -3
  41. office365/outlook/calendar/events/event.py +45 -0
  42. office365/outlook/calendar/response_status.py +11 -0
  43. office365/outlook/calendar/rooms/room.py +14 -0
  44. office365/outlook/mail/automatic_replies_mailtips.py +5 -0
  45. office365/outlook/mail/conversation.py +1 -3
  46. office365/outlook/mail/folders/folder.py +1 -3
  47. office365/outlook/mail/tips.py +17 -0
  48. office365/planner/plans/plan.py +11 -1
  49. office365/reports/root.py +33 -0
  50. office365/runtime/auth/authentication_context.py +12 -2
  51. office365/runtime/odata/json_format.py +3 -2
  52. office365/runtime/odata/request.py +12 -2
  53. office365/runtime/queries/upload_session.py +5 -0
  54. office365/sharepoint/alerts/collection.py +2 -1
  55. office365/sharepoint/attachments/attachment.py +3 -9
  56. office365/sharepoint/client_context.py +4 -2
  57. office365/sharepoint/contenttypes/content_type.py +13 -1
  58. office365/sharepoint/contenttypes/fieldlinks/collection.py +1 -1
  59. office365/sharepoint/directory/helper.py +2 -0
  60. office365/sharepoint/fields/collection.py +4 -3
  61. office365/sharepoint/folders/folder.py +1 -3
  62. office365/sharepoint/migrationcenter/deploy_status.py +5 -0
  63. office365/sharepoint/migrationcenter/service/performance/__init__.py +0 -0
  64. office365/sharepoint/migrationcenter/service/performance/dashboard_data.py +9 -0
  65. office365/sharepoint/migrationcenter/service/performance/data.py +7 -0
  66. office365/sharepoint/migrationcenter/service/performance/entity_data.py +5 -0
  67. office365/sharepoint/principal/principal.py +2 -4
  68. office365/sharepoint/recyclebin/item.py +107 -7
  69. office365/sharepoint/sharing/information.py +9 -0
  70. office365/sharepoint/sharing/link_info.py +6 -0
  71. office365/sharepoint/sharing/permission_collection.py +18 -0
  72. office365/sharepoint/sites/script_safe_domain.py +5 -0
  73. office365/sharepoint/sites/site.py +10 -4
  74. office365/sharepoint/taxonomy/field_value.py +1 -1
  75. office365/sharepoint/tenant/administration/powerapps/__init__.py +0 -0
  76. office365/sharepoint/tenant/administration/powerapps/environment_context.py +8 -0
  77. office365/sharepoint/webs/information_collection.py +1 -1
  78. office365/sharepoint/webs/regional_settings.py +71 -0
  79. office365/sharepoint/webs/web.py +10 -5
  80. office365/teams/apps/catalog.py +1 -0
  81. office365/teams/chats/chat.py +4 -0
  82. office365/teams/schedule/schedule.py +6 -2
  83. {Office365_REST_Python_Client-2.5.6.dist-info → Office365_REST_Python_Client-2.5.7.dist-info}/LICENSE +0 -0
  84. {Office365_REST_Python_Client-2.5.6.dist-info → Office365_REST_Python_Client-2.5.7.dist-info}/WHEEL +0 -0
  85. {Office365_REST_Python_Client-2.5.6.dist-info → Office365_REST_Python_Client-2.5.7.dist-info}/top_level.txt +0 -0
@@ -38,4 +38,4 @@ class AppRole(ClientValue):
38
38
  return "{0} {1}".format(self.allowedMemberTypes, self.value)
39
39
 
40
40
  def __repr__(self):
41
- return "{0}".format(self.id)
41
+ return self.value or self.id or self.entity_type_name
@@ -1,3 +1,6 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
1
4
  from office365.directory.audit.provisioning.service_principal import (
2
5
  ProvisioningServicePrincipal,
3
6
  )
@@ -7,6 +10,29 @@ from office365.entity import Entity
7
10
  class ProvisioningObjectSummary(Entity):
8
11
  """Represents an action performed by the Azure AD Provisioning service and its associated properties."""
9
12
 
13
+ @property
14
+ def activity_datetime(self):
15
+ """Represents date and time information using ISO 8601 format and is always in UTC time."""
16
+ return self.properties.get("activityDateTime", datetime.min)
17
+
18
+ @property
19
+ def change_id(self):
20
+ # type: () -> Optional[str]
21
+ """Unique ID of this change in this cycle. Supports $filter (eq, contains)."""
22
+ return self.properties.get("changeId", None)
23
+
24
+ @property
25
+ def cycle_id(self):
26
+ # type: () -> Optional[str]
27
+ """Unique ID per job iteration. Supports $filter (eq, contains)."""
28
+ return self.properties.get("cycleId", None)
29
+
30
+ @property
31
+ def duration_in_milliseconds(self):
32
+ # type: () -> Optional[int]
33
+ """Indicates how long this provisioning action took to finish. Measured in milliseconds."""
34
+ return self.properties.get("durationInMilliseconds", None)
35
+
10
36
  @property
11
37
  def service_principal(self):
12
38
  """Represents the service principal used for provisioning."""
@@ -14,6 +40,9 @@ class ProvisioningObjectSummary(Entity):
14
40
 
15
41
  def get_property(self, name, default_value=None):
16
42
  if default_value is None:
17
- property_mapping = {"servicePrincipal": self.service_principal}
43
+ property_mapping = {
44
+ "activityDateTime": self.activity_datetime,
45
+ "servicePrincipal": self.service_principal,
46
+ }
18
47
  default_value = property_mapping.get(name, None)
19
48
  return super(ProvisioningObjectSummary, self).get_property(name, default_value)
@@ -1,5 +1,13 @@
1
+ from typing import Optional
2
+
1
3
  from office365.directory.authentication.methods.method import AuthenticationMethod
2
4
 
3
5
 
4
6
  class Fido2AuthenticationMethod(AuthenticationMethod):
5
7
  """Representation of a FIDO2 security key registered to a user. FIDO2 is a sign-in authentication method."""
8
+
9
+ @property
10
+ def model(self):
11
+ # type: () -> Optional[str]
12
+ """The manufacturer-assigned model of the FIDO2 security key."""
13
+ return self.properties.get("model", None)
@@ -1,6 +1,29 @@
1
+ from datetime import datetime
2
+ from typing import Optional
3
+
1
4
  from office365.directory.authentication.methods.method import AuthenticationMethod
2
5
 
3
6
 
4
7
  class PasswordAuthenticationMethod(AuthenticationMethod):
5
8
  """A representation of a user's password. For security, the password itself will never be returned in the object,
6
9
  but action can be taken to reset a password."""
10
+
11
+ @property
12
+ def created_datetime(self):
13
+ # type: () -> datetime
14
+ """The date and time when this password was last updated. This property is currently not populated."""
15
+ return self.properties.get("createdDateTime", datetime.min)
16
+
17
+ @property
18
+ def password(self):
19
+ # type: () -> Optional[str]
20
+ """For security, the password is always returned as null from a LIST or GET operation."""
21
+ return self.properties.get("password", None)
22
+
23
+ def get_property(self, name, default_value=None):
24
+ if default_value is None:
25
+ property_mapping = {"createdDateTime": self.created_datetime}
26
+ default_value = property_mapping.get(name, None)
27
+ return super(PasswordAuthenticationMethod, self).get_property(
28
+ name, default_value
29
+ )
@@ -0,0 +1,7 @@
1
+ from office365.entity import Entity
2
+
3
+
4
+ class CustomSecurityAttributeDefinition(Entity):
5
+ """Represents the schema of a custom security attribute (key-value pair).
6
+ For example, the custom security attribute name, description, data type, and allowed values.
7
+ """
@@ -0,0 +1,6 @@
1
+ from office365.entity import Entity
2
+
3
+
4
+ class DeviceLocalCredentialInfo(Entity):
5
+ """Represents local administrator credential information for all device objects in Azure Active Directory
6
+ that are enabled with Local Admin Password Solution (LAPS)."""
@@ -1,4 +1,8 @@
1
1
  from office365.directory.administrative_unit import AdministrativeUnit
2
+ from office365.directory.custom_security_attribute_definition import (
3
+ CustomSecurityAttributeDefinition,
4
+ )
5
+ from office365.directory.device_local_credential_info import DeviceLocalCredentialInfo
2
6
  from office365.directory.object_collection import DirectoryObjectCollection
3
7
  from office365.entity import Entity
4
8
  from office365.entity_collection import EntityCollection
@@ -10,6 +14,42 @@ class Directory(Entity):
10
14
  "container". Deleted items will remain available to restore for up to 30 days. After 30 days, the items are
11
15
  permanently deleted."""
12
16
 
17
+ @property
18
+ def device_local_credentials(self):
19
+ """Conceptual container for user and group directory objects."""
20
+ return self.properties.get(
21
+ "deviceLocalCredentials",
22
+ EntityCollection(
23
+ self.context,
24
+ DeviceLocalCredentialInfo,
25
+ ResourcePath("deviceLocalCredentials", self.resource_path),
26
+ ),
27
+ )
28
+
29
+ @property
30
+ def administrative_units(self):
31
+ """Conceptual container for user and group directory objects."""
32
+ return self.properties.get(
33
+ "administrativeUnits",
34
+ EntityCollection(
35
+ self.context,
36
+ AdministrativeUnit,
37
+ ResourcePath("administrativeUnits", self.resource_path),
38
+ ),
39
+ )
40
+
41
+ @property
42
+ def custom_security_attribute_definitions(self):
43
+ """Conceptual container for customSecurityAttributeDefinition objects and their properties."""
44
+ return self.properties.get(
45
+ "customSecurityAttributeDefinitions",
46
+ EntityCollection(
47
+ self.context,
48
+ CustomSecurityAttributeDefinition,
49
+ ResourcePath("customSecurityAttributeDefinitions", self.resource_path),
50
+ ),
51
+ )
52
+
13
53
  def deleted_items(self, entity_type=None):
14
54
  """Recently deleted items. Read-only. Nullable."""
15
55
  if entity_type:
@@ -27,18 +67,6 @@ class Directory(Entity):
27
67
  ),
28
68
  )
29
69
 
30
- @property
31
- def administrative_units(self):
32
- """Conceptual container for user and group directory objects."""
33
- return self.properties.get(
34
- "administrativeUnits",
35
- EntityCollection(
36
- self.context,
37
- AdministrativeUnit,
38
- ResourcePath("administrativeUnits", self.resource_path),
39
- ),
40
- )
41
-
42
70
  @property
43
71
  def deleted_groups(self):
44
72
  """Recently deleted groups"""
@@ -3,7 +3,7 @@ from office365.entity_collection import EntityCollection
3
3
  from office365.runtime.queries.function import FunctionQuery
4
4
 
5
5
 
6
- class AppConsentRequestCollection(EntityCollection):
6
+ class AppConsentRequestCollection(EntityCollection[AppConsentRequest]):
7
7
  """AppConsentRequest's collection"""
8
8
 
9
9
  def __init__(self, context, resource_path=None):
@@ -1,3 +1,5 @@
1
+ from typing import Optional
2
+
1
3
  from office365.entity import Entity
2
4
 
3
5
 
@@ -6,3 +8,9 @@ class AgreementAcceptance(Entity):
6
8
  Represents the current status of a user's response to a company's customizable terms of use agreement powered by
7
9
  Azure Active Directory (Azure AD).
8
10
  """
11
+
12
+ @property
13
+ def user_principal_name(self):
14
+ # type: () -> Optional[str]
15
+ """UPN of the user when the acceptance was recorded."""
16
+ return self.properties.get("userPrincipalName", None)
@@ -4,7 +4,7 @@ from office365.directory.identitygovernance.userconsent.request import (
4
4
  from office365.entity_collection import EntityCollection
5
5
 
6
6
 
7
- class UserConsentRequestCollection(EntityCollection):
7
+ class UserConsentRequestCollection(EntityCollection[UserConsentRequest]):
8
8
  """AppConsentRequest's collection"""
9
9
 
10
10
  def __init__(self, context, resource_path=None):
@@ -15,7 +15,7 @@ class ResourceReference(ClientValue):
15
15
  self.webUrl = web_url
16
16
 
17
17
  def __str__(self):
18
- return self.type
18
+ return self.type or ""
19
19
 
20
20
  def __repr__(self):
21
21
  return "{0}:{1}".format(self.type, self.webUrl)
@@ -0,0 +1,6 @@
1
+ from office365.entity import Entity
2
+
3
+
4
+ class DeviceRegistrationPolicy(Entity):
5
+ """Represents the policy scope that controls quota restrictions, additional authentication, and authorization
6
+ policies to register device identities to your organization."""
@@ -9,6 +9,7 @@ from office365.directory.policies.authentication_strength import (
9
9
  from office365.directory.policies.authorization import AuthorizationPolicy
10
10
  from office365.directory.policies.conditional_access import ConditionalAccessPolicy
11
11
  from office365.directory.policies.cross_tenant_access import CrossTenantAccessPolicy
12
+ from office365.directory.policies.device_registration import DeviceRegistrationPolicy
12
13
  from office365.directory.policies.permission_grant import PermissionGrantPolicy
13
14
  from office365.directory.policies.tenant_app_management import TenantAppManagementPolicy
14
15
  from office365.entity import Entity
@@ -33,6 +34,17 @@ class PolicyRoot(Entity):
33
34
  ),
34
35
  )
35
36
 
37
+ @property
38
+ def device_registration_policy(self):
39
+ """ """
40
+ return self.properties.get(
41
+ "deviceRegistrationPolicy",
42
+ DeviceRegistrationPolicy(
43
+ self.context,
44
+ ResourcePath("deviceRegistrationPolicy", self.resource_path),
45
+ ),
46
+ )
47
+
36
48
  def authentication_strength_policies(self):
37
49
  # type: () -> EntityCollection[AuthenticationStrengthPolicy]
38
50
  """
@@ -147,6 +159,7 @@ class PolicyRoot(Entity):
147
159
  "conditional_access_policies": self.conditional_access_policies,
148
160
  "crossTenantAccessPolicy": self.cross_tenant_access_policy,
149
161
  "defaultAppManagementPolicy": self.default_app_management_policy,
162
+ "deviceRegistrationPolicy": self.device_registration_policy,
150
163
  "permissionGrantPolicies": self.permission_grant_policies,
151
164
  }
152
165
  default_value = property_mapping.get(name, None)
@@ -0,0 +1,7 @@
1
+ from office365.entity import Entity
2
+
3
+
4
+ class ArticleIndicator(Entity):
5
+ """
6
+ Represents a resource that communicates indicators of threat or compromise related to the contents of an article
7
+ """
@@ -111,10 +111,8 @@ class ServicePrincipal(DirectoryObject):
111
111
 
112
112
  def _grant(principal):
113
113
  # type: ("ServicePrincipal") -> None
114
- app_role_id = repr(app_role)
115
- principal_id = principal.id
116
114
  self.app_role_assigned_to.add(
117
- principalId=principal_id, resourceId=self.id, appRoleId=app_role_id
115
+ principalId=principal.id, resourceId=self.id, appRoleId=app_role.id
118
116
  )
119
117
 
120
118
  def _ensure_principal():
@@ -128,20 +126,17 @@ class ServicePrincipal(DirectoryObject):
128
126
  """Revokes an app role assignment from a client service principal"""
129
127
 
130
128
  def _revoke(principal):
131
- # type ("ServicePrincipal") -> None
132
- principal_id = principal.id
133
- app_role_id = repr(app_role)
129
+ # type: ("ServicePrincipal") -> None
134
130
  app_role_assigned_to_ids = [
135
131
  item.id
136
132
  for item in self.app_role_assigned_to
137
- if item.principal_id == principal_id and item.app_role_id == app_role_id
133
+ if item.principal_id == principal.id and item.app_role_id == app_role.id
138
134
  ]
139
135
  if len(app_role_assigned_to_ids) > 0:
140
136
  self.app_role_assigned_to[app_role_assigned_to_ids[0]].delete_object()
141
137
 
142
138
  def _ensure_resource(principal):
143
139
  self.ensure_properties(["id", "appRoleAssignedTo"], _revoke, principal)
144
- # self.app_role_assigned_to.get_all(page_loaded=_revoke)
145
140
 
146
141
  def _ensure_principal():
147
142
  self.context.service_principals.get_by_app(app).get().after_execute(
@@ -1,4 +1,7 @@
1
+ from office365.directory.synchronization.directory_definition import DirectoryDefinition
1
2
  from office365.entity import Entity
3
+ from office365.entity_collection import EntityCollection
4
+ from office365.runtime.paths.resource_path import ResourcePath
2
5
 
3
6
 
4
7
  class SynchronizationSchema(Entity):
@@ -9,3 +12,16 @@ class SynchronizationSchema(Entity):
9
12
 
10
13
  The following sections describe the high-level components of the synchronization schema.
11
14
  """
15
+
16
+ @property
17
+ def directories(self):
18
+ # type: () -> EntityCollection[DirectoryDefinition]
19
+ """Contains the collection of directories and all of their objects."""
20
+ return self.properties.get(
21
+ "directories",
22
+ EntityCollection(
23
+ self.context,
24
+ DirectoryDefinition,
25
+ ResourcePath("directories", self.resource_path),
26
+ ),
27
+ )
@@ -50,6 +50,7 @@ from office365.outlook.mail.mailbox_settings import MailboxSettings
50
50
  from office365.outlook.mail.messages.collection import MessageCollection
51
51
  from office365.outlook.mail.messages.message import Message
52
52
  from office365.outlook.mail.recipient import Recipient
53
+ from office365.outlook.mail.tips import MailTips
53
54
  from office365.outlook.user import OutlookUser
54
55
  from office365.planner.user import PlannerUser
55
56
  from office365.runtime.client_result import ClientResult
@@ -169,6 +170,28 @@ class User(DirectoryObject):
169
170
  self.context.add_query(qry)
170
171
  return self
171
172
 
173
+ def get_mail_tips(self, email_addresses, mail_tips_options=None):
174
+ """Get the MailTips of one or more recipients as available to the signed-in user.
175
+ :param list[str] email_addresses: A collection of SMTP addresses of recipients to get MailTips for.
176
+ :param str mail_tips_options: A enumeration of flags that represents the requested mailtips.
177
+ Possible values are: automaticReplies, customMailTip, deliveryRestriction, externalMemberCount,
178
+ mailboxFullStatus, maxMessageSize, moderationStatus, recipientScope, recipientSuggestions,
179
+ and totalMemberCount.
180
+ """
181
+ return_type = ClientResult(self.context, ClientValueCollection(MailTips))
182
+ payload = {
183
+ "EmailAddresses": StringCollection(email_addresses),
184
+ "MailTipsOptions": mail_tips_options,
185
+ }
186
+ qry = ServiceOperationQuery(
187
+ self,
188
+ "getMailTips",
189
+ None,
190
+ payload,
191
+ )
192
+ self.context.add_query(qry)
193
+ return return_type
194
+
172
195
  def send_mail(
173
196
  self,
174
197
  subject,
@@ -2,6 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import os
4
4
  from datetime import datetime
5
+ from functools import partial
6
+ from os.path import isfile, join
5
7
  from typing import IO, AnyStr, Callable, Optional, TypeVar
6
8
 
7
9
  import requests
@@ -272,6 +274,30 @@ class DriveItem(BaseItem):
272
274
  name = os.path.basename(path_or_file)
273
275
  return self.upload(name, content)
274
276
 
277
+ def upload_folder(self, path, file_uploaded=None):
278
+ # type: (str, Callable[["DriveItem"], None]) -> "DriveItem"
279
+
280
+ def _after_file_upload(return_type):
281
+ # type: ("DriveItem") -> None
282
+ if callable(file_uploaded):
283
+ file_uploaded(return_type)
284
+
285
+ def _upload_folder(source_path, target_folder):
286
+ # type: (str, "DriveItem") -> None
287
+ for name in os.listdir(source_path):
288
+ cur_path = join(source_path, name)
289
+ if isfile(cur_path):
290
+ with open(cur_path, "rb") as f:
291
+ target_folder.upload_file(f).after_execute(_after_file_upload)
292
+ else:
293
+ target_folder.create_folder(name).after_execute(
294
+ partial(_upload_folder, cur_path)
295
+ )
296
+
297
+ """Uploads a folder"""
298
+ _upload_folder(path, self)
299
+ return self
300
+
275
301
  def get_content(self, format_name=None):
276
302
  # type: (Optional[str]) -> ClientResult[AnyStr]
277
303
  """
@@ -302,6 +328,52 @@ class DriveItem(BaseItem):
302
328
  self.get_content().after_execute(_save_content)
303
329
  return self
304
330
 
331
+ def download_folder(
332
+ self, download_file, after_file_downloaded=None, recursive=True
333
+ ):
334
+ # type: (IO, Callable[[File], None], bool) -> "DriveItem"
335
+ """
336
+ Download the folder content
337
+ """
338
+ import zipfile
339
+
340
+ def _after_file_downloaded(drive_item, base_path, result):
341
+ # type: ("DriveItem", str, ClientResult[AnyStr]) -> None
342
+ with zipfile.ZipFile(download_file.name, "a", zipfile.ZIP_DEFLATED) as zf:
343
+ zip_path = (
344
+ "/".join([base_path, drive_item.name])
345
+ if base_path is not None
346
+ else drive_item.name
347
+ )
348
+ zf.writestr(zip_path, result.value)
349
+ if callable(after_file_downloaded):
350
+ after_file_downloaded(drive_item)
351
+
352
+ def _after_folder_downloaded(parent_item, base_path=None):
353
+ # type: ("DriveItem", str) -> None
354
+ for drive_item in parent_item.children:
355
+ if drive_item.is_file:
356
+ drive_item.get_content().after_execute(
357
+ partial(_after_file_downloaded, drive_item, base_path)
358
+ )
359
+ else:
360
+ if recursive:
361
+ if base_path is None:
362
+ next_base_path = str(drive_item.name)
363
+ else:
364
+ next_base_path = "/".join([base_path, drive_item.name])
365
+ _download_folder(drive_item, next_base_path)
366
+
367
+ def _download_folder(drive_item, prev_result=None):
368
+ # type: ("DriveItem", str) -> None
369
+ drive_item.ensure_properties(
370
+ ["children", "name"],
371
+ partial(_after_folder_downloaded, drive_item, prev_result),
372
+ )
373
+
374
+ _download_folder(self)
375
+ return self
376
+
305
377
  def download_session(
306
378
  self, file_object, chunk_downloaded=None, chunk_size=1024 * 1024
307
379
  ):
@@ -600,9 +672,7 @@ class DriveItem(BaseItem):
600
672
  @property
601
673
  def audio(self):
602
674
  # type: () -> Audio
603
- """
604
- Audio metadata, if the item is an audio file. Read-only.
605
- """
675
+ """Audio metadata, if the item is an audio file. Read-only."""
606
676
  return self.properties.get("audio", Audio())
607
677
 
608
678
  @property
@@ -616,9 +686,7 @@ class DriveItem(BaseItem):
616
686
  @property
617
687
  def photo(self):
618
688
  # type: () -> Photo
619
- """
620
- Photo metadata, if the item is a photo. Read-only.
621
- """
689
+ """Photo metadata, if the item is a photo. Read-only."""
622
690
  return self.properties.get("photo", Photo())
623
691
 
624
692
  @property
@@ -17,7 +17,7 @@ class List(BaseItem):
17
17
  including template and field definitions."""
18
18
 
19
19
  def __str__(self):
20
- return self.display_name
20
+ return self.display_name or self.entity_type_name
21
21
 
22
22
  @property
23
23
  def display_name(self):
File without changes
@@ -0,0 +1,29 @@
1
+ from typing import Optional
2
+
3
+ from office365.base_item import BaseItem
4
+ from office365.onedrive.driveitems.publication_facet import PublicationFacet
5
+
6
+
7
+ class BaseSitePage(BaseItem):
8
+ """An abstract type that represents a page in the site page library."""
9
+
10
+ @property
11
+ def publishing_state(self):
12
+ # type: () -> Optional[str]
13
+ """The publishing status and the MM.mm version of the page."""
14
+ return self.properties.get("publishingState", PublicationFacet())
15
+
16
+ @property
17
+ def page_layout(self):
18
+ # type: () -> Optional[str]
19
+ """
20
+ The name of the page layout of the page.
21
+ The possible values are: microsoftReserved, article, home, unknownFutureValue.
22
+ """
23
+ return self.properties.get("pageLayout", None)
24
+
25
+ @property
26
+ def title(self):
27
+ # type: () -> Optional[str]
28
+ """Title of the sitePage."""
29
+ return self.properties.get("title", None)
@@ -0,0 +1,43 @@
1
+ from office365.entity import Entity
2
+ from office365.entity_collection import EntityCollection
3
+ from office365.onedrive.sitepages.horizontal_section import HorizontalSection
4
+ from office365.onedrive.sitepages.vertical_section import VerticalSection
5
+ from office365.runtime.paths.resource_path import ResourcePath
6
+
7
+
8
+ class CanvasLayout(Entity):
9
+ """Represents the layout of the content in a given SharePoint page."""
10
+
11
+ @property
12
+ def horizontal_sections(self):
13
+ # type: () -> EntityCollection[HorizontalSection]
14
+ """Collection of horizontal sections on the SharePoint page.."""
15
+ return self.properties.get(
16
+ "horizontalSections",
17
+ EntityCollection(
18
+ self.context,
19
+ HorizontalSection,
20
+ ResourcePath("horizontalSections", self.resource_path),
21
+ ),
22
+ )
23
+
24
+ @property
25
+ def vertical_section(self):
26
+ # type: () -> VerticalSection
27
+ """Vertical section on the SharePoint page."""
28
+ return self.properties.get(
29
+ "verticalSection",
30
+ VerticalSection(
31
+ self.context,
32
+ ResourcePath("verticalSection", self.resource_path),
33
+ ),
34
+ )
35
+
36
+ def get_property(self, name, default_value=None):
37
+ if default_value is None:
38
+ property_mapping = {
39
+ "horizontalSections": self.horizontal_sections,
40
+ "verticalSection": self.vertical_section,
41
+ }
42
+ default_value = property_mapping.get(name, None)
43
+ return super(CanvasLayout, self).get_property(name, default_value)
@@ -0,0 +1,32 @@
1
+ from office365.entity_collection import EntityCollection
2
+ from office365.onedrive.sitepages.site_page import SitePage
3
+ from office365.onedrive.sitepages.title_area import TitleArea
4
+ from office365.runtime.http.request_options import RequestOptions
5
+
6
+
7
+ class SitePageCollection(EntityCollection[SitePage]):
8
+ """Sites container"""
9
+
10
+ def __init__(self, context, resource_path=None):
11
+ super(SitePageCollection, self).__init__(context, SitePage, resource_path)
12
+
13
+ def add(self, title):
14
+ """
15
+ Create a new sitePage in the site pages list in a site.
16
+
17
+ """
18
+
19
+ def _construct_request(request):
20
+ # type: (RequestOptions) -> None
21
+ request.set_header("Content-Type", "application/json")
22
+
23
+ return (
24
+ super(SitePageCollection, self)
25
+ .add(
26
+ title=title,
27
+ name="{0}.aspx".format(title),
28
+ pageLayout="article",
29
+ titleArea=TitleArea(),
30
+ )
31
+ .before_execute(_construct_request)
32
+ )
@@ -0,0 +1,23 @@
1
+ from office365.entity import Entity
2
+ from office365.entity_collection import EntityCollection
3
+ from office365.onedrive.sitepages.horizontal_section_column import (
4
+ HorizontalSectionColumn,
5
+ )
6
+ from office365.runtime.paths.resource_path import ResourcePath
7
+
8
+
9
+ class HorizontalSection(Entity):
10
+ """Represents a horizontal section in a given SharePoint page."""
11
+
12
+ @property
13
+ def columns(self):
14
+ # type: () -> EntityCollection[HorizontalSectionColumn]
15
+ """The set of vertical columns in this section."""
16
+ return self.properties.get(
17
+ "columns",
18
+ EntityCollection(
19
+ self.context,
20
+ HorizontalSectionColumn,
21
+ ResourcePath("columns", self.resource_path),
22
+ ),
23
+ )
@@ -0,0 +1,27 @@
1
+ from office365.entity import Entity
2
+ from office365.entity_collection import EntityCollection
3
+ from office365.onedrive.sitepages.web_part import WebPart
4
+ from office365.runtime.paths.resource_path import ResourcePath
5
+
6
+
7
+ class HorizontalSectionColumn(Entity):
8
+ """Represents a vertical column in a given horizontal section."""
9
+
10
+ @property
11
+ def web_parts(self):
12
+ # type: () -> EntityCollection[WebPart]
13
+ """The set of web parts in this section."""
14
+ return self.properties.get(
15
+ "webParts",
16
+ EntityCollection(
17
+ self.context, WebPart, ResourcePath("webParts", self.resource_path)
18
+ ),
19
+ )
20
+
21
+ def get_property(self, name, default_value=None):
22
+ if default_value is None:
23
+ property_mapping = {
24
+ "webParts": self.web_parts,
25
+ }
26
+ default_value = property_mapping.get(name, None)
27
+ return super(HorizontalSectionColumn, self).get_property(name, default_value)