Added JSON output to listGroups and allowed json to be activated with -j (#401)

* Added json output to listGroups and allowed json to be activated with -j

* Renamed classes

* Added AsamK's suggestions

* Removed isRegisted check since that is causing a conflict with upstream

* Fixed an issue in the help message for listGroupsCommand

* Re-enabled --json for receive and getUserStatuses commands as deprecated

* Added better depricated warning message and clarified some java doc stuff
This commit is contained in:
Atomic-Bean 2021-01-14 02:21:31 +10:30 committed by GitHub
parent c9fa28d844
commit 90f5cd79c9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 134 additions and 41 deletions

View file

@ -299,6 +299,9 @@ public class Main {
mut.addArgument("--dbus").help("Make request via user dbus.").action(Arguments.storeTrue());
mut.addArgument("--dbus-system").help("Make request via system dbus.").action(Arguments.storeTrue());
parser.addArgument("-o", "--output").help("Choose to output in plain text or JSON")
.choices("plain-text", "json").setDefault("plain-text");
Subparsers subparsers = parser.addSubparsers()
.title("subcommands")
.dest("command")

View file

@ -8,6 +8,8 @@ import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import org.asamk.signal.manager.Manager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashSet;
@ -17,12 +19,15 @@ import java.util.stream.Collectors;
public class GetUserStatusCommand implements LocalCommand {
// TODO delete later when "json" variable is removed
final static Logger logger = LoggerFactory.getLogger(GetUserStatusCommand.class);
@Override
public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("number").help("Phone number").nargs("+");
subparser.help("Check if the specified phone number/s have been registered");
subparser.addArgument("--json")
.help("Output received messages in json format, one json object per line.")
.help("WARNING: This parameter is now deprecated! Please use the \"output\" option instead.\n\nOutput received messages in json format, one json object per line.")
.action(Arguments.storeTrue());
}
@ -32,6 +37,13 @@ public class GetUserStatusCommand implements LocalCommand {
ObjectMapper jsonProcessor = new ObjectMapper();
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
boolean inJson = ns.getString("output").equals("json");
// TODO delete later when "json" variable is removed
if (ns.getBoolean("json")) {
logger.warn("\"--json\" option has been deprecated, please use \"output\" instead.");
}
// Get a map of registration statuses
Map<String, Boolean> registered;
try {
@ -42,7 +54,7 @@ public class GetUserStatusCommand implements LocalCommand {
}
// Output
if (ns.getBoolean("json")) {
if (inJson) {
List<JsonIsRegistered> objects = registered.entrySet()
.stream()
.map(entry -> new JsonIsRegistered(entry.getKey(), entry.getValue()))

View file

@ -9,32 +9,39 @@ import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class ListGroupsCommand implements LocalCommand {
private static void printGroup(Manager m, GroupInfo group, boolean detailed) {
private static Set<String> resolveMembers(Manager m, Set<SignalServiceAddress> addresses) {
return addresses.stream().map(m::resolveSignalServiceAddress)
.map(SignalServiceAddress::getLegacyIdentifier)
.collect(Collectors.toSet());
}
private static int printGroupsJson(ObjectMapper jsonProcessor, List<?> objects) {
try {
jsonProcessor.writeValue(System.out, objects);
System.out.println();
} catch (IOException e) {
System.err.println(e.getMessage());
return 1;
}
return 0;
}
private static void printGroupPlainText(Manager m, GroupInfo group, boolean detailed) {
if (detailed) {
Set<String> members = group.getMembers()
.stream()
.map(m::resolveSignalServiceAddress)
.map(SignalServiceAddress::getLegacyIdentifier)
.collect(Collectors.toSet());
Set<String> pendingMembers = group.getPendingMembers()
.stream()
.map(m::resolveSignalServiceAddress)
.map(SignalServiceAddress::getLegacyIdentifier)
.collect(Collectors.toSet());
Set<String> requestingMembers = group.getRequestingMembers()
.stream()
.map(m::resolveSignalServiceAddress)
.map(SignalServiceAddress::getLegacyIdentifier)
.collect(Collectors.toSet());
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
System.out.println(String.format(
@ -43,9 +50,9 @@ public class ListGroupsCommand implements LocalCommand {
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked(),
members,
pendingMembers,
requestingMembers,
resolveMembers(m, group.getMembers()),
resolveMembers(m, group.getPendingMembers()),
resolveMembers(m, group.getRequestingMembers()),
groupInviteLink == null ? '-' : groupInviteLink.getUrl()));
} else {
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
@ -58,18 +65,68 @@ public class ListGroupsCommand implements LocalCommand {
@Override
public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue()).help("List members of each group");
subparser.help("List group name and ids");
subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue())
.help("List the members and group invite links of each group. If output=json, then this is always set");
subparser.help("List group information including names, ids, active status, blocked status and members");
}
@Override
public int handleCommand(final Namespace ns, final Manager m) {
List<GroupInfo> groups = m.getGroups();
boolean detailed = ns.getBoolean("detailed");
if (ns.getString("output").equals("json")) {
final ObjectMapper jsonProcessor = new ObjectMapper();
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
for (GroupInfo group : groups) {
printGroup(m, group, detailed);
List<JsonGroup> objects = new ArrayList<>();
for (GroupInfo group : m.getGroups()) {
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
objects.add(new JsonGroup(group.getGroupId().toBase64(),
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked(),
resolveMembers(m, group.getMembers()),
resolveMembers(m, group.getPendingMembers()),
resolveMembers(m, group.getRequestingMembers()),
groupInviteLink == null ? null : groupInviteLink.getUrl()));
}
return printGroupsJson(jsonProcessor, objects);
} else {
boolean detailed = ns.getBoolean("detailed");
for (GroupInfo group : m.getGroups()) {
printGroupPlainText(m, group, detailed);
}
}
return 0;
}
private static final class JsonGroup {
public String id;
public String name;
public boolean isMember;
public boolean isBlocked;
public Set<String> members;
public Set<String> pendingMembers;
public Set<String> requestingMembers;
public String groupInviteLink;
public JsonGroup(String id, String name, boolean isMember, boolean isBlocked,
Set<String> members, Set<String> pendingMembers,
Set<String> requestingMembers, String groupInviteLink)
{
this.id = id;
this.name = name;
this.isMember = isMember;
this.isBlocked = isBlocked;
this.members = members;
this.pendingMembers = pendingMembers;
this.requestingMembers = requestingMembers;
this.groupInviteLink = groupInviteLink;
}
}
}

View file

@ -20,6 +20,10 @@ import org.freedesktop.dbus.connections.impl.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;
import org.whispersystems.util.Base64;
// TODO delete later when "json" variable is removed
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@ -27,6 +31,9 @@ import static org.asamk.signal.util.ErrorUtils.handleAssertionError;
public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
// TODO delete later when "json" variable is removed
final static Logger logger = LoggerFactory.getLogger(ReceiveCommand.class);
@Override
public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-t", "--timeout")
@ -36,13 +43,21 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
.help("Dont download attachments of received messages.")
.action(Arguments.storeTrue());
subparser.addArgument("--json")
.help("Output received messages in json format, one json object per line.")
.help("WARNING: This parameter is now deprecated! Please use the \"output\" option instead.\n\nOutput received messages in json format, one json object per line.")
.action(Arguments.storeTrue());
}
public int handleCommand(final Namespace ns, final Signal signal, DBusConnection dbusconnection) {
final ObjectMapper jsonProcessor;
boolean inJson = ns.getString("output").equals("json") || ns.getBoolean("json");
// TODO delete later when "json" variable is removed
if (ns.getBoolean("json")) {
logger.warn("\"--json\" option has been deprecated, please use \"output\" instead.");
}
if (inJson) {
jsonProcessor = new ObjectMapper();
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
@ -146,6 +161,13 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
@Override
public int handleCommand(final Namespace ns, final Manager m) {
boolean inJson = ns.getString("output").equals("json") || ns.getBoolean("json");
// TODO delete later when "json" variable is removed
if (ns.getBoolean("json")) {
logger.warn("\"--json\" option has been deprecated, please use \"output\" instead.");
}
double timeout = 5;
if (ns.getDouble("timeout") != null) {
timeout = ns.getDouble("timeout");
@ -157,7 +179,7 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
}
boolean ignoreAttachments = ns.getBoolean("ignore_attachments");
try {
final Manager.ReceiveMessageHandler handler = ns.getBoolean("json")
final Manager.ReceiveMessageHandler handler = inJson
? new JsonReceiveMessageHandler(m)
: new ReceiveMessageHandler(m);
m.receiveMessages((long) (timeout * 1000),

View file

@ -312,7 +312,7 @@ public class Manager implements Closeable {
*
* @param numbers The set of phone number in question
* @return A map of numbers to booleans. True if registered, false otherwise. Should never be null
* @throws IOException if its unable to check if the users are registered
* @throws IOException if its unable to get the contacts to check if they're registered
*/
public Map<String, Boolean> areUsersRegistered(Set<String> numbers) throws IOException {
// Note "contactDetails" has no optionals. It only gives us info on users who are registered