Skip to content

Commit bbc780e

Browse files
committed
refactor: clean up meeting_finder.py — remove verbosity, strftime, step comments
1 parent 38b79a4 commit bbc780e

31 files changed

Lines changed: 376 additions & 133 deletions

examples/outlook/calendars/availability.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@
2525
client = GraphClient(tenant=test_tenant).with_username_and_password(test_client_id, test_username, test_password)
2626

2727
# 1. Find suggested meeting times
28-
suggestions = client.me.find_meeting_times().execute_query()
29-
for s in suggestions.value.meetingTimeSuggestions or []:
30-
times = s.meeting_time_slot
31-
print(f" Suggested: {times.start.date_time}{times.end.date_time}")
28+
result = client.me.find_meeting_times().execute_query()
29+
for s in result.value.meetingTimeSuggestions:
30+
print(f" Suggested: {s.meetingTimeSlot.start}{s.meetingTimeSlot.end}")
3231

3332
# 2. Get free/busy schedule for a user
3433
end_time = datetime.now()
@@ -38,7 +37,7 @@
3837
start_time=start_time,
3938
end_time=end_time,
4039
).execute_query()
41-
for item in schedule.value or []:
42-
print(f"\n Schedule for: {item.schedule_id}")
43-
for slot in item.availability_view or []:
44-
print(f" {slot.status}: {slot.start.date_time}{slot.end.date_time}")
40+
for item in schedule.value:
41+
print(f"\n Schedule for: {item.scheduleId}")
42+
for slot in item.scheduleItems:
43+
print(f" {slot.status}: {slot.start}{slot.end}")

examples/outlook/calendars/meeting_finder.py

Lines changed: 19 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,11 @@
11
"""
2-
Meeting finder: suggest optimal time slots and resolve rooms.
2+
Find meeting times and list rooms in the tenant.
33
4-
Brings together three related patterns:
5-
1. Find available meeting times that work for all attendees.
6-
2. List room lists and rooms in the tenant.
7-
3. Get free/busy schedule for a room across a time window.
8-
9-
Useful for scheduling assistants, booking flows, and room
10-
management tooling.
11-
12-
Requires delegated permissions:
13-
Calendars.ReadWrite Create and manage events
14-
MailboxSettings.Read Read user availability
15-
Place.Read.All List rooms and room lists
16-
17-
https://learn.microsoft.com/en-us/graph/api/user-findmeetingtimes
18-
https://learn.microsoft.com/en-us/graph/api/resources/place
4+
Requires delegated permissions Calendars.ReadWrite, MailboxSettings.Read,
5+
Place.Read.All.
196
"""
207

21-
from datetime import datetime, timedelta, timezone
8+
from datetime import timedelta
229

2310
from office365.graph_client import GraphClient
2411
from tests import test_client_id, test_password, test_tenant, test_username
@@ -27,71 +14,32 @@
2714
def main():
2815
client = GraphClient(tenant=test_tenant).with_username_and_password(test_client_id, test_username, test_password)
2916

30-
# -- Step 1: list room lists and rooms in the tenant --
31-
print("Places (room lists and rooms):")
32-
all_places = client.places.get().execute_query()
33-
for p in all_places:
34-
print(f" {p.display_name:45s} type={p.entity_type_name}")
35-
print()
36-
37-
# Try to get room lists specifically
3817
room_lists = client.places.room_lists.get().execute_query()
3918
if room_lists:
40-
print("Room lists:")
4119
for rl in room_lists:
42-
print(f" {rl.display_name:45s} {rl.email_address or ''}")
43-
# Get rooms in this list
20+
print(f"Room list: {rl.display_name} ({rl.email_address or ''})")
4421
try:
4522
rooms = rl.rooms.get().execute_query()
4623
for room in rooms:
47-
print(f" {room.display_name:40s} {room.email_address or ''} ({room.capacity or '?'} seats)")
24+
print(f" {room.display_name} {room.email_address} (capacity: {room.capacity})")
4825
except Exception:
4926
pass
50-
else:
51-
print("(No room lists found — room list management may need Place.Read.All)")
52-
53-
# -- Step 2: find meeting times for next week --
54-
now = datetime.now(timezone.utc)
55-
start_time = now + timedelta(days=1)
56-
end_time = now + timedelta(days=7)
5727

