Send
This commit is contained in:
parent
ccb3d06be5
commit
6a35ad2554
1 changed files with 70 additions and 21 deletions
91
mmcli.py
91
mmcli.py
|
@ -31,16 +31,13 @@ def yes_no(x):
|
||||||
return "yes" if x else "no"
|
return "yes" if x else "no"
|
||||||
|
|
||||||
|
|
||||||
def get_posts_for_channel(self, channel_id: str, **kwargs) -> Generator[Dict, None, None]:
|
def get_posts_for_channel(self, channel_id: str, progress=lambda x: None, **kwargs) -> Generator[Dict, None, None]:
|
||||||
"""
|
"""
|
||||||
Generator: Get a page of posts in a channel. Use the query parameters to modify the behaviour of this endpoint.
|
@raises ApiException: Passed on from lower layers.
|
||||||
|
|
||||||
@param channel_id: The channel ID to iterate over.
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
ApiException: Passed on from lower layers.
|
|
||||||
"""
|
"""
|
||||||
page = 0
|
page = 0
|
||||||
|
posts = []
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
data_page = self._get(f"/v4/channels/{channel_id}/posts", params={"page":str(page), "per_page":200, **kwargs})
|
data_page = self._get(f"/v4/channels/{channel_id}/posts", params={"page":str(page), "per_page":200, **kwargs})
|
||||||
|
|
||||||
|
@ -48,11 +45,15 @@ def get_posts_for_channel(self, channel_id: str, **kwargs) -> Generator[Dict, No
|
||||||
break
|
break
|
||||||
page += 1
|
page += 1
|
||||||
|
|
||||||
for order in data_page["order"]:
|
posts.extend(data_page["posts"][order] for order in data_page["order"])
|
||||||
yield data_page["posts"][order]
|
progress(len(posts))
|
||||||
|
|
||||||
sleep(0.1)
|
sleep(0.1)
|
||||||
|
|
||||||
|
# Mattermost gives newest first, so reverse order
|
||||||
|
posts.reverse()
|
||||||
|
|
||||||
|
return posts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ID_PREFIX = "id:"
|
ID_PREFIX = "id:"
|
||||||
|
@ -105,15 +106,17 @@ def login(mm_api, parsed):
|
||||||
f"TOTP token provided: {yes_no(parsed.totp)}",
|
f"TOTP token provided: {yes_no(parsed.totp)}",
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
mm_api.login(parsed.user, parsed.password, parsed.totp)
|
mm_api.login(parsed.user, parsed.password, parsed.totp)
|
||||||
return mm_api._bearer
|
|
||||||
|
if parsed.format == "json":
|
||||||
|
print(json.dumps({"token": mm_api._bearer}))
|
||||||
|
elif parsed.format == "tsv":
|
||||||
|
print(mm_api._bearer)
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
def cat(mm_api: mattermost.MMApi, parsed):
|
def cat(mm_api: mattermost.MMApi, parsed):
|
||||||
|
|
||||||
|
|
||||||
# FIXME Wrong order
|
|
||||||
|
|
||||||
|
|
||||||
channels = [
|
channels = [
|
||||||
resolve_team_channel(mm_api, query)
|
resolve_team_channel(mm_api, query)
|
||||||
for query in parsed.channels
|
for query in parsed.channels
|
||||||
|
@ -135,9 +138,40 @@ def cat(mm_api: mattermost.MMApi, parsed):
|
||||||
def attribute(key_value):
|
def attribute(key_value):
|
||||||
return key_value
|
return key_value
|
||||||
|
|
||||||
for post in get_posts_for_channel(mm_api, channel["id"], after=parsed.after):
|
posts = get_posts_for_channel(mm_api, channel["id"], after=parsed.after)
|
||||||
|
for post in posts:
|
||||||
print(post_str(attribute, post, parsed))
|
print(post_str(attribute, post, parsed))
|
||||||
print(parsed.after)
|
|
||||||
|
|
||||||
|
def send(mm_api: mattermost.MMApi, parsed):
|
||||||
|
read_stdin = parsed.message is None or parsed.channel is None
|
||||||
|
|
||||||
|
team, channel = resolve_team_channel(mm_api, parsed.channel) if parsed.channel is not None else (None, None)
|
||||||
|
|
||||||
|
if read_stdin:
|
||||||
|
if sys.stdin.isatty():
|
||||||
|
print("Reading from tty. (You can type the message objects below. Or maybe you meant to redirect something to stdin.)", file=sys.stderr)
|
||||||
|
|
||||||
|
for line in sys.stdin:
|
||||||
|
msg = json.loads(line)
|
||||||
|
|
||||||
|
if "channel_id" in msg:
|
||||||
|
channel_id = msg["channel_id"]
|
||||||
|
elif "channel" in msg:
|
||||||
|
_, local_channel = resolve_team_channel(mm_api, msg["channel"])
|
||||||
|
channel_id = local_channel["id"]
|
||||||
|
elif channel is not None:
|
||||||
|
channel_id = channel["id"]
|
||||||
|
else:
|
||||||
|
print(f"Illegal message, missing channel: {line.strip()}", file=sys.stderr)
|
||||||
|
raise ValueError("Illegal message, missing channel")
|
||||||
|
|
||||||
|
sent = mm_api.create_post(channel_id, msg["message"], props={"from_mmcli": "true"}, filepaths=msg.get("attachments", msg.get("attachments")))
|
||||||
|
print(sent)
|
||||||
|
|
||||||
|
else:
|
||||||
|
sent = mm_api.create_post(channel["id"], parsed.message, props={"from_mmcli": "true"}, filepaths=parsed.attach)
|
||||||
|
print(sent)
|
||||||
|
|
||||||
|
|
||||||
def post_str(attribute, post, parsed):
|
def post_str(attribute, post, parsed):
|
||||||
|
@ -152,14 +186,16 @@ def post_str(attribute, post, parsed):
|
||||||
if parsed.format == "tsv":
|
if parsed.format == "tsv":
|
||||||
msg = obj.get("message", "").replace("\\", "\\\\").replace("\t", r"\t").replace("\n", r"\n")
|
msg = obj.get("message", "").replace("\\", "\\\\").replace("\t", r"\t").replace("\n", r"\n")
|
||||||
return f"{obj['id']}\t{obj['create_at']}\t{obj.get('username') or obj['user_id']}\t{msg}"
|
return f"{obj['id']}\t{obj['create_at']}\t{obj.get('username') or obj['user_id']}\t{msg}"
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
ACTIONS = {
|
ACTIONS = {
|
||||||
"login": {"function": login, "accesstoken_required": False},
|
"login": {"function": login, "accesstoken_required": False},
|
||||||
"cat": {"function": cat},
|
"cat": {"function": cat},
|
||||||
|
"send": {"function": send},
|
||||||
}
|
}
|
||||||
|
|
||||||
FORMATTERS = { "json", "tsv", "csv" }
|
FORMATTERS = { "json", "tsv" }
|
||||||
|
|
||||||
ENVVAR_SERVER = "MM_SERVER"
|
ENVVAR_SERVER = "MM_SERVER"
|
||||||
ENVVAR_USERNAME = "MM_USERNAME"
|
ENVVAR_USERNAME = "MM_USERNAME"
|
||||||
|
@ -200,13 +236,26 @@ Hint: JSON output can be filtered on the command line with jq(1).
|
||||||
parser_login.add_argument("--password", default=os.getenv(ENVVAR_PASSWORD))
|
parser_login.add_argument("--password", default=os.getenv(ENVVAR_PASSWORD))
|
||||||
parser_login.add_argument("--totp", default=os.getenv(ENVVAR_TOTP))
|
parser_login.add_argument("--totp", default=os.getenv(ENVVAR_TOTP))
|
||||||
|
|
||||||
parser_cat = subparsers.add_parser("cat", help="list messages in channel(s)")
|
# TODO support multiple channels
|
||||||
parser_cat.add_argument(
|
# parser_cat = subparsers.add_parser("cat", help="list messages in channel(s)")
|
||||||
"channels", nargs="+", help="URL names of team and channel: '<team>/<channel>'")
|
# parser_cat.add_argument(
|
||||||
|
# "channels", nargs="+", help="URL names of team and channel: '<team>/<channel>'")
|
||||||
|
parser_cat = subparsers.add_parser("cat", help="list messages in channel")
|
||||||
|
parser_cat.add_argument("channel", help="URL names of team and channel: '<team>/<channel>'")
|
||||||
|
# ---
|
||||||
parser_cat.add_argument("--after", help="all after post with ID")
|
parser_cat.add_argument("--after", help="all after post with ID")
|
||||||
parser_cat.add_argument("--since", help="all after timestamp")
|
parser_cat.add_argument("--since", help="all after timestamp")
|
||||||
parser_cat.add_argument("-f", "--follow", help="keep running, printing new posts as they come in")
|
parser_cat.add_argument("-f", "--follow", help="keep running, printing new posts as they come in")
|
||||||
|
|
||||||
|
parser_send = subparsers.add_parser("send", help="send message(s)")
|
||||||
|
parser_send.add_argument(
|
||||||
|
"--channel", help="URL names of team and channel: '<team>/<channel>'; if not provided, "
|
||||||
|
"messages must be provided on stdin and each must specify channel")
|
||||||
|
parser_send.add_argument(
|
||||||
|
"--message", help="message; if not provided, messages will be expected on stdin")
|
||||||
|
parser_send.add_argument(
|
||||||
|
"--attach", nargs="+", help="filename of file to attach")
|
||||||
|
|
||||||
parsed = argparser.parse_args()
|
parsed = argparser.parse_args()
|
||||||
|
|
||||||
if not parsed.server:
|
if not parsed.server:
|
||||||
|
|
Loading…
Reference in a new issue