Skip to content

Commit a42face

Browse files
committed
Outlook API new types and methods
1 parent ce11b31 commit a42face

File tree

15 files changed

+158
-9
lines changed

15 files changed

+158
-9
lines changed

examples/auth/interactive.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
me = client.me.get().execute_query()
1818
print("Welcome, {0}!".format(me.given_name))
1919
site = client.sites.root.get().execute_query()
20-
print("Site Url: {0}!".format(site.web_url))
20+
print("Site Url: {0}".format(site.web_url))

office365/directory/identitygovernance/workflow/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from office365.entity import Entity
2+
3+
4+
class WorkflowBase(Entity):
5+
"""An abstract type that exposes the properties for configuring a custom lifecycle workflow."""

office365/directory/synchronization/progress.py

+12
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,15 @@
33

44
class SynchronizationProgress(ClientValue):
55
"""Represents the progress of a synchronizationJob toward completion."""
6+
7+
def __init__(
8+
self,
9+
completed_units=None,
10+
progress_observation_date_time=None,
11+
total_units=None,
12+
units=None,
13+
):
14+
self.completedUnits = completed_units
15+
self.progressObservationDateTime = progress_observation_date_time
16+
self.totalUnits = total_units
17+
self.units = units
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from office365.entity import Entity
2+
3+
4+
class UserInsightsSettings(Entity):
5+
""""""

office365/directory/users/settings.py

+51-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
from typing import Optional
2+
3+
from office365.directory.users.insights_settings import UserInsightsSettings
4+
from office365.directory.users.storage import UserStorage
15
from office365.entity import Entity
26
from office365.runtime.paths.resource_path import ResourcePath
37
from office365.teams.schedule.shifts.preferences import ShiftPreferences
@@ -6,6 +10,41 @@
610
class UserSettings(Entity):
711
"""The current user settings for content discovery."""
812

13+
@property
14+
def contribution_to_content_discovery_as_organization_disabled(self):
15+
# type: () -> Optional[bool]
16+
"""Reflects the organization level setting controlling delegate access to the trending API.
17+
When set to true, the organization doesn't have access to Office Delve. The relevancy of the content
18+
displayed in Microsoft 365, for example in Suggested sites in SharePoint Home and the Discover view in
19+
OneDrive for work or school is affected for the whole organization. This setting is read-only and can only
20+
be changed by administrators in the SharePoint admin center."""
21+
return self.properties.get(
22+
"contributionToContentDiscoveryAsOrganizationDisabled", None
23+
)
24+
25+
@property
26+
def contribution_to_content_discovery_disabled(self):
27+
# type: () -> Optional[bool]
28+
"""When set to true, the delegate access to the user's trending API is disabled.
29+
When set to true, documents in the user's Office Delve are disabled. When set to true, the relevancy of
30+
the content displayed in Microsoft 365, for example in Suggested sites in SharePoint Home and the
31+
Discover view in OneDrive for work or school is affected. Users can control this setting in Office Delve
32+
"""
33+
return self.properties.get("contributionToContentDiscoveryDisabled", None)
34+
35+
@property
36+
def item_insights(self):
37+
# type: () -> UserInsightsSettings
38+
"""The user's settings for the visibility of meeting hour insights, and insights derived between
39+
a user and other items in Microsoft 365, such as documents or sites.
40+
Get userInsightsSettings through this navigation property."""
41+
return self.properties.get(
42+
"itemInsights",
43+
UserInsightsSettings(
44+
self.context, ResourcePath("itemInsights", self.resource_path)
45+
),
46+
)
47+
948
@property
1049
def shift_preferences(self):
1150
# type: () -> ShiftPreferences
@@ -16,8 +55,19 @@ def shift_preferences(self):
1655
),
1756
)
1857

