Skip to content

Commit aa9bb28

Browse files
committed
copilot: file:files.py の設計を参考に、 file:microsoft_graphs.py の実装を CLI で柔軟に実行できるように整理して
1 parent 3575a40 commit aa9bb28

File tree

2 files changed

+93
-24
lines changed

2 files changed

+93
-24
lines changed

docs/index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,19 @@ uv run python scripts/speeches.py delete-transcription "$JOB_ID" --force
115115

116116
- [Build Python apps with Microsoft Graph](https://learn.microsoft.com/en-us/graph/tutorials/python?tabs=aad)
117117

118+
### Fundamentals
119+
120+
```shell
121+
# Help
122+
uv run python scripts/microsoft_graphs.py --help
123+
124+
# Get access token
125+
uv run python scripts/microsoft_graphs.py get-access-token
126+
127+
# Get my profile
128+
uv run python scripts/microsoft_graphs.py get-my-profile
129+
```
130+
118131
## MCP
119132

120133
- [FastAPI-MCP](https://github.com/tadata-org/fastapi_mcp)

scripts/microsoft_graphs.py

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,102 @@
1+
#!/usr/bin/env python
2+
13
import asyncio
24

5+
import typer
36
from azure.identity import DeviceCodeCredential
47
from msgraph import GraphServiceClient
58
from msgraph.generated.users.item.user_item_request_builder import UserItemRequestBuilder
9+
from rich.console import Console
10+
from rich.table import Table
611

712
from template_fastapi.settings.microsoft_graphs import get_microsoft_graph_settings
813

14+
app = typer.Typer()
15+
console = Console()
16+
917

10-
async def main():
11-
# Load settings
18+
def get_graph_client() -> tuple[GraphServiceClient, list[str]]:
19+
"""Microsoft Graph クライアントを取得する"""
1220
settings = get_microsoft_graph_settings()
1321
scopes = settings.microsoft_graph_user_scopes.split(" ")
1422

15-
print(settings.model_dump_json(indent=2))
16-
print(scopes)
17-
18-
# Add authentication
1923
device_code_credential = DeviceCodeCredential(
2024
client_id=settings.microsoft_graph_client_id,
2125
tenant_id=settings.microsoft_graph_tenant_id,
2226
)
23-
# access_token = device_code_credential.get_token(*scopes)
24-
# print(f"Access Token: {access_token.token}")
25-
26-
# Get user profile
27-
# Only request specific properties using $select
28-
query_params = UserItemRequestBuilder.UserItemRequestBuilderGetQueryParameters(
29-
select=[
30-
"displayName",
31-
"mail",
32-
"userPrincipalName",
33-
]
34-
)
35-
request_config = UserItemRequestBuilder.UserItemRequestBuilderGetRequestConfiguration(query_parameters=query_params)
36-
user_client = GraphServiceClient(
27+
28+
client = GraphServiceClient(
3729
credentials=device_code_credential,
3830
scopes=scopes,
3931
)
4032

41-
user = await user_client.me.get(request_configuration=request_config)
42-
print(f"User: {user.display_name} ({user.mail})")
33+
return client, scopes
34+
35+
36+
@app.command()
37+
def get_my_profile(
38+
fields: list[str] | None = typer.Option(None, "--field", "-f", help="取得するフィールドを指定(複数指定可能)"),
39+
):
40+
"""自分のプロファイル情報を取得する"""
41+
console.print("[bold green]ユーザープロファイル[/bold green]を取得します")
42+
43+
# デフォルトのフィールド
44+
default_fields = ["displayName", "mail", "userPrincipalName", "id", "jobTitle", "department"]
45+
select_fields = fields or default_fields
46+
47+
async def _get_profile():
48+
try:
49+
client, _ = get_graph_client()
50+
51+
query_params = UserItemRequestBuilder.UserItemRequestBuilderGetQueryParameters(select=select_fields)
52+
request_config = UserItemRequestBuilder.UserItemRequestBuilderGetRequestConfiguration(
53+
query_parameters=query_params
54+
)
55+
56+
user = await client.me.get(request_configuration=request_config)
57+
58+
# テーブルで表示
59+
table = Table(title="ユーザープロファイル")
60+
table.add_column("項目", style="cyan")
61+
table.add_column("値", style="green")
62+
63+
# 動的にフィールドを表示
64+
for field in select_fields:
65+
value = getattr(user, field.replace("_", ""), "N/A")
66+
if value is not None:
67+
table.add_row(field, str(value))
68+
69+
console.print(table)
70+
71+
except Exception as e:
72+
console.print(f"[bold red]エラー[/bold red]: {str(e)}")
73+
74+
asyncio.run(_get_profile())
75+
76+
77+
@app.command()
78+
def get_access_token():
79+
"""アクセストークンを取得する"""
80+
console.print("[bold green]アクセストークン[/bold green]を取得します")
81+
82+
try:
83+
settings = get_microsoft_graph_settings()
84+
scopes = settings.microsoft_graph_user_scopes.split(" ")
85+
86+
device_code_credential = DeviceCodeCredential(
87+
client_id=settings.microsoft_graph_client_id,
88+
tenant_id=settings.microsoft_graph_tenant_id,
89+
)
90+
91+
access_token = device_code_credential.get_token(*scopes)
92+
93+
console.print("[bold green]トークン取得成功[/bold green]")
94+
console.print(f" トークン: {access_token.token}")
95+
console.print(f" 期限: {access_token.expires_on}")
96+
97+
except Exception as e:
98+
console.print(f"[bold red]エラー[/bold red]: {str(e)}")
4399

44100

45-
# Run main
46-
asyncio.run(main())
101+
if __name__ == "__main__":
102+
app()

0 commit comments

Comments
 (0)