Simple user command may work.
This commit is contained in:
@@ -7,3 +7,4 @@ transaction
|
|||||||
ZEO
|
ZEO
|
||||||
podman
|
podman
|
||||||
click
|
click
|
||||||
|
tabulate
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
import click
|
import click
|
||||||
from packetserver.client.cli.config import get_config, default_app_dir, config_path
|
from packetserver.client.cli.config import get_config, default_app_dir, config_path
|
||||||
from packetserver.client.cli.constants import DEFAULT_DB_FILE
|
from packetserver.client.cli.constants import DEFAULT_DB_FILE
|
||||||
|
from packetserver.client import Client
|
||||||
|
from packetserver.common.constants import yes_values
|
||||||
|
from packetserver.client.cli.util import format_list_dicts
|
||||||
import ZODB
|
import ZODB
|
||||||
import ZODB.FileStorage
|
import ZODB.FileStorage
|
||||||
|
import ax25
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from packetserver.client import Client
|
from packetserver.client import Client
|
||||||
|
from packetserver.client import users
|
||||||
from packetserver.client.users import get_user_by_username, UserWrapper
|
from packetserver.client.users import get_user_by_username, UserWrapper
|
||||||
|
|
||||||
VERSION="0.1.0-alpha"
|
VERSION="0.1.0-alpha"
|
||||||
@@ -17,27 +22,85 @@ VERSION="0.1.0-alpha"
|
|||||||
@click.group()
|
@click.group()
|
||||||
@click.option('--conf', default=config_path(), help='path to configfile')
|
@click.option('--conf', default=config_path(), help='path to configfile')
|
||||||
@click.option('--server', '-s', default='', help="server radio callsign to connect to (required)")
|
@click.option('--server', '-s', default='', help="server radio callsign to connect to (required)")
|
||||||
@click.option('--agwpe', '-a', default='localhost', help="AGWPE TNC server address to connect to (config file)")
|
@click.option('--agwpe', '-a', default='', help="AGWPE TNC server address to connect to (config file)")
|
||||||
@click.option('--port', '-p', default=8000, help="AGWPE TNC server port to connect to (config file)")
|
@click.option('--port', '-p', default=0, help="AGWPE TNC server port to connect to (config file)")
|
||||||
@click.option('--callsign', '-c', default='', help="radio callsign[+ssid] of this client station (config file)")
|
@click.option('--callsign', '-c', default='', help="radio callsign[+ssid] of this client station (config file)")
|
||||||
@click.version_option(VERSION,"--version", "-v")
|
@click.version_option(VERSION,"--version", "-v")
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def cli(ctx, conf, server, agwpe, port, callsign):
|
def cli(ctx, conf, server, agwpe, port, callsign):
|
||||||
"""Command line interface for the PacketServer client and server API."""
|
"""Command line interface for the PacketServer client and server API."""
|
||||||
|
ctx.ensure_object(dict)
|
||||||
cfg = get_config(config_file_path=conf)
|
cfg = get_config(config_file_path=conf)
|
||||||
|
|
||||||
|
if callsign.strip() != '':
|
||||||
|
ctx.obj['callsign'] = callsign.strip().upper()
|
||||||
|
else:
|
||||||
|
if 'callsign' in cfg['cli']:
|
||||||
|
ctx.obj['callsign'] = cfg['cli']['callsign']
|
||||||
|
else:
|
||||||
|
raise ValueError("You must provide client station's callsign.")
|
||||||
|
|
||||||
|
if not ax25.Address.valid_call(ctx.obj['callsign']):
|
||||||
|
raise ValueError(f"Provided client callsign '{ctx.obj['callsign']}' is invalid.")
|
||||||
|
|
||||||
|
if server.strip() != '':
|
||||||
|
ctx.obj['server'] = server.strip().upper()
|
||||||
|
else:
|
||||||
|
if 'server' in cfg['cli']:
|
||||||
|
ctx.obj['server'] = cfg['cli']['server']
|
||||||
|
else:
|
||||||
|
raise ValueError("Remote BBS server callsign must be specified.")
|
||||||
|
|
||||||
|
if not ax25.Address.valid_call(ctx.obj['server']):
|
||||||
|
raise ValueError(f"Provided remote server callsign '{ctx.obj['server']}' is invalid.")
|
||||||
|
|
||||||
|
if agwpe.strip() != '':
|
||||||
|
ctx.obj['agwpe_server'] = agwpe.strip()
|
||||||
|
else:
|
||||||
|
if 'agwpe_server' in cfg['cli']:
|
||||||
|
ctx.obj['agwpe_server'] = cfg['cli']['agwpe_server']
|
||||||
|
else:
|
||||||
|
ctx.obj['agwpe_server'] = 'localhost'
|
||||||
|
|
||||||
|
if port != 0:
|
||||||
|
ctx.obj['port'] = port
|
||||||
|
else:
|
||||||
|
if 'port' in cfg['cli']:
|
||||||
|
ctx.obj['port'] = int(cfg['cli']['port'])
|
||||||
|
else:
|
||||||
|
ctx.obj['port'] = 8000
|
||||||
|
|
||||||
storage = ZODB.FileStorage.FileStorage(os.path.join(cfg['cli']['directory'], DEFAULT_DB_FILE))
|
storage = ZODB.FileStorage.FileStorage(os.path.join(cfg['cli']['directory'], DEFAULT_DB_FILE))
|
||||||
db = ZODB.DB(storage)
|
db = ZODB.DB(storage)
|
||||||
ctx.ensure_object(dict)
|
client = Client(ctx.obj['agwpe_server'], ctx.obj['port'], ctx.obj['callsign'], keep_log=True)
|
||||||
|
ctx.obj['client'] = client
|
||||||
ctx.obj['CONFIG'] = cfg
|
ctx.obj['CONFIG'] = cfg
|
||||||
ctx.obj['bbs'] = server
|
ctx.obj['bbs'] = server
|
||||||
ctx.obj['db'] = db
|
ctx.obj['db'] = db
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
@click.option('--username', '-u', default='', help="the username (CALLSIGN) to lookup on the bbs")
|
@click.argument('username', required=False, default='', help="the username (CALLSIGN) to lookup on the bbs")
|
||||||
|
@click.option('--list-users', '-l', is_flag=True, default=False, help="If set, downloads list of all users.")
|
||||||
|
@click.option("--output-format", "-f", default="table", help="Print data as table[default], list, or JSON",
|
||||||
|
type=click.Choice(['table', 'json', 'list'], case_sensitive=False))
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def user(ctx):
|
def user(ctx, list_users, output_format, username):
|
||||||
"""Query users on the BBS and customize personal settings."""
|
"""Query users on the BBS."""
|
||||||
pass
|
client = ctx.obj['client']
|
||||||
|
# validate args
|
||||||
|
if list_users and (username.strip() != ""):
|
||||||
|
raise ValueError("Can't specify a username while listing all users.")
|
||||||
|
|
||||||
|
if not list_users and (username.strip() == ""):
|
||||||
|
raise ValueError("Must provide either a username or --list-users flag.")
|
||||||
|
|
||||||
|
output_objects = []
|
||||||
|
if list_users:
|
||||||
|
output_objects = users.get_users(client, ctx.obj['bbs'])
|
||||||
|
else:
|
||||||
|
output_objects.append(users.get_user_by_username(client, ctx.obj['bbs'], username))
|
||||||
|
|
||||||
|
click.echo(format_list_dicts([x.pretty_dict() for x in output_objects], output_format=output_format.lower()))
|
||||||
|
|
||||||
cli.add_command(user)
|
cli.add_command(user)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,23 @@
|
|||||||
|
from tabulate import tabulate
|
||||||
|
import json
|
||||||
|
|
||||||
|
def format_list_dicts(dicts: list[dict], output_format: str = "table"):
|
||||||
|
if output_format == "table":
|
||||||
|
return tabulate(dicts, headers="keys")
|
||||||
|
|
||||||
|
elif output_format == "json":
|
||||||
|
return json.dumps(dicts, indent=2)
|
||||||
|
|
||||||
|
elif output_format == "list":
|
||||||
|
output = "-------------\n"
|
||||||
|
for i in dicts:
|
||||||
|
t = []
|
||||||
|
for key in i:
|
||||||
|
t.append([str(key), str(i[key])])
|
||||||
|
output = output + tabulate(t) + "-------------\n"
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ValueError("Unsupported format type.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,18 @@ class UserWrapper:
|
|||||||
raise ValueError("Data dict was not an object dictionary.")
|
raise ValueError("Data dict was not an object dictionary.")
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
|
def pretty_dict(self) -> dict:
|
||||||
|
out_dict = {}
|
||||||
|
for a in ['username', 'status', 'bio', 'socials', 'created', 'last_seen', 'email', 'location']:
|
||||||
|
if a != 'socials':
|
||||||
|
out_dict[a] = getattr(self, a)
|
||||||
|
else:
|
||||||
|
social_str = "\n".join(self.socials)
|
||||||
|
out_dict['socials'] = social_str
|
||||||
|
|
||||||
|
return out_dict
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<UserWrapper: {self.username}>"
|
return f"<UserWrapper: {self.username}>"
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ setup(
|
|||||||
'pyham_ax25',
|
'pyham_ax25',
|
||||||
'ZODB',
|
'ZODB',
|
||||||
'ZEO',
|
'ZEO',
|
||||||
'podman'
|
'podman',
|
||||||
|
'tabulate'
|
||||||
],
|
],
|
||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
|
|||||||
Reference in New Issue
Block a user