58-
# Collect room email addresses if available
59-
attendee_smtp = ["meganb@contoso.onmicrosoft.com"]
28+
attendees = ["meganb@contoso.onmicrosoft.com"]
6029
if room_lists:
61-
for rl in room_lists[:1]: # first room list
62-
try:
63-
rooms = rl.rooms.get().execute_query()
64-
attendee_smtp.extend(r.email_address for r in rooms[:2] if r.email_address)
65-
except Exception:
66-
pass
67-
68-
print(f"\nFinding meeting times for: {', '.join(attendee_smtp)}")
69-
print(f" Window: {start_time.strftime('%Y-%m-%d %H:%M')}{end_time.strftime('%Y-%m-%d %H:%M')}")
70-
71-
suggestions = client.me.find_meeting_times(
72-
attendees=attendee_smtp,
73-
meeting_duration=timedelta(hours=1),
74-
max_candidates=5,
30+
try:
31+
rooms = room_lists[0].rooms.get().execute_query()
32+
attendees.extend(r.email_address for r in rooms[:2] if r.email_address)
33+
except Exception:
34+
pass
35+
36+
result = client.me.find_meeting_times(
37+
attendees=attendees, meeting_duration=timedelta(hours=1), max_candidates=5
7538
).execute_query()
76-
77-
if suggestions and hasattr(suggestions, "value") and suggestions.value:
78-
print(f"\nSuggested times ({len(suggestions.value)} candidate(s)):\n")
79-
# The value is a MeetingTimeSuggestionsResult
80-
result = suggestions.value
81-
if hasattr(result, "meeting_time_suggestions") and result.meeting_time_suggestions:
82-
for s in result.meeting_time_suggestions:
83-
slot = s.meeting_time_slot
84-
print(
85-
f" {slot.start.strftime('%Y-%m-%d %H:%M')} — "
86-
f"{slot.end.strftime('%H:%M')} (confidence: {s.confidence})"
87-
)
88-
if hasattr(s, "locations") and s.locations:
89-
for loc in s.locations:
90-
print(f" Location: {loc.display_name}")
91-
else:
92-
print(" (no detailed suggestions — check permissions)")
93-
else:
94-
print(" No meeting suggestions returned.")
39+
if result and result.value and result.value.meeting_time_suggestions:
40+
for s in result.value.meeting_time_suggestions:
41+
slot = s.meeting_time_slot
42+
print(f" {slot.start}{slot.end} (confidence: {s.confidence})")
9543

9644

9745
if __name__ == "__main__":

examples/outlook/messages/mail_tips.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121

2222
client = GraphClient(tenant=test_tenant).with_username_and_password(test_client_id, test_username, test_password)
2323

24-
tips = client.me.get_mail_tips([test_user_principal_name]).execute_query()
25-
for tip in tips.value or []:
26-
print(f"Recipient: {tip.email_address.address}")
27-
print(f" Auto-replies: {tip.automatic_replies.message if tip.automatic_replies else 'none'}")
24+
result = client.me.get_mail_tips([test_user_principal_name]).execute_query()
25+
for tip in result.value:
26+
print(f"Recipient: {tip.emailAddress}")
27+
print(f" Auto-replies: {tip.automaticReplies.message}")
2828
print(f" Out of office: {tip.out_of_office}")
2929
print(f" Mailbox full: {tip.mailbox_full}")
3030
print(f" Max message size: {tip.max_message_size}")

examples/outlook/messages/mailbox_settings.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,17 @@
1818
client = GraphClient(tenant=test_tenant).with_username_and_password(test_client_id, test_username, test_password)
1919

2020
# Read current mailbox settings
21-
settings = client.me.mailbox_settings.get().execute_query()
22-
print(f"Current automatic replies: {settings.automatic_replies_status}")
23-
24-
# Enable scheduled automatic replies
25-
settings.set_property(
26-
"automaticRepliesSetting",
27-
{
28-
"status": "scheduled",
29-
"scheduledStartDateTime": {
30-
"dateTime": (datetime.utcnow() + timedelta(hours=1)).isoformat(),
31-
"timeZone": "UTC",
32-
},
33-
"scheduledEndDateTime": {
34-
"dateTime": (datetime.utcnow() + timedelta(days=7)).isoformat(),
35-
"timeZone": "UTC",
36-
},
37-
"internalReplyMessage": "I'm out of the office this week.",
38-
"externalReplyMessage": "I'm out of the office. Please contact my manager.",
39-
},
40-
).update().execute_query()
21+
me = client.me.select(["MailboxSettings"]).get().execute_query()
22+
print(f"Current automatic replies: {me.mailbox_settings.automaticRepliesSetting}")
23+
24+
start = datetime.now()
25+
end = start + timedelta(days=5)
26+
me.enable_automatic_replies_setting(
27+
status="scheduled",
28+
scheduled_start_datetime=start,
29+
scheduled_end_datetime=end,
30+
internal_reply_message="I'm out of the office this week.",
31+
external_reply_message="I'm out of the office. Please contact my manager.",
32+
).execute_query()
33+
4134
print("Automatic replies enabled")
Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
"""
2-
Shared mailboxes: list, check quotas, and find without owners.
2+
Shared mailboxes: list shared mailboxes in the tenant.
33
4-
Track shared mailboxes for licensing and governance.
5-
6-
Requires delegated permission ``User.Read.All``.
7-
8-
https://learn.microsoft.com/en-us/graph/api/user-list
4+
Requires delegated permission User.Read.All.
95
"""
106

117
from office365.graph_client import GraphClient
@@ -14,8 +10,8 @@
1410
client = GraphClient(tenant=test_tenant).with_client_secret(test_client_id, test_client_secret)
1511

1612
shared = (
17-
client.users.filter("userType eq 'member' and userPrincipalName startsWith 'shared'").top(10).get().execute_query()
13+
client.users.filter("userType eq 'Member' and startswith(userPrincipalName, 'shared')").top(10).get().execute_query()
1814
)
19-
print(f"Shared mailboxes found: {len(shared)}")
15+
print(f"Shared mailboxes: {len(shared)}")
2016
for m in shared:
21-
print(f" {m.display_name:30s} {m.user_principal_name} ({m.user_type or '?'})")
17+
print(f" {m.user_principal_name}")

examples/teams/call_records.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ def main():
1515
print(f"Call records: {len(records)}\n")
1616

1717
for r in records:
18-
org = r.organizer.user.user_principal_name if r.organizer and r.organizer.user else "?"
19-
print(f" {r.start_date_time} {r.type_.name} organizer={org}")
18+
print(f" {r.start_date_time} {r.type_.name} organizer={r.organizer.user}")
2019

2120
if records:
2221
print()

examples/teams/tags/create_and_assign.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def main():
3030

3131
if member_ids:
3232
tag = team.tags.add(
33-
displayName=TAG_NAME, description=TAG_DESCRIPTION,
33+
displayName=TAG_NAME,
34+
description=TAG_DESCRIPTION,
3435
members=[{"userId": uid} for uid in member_ids],
3536
).execute_query()
3637
print(f"Tag created: {tag.display_name} ({len(member_ids)} members)")

generator/.checkpoints/SharePoint.xml.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

office365/outlook/mail/tips/tips.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,17 @@
44

55
from office365.outlook.calendar.email_address import EmailAddress
66
from office365.outlook.mail.automaticreplies.mailtips import AutomaticRepliesMailTips
7+
from office365.outlook.mail.recipient import Recipient
8+
from office365.outlook.mail.recipientscopetype import RecipientScopeType
79
from office365.outlook.mail.tips.error import MailTipsError
810
from office365.runtime.client_value import ClientValue
11+
from office365.runtime.client_value_collection import ClientValueCollection
912

1013

1114
@dataclass
1215
class MailTips(ClientValue):
1316
"""Informative messages about a recipient, displayed to users while they're composing a message.
1417
For example, an out-of-office message as an automatic reply for a message recipient.
15-
16-
Fields:
17-
automaticReplies: Mail tips for automatic reply if set up by the recipient.
18-
customMailTip: A custom mail tip set on the recipient's mailbox.
19-
deliveryRestricted: Whether the recipient is delivery restricted.
20-
emailAddress: Email address of the recipient.
21-
error: Error raised when an error occurs during mail tips retrieval.
22-
externalMemberCount: Number of external members if the recipient is a distribution list.
23-
isModerated: Whether sending messages to the recipient requires approval.
2418
"""
2519

2620
automaticReplies: AutomaticRepliesMailTips = field(default_factory=AutomaticRepliesMailTips)
@@ -30,6 +24,13 @@ class MailTips(ClientValue):
3024
error: MailTipsError = field(default_factory=MailTipsError)
3125
externalMemberCount: int | None = None
3226
isModerated: bool | None = None
27+
mailboxFull: bool | None = None
28+
maxMessageSize: int | None = None
29+
recipientScope: RecipientScopeType | None = None
30+
recipientSuggestions: ClientValueCollection[Recipient] = field(
31+
default_factory=lambda: ClientValueCollection(Recipient)
32+
)
33+
totalMemberCount: int | None = None
3334

3435
@property
3536
def entity_type_name(self) -> str:
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from __future__ import annotations
2+
3+
from office365.runtime.client_value import ClientValue
4+
5+
6+
class FieldInsertionItem(ClientValue):
7+
Content: str | None = None
8+
DataType: str | None = None
9+
Name: str | None = None
10+
11+
@property
12+
def entity_type_name(self) -> str:
13+
return "Microsoft.SharePoint.Agreements.Models.FieldInsertionItem"

0 commit comments

Comments
 (0)