direct-cli 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- direct_cli/__init__.py +14 -0
- direct_cli/api.py +94 -0
- direct_cli/auth.py +58 -0
- direct_cli/cli.py +85 -0
- direct_cli/commands/__init__.py +61 -0
- direct_cli/commands/adextensions.py +96 -0
- direct_cli/commands/adgroups.py +189 -0
- direct_cli/commands/adimages.py +63 -0
- direct_cli/commands/ads.py +306 -0
- direct_cli/commands/agencyclients.py +64 -0
- direct_cli/commands/audiencetargets.py +187 -0
- direct_cli/commands/bidmodifiers.py +110 -0
- direct_cli/commands/bids.py +108 -0
- direct_cli/commands/businesses.py +61 -0
- direct_cli/commands/campaigns.py +311 -0
- direct_cli/commands/changes.py +97 -0
- direct_cli/commands/clients.py +98 -0
- direct_cli/commands/creatives.py +68 -0
- direct_cli/commands/dictionaries.py +64 -0
- direct_cli/commands/dynamicads.py +104 -0
- direct_cli/commands/feeds.py +99 -0
- direct_cli/commands/keywordbids.py +111 -0
- direct_cli/commands/keywords.py +309 -0
- direct_cli/commands/keywordsresearch.py +71 -0
- direct_cli/commands/leads.py +65 -0
- direct_cli/commands/negativekeywordsharedsets.py +97 -0
- direct_cli/commands/reports.py +128 -0
- direct_cli/commands/retargeting.py +104 -0
- direct_cli/commands/sitelinks.py +92 -0
- direct_cli/commands/smartadtargets.py +104 -0
- direct_cli/commands/turbopages.py +97 -0
- direct_cli/commands/vcards.py +93 -0
- direct_cli/output.py +143 -0
- direct_cli/utils.py +120 -0
- direct_cli-0.0.0.dist-info/METADATA +393 -0
- direct_cli-0.0.0.dist-info/RECORD +39 -0
- direct_cli-0.0.0.dist-info/WHEEL +5 -0
- direct_cli-0.0.0.dist-info/entry_points.txt +2 -0
- direct_cli-0.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RetargetingLists commands
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from ..api import create_client
|
|
9
|
+
from ..output import format_output, print_error
|
|
10
|
+
from ..utils import parse_ids, get_default_fields
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def retargeting():
|
|
15
|
+
"""Manage retargeting lists"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@retargeting.command()
|
|
20
|
+
@click.option("--ids", help="Comma-separated list IDs")
|
|
21
|
+
@click.option("--types", help="Filter by types")
|
|
22
|
+
@click.option("--limit", type=int, help="Limit number of results")
|
|
23
|
+
@click.option("--fetch-all", is_flag=True, help="Fetch all pages")
|
|
24
|
+
@click.option("--format", "output_format", default="json", help="Output format")
|
|
25
|
+
@click.option("--output", help="Output file")
|
|
26
|
+
@click.option("--fields", help="Comma-separated field names")
|
|
27
|
+
@click.pass_context
|
|
28
|
+
def get(ctx, ids, types, limit, fetch_all, output_format, output, fields):
|
|
29
|
+
"""Get retargeting lists"""
|
|
30
|
+
try:
|
|
31
|
+
client = create_client(
|
|
32
|
+
token=ctx.obj.get("token"),
|
|
33
|
+
login=ctx.obj.get("login"),
|
|
34
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
field_names = (
|
|
38
|
+
fields.split(",") if fields else get_default_fields("retargetinglists")
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
criteria = {}
|
|
42
|
+
if ids:
|
|
43
|
+
criteria["Ids"] = parse_ids(ids)
|
|
44
|
+
if types:
|
|
45
|
+
criteria["Types"] = types.split(",")
|
|
46
|
+
|
|
47
|
+
params = {"SelectionCriteria": criteria, "FieldNames": field_names}
|
|
48
|
+
|
|
49
|
+
if limit:
|
|
50
|
+
params["Page"] = {"Limit": limit}
|
|
51
|
+
|
|
52
|
+
body = {"method": "get", "params": params}
|
|
53
|
+
|
|
54
|
+
result = client.retargeting().post(data=body)
|
|
55
|
+
|
|
56
|
+
if fetch_all:
|
|
57
|
+
items = []
|
|
58
|
+
for item in result().iter_items():
|
|
59
|
+
items.append(item)
|
|
60
|
+
format_output(items, output_format, output)
|
|
61
|
+
else:
|
|
62
|
+
data = result().extract()
|
|
63
|
+
format_output(data, output_format, output)
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
print_error(str(e))
|
|
67
|
+
raise click.Abort()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@retargeting.command()
|
|
71
|
+
@click.option("--name", required=True, help="List name")
|
|
72
|
+
@click.option(
|
|
73
|
+
"--type", "list_type", required=True, help="List type (AUDIENCE_SEGMENT, etc.)"
|
|
74
|
+
)
|
|
75
|
+
@click.option("--json", "extra_json", help="Additional JSON parameters")
|
|
76
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
77
|
+
@click.pass_context
|
|
78
|
+
def add(ctx, name, list_type, extra_json, dry_run):
|
|
79
|
+
"""Add new retargeting list"""
|
|
80
|
+
try:
|
|
81
|
+
list_data = {"Name": name, "Type": list_type}
|
|
82
|
+
|
|
83
|
+
if extra_json:
|
|
84
|
+
extra = json.loads(extra_json)
|
|
85
|
+
list_data.update(extra)
|
|
86
|
+
|
|
87
|
+
body = {"method": "add", "params": {"RetargetingLists": [list_data]}}
|
|
88
|
+
|
|
89
|
+
if dry_run:
|
|
90
|
+
format_output(body, "json", None)
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
client = create_client(
|
|
94
|
+
token=ctx.obj.get("token"),
|
|
95
|
+
login=ctx.obj.get("login"),
|
|
96
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
result = client.retargeting().post(data=body)
|
|
100
|
+
format_output(result().extract(), "json", None)
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print_error(str(e))
|
|
104
|
+
raise click.Abort()
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Sitelinks commands
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from ..api import create_client
|
|
9
|
+
from ..output import format_output, print_error
|
|
10
|
+
from ..utils import parse_ids
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def sitelinks():
|
|
15
|
+
"""Manage sitelinks"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@sitelinks.command()
|
|
20
|
+
@click.option("--ids", help="Comma-separated sitelink IDs")
|
|
21
|
+
@click.option("--limit", type=int, help="Limit number of results")
|
|
22
|
+
@click.option("--fetch-all", is_flag=True, help="Fetch all pages")
|
|
23
|
+
@click.option("--format", "output_format", default="json", help="Output format")
|
|
24
|
+
@click.option("--output", help="Output file")
|
|
25
|
+
@click.option("--fields", help="Comma-separated field names")
|
|
26
|
+
@click.pass_context
|
|
27
|
+
def get(ctx, ids, limit, fetch_all, output_format, output, fields):
|
|
28
|
+
"""Get sitelinks"""
|
|
29
|
+
try:
|
|
30
|
+
client = create_client(
|
|
31
|
+
token=ctx.obj.get("token"),
|
|
32
|
+
login=ctx.obj.get("login"),
|
|
33
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
field_names = fields.split(",") if fields else ["Id", "Sitelinks"]
|
|
37
|
+
|
|
38
|
+
criteria = {}
|
|
39
|
+
if ids:
|
|
40
|
+
criteria["Ids"] = parse_ids(ids)
|
|
41
|
+
|
|
42
|
+
params = {"SelectionCriteria": criteria, "FieldNames": field_names}
|
|
43
|
+
|
|
44
|
+
if limit:
|
|
45
|
+
params["Page"] = {"Limit": limit}
|
|
46
|
+
|
|
47
|
+
body = {"method": "get", "params": params}
|
|
48
|
+
|
|
49
|
+
result = client.sitelinks().post(data=body)
|
|
50
|
+
|
|
51
|
+
if fetch_all:
|
|
52
|
+
items = []
|
|
53
|
+
for item in result().iter_items():
|
|
54
|
+
items.append(item)
|
|
55
|
+
format_output(items, output_format, output)
|
|
56
|
+
else:
|
|
57
|
+
data = result().extract()
|
|
58
|
+
format_output(data, output_format, output)
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
print_error(str(e))
|
|
62
|
+
raise click.Abort()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@sitelinks.command()
|
|
66
|
+
@click.option("--links", required=True, help="JSON array of sitelinks")
|
|
67
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
68
|
+
@click.pass_context
|
|
69
|
+
def add(ctx, links, dry_run):
|
|
70
|
+
"""Add sitelinks set"""
|
|
71
|
+
try:
|
|
72
|
+
body = {
|
|
73
|
+
"method": "add",
|
|
74
|
+
"params": {"SitelinksSets": [{"Sitelinks": json.loads(links)}]},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if dry_run:
|
|
78
|
+
format_output(body, "json", None)
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
client = create_client(
|
|
82
|
+
token=ctx.obj.get("token"),
|
|
83
|
+
login=ctx.obj.get("login"),
|
|
84
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
result = client.sitelinks().post(data=body)
|
|
88
|
+
format_output(result().extract(), "json", None)
|
|
89
|
+
|
|
90
|
+
except Exception as e:
|
|
91
|
+
print_error(str(e))
|
|
92
|
+
raise click.Abort()
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SmartAdTargets commands
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from ..api import create_client
|
|
9
|
+
from ..output import format_output, print_error
|
|
10
|
+
from ..utils import parse_ids
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def smartadtargets():
|
|
15
|
+
"""Manage smart ad targets"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@smartadtargets.command()
|
|
20
|
+
@click.option("--ids", help="Comma-separated target IDs")
|
|
21
|
+
@click.option("--adgroup-ids", help="Comma-separated ad group IDs")
|
|
22
|
+
@click.option("--limit", type=int, help="Limit number of results")
|
|
23
|
+
@click.option("--fetch-all", is_flag=True, help="Fetch all pages")
|
|
24
|
+
@click.option("--format", "output_format", default="json", help="Output format")
|
|
25
|
+
@click.option("--output", help="Output file")
|
|
26
|
+
@click.option("--fields", help="Comma-separated field names")
|
|
27
|
+
@click.pass_context
|
|
28
|
+
def get(ctx, ids, adgroup_ids, limit, fetch_all, output_format, output, fields):
|
|
29
|
+
"""Get smart ad targets"""
|
|
30
|
+
try:
|
|
31
|
+
client = create_client(
|
|
32
|
+
token=ctx.obj.get("token"),
|
|
33
|
+
login=ctx.obj.get("login"),
|
|
34
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
field_names = (
|
|
38
|
+
fields.split(",")
|
|
39
|
+
if fields
|
|
40
|
+
else ["Id", "CampaignId", "AdGroupId", "Status", "ServingStatus"]
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
criteria = {}
|
|
44
|
+
if ids:
|
|
45
|
+
criteria["Ids"] = parse_ids(ids)
|
|
46
|
+
if adgroup_ids:
|
|
47
|
+
criteria["AdGroupIds"] = parse_ids(adgroup_ids)
|
|
48
|
+
|
|
49
|
+
params = {"SelectionCriteria": criteria, "FieldNames": field_names}
|
|
50
|
+
|
|
51
|
+
if limit:
|
|
52
|
+
params["Page"] = {"Limit": limit}
|
|
53
|
+
|
|
54
|
+
body = {"method": "get", "params": params}
|
|
55
|
+
|
|
56
|
+
result = client.smartadtargets().post(data=body)
|
|
57
|
+
|
|
58
|
+
if fetch_all:
|
|
59
|
+
items = []
|
|
60
|
+
for item in result().iter_items():
|
|
61
|
+
items.append(item)
|
|
62
|
+
format_output(items, output_format, output)
|
|
63
|
+
else:
|
|
64
|
+
data = result().extract()
|
|
65
|
+
format_output(data, output_format, output)
|
|
66
|
+
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print_error(str(e))
|
|
69
|
+
raise click.Abort()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@smartadtargets.command()
|
|
73
|
+
@click.option("--adgroup-id", required=True, type=int, help="Ad group ID")
|
|
74
|
+
@click.option("--type", "target_type", required=True, help="Target type")
|
|
75
|
+
@click.option("--json", "extra_json", help="Additional JSON parameters")
|
|
76
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
77
|
+
@click.pass_context
|
|
78
|
+
def add(ctx, adgroup_id, target_type, extra_json, dry_run):
|
|
79
|
+
"""Add smart ad target"""
|
|
80
|
+
try:
|
|
81
|
+
target_data = {"AdGroupId": adgroup_id, "Type": target_type}
|
|
82
|
+
|
|
83
|
+
if extra_json:
|
|
84
|
+
extra = json.loads(extra_json)
|
|
85
|
+
target_data.update(extra)
|
|
86
|
+
|
|
87
|
+
body = {"method": "add", "params": {"SmartAdTargets": [target_data]}}
|
|
88
|
+
|
|
89
|
+
if dry_run:
|
|
90
|
+
format_output(body, "json", None)
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
client = create_client(
|
|
94
|
+
token=ctx.obj.get("token"),
|
|
95
|
+
login=ctx.obj.get("login"),
|
|
96
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
result = client.smartadtargets().post(data=body)
|
|
100
|
+
format_output(result().extract(), "json", None)
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print_error(str(e))
|
|
104
|
+
raise click.Abort()
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TurboPages commands
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from ..api import create_client
|
|
9
|
+
from ..output import format_output, print_error
|
|
10
|
+
from ..utils import parse_ids
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def turbopages():
|
|
15
|
+
"""Manage Turbo Pages"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@turbopages.command()
|
|
20
|
+
@click.option("--ids", help="Comma-separated Turbo Page IDs")
|
|
21
|
+
@click.option("--limit", type=int, help="Limit number of results")
|
|
22
|
+
@click.option("--fetch-all", is_flag=True, help="Fetch all pages")
|
|
23
|
+
@click.option("--format", "output_format", default="json", help="Output format")
|
|
24
|
+
@click.option("--output", help="Output file")
|
|
25
|
+
@click.option("--fields", help="Comma-separated field names")
|
|
26
|
+
@click.pass_context
|
|
27
|
+
def get(ctx, ids, limit, fetch_all, output_format, output, fields):
|
|
28
|
+
"""Get Turbo Pages"""
|
|
29
|
+
try:
|
|
30
|
+
client = create_client(
|
|
31
|
+
token=ctx.obj.get("token"),
|
|
32
|
+
login=ctx.obj.get("login"),
|
|
33
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
field_names = fields.split(",") if fields else ["Id", "Name", "Status", "Href"]
|
|
37
|
+
|
|
38
|
+
criteria = {}
|
|
39
|
+
if ids:
|
|
40
|
+
criteria["Ids"] = parse_ids(ids)
|
|
41
|
+
|
|
42
|
+
params = {"SelectionCriteria": criteria, "FieldNames": field_names}
|
|
43
|
+
|
|
44
|
+
if limit:
|
|
45
|
+
params["Page"] = {"Limit": limit}
|
|
46
|
+
|
|
47
|
+
body = {"method": "get", "params": params}
|
|
48
|
+
|
|
49
|
+
result = client.turbopages().post(data=body)
|
|
50
|
+
|
|
51
|
+
if fetch_all:
|
|
52
|
+
items = []
|
|
53
|
+
for item in result().iter_items():
|
|
54
|
+
items.append(item)
|
|
55
|
+
format_output(items, output_format, output)
|
|
56
|
+
else:
|
|
57
|
+
data = result().extract()
|
|
58
|
+
format_output(data, output_format, output)
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
print_error(str(e))
|
|
62
|
+
raise click.Abort()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@turbopages.command()
|
|
66
|
+
@click.option("--name", required=True, help="Page name")
|
|
67
|
+
@click.option("--url", required=True, help="Page URL")
|
|
68
|
+
@click.option("--json", "extra_json", help="Additional JSON parameters")
|
|
69
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
70
|
+
@click.pass_context
|
|
71
|
+
def add(ctx, name, url, extra_json, dry_run):
|
|
72
|
+
"""Add Turbo Page"""
|
|
73
|
+
try:
|
|
74
|
+
page_data = {"Name": name, "Href": url}
|
|
75
|
+
|
|
76
|
+
if extra_json:
|
|
77
|
+
extra = json.loads(extra_json)
|
|
78
|
+
page_data.update(extra)
|
|
79
|
+
|
|
80
|
+
body = {"method": "add", "params": {"TurboPages": [page_data]}}
|
|
81
|
+
|
|
82
|
+
if dry_run:
|
|
83
|
+
format_output(body, "json", None)
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
client = create_client(
|
|
87
|
+
token=ctx.obj.get("token"),
|
|
88
|
+
login=ctx.obj.get("login"),
|
|
89
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
result = client.turbopages().post(data=body)
|
|
93
|
+
format_output(result().extract(), "json", None)
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
print_error(str(e))
|
|
97
|
+
raise click.Abort()
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
VCards commands
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import click
|
|
7
|
+
|
|
8
|
+
from ..api import create_client
|
|
9
|
+
from ..output import format_output, print_error
|
|
10
|
+
from ..utils import parse_ids
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@click.group()
|
|
14
|
+
def vcards():
|
|
15
|
+
"""Manage vCards"""
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@vcards.command()
|
|
20
|
+
@click.option("--ids", help="Comma-separated vCard IDs")
|
|
21
|
+
@click.option("--limit", type=int, help="Limit number of results")
|
|
22
|
+
@click.option("--fetch-all", is_flag=True, help="Fetch all pages")
|
|
23
|
+
@click.option("--format", "output_format", default="json", help="Output format")
|
|
24
|
+
@click.option("--output", help="Output file")
|
|
25
|
+
@click.option("--fields", help="Comma-separated field names")
|
|
26
|
+
@click.pass_context
|
|
27
|
+
def get(ctx, ids, limit, fetch_all, output_format, output, fields):
|
|
28
|
+
"""Get vCards"""
|
|
29
|
+
try:
|
|
30
|
+
client = create_client(
|
|
31
|
+
token=ctx.obj.get("token"),
|
|
32
|
+
login=ctx.obj.get("login"),
|
|
33
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
field_names = (
|
|
37
|
+
fields.split(",")
|
|
38
|
+
if fields
|
|
39
|
+
else ["Id", "CampaignId", "Country", "City", "CompanyName"]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
criteria = {}
|
|
43
|
+
if ids:
|
|
44
|
+
criteria["Ids"] = parse_ids(ids)
|
|
45
|
+
|
|
46
|
+
params = {"SelectionCriteria": criteria, "FieldNames": field_names}
|
|
47
|
+
|
|
48
|
+
if limit:
|
|
49
|
+
params["Page"] = {"Limit": limit}
|
|
50
|
+
|
|
51
|
+
body = {"method": "get", "params": params}
|
|
52
|
+
|
|
53
|
+
result = client.vcards().post(data=body)
|
|
54
|
+
|
|
55
|
+
if fetch_all:
|
|
56
|
+
items = []
|
|
57
|
+
for item in result().iter_items():
|
|
58
|
+
items.append(item)
|
|
59
|
+
format_output(items, output_format, output)
|
|
60
|
+
else:
|
|
61
|
+
data = result().extract()
|
|
62
|
+
format_output(data, output_format, output)
|
|
63
|
+
|
|
64
|
+
except Exception as e:
|
|
65
|
+
print_error(str(e))
|
|
66
|
+
raise click.Abort()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@vcards.command()
|
|
70
|
+
@click.option("--json", "vcard_json", required=True, help="vCard data in JSON")
|
|
71
|
+
@click.option("--dry-run", is_flag=True, help="Show request without sending")
|
|
72
|
+
@click.pass_context
|
|
73
|
+
def add(ctx, vcard_json, dry_run):
|
|
74
|
+
"""Add vCard"""
|
|
75
|
+
try:
|
|
76
|
+
body = {"method": "add", "params": {"VCards": [json.loads(vcard_json)]}}
|
|
77
|
+
|
|
78
|
+
if dry_run:
|
|
79
|
+
format_output(body, "json", None)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
client = create_client(
|
|
83
|
+
token=ctx.obj.get("token"),
|
|
84
|
+
login=ctx.obj.get("login"),
|
|
85
|
+
sandbox=ctx.obj.get("sandbox"),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
result = client.vcards().post(data=body)
|
|
89
|
+
format_output(result().extract(), "json", None)
|
|
90
|
+
|
|
91
|
+
except Exception as e:
|
|
92
|
+
print_error(str(e))
|
|
93
|
+
raise click.Abort()
|
direct_cli/output.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Output formatting module for Direct CLI
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import csv
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Any, List, Dict, Optional
|
|
9
|
+
from io import StringIO
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from tabulate import tabulate
|
|
13
|
+
except ImportError:
|
|
14
|
+
tabulate = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def format_output(
|
|
18
|
+
data: Any,
|
|
19
|
+
format_type: str = "json",
|
|
20
|
+
output_file: Optional[str] = None,
|
|
21
|
+
headers: Optional[List[str]] = None,
|
|
22
|
+
) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Format data for output
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
data: Data to format
|
|
28
|
+
format_type: Output format ('json', 'table', 'csv', 'tsv')
|
|
29
|
+
output_file: Output file path (if None, print to stdout)
|
|
30
|
+
headers: Column headers for table/csv/tsv format
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Formatted string
|
|
34
|
+
"""
|
|
35
|
+
if format_type == "json":
|
|
36
|
+
output = format_json(data)
|
|
37
|
+
elif format_type == "table":
|
|
38
|
+
output = format_table(data, headers)
|
|
39
|
+
elif format_type == "csv":
|
|
40
|
+
output = format_csv(data, headers)
|
|
41
|
+
elif format_type == "tsv":
|
|
42
|
+
output = format_tsv(data, headers)
|
|
43
|
+
else:
|
|
44
|
+
output = str(data)
|
|
45
|
+
|
|
46
|
+
if output_file:
|
|
47
|
+
with open(output_file, "w", encoding="utf-8") as f:
|
|
48
|
+
f.write(output)
|
|
49
|
+
else:
|
|
50
|
+
print(output)
|
|
51
|
+
|
|
52
|
+
return output
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def format_json(data: Any, indent: int = 2) -> str:
|
|
56
|
+
"""Format data as JSON"""
|
|
57
|
+
return json.dumps(data, ensure_ascii=False, indent=indent, default=str)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def format_table(data: Any, headers: Optional[List[str]] = None) -> str:
|
|
61
|
+
"""Format data as table"""
|
|
62
|
+
if not tabulate:
|
|
63
|
+
return format_json(data)
|
|
64
|
+
|
|
65
|
+
if isinstance(data, list) and len(data) > 0:
|
|
66
|
+
if isinstance(data[0], dict):
|
|
67
|
+
return tabulate(data, headers="keys", tablefmt="grid")
|
|
68
|
+
elif isinstance(data[0], list):
|
|
69
|
+
return tabulate(data, headers=headers or [], tablefmt="grid")
|
|
70
|
+
elif isinstance(data, dict):
|
|
71
|
+
# Convert dict to list of lists for table display
|
|
72
|
+
rows = [[k, v] for k, v in data.items()]
|
|
73
|
+
return tabulate(rows, headers=["Key", "Value"], tablefmt="grid")
|
|
74
|
+
|
|
75
|
+
return str(data)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def format_csv(data: Any, headers: Optional[List[str]] = None) -> str:
|
|
79
|
+
"""Format data as CSV"""
|
|
80
|
+
output = StringIO()
|
|
81
|
+
|
|
82
|
+
if isinstance(data, list) and len(data) > 0:
|
|
83
|
+
if isinstance(data[0], dict):
|
|
84
|
+
fieldnames = headers or list(data[0].keys())
|
|
85
|
+
writer = csv.DictWriter(output, fieldnames=fieldnames)
|
|
86
|
+
writer.writeheader()
|
|
87
|
+
writer.writerows(data)
|
|
88
|
+
elif isinstance(data[0], list):
|
|
89
|
+
writer = csv.writer(output)
|
|
90
|
+
if headers:
|
|
91
|
+
writer.writerow(headers)
|
|
92
|
+
writer.writerows(data)
|
|
93
|
+
elif isinstance(data, dict):
|
|
94
|
+
writer = csv.writer(output)
|
|
95
|
+
writer.writerow(["Key", "Value"])
|
|
96
|
+
for k, v in data.items():
|
|
97
|
+
writer.writerow([k, v])
|
|
98
|
+
|
|
99
|
+
return output.getvalue()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def format_tsv(data: Any, headers: Optional[List[str]] = None) -> str:
|
|
103
|
+
"""Format data as TSV"""
|
|
104
|
+
output = StringIO()
|
|
105
|
+
|
|
106
|
+
if isinstance(data, list) and len(data) > 0:
|
|
107
|
+
if isinstance(data[0], dict):
|
|
108
|
+
fieldnames = headers or list(data[0].keys())
|
|
109
|
+
writer = csv.DictWriter(output, fieldnames=fieldnames, delimiter="\t")
|
|
110
|
+
writer.writeheader()
|
|
111
|
+
writer.writerows(data)
|
|
112
|
+
elif isinstance(data[0], list):
|
|
113
|
+
writer = csv.writer(output, delimiter="\t")
|
|
114
|
+
if headers:
|
|
115
|
+
writer.writerow(headers)
|
|
116
|
+
writer.writerows(data)
|
|
117
|
+
elif isinstance(data, dict):
|
|
118
|
+
writer = csv.writer(output, delimiter="\t")
|
|
119
|
+
writer.writerow(["Key", "Value"])
|
|
120
|
+
for k, v in data.items():
|
|
121
|
+
writer.writerow([k, v])
|
|
122
|
+
|
|
123
|
+
return output.getvalue()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def print_success(message: str) -> None:
|
|
127
|
+
"""Print success message"""
|
|
128
|
+
print(f"\033[32m✓ {message}\033[0m")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def print_error(message: str) -> None:
|
|
132
|
+
"""Print error message"""
|
|
133
|
+
print(f"\033[31m✗ {message}\033[0m", file=sys.stderr)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def print_warning(message: str) -> None:
|
|
137
|
+
"""Print warning message"""
|
|
138
|
+
print(f"\033[33m⚠ {message}\033[0m")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def print_info(message: str) -> None:
|
|
142
|
+
"""Print info message"""
|
|
143
|
+
print(f"ℹ {message}")
|