mirror of
https://github.com/HKUDS/CLI-Anything.git
synced 2026-10-31 02:42:19 +08:00
Merge pull request #275 from iGodly/feat/mailchimp-cli-harness
feat: add Mailchimp CLI harness
This commit is contained in:
@@ -87,6 +87,7 @@
|
||||
!/macrocli/
|
||||
!/sbox/
|
||||
!/quietshrink/
|
||||
!/mailchimp/
|
||||
|
||||
# Step 5: Inside each software dir, ignore everything (including dotfiles)
|
||||
/gimp/*
|
||||
@@ -181,6 +182,8 @@
|
||||
/sbox/.*
|
||||
/quietshrink/*
|
||||
/quietshrink/.*
|
||||
/mailchimp/*
|
||||
/mailchimp/.*
|
||||
|
||||
# Step 6: ...except agent-harness/
|
||||
!/gimp/agent-harness/
|
||||
@@ -235,6 +238,7 @@
|
||||
!/macrocli/agent-harness/
|
||||
!/sbox/agent-harness/
|
||||
!/quietshrink/agent-harness/
|
||||
!/mailchimp/agent-harness/
|
||||
|
||||
# Exclude non-gedit demo macros from macrocli (local only)
|
||||
/macrocli/agent-harness/cli_anything/macrocli/macro_definitions/demo/flameshot*
|
||||
|
||||
@@ -862,6 +862,13 @@ Each application received complete, production-ready CLI interfaces — not demo
|
||||
<td align="center">✅ <a href="n8n/agent-harness/">55+ cmds</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><strong>📧 <a href="mailchimp/agent-harness/">Mailchimp</a></strong></td>
|
||||
<td>Email Marketing & Automation</td>
|
||||
<td><code>cli-anything-mailchimp</code></td>
|
||||
<td>Mailchimp Marketing API v3.0</td>
|
||||
<td align="center">✅ <a href="mailchimp/agent-harness/">303 cmds</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><strong>📚 <a href="zotero/agent-harness/">Zotero</a></strong></td>
|
||||
<td>Reference Management</td>
|
||||
<td><code>cli-anything-zotero</code></td>
|
||||
@@ -1162,6 +1169,7 @@ cli-anything/
|
||||
├── 🎵 audacity/agent-harness/ # Audacity CLI (161 tests)
|
||||
├── 🌐 browser/agent-harness/ # Browser CLI (DOMShell MCP, new)
|
||||
├── 📄 libreoffice/agent-harness/ # LibreOffice CLI (158 tests)
|
||||
├── 📧 mailchimp/agent-harness/ # Mailchimp Marketing API CLI (303 commands, 36 unit tests)
|
||||
├── 📚 zotero/agent-harness/ # Zotero CLI (new, write import support)
|
||||
├── 📝 mubu/agent-harness/ # Mubu CLI (96 tests)
|
||||
├── 📹 obs-studio/agent-harness/ # OBS Studio CLI (153 tests)
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# MAILCHIMP.md — cli-anything Harness for Mailchimp Marketing API v3.0
|
||||
|
||||
## Overview
|
||||
|
||||
`cli-anything-mailchimp` makes the [Mailchimp Marketing API v3.0](https://mailchimp.com/developer/marketing/docs/fundamentals/) fully agent-native. Every endpoint from the official Swagger spec is exposed as a typed Click command, with JSON output and REPL mode.
|
||||
|
||||
**303 commands across 30 resource groups**, covering the full Marketing API surface.
|
||||
|
||||
---
|
||||
|
||||
## Backend
|
||||
|
||||
| Property | Value |
|
||||
|---|---|
|
||||
| API base | `https://<dc>.api.mailchimp.com/3.0` |
|
||||
| Auth | HTTP Basic — username `anystring`, password = API key |
|
||||
| Key format | `<random>-<datacenter>` e.g. `abc123-us8` |
|
||||
| Spec source | `mailchimp/mailchimp-client-lib-codegen` → `spec/marketing.json` (Swagger 2.0) |
|
||||
|
||||
**Required env var:**
|
||||
```bash
|
||||
export MAILCHIMP_API_KEY=<your-key>-<datacenter>
|
||||
```
|
||||
No config files. The data-centre prefix (`us8`, `eu2`, etc.) is derived automatically from the API key suffix.
|
||||
|
||||
---
|
||||
|
||||
## Command Hierarchy
|
||||
|
||||
```
|
||||
cli-anything-mailchimp [--json] [--version]
|
||||
│
|
||||
├── ping # GET /ping — health check
|
||||
├── root # GET / — account info
|
||||
│
|
||||
├── lists # 66 operations (audiences, members, merge fields, segments, tags, webhooks)
|
||||
│ ├── list / get / create / update / delete
|
||||
│ ├── list-lists-id-members / get-lists-id-members-id / create-members / ...
|
||||
│ ├── list-merge-fields / create-merge-fields / ...
|
||||
│ ├── list-segments / get-segment-id / create-segments / ...
|
||||
│ └── list-webhooks / get-webhook-id / create-webhooks / ...
|
||||
│
|
||||
├── campaigns # 22 operations
|
||||
│ ├── list / get / create / update / delete
|
||||
│ ├── send / schedule / cancel-send / pause / resume / replicate
|
||||
│ ├── list-content / list-feedback / get-feedback-id / create-feedback
|
||||
│ └── list-send-checklist / create-resend
|
||||
│
|
||||
├── reports # 22 operations — sent campaign analytics
|
||||
│ ├── list / get
|
||||
│ ├── list-abuse-reports / list-click-details / list-domain-performance
|
||||
│ ├── list-email-activity / list-locations / list-open-details
|
||||
│ └── list-sub-reports / list-unsubscribed
|
||||
│
|
||||
├── automations # 18 operations
|
||||
│ ├── list / get / create / update
|
||||
│ ├── pause / start / archive
|
||||
│ └── list-emails / get-email / pause-email / start-email / delete-email
|
||||
│
|
||||
├── ecommerce # 60 operations — stores, orders, products, carts, promo codes
|
||||
├── templates # 6 operations
|
||||
├── template-folders # 5 operations
|
||||
├── campaign-folders # 5 operations
|
||||
├── file-manager # 11 operations — files and folders
|
||||
├── reporting # 12 operations — Facebook/landing-page reporting
|
||||
├── landing-pages # 8 operations
|
||||
├── sms-campaigns # 10 operations
|
||||
├── surveys # 3 operations
|
||||
├── audiences # 4 operations — connected audience management
|
||||
├── batch-webhooks # 5 operations
|
||||
├── batches # 4 operations — bulk API batch operations
|
||||
├── connected-sites # 5 operations
|
||||
├── contacts # 4 operations
|
||||
├── conversations # 4 operations
|
||||
├── customer-journeys # 1 operation
|
||||
├── facebook-ads # 2 operations
|
||||
├── verified-domains # 5 operations
|
||||
├── authorized-apps # 2 operations
|
||||
├── activity-feed # 1 operation
|
||||
├── account-export # 1 operation
|
||||
├── account-exports # 2 operations
|
||||
├── search-campaigns # 1 operation
|
||||
└── search-members # 1 operation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output Strategy
|
||||
|
||||
All commands share a root `--json` flag:
|
||||
|
||||
```bash
|
||||
cli-anything-mailchimp --json lists list
|
||||
cli-anything-mailchimp --json campaigns get <campaign_id>
|
||||
```
|
||||
|
||||
**JSON envelopes** (commands emit the native Mailchimp API response):
|
||||
|
||||
| Endpoint type | Shape |
|
||||
|---|---|
|
||||
| List / collection | Native shape: `{"lists":[...], "total_items":N}` / `{"campaigns":[...]}` etc. — resource key matches the API path noun |
|
||||
| Single resource GET | Raw Mailchimp response object |
|
||||
| Mutation (POST/PATCH/PUT) | Raw Mailchimp response object |
|
||||
| DELETE | `{"ok": true, "message": "Deleted."}` |
|
||||
| Error | `{"ok": false, "message": "...", "data": <mailchimp-problem-detail>}` |
|
||||
|
||||
Use the Mailchimp-native field name when piping to `jq` (e.g. `.lists[]`, `.campaigns[]`, `.members[]`).
|
||||
|
||||
Human mode prints compact key-value pairs for single objects and annotated lists for collections.
|
||||
|
||||
Collection commands expose Mailchimp's native `count` and `offset` query parameters where the API supports them. The CLI does not auto-fetch every page by default.
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions
|
||||
|
||||
1. **Code generation from spec** — 303 commands are auto-generated from Mailchimp's public Swagger 2.0 spec via `_codegen/generate.py`. Generated files are committed so end-users get fast `--help` without downloading the spec.
|
||||
|
||||
2. **Env-var-only auth** — per CLI-Anything convention, no config files. `MAILCHIMP_API_KEY` is the single source of truth.
|
||||
|
||||
3. **Verbatim `repl_skin.py`** — the REPL skin is copied unmodified from `cli-anything-plugin/repl_skin.py` as required by CLI-Anything's contribution rules.
|
||||
|
||||
4. **Path params as positional args** — Mailchimp path parameters (`{list_id}`, `{campaign_id}`, etc.) become required positional Click arguments, keeping commands concise.
|
||||
|
||||
5. **Body as `--data` JSON** — request bodies are passed as `--data '{"key": "value"}'` JSON strings. This avoids generating dozens of per-field flags per command and works naturally for agent use (agents can construct JSON payloads directly).
|
||||
|
||||
6. **Subscriber hash utility** — `cli_anything.mailchimp.core.client.subscriber_hash(email)` computes the MD5 hash Mailchimp uses as a member identifier, matching the Node.js reference implementation.
|
||||
|
||||
---
|
||||
|
||||
## File Layout
|
||||
|
||||
```
|
||||
mailchimp/agent-harness/
|
||||
├── setup.py
|
||||
├── MAILCHIMP.md ← this file
|
||||
└── cli_anything/mailchimp/
|
||||
├── __init__.py
|
||||
├── __main__.py
|
||||
├── mailchimp_cli.py ← Click root + REPL
|
||||
├── README.md
|
||||
├── core/
|
||||
│ ├── client.py ← HTTP client, auth, error handling
|
||||
│ └── pagination.py ← count/offset paginator
|
||||
├── commands/ ← auto-generated (30 modules)
|
||||
│ ├── __init__.py ← imports ALL_GROUPS
|
||||
│ ├── lists.py ← 66 commands
|
||||
│ ├── campaigns.py ← 22 commands
|
||||
│ └── ... ← one module per tag
|
||||
├── utils/
|
||||
│ ├── output.py ← _out() JSON/human switch
|
||||
│ └── repl_skin.py ← verbatim copy from cli-anything-plugin/repl_skin.py
|
||||
├── _codegen/
|
||||
│ └── generate.py ← spec → commands/*.py generator
|
||||
├── skills/SKILL.md ← packaged skill copy
|
||||
└── tests/
|
||||
├── TEST.md
|
||||
├── test_core.py ← unit tests (no API key)
|
||||
└── test_full_e2e.py ← 9 live tests (gated on API key)
|
||||
```
|
||||
@@ -0,0 +1,26 @@
|
||||
# cli-anything-mailchimp
|
||||
|
||||
Python CLI harness for the [Mailchimp Marketing API v3.0](https://mailchimp.com/developer/marketing/docs/fundamentals/), built on the [CLI-Anything](https://github.com/HKUDS/CLI-Anything) framework.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=mailchimp/agent-harness
|
||||
```
|
||||
|
||||
## Auth
|
||||
|
||||
```bash
|
||||
export MAILCHIMP_API_KEY=<your-api-key>-<datacenter>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
cli-anything-mailchimp ping
|
||||
cli-anything-mailchimp --json lists list
|
||||
cli-anything-mailchimp --json campaigns list --count 10
|
||||
cli-anything-mailchimp # interactive REPL
|
||||
```
|
||||
|
||||
See `SKILL.md` for full command reference.
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
from cli_anything.mailchimp.mailchimp_cli import main
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,429 @@
|
||||
"""
|
||||
Code generator: Mailchimp Swagger 2.0 spec → Click command modules.
|
||||
|
||||
Usage:
|
||||
python -m cli_anything.mailchimp._codegen.generate
|
||||
|
||||
Downloads the Mailchimp Marketing API spec and emits one Python module per
|
||||
tag into cli_anything/mailchimp/commands/. The generated files are committed
|
||||
to the repository so end-users do not need to run the generator.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import builtins
|
||||
import json
|
||||
import keyword
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
SPEC_URL = (
|
||||
"https://raw.githubusercontent.com/mailchimp/mailchimp-client-lib-codegen"
|
||||
"/main/spec/marketing.json"
|
||||
)
|
||||
|
||||
OUT_DIR = Path(__file__).resolve().parents[1] / "commands"
|
||||
|
||||
# Tags that should be skipped (internal/meta).
|
||||
_SKIP_TAGS: set[str] = set()
|
||||
|
||||
# Names that must not appear as Python function/param names even if technically
|
||||
# valid identifiers (builtins + common shadowing traps).
|
||||
_BUILTIN_NAMES: frozenset[str] = frozenset(dir(builtins))
|
||||
|
||||
|
||||
def _slugify(name: str) -> str:
|
||||
"""Convert camelCase or PascalCase or space-separated to kebab-case."""
|
||||
s = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1-\2", name)
|
||||
s = re.sub(r"([a-z\d])([A-Z])", r"\1-\2", s)
|
||||
s = s.replace(" ", "-").replace("_", "-").lower()
|
||||
s = re.sub(r"-+", "-", s).strip("-")
|
||||
return s
|
||||
|
||||
|
||||
def _safe_name(name: str) -> str:
|
||||
"""Convert a string to a safe Python identifier (keywords and builtins get underscore suffix)."""
|
||||
name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
||||
if name and name[0].isdigit():
|
||||
name = "_" + name
|
||||
if keyword.iskeyword(name) or name in _BUILTIN_NAMES:
|
||||
name += "_"
|
||||
return name
|
||||
|
||||
|
||||
def _tag_to_module(tag: str) -> str:
|
||||
return _slugify(tag).replace("-", "_")
|
||||
|
||||
|
||||
def _tag_to_group(tag: str) -> str:
|
||||
return _slugify(tag)
|
||||
|
||||
|
||||
def _infer_command_name(method: str, path: str, operation_id: str) -> str:
|
||||
"""Derive a clean command name from the HTTP method and path."""
|
||||
# Action endpoints (POST to .../actions/xxx)
|
||||
action_match = re.search(r"/actions/([^/]+)$", path)
|
||||
if action_match:
|
||||
return _slugify(action_match.group(1))
|
||||
|
||||
# Determine if this is a collection endpoint or single-resource by checking
|
||||
# whether the path ends with a path parameter.
|
||||
ends_with_param = bool(re.search(r"\{[^}]+\}$", path))
|
||||
|
||||
if method == "get":
|
||||
return "get" if ends_with_param else "list"
|
||||
elif method == "post":
|
||||
return "create"
|
||||
elif method in ("patch", "put"):
|
||||
return "update"
|
||||
elif method == "delete":
|
||||
return "delete"
|
||||
else:
|
||||
return _slugify(operation_id)
|
||||
|
||||
|
||||
def _dedup_suffix(cmd_name: str, path: str, operation_id: str, count: int) -> str:
|
||||
"""Return a unique suffix for a colliding command name.
|
||||
|
||||
Prefers a slug derived from the operationId over a raw path segment,
|
||||
because path segments are often path-param shaped ({list_id}) which
|
||||
produces confusing names like 'create-list-id'.
|
||||
"""
|
||||
# Try a meaningful suffix from the operationId (strip the HTTP verb prefix)
|
||||
op_slug = _slugify(re.sub(r"^(get|post|patch|put|delete)", "", operation_id))
|
||||
if op_slug and op_slug != cmd_name:
|
||||
return f"{cmd_name}-{op_slug}"
|
||||
|
||||
# Fall back to the last non-param path segment
|
||||
segments = [s for s in path.rstrip("/").split("/") if s and not s.startswith("{")]
|
||||
if segments:
|
||||
suffix = _slugify(segments[-1])
|
||||
if suffix and suffix != cmd_name:
|
||||
return f"{cmd_name}-{suffix}"
|
||||
|
||||
return f"{cmd_name}-{count}"
|
||||
|
||||
|
||||
def _param_type_to_click(param: dict) -> str:
|
||||
t = param.get("type", "string")
|
||||
if t == "integer":
|
||||
return "int"
|
||||
if t == "boolean":
|
||||
return "bool"
|
||||
return "str"
|
||||
|
||||
|
||||
def _click_help_text(description: str) -> str:
|
||||
"""Return a single-line Click help string without truncating useful API context."""
|
||||
first_line = description.split("\n")[0]
|
||||
return " ".join(first_line.replace('"', '\\"').split())
|
||||
|
||||
|
||||
def _collect_params(operation: dict, path: str) -> tuple[list[dict], list[dict], dict | None]:
|
||||
"""Return (path_params, query_params, body_param) from operation."""
|
||||
params = operation.get("parameters", [])
|
||||
path_params = [p for p in params if p.get("in") == "path"]
|
||||
query_params = [p for p in params if p.get("in") == "query"]
|
||||
body_params = [p for p in params if p.get("in") == "body"]
|
||||
body = body_params[0] if body_params else None
|
||||
return path_params, query_params, body
|
||||
|
||||
|
||||
def _generate_command_func(
|
||||
cmd_name: str,
|
||||
method: str,
|
||||
path: str,
|
||||
operation: dict,
|
||||
path_params: list,
|
||||
query_params: list,
|
||||
body_param: dict | None,
|
||||
) -> str:
|
||||
summary = operation.get("summary", "").replace('"', '\\"')
|
||||
# C1: prefix with _cmd_ so no builtin shadowing (list, get, delete, etc.)
|
||||
func_name = "_cmd_" + _safe_name(cmd_name.replace("-", "_"))
|
||||
|
||||
lines: list[str] = []
|
||||
|
||||
group_var = f"{_tag_to_module(operation['tags'][0])}_group"
|
||||
decorators = [f'@{group_var}.command("{cmd_name}")']
|
||||
|
||||
# Path params as Click arguments (positional)
|
||||
for p in path_params:
|
||||
py_arg = _safe_name(p["name"]).upper()
|
||||
decorators.append(f'@click.argument("{py_arg}")')
|
||||
|
||||
# Body option
|
||||
if body_param is not None:
|
||||
decorators.append(
|
||||
'@click.option("--data", default=None, '
|
||||
'help="Request body as JSON string.")'
|
||||
)
|
||||
|
||||
# I3: All query params (no arbitrary cap); --extra-params escape hatch
|
||||
for p in query_params:
|
||||
flag = _slugify(p["name"])
|
||||
py_name = _safe_name(p["name"]).lower()
|
||||
ptype = _param_type_to_click(p)
|
||||
desc = _click_help_text(p.get("description", ""))
|
||||
if ptype == "int":
|
||||
type_clause = "type=int, "
|
||||
elif ptype == "bool":
|
||||
type_clause = "type=bool, "
|
||||
else:
|
||||
type_clause = ""
|
||||
decorators.append(
|
||||
f'@click.option("--{flag}", "{py_name}", default=None, {type_clause}help="{desc}")'
|
||||
)
|
||||
|
||||
# Escape hatch for extra/future query params
|
||||
decorators.append(
|
||||
'@click.option("--extra-params", default=None, '
|
||||
'help="Extra query params as JSON object, e.g. \'{\\"key\\":\\"val\\"}\'")'
|
||||
)
|
||||
|
||||
decorators.append("@click.pass_context")
|
||||
|
||||
for d in decorators:
|
||||
lines.append(d)
|
||||
|
||||
# Function signature — M4: no module-level USE_JSON import needed
|
||||
sig_parts = ["ctx"]
|
||||
for p in path_params:
|
||||
sig_parts.append(_safe_name(p["name"]).lower())
|
||||
if body_param is not None:
|
||||
sig_parts.append("data")
|
||||
for p in query_params:
|
||||
sig_parts.append(_safe_name(p["name"]).lower())
|
||||
sig_parts.append("extra_params")
|
||||
|
||||
lines.append(f'def {func_name}({", ".join(sig_parts)}):')
|
||||
lines.append(f' """{summary}"""')
|
||||
|
||||
lines.append(" from cli_anything.mailchimp.core.client import get_client, MailchimpError")
|
||||
lines.append(" from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err")
|
||||
|
||||
# Build path with lowercased path params
|
||||
url_parts = re.sub(
|
||||
r"\{([^}]+)\}",
|
||||
lambda m: "{" + _safe_name(m.group(1)).lower() + "}",
|
||||
path,
|
||||
)
|
||||
lines.append(f' path = f"{url_parts}"')
|
||||
|
||||
# Build query params dict
|
||||
if query_params:
|
||||
lines.append(" params = {k: v for k, v in {")
|
||||
for p in query_params:
|
||||
py_name = _safe_name(p["name"]).lower()
|
||||
lines.append(f' "{p["name"]}": {py_name},')
|
||||
lines.append(" }.items() if v is not None}")
|
||||
else:
|
||||
lines.append(" params = {}")
|
||||
|
||||
# Merge --extra-params
|
||||
lines.append(" if extra_params:")
|
||||
lines.append(' params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))')
|
||||
|
||||
# Parse body
|
||||
if body_param is not None:
|
||||
lines.append(' body = _parse_json_option(data, "--data") if data else None')
|
||||
|
||||
# Make the request
|
||||
lines.append(" client = get_client()")
|
||||
lines.append(" try:")
|
||||
if method == "get":
|
||||
lines.append(" result = client.get(path, params=params or None)")
|
||||
elif method == "post":
|
||||
body_arg = "body" if body_param else "None"
|
||||
lines.append(f" result = client.post(path, json={body_arg}, params=params or None)")
|
||||
elif method == "patch":
|
||||
body_arg = "body" if body_param else "None"
|
||||
lines.append(f" result = client.patch(path, json={body_arg}, params=params or None)")
|
||||
elif method == "put":
|
||||
body_arg = "body" if body_param else "None"
|
||||
lines.append(f" result = client.put(path, json={body_arg}, params=params or None)")
|
||||
elif method == "delete":
|
||||
lines.append(" result = client.delete(path, params=params or None)")
|
||||
else:
|
||||
lines.append(" result = client.get(path, params=params or None)")
|
||||
|
||||
lines.append(" except MailchimpError as e:")
|
||||
lines.append(" _out_err(e.status, e.title, e.detail, e.raw)")
|
||||
lines.append(" return")
|
||||
|
||||
if method == "delete":
|
||||
lines.append(' _out_ok("Deleted.")')
|
||||
else:
|
||||
lines.append(" _out(result)")
|
||||
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _generate_module(tag: str, operations: list[tuple[str, str, dict]]) -> str:
|
||||
"""Generate a complete Python module for a given tag."""
|
||||
module_name = _tag_to_module(tag)
|
||||
group_name = _tag_to_group(tag)
|
||||
group_var = f"{module_name}_group"
|
||||
|
||||
group_decorator = f'@click.group("{group_name}")'
|
||||
group_signature = f"def {group_var}(ctx):"
|
||||
if tag.lower() == "ping":
|
||||
group_decorator = f'@click.group("{group_name}", invoke_without_command=True)'
|
||||
group_lines = [
|
||||
f' """{_slugify(tag)} resource commands."""',
|
||||
]
|
||||
if tag.lower() == "ping":
|
||||
group_lines.extend(
|
||||
[
|
||||
" if ctx.invoked_subcommand is None:",
|
||||
" ctx.invoke(_cmd_list_)",
|
||||
]
|
||||
)
|
||||
|
||||
header_lines = [
|
||||
f'"""Commands for the Mailchimp /{group_name} API resource.',
|
||||
"",
|
||||
"Auto-generated by cli_anything/mailchimp/_codegen/generate.py.",
|
||||
"Do not edit manually — re-run the generator to update.",
|
||||
'"""',
|
||||
"",
|
||||
"import json",
|
||||
"",
|
||||
"import click",
|
||||
"",
|
||||
"",
|
||||
"def _parse_json_option(value, option_name, require_object=False):",
|
||||
" try:",
|
||||
" parsed = json.loads(value)",
|
||||
" except json.JSONDecodeError as exc:",
|
||||
" raise click.BadParameter(",
|
||||
' f"must be valid JSON ({exc.msg})",',
|
||||
" param_hint=option_name,",
|
||||
" ) from exc",
|
||||
" if require_object and not isinstance(parsed, dict):",
|
||||
' raise click.BadParameter("must be a JSON object", param_hint=option_name)',
|
||||
" return parsed",
|
||||
"",
|
||||
"",
|
||||
group_decorator,
|
||||
"@click.pass_context",
|
||||
group_signature,
|
||||
*group_lines,
|
||||
"",
|
||||
"",
|
||||
]
|
||||
header = "\n".join(header_lines)
|
||||
|
||||
body_parts: list[str] = []
|
||||
# Track ALL assigned names (base + deduped) to guarantee uniqueness.
|
||||
assigned: set[str] = set()
|
||||
|
||||
for method, path, operation in sorted(operations, key=lambda x: (x[1], x[0])):
|
||||
op_id = operation.get("operationId", "")
|
||||
cmd_name = _infer_command_name(method, path, op_id)
|
||||
|
||||
# I4: De-duplicate using operationId slug; fall back to counter if still collides.
|
||||
if cmd_name in assigned:
|
||||
candidate = _dedup_suffix(cmd_name, path, op_id, 2)
|
||||
counter = 2
|
||||
while candidate in assigned:
|
||||
counter += 1
|
||||
candidate = f"{cmd_name}-{counter}"
|
||||
cmd_name = candidate
|
||||
|
||||
assigned.add(cmd_name)
|
||||
|
||||
operation = dict(operation)
|
||||
operation.setdefault("tags", [tag])
|
||||
|
||||
path_params, query_params, body_param = _collect_params(operation, path)
|
||||
func_code = _generate_command_func(
|
||||
cmd_name, method, path, operation, path_params, query_params, body_param
|
||||
)
|
||||
body_parts.append(func_code)
|
||||
if tag.lower() == "campaigns" and cmd_name == "list-campaigns-id-content":
|
||||
body_parts.append('campaigns_group.add_command(_cmd_list_campaigns_id_content, "list-content")\n')
|
||||
if tag.lower() == "campaigns" and cmd_name == "list-campaigns-id-send-checklist":
|
||||
body_parts.append('campaigns_group.add_command(_cmd_list_campaigns_id_send_checklist, "list-send-checklist")\n')
|
||||
if tag.lower() == "reports" and cmd_name == "list-reports-id-click-details":
|
||||
body_parts.append('reports_group.add_command(_cmd_list_reports_id_click_details, "list-click-details")\n')
|
||||
if tag.lower() == "reports" and cmd_name == "list-reports-id-domain-performance":
|
||||
body_parts.append('reports_group.add_command(_cmd_list_reports_id_domain_performance, "list-domain-performance")\n')
|
||||
if tag.lower() == "reports" and cmd_name == "list-reports-id-email-activity":
|
||||
body_parts.append('reports_group.add_command(_cmd_list_reports_id_email_activity, "list-email-activity")\n')
|
||||
if tag.lower() == "reports" and cmd_name == "list-reports-id-locations":
|
||||
body_parts.append('reports_group.add_command(_cmd_list_reports_id_locations, "list-locations")\n')
|
||||
if tag.lower() == "reports" and cmd_name == "list-reports-id-open-details":
|
||||
body_parts.append('reports_group.add_command(_cmd_list_reports_id_open_details, "list-open-details")\n')
|
||||
if tag.lower() == "reports" and cmd_name == "list-reports-id-unsubscribed":
|
||||
body_parts.append('reports_group.add_command(_cmd_list_reports_id_unsubscribed, "list-unsubscribed")\n')
|
||||
if tag.lower() == "automations" and cmd_name == "list-automations-id-emails":
|
||||
body_parts.append('automations_group.add_command(_cmd_list_automations_id_emails, "list-emails")\n')
|
||||
if tag.lower() == "lists" and cmd_name == "create-lists-id-members":
|
||||
body_parts.append('lists_group.add_command(_cmd_create_lists_id_members, "create-members")\n')
|
||||
if tag.lower() == "lists" and cmd_name == "list-preview-a-segment":
|
||||
body_parts.append('lists_group.add_command(_cmd_list_preview_a_segment, "list-lists-id-segments")\n')
|
||||
|
||||
return header + "\n".join(body_parts)
|
||||
|
||||
|
||||
def load_spec(url: str = SPEC_URL) -> dict:
|
||||
print(f"Fetching spec from {url} ...", file=sys.stderr)
|
||||
resp = requests.get(url, timeout=60)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def generate(spec: dict, out_dir: Path = OUT_DIR) -> None:
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
by_tag: dict[str, list[tuple[str, str, dict]]] = defaultdict(list)
|
||||
|
||||
for path, path_item in spec.get("paths", {}).items():
|
||||
for method, operation in path_item.items():
|
||||
if method not in ("get", "post", "patch", "put", "delete"):
|
||||
continue
|
||||
if not isinstance(operation, dict):
|
||||
continue
|
||||
tags = operation.get("tags", ["misc"])
|
||||
tag = tags[0]
|
||||
if tag in _SKIP_TAGS:
|
||||
continue
|
||||
by_tag[tag].append((method, path, operation))
|
||||
|
||||
generated: list[str] = []
|
||||
for tag, operations in sorted(by_tag.items()):
|
||||
module_name = _tag_to_module(tag)
|
||||
out_path = out_dir / f"{module_name}.py"
|
||||
code = _generate_module(tag, operations)
|
||||
out_path.write_text(code, encoding="utf-8")
|
||||
generated.append(module_name)
|
||||
print(f" Generated {out_path.name} ({len(operations)} commands)", file=sys.stderr)
|
||||
|
||||
# Write __init__.py that imports all groups
|
||||
init_lines = ['"""Auto-generated command groups for cli-anything-mailchimp."""', ""]
|
||||
for mod in sorted(generated):
|
||||
group_var = f"{mod}_group"
|
||||
init_lines.append(f"from cli_anything.mailchimp.commands.{mod} import {group_var}")
|
||||
init_lines.append("")
|
||||
init_lines.append("ALL_GROUPS = [")
|
||||
for mod in sorted(generated):
|
||||
group_var = f"{mod}_group"
|
||||
init_lines.append(f" {group_var},")
|
||||
init_lines.append("]")
|
||||
init_lines.append("")
|
||||
|
||||
(out_dir / "__init__.py").write_text("\n".join(init_lines), encoding="utf-8")
|
||||
print(f"\nDone — {len(generated)} modules written to {out_dir}", file=sys.stderr)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
spec = load_spec()
|
||||
generate(spec)
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Auto-generated command groups for cli-anything-mailchimp."""
|
||||
|
||||
from cli_anything.mailchimp.commands.account_export import account_export_group
|
||||
from cli_anything.mailchimp.commands.account_exports import account_exports_group
|
||||
from cli_anything.mailchimp.commands.activity_feed import activity_feed_group
|
||||
from cli_anything.mailchimp.commands.audiences import audiences_group
|
||||
from cli_anything.mailchimp.commands.authorized_apps import authorized_apps_group
|
||||
from cli_anything.mailchimp.commands.automations import automations_group
|
||||
from cli_anything.mailchimp.commands.batch_webhooks import batch_webhooks_group
|
||||
from cli_anything.mailchimp.commands.batches import batches_group
|
||||
from cli_anything.mailchimp.commands.campaign_folders import campaign_folders_group
|
||||
from cli_anything.mailchimp.commands.campaigns import campaigns_group
|
||||
from cli_anything.mailchimp.commands.connected_sites import connected_sites_group
|
||||
from cli_anything.mailchimp.commands.contacts import contacts_group
|
||||
from cli_anything.mailchimp.commands.conversations import conversations_group
|
||||
from cli_anything.mailchimp.commands.customer_journeys import customer_journeys_group
|
||||
from cli_anything.mailchimp.commands.ecommerce import ecommerce_group
|
||||
from cli_anything.mailchimp.commands.facebook_ads import facebook_ads_group
|
||||
from cli_anything.mailchimp.commands.file_manager import file_manager_group
|
||||
from cli_anything.mailchimp.commands.landing_pages import landing_pages_group
|
||||
from cli_anything.mailchimp.commands.lists import lists_group
|
||||
from cli_anything.mailchimp.commands.ping import ping_group
|
||||
from cli_anything.mailchimp.commands.reporting import reporting_group
|
||||
from cli_anything.mailchimp.commands.reports import reports_group
|
||||
from cli_anything.mailchimp.commands.root import root_group
|
||||
from cli_anything.mailchimp.commands.search_campaigns import search_campaigns_group
|
||||
from cli_anything.mailchimp.commands.search_members import search_members_group
|
||||
from cli_anything.mailchimp.commands.sms_campaigns import sms_campaigns_group
|
||||
from cli_anything.mailchimp.commands.surveys import surveys_group
|
||||
from cli_anything.mailchimp.commands.template_folders import template_folders_group
|
||||
from cli_anything.mailchimp.commands.templates import templates_group
|
||||
from cli_anything.mailchimp.commands.verified_domains import verified_domains_group
|
||||
|
||||
ALL_GROUPS = [
|
||||
account_export_group,
|
||||
account_exports_group,
|
||||
activity_feed_group,
|
||||
audiences_group,
|
||||
authorized_apps_group,
|
||||
automations_group,
|
||||
batch_webhooks_group,
|
||||
batches_group,
|
||||
campaign_folders_group,
|
||||
campaigns_group,
|
||||
connected_sites_group,
|
||||
contacts_group,
|
||||
conversations_group,
|
||||
customer_journeys_group,
|
||||
ecommerce_group,
|
||||
facebook_ads_group,
|
||||
file_manager_group,
|
||||
landing_pages_group,
|
||||
lists_group,
|
||||
ping_group,
|
||||
reporting_group,
|
||||
reports_group,
|
||||
root_group,
|
||||
search_campaigns_group,
|
||||
search_members_group,
|
||||
sms_campaigns_group,
|
||||
surveys_group,
|
||||
template_folders_group,
|
||||
templates_group,
|
||||
verified_domains_group,
|
||||
]
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Commands for the Mailchimp /account-export API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("account-export")
|
||||
@click.pass_context
|
||||
def account_export_group(ctx):
|
||||
"""account-export resource commands."""
|
||||
|
||||
@account_export_group.command("get")
|
||||
@click.argument("EXPORT_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, export_id, fields, exclude_fields, extra_params):
|
||||
"""Get account export info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/account-exports/{export_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,77 @@
|
||||
"""Commands for the Mailchimp /account-exports API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("account-exports")
|
||||
@click.pass_context
|
||||
def account_exports_group(ctx):
|
||||
"""account-exports resource commands."""
|
||||
|
||||
@account_exports_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List account exports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/account-exports"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@account_exports_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add export"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/account-exports"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Commands for the Mailchimp /activity-feed API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("activity-feed")
|
||||
@click.pass_context
|
||||
def activity_feed_group(ctx):
|
||||
"""activity-feed resource commands."""
|
||||
|
||||
@activity_feed_group.command("list")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, count, offset, extra_params):
|
||||
"""Get latest chimp chatter"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/activity-feed/chimp-chatter"
|
||||
params = {k: v for k, v in {
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,150 @@
|
||||
"""Commands for the Mailchimp /audiences API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("audiences")
|
||||
@click.pass_context
|
||||
def audiences_group(ctx):
|
||||
"""audiences resource commands."""
|
||||
|
||||
@audiences_group.command("list")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--cursor", "cursor", default=None, help="Paginate through a collection of records by setting the `cursor` parameter to a `next_cursor` attribute returned by a previous request. Default value fetches the first \"page\" of results.")
|
||||
@click.option("--created-before", "created_before", default=None, help="Restricts the response to contacts created at or before the specified time (inclusive). Uses ISO 8601 format: 2025-04-23T15:41:36+00:00.")
|
||||
@click.option("--created-since", "created_since", default=None, help="Restricts the response to contacts created after the specified time (exclusive). Uses ISO 8601 format: 2025-04-23T15:41:36+00:00.")
|
||||
@click.option("--updated-before", "updated_before", default=None, help="Restricts the response to contacts updated at or before the specified time (inclusive). Uses ISO 8601 format: 2025-04-23T15:41:36+00:00.")
|
||||
@click.option("--updated-since", "updated_since", default=None, help="Restricts the response to contacts updated after the specified time (exclusive). Uses ISO 8601 format: 2025-04-23T15:41:36+00:00.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Specifies the field to sort the returned contacts by.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, audience_id, fields, exclude_fields, count, cursor, created_before, created_since, updated_before, updated_since, sort_field, sort_dir, extra_params):
|
||||
"""Get Contacts"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}/contacts"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"cursor": cursor,
|
||||
"created_before": created_before,
|
||||
"created_since": created_since,
|
||||
"updated_before": updated_before,
|
||||
"updated_since": updated_since,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@audiences_group.command("create")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--merge-field-validation-mode", "merge_field_validation_mode", default=None, help="Defines how merge field validation is handled. When set to `ignore_required_checks`, the API does not raise an error if required merge fields are missing from the request. When set to `strict`, the API enforces validation and returns an error if any required merge field is not provided. If this setting is omitted, `strict` is applied by default.")
|
||||
@click.option("--data-mode", "data_mode", default=None, help="Indicates the data processing mode. In `historical` mode, contact data changes do not trigger automations or webhooks. In `live mode`, such changes do trigger them.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, audience_id, data, merge_field_validation_mode, data_mode, extra_params):
|
||||
"""Add Contact"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}/contacts"
|
||||
params = {k: v for k, v in {
|
||||
"merge_field_validation_mode": merge_field_validation_mode,
|
||||
"data_mode": data_mode,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@audiences_group.command("get")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.argument("CONTACT_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, audience_id, contact_id, fields, exclude_fields, extra_params):
|
||||
"""Get Contact"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}/contacts/{contact_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@audiences_group.command("update")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.argument("CONTACT_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--merge-field-validation-mode", "merge_field_validation_mode", default=None, help="Defines how merge field validation is handled. When set to `ignore_required_checks`, the API does not raise an error if required merge fields are missing from the request. When set to `strict`, the API enforces validation and returns an error if any required merge field is not provided. If this setting is omitted, `strict` is applied by default.")
|
||||
@click.option("--data-mode", "data_mode", default=None, help="Indicates the data processing mode. In `historical` mode, contact data changes do not trigger automations or webhooks. In `live mode`, such changes do trigger them.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, audience_id, contact_id, data, merge_field_validation_mode, data_mode, extra_params):
|
||||
"""Update Contact"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}/contacts/{contact_id}"
|
||||
params = {k: v for k, v in {
|
||||
"merge_field_validation_mode": merge_field_validation_mode,
|
||||
"data_mode": data_mode,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,81 @@
|
||||
"""Commands for the Mailchimp /authorized-apps API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("authorized-apps")
|
||||
@click.pass_context
|
||||
def authorized_apps_group(ctx):
|
||||
"""authorized-apps resource commands."""
|
||||
|
||||
@authorized_apps_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List authorized apps"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/authorized-apps"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@authorized_apps_group.command("get")
|
||||
@click.argument("APP_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, app_id, fields, exclude_fields, extra_params):
|
||||
"""Get authorized app info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/authorized-apps/{app_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,430 @@
|
||||
"""Commands for the Mailchimp /automations API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("automations")
|
||||
@click.pass_context
|
||||
def automations_group(ctx):
|
||||
"""automations resource commands."""
|
||||
|
||||
@automations_group.command("list")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--before-create-time", "before_create_time", default=None, help="Restrict the response to automations created before this time. Uses the ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-create-time", "since_create_time", default=None, help="Restrict the response to automations created after this time. Uses the ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--before-start-time", "before_start_time", default=None, help="Restrict the response to automations started before this time. Uses the ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-start-time", "since_start_time", default=None, help="Restrict the response to automations started after this time. Uses the ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--status", "status", default=None, help="Restrict the results to automations with the specified status.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, count, offset, fields, exclude_fields, before_create_time, since_create_time, before_start_time, since_start_time, status, extra_params):
|
||||
"""List automations"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations"
|
||||
params = {k: v for k, v in {
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"before_create_time": before_create_time,
|
||||
"since_create_time": since_create_time,
|
||||
"before_start_time": before_start_time,
|
||||
"since_start_time": since_start_time,
|
||||
"status": status,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add automation"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("get")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, workflow_id, fields, exclude_fields, extra_params):
|
||||
"""Get automation info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("archive")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_archive(ctx, workflow_id, extra_params):
|
||||
"""Archive automation"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/actions/archive"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("pause-all-emails")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_pause_all_emails(ctx, workflow_id, extra_params):
|
||||
"""Pause automation emails"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/actions/pause-all-emails"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("start-all-emails")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_start_all_emails(ctx, workflow_id, extra_params):
|
||||
"""Start automation emails"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/actions/start-all-emails"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("list-automations-id-emails")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_automations_id_emails(ctx, workflow_id, extra_params):
|
||||
"""List automated emails"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
automations_group.add_command(_cmd_list_automations_id_emails, "list-emails")
|
||||
|
||||
@automations_group.command("delete")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, workflow_id, workflow_email_id, extra_params):
|
||||
"""Delete workflow email"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@automations_group.command("get-automations-id-emails-id")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_automations_id_emails_id(ctx, workflow_id, workflow_email_id, extra_params):
|
||||
"""Get workflow email info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("update")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, workflow_id, workflow_email_id, data, extra_params):
|
||||
"""Update workflow email"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("pause")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_pause(ctx, workflow_id, workflow_email_id, extra_params):
|
||||
"""Pause automated email"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}/actions/pause"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("start")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_start(ctx, workflow_id, workflow_email_id, extra_params):
|
||||
"""Start automated email"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}/actions/start"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("list-automations-id-emails-id-queue")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_automations_id_emails_id_queue(ctx, workflow_id, workflow_email_id, extra_params):
|
||||
"""List automated email subscribers"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}/queue"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("create-automations-id-emails-id-queue")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create_automations_id_emails_id_queue(ctx, workflow_id, workflow_email_id, data, extra_params):
|
||||
"""Add subscriber to workflow email"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}/queue"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("get-automations-id-emails-id-queue-id")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("WORKFLOW_EMAIL_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_automations_id_emails_id_queue_id(ctx, workflow_id, workflow_email_id, subscriber_hash, extra_params):
|
||||
"""Get automated email subscriber"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/emails/{workflow_email_id}/queue/{subscriber_hash}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("list-automations-id-removed-subscribers")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_automations_id_removed_subscribers(ctx, workflow_id, extra_params):
|
||||
"""List subscribers removed from workflow"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/removed-subscribers"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("create-automations-id-removed-subscribers")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create_automations_id_removed_subscribers(ctx, workflow_id, data, extra_params):
|
||||
"""Remove subscriber from workflow"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/removed-subscribers"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@automations_group.command("get-automations-id-removed-subscribers-id")
|
||||
@click.argument("WORKFLOW_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_automations_id_removed_subscribers_id(ctx, workflow_id, subscriber_hash, extra_params):
|
||||
"""Get subscriber removed from workflow"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/automations/{workflow_id}/removed-subscribers/{subscriber_hash}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,144 @@
|
||||
"""Commands for the Mailchimp /batch-webhooks API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("batch-webhooks")
|
||||
@click.pass_context
|
||||
def batch_webhooks_group(ctx):
|
||||
"""batch-webhooks resource commands."""
|
||||
|
||||
@batch_webhooks_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List batch webhooks"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batch-webhooks"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@batch_webhooks_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add batch webhook"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batch-webhooks"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@batch_webhooks_group.command("delete")
|
||||
@click.argument("BATCH_WEBHOOK_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, batch_webhook_id, extra_params):
|
||||
"""Delete batch webhook"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batch-webhooks/{batch_webhook_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@batch_webhooks_group.command("get")
|
||||
@click.argument("BATCH_WEBHOOK_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, batch_webhook_id, fields, exclude_fields, extra_params):
|
||||
"""Get batch webhook info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batch-webhooks/{batch_webhook_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@batch_webhooks_group.command("update")
|
||||
@click.argument("BATCH_WEBHOOK_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, batch_webhook_id, data, extra_params):
|
||||
"""Update batch webhook"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batch-webhooks/{batch_webhook_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,122 @@
|
||||
"""Commands for the Mailchimp /batches API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("batches")
|
||||
@click.pass_context
|
||||
def batches_group(ctx):
|
||||
"""batches resource commands."""
|
||||
|
||||
@batches_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List batch requests"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batches"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@batches_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Start batch operation"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batches"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@batches_group.command("delete")
|
||||
@click.argument("BATCH_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, batch_id, extra_params):
|
||||
"""Delete batch request"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batches/{batch_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@batches_group.command("get")
|
||||
@click.argument("BATCH_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, batch_id, fields, exclude_fields, extra_params):
|
||||
"""Get batch operation status"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/batches/{batch_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,144 @@
|
||||
"""Commands for the Mailchimp /campaign-folders API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("campaign-folders")
|
||||
@click.pass_context
|
||||
def campaign_folders_group(ctx):
|
||||
"""campaign-folders resource commands."""
|
||||
|
||||
@campaign_folders_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List campaign folders"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaign-folders"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaign_folders_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add campaign folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaign-folders"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaign_folders_group.command("delete")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, folder_id, extra_params):
|
||||
"""Delete campaign folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaign-folders/{folder_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@campaign_folders_group.command("get")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, folder_id, fields, exclude_fields, extra_params):
|
||||
"""Get campaign folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaign-folders/{folder_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaign_folders_group.command("update")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, folder_id, data, extra_params):
|
||||
"""Update campaign folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaign-folders/{folder_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,553 @@
|
||||
"""Commands for the Mailchimp /campaigns API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("campaigns")
|
||||
@click.pass_context
|
||||
def campaigns_group(ctx):
|
||||
"""campaigns resource commands."""
|
||||
|
||||
@campaigns_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--type", "type_", default=None, help="The campaign type.")
|
||||
@click.option("--status", "status", default=None, help="The status of the campaign.")
|
||||
@click.option("--before-send-time", "before_send_time", default=None, help="Restrict the response to campaigns sent before the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-send-time", "since_send_time", default=None, help="Restrict the response to campaigns sent after the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--before-create-time", "before_create_time", default=None, help="Restrict the response to campaigns created before the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-create-time", "since_create_time", default=None, help="Restrict the response to campaigns created after the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--list-id", "list_id", default=None, help="The unique id for the list.")
|
||||
@click.option("--folder-id", "folder_id", default=None, help="The unique folder id.")
|
||||
@click.option("--member-id", "member_id", default=None, help="Retrieve campaigns sent to a particular list member. Member ID is The MD5 hash of the lowercase version of the list member’s email address.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--include-resend-shortcut-eligibility", "include_resend_shortcut_eligibility", default=None, type=bool, help="Return the `resend_shortcut_eligibility` field in the response, which tells you if the campaign is eligible for the various Campaign Resend Shortcuts offered.")
|
||||
@click.option("--include-resend-shortcut-usage", "include_resend_shortcut_usage", default=None, type=bool, help="Return the `resend_shortcut_usage` field in the response. This includes information about campaigns related by a shortcut.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, type_, status, before_send_time, since_send_time, before_create_time, since_create_time, list_id, folder_id, member_id, sort_field, sort_dir, include_resend_shortcut_eligibility, include_resend_shortcut_usage, extra_params):
|
||||
"""List campaigns"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"type": type_,
|
||||
"status": status,
|
||||
"before_send_time": before_send_time,
|
||||
"since_send_time": since_send_time,
|
||||
"before_create_time": before_create_time,
|
||||
"since_create_time": since_create_time,
|
||||
"list_id": list_id,
|
||||
"folder_id": folder_id,
|
||||
"member_id": member_id,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
"include_resend_shortcut_eligibility": include_resend_shortcut_eligibility,
|
||||
"include_resend_shortcut_usage": include_resend_shortcut_usage,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("delete")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, campaign_id, extra_params):
|
||||
"""Delete campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@campaigns_group.command("get")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--include-resend-shortcut-eligibility", "include_resend_shortcut_eligibility", default=None, type=bool, help="Return the `resend_shortcut_eligibility` field in the response, which tells you if the campaign is eligible for the various Campaign Resend Shortcuts offered.")
|
||||
@click.option("--include-resend-shortcut-usage", "include_resend_shortcut_usage", default=None, type=bool, help="Return the `resend_shortcut_usage` field in the response. This includes information about campaigns related by a shortcut.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, campaign_id, fields, exclude_fields, include_resend_shortcut_eligibility, include_resend_shortcut_usage, extra_params):
|
||||
"""Get campaign info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"include_resend_shortcut_eligibility": include_resend_shortcut_eligibility,
|
||||
"include_resend_shortcut_usage": include_resend_shortcut_usage,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("update")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, campaign_id, data, extra_params):
|
||||
"""Update campaign settings"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("cancel-send")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_cancel_send(ctx, campaign_id, extra_params):
|
||||
"""Cancel campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/cancel-send"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("create-resend")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create_resend(ctx, campaign_id, data, extra_params):
|
||||
"""Resend campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/create-resend"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("pause")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_pause(ctx, campaign_id, extra_params):
|
||||
"""Pause rss campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/pause"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("replicate")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_replicate(ctx, campaign_id, extra_params):
|
||||
"""Replicate campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/replicate"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("resume")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_resume(ctx, campaign_id, extra_params):
|
||||
"""Resume rss campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/resume"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("schedule")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_schedule(ctx, campaign_id, data, extra_params):
|
||||
"""Schedule campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/schedule"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("send")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_send(ctx, campaign_id, extra_params):
|
||||
"""Send campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/send"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("test")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_test(ctx, campaign_id, data, extra_params):
|
||||
"""Send test email"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/test"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("unschedule")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_unschedule(ctx, campaign_id, extra_params):
|
||||
"""Unschedule campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/actions/unschedule"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("list-campaigns-id-content")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_campaigns_id_content(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""Get campaign content"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/content"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
campaigns_group.add_command(_cmd_list_campaigns_id_content, "list-content")
|
||||
|
||||
@campaigns_group.command("update-campaigns-id-content")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update_campaigns_id_content(ctx, campaign_id, data, extra_params):
|
||||
"""Set campaign content"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/content"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.put(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("list-campaigns-id-feedback")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_campaigns_id_feedback(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""List campaign feedback"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/feedback"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("create-campaigns-id-feedback")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create_campaigns_id_feedback(ctx, campaign_id, data, extra_params):
|
||||
"""Add campaign feedback"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/feedback"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("delete-campaigns-id-feedback-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("FEEDBACK_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete_campaigns_id_feedback_id(ctx, campaign_id, feedback_id, extra_params):
|
||||
"""Delete campaign feedback message"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/feedback/{feedback_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@campaigns_group.command("get-campaigns-id-feedback-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("FEEDBACK_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_campaigns_id_feedback_id(ctx, campaign_id, feedback_id, fields, exclude_fields, extra_params):
|
||||
"""Get campaign feedback message"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/feedback/{feedback_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("update-campaigns-id-feedback-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("FEEDBACK_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update_campaigns_id_feedback_id(ctx, campaign_id, feedback_id, data, extra_params):
|
||||
"""Update campaign feedback message"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/feedback/{feedback_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@campaigns_group.command("list-campaigns-id-send-checklist")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_campaigns_id_send_checklist(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""Get campaign send checklist"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/campaigns/{campaign_id}/send-checklist"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
campaigns_group.add_command(_cmd_list_campaigns_id_send_checklist, "list-send-checklist")
|
||||
@@ -0,0 +1,142 @@
|
||||
"""Commands for the Mailchimp /connected-sites API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("connected-sites")
|
||||
@click.pass_context
|
||||
def connected_sites_group(ctx):
|
||||
"""connected-sites resource commands."""
|
||||
|
||||
@connected_sites_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List connected sites"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/connected-sites"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@connected_sites_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add connected site"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/connected-sites"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@connected_sites_group.command("delete")
|
||||
@click.argument("CONNECTED_SITE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, connected_site_id, extra_params):
|
||||
"""Delete connected site"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/connected-sites/{connected_site_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@connected_sites_group.command("get")
|
||||
@click.argument("CONNECTED_SITE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, connected_site_id, fields, exclude_fields, extra_params):
|
||||
"""Get connected site"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/connected-sites/{connected_site_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@connected_sites_group.command("verify-script-installation")
|
||||
@click.argument("CONNECTED_SITE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_verify_script_installation(ctx, connected_site_id, extra_params):
|
||||
"""Verify connected site script"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/connected-sites/{connected_site_id}/actions/verify-script-installation"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,123 @@
|
||||
"""Commands for the Mailchimp /contacts API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("contacts")
|
||||
@click.pass_context
|
||||
def contacts_group(ctx):
|
||||
"""contacts resource commands."""
|
||||
|
||||
@contacts_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""Get a list of audiences"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@contacts_group.command("get")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, audience_id, fields, exclude_fields, extra_params):
|
||||
"""Get audience info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@contacts_group.command("archive")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.argument("CONTACT_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_archive(ctx, audience_id, contact_id, extra_params):
|
||||
"""Archive Contact"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}/contacts/{contact_id}/actions/archive"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@contacts_group.command("forget")
|
||||
@click.argument("AUDIENCE_ID")
|
||||
@click.argument("CONTACT_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_forget(ctx, audience_id, contact_id, extra_params):
|
||||
"""Forget Contact"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/audiences/{audience_id}/contacts/{contact_id}/actions/forget"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,144 @@
|
||||
"""Commands for the Mailchimp /conversations API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("conversations")
|
||||
@click.pass_context
|
||||
def conversations_group(ctx):
|
||||
"""conversations resource commands."""
|
||||
|
||||
@conversations_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--has-unread-messages", "has_unread_messages", default=None, help="Whether the conversation has any unread messages.")
|
||||
@click.option("--list-id", "list_id", default=None, help="The unique id for the list.")
|
||||
@click.option("--campaign-id", "campaign_id", default=None, help="The unique id for the campaign.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, has_unread_messages, list_id, campaign_id, extra_params):
|
||||
"""List conversations"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/conversations"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"has_unread_messages": has_unread_messages,
|
||||
"list_id": list_id,
|
||||
"campaign_id": campaign_id,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@conversations_group.command("get")
|
||||
@click.argument("CONVERSATION_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, conversation_id, fields, exclude_fields, extra_params):
|
||||
"""Get conversation"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/conversations/{conversation_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@conversations_group.command("list-conversations-id-messages")
|
||||
@click.argument("CONVERSATION_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--is-read", "is_read", default=None, help="Whether a conversation message has been marked as read.")
|
||||
@click.option("--before-timestamp", "before_timestamp", default=None, help="Restrict the response to messages created before the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-timestamp", "since_timestamp", default=None, help="Restrict the response to messages created after the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_conversations_id_messages(ctx, conversation_id, fields, exclude_fields, is_read, before_timestamp, since_timestamp, extra_params):
|
||||
"""List messages"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/conversations/{conversation_id}/messages"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"is_read": is_read,
|
||||
"before_timestamp": before_timestamp,
|
||||
"since_timestamp": since_timestamp,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@conversations_group.command("get-conversations-id-messages-id")
|
||||
@click.argument("CONVERSATION_ID")
|
||||
@click.argument("MESSAGE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_conversations_id_messages_id(ctx, conversation_id, message_id, fields, exclude_fields, extra_params):
|
||||
"""Get message"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/conversations/{conversation_id}/messages/{message_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,51 @@
|
||||
"""Commands for the Mailchimp /customer-journeys API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("customer-journeys")
|
||||
@click.pass_context
|
||||
def customer_journeys_group(ctx):
|
||||
"""customer-journeys resource commands."""
|
||||
|
||||
@customer_journeys_group.command("trigger")
|
||||
@click.argument("JOURNEY_ID")
|
||||
@click.argument("STEP_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_trigger(ctx, journey_id, step_id, data, extra_params):
|
||||
"""Customer Journeys API trigger for a contact"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/customer-journeys/journeys/{journey_id}/steps/{step_id}/actions/trigger"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
"""Commands for the Mailchimp /facebook-ads API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("facebook-ads")
|
||||
@click.pass_context
|
||||
def facebook_ads_group(ctx):
|
||||
"""facebook-ads resource commands."""
|
||||
|
||||
@facebook_ads_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, sort_field, sort_dir, extra_params):
|
||||
"""List facebook ads"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/facebook-ads"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@facebook_ads_group.command("get")
|
||||
@click.argument("OUTREACH_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, outreach_id, fields, exclude_fields, extra_params):
|
||||
"""Get facebook ad info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/facebook-ads/{outreach_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,319 @@
|
||||
"""Commands for the Mailchimp /file-manager API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("file-manager")
|
||||
@click.pass_context
|
||||
def file_manager_group(ctx):
|
||||
"""file-manager resource commands."""
|
||||
|
||||
@file_manager_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--type", "type_", default=None, help="The file type for the File Manager file.")
|
||||
@click.option("--created-by", "created_by", default=None, help="The Mailchimp account user who created the File Manager file.")
|
||||
@click.option("--before-created-at", "before_created_at", default=None, help="Restrict the response to files created before the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-created-at", "since_created_at", default=None, help="Restrict the response to files created after the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, type_, created_by, before_created_at, since_created_at, sort_field, sort_dir, extra_params):
|
||||
"""List stored files"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/files"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"type": type_,
|
||||
"created_by": created_by,
|
||||
"before_created_at": before_created_at,
|
||||
"since_created_at": since_created_at,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add file"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/files"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("delete")
|
||||
@click.argument("FILE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, file_id, extra_params):
|
||||
"""Delete file"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/files/{file_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@file_manager_group.command("get")
|
||||
@click.argument("FILE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, file_id, fields, exclude_fields, extra_params):
|
||||
"""Get file"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/files/{file_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("update")
|
||||
@click.argument("FILE_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, file_id, data, extra_params):
|
||||
"""Update file"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/files/{file_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("list-file-manager-folders")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--created-by", "created_by", default=None, help="The Mailchimp account user who created the File Manager file.")
|
||||
@click.option("--before-created-at", "before_created_at", default=None, help="Restrict the response to files created before the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-created-at", "since_created_at", default=None, help="Restrict the response to files created after the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_file_manager_folders(ctx, fields, exclude_fields, count, offset, created_by, before_created_at, since_created_at, extra_params):
|
||||
"""List folders"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/folders"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"created_by": created_by,
|
||||
"before_created_at": before_created_at,
|
||||
"since_created_at": since_created_at,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("create-file-manager-folders")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create_file_manager_folders(ctx, data, extra_params):
|
||||
"""Add folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/folders"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("delete-file-manager-folders-id")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete_file_manager_folders_id(ctx, folder_id, extra_params):
|
||||
"""Delete folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/folders/{folder_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@file_manager_group.command("get-file-manager-folders-id")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_file_manager_folders_id(ctx, folder_id, fields, exclude_fields, extra_params):
|
||||
"""Get folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/folders/{folder_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("update-file-manager-folders-id")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update_file_manager_folders_id(ctx, folder_id, data, extra_params):
|
||||
"""Update folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/folders/{folder_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@file_manager_group.command("list-file-manager-folders-files")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--type", "type_", default=None, help="The file type for the File Manager file.")
|
||||
@click.option("--created-by", "created_by", default=None, help="The Mailchimp account user who created the File Manager file.")
|
||||
@click.option("--before-created-at", "before_created_at", default=None, help="Restrict the response to files created before the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-created-at", "since_created_at", default=None, help="Restrict the response to files created after the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_file_manager_folders_files(ctx, folder_id, fields, exclude_fields, count, offset, type_, created_by, before_created_at, since_created_at, sort_field, sort_dir, extra_params):
|
||||
"""List stored files"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/file-manager/folders/{folder_id}/files"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"type": type_,
|
||||
"created_by": created_by,
|
||||
"before_created_at": before_created_at,
|
||||
"since_created_at": since_created_at,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,214 @@
|
||||
"""Commands for the Mailchimp /landing-pages API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("landing-pages")
|
||||
@click.pass_context
|
||||
def landing_pages_group(ctx):
|
||||
"""landing-pages resource commands."""
|
||||
|
||||
@landing_pages_group.command("list")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, sort_dir, sort_field, fields, exclude_fields, count, extra_params):
|
||||
"""List landing pages"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages"
|
||||
params = {k: v for k, v in {
|
||||
"sort_dir": sort_dir,
|
||||
"sort_field": sort_field,
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@landing_pages_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--use-default-list", "use_default_list", default=None, type=bool, help="Will create the Landing Page using the account's Default List instead of requiring a list_id.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, use_default_list, extra_params):
|
||||
"""Add landing page"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages"
|
||||
params = {k: v for k, v in {
|
||||
"use_default_list": use_default_list,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@landing_pages_group.command("delete")
|
||||
@click.argument("PAGE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, page_id, extra_params):
|
||||
"""Delete landing page"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages/{page_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@landing_pages_group.command("get")
|
||||
@click.argument("PAGE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, page_id, fields, exclude_fields, extra_params):
|
||||
"""Get landing page info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages/{page_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@landing_pages_group.command("update")
|
||||
@click.argument("PAGE_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, page_id, data, extra_params):
|
||||
"""Update landing page"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages/{page_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@landing_pages_group.command("publish")
|
||||
@click.argument("PAGE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_publish(ctx, page_id, extra_params):
|
||||
"""Publish landing page"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages/{page_id}/actions/publish"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@landing_pages_group.command("unpublish")
|
||||
@click.argument("PAGE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_unpublish(ctx, page_id, extra_params):
|
||||
"""Unpublish landing page"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages/{page_id}/actions/unpublish"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@landing_pages_group.command("list-landing-page-id-content")
|
||||
@click.argument("PAGE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_landing_page_id_content(ctx, page_id, fields, exclude_fields, extra_params):
|
||||
"""Get landing page content"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/landing-pages/{page_id}/content"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,49 @@
|
||||
"""Commands for the Mailchimp /ping API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("ping", invoke_without_command=True)
|
||||
@click.pass_context
|
||||
def ping_group(ctx):
|
||||
"""ping resource commands."""
|
||||
if ctx.invoked_subcommand is None:
|
||||
ctx.invoke(_cmd_list_)
|
||||
|
||||
@ping_group.command("list")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, extra_params):
|
||||
"""Ping"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/ping"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,353 @@
|
||||
"""Commands for the Mailchimp /reporting API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("reporting")
|
||||
@click.pass_context
|
||||
def reporting_group(ctx):
|
||||
"""reporting resource commands."""
|
||||
|
||||
@reporting_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, sort_field, sort_dir, extra_params):
|
||||
"""List facebook ads reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/facebook-ads"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("get")
|
||||
@click.argument("OUTREACH_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, outreach_id, fields, exclude_fields, extra_params):
|
||||
"""Get facebook ad report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/facebook-ads/{outreach_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("list-reporting-facebook-ads-id-ecommerce-product-activity")
|
||||
@click.argument("OUTREACH_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reporting_facebook_ads_id_ecommerce_product_activity(ctx, outreach_id, fields, exclude_fields, count, offset, sort_field, extra_params):
|
||||
"""List facebook ecommerce report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/facebook-ads/{outreach_id}/ecommerce-product-activity"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"sort_field": sort_field,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("list-reporting-landing-pages")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reporting_landing_pages(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List landing pages reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/landing-pages"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("get-reporting-landing-pages-id")
|
||||
@click.argument("OUTREACH_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reporting_landing_pages_id(ctx, outreach_id, fields, exclude_fields, extra_params):
|
||||
"""Get landing page report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/landing-pages/{outreach_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("list-reporting-surveys")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reporting_surveys(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List survey reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("get-reporting-surveys-id")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reporting_surveys_id(ctx, survey_id, fields, exclude_fields, extra_params):
|
||||
"""Get survey report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys/{survey_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("list-reporting-surveys-id-questions")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reporting_surveys_id_questions(ctx, survey_id, fields, exclude_fields, extra_params):
|
||||
"""List survey question reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys/{survey_id}/questions"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("get-reporting-surveys-id-questions-id")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.argument("QUESTION_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reporting_surveys_id_questions_id(ctx, survey_id, question_id, fields, exclude_fields, extra_params):
|
||||
"""Get survey question report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys/{survey_id}/questions/{question_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("list-reporting-surveys-id-questions-id-answers")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.argument("QUESTION_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--respondent-familiarity-is", "respondent_familiarity_is", default=None, help="Filter survey responses by familiarity of the respondents.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reporting_surveys_id_questions_id_answers(ctx, survey_id, question_id, fields, exclude_fields, respondent_familiarity_is, extra_params):
|
||||
"""List answers for question"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys/{survey_id}/questions/{question_id}/answers"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"respondent_familiarity_is": respondent_familiarity_is,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("list-reporting-surveys-id-responses")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--answered-question", "answered_question", default=None, type=int, help="The ID of the question that was answered.")
|
||||
@click.option("--chose-answer", "chose_answer", default=None, help="The ID of the option chosen to filter responses on.")
|
||||
@click.option("--respondent-familiarity-is", "respondent_familiarity_is", default=None, help="Filter survey responses by familiarity of the respondents.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reporting_surveys_id_responses(ctx, survey_id, fields, exclude_fields, answered_question, chose_answer, respondent_familiarity_is, extra_params):
|
||||
"""List survey responses"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys/{survey_id}/responses"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"answered_question": answered_question,
|
||||
"chose_answer": chose_answer,
|
||||
"respondent_familiarity_is": respondent_familiarity_is,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reporting_group.command("get-reporting-surveys-id-responses-id")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.argument("RESPONSE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reporting_surveys_id_responses_id(ctx, survey_id, response_id, extra_params):
|
||||
"""Get survey response"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reporting/surveys/{survey_id}/responses/{response_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,656 @@
|
||||
"""Commands for the Mailchimp /reports API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("reports")
|
||||
@click.pass_context
|
||||
def reports_group(ctx):
|
||||
"""reports resource commands."""
|
||||
|
||||
@reports_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--type", "type_", default=None, help="The campaign type.")
|
||||
@click.option("--before-send-time", "before_send_time", default=None, help="Restrict the response to campaigns sent before the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--since-send-time", "since_send_time", default=None, help="Restrict the response to campaigns sent after the set time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, type_, before_send_time, since_send_time, extra_params):
|
||||
"""List campaign reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"type": type_,
|
||||
"before_send_time": before_send_time,
|
||||
"since_send_time": since_send_time,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("get")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""Get campaign report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-abuse-reports-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_abuse_reports_id(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""List abuse reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/abuse-reports"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("get-reports-id-abuse-reports-id-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("REPORT_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_abuse_reports_id_id(ctx, campaign_id, report_id, fields, exclude_fields, extra_params):
|
||||
"""Get abuse report"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/abuse-reports/{report_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-advice")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_advice(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""List campaign feedback"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/advice"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-click-details")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns click reports sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_click_details(ctx, campaign_id, fields, exclude_fields, count, offset, sort_field, sort_dir, extra_params):
|
||||
"""List campaign details"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/click-details"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
reports_group.add_command(_cmd_list_reports_id_click_details, "list-click-details")
|
||||
|
||||
@reports_group.command("get-reports-id-click-details-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("LINK_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_click_details_id(ctx, campaign_id, link_id, fields, exclude_fields, extra_params):
|
||||
"""Get campaign link details"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/click-details/{link_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-click-details-id-members")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("LINK_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_click_details_id_members(ctx, campaign_id, link_id, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List clicked link subscribers"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/click-details/{link_id}/members"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("get-reports-id-click-details-id-members-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("LINK_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_click_details_id_members_id(ctx, campaign_id, link_id, subscriber_hash, fields, exclude_fields, extra_params):
|
||||
"""Get clicked link subscriber"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/click-details/{link_id}/members/{subscriber_hash}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-domain-performance")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_domain_performance(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""List domain performance stats"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/domain-performance"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
reports_group.add_command(_cmd_list_reports_id_domain_performance, "list-domain-performance")
|
||||
|
||||
@reports_group.command("list-reports-id-ecommerce-product-activity")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns files sorted by the specified field.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_ecommerce_product_activity(ctx, campaign_id, fields, exclude_fields, count, offset, sort_field, extra_params):
|
||||
"""List campaign product activity"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/ecommerce-product-activity"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"sort_field": sort_field,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-eepurl")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_eepurl(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""List EepURL activity"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/eepurl"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-email-activity")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--since", "since", default=None, help="Restrict results to email activity events that occur after a specific time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_email_activity(ctx, campaign_id, fields, exclude_fields, count, offset, since, extra_params):
|
||||
"""List email activity"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/email-activity"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"since": since,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
reports_group.add_command(_cmd_list_reports_id_email_activity, "list-email-activity")
|
||||
|
||||
@reports_group.command("get-reports-id-email-activity-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--since", "since", default=None, help="Restrict results to email activity events that occur after a specific time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_email_activity_id(ctx, campaign_id, subscriber_hash, fields, exclude_fields, since, extra_params):
|
||||
"""Get subscriber email activity"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/email-activity/{subscriber_hash}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"since": since,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-locations")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_locations(ctx, campaign_id, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List top open activities"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/locations"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
reports_group.add_command(_cmd_list_reports_id_locations, "list-locations")
|
||||
|
||||
@reports_group.command("list-reports-id-open-details")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--since", "since", default=None, help="Restrict results to campaign open events that occur after a specific time. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns open reports sorted by the specified field.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_open_details(ctx, campaign_id, fields, exclude_fields, count, offset, since, sort_field, sort_dir, extra_params):
|
||||
"""List campaign open details"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/open-details"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"since": since,
|
||||
"sort_field": sort_field,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
reports_group.add_command(_cmd_list_reports_id_open_details, "list-open-details")
|
||||
|
||||
@reports_group.command("get-reports-id-open-details-id-members-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_open_details_id_members_id(ctx, campaign_id, subscriber_hash, fields, exclude_fields, extra_params):
|
||||
"""Get opened campaign subscriber"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/open-details/{subscriber_hash}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-sent-to")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_sent_to(ctx, campaign_id, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List campaign recipients"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/sent-to"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("get-reports-id-sent-to-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_sent_to_id(ctx, campaign_id, subscriber_hash, fields, exclude_fields, extra_params):
|
||||
"""Get campaign recipient info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/sent-to/{subscriber_hash}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-sub-reports-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_sub_reports_id(ctx, campaign_id, fields, exclude_fields, extra_params):
|
||||
"""List child campaign reports"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/sub-reports"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@reports_group.command("list-reports-id-unsubscribed")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_reports_id_unsubscribed(ctx, campaign_id, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List unsubscribed members"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/unsubscribed"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
reports_group.add_command(_cmd_list_reports_id_unsubscribed, "list-unsubscribed")
|
||||
|
||||
@reports_group.command("get-reports-id-unsubscribed-id")
|
||||
@click.argument("CAMPAIGN_ID")
|
||||
@click.argument("SUBSCRIBER_HASH")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get_reports_id_unsubscribed_id(ctx, campaign_id, subscriber_hash, fields, exclude_fields, extra_params):
|
||||
"""Get unsubscribed member"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/reports/{campaign_id}/unsubscribed/{subscriber_hash}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Commands for the Mailchimp /root API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("root")
|
||||
@click.pass_context
|
||||
def root_group(ctx):
|
||||
"""root resource commands."""
|
||||
|
||||
@root_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, extra_params):
|
||||
"""List api root resources"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,54 @@
|
||||
"""Commands for the Mailchimp /search-campaigns API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("search-campaigns")
|
||||
@click.pass_context
|
||||
def search_campaigns_group(ctx):
|
||||
"""search-campaigns resource commands."""
|
||||
|
||||
@search_campaigns_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--query", "query", default=None, help="The search query used to filter results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, query, extra_params):
|
||||
"""Search campaigns"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/search-campaigns"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"query": query,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Commands for the Mailchimp /search-members API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("search-members")
|
||||
@click.pass_context
|
||||
def search_members_group(ctx):
|
||||
"""search-members resource commands."""
|
||||
|
||||
@search_members_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--query", "query", default=None, help="The search query used to filter results. Query should be a valid email, or a string representing a contact's first or last name.")
|
||||
@click.option("--list-id", "list_id", default=None, help="The unique id for the list.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, query, list_id, extra_params):
|
||||
"""Search members"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/search-members"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"query": query,
|
||||
"list_id": list_id,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,253 @@
|
||||
"""Commands for the Mailchimp /sms-campaigns API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("sms-campaigns")
|
||||
@click.pass_context
|
||||
def sms_campaigns_group(ctx):
|
||||
"""sms-campaigns resource commands."""
|
||||
|
||||
@sms_campaigns_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List SMS campaigns"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add SMS campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("delete")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, sms_campaign_id, extra_params):
|
||||
"""Delete SMS campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@sms_campaigns_group.command("get")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, sms_campaign_id, fields, exclude_fields, extra_params):
|
||||
"""Get SMS campaign info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("update")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, sms_campaign_id, data, extra_params):
|
||||
"""Update SMS campaign settings"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("cancel-send")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_cancel_send(ctx, sms_campaign_id, extra_params):
|
||||
"""Cancel SMS campaign send"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}/actions/cancel-send"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("schedule")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_schedule(ctx, sms_campaign_id, data, extra_params):
|
||||
"""Schedule SMS campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}/actions/schedule"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("send")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_send(ctx, sms_campaign_id, extra_params):
|
||||
"""Send SMS campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}/actions/send"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("list-sms-campaigns-id-content")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_sms_campaigns_id_content(ctx, sms_campaign_id, fields, exclude_fields, extra_params):
|
||||
"""Get SMS campaign content"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}/content"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@sms_campaigns_group.command("update-sms-campaigns-id-content")
|
||||
@click.argument("SMS_CAMPAIGN_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update_sms_campaigns_id_content(ctx, sms_campaign_id, data, extra_params):
|
||||
"""Set SMS campaign content"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/sms-campaigns/{sms_campaign_id}/content"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.put(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,91 @@
|
||||
"""Commands for the Mailchimp /surveys API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("surveys")
|
||||
@click.pass_context
|
||||
def surveys_group(ctx):
|
||||
"""surveys resource commands."""
|
||||
|
||||
@surveys_group.command("create-email")
|
||||
@click.argument("LIST_ID")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create_email(ctx, list_id, survey_id, extra_params):
|
||||
"""Create a Survey Campaign"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/lists/{list_id}/surveys/{survey_id}/actions/create-email"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@surveys_group.command("publish")
|
||||
@click.argument("LIST_ID")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_publish(ctx, list_id, survey_id, extra_params):
|
||||
"""Publish a Survey"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/lists/{list_id}/surveys/{survey_id}/actions/publish"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@surveys_group.command("unpublish")
|
||||
@click.argument("LIST_ID")
|
||||
@click.argument("SURVEY_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_unpublish(ctx, list_id, survey_id, extra_params):
|
||||
"""Unpublish a Survey"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/lists/{list_id}/surveys/{survey_id}/actions/unpublish"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=None, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,144 @@
|
||||
"""Commands for the Mailchimp /template-folders API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("template-folders")
|
||||
@click.pass_context
|
||||
def template_folders_group(ctx):
|
||||
"""template-folders resource commands."""
|
||||
|
||||
@template_folders_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, extra_params):
|
||||
"""List template folders"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/template-folders"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@template_folders_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add template folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/template-folders"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@template_folders_group.command("delete")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, folder_id, extra_params):
|
||||
"""Delete template folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/template-folders/{folder_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@template_folders_group.command("get")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, folder_id, fields, exclude_fields, extra_params):
|
||||
"""Get template folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/template-folders/{folder_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@template_folders_group.command("update")
|
||||
@click.argument("FOLDER_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, folder_id, data, extra_params):
|
||||
"""Update template folder"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/template-folders/{folder_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,187 @@
|
||||
"""Commands for the Mailchimp /templates API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("templates")
|
||||
@click.pass_context
|
||||
def templates_group(ctx):
|
||||
"""templates resource commands."""
|
||||
|
||||
@templates_group.command("list")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--count", "count", default=None, type=int, help="The number of records to return. Default value is 10. Maximum value is 1000")
|
||||
@click.option("--offset", "offset", default=None, type=int, help="Used for [pagination](https://mailchimp.com/developer/marketing/docs/methods-parameters/#pagination), this is the number of records from a collection to skip. Default value is 0.")
|
||||
@click.option("--created-by", "created_by", default=None, help="The Mailchimp account user who created the template.")
|
||||
@click.option("--since-date-created", "since_date_created", default=None, help="Restrict the response to templates created after the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--before-date-created", "before_date_created", default=None, help="Restrict the response to templates created before the set date. Uses ISO 8601 time format: 2015-10-21T15:41:36+00:00.")
|
||||
@click.option("--type", "type_", default=None, help="Limit results based on template type.")
|
||||
@click.option("--category", "category", default=None, help="Limit results based on category.")
|
||||
@click.option("--folder-id", "folder_id", default=None, help="The unique folder id.")
|
||||
@click.option("--sort-field", "sort_field", default=None, help="Returns user templates sorted by the specified field.")
|
||||
@click.option("--content-type", "content_type", default=None, help="Limit results based on how the template's content is put together. Only templates of type `user` can be filtered by `content_type`. If you want to retrieve saved templates created with the legacy email editor, then filter `content_type` to `template`. If you'd rather pull your saved templates for the new editor, filter to `multichannel`. For code your own templates, filter to `html`.")
|
||||
@click.option("--sort-dir", "sort_dir", default=None, help="Determines the order direction for sorted results.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, fields, exclude_fields, count, offset, created_by, since_date_created, before_date_created, type_, category, folder_id, sort_field, content_type, sort_dir, extra_params):
|
||||
"""List templates"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/templates"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
"count": count,
|
||||
"offset": offset,
|
||||
"created_by": created_by,
|
||||
"since_date_created": since_date_created,
|
||||
"before_date_created": before_date_created,
|
||||
"type": type_,
|
||||
"category": category,
|
||||
"folder_id": folder_id,
|
||||
"sort_field": sort_field,
|
||||
"content_type": content_type,
|
||||
"sort_dir": sort_dir,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@templates_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add template"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/templates"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@templates_group.command("delete")
|
||||
@click.argument("TEMPLATE_ID")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, template_id, extra_params):
|
||||
"""Delete template"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/templates/{template_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@templates_group.command("get")
|
||||
@click.argument("TEMPLATE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, template_id, fields, exclude_fields, extra_params):
|
||||
"""Get template info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/templates/{template_id}"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@templates_group.command("update")
|
||||
@click.argument("TEMPLATE_ID")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_update(ctx, template_id, data, extra_params):
|
||||
"""Update template"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/templates/{template_id}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.patch(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@templates_group.command("list-templates-id-default-content")
|
||||
@click.argument("TEMPLATE_ID")
|
||||
@click.option("--fields", "fields", default=None, help="A comma-separated list of fields to return. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--exclude-fields", "exclude_fields", default=None, help="A comma-separated list of fields to exclude. Reference parameters of sub-objects with dot notation.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_templates_id_default_content(ctx, template_id, fields, exclude_fields, extra_params):
|
||||
"""View default content"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/templates/{template_id}/default-content"
|
||||
params = {k: v for k, v in {
|
||||
"fields": fields,
|
||||
"exclude_fields": exclude_fields,
|
||||
}.items() if v is not None}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1,130 @@
|
||||
"""Commands for the Mailchimp /verified-domains API resource.
|
||||
|
||||
Auto-generated by cli_anything/mailchimp/_codegen/generate.py.
|
||||
Do not edit manually — re-run the generator to update.
|
||||
"""
|
||||
|
||||
import json
|
||||
|
||||
import click
|
||||
|
||||
|
||||
def _parse_json_option(value, option_name, require_object=False):
|
||||
try:
|
||||
parsed = json.loads(value)
|
||||
except json.JSONDecodeError as exc:
|
||||
raise click.BadParameter(
|
||||
f"must be valid JSON ({exc.msg})",
|
||||
param_hint=option_name,
|
||||
) from exc
|
||||
if require_object and not isinstance(parsed, dict):
|
||||
raise click.BadParameter("must be a JSON object", param_hint=option_name)
|
||||
return parsed
|
||||
|
||||
|
||||
@click.group("verified-domains")
|
||||
@click.pass_context
|
||||
def verified_domains_group(ctx):
|
||||
"""verified-domains resource commands."""
|
||||
|
||||
@verified_domains_group.command("list")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_list_(ctx, extra_params):
|
||||
"""List sending domains"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/verified-domains"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@verified_domains_group.command("create")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_create(ctx, data, extra_params):
|
||||
"""Add domain to account"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/verified-domains"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@verified_domains_group.command("delete")
|
||||
@click.argument("DOMAIN_NAME")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_delete(ctx, domain_name, extra_params):
|
||||
"""Delete domain"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/verified-domains/{domain_name}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.delete(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out_ok("Deleted.")
|
||||
|
||||
@verified_domains_group.command("get")
|
||||
@click.argument("DOMAIN_NAME")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_get(ctx, domain_name, extra_params):
|
||||
"""Get domain info"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/verified-domains/{domain_name}"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.get(path, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
|
||||
@verified_domains_group.command("verify")
|
||||
@click.argument("DOMAIN_NAME")
|
||||
@click.option("--data", default=None, help="Request body as JSON string.")
|
||||
@click.option("--extra-params", default=None, help="Extra query params as JSON object, e.g. '{\"key\":\"val\"}'")
|
||||
@click.pass_context
|
||||
def _cmd_verify(ctx, domain_name, data, extra_params):
|
||||
"""Verify domain"""
|
||||
from cli_anything.mailchimp.core.client import get_client, MailchimpError
|
||||
from cli_anything.mailchimp.utils.output import _out, _out_ok, _out_err
|
||||
path = f"/verified-domains/{domain_name}/actions/verify"
|
||||
params = {}
|
||||
if extra_params:
|
||||
params.update(_parse_json_option(extra_params, "--extra-params", require_object=True))
|
||||
body = _parse_json_option(data, "--data") if data else None
|
||||
client = get_client()
|
||||
try:
|
||||
result = client.post(path, json=body, params=params or None)
|
||||
except MailchimpError as e:
|
||||
_out_err(e.status, e.title, e.detail, e.raw)
|
||||
return
|
||||
_out(result)
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
"""Mailchimp Marketing API v3.0 HTTP client."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
|
||||
_BASE = "https://{dc}.api.mailchimp.com/3.0"
|
||||
_DEFAULT_TIMEOUT = 30
|
||||
|
||||
|
||||
def _server_prefix(api_key: str) -> str:
|
||||
"""Derive the data-centre prefix from the API key suffix (e.g. 'us8')."""
|
||||
if "-" not in api_key:
|
||||
raise ValueError(
|
||||
"MAILCHIMP_API_KEY must include the data-centre suffix, "
|
||||
"e.g. 'abc123-us8'."
|
||||
)
|
||||
return api_key.rsplit("-", 1)[-1]
|
||||
|
||||
|
||||
def subscriber_hash(email: str) -> str:
|
||||
"""MD5 hash of the lowercased email — Mailchimp's subscriber identifier."""
|
||||
return hashlib.md5(email.strip().lower().encode()).hexdigest()
|
||||
|
||||
|
||||
class MailchimpAuthError(Exception):
|
||||
"""Raised when no API key is available."""
|
||||
|
||||
|
||||
class MailchimpError(Exception):
|
||||
def __init__(self, status: int, title: str, detail: str, raw: dict):
|
||||
super().__init__(f"HTTP {status}: {title} — {detail}")
|
||||
self.status = status
|
||||
self.title = title
|
||||
self.detail = detail
|
||||
self.raw = raw
|
||||
|
||||
|
||||
class MailchimpClient:
|
||||
def __init__(self, api_key: str | None = None):
|
||||
key = api_key or os.environ.get("MAILCHIMP_API_KEY", "")
|
||||
if not key:
|
||||
raise MailchimpAuthError(
|
||||
"MAILCHIMP_API_KEY is not set. "
|
||||
"Export it before use: export MAILCHIMP_API_KEY=<key>-<dc>"
|
||||
)
|
||||
self._key = key
|
||||
try:
|
||||
self._dc = _server_prefix(key)
|
||||
except ValueError as e:
|
||||
raise MailchimpAuthError(str(e)) from e
|
||||
self._base = _BASE.format(dc=self._dc)
|
||||
self._session = requests.Session()
|
||||
self._session.auth = ("anystring", key)
|
||||
self._session.headers.update({"User-Agent": "cli-anything-mailchimp/0.1.0"})
|
||||
|
||||
# ── Low-level request helpers ──────────────────────────────────────
|
||||
|
||||
def _url(self, path: str) -> str:
|
||||
return f"{self._base}/{path.lstrip('/')}"
|
||||
|
||||
def _raise(self, resp: requests.Response) -> None:
|
||||
if resp.ok:
|
||||
return
|
||||
try:
|
||||
body = resp.json()
|
||||
raise MailchimpError(
|
||||
status=resp.status_code,
|
||||
title=body.get("title", resp.reason),
|
||||
detail=body.get("detail", ""),
|
||||
raw=body,
|
||||
)
|
||||
except ValueError:
|
||||
raise MailchimpError(
|
||||
status=resp.status_code,
|
||||
title=resp.reason,
|
||||
detail=resp.text[:200],
|
||||
raw={},
|
||||
)
|
||||
|
||||
def get(self, path: str, params: dict | None = None) -> Any:
|
||||
resp = self._session.get(self._url(path), params=params, timeout=_DEFAULT_TIMEOUT)
|
||||
self._raise(resp)
|
||||
return resp.json()
|
||||
|
||||
def post(self, path: str, json: dict | None = None, params: dict | None = None) -> Any:
|
||||
resp = self._session.post(
|
||||
self._url(path), json=json, params=params, timeout=_DEFAULT_TIMEOUT
|
||||
)
|
||||
self._raise(resp)
|
||||
if resp.status_code == 204:
|
||||
return {}
|
||||
return resp.json()
|
||||
|
||||
def patch(self, path: str, json: dict | None = None, params: dict | None = None) -> Any:
|
||||
resp = self._session.patch(
|
||||
self._url(path), json=json, params=params, timeout=_DEFAULT_TIMEOUT
|
||||
)
|
||||
self._raise(resp)
|
||||
return resp.json()
|
||||
|
||||
def put(self, path: str, json: dict | None = None, params: dict | None = None) -> Any:
|
||||
resp = self._session.put(
|
||||
self._url(path), json=json, params=params, timeout=_DEFAULT_TIMEOUT
|
||||
)
|
||||
self._raise(resp)
|
||||
return resp.json()
|
||||
|
||||
def delete(self, path: str, params: dict | None = None) -> dict:
|
||||
resp = self._session.delete(
|
||||
self._url(path), params=params, timeout=_DEFAULT_TIMEOUT
|
||||
)
|
||||
self._raise(resp)
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
def get_client() -> MailchimpClient:
|
||||
"""Return a client instance, printing an error and exiting if key is missing."""
|
||||
try:
|
||||
return MailchimpClient()
|
||||
except MailchimpAuthError as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
@@ -0,0 +1,68 @@
|
||||
"""Generic count/offset paginator for the Mailchimp API."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Generator
|
||||
|
||||
_PAGE_SIZE = 1000
|
||||
|
||||
|
||||
def paginate(
|
||||
client,
|
||||
path: str,
|
||||
result_key: str,
|
||||
params: dict | None = None,
|
||||
page_size: int = _PAGE_SIZE,
|
||||
) -> Generator[dict, None, None]:
|
||||
"""Yield all items from a paginated Mailchimp endpoint.
|
||||
|
||||
Args:
|
||||
client: MailchimpClient instance.
|
||||
path: API path, e.g. "/lists".
|
||||
result_key: Key inside the response that holds the item array.
|
||||
params: Extra query params (count/offset will be added automatically).
|
||||
page_size: Items per page.
|
||||
"""
|
||||
params = dict(params or {})
|
||||
params["count"] = page_size
|
||||
offset = 0
|
||||
total: int | None = None
|
||||
|
||||
while True:
|
||||
params["offset"] = offset
|
||||
data = client.get(path, params=params)
|
||||
items: list = data.get(result_key, [])
|
||||
|
||||
if total is None:
|
||||
total = data.get("total_items", None)
|
||||
|
||||
yield from items
|
||||
|
||||
offset += len(items)
|
||||
# Stop when we have fetched all items or got an empty page
|
||||
if not items or (total is not None and offset >= total):
|
||||
break
|
||||
|
||||
|
||||
def collect(
|
||||
client,
|
||||
path: str,
|
||||
result_key: str,
|
||||
params: dict | None = None,
|
||||
page_size: int = _PAGE_SIZE,
|
||||
) -> tuple[list[dict], int]:
|
||||
"""Return (items, total_items) — fetches a single page by default.
|
||||
|
||||
When the caller passes explicit count/offset in params those are respected;
|
||||
otherwise a single page of page_size is fetched.
|
||||
"""
|
||||
params = dict(params or {})
|
||||
if "count" not in params:
|
||||
params["count"] = page_size
|
||||
if "offset" not in params:
|
||||
params["offset"] = 0
|
||||
|
||||
data = client.get(path, params=params)
|
||||
items = data.get(result_key, [])
|
||||
total = data.get("total_items", len(items))
|
||||
return items, total
|
||||
@@ -0,0 +1,93 @@
|
||||
"""cli-anything harness for the Mailchimp Marketing API v3.0."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import click
|
||||
|
||||
import cli_anything.mailchimp.utils.output as _output_mod
|
||||
from cli_anything.mailchimp.commands import ALL_GROUPS
|
||||
|
||||
|
||||
@click.group(invoke_without_command=True)
|
||||
@click.option("--json", "use_json", is_flag=True, default=False, help="Output as JSON.")
|
||||
@click.version_option("0.1.0", prog_name="cli-anything-mailchimp")
|
||||
@click.pass_context
|
||||
def cli(ctx: click.Context, use_json: bool) -> None:
|
||||
"""cli-anything harness for the Mailchimp Marketing API v3.0.
|
||||
|
||||
Set MAILCHIMP_API_KEY before use:
|
||||
|
||||
export MAILCHIMP_API_KEY=<your-key>-<dc>
|
||||
|
||||
Run without arguments to enter the interactive REPL.
|
||||
"""
|
||||
ctx.ensure_object(dict)
|
||||
_output_mod.USE_JSON = use_json
|
||||
if ctx.invoked_subcommand is None:
|
||||
_start_repl()
|
||||
|
||||
|
||||
# Register all generated resource groups
|
||||
for _group in ALL_GROUPS:
|
||||
cli.add_command(_group)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Entry point for the Click CLI."""
|
||||
cli()
|
||||
|
||||
|
||||
def _start_repl() -> None:
|
||||
"""Interactive REPL using prompt_toolkit."""
|
||||
from cli_anything.mailchimp.utils.repl_skin import ReplSkin
|
||||
import shlex
|
||||
|
||||
skin = ReplSkin("mailchimp", version="0.1.0")
|
||||
skin.print_banner()
|
||||
|
||||
pt_session = skin.create_prompt_session()
|
||||
|
||||
while True:
|
||||
try:
|
||||
raw = skin.get_input(pt_session)
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
skin.print_goodbye()
|
||||
break
|
||||
|
||||
line = raw.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line in ("quit", "exit", "q"):
|
||||
skin.print_goodbye()
|
||||
break
|
||||
if line in ("help", "?"):
|
||||
_print_repl_help(skin)
|
||||
continue
|
||||
|
||||
try:
|
||||
args = shlex.split(line)
|
||||
except ValueError as e:
|
||||
skin.error(f"Parse error: {e}")
|
||||
continue
|
||||
|
||||
try:
|
||||
cli.main(args=args, standalone_mode=False)
|
||||
except SystemExit:
|
||||
pass
|
||||
except click.UsageError as e:
|
||||
skin.error(str(e))
|
||||
except Exception as e:
|
||||
skin.error(str(e))
|
||||
|
||||
|
||||
def _print_repl_help(skin: object) -> None:
|
||||
from cli_anything.mailchimp.commands import ALL_GROUPS
|
||||
|
||||
commands = {g.name: (g.help or "").split("\n")[0] for g in ALL_GROUPS}
|
||||
commands["--help"] = "Show help for any command"
|
||||
commands["quit"] = "Exit the REPL"
|
||||
skin.help(commands) # type: ignore[attr-defined]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,228 @@
|
||||
---
|
||||
name: cli-anything-mailchimp
|
||||
description: CLI harness for the Mailchimp Marketing API v3.0 — 303 commands across 30 resource groups (lists, campaigns, reports, automations, ecommerce, templates, and more). Supports JSON output and interactive REPL mode.
|
||||
---
|
||||
|
||||
# cli-anything-mailchimp
|
||||
|
||||
## Identity
|
||||
|
||||
An agent-native CLI for the [Mailchimp Marketing API v3.0](https://mailchimp.com/developer/marketing/docs/fundamentals/), built on the [CLI-Anything](https://github.com/HKUDS/CLI-Anything) framework.
|
||||
|
||||
## What This CLI Does
|
||||
|
||||
- Manage **audiences (lists)** — create, update, delete lists; add/update/archive members; manage merge fields, segments, tags, and webhooks.
|
||||
- Run **campaigns** — create, schedule, send, pause, replicate, and analyse email campaigns.
|
||||
- Read **reports** — open rates, click rates, bounce stats, unsubscribes, email activity, geographic data.
|
||||
- Control **automations** — create and manage automated email workflows.
|
||||
- Manage **e-commerce** — stores, orders, customers, products, carts, and promo codes.
|
||||
- Use **templates, file manager, landing pages, SMS campaigns, surveys**, and all other Marketing API resources.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- `MAILCHIMP_API_KEY` environment variable set to your API key (including datacenter suffix, e.g. `abc123-us8`)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# From the CLI-Anything repo (once merged):
|
||||
pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=mailchimp/agent-harness
|
||||
|
||||
# During development:
|
||||
cd mailchimp/agent-harness && pip install -e .
|
||||
```
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Root
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `cli-anything-mailchimp ping` | Health check — confirms API connectivity |
|
||||
| `cli-anything-mailchimp root list` | Get account info |
|
||||
| `cli-anything-mailchimp --json <cmd>` | Output any command as JSON |
|
||||
| `cli-anything-mailchimp` | Launch interactive REPL |
|
||||
|
||||
### Lists (Audiences)
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `lists list` | List all audiences |
|
||||
| `lists get <LIST_ID>` | Get audience info |
|
||||
| `lists create --data '<json>'` | Create audience |
|
||||
| `lists update <LIST_ID> --data '<json>'` | Update audience |
|
||||
| `lists delete <LIST_ID>` | Delete audience |
|
||||
| `lists list-lists-id-members <LIST_ID>` | List members |
|
||||
| `lists get-lists-id-members-id <LIST_ID> <SUBSCRIBER_HASH>` | Get member by MD5 hash |
|
||||
| `lists create-lists-id-members <LIST_ID> --data '<json>'` | Add member |
|
||||
| `lists list-lists-id-merge-fields <LIST_ID>` | List merge fields |
|
||||
| `lists create-lists-id-merge-fields <LIST_ID> --data '<json>'` | Add merge field |
|
||||
| `lists list-lists-id-segments <LIST_ID>` | List segments |
|
||||
| `lists list-list-member-tags <LIST_ID> <SUBSCRIBER_HASH>` | List member tags |
|
||||
| `lists create-list-member-tags <LIST_ID> <SUBSCRIBER_HASH> --data '<json>'` | Add/remove member tags |
|
||||
| `lists list-lists-id-webhooks <LIST_ID>` | List webhooks |
|
||||
| `lists create-lists-id-webhooks <LIST_ID> --data '<json>'` | Add webhook |
|
||||
|
||||
### Campaigns
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `campaigns list` | List campaigns |
|
||||
| `campaigns get <CAMPAIGN_ID>` | Get campaign info |
|
||||
| `campaigns create --data '<json>'` | Create campaign |
|
||||
| `campaigns update <CAMPAIGN_ID> --data '<json>'` | Update campaign settings |
|
||||
| `campaigns delete <CAMPAIGN_ID>` | Delete campaign |
|
||||
| `campaigns send <CAMPAIGN_ID>` | Send campaign immediately |
|
||||
| `campaigns schedule <CAMPAIGN_ID> --data '<json>'` | Schedule campaign |
|
||||
| `campaigns cancel-send <CAMPAIGN_ID>` | Cancel scheduled send |
|
||||
| `campaigns pause <CAMPAIGN_ID>` | Pause RSS campaign |
|
||||
| `campaigns resume <CAMPAIGN_ID>` | Resume RSS campaign |
|
||||
| `campaigns replicate <CAMPAIGN_ID>` | Duplicate campaign |
|
||||
| `campaigns list-content <CAMPAIGN_ID>` | Get campaign content |
|
||||
| `campaigns list-send-checklist <CAMPAIGN_ID>` | Pre-send checklist |
|
||||
|
||||
### Reports
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `reports list` | List all campaign reports |
|
||||
| `reports get <CAMPAIGN_ID>` | Get campaign summary report |
|
||||
| `reports list-email-activity <CAMPAIGN_ID>` | Per-subscriber open/click activity |
|
||||
| `reports list-click-details <CAMPAIGN_ID>` | Link click breakdown |
|
||||
| `reports list-open-details <CAMPAIGN_ID>` | Per-subscriber opens |
|
||||
| `reports list-unsubscribed <CAMPAIGN_ID>` | Unsubscribers |
|
||||
| `reports list-locations <CAMPAIGN_ID>` | Geographic breakdown |
|
||||
| `reports list-domain-performance <CAMPAIGN_ID>` | Per-domain stats |
|
||||
|
||||
### Automations
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `automations list` | List automations |
|
||||
| `automations get <WORKFLOW_ID>` | Get automation info |
|
||||
| `automations create --data '<json>'` | Create automation |
|
||||
| `automations pause <WORKFLOW_ID>` | Pause automation |
|
||||
| `automations start <WORKFLOW_ID>` | Start automation |
|
||||
| `automations archive <WORKFLOW_ID>` | Archive automation |
|
||||
| `automations list-emails <WORKFLOW_ID>` | List automation emails |
|
||||
|
||||
### E-commerce
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `ecommerce list-ecommerce-stores` | List stores |
|
||||
| `ecommerce get <STORE_ID>` | Get store info |
|
||||
| `ecommerce create --data '<json>'` | Add store |
|
||||
| `ecommerce list-ecommerce-stores-id-orders <STORE_ID>` | List orders |
|
||||
| `ecommerce list-ecommerce-stores-id-products <STORE_ID>` | List products |
|
||||
| `ecommerce list-ecommerce-stores-id-customers <STORE_ID>` | List customers |
|
||||
| `ecommerce list-ecommerce-stores-id-carts <STORE_ID>` | List carts |
|
||||
| `ecommerce list-ecommerce-stores-id-promocodes <PROMO_RULE_ID> <STORE_ID>` | List promo codes |
|
||||
|
||||
### Other Resources
|
||||
|
||||
| Group | Description |
|
||||
|---|---|
|
||||
| `templates` | Email templates (list, get, create, update, delete) |
|
||||
| `template-folders` | Template folders |
|
||||
| `campaign-folders` | Campaign folders |
|
||||
| `file-manager` | Files and folders in the file manager |
|
||||
| `landing-pages` | Landing pages (list, create, publish, unpublish) |
|
||||
| `sms-campaigns` | SMS campaigns (10 operations) |
|
||||
| `surveys` | Surveys (list, get, publish) |
|
||||
| `reporting` | Facebook ad and landing page reporting |
|
||||
| `search-campaigns` | Search campaigns by query |
|
||||
| `search-members` | Search members across all audiences |
|
||||
| `batches` | Batch API operations |
|
||||
| `batch-webhooks` | Batch operation webhooks |
|
||||
| `verified-domains` | Email domain verification |
|
||||
| `authorized-apps` | OAuth connected apps |
|
||||
| `connected-sites` | Connected site integrations |
|
||||
| `conversations` | Inbox conversations |
|
||||
| `activity-feed` | Account activity feed |
|
||||
| `account-exports` | Account data exports |
|
||||
|
||||
## JSON Output
|
||||
|
||||
All commands support `--json` at the root level:
|
||||
|
||||
```bash
|
||||
# List all audiences as JSON
|
||||
cli-anything-mailchimp --json lists list
|
||||
|
||||
# Get a campaign report as JSON
|
||||
cli-anything-mailchimp --json reports get abc123def
|
||||
|
||||
# Pipe to jq — use the native Mailchimp field name for the resource
|
||||
cli-anything-mailchimp --json lists list | jq '.lists[].name'
|
||||
cli-anything-mailchimp --json campaigns list | jq '.campaigns[].id'
|
||||
```
|
||||
|
||||
**Envelope shapes** (native Mailchimp API response — use the resource-specific key):
|
||||
|
||||
```json
|
||||
// List endpoints — key matches the resource name (lists, campaigns, members, etc.)
|
||||
{"lists": [...], "total_items": 42, "_links": [...]}
|
||||
{"campaigns": [...], "total_items": 10, "_links": [...]}
|
||||
|
||||
// Single resource GET / POST / PATCH
|
||||
{"id": "abc123", "name": "My List", ...}
|
||||
|
||||
// DELETE
|
||||
{"ok": true, "message": "Deleted."}
|
||||
|
||||
// Error
|
||||
{"ok": false, "message": "Resource Not Found: ...", "data": {...}}
|
||||
```
|
||||
|
||||
## Common Agent Patterns
|
||||
|
||||
```bash
|
||||
# Get account health
|
||||
cli-anything-mailchimp --json ping | jq '.health_status'
|
||||
|
||||
# List all audience IDs and names
|
||||
cli-anything-mailchimp --json lists list | jq '.lists[] | {id, name}'
|
||||
|
||||
# Find all subscribed members in an audience
|
||||
cli-anything-mailchimp --json lists list-lists-id-members <list_id> --status subscribed | jq '.members[].email_address'
|
||||
|
||||
# Create a campaign and get its send checklist
|
||||
cli-anything-mailchimp --json campaigns create --data '{"type":"regular","settings":{"subject_line":"Hello","from_name":"Me","reply_to":"me@example.com"}}' | jq '.id'
|
||||
cli-anything-mailchimp --json campaigns list-send-checklist <campaign_id> | jq '.items[] | select(.result == false)'
|
||||
|
||||
# Get unsubscribes for a sent campaign
|
||||
cli-anything-mailchimp --json reports list-unsubscribed <campaign_id> | jq '.unsubscribes[].email_address'
|
||||
|
||||
# Add a member to an audience (subscriber hash = MD5 of lowercased email)
|
||||
cli-anything-mailchimp --json lists create-members <list_id> --data '{"email_address":"user@example.com","status":"subscribed"}'
|
||||
|
||||
# Search for a member across all audiences
|
||||
cli-anything-mailchimp --json search-members list --query "user@example.com" | jq '.exact_matches.members[]'
|
||||
```
|
||||
|
||||
## Interactive REPL
|
||||
|
||||
Run `cli-anything-mailchimp` with no arguments to enter the REPL:
|
||||
|
||||
```
|
||||
◆ cli-anything · Mailchimp
|
||||
v0.1.0
|
||||
Type help for commands, quit to exit
|
||||
|
||||
◆ mailchimp ❯ ping
|
||||
✓ {"health_status": "Everything's Chimpy!"}
|
||||
|
||||
◆ mailchimp ❯ --json lists list
|
||||
{"lists": [...], "total_items": 3, "_links": [...]}
|
||||
|
||||
◆ mailchimp ❯ quit
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Subscriber hash**: Mailchimp identifies members by the MD5 hash of their lowercased email. Compute with `python -c "import hashlib; email='email@example.com'; print(hashlib.md5(email.strip().lower().encode()).hexdigest())"`.
|
||||
- **Body payloads**: All POST/PATCH/PUT commands accept `--data '<json>'`. See [Mailchimp API docs](https://mailchimp.com/developer/marketing/api/) for the schema of each endpoint.
|
||||
- **Datacenter**: Your API key ends in `-us8`, `-eu2`, etc. The CLI extracts this automatically — include it in `MAILCHIMP_API_KEY`.
|
||||
- **Rate limits**: The Marketing API rate-limits at 10 concurrent connections and a rolling per-account limit. For bulk operations, use the `batches` group.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Test Guide — cli-anything-mailchimp
|
||||
|
||||
## Prerequisites
|
||||
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
# dev extras: pytest, pytest-cov, responses
|
||||
```
|
||||
|
||||
## Unit tests (no API key needed)
|
||||
|
||||
```bash
|
||||
cd mailchimp/agent-harness
|
||||
pytest cli_anything/mailchimp/tests/test_core.py -v
|
||||
```
|
||||
|
||||
Expected: all collected tests pass. Runtime < 5 seconds.
|
||||
|
||||
## Live E2E tests (requires MAILCHIMP_API_KEY)
|
||||
|
||||
```bash
|
||||
export MAILCHIMP_API_KEY=<your-key>-<datacenter>
|
||||
pytest cli_anything/mailchimp/tests/test_full_e2e.py -v -s
|
||||
```
|
||||
|
||||
Expected: 9 tests. The fixture creates a throwaway audience, runs member and
|
||||
merge-field operations against it, then deletes it. Runtime ~15–30 seconds.
|
||||
|
||||
Cleanup is automatic (the `test_list` fixture deletes the audience in a
|
||||
`finally` block). If a run is interrupted, delete the `cli-anything-test-*`
|
||||
list from your Mailchimp account manually.
|
||||
|
||||
## Coverage
|
||||
|
||||
```bash
|
||||
pytest cli_anything/mailchimp/tests/test_core.py --cov=cli_anything.mailchimp.core --cov-report=term-missing
|
||||
```
|
||||
|
||||
Target: ≥ 80% line coverage on `core/`.
|
||||
@@ -0,0 +1,566 @@
|
||||
"""Unit tests for cli-anything-mailchimp core modules."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import responses as resp_lib
|
||||
import requests
|
||||
|
||||
# ── client tests ──────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestServerPrefix(unittest.TestCase):
|
||||
def test_extracts_suffix(self):
|
||||
from cli_anything.mailchimp.core.client import _server_prefix
|
||||
|
||||
assert _server_prefix("abc123-us8") == "us8"
|
||||
assert _server_prefix("xyz-eu2") == "eu2"
|
||||
|
||||
def test_missing_suffix_raises(self):
|
||||
from cli_anything.mailchimp.core.client import _server_prefix
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
_server_prefix("nodashinkey")
|
||||
|
||||
|
||||
class TestSubscriberHash(unittest.TestCase):
|
||||
def test_md5_lowercased(self):
|
||||
from cli_anything.mailchimp.core.client import subscriber_hash
|
||||
|
||||
# Known MD5 of "test@example.com"
|
||||
assert subscriber_hash("test@example.com") == "55502f40dc8b7c769880b10874abc9d0"
|
||||
# Should normalise to lowercase before hashing
|
||||
assert subscriber_hash("TEST@EXAMPLE.COM") == subscriber_hash("test@example.com")
|
||||
|
||||
def test_strips_whitespace(self):
|
||||
from cli_anything.mailchimp.core.client import subscriber_hash
|
||||
|
||||
assert subscriber_hash(" test@example.com ") == subscriber_hash("test@example.com")
|
||||
|
||||
|
||||
class TestMailchimpClient(unittest.TestCase):
|
||||
def _make_client(self, key: str = "testkey-us1"):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
return MailchimpClient(api_key=key)
|
||||
|
||||
def test_base_url(self):
|
||||
client = self._make_client("abc-us8")
|
||||
assert client._base == "https://us8.api.mailchimp.com/3.0"
|
||||
|
||||
def test_auth_header(self):
|
||||
client = self._make_client("abc-us8")
|
||||
assert client._session.auth == ("anystring", "abc-us8")
|
||||
|
||||
def test_missing_key_raises_auth_error(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient, MailchimpAuthError
|
||||
import os
|
||||
|
||||
orig = os.environ.pop("MAILCHIMP_API_KEY", None)
|
||||
try:
|
||||
with self.assertRaises(MailchimpAuthError):
|
||||
MailchimpClient(api_key=None)
|
||||
finally:
|
||||
if orig:
|
||||
os.environ["MAILCHIMP_API_KEY"] = orig
|
||||
|
||||
def test_get_client_exits_on_missing_key(self):
|
||||
from cli_anything.mailchimp.core.client import get_client
|
||||
import os
|
||||
|
||||
orig = os.environ.pop("MAILCHIMP_API_KEY", None)
|
||||
try:
|
||||
with self.assertRaises(SystemExit):
|
||||
get_client()
|
||||
finally:
|
||||
if orig:
|
||||
os.environ["MAILCHIMP_API_KEY"] = orig
|
||||
|
||||
def test_get_client_exits_cleanly_on_key_without_suffix(self):
|
||||
from cli_anything.mailchimp.core.client import get_client
|
||||
import os
|
||||
|
||||
orig = os.environ.get("MAILCHIMP_API_KEY")
|
||||
os.environ["MAILCHIMP_API_KEY"] = "invalid"
|
||||
try:
|
||||
with self.assertRaises(SystemExit):
|
||||
get_client()
|
||||
finally:
|
||||
if orig is None:
|
||||
os.environ.pop("MAILCHIMP_API_KEY", None)
|
||||
else:
|
||||
os.environ["MAILCHIMP_API_KEY"] = orig
|
||||
|
||||
@resp_lib.activate
|
||||
def test_get_success(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
resp_lib.add(
|
||||
resp_lib.GET,
|
||||
"https://us1.api.mailchimp.com/3.0/ping",
|
||||
json={"health_status": "Everything's Chimpy!"},
|
||||
status=200,
|
||||
)
|
||||
result = client.get("/ping")
|
||||
assert result["health_status"] == "Everything's Chimpy!"
|
||||
|
||||
@resp_lib.activate
|
||||
def test_get_error_raises(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient, MailchimpError
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
resp_lib.add(
|
||||
resp_lib.GET,
|
||||
"https://us1.api.mailchimp.com/3.0/lists/bad",
|
||||
json={"title": "Resource Not Found", "detail": "The requested resource could not be found.", "status": 404},
|
||||
status=404,
|
||||
)
|
||||
with self.assertRaises(MailchimpError) as ctx:
|
||||
client.get("/lists/bad")
|
||||
assert ctx.exception.status == 404
|
||||
assert "Resource Not Found" in ctx.exception.title
|
||||
|
||||
@resp_lib.activate
|
||||
def test_post_success(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
resp_lib.add(
|
||||
resp_lib.POST,
|
||||
"https://us1.api.mailchimp.com/3.0/lists",
|
||||
json={"id": "abc123", "name": "My List"},
|
||||
status=200,
|
||||
)
|
||||
result = client.post("/lists", json={"name": "My List"})
|
||||
assert result["id"] == "abc123"
|
||||
|
||||
@resp_lib.activate
|
||||
def test_delete_returns_ok(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
resp_lib.add(
|
||||
resp_lib.DELETE,
|
||||
"https://us1.api.mailchimp.com/3.0/lists/abc123",
|
||||
status=204,
|
||||
)
|
||||
result = client.delete("/lists/abc123")
|
||||
assert result == {"ok": True}
|
||||
|
||||
def test_patch_forwards_query_params(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
client._session.patch = MagicMock()
|
||||
client._session.patch.return_value.ok = True
|
||||
client._session.patch.return_value.json.return_value = {"id": "contact-1"}
|
||||
|
||||
result = client.patch(
|
||||
"/audiences/audience-1/contacts/contact-1",
|
||||
json={"email_address": "user@example.com"},
|
||||
params={"data_mode": "sync"},
|
||||
)
|
||||
|
||||
assert result == {"id": "contact-1"}
|
||||
client._session.patch.assert_called_once_with(
|
||||
"https://us1.api.mailchimp.com/3.0/audiences/audience-1/contacts/contact-1",
|
||||
json={"email_address": "user@example.com"},
|
||||
params={"data_mode": "sync"},
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
def test_put_forwards_query_params(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
client._session.put = MagicMock()
|
||||
client._session.put.return_value.ok = True
|
||||
client._session.put.return_value.json.return_value = {"id": "member-1"}
|
||||
|
||||
result = client.put(
|
||||
"/lists/list-1/members/hash-1",
|
||||
json={"email_address": "user@example.com"},
|
||||
params={"skip_merge_validation": True},
|
||||
)
|
||||
|
||||
assert result == {"id": "member-1"}
|
||||
client._session.put.assert_called_once_with(
|
||||
"https://us1.api.mailchimp.com/3.0/lists/list-1/members/hash-1",
|
||||
json={"email_address": "user@example.com"},
|
||||
params={"skip_merge_validation": True},
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
def test_delete_forwards_query_params(self):
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
client = MailchimpClient(api_key="key-us1")
|
||||
client._session.delete = MagicMock()
|
||||
client._session.delete.return_value.ok = True
|
||||
|
||||
result = client.delete("/lists/list-1", params={"force": True})
|
||||
|
||||
assert result == {"ok": True}
|
||||
client._session.delete.assert_called_once_with(
|
||||
"https://us1.api.mailchimp.com/3.0/lists/list-1",
|
||||
params={"force": True},
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
|
||||
# ── pagination tests ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestPagination(unittest.TestCase):
|
||||
def _mock_client(self, pages: list[list]) -> MagicMock:
|
||||
client = MagicMock()
|
||||
side_effects = [
|
||||
{"lists": page, "total_items": sum(len(p) for p in pages)}
|
||||
for page in pages
|
||||
]
|
||||
client.get.side_effect = side_effects
|
||||
return client
|
||||
|
||||
def test_single_page(self):
|
||||
from cli_anything.mailchimp.core.pagination import paginate
|
||||
|
||||
client = self._mock_client([[{"id": "1"}, {"id": "2"}]])
|
||||
items = list(paginate(client, "/lists", "lists", page_size=100))
|
||||
assert items == [{"id": "1"}, {"id": "2"}]
|
||||
assert client.get.call_count == 1
|
||||
|
||||
def test_multiple_pages(self):
|
||||
from cli_anything.mailchimp.core.pagination import paginate
|
||||
|
||||
page1 = [{"id": str(i)} for i in range(5)]
|
||||
page2 = [{"id": str(i)} for i in range(5, 8)]
|
||||
client = self._mock_client([page1, page2])
|
||||
items = list(paginate(client, "/lists", "lists", page_size=5))
|
||||
assert len(items) == 8
|
||||
assert client.get.call_count == 2
|
||||
|
||||
def test_empty_result(self):
|
||||
from cli_anything.mailchimp.core.pagination import paginate
|
||||
|
||||
client = self._mock_client([[]])
|
||||
items = list(paginate(client, "/lists", "lists"))
|
||||
assert items == []
|
||||
|
||||
def test_exact_page_boundary_no_extra_fetch(self):
|
||||
"""When total_items == page_size, paginator must not fetch a second empty page (I6 fix)."""
|
||||
from cli_anything.mailchimp.core.pagination import paginate
|
||||
|
||||
page = [{"id": str(i)} for i in range(5)]
|
||||
client = MagicMock()
|
||||
# First call returns exactly page_size items with total_items matching
|
||||
client.get.return_value = {"lists": page, "total_items": 5}
|
||||
items = list(paginate(client, "/lists", "lists", page_size=5))
|
||||
assert len(items) == 5
|
||||
assert client.get.call_count == 1 # must not make a second call
|
||||
|
||||
def test_collect_returns_total(self):
|
||||
from cli_anything.mailchimp.core.pagination import collect
|
||||
|
||||
client = MagicMock()
|
||||
client.get.return_value = {"lists": [{"id": "1"}], "total_items": 42}
|
||||
items, total = collect(client, "/lists", "lists")
|
||||
assert items == [{"id": "1"}]
|
||||
assert total == 42
|
||||
|
||||
|
||||
# ── output tests ──────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestOutput(unittest.TestCase):
|
||||
def setUp(self):
|
||||
import cli_anything.mailchimp.utils.output as out
|
||||
self._orig = out.USE_JSON
|
||||
out.USE_JSON = False
|
||||
|
||||
def tearDown(self):
|
||||
import cli_anything.mailchimp.utils.output as out
|
||||
out.USE_JSON = self._orig
|
||||
|
||||
def test_json_mode_outputs_json(self):
|
||||
import cli_anything.mailchimp.utils.output as out
|
||||
import io
|
||||
|
||||
out.USE_JSON = True
|
||||
captured = io.StringIO()
|
||||
with patch("builtins.print", lambda *a, **kw: captured.write(str(a[0]) + "\n")):
|
||||
out._out({"key": "value"})
|
||||
|
||||
parsed = json.loads(captured.getvalue())
|
||||
assert parsed["key"] == "value"
|
||||
|
||||
# ── smoke import tests ────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestGeneratedCommandsImport(unittest.TestCase):
|
||||
"""Verify every generated command module imports cleanly and registers commands.
|
||||
|
||||
This catches codegen regressions like C1 (builtin shadowing) which would
|
||||
cause Click to fail silently or raise at import time.
|
||||
"""
|
||||
|
||||
def test_all_groups_importable(self):
|
||||
from cli_anything.mailchimp.commands import ALL_GROUPS
|
||||
|
||||
assert len(ALL_GROUPS) == 30, f"Expected 30 groups, got {len(ALL_GROUPS)}"
|
||||
for group in ALL_GROUPS:
|
||||
assert group.name is not None
|
||||
assert len(group.commands) > 0, f"Group {group.name!r} has no commands"
|
||||
|
||||
def test_generator_preserves_complete_first_line_help(self):
|
||||
from cli_anything.mailchimp._codegen.generate import _click_help_text
|
||||
|
||||
description = (
|
||||
"Used for [pagination](https://mailchimp.com/developer/marketing/docs/fundamentals/#pagination) "
|
||||
"with enough context to exceed eighty characters.\nSecond line omitted."
|
||||
)
|
||||
|
||||
help_text = _click_help_text(description)
|
||||
|
||||
assert help_text.endswith("eighty characters.")
|
||||
assert "\n" not in help_text
|
||||
|
||||
def test_no_builtin_shadowing_in_function_names(self):
|
||||
"""Ensure generated functions are prefixed with _cmd_ (not builtins)."""
|
||||
import glob
|
||||
import ast
|
||||
import builtins as _builtins
|
||||
|
||||
builtin_names = set(dir(_builtins))
|
||||
issues = []
|
||||
|
||||
for path in glob.glob("cli_anything/mailchimp/commands/*.py"):
|
||||
tree = ast.parse(open(path).read())
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.FunctionDef):
|
||||
if node.name in builtin_names:
|
||||
issues.append(f"{path}: def {node.name}()")
|
||||
|
||||
assert not issues, "Builtin shadowing in generated code:\n" + "\n".join(issues)
|
||||
|
||||
def test_all_commands_have_extra_params(self):
|
||||
"""Every generated command must accept --extra-params (I3 fix)."""
|
||||
from cli_anything.mailchimp.commands import ALL_GROUPS
|
||||
import click
|
||||
|
||||
missing = []
|
||||
for group in ALL_GROUPS:
|
||||
for cmd_name, cmd in group.commands.items():
|
||||
if isinstance(cmd, click.Group):
|
||||
continue
|
||||
param_names = [p.name for p in cmd.params]
|
||||
if "extra_params" not in param_names:
|
||||
missing.append(f"{group.name} {cmd_name}")
|
||||
|
||||
assert not missing, "--extra-params missing on:\n" + "\n".join(missing)
|
||||
|
||||
def test_generated_patch_command_forwards_query_params(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.audiences import audiences_group
|
||||
|
||||
client = MagicMock()
|
||||
client.patch.return_value = {"id": "contact-1"}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
result = CliRunner().invoke(
|
||||
audiences_group,
|
||||
[
|
||||
"update",
|
||||
"audience-1",
|
||||
"contact-1",
|
||||
"--data",
|
||||
'{"email_address":"user@example.com"}',
|
||||
"--data-mode",
|
||||
"sync",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
client.patch.assert_called_once_with(
|
||||
"/audiences/audience-1/contacts/contact-1",
|
||||
json={"email_address": "user@example.com"},
|
||||
params={"data_mode": "sync"},
|
||||
)
|
||||
|
||||
def test_generated_put_command_forwards_query_params(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.lists import lists_group
|
||||
|
||||
client = MagicMock()
|
||||
client.put.return_value = {"id": "member-1"}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
result = CliRunner().invoke(
|
||||
lists_group,
|
||||
[
|
||||
"update-3",
|
||||
"list-1",
|
||||
"hash-1",
|
||||
"--data",
|
||||
'{"email_address":"user@example.com"}',
|
||||
"--skip-merge-validation",
|
||||
"true",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
client.put.assert_called_once_with(
|
||||
"/lists/list-1/members/hash-1",
|
||||
json={"email_address": "user@example.com"},
|
||||
params={"skip_merge_validation": True},
|
||||
)
|
||||
|
||||
def test_generated_keyword_query_option_uses_safe_callback_name(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.templates import templates_group
|
||||
|
||||
client = MagicMock()
|
||||
client.get.return_value = {"templates": []}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
result = CliRunner().invoke(templates_group, ["list", "--type", "user"])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
client.get.assert_called_once_with("/templates", params={"type": "user"})
|
||||
|
||||
def test_campaign_shortcut_aliases_match_generated_commands(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.campaigns import campaigns_group
|
||||
|
||||
client = MagicMock()
|
||||
client.get.return_value = {"items": []}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
content = CliRunner().invoke(campaigns_group, ["list-content", "campaign-1"])
|
||||
checklist = CliRunner().invoke(campaigns_group, ["list-send-checklist", "campaign-1"])
|
||||
|
||||
assert content.exit_code == 0, content.output
|
||||
assert checklist.exit_code == 0, checklist.output
|
||||
client.get.assert_any_call("/campaigns/campaign-1/content", params=None)
|
||||
client.get.assert_any_call("/campaigns/campaign-1/send-checklist", params=None)
|
||||
|
||||
def test_report_shortcut_aliases_match_generated_commands(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.reports import reports_group
|
||||
|
||||
client = MagicMock()
|
||||
client.get.return_value = {"items": []}
|
||||
|
||||
shortcuts = {
|
||||
"list-email-activity": "/reports/campaign-1/email-activity",
|
||||
"list-click-details": "/reports/campaign-1/click-details",
|
||||
"list-open-details": "/reports/campaign-1/open-details",
|
||||
"list-unsubscribed": "/reports/campaign-1/unsubscribed",
|
||||
"list-locations": "/reports/campaign-1/locations",
|
||||
"list-domain-performance": "/reports/campaign-1/domain-performance",
|
||||
}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
for command in shortcuts:
|
||||
result = CliRunner().invoke(reports_group, [command, "campaign-1"])
|
||||
assert result.exit_code == 0, result.output
|
||||
|
||||
for path in shortcuts.values():
|
||||
client.get.assert_any_call(path, params=None)
|
||||
|
||||
def test_automation_and_segment_shortcut_aliases_match_generated_commands(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.automations import automations_group
|
||||
from cli_anything.mailchimp.commands.lists import lists_group
|
||||
|
||||
client = MagicMock()
|
||||
client.get.return_value = {"items": []}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
emails = CliRunner().invoke(automations_group, ["list-emails", "workflow-1"])
|
||||
segments = CliRunner().invoke(lists_group, ["list-lists-id-segments", "list-1"])
|
||||
|
||||
assert emails.exit_code == 0, emails.output
|
||||
assert segments.exit_code == 0, segments.output
|
||||
client.get.assert_any_call("/automations/workflow-1/emails", params=None)
|
||||
client.get.assert_any_call("/lists/list-1/segments", params=None)
|
||||
|
||||
def test_ping_group_invokes_health_check_without_list_subcommand(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.mailchimp_cli import cli
|
||||
|
||||
client = MagicMock()
|
||||
client.get.return_value = {"health_status": "Everything's Chimpy!"}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
result = CliRunner().invoke(cli, ["ping"])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
client.get.assert_called_once_with("/ping", params=None)
|
||||
|
||||
def test_create_members_alias_matches_generated_command(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.lists import lists_group
|
||||
|
||||
client = MagicMock()
|
||||
client.post.return_value = {"id": "member-1"}
|
||||
|
||||
with patch("cli_anything.mailchimp.core.client.get_client", return_value=client):
|
||||
result = CliRunner().invoke(
|
||||
lists_group,
|
||||
[
|
||||
"create-members",
|
||||
"list-1",
|
||||
"--data",
|
||||
'{"email_address":"user@example.com","status":"subscribed"}',
|
||||
"--skip-merge-validation",
|
||||
"true",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
client.post.assert_called_once_with(
|
||||
"/lists/list-1/members",
|
||||
json={"email_address": "user@example.com", "status": "subscribed"},
|
||||
params={"skip_merge_validation": True},
|
||||
)
|
||||
|
||||
def test_invalid_data_json_reports_click_error(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.lists import lists_group
|
||||
|
||||
result = CliRunner().invoke(lists_group, ["create", "--data", "{bad"])
|
||||
|
||||
assert result.exit_code == 2
|
||||
assert "Invalid value for --data" in result.output
|
||||
assert "valid JSON" in result.output
|
||||
assert "Traceback" not in result.output
|
||||
|
||||
def test_extra_params_must_be_json_object(self):
|
||||
from click.testing import CliRunner
|
||||
from cli_anything.mailchimp.commands.lists import lists_group
|
||||
|
||||
result = CliRunner().invoke(lists_group, ["list", "--extra-params", "[]"])
|
||||
|
||||
assert result.exit_code == 2
|
||||
assert "Invalid value for --extra-params" in result.output
|
||||
assert "JSON object" in result.output
|
||||
assert "Traceback" not in result.output
|
||||
|
||||
def test_cli_without_subcommand_starts_repl_through_click(self):
|
||||
from click.testing import CliRunner
|
||||
import cli_anything.mailchimp.mailchimp_cli as mailchimp_cli
|
||||
|
||||
with patch.object(mailchimp_cli, "_start_repl") as start_repl:
|
||||
result = CliRunner().invoke(mailchimp_cli.cli, [])
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
start_repl.assert_called_once_with()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,127 @@
|
||||
"""End-to-end tests against the live Mailchimp API.
|
||||
|
||||
Skipped unless MAILCHIMP_API_KEY is set. Creates a throwaway audience,
|
||||
exercises member and merge-field operations, then cleans up.
|
||||
|
||||
Run:
|
||||
MAILCHIMP_API_KEY=<key>-<dc> pytest tests/test_full_e2e.py -v -s
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not os.environ.get("MAILCHIMP_API_KEY"),
|
||||
reason="MAILCHIMP_API_KEY not set — skipping live API tests",
|
||||
)
|
||||
|
||||
TEST_LIST_NAME = f"cli-anything-test-{uuid.uuid4().hex[:8]}"
|
||||
TEST_EMAIL = f"cli-test-{uuid.uuid4().hex[:8]}@example.com"
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def client():
|
||||
from cli_anything.mailchimp.core.client import MailchimpClient
|
||||
|
||||
return MailchimpClient()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def test_list(client):
|
||||
"""Create a throwaway Mailchimp audience, yield its ID, then delete it."""
|
||||
body = {
|
||||
"name": TEST_LIST_NAME,
|
||||
"contact": {
|
||||
"company": "CLI-Anything Test",
|
||||
"address1": "123 Test St",
|
||||
"city": "Testville",
|
||||
"state": "CA",
|
||||
"zip": "90210",
|
||||
"country": "US",
|
||||
},
|
||||
"permission_reminder": "test permission reminder",
|
||||
"email_type_option": False,
|
||||
"campaign_defaults": {
|
||||
"from_name": "CLI Test",
|
||||
"from_email": "test@example.com",
|
||||
"subject": "Test",
|
||||
"language": "en",
|
||||
},
|
||||
}
|
||||
result = client.post("/lists", json=body)
|
||||
list_id = result["id"]
|
||||
yield list_id
|
||||
# Cleanup — delete the test list
|
||||
try:
|
||||
client.delete(f"/lists/{list_id}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class TestPing:
|
||||
def test_ping(self, client):
|
||||
result = client.get("/ping")
|
||||
assert "health_status" in result
|
||||
|
||||
|
||||
class TestLists:
|
||||
def test_get_lists(self, client):
|
||||
result = client.get("/lists", params={"count": 1})
|
||||
assert "lists" in result
|
||||
assert isinstance(result["lists"], list)
|
||||
|
||||
def test_create_and_get_list(self, client, test_list):
|
||||
result = client.get(f"/lists/{test_list}")
|
||||
assert result["id"] == test_list
|
||||
assert result["name"] == TEST_LIST_NAME
|
||||
|
||||
def test_update_list(self, client, test_list):
|
||||
new_name = TEST_LIST_NAME + "-updated"
|
||||
result = client.patch(f"/lists/{test_list}", json={"name": new_name})
|
||||
assert result["name"] == new_name
|
||||
# Restore
|
||||
client.patch(f"/lists/{test_list}", json={"name": TEST_LIST_NAME})
|
||||
|
||||
|
||||
class TestMembers:
|
||||
def test_add_member(self, client, test_list):
|
||||
body = {
|
||||
"email_address": TEST_EMAIL,
|
||||
"status": "subscribed",
|
||||
}
|
||||
result = client.post(f"/lists/{test_list}/members", json=body)
|
||||
assert result["email_address"] == TEST_EMAIL
|
||||
assert result["status"] == "subscribed"
|
||||
|
||||
def test_get_member(self, client, test_list):
|
||||
from cli_anything.mailchimp.core.client import subscriber_hash
|
||||
|
||||
h = subscriber_hash(TEST_EMAIL)
|
||||
result = client.get(f"/lists/{test_list}/members/{h}")
|
||||
assert result["email_address"] == TEST_EMAIL
|
||||
|
||||
def test_list_members(self, client, test_list):
|
||||
result = client.get(f"/lists/{test_list}/members", params={"count": 10})
|
||||
emails = [m["email_address"] for m in result.get("members", [])]
|
||||
assert TEST_EMAIL in emails
|
||||
|
||||
def test_archive_member(self, client, test_list):
|
||||
from cli_anything.mailchimp.core.client import subscriber_hash
|
||||
|
||||
h = subscriber_hash(TEST_EMAIL)
|
||||
result = client.delete(f"/lists/{test_list}/members/{h}")
|
||||
assert result == {"ok": True}
|
||||
|
||||
|
||||
class TestMergeFields:
|
||||
def test_create_and_list_merge_fields(self, client, test_list):
|
||||
body = {"tag": "TESTFIELD", "name": "Test Field", "type": "text"}
|
||||
result = client.post(f"/lists/{test_list}/merge-fields", json=body)
|
||||
assert result["tag"] == "TESTFIELD"
|
||||
|
||||
fields = client.get(f"/lists/{test_list}/merge-fields")
|
||||
tags = [f["tag"] for f in fields.get("merge_fields", [])]
|
||||
assert "TESTFIELD" in tags
|
||||
@@ -0,0 +1,86 @@
|
||||
"""JSON / human output helpers for cli-anything-mailchimp."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
# Module-level flag set by the root CLI group's --json option.
|
||||
USE_JSON: bool = False
|
||||
|
||||
|
||||
def _out(data: Any) -> None:
|
||||
"""Print data as JSON (when --json) or human-readable text."""
|
||||
if USE_JSON:
|
||||
print(json.dumps(data, indent=2, default=str))
|
||||
elif isinstance(data, dict):
|
||||
_print_dict(data)
|
||||
elif isinstance(data, list):
|
||||
_print_list(data)
|
||||
else:
|
||||
print(data)
|
||||
|
||||
|
||||
def _out_ok(message: str, data: dict | None = None) -> None:
|
||||
"""Print a success/mutation result.
|
||||
|
||||
JSON shape: {"ok": true, "message": "<msg>"} or {"ok": true, "message": "...", "data": {...}}
|
||||
"""
|
||||
if USE_JSON:
|
||||
payload: dict = {"ok": True, "message": message}
|
||||
if data:
|
||||
payload["data"] = data
|
||||
print(json.dumps(payload, indent=2, default=str))
|
||||
else:
|
||||
print(f" \033[38;5;78m✓\033[0m {message}")
|
||||
if data:
|
||||
_print_dict(data)
|
||||
|
||||
|
||||
def _out_err(status: int, title: str, detail: str, raw: dict | None = None) -> None:
|
||||
"""Print an error and exit non-zero."""
|
||||
if USE_JSON:
|
||||
print(
|
||||
json.dumps(
|
||||
{"ok": False, "message": f"{title}: {detail}", "data": raw or {}},
|
||||
indent=2,
|
||||
),
|
||||
file=sys.stderr,
|
||||
)
|
||||
else:
|
||||
print(f" \033[38;5;196m✗\033[0m HTTP {status}: {title}", file=sys.stderr)
|
||||
if detail:
|
||||
print(f" {detail}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# ── Formatting helpers ─────────────────────────────────────────────────
|
||||
|
||||
|
||||
_GRAY = "\033[38;5;245m"
|
||||
_WHITE = "\033[97m"
|
||||
_CYAN = "\033[38;5;80m"
|
||||
_RESET = "\033[0m"
|
||||
|
||||
|
||||
def _print_dict(d: dict, indent: int = 2) -> None:
|
||||
prefix = " " * indent
|
||||
for k, v in d.items():
|
||||
key = f"{_GRAY}{k}:{_RESET}"
|
||||
if isinstance(v, dict):
|
||||
print(f"{prefix}{key}")
|
||||
_print_dict(v, indent + 2)
|
||||
elif isinstance(v, list):
|
||||
print(f"{prefix}{key} [{len(v)} items]")
|
||||
else:
|
||||
print(f"{prefix}{key} {_WHITE}{v}{_RESET}")
|
||||
|
||||
|
||||
def _print_list(items: list, indent: int = 2) -> None:
|
||||
for item in items:
|
||||
if isinstance(item, dict):
|
||||
_print_dict(item, indent)
|
||||
print()
|
||||
else:
|
||||
print(" " * indent + str(item))
|
||||
@@ -0,0 +1,567 @@
|
||||
"""cli-anything REPL Skin — Unified terminal interface for all CLI harnesses.
|
||||
|
||||
Copy this file into your CLI package at:
|
||||
cli_anything/<software>/utils/repl_skin.py
|
||||
|
||||
Usage:
|
||||
from cli_anything.<software>.utils.repl_skin import ReplSkin
|
||||
|
||||
skin = ReplSkin("shotcut", version="1.0.0")
|
||||
skin.print_banner() # auto-detects repo-root or packaged SKILL.md
|
||||
prompt_text = skin.prompt(project_name="my_video.mlt", modified=True)
|
||||
skin.success("Project saved")
|
||||
skin.error("File not found")
|
||||
skin.warning("Unsaved changes")
|
||||
skin.info("Processing 24 clips...")
|
||||
skin.status("Track 1", "3 clips, 00:02:30")
|
||||
skin.table(headers, rows)
|
||||
skin.print_goodbye()
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# ── ANSI color codes (no external deps for core styling) ──────────────
|
||||
|
||||
_RESET = "\033[0m"
|
||||
_BOLD = "\033[1m"
|
||||
_DIM = "\033[2m"
|
||||
_ITALIC = "\033[3m"
|
||||
_UNDERLINE = "\033[4m"
|
||||
|
||||
# Brand colors
|
||||
_CYAN = "\033[38;5;80m" # cli-anything brand cyan
|
||||
_CYAN_BG = "\033[48;5;80m"
|
||||
_WHITE = "\033[97m"
|
||||
_GRAY = "\033[38;5;245m"
|
||||
_DARK_GRAY = "\033[38;5;240m"
|
||||
_LIGHT_GRAY = "\033[38;5;250m"
|
||||
|
||||
# Software accent colors — each software gets a unique accent
|
||||
_ACCENT_COLORS = {
|
||||
"gimp": "\033[38;5;214m", # warm orange
|
||||
"blender": "\033[38;5;208m", # deep orange
|
||||
"inkscape": "\033[38;5;39m", # bright blue
|
||||
"audacity": "\033[38;5;33m", # navy blue
|
||||
"libreoffice": "\033[38;5;40m", # green
|
||||
"obs_studio": "\033[38;5;55m", # purple
|
||||
"kdenlive": "\033[38;5;69m", # slate blue
|
||||
"shotcut": "\033[38;5;35m", # teal green
|
||||
}
|
||||
_DEFAULT_ACCENT = "\033[38;5;75m" # default sky blue
|
||||
|
||||
# Status colors
|
||||
_GREEN = "\033[38;5;78m"
|
||||
_YELLOW = "\033[38;5;220m"
|
||||
_RED = "\033[38;5;196m"
|
||||
_BLUE = "\033[38;5;75m"
|
||||
_MAGENTA = "\033[38;5;176m"
|
||||
|
||||
_SKILL_SOURCE_REPO = os.environ.get("CLI_ANYTHING_SKILL_REPO", "HKUDS/CLI-Anything")
|
||||
|
||||
# ── Brand icon ────────────────────────────────────────────────────────
|
||||
|
||||
# The cli-anything icon: a small colored diamond/chevron mark
|
||||
_ICON = f"{_CYAN}{_BOLD}◆{_RESET}"
|
||||
_ICON_SMALL = f"{_CYAN}▸{_RESET}"
|
||||
|
||||
# ── Box drawing characters ────────────────────────────────────────────
|
||||
|
||||
_H_LINE = "─"
|
||||
_V_LINE = "│"
|
||||
_TL = "╭"
|
||||
_TR = "╮"
|
||||
_BL = "╰"
|
||||
_BR = "╯"
|
||||
_T_DOWN = "┬"
|
||||
_T_UP = "┴"
|
||||
_T_RIGHT = "├"
|
||||
_T_LEFT = "┤"
|
||||
_CROSS = "┼"
|
||||
|
||||
|
||||
def _strip_ansi(text: str) -> str:
|
||||
"""Remove ANSI escape codes for length calculation."""
|
||||
import re
|
||||
return re.sub(r"\033\[[^m]*m", "", text)
|
||||
|
||||
|
||||
def _visible_len(text: str) -> int:
|
||||
"""Get visible length of text (excluding ANSI codes)."""
|
||||
return len(_strip_ansi(text))
|
||||
|
||||
|
||||
def _display_home_path(path: str) -> str:
|
||||
"""Display a path relative to the home directory when possible."""
|
||||
expanded = Path(path).expanduser().resolve()
|
||||
home = Path.home().resolve()
|
||||
try:
|
||||
relative = expanded.relative_to(home)
|
||||
return f"~/{relative.as_posix()}"
|
||||
except ValueError:
|
||||
return str(expanded)
|
||||
|
||||
|
||||
class ReplSkin:
|
||||
"""Unified REPL skin for cli-anything CLIs.
|
||||
|
||||
Provides consistent branding, prompts, and message formatting
|
||||
across all CLI harnesses built with the cli-anything methodology.
|
||||
"""
|
||||
|
||||
def __init__(self, software: str, version: str = "1.0.0",
|
||||
history_file: str | None = None, skill_path: str | None = None):
|
||||
"""Initialize the REPL skin.
|
||||
|
||||
Args:
|
||||
software: Software name (e.g., "gimp", "shotcut", "blender").
|
||||
version: CLI version string.
|
||||
history_file: Path for persistent command history.
|
||||
Defaults to ~/.cli-anything-<software>/history
|
||||
skill_path: Path to the SKILL.md file for agent discovery.
|
||||
Auto-detected from the repo-root skills/ tree when present,
|
||||
otherwise from the package's skills/ directory.
|
||||
Displayed in banner for AI agents to know where to read skill info.
|
||||
"""
|
||||
self.software = software.lower().replace("-", "_")
|
||||
self.display_name = software.replace("_", " ").title()
|
||||
self.version = version
|
||||
software_aliases = {"iterm2_ctl": "iterm2"}
|
||||
self.skill_slug = software_aliases.get(self.software, self.software).replace("_", "-")
|
||||
self.skill_id = f"cli-anything-{self.skill_slug}"
|
||||
self.skill_install_cmd = (
|
||||
f"npx skills add {_SKILL_SOURCE_REPO} --skill {self.skill_id} -g -y"
|
||||
)
|
||||
global_skill_root = Path(
|
||||
os.environ.get("CLI_ANYTHING_GLOBAL_SKILLS_DIR", str(Path.home() / ".agents" / "skills"))
|
||||
).expanduser()
|
||||
self.global_skill_path = str(global_skill_root / self.skill_id / "SKILL.md")
|
||||
|
||||
# Prefer repo-root canonical skills/<skill-id>/SKILL.md when running
|
||||
# inside the CLI-Anything monorepo. Fall back to the packaged
|
||||
# cli_anything/<software>/skills/SKILL.md for installed harnesses.
|
||||
if skill_path is None:
|
||||
package_skill = Path(__file__).resolve().parent.parent / "skills" / "SKILL.md"
|
||||
repo_skill = None
|
||||
for parent in Path(__file__).resolve().parents:
|
||||
candidate = parent / "skills" / self.skill_id / "SKILL.md"
|
||||
if candidate.is_file():
|
||||
repo_skill = candidate
|
||||
break
|
||||
if repo_skill and repo_skill.is_file():
|
||||
skill_path = str(repo_skill)
|
||||
elif package_skill.is_file():
|
||||
skill_path = str(package_skill)
|
||||
self.skill_path = skill_path
|
||||
self.accent = _ACCENT_COLORS.get(self.software, _DEFAULT_ACCENT)
|
||||
|
||||
# History file
|
||||
if history_file is None:
|
||||
hist_dir = Path.home() / f".cli-anything-{self.software}"
|
||||
hist_dir.mkdir(parents=True, exist_ok=True)
|
||||
self.history_file = str(hist_dir / "history")
|
||||
else:
|
||||
self.history_file = history_file
|
||||
|
||||
# Detect terminal capabilities
|
||||
self._color = self._detect_color_support()
|
||||
|
||||
def _detect_color_support(self) -> bool:
|
||||
"""Check if terminal supports color."""
|
||||
if os.environ.get("NO_COLOR"):
|
||||
return False
|
||||
if os.environ.get("CLI_ANYTHING_NO_COLOR"):
|
||||
return False
|
||||
if not hasattr(sys.stdout, "isatty"):
|
||||
return False
|
||||
return sys.stdout.isatty()
|
||||
|
||||
def _c(self, code: str, text: str) -> str:
|
||||
"""Apply color code if colors are supported."""
|
||||
if not self._color:
|
||||
return text
|
||||
return f"{code}{text}{_RESET}"
|
||||
|
||||
# ── Banner ────────────────────────────────────────────────────────
|
||||
|
||||
def print_banner(self):
|
||||
"""Print the startup banner with branding."""
|
||||
import textwrap
|
||||
|
||||
inner = 72
|
||||
|
||||
def _box_line(content: str) -> str:
|
||||
"""Wrap content in box drawing, padding to inner width."""
|
||||
pad = inner - _visible_len(content)
|
||||
vl = self._c(_DARK_GRAY, _V_LINE)
|
||||
return f"{vl}{content}{' ' * max(0, pad)}{vl}"
|
||||
|
||||
def _meta_lines(label: str, value: str) -> list[str]:
|
||||
"""Wrap a metadata line for the banner box."""
|
||||
icon = self._c(_MAGENTA, "◇")
|
||||
label_text = self._c(_DARK_GRAY, label)
|
||||
prefix = f" {icon} {label_text} "
|
||||
available = max(12, inner - _visible_len(prefix))
|
||||
wrapped = textwrap.wrap(
|
||||
value,
|
||||
width=available,
|
||||
break_long_words=True,
|
||||
break_on_hyphens=False,
|
||||
) or [""]
|
||||
lines = [f"{prefix}{self._c(_LIGHT_GRAY, wrapped[0])}"]
|
||||
continuation_prefix = " " * _visible_len(prefix)
|
||||
for chunk in wrapped[1:]:
|
||||
lines.append(f"{continuation_prefix}{self._c(_LIGHT_GRAY, chunk)}")
|
||||
return lines
|
||||
|
||||
top = self._c(_DARK_GRAY, f"{_TL}{_H_LINE * inner}{_TR}")
|
||||
bot = self._c(_DARK_GRAY, f"{_BL}{_H_LINE * inner}{_BR}")
|
||||
|
||||
# Title: ◆ cli-anything · Shotcut
|
||||
icon = self._c(_CYAN + _BOLD, "◆")
|
||||
brand = self._c(_CYAN + _BOLD, "cli-anything")
|
||||
dot = self._c(_DARK_GRAY, "·")
|
||||
name = self._c(self.accent + _BOLD, self.display_name)
|
||||
title = f" {icon} {brand} {dot} {name}"
|
||||
|
||||
ver = f" {self._c(_DARK_GRAY, f' v{self.version}')}"
|
||||
tip = f" {self._c(_DARK_GRAY, ' Type help for commands, quit to exit')}"
|
||||
empty = ""
|
||||
|
||||
meta_lines: list[str] = []
|
||||
meta_lines.extend(_meta_lines("Install:", self.skill_install_cmd))
|
||||
meta_lines.extend(_meta_lines("Global skill:", _display_home_path(self.global_skill_path)))
|
||||
print(top)
|
||||
print(_box_line(title))
|
||||
print(_box_line(ver))
|
||||
for line in meta_lines:
|
||||
print(_box_line(line))
|
||||
print(_box_line(empty))
|
||||
print(_box_line(tip))
|
||||
print(bot)
|
||||
print()
|
||||
|
||||
# ── Prompt ────────────────────────────────────────────────────────
|
||||
|
||||
def prompt(self, project_name: str = "", modified: bool = False,
|
||||
context: str = "") -> str:
|
||||
"""Build a styled prompt string for prompt_toolkit or input().
|
||||
|
||||
Args:
|
||||
project_name: Current project name (empty if none open).
|
||||
modified: Whether the project has unsaved changes.
|
||||
context: Optional extra context to show in prompt.
|
||||
|
||||
Returns:
|
||||
Formatted prompt string.
|
||||
"""
|
||||
parts = []
|
||||
|
||||
# Icon
|
||||
if self._color:
|
||||
parts.append(f"{_CYAN}◆{_RESET} ")
|
||||
else:
|
||||
parts.append("> ")
|
||||
|
||||
# Software name
|
||||
parts.append(self._c(self.accent + _BOLD, self.software))
|
||||
|
||||
# Project context
|
||||
if project_name or context:
|
||||
ctx = context or project_name
|
||||
mod = "*" if modified else ""
|
||||
parts.append(f" {self._c(_DARK_GRAY, '[')}")
|
||||
parts.append(self._c(_LIGHT_GRAY, f"{ctx}{mod}"))
|
||||
parts.append(self._c(_DARK_GRAY, ']'))
|
||||
|
||||
parts.append(self._c(_GRAY, " ❯ "))
|
||||
|
||||
return "".join(parts)
|
||||
|
||||
def prompt_tokens(self, project_name: str = "", modified: bool = False,
|
||||
context: str = ""):
|
||||
"""Build prompt_toolkit formatted text tokens for the prompt.
|
||||
|
||||
Use with prompt_toolkit's FormattedText for proper ANSI handling.
|
||||
|
||||
Returns:
|
||||
list of (style, text) tuples for prompt_toolkit.
|
||||
"""
|
||||
accent_hex = _ANSI_256_TO_HEX.get(self.accent, "#5fafff")
|
||||
tokens = []
|
||||
|
||||
tokens.append(("class:icon", "◆ "))
|
||||
tokens.append(("class:software", self.software))
|
||||
|
||||
if project_name or context:
|
||||
ctx = context or project_name
|
||||
mod = "*" if modified else ""
|
||||
tokens.append(("class:bracket", " ["))
|
||||
tokens.append(("class:context", f"{ctx}{mod}"))
|
||||
tokens.append(("class:bracket", "]"))
|
||||
|
||||
tokens.append(("class:arrow", " ❯ "))
|
||||
|
||||
return tokens
|
||||
|
||||
def get_prompt_style(self):
|
||||
"""Get a prompt_toolkit Style object matching the skin.
|
||||
|
||||
Returns:
|
||||
prompt_toolkit.styles.Style
|
||||
"""
|
||||
try:
|
||||
from prompt_toolkit.styles import Style
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
accent_hex = _ANSI_256_TO_HEX.get(self.accent, "#5fafff")
|
||||
|
||||
return Style.from_dict({
|
||||
"icon": "#5fdfdf bold", # cyan brand color
|
||||
"software": f"{accent_hex} bold",
|
||||
"bracket": "#585858",
|
||||
"context": "#bcbcbc",
|
||||
"arrow": "#808080",
|
||||
# Completion menu
|
||||
"completion-menu.completion": "bg:#303030 #bcbcbc",
|
||||
"completion-menu.completion.current": f"bg:{accent_hex} #000000",
|
||||
"completion-menu.meta.completion": "bg:#303030 #808080",
|
||||
"completion-menu.meta.completion.current": f"bg:{accent_hex} #000000",
|
||||
# Auto-suggest
|
||||
"auto-suggest": "#585858",
|
||||
# Bottom toolbar
|
||||
"bottom-toolbar": "bg:#1c1c1c #808080",
|
||||
"bottom-toolbar.text": "#808080",
|
||||
})
|
||||
|
||||
# ── Messages ──────────────────────────────────────────────────────
|
||||
|
||||
def success(self, message: str):
|
||||
"""Print a success message with green checkmark."""
|
||||
icon = self._c(_GREEN + _BOLD, "✓")
|
||||
print(f" {icon} {self._c(_GREEN, message)}")
|
||||
|
||||
def error(self, message: str):
|
||||
"""Print an error message with red cross."""
|
||||
icon = self._c(_RED + _BOLD, "✗")
|
||||
print(f" {icon} {self._c(_RED, message)}", file=sys.stderr)
|
||||
|
||||
def warning(self, message: str):
|
||||
"""Print a warning message with yellow triangle."""
|
||||
icon = self._c(_YELLOW + _BOLD, "⚠")
|
||||
print(f" {icon} {self._c(_YELLOW, message)}")
|
||||
|
||||
def info(self, message: str):
|
||||
"""Print an info message with blue dot."""
|
||||
icon = self._c(_BLUE, "●")
|
||||
print(f" {icon} {self._c(_LIGHT_GRAY, message)}")
|
||||
|
||||
def hint(self, message: str):
|
||||
"""Print a subtle hint message."""
|
||||
print(f" {self._c(_DARK_GRAY, message)}")
|
||||
|
||||
def section(self, title: str):
|
||||
"""Print a section header."""
|
||||
print()
|
||||
print(f" {self._c(self.accent + _BOLD, title)}")
|
||||
print(f" {self._c(_DARK_GRAY, _H_LINE * len(title))}")
|
||||
|
||||
# ── Status display ────────────────────────────────────────────────
|
||||
|
||||
def status(self, label: str, value: str):
|
||||
"""Print a key-value status line."""
|
||||
lbl = self._c(_GRAY, f" {label}:")
|
||||
val = self._c(_WHITE, f" {value}")
|
||||
print(f"{lbl}{val}")
|
||||
|
||||
def status_block(self, items: dict[str, str], title: str = ""):
|
||||
"""Print a block of status key-value pairs.
|
||||
|
||||
Args:
|
||||
items: Dict of label -> value pairs.
|
||||
title: Optional title for the block.
|
||||
"""
|
||||
if title:
|
||||
self.section(title)
|
||||
|
||||
max_key = max(len(k) for k in items) if items else 0
|
||||
for label, value in items.items():
|
||||
lbl = self._c(_GRAY, f" {label:<{max_key}}")
|
||||
val = self._c(_WHITE, f" {value}")
|
||||
print(f"{lbl}{val}")
|
||||
|
||||
def progress(self, current: int, total: int, label: str = ""):
|
||||
"""Print a simple progress indicator.
|
||||
|
||||
Args:
|
||||
current: Current step number.
|
||||
total: Total number of steps.
|
||||
label: Optional label for the progress.
|
||||
"""
|
||||
pct = int(current / total * 100) if total > 0 else 0
|
||||
bar_width = 20
|
||||
filled = int(bar_width * current / total) if total > 0 else 0
|
||||
bar = "█" * filled + "░" * (bar_width - filled)
|
||||
text = f" {self._c(_CYAN, bar)} {self._c(_GRAY, f'{pct:3d}%')}"
|
||||
if label:
|
||||
text += f" {self._c(_LIGHT_GRAY, label)}"
|
||||
print(text)
|
||||
|
||||
# ── Table display ─────────────────────────────────────────────────
|
||||
|
||||
def table(self, headers: list[str], rows: list[list[str]],
|
||||
max_col_width: int = 40):
|
||||
"""Print a formatted table with box-drawing characters.
|
||||
|
||||
Args:
|
||||
headers: Column header strings.
|
||||
rows: List of rows, each a list of cell strings.
|
||||
max_col_width: Maximum column width before truncation.
|
||||
"""
|
||||
if not headers:
|
||||
return
|
||||
|
||||
# Calculate column widths
|
||||
col_widths = [min(len(h), max_col_width) for h in headers]
|
||||
for row in rows:
|
||||
for i, cell in enumerate(row):
|
||||
if i < len(col_widths):
|
||||
col_widths[i] = min(
|
||||
max(col_widths[i], len(str(cell))), max_col_width
|
||||
)
|
||||
|
||||
def pad(text: str, width: int) -> str:
|
||||
t = str(text)[:width]
|
||||
return t + " " * (width - len(t))
|
||||
|
||||
# Header
|
||||
header_cells = [
|
||||
self._c(_CYAN + _BOLD, pad(h, col_widths[i]))
|
||||
for i, h in enumerate(headers)
|
||||
]
|
||||
sep = self._c(_DARK_GRAY, f" {_V_LINE} ")
|
||||
header_line = f" {sep.join(header_cells)}"
|
||||
print(header_line)
|
||||
|
||||
# Separator
|
||||
sep_parts = [self._c(_DARK_GRAY, _H_LINE * w) for w in col_widths]
|
||||
sep_line = self._c(_DARK_GRAY, f" {'───'.join([_H_LINE * w for w in col_widths])}")
|
||||
print(sep_line)
|
||||
|
||||
# Rows
|
||||
for row in rows:
|
||||
cells = []
|
||||
for i, cell in enumerate(row):
|
||||
if i < len(col_widths):
|
||||
cells.append(self._c(_LIGHT_GRAY, pad(str(cell), col_widths[i])))
|
||||
row_sep = self._c(_DARK_GRAY, f" {_V_LINE} ")
|
||||
print(f" {row_sep.join(cells)}")
|
||||
|
||||
# ── Help display ──────────────────────────────────────────────────
|
||||
|
||||
def help(self, commands: dict[str, str]):
|
||||
"""Print a formatted help listing.
|
||||
|
||||
Args:
|
||||
commands: Dict of command -> description pairs.
|
||||
"""
|
||||
self.section("Commands")
|
||||
max_cmd = max(len(c) for c in commands) if commands else 0
|
||||
for cmd, desc in commands.items():
|
||||
cmd_styled = self._c(self.accent, f" {cmd:<{max_cmd}}")
|
||||
desc_styled = self._c(_GRAY, f" {desc}")
|
||||
print(f"{cmd_styled}{desc_styled}")
|
||||
print()
|
||||
|
||||
# ── Goodbye ───────────────────────────────────────────────────────
|
||||
|
||||
def print_goodbye(self):
|
||||
"""Print a styled goodbye message."""
|
||||
print(f"\n {_ICON_SMALL} {self._c(_GRAY, 'Goodbye!')}\n")
|
||||
|
||||
# ── Prompt toolkit session factory ────────────────────────────────
|
||||
|
||||
def create_prompt_session(self):
|
||||
"""Create a prompt_toolkit PromptSession with skin styling.
|
||||
|
||||
Returns:
|
||||
A configured PromptSession, or None if prompt_toolkit unavailable.
|
||||
"""
|
||||
try:
|
||||
from prompt_toolkit import PromptSession
|
||||
from prompt_toolkit.history import FileHistory
|
||||
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
||||
from prompt_toolkit.formatted_text import FormattedText
|
||||
|
||||
style = self.get_prompt_style()
|
||||
|
||||
session = PromptSession(
|
||||
history=FileHistory(self.history_file),
|
||||
auto_suggest=AutoSuggestFromHistory(),
|
||||
style=style,
|
||||
enable_history_search=True,
|
||||
)
|
||||
return session
|
||||
except ImportError:
|
||||
return None
|
||||
|
||||
def get_input(self, pt_session, project_name: str = "",
|
||||
modified: bool = False, context: str = "") -> str:
|
||||
"""Get input from user using prompt_toolkit or fallback.
|
||||
|
||||
Args:
|
||||
pt_session: A prompt_toolkit PromptSession (or None).
|
||||
project_name: Current project name.
|
||||
modified: Whether project has unsaved changes.
|
||||
context: Optional context string.
|
||||
|
||||
Returns:
|
||||
User input string (stripped).
|
||||
"""
|
||||
if pt_session is not None:
|
||||
from prompt_toolkit.formatted_text import FormattedText
|
||||
tokens = self.prompt_tokens(project_name, modified, context)
|
||||
return pt_session.prompt(FormattedText(tokens)).strip()
|
||||
else:
|
||||
raw_prompt = self.prompt(project_name, modified, context)
|
||||
return input(raw_prompt).strip()
|
||||
|
||||
# ── Toolbar builder ───────────────────────────────────────────────
|
||||
|
||||
def bottom_toolbar(self, items: dict[str, str]):
|
||||
"""Create a bottom toolbar callback for prompt_toolkit.
|
||||
|
||||
Args:
|
||||
items: Dict of label -> value pairs to show in toolbar.
|
||||
|
||||
Returns:
|
||||
A callable that returns FormattedText for the toolbar.
|
||||
"""
|
||||
def toolbar():
|
||||
from prompt_toolkit.formatted_text import FormattedText
|
||||
parts = []
|
||||
for i, (k, v) in enumerate(items.items()):
|
||||
if i > 0:
|
||||
parts.append(("class:bottom-toolbar.text", " │ "))
|
||||
parts.append(("class:bottom-toolbar.text", f" {k}: "))
|
||||
parts.append(("class:bottom-toolbar", v))
|
||||
return FormattedText(parts)
|
||||
return toolbar
|
||||
|
||||
|
||||
# ── ANSI 256-color to hex mapping (for prompt_toolkit styles) ─────────
|
||||
|
||||
_ANSI_256_TO_HEX = {
|
||||
"\033[38;5;33m": "#0087ff", # audacity navy blue
|
||||
"\033[38;5;35m": "#00af5f", # shotcut teal
|
||||
"\033[38;5;39m": "#00afff", # inkscape bright blue
|
||||
"\033[38;5;40m": "#00d700", # libreoffice green
|
||||
"\033[38;5;55m": "#5f00af", # obs purple
|
||||
"\033[38;5;69m": "#5f87ff", # kdenlive slate blue
|
||||
"\033[38;5;75m": "#5fafff", # default sky blue
|
||||
"\033[38;5;80m": "#5fd7d7", # brand cyan
|
||||
"\033[38;5;208m": "#ff8700", # blender deep orange
|
||||
"\033[38;5;214m": "#ffaf00", # gimp warm orange
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import os
|
||||
from setuptools import setup, find_namespace_packages
|
||||
|
||||
_here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
with open(os.path.join(_here, "cli_anything/mailchimp/README.md"), encoding="utf-8") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setup(
|
||||
name="cli-anything-mailchimp",
|
||||
version="0.1.0",
|
||||
description="cli-anything harness for the Mailchimp Marketing API v3.0",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
author="cli-anything contributors",
|
||||
license="Apache-2.0",
|
||||
python_requires=">=3.10",
|
||||
packages=find_namespace_packages(include=["cli_anything.*"]),
|
||||
package_data={"cli_anything.mailchimp": ["skills/SKILL.md", "README.md"]},
|
||||
install_requires=[
|
||||
"click>=8.0",
|
||||
"requests>=2.28",
|
||||
"prompt-toolkit>=3.0",
|
||||
],
|
||||
extras_require={
|
||||
"dev": ["pytest>=7.0", "pytest-cov", "responses>=0.23"],
|
||||
},
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"cli-anything-mailchimp=cli_anything.mailchimp.mailchimp_cli:main",
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Operating System :: OS Independent",
|
||||
],
|
||||
)
|
||||
@@ -1086,6 +1086,25 @@
|
||||
"url": "https://github.com/collectivewinca"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mailchimp",
|
||||
"display_name": "Mailchimp",
|
||||
"version": "0.1.0",
|
||||
"description": "Mailchimp Marketing API v3.0 — manage audiences, campaigns, reports, automations, ecommerce, templates, and more from an agent-native CLI",
|
||||
"requires": "MAILCHIMP_API_KEY",
|
||||
"homepage": "https://mailchimp.com/developer/marketing/",
|
||||
"source_url": null,
|
||||
"install_cmd": "pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=mailchimp/agent-harness",
|
||||
"entry_point": "cli-anything-mailchimp",
|
||||
"skill_md": "skills/cli-anything-mailchimp/SKILL.md",
|
||||
"category": "web",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "iGodly",
|
||||
"url": "https://github.com/iGodly"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
---
|
||||
name: cli-anything-mailchimp
|
||||
description: CLI harness for the Mailchimp Marketing API v3.0 — 303 commands across 30 resource groups (lists, campaigns, reports, automations, ecommerce, templates, and more). Supports JSON output and interactive REPL mode.
|
||||
---
|
||||
|
||||
# cli-anything-mailchimp
|
||||
|
||||
## Identity
|
||||
|
||||
An agent-native CLI for the [Mailchimp Marketing API v3.0](https://mailchimp.com/developer/marketing/docs/fundamentals/), built on the [CLI-Anything](https://github.com/HKUDS/CLI-Anything) framework.
|
||||
|
||||
## What This CLI Does
|
||||
|
||||
- Manage **audiences (lists)** — create, update, delete lists; add/update/archive members; manage merge fields, segments, tags, and webhooks.
|
||||
- Run **campaigns** — create, schedule, send, pause, replicate, and analyse email campaigns.
|
||||
- Read **reports** — open rates, click rates, bounce stats, unsubscribes, email activity, geographic data.
|
||||
- Control **automations** — create and manage automated email workflows.
|
||||
- Manage **e-commerce** — stores, orders, customers, products, carts, and promo codes.
|
||||
- Use **templates, file manager, landing pages, SMS campaigns, surveys**, and all other Marketing API resources.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10+
|
||||
- `MAILCHIMP_API_KEY` environment variable set to your API key (including datacenter suffix, e.g. `abc123-us8`)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# From the CLI-Anything repo (once merged):
|
||||
pip install git+https://github.com/HKUDS/CLI-Anything.git#subdirectory=mailchimp/agent-harness
|
||||
|
||||
# During development:
|
||||
cd mailchimp/agent-harness && pip install -e .
|
||||
```
|
||||
|
||||
## Command Reference
|
||||
|
||||
### Root
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `cli-anything-mailchimp ping` | Health check — confirms API connectivity |
|
||||
| `cli-anything-mailchimp root list` | Get account info |
|
||||
| `cli-anything-mailchimp --json <cmd>` | Output any command as JSON |
|
||||
| `cli-anything-mailchimp` | Launch interactive REPL |
|
||||
|
||||
### Lists (Audiences)
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `lists list` | List all audiences |
|
||||
| `lists get <LIST_ID>` | Get audience info |
|
||||
| `lists create --data '<json>'` | Create audience |
|
||||
| `lists update <LIST_ID> --data '<json>'` | Update audience |
|
||||
| `lists delete <LIST_ID>` | Delete audience |
|
||||
| `lists list-lists-id-members <LIST_ID>` | List members |
|
||||
| `lists get-lists-id-members-id <LIST_ID> <SUBSCRIBER_HASH>` | Get member by MD5 hash |
|
||||
| `lists create-lists-id-members <LIST_ID> --data '<json>'` | Add member |
|
||||
| `lists list-lists-id-merge-fields <LIST_ID>` | List merge fields |
|
||||
| `lists create-lists-id-merge-fields <LIST_ID> --data '<json>'` | Add merge field |
|
||||
| `lists list-lists-id-segments <LIST_ID>` | List segments |
|
||||
| `lists list-list-member-tags <LIST_ID> <SUBSCRIBER_HASH>` | List member tags |
|
||||
| `lists create-list-member-tags <LIST_ID> <SUBSCRIBER_HASH> --data '<json>'` | Add/remove member tags |
|
||||
| `lists list-lists-id-webhooks <LIST_ID>` | List webhooks |
|
||||
| `lists create-lists-id-webhooks <LIST_ID> --data '<json>'` | Add webhook |
|
||||
|
||||
### Campaigns
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `campaigns list` | List campaigns |
|
||||
| `campaigns get <CAMPAIGN_ID>` | Get campaign info |
|
||||
| `campaigns create --data '<json>'` | Create campaign |
|
||||
| `campaigns update <CAMPAIGN_ID> --data '<json>'` | Update campaign settings |
|
||||
| `campaigns delete <CAMPAIGN_ID>` | Delete campaign |
|
||||
| `campaigns send <CAMPAIGN_ID>` | Send campaign immediately |
|
||||
| `campaigns schedule <CAMPAIGN_ID> --data '<json>'` | Schedule campaign |
|
||||
| `campaigns cancel-send <CAMPAIGN_ID>` | Cancel scheduled send |
|
||||
| `campaigns pause <CAMPAIGN_ID>` | Pause RSS campaign |
|
||||
| `campaigns resume <CAMPAIGN_ID>` | Resume RSS campaign |
|
||||
| `campaigns replicate <CAMPAIGN_ID>` | Duplicate campaign |
|
||||
| `campaigns list-content <CAMPAIGN_ID>` | Get campaign content |
|
||||
| `campaigns list-send-checklist <CAMPAIGN_ID>` | Pre-send checklist |
|
||||
|
||||
### Reports
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `reports list` | List all campaign reports |
|
||||
| `reports get <CAMPAIGN_ID>` | Get campaign summary report |
|
||||
| `reports list-email-activity <CAMPAIGN_ID>` | Per-subscriber open/click activity |
|
||||
| `reports list-click-details <CAMPAIGN_ID>` | Link click breakdown |
|
||||
| `reports list-open-details <CAMPAIGN_ID>` | Per-subscriber opens |
|
||||
| `reports list-unsubscribed <CAMPAIGN_ID>` | Unsubscribers |
|
||||
| `reports list-locations <CAMPAIGN_ID>` | Geographic breakdown |
|
||||
| `reports list-domain-performance <CAMPAIGN_ID>` | Per-domain stats |
|
||||
|
||||
### Automations
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `automations list` | List automations |
|
||||
| `automations get <WORKFLOW_ID>` | Get automation info |
|
||||
| `automations create --data '<json>'` | Create automation |
|
||||
| `automations pause <WORKFLOW_ID>` | Pause automation |
|
||||
| `automations start <WORKFLOW_ID>` | Start automation |
|
||||
| `automations archive <WORKFLOW_ID>` | Archive automation |
|
||||
| `automations list-emails <WORKFLOW_ID>` | List automation emails |
|
||||
|
||||
### E-commerce
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `ecommerce list-ecommerce-stores` | List stores |
|
||||
| `ecommerce get <STORE_ID>` | Get store info |
|
||||
| `ecommerce create --data '<json>'` | Add store |
|
||||
| `ecommerce list-ecommerce-stores-id-orders <STORE_ID>` | List orders |
|
||||
| `ecommerce list-ecommerce-stores-id-products <STORE_ID>` | List products |
|
||||
| `ecommerce list-ecommerce-stores-id-customers <STORE_ID>` | List customers |
|
||||
| `ecommerce list-ecommerce-stores-id-carts <STORE_ID>` | List carts |
|
||||
| `ecommerce list-ecommerce-stores-id-promocodes <PROMO_RULE_ID> <STORE_ID>` | List promo codes |
|
||||
|
||||
### Other Resources
|
||||
|
||||
| Group | Description |
|
||||
|---|---|
|
||||
| `templates` | Email templates (list, get, create, update, delete) |
|
||||
| `template-folders` | Template folders |
|
||||
| `campaign-folders` | Campaign folders |
|
||||
| `file-manager` | Files and folders in the file manager |
|
||||
| `landing-pages` | Landing pages (list, create, publish, unpublish) |
|
||||
| `sms-campaigns` | SMS campaigns (10 operations) |
|
||||
| `surveys` | Surveys (list, get, publish) |
|
||||
| `reporting` | Facebook ad and landing page reporting |
|
||||
| `search-campaigns` | Search campaigns by query |
|
||||
| `search-members` | Search members across all audiences |
|
||||
| `batches` | Batch API operations |
|
||||
| `batch-webhooks` | Batch operation webhooks |
|
||||
| `verified-domains` | Email domain verification |
|
||||
| `authorized-apps` | OAuth connected apps |
|
||||
| `connected-sites` | Connected site integrations |
|
||||
| `conversations` | Inbox conversations |
|
||||
| `activity-feed` | Account activity feed |
|
||||
| `account-exports` | Account data exports |
|
||||
|
||||
## JSON Output
|
||||
|
||||
All commands support `--json` at the root level:
|
||||
|
||||
```bash
|
||||
# List all audiences as JSON
|
||||
cli-anything-mailchimp --json lists list
|
||||
|
||||
# Get a campaign report as JSON
|
||||
cli-anything-mailchimp --json reports get abc123def
|
||||
|
||||
# Pipe to jq — use the native Mailchimp field name for the resource
|
||||
cli-anything-mailchimp --json lists list | jq '.lists[].name'
|
||||
cli-anything-mailchimp --json campaigns list | jq '.campaigns[].id'
|
||||
```
|
||||
|
||||
**Envelope shapes** (native Mailchimp API response — use the resource-specific key):
|
||||
|
||||
```json
|
||||
// List endpoints — key matches the resource name (lists, campaigns, members, etc.)
|
||||
{"lists": [...], "total_items": 42, "_links": [...]}
|
||||
{"campaigns": [...], "total_items": 10, "_links": [...]}
|
||||
|
||||
// Single resource GET / POST / PATCH
|
||||
{"id": "abc123", "name": "My List", ...}
|
||||
|
||||
// DELETE
|
||||
{"ok": true, "message": "Deleted."}
|
||||
|
||||
// Error
|
||||
{"ok": false, "message": "Resource Not Found: ...", "data": {...}}
|
||||
```
|
||||
|
||||
## Common Agent Patterns
|
||||
|
||||
```bash
|
||||
# Get account health
|
||||
cli-anything-mailchimp --json ping | jq '.health_status'
|
||||
|
||||
# List all audience IDs and names
|
||||
cli-anything-mailchimp --json lists list | jq '.lists[] | {id, name}'
|
||||
|
||||
# Find all subscribed members in an audience
|
||||
cli-anything-mailchimp --json lists list-lists-id-members <list_id> --status subscribed | jq '.members[].email_address'
|
||||
|
||||
# Create a campaign and get its send checklist
|
||||
cli-anything-mailchimp --json campaigns create --data '{"type":"regular","settings":{"subject_line":"Hello","from_name":"Me","reply_to":"me@example.com"}}' | jq '.id'
|
||||
cli-anything-mailchimp --json campaigns list-send-checklist <campaign_id> | jq '.items[] | select(.result == false)'
|
||||
|
||||
# Get unsubscribes for a sent campaign
|
||||
cli-anything-mailchimp --json reports list-unsubscribed <campaign_id> | jq '.unsubscribes[].email_address'
|
||||
|
||||
# Add a member to an audience (subscriber hash = MD5 of lowercased email)
|
||||
cli-anything-mailchimp --json lists create-members <list_id> --data '{"email_address":"user@example.com","status":"subscribed"}'
|
||||
|
||||
# Search for a member across all audiences
|
||||
cli-anything-mailchimp --json search-members list --query "user@example.com" | jq '.exact_matches.members[]'
|
||||
```
|
||||
|
||||
## Interactive REPL
|
||||
|
||||
Run `cli-anything-mailchimp` with no arguments to enter the REPL:
|
||||
|
||||
```
|
||||
◆ cli-anything · Mailchimp
|
||||
v0.1.0
|
||||
Type help for commands, quit to exit
|
||||
|
||||
◆ mailchimp ❯ ping
|
||||
✓ {"health_status": "Everything's Chimpy!"}
|
||||
|
||||
◆ mailchimp ❯ --json lists list
|
||||
{"lists": [...], "total_items": 3, "_links": [...]}
|
||||
|
||||
◆ mailchimp ❯ quit
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- **Subscriber hash**: Mailchimp identifies members by the MD5 hash of their lowercased email. Compute with `python -c "import hashlib; email='email@example.com'; print(hashlib.md5(email.strip().lower().encode()).hexdigest())"`.
|
||||
- **Body payloads**: All POST/PATCH/PUT commands accept `--data '<json>'`. See [Mailchimp API docs](https://mailchimp.com/developer/marketing/api/) for the schema of each endpoint.
|
||||
- **Datacenter**: Your API key ends in `-us8`, `-eu2`, etc. The CLI extracts this automatically — include it in `MAILCHIMP_API_KEY`.
|
||||
- **Rate limits**: The Marketing API rate-limits at 10 concurrent connections and a rolling per-account limit. For bulk operations, use the `batches` group.
|
||||
Reference in New Issue
Block a user