58+
@property
59+
def storage(self):
60+
# type: () -> ShiftPreferences
61+
return self.properties.get(
62+
"storage",
63+
UserStorage(self.context, ResourcePath("storage", self.resource_path)),
64+
)
65+
1966
def get_property(self, name, default_value=None):
2067
if default_value is None:
21-
property_mapping = {"shiftPreferences": self.shift_preferences}
68+
property_mapping = {
69+
"itemInsights": self.item_insights,
70+
"shiftPreferences": self.shift_preferences,
71+
}
2272
default_value = property_mapping.get(name, None)
2373
return super(UserSettings, self).get_property(name, default_value)

office365/directory/users/storage.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from office365.entity import Entity
2+
3+
4+
class UserStorage(Entity):
5+
""""""

office365/entity_collection.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from typing import TYPE_CHECKING, Any, Optional, Type, TypeVar
22

3+
from typing_extensions import Self
4+
35
from office365.entity import Entity
46
from office365.runtime.client_object_collection import ClientObjectCollection
57
from office365.runtime.compat import is_string_type
@@ -21,6 +23,17 @@ def __init__(self, context, item_type, resource_path=None, parent=None):
2123
super(EntityCollection, self).__init__(
2224
context, item_type, resource_path, parent
2325
)
26+
self._delta_request_url = None
27+
28+
def token(self, value):
29+
"""
30+
Apply delta query
31+
32+
:param str value: If unspecified, enumerates the hierarchy's current state. If latest, returns empty
33+
response with latest delta token. If a previous delta token, returns new state since that token.
34+
"""
35+
self.query_options.custom["token"] = value
36+
return self
2437

2538
def __getitem__(self, key):
2639
# type: (int | str) -> T
@@ -58,6 +71,14 @@ def create_typed_object(self, initial_properties=None, resource_path=None):
5871
initial_properties, resource_path
5972
)
6073

74+
def set_property(self, key, value, persist_changes=False):
75+
# type: (str | int, dict, bool) -> Self
76+
if key == "__deltaLinkUrl":
77+
self._delta_request_url = value
78+
else:
79+
super(EntityCollection, self).set_property(key, value, persist_changes)
80+
return self
81+
6182
@property
6283
def context(self):
6384
# type: () -> GraphClient

office365/outlook/mail/folders/folder.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from office365.entity import Entity
88
from office365.entity_collection import EntityCollection
99
from office365.outlook.mail.messages.collection import MessageCollection
10-
from office365.outlook.mail.messages.rules.rule import MessageRule
10+
from office365.outlook.mail.messages.rules.collection import MessageRuleCollection
1111
from office365.runtime.paths.resource_path import ResourcePath
1212
from office365.runtime.queries.service_operation import ServiceOperationQuery
1313

@@ -116,13 +116,12 @@ def child_folders(self):
116116

