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

This commit is contained in:
david-harley 2021-01-07 15:02:47 +10:30
parent 88d81c7a63
commit 38a2da4855
4 changed files with 142 additions and 30 deletions

View file

@ -130,7 +130,7 @@ Uses a list of phone numbers to determine the statuses of those users. Shows if
[NUMBER [NUMBER ...]]:: [NUMBER [NUMBER ...]]::
One or more numbers to check. One or more numbers to check.
*--json*:: *--j*, *--json*::
Output the statuses as an array of json objects. Output the statuses as an array of json objects.
=== send === send
@ -184,7 +184,7 @@ Number of seconds to wait for new messages (negative values disable timeout).
Default is 5 seconds. Default is 5 seconds.
*--ignore-attachments*:: *--ignore-attachments*::
Dont download attachments of received messages. Dont download attachments of received messages.
*--json*:: *--j*, *--json*::
Output received messages in json format, one object per line. Output received messages in json format, one object per line.
=== joinGroup === joinGroup
@ -222,10 +222,13 @@ Specify the recipient group ID in base64 encoding.
=== listGroups === listGroups
Show a list of known groups. Show a list of known groups and related information.
*-d*, *--detailed*:: *-d*, *--detailed*::
Include the list of members of each group. Include the list of members of each group and the group invite link.
*--j*, *--json*::
Output group information as a list of json objects.
=== listIdentities === listIdentities

View file

@ -21,7 +21,7 @@ public class GetUserStatusCommand implements LocalCommand {
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("number").help("Phone number").nargs("+"); subparser.addArgument("number").help("Phone number").nargs("+");
subparser.help("Check if the specified phone number/s have been registered"); subparser.help("Check if the specified phone number/s have been registered");
subparser.addArgument("--json") subparser.addArgument("-j", "--json")
.help("Output received messages in json format, one json object per line.") .help("Output received messages in json format, one json object per line.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
} }

View file

@ -9,32 +9,61 @@ import org.asamk.signal.manager.groups.GroupInviteLinkUrl;
import org.asamk.signal.manager.storage.groups.GroupInfo; import org.asamk.signal.manager.storage.groups.GroupInfo;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; 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.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class ListGroupsCommand implements LocalCommand { public class ListGroupsCommand implements LocalCommand {
private static void printGroup(Manager m, GroupInfo group, boolean detailed) { private enum MembersType {
MEMBERS,
PENDING_MEMBERS,
REQUESTING_MEMBERS,
}
private static Set<String> getMembersSet(Manager m, GroupInfo group, MembersType type) {
Set<SignalServiceAddress> members;
switch (type) {
case MEMBERS:
members = group.getMembers();
break;
case PENDING_MEMBERS:
members = group.getPendingMembers();
break;
case REQUESTING_MEMBERS:
members = group.getRequestingMembers();
break;
default:
return Collections.emptySet();
}
return members.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) { 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(); final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
System.out.println(String.format( System.out.println(String.format(
@ -43,9 +72,9 @@ public class ListGroupsCommand implements LocalCommand {
group.getTitle(), group.getTitle(),
group.isMember(m.getSelfAddress()), group.isMember(m.getSelfAddress()),
group.isBlocked(), group.isBlocked(),
members, getMembersSet(m, group, MembersType.MEMBERS),
pendingMembers, getMembersSet(m, group, MembersType.PENDING_MEMBERS),
requestingMembers, getMembersSet(m, group, MembersType.REQUESTING_MEMBERS),
groupInviteLink == null ? '-' : groupInviteLink.getUrl())); groupInviteLink == null ? '-' : groupInviteLink.getUrl()));
} else { } else {
System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b", System.out.println(String.format("Id: %s Name: %s Active: %s Blocked: %b",
@ -60,6 +89,9 @@ public class ListGroupsCommand implements LocalCommand {
public void attachToSubparser(final Subparser subparser) { public void attachToSubparser(final Subparser subparser) {
subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue()).help("List members of each group"); subparser.addArgument("-d", "--detailed").action(Arguments.storeTrue()).help("List members of each group");
subparser.help("List group name and ids"); subparser.help("List group name and ids");
subparser.addArgument("-j", "--json")
.help("Output received messages in json format, one json object per line.")
.action(Arguments.storeTrue());
} }
@Override @Override
@ -72,9 +104,86 @@ public class ListGroupsCommand implements LocalCommand {
List<GroupInfo> groups = m.getGroups(); List<GroupInfo> groups = m.getGroups();
boolean detailed = ns.getBoolean("detailed"); boolean detailed = ns.getBoolean("detailed");
for (GroupInfo group : groups) { if (ns.getBoolean("json")) {
printGroup(m, group, detailed); final ObjectMapper jsonProcessor = new ObjectMapper();
jsonProcessor.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jsonProcessor.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
if (detailed) {
List<JsonListGroupDetailed> objects = new ArrayList<>();
for (GroupInfo group : groups) {
final GroupInviteLinkUrl groupInviteLink = group.getGroupInviteLink();
objects.add(new JsonListGroupDetailed(group.getGroupId().toBase64(),
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked(),
getMembersSet(m, group, MembersType.MEMBERS),
getMembersSet(m, group, MembersType.PENDING_MEMBERS),
getMembersSet(m, group, MembersType.REQUESTING_MEMBERS),
groupInviteLink == null ? null : groupInviteLink.getUrl()));
}
return printGroupsJson(jsonProcessor, objects);
} else {
List<JsonListGroup> objects = groups.stream().map(
group -> new JsonListGroup(group.getGroupId().toBase64(),
group.getTitle(),
group.isMember(m.getSelfAddress()),
group.isBlocked()))
.collect(Collectors.toList());
return printGroupsJson(jsonProcessor, objects);
}
} else {
for (GroupInfo group : groups) {
printGroupPlainText(m, group, detailed);
}
} }
return 0; return 0;
} }
private static final class JsonListGroup {
public String id;
public String name;
public boolean isMember;
public boolean isBlocked;
public JsonListGroup(String id, String name, boolean isMember, boolean isBlocked) {
this.id = id;
this.name = name;
this.isMember = isMember;
this.isBlocked = isBlocked;
}
}
private static final class JsonListGroupDetailed {
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 JsonListGroupDetailed(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

@ -35,7 +35,7 @@ public class ReceiveCommand implements ExtendedDbusCommand, LocalCommand {
subparser.addArgument("--ignore-attachments") subparser.addArgument("--ignore-attachments")
.help("Dont download attachments of received messages.") .help("Dont download attachments of received messages.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
subparser.addArgument("--json") subparser.addArgument("-j", "--json")
.help("Output received messages in json format, one json object per line.") .help("Output received messages in json format, one json object per line.")
.action(Arguments.storeTrue()); .action(Arguments.storeTrue());
} }