Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ $ pyaxm-cli devices [OPTIONS]

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli device`
Expand All @@ -56,6 +57,7 @@ $ pyaxm-cli device [OPTIONS] DEVICE_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli apple-care-coverage`
Expand All @@ -74,6 +76,7 @@ $ pyaxm-cli apple-care-coverage [OPTIONS] DEVICE_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli mdm-servers`
Expand All @@ -88,6 +91,7 @@ $ pyaxm-cli mdm-servers [OPTIONS]

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli mdm-server`
Expand All @@ -106,6 +110,7 @@ $ pyaxm-cli mdm-server [OPTIONS] SERVER_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli mdm-server-assigned`
Expand All @@ -124,6 +129,7 @@ $ pyaxm-cli mdm-server-assigned [OPTIONS] DEVICE_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli assign-device`
Expand All @@ -143,6 +149,7 @@ $ pyaxm-cli assign-device [OPTIONS] DEVICE_IDS... SERVER_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli unassign-device`
Expand All @@ -162,6 +169,7 @@ $ pyaxm-cli unassign-device [OPTIONS] DEVICE_IDS... SERVER_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli audit-events`
Expand All @@ -187,6 +195,7 @@ $ pyaxm-cli audit-events [OPTIONS] START_TIMESTAMP END_TIMESTAMP
* `-l, --limit INTEGER`
* `-f, --fields TEXT`
* `-c, --cursor TEXT`
* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli users`
Expand All @@ -201,6 +210,7 @@ $ pyaxm-cli users [OPTIONS]

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.

## `pyaxm-cli user`
Expand All @@ -219,4 +229,5 @@ $ pyaxm-cli user [OPTIONS] USER_ID

**Options**:

* `--format TEXT`: Output format [default: yaml]
* `--help`: Show this message and exit.
98 changes: 67 additions & 31 deletions pyaxm/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import sys
import pandas as pd
import typer
import yaml
from typing_extensions import Annotated
from typing import List, Optional
from pyaxm.client import Client
Expand All @@ -9,11 +10,24 @@
app = typer.Typer()


def _output(data, format: str):
"""Output data as YAML or CSV to stdout."""
if format == "csv":
if isinstance(data, dict):
data = [data]
df = pd.DataFrame(data)
df.to_csv(sys.stdout, index=False)
else:
yaml.dump(data, sys.stdout, default_flow_style=False)


# ── device commands ─────────────────────────────────────────────────


@app.command()
def devices():
def devices(
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""List all devices in the organization."""
client = Client()
devices = client.list_devices()
Expand All @@ -22,37 +36,45 @@ def devices():
info = {"id": d.id}
info.update(d.attributes.model_dump())
records.append(info)
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)

_output(records, format)


@app.command()
def device(device_id: Annotated[str, typer.Argument()]):
def device(
device_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Get a device by ID."""
client = Client()
d = client.get_device(device_id)
info = {"id": d.id}
if d.attributes:
info.update(d.attributes.model_dump())
df = pd.DataFrame([info])
df.to_csv(sys.stdout, index=False)

_output(info, format)


@app.command()
def apple_care_coverage(device_id: Annotated[str, typer.Argument()]):
def apple_care_coverage(
device_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Get AppleCare coverage for a device."""
client = Client()
coverage = client.get_apple_care_coverage(device_id)
records = [{"id": item.id, **item.attributes.model_dump()} for item in coverage]
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)

_output(records, format)


# ── MDM server commands ─────────────────────────────────────────────


@app.command()
def mdm_servers():
def mdm_servers(
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""List all MDM servers."""
client = Client()
servers = client.list_mdm_servers()
Expand All @@ -61,43 +83,50 @@ def mdm_servers():
info = {"id": s.id}
info.update(s.attributes.model_dump())
records.append(info)
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)

_output(records, format)


@app.command()
def mdm_server(server_id: Annotated[str, typer.Argument()]):
def mdm_server(
server_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""List devices in a specific MDM server."""
client = Client()
devices = client.list_devices_in_mdm_server(server_id)
records = [{"id": d.id} for d in devices]
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)

_output(records, format)


@app.command()
def mdm_server_assigned(device_id: Annotated[str, typer.Argument()]):
def mdm_server_assigned(
device_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Get the server assignment for a device."""
client = Client()
assignment = client.get_device_server_assignment(device_id)
records = [{"id": assignment.id}]
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)
info = {"id": assignment.id}

_output(info, format)


@app.command()
def assign_device(
device_ids: Annotated[List[str], typer.Argument()],
server_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Assign one or more devices to an MDM server."""
client = Client()
activity = client.assign_unassign_device_to_mdm_server(device_ids, server_id, "ASSIGN_DEVICES")
info = {"id": activity.id}
if activity.attributes:
info.update(activity.attributes.model_dump())
df = pd.DataFrame([info])
df.to_csv(sys.stdout, index=False)

_output(info, format)

file_path = download_activity_csv(activity)
if file_path:
Expand All @@ -108,15 +137,16 @@ def assign_device(
def unassign_device(
device_ids: Annotated[List[str], typer.Argument()],
server_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Unassign one or more devices from an MDM server."""
client = Client()
activity = client.assign_unassign_device_to_mdm_server(device_ids, server_id, "UNASSIGN_DEVICES")
info = {"id": activity.id}
if activity.attributes:
info.update(activity.attributes.model_dump())
df = pd.DataFrame([info])
df.to_csv(sys.stdout, index=False)

_output(info, format)

file_path = download_activity_csv(activity)
if file_path:
Expand All @@ -136,6 +166,7 @@ def audit_events(
limit: Annotated[Optional[int], typer.Option("--limit", "-l")] = None,
fields: Annotated[Optional[List[str]], typer.Option("--fields", "-f")] = None,
cursor: Annotated[Optional[str], typer.Option("--cursor", "-c")] = None,
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Get a list of audit events."""
client = Client()
Expand All @@ -154,15 +185,17 @@ def audit_events(
info = {"id": event.id}
info.update(event.attributes.model_dump())
records.append(info)
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)

_output(records, format)


# ── user commands ───────────────────────────────────────────────────


@app.command()
def users():
def users(
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""List all users in the organization."""
client = Client()
users = client.list_users()
Expand All @@ -171,20 +204,23 @@ def users():
info = {"id": u.id}
info.update(u.attributes.model_dump())
records.append(info)
df = pd.DataFrame(records)
df.to_csv(sys.stdout, index=False)

_output(records, format)


@app.command()
def user(user_id: Annotated[str, typer.Argument()]):
def user(
user_id: Annotated[str, typer.Argument()],
format: Annotated[str, typer.Option("--format", help="Output format")] = "yaml",
):
"""Get a user by ID."""
client = Client()
item = client.get_user(user_id)
info = {"id": item.id}
if item.attributes:
info.update(item.attributes.model_dump())
df = pd.DataFrame([info])
df.to_csv(sys.stdout, index=False)

_output(info, format)


if __name__ == "__main__":
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies = [
"pyjwt",
"pandas",
"typer",
"pyyaml",
]
readme = "README.md"
license = "GPL-3.0-or-later"
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ requests
pyjwt
pandas
typer
pyyaml
Loading