117117
@property
118118
def message_rules(self):
119-
# type: () -> EntityCollection[MessageRule]
119+
# type: () -> MessageRuleCollection
120120
""""""
121121
return self.properties.get(
122122
"messageRules",
123-
EntityCollection(
123+
MessageRuleCollection(
124124
self.context,
125-
MessageRule,
126125
ResourcePath("messageRules", self.resource_path),
127126
),
128127
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from office365.entity_collection import EntityCollection
2+
from office365.outlook.mail.messages.rules.rule import MessageRule
3+
4+
5+
class MessageRuleCollection(EntityCollection[MessageRule]):
6+
def __init__(self, context, resource_path=None):
7+
super(MessageRuleCollection, self).__init__(context, MessageRule, resource_path)
8+
9+
def add(self, display_name, sequence, actions, **kwargs):
10+
"""
11+
Create a messageRule object by specifying a set of conditions and actions.
12+
Outlook carries out those actions if an incoming message in the user's Inbox meets the specified conditions.
13+
This API is available in the following national cloud deployments.
14+
15+
:param str display_name: The display name of the rule.
16+
:param int sequence: Indicates the order in which the rule is executed, among other rules.
17+
:param MessageRuleActions actions: Actions to be taken on a message when the corresponding conditions,
18+
if any, are fulfilled.
19+
"""
20+
props = {
21+
"displayName": display_name,
22+
"sequence": sequence,
23+
"actions": actions.to_json(),
24+
**kwargs,
25+
}
26+
return super(MessageRuleCollection, self).add(**props)

office365/runtime/client_object_collection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ def parent(self):
234234
@property
235235
def has_next(self):
236236
# type: () -> bool
237-
""""""
237+
"""Determines whether the collection contains a next page of data."""
238238
return self._next_request_url is not None
239239

240240
@property

office365/sharepoint/webs/web.py

+4
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,7 @@ def get_client_side_components_by_id(self, component_ids=None):
961961
return return_type
962962

963963
def get_file_by_server_relative_url(self, server_relative_url):
964+
# type: (str) -> File
964965
"""
965966
Returns the file object located at the specified server-relative URL, for example:
966967
- "/sites/MySite/Shared Documents/MyDocument.docx"
@@ -978,6 +979,7 @@ def get_file_by_server_relative_url(self, server_relative_url):
978979
)
979980

980981
def get_file_by_server_relative_path(self, path):
982+
# type: (str) -> File
981983
"""Returns the file object located at the specified server-relative path, for example:
982984
- "/sites/MySite/Shared Documents/MyDocument.docx"
983985
- "Shared Documents/MyDocument.docx"
@@ -995,6 +997,7 @@ def get_file_by_server_relative_path(self, path):
995997
)
996998

997999
def get_folder_by_server_relative_url(self, url):
1000+
# type: (str) -> Folder
9981001
"""Returns the folder object located at the specified server-relative URL.
9991002
10001003
:param str url: Specifies the server-relative URL for the folder.
@@ -1008,6 +1011,7 @@ def get_folder_by_server_relative_url(self, url):
10081011
)
10091012

10101013
def get_folder_by_server_relative_path(self, decoded_url):
1014+
# type: (str) -> Folder
10111015
"""Returns the folder object located at the specified server-relative URL, for example:
10121016
- "/sites/MySite/Shared Documents"
10131017
- "Shared Documents"

tests/directory/test_service_principal.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def setUpClass(cls):
1515
super(TestServicePrincipal, cls).setUpClass()
1616
app_name = create_unique_name("App")
1717
cls.target_app = cls.client.applications.add(
18-
display_name=app_name
18+
displayName=app_name
1919
).execute_query()
2020

2121
@classmethod

tests/onedrive/test_drive.py

+8
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,11 @@ def test5_shared_with_me(self):
4444
# def test6_list_bundles(self):
4545
# result = self.client.me.drive.bundles.get().execute_query()
4646
# self.assertIsNotNone(result.resource_path)
47+
48+
def test7_list_changes(self):
49+
result = self.client.me.drive.root.delta.get().execute_query()
50+
self.assertIsNotNone(result.resource_path)
51+
52+
#def test8_get_delta_link(self):
53+
# result = self.client.me.drive.root.delta.token("latest").get().execute_query()
54+
# self.assertIsNotNone(result.resource_path)

tests/outlook/test_message_rules.py

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
1+
from office365.outlook.mail.messages.rules.actions import MessageRuleActions
12
from office365.outlook.mail.messages.rules.rule import MessageRule
3+
from office365.outlook.mail.recipient import Recipient
24
from tests.graph_case import GraphTestCase
35

46

57
class TestMessageRules(GraphTestCase):
68
target_message_rule = None # type: MessageRule
79

8-
def test1_list_inbox_rules(self):
10+
def test1_create_rule(self):
11+
actions = MessageRuleActions(
12+
forward_to=[Recipient.from_email("[email protected]")],
13+
stop_processing_rules=True,
14+
)
15+
message_rules = (
16+
self.client.me.mail_folders["inbox"]
17+
.message_rules.add("From partner", 2, actions)
18+
.execute_query()
19+
)
20+
self.assertIsNotNone(message_rules.resource_path)
21+
22+
def test2_list_rules(self):
923
message_rules = (
1024
self.client.me.mail_folders["inbox"].message_rules.get().execute_query()
1125
)

0 commit comments

Comments
 (0)