forked from Qortal/qortal
Join/Leave account groups + API calls
This commit is contained in:
parent
760cb6cd37
commit
02a620d57b
@ -6,7 +6,6 @@ import javax.xml.bind.annotation.XmlAccessType;
|
|||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
import javax.xml.bind.annotation.XmlElement;
|
||||||
|
|
||||||
import org.qora.data.group.GroupAdminData;
|
|
||||||
import org.qora.data.group.GroupData;
|
import org.qora.data.group.GroupData;
|
||||||
import org.qora.data.group.GroupMemberData;
|
import org.qora.data.group.GroupMemberData;
|
||||||
|
|
||||||
@ -23,16 +22,19 @@ public class GroupWithMemberInfo {
|
|||||||
|
|
||||||
Integer memberCount;
|
Integer memberCount;
|
||||||
|
|
||||||
public List<GroupAdminData> groupAdmins;
|
@XmlElement(name = "admins")
|
||||||
|
public List<String> groupAdminAddresses;
|
||||||
|
|
||||||
|
@XmlElement(name = "members")
|
||||||
public List<GroupMemberData> groupMembers;
|
public List<GroupMemberData> groupMembers;
|
||||||
|
|
||||||
// For JAX-RS
|
// For JAX-RS
|
||||||
protected GroupWithMemberInfo() {
|
protected GroupWithMemberInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupWithMemberInfo(GroupData groupData, List<GroupAdminData> groupAdmins, List<GroupMemberData> groupMembers, Integer memberCount) {
|
public GroupWithMemberInfo(GroupData groupData, List<String> groupAdminAddresses, List<GroupMemberData> groupMembers, Integer memberCount) {
|
||||||
this.groupData = groupData;
|
this.groupData = groupData;
|
||||||
this.groupAdmins = groupAdmins;
|
this.groupAdminAddresses = groupAdminAddresses;
|
||||||
this.groupMembers = groupMembers;
|
this.groupMembers = groupMembers;
|
||||||
this.memberCount = memberCount;
|
this.memberCount = memberCount;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import org.qora.data.group.GroupData;
|
|||||||
import org.qora.data.group.GroupMemberData;
|
import org.qora.data.group.GroupMemberData;
|
||||||
import org.qora.data.transaction.CreateGroupTransactionData;
|
import org.qora.data.transaction.CreateGroupTransactionData;
|
||||||
import org.qora.data.transaction.JoinGroupTransactionData;
|
import org.qora.data.transaction.JoinGroupTransactionData;
|
||||||
|
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||||
import org.qora.data.transaction.UpdateGroupTransactionData;
|
import org.qora.data.transaction.UpdateGroupTransactionData;
|
||||||
import org.qora.repository.DataException;
|
import org.qora.repository.DataException;
|
||||||
import org.qora.repository.Repository;
|
import org.qora.repository.Repository;
|
||||||
@ -41,6 +42,7 @@ import org.qora.transaction.Transaction.ValidationResult;
|
|||||||
import org.qora.transform.TransformationException;
|
import org.qora.transform.TransformationException;
|
||||||
import org.qora.transform.transaction.CreateGroupTransactionTransformer;
|
import org.qora.transform.transaction.CreateGroupTransactionTransformer;
|
||||||
import org.qora.transform.transaction.JoinGroupTransactionTransformer;
|
import org.qora.transform.transaction.JoinGroupTransactionTransformer;
|
||||||
|
import org.qora.transform.transaction.LeaveGroupTransactionTransformer;
|
||||||
import org.qora.transform.transaction.UpdateGroupTransactionTransformer;
|
import org.qora.transform.transaction.UpdateGroupTransactionTransformer;
|
||||||
import org.qora.utils.Base58;
|
import org.qora.utils.Base58;
|
||||||
|
|
||||||
@ -137,7 +139,7 @@ public class GroupsResource {
|
|||||||
groupMembers = repository.getGroupRepository().getAllGroupMembers(groupData.getGroupName());
|
groupMembers = repository.getGroupRepository().getAllGroupMembers(groupData.getGroupName());
|
||||||
|
|
||||||
// Strip groupName from member info
|
// Strip groupName from member info
|
||||||
groupMembers = groupMembers.stream().map(groupMemberData -> new GroupMemberData(null, groupMemberData.getMember(), groupMemberData.getJoined())).collect(Collectors.toList());
|
groupMembers = groupMembers.stream().map(groupMemberData -> new GroupMemberData(null, groupMemberData.getMember(), groupMemberData.getJoined(), null)).collect(Collectors.toList());
|
||||||
|
|
||||||
memberCount = groupMembers.size();
|
memberCount = groupMembers.size();
|
||||||
} else {
|
} else {
|
||||||
@ -148,10 +150,10 @@ public class GroupsResource {
|
|||||||
// Always include admins
|
// Always include admins
|
||||||
List<GroupAdminData> groupAdmins = repository.getGroupRepository().getAllGroupAdmins(groupData.getGroupName());
|
List<GroupAdminData> groupAdmins = repository.getGroupRepository().getAllGroupAdmins(groupData.getGroupName());
|
||||||
|
|
||||||
// Strip groupName from admin info
|
// We only need admin addresses
|
||||||
groupAdmins = groupAdmins.stream().map(groupAdminData -> new GroupAdminData(null, groupAdminData.getAdmin())).collect(Collectors.toList());
|
List<String> groupAdminAddresses = groupAdmins.stream().map(groupAdminData -> groupAdminData.getAdmin()).collect(Collectors.toList());
|
||||||
|
|
||||||
return new GroupWithMemberInfo(groupData, groupAdmins, groupMembers, memberCount);
|
return new GroupWithMemberInfo(groupData, groupAdminAddresses, groupMembers, memberCount);
|
||||||
} catch (DataException e) {
|
} catch (DataException e) {
|
||||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
||||||
}
|
}
|
||||||
@ -287,4 +289,47 @@ public class GroupsResource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/leave")
|
||||||
|
@Operation(
|
||||||
|
summary = "Build raw, unsigned, LEAVE_GROUP transaction",
|
||||||
|
requestBody = @RequestBody(
|
||||||
|
required = true,
|
||||||
|
content = @Content(
|
||||||
|
mediaType = MediaType.APPLICATION_JSON,
|
||||||
|
schema = @Schema(
|
||||||
|
implementation = LeaveGroupTransactionData.class
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
responses = {
|
||||||
|
@ApiResponse(
|
||||||
|
description = "raw, unsigned, LEAVE_GROUP transaction encoded in Base58",
|
||||||
|
content = @Content(
|
||||||
|
mediaType = MediaType.TEXT_PLAIN,
|
||||||
|
schema = @Schema(
|
||||||
|
type = "string"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||||
|
public String leaveGroup(LeaveGroupTransactionData transactionData) {
|
||||||
|
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||||
|
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||||
|
|
||||||
|
ValidationResult result = transaction.isValidUnconfirmed();
|
||||||
|
if (result != ValidationResult.OK)
|
||||||
|
throw TransactionsResource.createTransactionInvalidException(request, result);
|
||||||
|
|
||||||
|
byte[] bytes = LeaveGroupTransactionTransformer.toBytes(transactionData);
|
||||||
|
return Base58.encode(bytes);
|
||||||
|
} catch (TransformationException e) {
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e);
|
||||||
|
} catch (DataException e) {
|
||||||
|
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -2,6 +2,7 @@ package org.qora.data.group;
|
|||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlTransient;
|
||||||
|
|
||||||
// All properties to be converted to JSON via JAX-RS
|
// All properties to be converted to JSON via JAX-RS
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
@ -10,6 +11,10 @@ public class GroupAdminData {
|
|||||||
// Properties
|
// Properties
|
||||||
private String groupName;
|
private String groupName;
|
||||||
private String admin;
|
private String admin;
|
||||||
|
/** Reference to transaction that triggered adminship */
|
||||||
|
// No need to ever expose this via API
|
||||||
|
@XmlTransient
|
||||||
|
private byte[] groupReference;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
@ -17,9 +22,10 @@ public class GroupAdminData {
|
|||||||
protected GroupAdminData() {
|
protected GroupAdminData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupAdminData(String groupName, String admin) {
|
public GroupAdminData(String groupName, String admin, byte[] groupReference) {
|
||||||
this.groupName = groupName;
|
this.groupName = groupName;
|
||||||
this.admin = admin;
|
this.admin = admin;
|
||||||
|
this.groupReference = groupReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters / setters
|
// Getters / setters
|
||||||
@ -32,4 +38,12 @@ public class GroupAdminData {
|
|||||||
return this.admin;
|
return this.admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getGroupReference() {
|
||||||
|
return this.groupReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupReference(byte[] groupReference) {
|
||||||
|
this.groupReference = groupReference;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package org.qora.data.group;
|
|||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlTransient;
|
||||||
|
|
||||||
// All properties to be converted to JSON via JAX-RS
|
// All properties to be converted to JSON via JAX-RS
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
@ -14,6 +15,9 @@ public class GroupData {
|
|||||||
private long created;
|
private long created;
|
||||||
private Long updated;
|
private Long updated;
|
||||||
private boolean isOpen;
|
private boolean isOpen;
|
||||||
|
/** Reference to transaction that created group */
|
||||||
|
// No need to ever expose this via API
|
||||||
|
@XmlTransient
|
||||||
private byte[] reference;
|
private byte[] reference;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
@ -2,6 +2,7 @@ package org.qora.data.group;
|
|||||||
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlTransient;
|
||||||
|
|
||||||
// All properties to be converted to JSON via JAX-RS
|
// All properties to be converted to JSON via JAX-RS
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
@ -11,6 +12,10 @@ public class GroupMemberData {
|
|||||||
private String groupName;
|
private String groupName;
|
||||||
private String member;
|
private String member;
|
||||||
private long joined;
|
private long joined;
|
||||||
|
/** Reference to transaction that triggered membership */
|
||||||
|
// No need to ever expose this via API
|
||||||
|
@XmlTransient
|
||||||
|
private byte[] groupReference;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
@ -18,10 +23,11 @@ public class GroupMemberData {
|
|||||||
protected GroupMemberData() {
|
protected GroupMemberData() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GroupMemberData(String groupName, String member, long joined) {
|
public GroupMemberData(String groupName, String member, long joined, byte[] groupReference) {
|
||||||
this.groupName = groupName;
|
this.groupName = groupName;
|
||||||
this.member = member;
|
this.member = member;
|
||||||
this.joined = joined;
|
this.joined = joined;
|
||||||
|
this.groupReference = groupReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters / setters
|
// Getters / setters
|
||||||
@ -38,4 +44,12 @@ public class GroupMemberData {
|
|||||||
return this.joined;
|
return this.joined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getGroupReference() {
|
||||||
|
return this.groupReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroupReference(byte[] groupReference) {
|
||||||
|
this.groupReference = groupReference;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ public class JoinGroupTransactionData extends TransactionData {
|
|||||||
// Properties
|
// Properties
|
||||||
@Schema(description = "joiner's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
|
@Schema(description = "joiner's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
|
||||||
private byte[] joinerPublicKey;
|
private byte[] joinerPublicKey;
|
||||||
@Schema(description = "which group to update", example = "my-group")
|
@Schema(description = "which group to join", example = "my-group")
|
||||||
private String groupName;
|
private String groupName;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
package org.qora.data.transaction;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
import javax.xml.bind.Unmarshaller;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessType;
|
||||||
|
import javax.xml.bind.annotation.XmlAccessorType;
|
||||||
|
import javax.xml.bind.annotation.XmlTransient;
|
||||||
|
|
||||||
|
import org.qora.transaction.Transaction.TransactionType;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
||||||
|
// All properties to be converted to JSON via JAX-RS
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
@Schema(allOf = { TransactionData.class })
|
||||||
|
public class LeaveGroupTransactionData extends TransactionData {
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
@Schema(description = "leaver's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP")
|
||||||
|
private byte[] leaverPublicKey;
|
||||||
|
@Schema(description = "which group to leave", example = "my-group")
|
||||||
|
private String groupName;
|
||||||
|
// No need to ever expose this via API
|
||||||
|
@XmlTransient
|
||||||
|
private byte[] memberReference;
|
||||||
|
// No need to ever expose this via API
|
||||||
|
@XmlTransient
|
||||||
|
private byte[] adminReference;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
// For JAX-RS
|
||||||
|
protected LeaveGroupTransactionData() {
|
||||||
|
super(TransactionType.LEAVE_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterUnmarshal(Unmarshaller u, Object parent) {
|
||||||
|
this.creatorPublicKey = this.leaverPublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeaveGroupTransactionData(byte[] leaverPublicKey, String groupName, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) {
|
||||||
|
super(TransactionType.LEAVE_GROUP, fee, leaverPublicKey, timestamp, reference, signature);
|
||||||
|
|
||||||
|
this.leaverPublicKey = leaverPublicKey;
|
||||||
|
this.groupName = groupName;
|
||||||
|
this.memberReference = memberReference;
|
||||||
|
this.adminReference = adminReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeaveGroupTransactionData(byte[] leaverPublicKey, String groupName, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) {
|
||||||
|
this(leaverPublicKey, groupName, null, null, fee, timestamp, reference, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeaveGroupTransactionData(byte[] leaverPublicKey, String groupName, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference) {
|
||||||
|
this(leaverPublicKey, groupName, memberReference, adminReference, fee, timestamp, reference, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LeaveGroupTransactionData(byte[] leaverPublicKey, String groupName, BigDecimal fee, long timestamp, byte[] reference) {
|
||||||
|
this(leaverPublicKey, groupName, null, null, fee, timestamp, reference, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters / setters
|
||||||
|
|
||||||
|
public byte[] getLeaverPublicKey() {
|
||||||
|
return this.leaverPublicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGroupName() {
|
||||||
|
return this.groupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getMemberReference() {
|
||||||
|
return this.memberReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMemberReference(byte[] memberReference) {
|
||||||
|
this.memberReference = memberReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getAdminReference() {
|
||||||
|
return this.adminReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdminReference(byte[] adminReference) {
|
||||||
|
this.adminReference = adminReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -34,7 +34,7 @@ import io.swagger.v3.oas.annotations.media.Schema.AccessMode;
|
|||||||
CreateOrderTransactionData.class, CancelOrderTransactionData.class,
|
CreateOrderTransactionData.class, CancelOrderTransactionData.class,
|
||||||
MultiPaymentTransactionData.class, DeployATTransactionData.class, MessageTransactionData.class, ATTransactionData.class,
|
MultiPaymentTransactionData.class, DeployATTransactionData.class, MessageTransactionData.class, ATTransactionData.class,
|
||||||
CreateGroupTransactionData.class, UpdateGroupTransactionData.class,
|
CreateGroupTransactionData.class, UpdateGroupTransactionData.class,
|
||||||
JoinGroupTransactionData.class
|
JoinGroupTransactionData.class, LeaveGroupTransactionData.class
|
||||||
})
|
})
|
||||||
//All properties to be converted to JSON via JAX-RS
|
//All properties to be converted to JSON via JAX-RS
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package org.qora.group;
|
package org.qora.group;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.qora.account.Account;
|
import org.qora.account.Account;
|
||||||
import org.qora.account.PublicKeyAccount;
|
import org.qora.account.PublicKeyAccount;
|
||||||
import org.qora.data.group.GroupAdminData;
|
import org.qora.data.group.GroupAdminData;
|
||||||
@ -7,9 +9,11 @@ import org.qora.data.group.GroupData;
|
|||||||
import org.qora.data.group.GroupMemberData;
|
import org.qora.data.group.GroupMemberData;
|
||||||
import org.qora.data.transaction.CreateGroupTransactionData;
|
import org.qora.data.transaction.CreateGroupTransactionData;
|
||||||
import org.qora.data.transaction.JoinGroupTransactionData;
|
import org.qora.data.transaction.JoinGroupTransactionData;
|
||||||
|
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||||
import org.qora.data.transaction.TransactionData;
|
import org.qora.data.transaction.TransactionData;
|
||||||
import org.qora.data.transaction.UpdateGroupTransactionData;
|
import org.qora.data.transaction.UpdateGroupTransactionData;
|
||||||
import org.qora.repository.DataException;
|
import org.qora.repository.DataException;
|
||||||
|
import org.qora.repository.GroupRepository;
|
||||||
import org.qora.repository.Repository;
|
import org.qora.repository.Repository;
|
||||||
|
|
||||||
public class Group {
|
public class Group {
|
||||||
@ -51,14 +55,14 @@ public class Group {
|
|||||||
|
|
||||||
// Processing
|
// Processing
|
||||||
|
|
||||||
public void create() throws DataException {
|
public void create(CreateGroupTransactionData createGroupTransactionData) throws DataException {
|
||||||
this.repository.getGroupRepository().save(this.groupData);
|
this.repository.getGroupRepository().save(this.groupData);
|
||||||
|
|
||||||
// Add owner as admin too
|
// Add owner as admin too
|
||||||
this.repository.getGroupRepository().save(new GroupAdminData(this.groupData.getGroupName(), this.groupData.getOwner()));
|
this.repository.getGroupRepository().save(new GroupAdminData(this.groupData.getGroupName(), this.groupData.getOwner(), createGroupTransactionData.getSignature()));
|
||||||
|
|
||||||
// Add owner as member too
|
// Add owner as member too
|
||||||
this.repository.getGroupRepository().save(new GroupMemberData(this.groupData.getGroupName(), this.groupData.getOwner(), this.groupData.getCreated()));
|
this.repository.getGroupRepository().save(new GroupMemberData(this.groupData.getGroupName(), this.groupData.getOwner(), this.groupData.getCreated(), createGroupTransactionData.getSignature()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void uncreate() throws DataException {
|
public void uncreate() throws DataException {
|
||||||
@ -71,8 +75,6 @@ public class Group {
|
|||||||
if (previousTransactionData == null)
|
if (previousTransactionData == null)
|
||||||
throw new DataException("Unable to revert group transaction as referenced transaction not found in repository");
|
throw new DataException("Unable to revert group transaction as referenced transaction not found in repository");
|
||||||
|
|
||||||
// XXX needs code to reinstate owner as admin and member
|
|
||||||
|
|
||||||
switch (previousTransactionData.getType()) {
|
switch (previousTransactionData.getType()) {
|
||||||
case CREATE_GROUP:
|
case CREATE_GROUP:
|
||||||
CreateGroupTransactionData previousCreateGroupTransactionData = (CreateGroupTransactionData) previousTransactionData;
|
CreateGroupTransactionData previousCreateGroupTransactionData = (CreateGroupTransactionData) previousTransactionData;
|
||||||
@ -93,9 +95,14 @@ public class Group {
|
|||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unable to revert group transaction due to unsupported referenced transaction");
|
throw new IllegalStateException("Unable to revert group transaction due to unsupported referenced transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Previous owner will still be admin and member at this point
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
public void update(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
||||||
|
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||||
|
String groupName = updateGroupTransactionData.getGroupName();
|
||||||
|
|
||||||
// Update reference in transaction data
|
// Update reference in transaction data
|
||||||
updateGroupTransactionData.setGroupReference(this.groupData.getReference());
|
updateGroupTransactionData.setGroupReference(this.groupData.getReference());
|
||||||
|
|
||||||
@ -109,15 +116,29 @@ public class Group {
|
|||||||
this.groupData.setUpdated(updateGroupTransactionData.getTimestamp());
|
this.groupData.setUpdated(updateGroupTransactionData.getTimestamp());
|
||||||
|
|
||||||
// Save updated group data
|
// Save updated group data
|
||||||
this.repository.getGroupRepository().save(this.groupData);
|
groupRepository.save(this.groupData);
|
||||||
|
|
||||||
// XXX new owner should be an admin if not already
|
String newOwner = updateGroupTransactionData.getNewOwner();
|
||||||
// XXX new owner should be a member if not already
|
|
||||||
|
|
||||||
// XXX what happens to previous owner? retained as admin?
|
// New owner should be a member if not already
|
||||||
|
if (!groupRepository.memberExists(groupName, newOwner)) {
|
||||||
|
GroupMemberData groupMemberData = new GroupMemberData(groupName, newOwner, updateGroupTransactionData.getTimestamp(), updateGroupTransactionData.getSignature());
|
||||||
|
groupRepository.save(groupMemberData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New owner should be an admin if not already
|
||||||
|
if (!groupRepository.adminExists(groupName, newOwner)) {
|
||||||
|
GroupAdminData groupAdminData = new GroupAdminData(groupName, newOwner, updateGroupTransactionData.getSignature());
|
||||||
|
groupRepository.save(groupAdminData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous owner retained as admin and member
|
||||||
}
|
}
|
||||||
|
|
||||||
public void revert(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
public void revert(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
||||||
|
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||||
|
String groupName = updateGroupTransactionData.getGroupName();
|
||||||
|
|
||||||
// Previous group reference is taken from this transaction's cached copy
|
// Previous group reference is taken from this transaction's cached copy
|
||||||
this.groupData.setReference(updateGroupTransactionData.getGroupReference());
|
this.groupData.setReference(updateGroupTransactionData.getGroupReference());
|
||||||
|
|
||||||
@ -125,21 +146,83 @@ public class Group {
|
|||||||
this.revert();
|
this.revert();
|
||||||
|
|
||||||
// Save reverted group data
|
// Save reverted group data
|
||||||
this.repository.getGroupRepository().save(this.groupData);
|
groupRepository.save(this.groupData);
|
||||||
|
|
||||||
|
// If ownership changed we need to do more work. Note groupData's owner is reverted at this point.
|
||||||
|
String newOwner = updateGroupTransactionData.getNewOwner();
|
||||||
|
if (!this.groupData.getOwner().equals(newOwner)) {
|
||||||
|
// If this update caused [what was] new owner to become admin, then revoke that now.
|
||||||
|
// (It's possible they were an admin prior to being given ownership so we need to retain that).
|
||||||
|
GroupAdminData groupAdminData = groupRepository.getAdmin(groupName, newOwner);
|
||||||
|
if (Arrays.equals(groupAdminData.getGroupReference(), updateGroupTransactionData.getSignature()))
|
||||||
|
groupRepository.deleteAdmin(groupName, newOwner);
|
||||||
|
|
||||||
|
// If this update caused [what was] new owner to become member, then revoke that now.
|
||||||
|
// (It's possible they were a member prior to being given ownership so we need to retain that).
|
||||||
|
GroupMemberData groupMemberData = groupRepository.getMember(groupName, newOwner);
|
||||||
|
if (Arrays.equals(groupMemberData.getGroupReference(), updateGroupTransactionData.getSignature()))
|
||||||
|
groupRepository.deleteMember(groupName, newOwner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void join(JoinGroupTransactionData joinGroupTransactionData) throws DataException {
|
public void join(JoinGroupTransactionData joinGroupTransactionData) throws DataException {
|
||||||
Account joiner = new PublicKeyAccount(this.repository, joinGroupTransactionData.getJoinerPublicKey());
|
Account joiner = new PublicKeyAccount(this.repository, joinGroupTransactionData.getJoinerPublicKey());
|
||||||
|
|
||||||
GroupMemberData groupMemberData = new GroupMemberData(joinGroupTransactionData.getGroupName(), joiner.getAddress(), joinGroupTransactionData.getTimestamp());
|
GroupMemberData groupMemberData = new GroupMemberData(joinGroupTransactionData.getGroupName(), joiner.getAddress(), joinGroupTransactionData.getTimestamp(), joinGroupTransactionData.getSignature());
|
||||||
this.repository.getGroupRepository().save(groupMemberData);
|
this.repository.getGroupRepository().save(groupMemberData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unjoin(JoinGroupTransactionData joinGroupTransactionData) throws DataException {
|
public void unjoin(JoinGroupTransactionData joinGroupTransactionData) throws DataException {
|
||||||
Account joiner = new PublicKeyAccount(this.repository, joinGroupTransactionData.getJoinerPublicKey());
|
Account joiner = new PublicKeyAccount(this.repository, joinGroupTransactionData.getJoinerPublicKey());
|
||||||
|
|
||||||
GroupMemberData groupMemberData = new GroupMemberData(joinGroupTransactionData.getGroupName(), joiner.getAddress(), joinGroupTransactionData.getTimestamp());
|
this.repository.getGroupRepository().deleteMember(joinGroupTransactionData.getGroupName(), joiner.getAddress());
|
||||||
this.repository.getGroupRepository().delete(groupMemberData);
|
}
|
||||||
|
|
||||||
|
public void leave(LeaveGroupTransactionData leaveGroupTransactionData) throws DataException {
|
||||||
|
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||||
|
String groupName = leaveGroupTransactionData.getGroupName();
|
||||||
|
Account leaver = new PublicKeyAccount(this.repository, leaveGroupTransactionData.getLeaverPublicKey());
|
||||||
|
|
||||||
|
// Potentially record reference to transaction that restores previous admin state.
|
||||||
|
// Owners can't leave as that would leave group ownerless and in unrecoverable state.
|
||||||
|
|
||||||
|
// Owners are also admins, so skip if owner
|
||||||
|
if (!leaver.getAddress().equals(this.groupData.getOwner())) {
|
||||||
|
// Fetch admin data for leaver
|
||||||
|
GroupAdminData groupAdminData = groupRepository.getAdmin(groupName, leaver.getAddress());
|
||||||
|
|
||||||
|
if (groupAdminData != null) {
|
||||||
|
// Leaver is admin - use promotion transaction reference as restore-state reference
|
||||||
|
leaveGroupTransactionData.setAdminReference(groupAdminData.getGroupReference());
|
||||||
|
|
||||||
|
// Remove as admin
|
||||||
|
groupRepository.deleteAdmin(groupName, leaver.getAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save membership transaction reference
|
||||||
|
GroupMemberData groupMemberData = groupRepository.getMember(groupName, leaver.getAddress());
|
||||||
|
leaveGroupTransactionData.setMemberReference(groupMemberData.getGroupReference());
|
||||||
|
|
||||||
|
// Remove as member
|
||||||
|
groupRepository.deleteMember(leaveGroupTransactionData.getGroupName(), leaver.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unleave(LeaveGroupTransactionData leaveGroupTransactionData) throws DataException {
|
||||||
|
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||||
|
String groupName = leaveGroupTransactionData.getGroupName();
|
||||||
|
Account leaver = new PublicKeyAccount(this.repository, leaveGroupTransactionData.getLeaverPublicKey());
|
||||||
|
|
||||||
|
// Rejoin as member
|
||||||
|
TransactionData membershipTransactionData = this.repository.getTransactionRepository().fromSignature(leaveGroupTransactionData.getMemberReference());
|
||||||
|
groupRepository.save(new GroupMemberData(groupName, leaver.getAddress(), membershipTransactionData.getTimestamp(), membershipTransactionData.getSignature()));
|
||||||
|
|
||||||
|
// Put back any admin state based on referenced group-related transaction
|
||||||
|
byte[] adminTransactionSignature = leaveGroupTransactionData.getAdminReference();
|
||||||
|
if (adminTransactionSignature != null) {
|
||||||
|
GroupAdminData groupAdminData = new GroupAdminData(leaveGroupTransactionData.getGroupName(), leaver.getAddress(), adminTransactionSignature);
|
||||||
|
groupRepository.save(groupAdminData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,15 +24,21 @@ public interface GroupRepository {
|
|||||||
|
|
||||||
// Group Admins
|
// Group Admins
|
||||||
|
|
||||||
|
public GroupAdminData getAdmin(String groupName, String address) throws DataException;
|
||||||
|
|
||||||
|
public boolean adminExists(String groupName, String address) throws DataException;
|
||||||
|
|
||||||
public List<GroupAdminData> getAllGroupAdmins(String groupName) throws DataException;
|
public List<GroupAdminData> getAllGroupAdmins(String groupName) throws DataException;
|
||||||
|
|
||||||
public void save(GroupAdminData groupAdminData) throws DataException;
|
public void save(GroupAdminData groupAdminData) throws DataException;
|
||||||
|
|
||||||
public void delete(GroupAdminData groupAdminData) throws DataException;
|
public void deleteAdmin(String groupName, String address) throws DataException;
|
||||||
|
|
||||||
// Group Members
|
// Group Members
|
||||||
|
|
||||||
public boolean memberExists(String groupName, String member) throws DataException;
|
public GroupMemberData getMember(String groupName, String address) throws DataException;
|
||||||
|
|
||||||
|
public boolean memberExists(String groupName, String address) throws DataException;
|
||||||
|
|
||||||
public List<GroupMemberData> getAllGroupMembers(String groupName) throws DataException;
|
public List<GroupMemberData> getAllGroupMembers(String groupName) throws DataException;
|
||||||
|
|
||||||
@ -41,6 +47,6 @@ public interface GroupRepository {
|
|||||||
|
|
||||||
public void save(GroupMemberData groupMemberData) throws DataException;
|
public void save(GroupMemberData groupMemberData) throws DataException;
|
||||||
|
|
||||||
public void delete(GroupMemberData groupMemberData) throws DataException;
|
public void deleteMember(String groupName, String address) throws DataException;
|
||||||
|
|
||||||
}
|
}
|
@ -416,12 +416,13 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
stmt.execute("CREATE INDEX AccountGroupOwnerIndex on AccountGroups (owner)");
|
stmt.execute("CREATE INDEX AccountGroupOwnerIndex on AccountGroups (owner)");
|
||||||
|
|
||||||
// Admins
|
// Admins
|
||||||
stmt.execute("CREATE TABLE AccountGroupAdmins (group_name GroupName, admin QoraAddress, PRIMARY KEY (group_name, admin))");
|
stmt.execute("CREATE TABLE AccountGroupAdmins (group_name GroupName, admin QoraAddress, group_reference Signature NOT NULL, PRIMARY KEY (group_name, admin))");
|
||||||
// For finding groups that address administrates
|
// For finding groups that address administrates
|
||||||
stmt.execute("CREATE INDEX AccountGroupAdminIndex on AccountGroupAdmins (admin)");
|
stmt.execute("CREATE INDEX AccountGroupAdminIndex on AccountGroupAdmins (admin)");
|
||||||
|
|
||||||
// Members
|
// Members
|
||||||
stmt.execute("CREATE TABLE AccountGroupMembers (group_name GroupName, address QoraAddress, joined TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY (group_name, address))");
|
stmt.execute("CREATE TABLE AccountGroupMembers (group_name GroupName, address QoraAddress, joined TIMESTAMP WITH TIME ZONE NOT NULL, group_reference Signature NOT NULL, "
|
||||||
|
+ "PRIMARY KEY (group_name, address))");
|
||||||
// For finding groups that address is member
|
// For finding groups that address is member
|
||||||
stmt.execute("CREATE INDEX AccountGroupMemberIndex on AccountGroupMembers (address)");
|
stmt.execute("CREATE INDEX AccountGroupMemberIndex on AccountGroupMembers (address)");
|
||||||
|
|
||||||
@ -450,13 +451,12 @@ public class HSQLDBDatabaseUpdates {
|
|||||||
stmt.execute("CREATE TABLE UpdateGroupTransactions (signature Signature, owner QoraPublicKey NOT NULL, group_name GroupName NOT NULL, "
|
stmt.execute("CREATE TABLE UpdateGroupTransactions (signature Signature, owner QoraPublicKey NOT NULL, group_name GroupName NOT NULL, "
|
||||||
+ "new_owner QoraAddress NOT NULL, new_description GenericDescription NOT NULL, new_is_open BOOLEAN NOT NULL, group_reference Signature, "
|
+ "new_owner QoraAddress NOT NULL, new_description GenericDescription NOT NULL, new_is_open BOOLEAN NOT NULL, group_reference Signature, "
|
||||||
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
// Account group join/leave transactions
|
// Account group join/leave transactions
|
||||||
stmt.execute("CREATE TABLE JoinGroupTransactions (signature Signature, joiner QoraPublicKey NOT NULL, group_name GroupName NOT NULL, "
|
stmt.execute("CREATE TABLE JoinGroupTransactions (signature Signature, joiner QoraPublicKey NOT NULL, group_name GroupName NOT NULL, "
|
||||||
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||||
stmt.execute("CREATE TABLE LeaveGroupTransactions (signature Signature, leaver QoraPublicKey NOT NULL, group_name GroupName NOT NULL, "
|
stmt.execute("CREATE TABLE LeaveGroupTransactions (signature Signature, leaver QoraPublicKey NOT NULL, group_name GroupName NOT NULL, "
|
||||||
|
+ "member_reference Signature, admin_reference Signature, "
|
||||||
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
+ "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -125,9 +125,9 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
Long updated = groupData.getUpdated();
|
Long updated = groupData.getUpdated();
|
||||||
Timestamp updatedTimestamp = updated == null ? null : new Timestamp(updated);
|
Timestamp updatedTimestamp = updated == null ? null : new Timestamp(updated);
|
||||||
|
|
||||||
saveHelper.bind("owner", groupData.getOwner()).bind("group_name", groupData.getGroupName())
|
saveHelper.bind("owner", groupData.getOwner()).bind("group_name", groupData.getGroupName()).bind("description", groupData.getDescription())
|
||||||
.bind("description", groupData.getDescription()).bind("created", new Timestamp(groupData.getCreated())).bind("updated", updatedTimestamp)
|
.bind("created", new Timestamp(groupData.getCreated())).bind("updated", updatedTimestamp).bind("reference", groupData.getReference())
|
||||||
.bind("reference", groupData.getReference()).bind("is_open", groupData.getIsOpen());
|
.bind("is_open", groupData.getIsOpen());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saveHelper.execute(this.repository);
|
saveHelper.execute(this.repository);
|
||||||
@ -156,18 +156,43 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
|
|
||||||
// Group Admins
|
// Group Admins
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroupAdminData getAdmin(String groupName, String address) throws DataException {
|
||||||
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT admin, group_reference FROM AccountGroupAdmins WHERE group_name = ?", groupName)) {
|
||||||
|
if (resultSet == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String admin = resultSet.getString(1);
|
||||||
|
byte[] groupReference = resultSet.getBytes(2);
|
||||||
|
|
||||||
|
return new GroupAdminData(groupName, admin, groupReference);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to fetch group admin from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean adminExists(String groupName, String address) throws DataException {
|
||||||
|
try {
|
||||||
|
return this.repository.exists("AccountGroupAdmins", "group_name = ? AND admin = ?", groupName, address);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to check for group admin in repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GroupAdminData> getAllGroupAdmins(String groupName) throws DataException {
|
public List<GroupAdminData> getAllGroupAdmins(String groupName) throws DataException {
|
||||||
List<GroupAdminData> admins = new ArrayList<>();
|
List<GroupAdminData> admins = new ArrayList<>();
|
||||||
|
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT admin FROM AccountGroupAdmins WHERE group_name = ?", groupName)) {
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT admin, group_reference FROM AccountGroupAdmins WHERE group_name = ?", groupName)) {
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return admins;
|
return admins;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
String admin = resultSet.getString(1);
|
String admin = resultSet.getString(1);
|
||||||
|
byte[] groupReference = resultSet.getBytes(2);
|
||||||
|
|
||||||
admins.add(new GroupAdminData(groupName, admin));
|
admins.add(new GroupAdminData(groupName, admin, groupReference));
|
||||||
} while (resultSet.next());
|
} while (resultSet.next());
|
||||||
|
|
||||||
return admins;
|
return admins;
|
||||||
@ -180,7 +205,8 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
public void save(GroupAdminData groupAdminData) throws DataException {
|
public void save(GroupAdminData groupAdminData) throws DataException {
|
||||||
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupAdmins");
|
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupAdmins");
|
||||||
|
|
||||||
saveHelper.bind("group_name", groupAdminData.getGroupName()).bind("admin", groupAdminData.getAdmin());
|
saveHelper.bind("group_name", groupAdminData.getGroupName()).bind("admin", groupAdminData.getAdmin()).bind("group_reference",
|
||||||
|
groupAdminData.getGroupReference());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saveHelper.execute(this.repository);
|
saveHelper.execute(this.repository);
|
||||||
@ -190,9 +216,9 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(GroupAdminData groupAdminData) throws DataException {
|
public void deleteAdmin(String groupName, String address) throws DataException {
|
||||||
try {
|
try {
|
||||||
this.repository.delete("AccountGroupAdmins", "group_name = ? AND admin = ?", groupAdminData.getGroupName(), groupAdminData.getAdmin());
|
this.repository.delete("AccountGroupAdmins", "group_name = ? AND admin = ?", groupName, address);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Unable to delete group admin info from repository", e);
|
throw new DataException("Unable to delete group admin info from repository", e);
|
||||||
}
|
}
|
||||||
@ -201,9 +227,26 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
// Group Members
|
// Group Members
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean memberExists(String groupName, String member) throws DataException {
|
public GroupMemberData getMember(String groupName, String address) throws DataException {
|
||||||
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT address, joined, group_reference FROM AccountGroupMembers WHERE group_name = ?",
|
||||||
|
groupName)) {
|
||||||
|
if (resultSet == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String member = resultSet.getString(1);
|
||||||
|
long joined = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)).getTime();
|
||||||
|
byte[] groupReference = resultSet.getBytes(3);
|
||||||
|
|
||||||
|
return new GroupMemberData(groupName, member, joined, groupReference);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to fetch group members from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean memberExists(String groupName, String address) throws DataException {
|
||||||
try {
|
try {
|
||||||
return this.repository.exists("AccountGroupMembers", "group_name = ? AND address = ?", groupName, member);
|
return this.repository.exists("AccountGroupMembers", "group_name = ? AND address = ?", groupName, address);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Unable to check for group member in repository", e);
|
throw new DataException("Unable to check for group member in repository", e);
|
||||||
}
|
}
|
||||||
@ -213,15 +256,17 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
public List<GroupMemberData> getAllGroupMembers(String groupName) throws DataException {
|
public List<GroupMemberData> getAllGroupMembers(String groupName) throws DataException {
|
||||||
List<GroupMemberData> members = new ArrayList<>();
|
List<GroupMemberData> members = new ArrayList<>();
|
||||||
|
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT address, joined FROM AccountGroupMembers WHERE group_name = ?", groupName)) {
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT address, joined, group_reference FROM AccountGroupMembers WHERE group_name = ?",
|
||||||
|
groupName)) {
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return members;
|
return members;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
String member = resultSet.getString(1);
|
String member = resultSet.getString(1);
|
||||||
long joined = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)).getTime();
|
long joined = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)).getTime();
|
||||||
|
byte[] groupReference = resultSet.getBytes(3);
|
||||||
|
|
||||||
members.add(new GroupMemberData(groupName, member, joined));
|
members.add(new GroupMemberData(groupName, member, joined, groupReference));
|
||||||
} while (resultSet.next());
|
} while (resultSet.next());
|
||||||
|
|
||||||
return members;
|
return members;
|
||||||
@ -232,7 +277,8 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer countGroupMembers(String groupName) throws DataException {
|
public Integer countGroupMembers(String groupName) throws DataException {
|
||||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_name, COUNT(*) FROM AccountGroupMembers WHERE group_name = ? GROUP BY group_name", groupName)) {
|
try (ResultSet resultSet = this.repository
|
||||||
|
.checkedExecute("SELECT group_name, COUNT(*) FROM AccountGroupMembers WHERE group_name = ? GROUP BY group_name", groupName)) {
|
||||||
if (resultSet == null)
|
if (resultSet == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -246,7 +292,8 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
public void save(GroupMemberData groupMemberData) throws DataException {
|
public void save(GroupMemberData groupMemberData) throws DataException {
|
||||||
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupMembers");
|
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupMembers");
|
||||||
|
|
||||||
saveHelper.bind("group_name", groupMemberData.getGroupName()).bind("address", groupMemberData.getMember()).bind("joined", new Timestamp(groupMemberData.getJoined()));
|
saveHelper.bind("group_name", groupMemberData.getGroupName()).bind("address", groupMemberData.getMember())
|
||||||
|
.bind("joined", new Timestamp(groupMemberData.getJoined())).bind("group_reference", groupMemberData.getGroupReference());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
saveHelper.execute(this.repository);
|
saveHelper.execute(this.repository);
|
||||||
@ -256,9 +303,9 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delete(GroupMemberData groupMemberData) throws DataException {
|
public void deleteMember(String groupName, String address) throws DataException {
|
||||||
try {
|
try {
|
||||||
this.repository.delete("AccountGroupMembers", "group_name = ? AND address = ?", groupMemberData.getGroupName(), groupMemberData.getMember());
|
this.repository.delete("AccountGroupMembers", "group_name = ? AND address = ?", groupName, address);
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new DataException("Unable to delete group member info from repository", e);
|
throw new DataException("Unable to delete group member info from repository", e);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package org.qora.repository.hsqldb.transaction;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||||
|
import org.qora.data.transaction.TransactionData;
|
||||||
|
import org.qora.repository.DataException;
|
||||||
|
import org.qora.repository.hsqldb.HSQLDBRepository;
|
||||||
|
import org.qora.repository.hsqldb.HSQLDBSaver;
|
||||||
|
|
||||||
|
public class HSQLDBLeaveGroupTransactionRepository extends HSQLDBTransactionRepository {
|
||||||
|
|
||||||
|
public HSQLDBLeaveGroupTransactionRepository(HSQLDBRepository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException {
|
||||||
|
try (ResultSet resultSet = this.repository
|
||||||
|
.checkedExecute("SELECT group_name, member_reference, admin_reference FROM LeaveGroupTransactions WHERE signature = ?", signature)) {
|
||||||
|
if (resultSet == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
String groupName = resultSet.getString(1);
|
||||||
|
byte[] memberReference = resultSet.getBytes(2);
|
||||||
|
byte[] adminReference = resultSet.getBytes(3);
|
||||||
|
|
||||||
|
return new LeaveGroupTransactionData(creatorPublicKey, groupName, memberReference, adminReference, fee, timestamp, reference, signature);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to fetch leave group transaction from repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(TransactionData transactionData) throws DataException {
|
||||||
|
LeaveGroupTransactionData leaveGroupTransactionData = (LeaveGroupTransactionData) transactionData;
|
||||||
|
|
||||||
|
HSQLDBSaver saveHelper = new HSQLDBSaver("LeaveGroupTransactions");
|
||||||
|
|
||||||
|
saveHelper.bind("signature", leaveGroupTransactionData.getSignature()).bind("leaver", leaveGroupTransactionData.getLeaverPublicKey())
|
||||||
|
.bind("group_name", leaveGroupTransactionData.getGroupName()).bind("member_reference", leaveGroupTransactionData.getMemberReference())
|
||||||
|
.bind("admin_reference", leaveGroupTransactionData.getAdminReference());
|
||||||
|
|
||||||
|
try {
|
||||||
|
saveHelper.execute(this.repository);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new DataException("Unable to save leave group transaction into repository", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -44,6 +44,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
private HSQLDBCreateGroupTransactionRepository createGroupTransactionRepository;
|
private HSQLDBCreateGroupTransactionRepository createGroupTransactionRepository;
|
||||||
private HSQLDBUpdateGroupTransactionRepository updateGroupTransactionRepository;
|
private HSQLDBUpdateGroupTransactionRepository updateGroupTransactionRepository;
|
||||||
private HSQLDBJoinGroupTransactionRepository joinGroupTransactionRepository;
|
private HSQLDBJoinGroupTransactionRepository joinGroupTransactionRepository;
|
||||||
|
private HSQLDBLeaveGroupTransactionRepository leaveGroupTransactionRepository;
|
||||||
|
|
||||||
public HSQLDBTransactionRepository(HSQLDBRepository repository) {
|
public HSQLDBTransactionRepository(HSQLDBRepository repository) {
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
@ -68,6 +69,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
this.createGroupTransactionRepository = new HSQLDBCreateGroupTransactionRepository(repository);
|
this.createGroupTransactionRepository = new HSQLDBCreateGroupTransactionRepository(repository);
|
||||||
this.updateGroupTransactionRepository = new HSQLDBUpdateGroupTransactionRepository(repository);
|
this.updateGroupTransactionRepository = new HSQLDBUpdateGroupTransactionRepository(repository);
|
||||||
this.joinGroupTransactionRepository = new HSQLDBJoinGroupTransactionRepository(repository);
|
this.joinGroupTransactionRepository = new HSQLDBJoinGroupTransactionRepository(repository);
|
||||||
|
this.leaveGroupTransactionRepository = new HSQLDBLeaveGroupTransactionRepository(repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HSQLDBTransactionRepository() {
|
protected HSQLDBTransactionRepository() {
|
||||||
@ -203,6 +205,9 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return this.joinGroupTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
return this.joinGroupTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return this.leaveGroupTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new DataException("Unsupported transaction type [" + type.name() + "] during fetch from HSQLDB repository");
|
throw new DataException("Unsupported transaction type [" + type.name() + "] during fetch from HSQLDB repository");
|
||||||
}
|
}
|
||||||
@ -535,6 +540,10 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
|||||||
this.joinGroupTransactionRepository.save(transactionData);
|
this.joinGroupTransactionRepository.save(transactionData);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
this.leaveGroupTransactionRepository.save(transactionData);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new DataException("Unsupported transaction type [" + transactionData.getType().name() + "] during save into HSQLDB repository");
|
throw new DataException("Unsupported transaction type [" + transactionData.getType().name() + "] during save into HSQLDB repository");
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ public class CreateGroupTransaction extends Transaction {
|
|||||||
public void process() throws DataException {
|
public void process() throws DataException {
|
||||||
// Create Group
|
// Create Group
|
||||||
Group group = new Group(this.repository, createGroupTransactionData);
|
Group group = new Group(this.repository, createGroupTransactionData);
|
||||||
group.create();
|
group.create(createGroupTransactionData);
|
||||||
|
|
||||||
// Save this transaction
|
// Save this transaction
|
||||||
this.repository.getTransactionRepository().save(createGroupTransactionData);
|
this.repository.getTransactionRepository().save(createGroupTransactionData);
|
||||||
|
143
src/main/java/org/qora/transaction/LeaveGroupTransaction.java
Normal file
143
src/main/java/org/qora/transaction/LeaveGroupTransaction.java
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package org.qora.transaction;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.qora.account.Account;
|
||||||
|
import org.qora.account.PublicKeyAccount;
|
||||||
|
import org.qora.asset.Asset;
|
||||||
|
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||||
|
import org.qora.data.group.GroupData;
|
||||||
|
import org.qora.data.transaction.TransactionData;
|
||||||
|
import org.qora.group.Group;
|
||||||
|
import org.qora.repository.DataException;
|
||||||
|
import org.qora.repository.Repository;
|
||||||
|
|
||||||
|
import com.google.common.base.Utf8;
|
||||||
|
|
||||||
|
public class LeaveGroupTransaction extends Transaction {
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
private LeaveGroupTransactionData leaveGroupTransactionData;
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
public LeaveGroupTransaction(Repository repository, TransactionData transactionData) {
|
||||||
|
super(repository, transactionData);
|
||||||
|
|
||||||
|
this.leaveGroupTransactionData = (LeaveGroupTransactionData) this.transactionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// More information
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Account> getRecipientAccounts() throws DataException {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInvolved(Account account) throws DataException {
|
||||||
|
String address = account.getAddress();
|
||||||
|
|
||||||
|
if (address.equals(this.getLeaver().getAddress()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal getAmount(Account account) throws DataException {
|
||||||
|
String address = account.getAddress();
|
||||||
|
BigDecimal amount = BigDecimal.ZERO.setScale(8);
|
||||||
|
|
||||||
|
if (address.equals(this.getLeaver().getAddress()))
|
||||||
|
amount = amount.subtract(this.transactionData.getFee());
|
||||||
|
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
|
||||||
|
public Account getLeaver() throws DataException {
|
||||||
|
return new PublicKeyAccount(this.repository, this.leaveGroupTransactionData.getLeaverPublicKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Processing
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidationResult isValid() throws DataException {
|
||||||
|
// Check group name size bounds
|
||||||
|
int groupNameLength = Utf8.encodedLength(leaveGroupTransactionData.getGroupName());
|
||||||
|
if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE)
|
||||||
|
return ValidationResult.INVALID_NAME_LENGTH;
|
||||||
|
|
||||||
|
// Check group name is lowercase
|
||||||
|
if (!leaveGroupTransactionData.getGroupName().equals(leaveGroupTransactionData.getGroupName().toLowerCase()))
|
||||||
|
return ValidationResult.NAME_NOT_LOWER_CASE;
|
||||||
|
|
||||||
|
GroupData groupData = this.repository.getGroupRepository().fromGroupName(leaveGroupTransactionData.getGroupName());
|
||||||
|
|
||||||
|
// Check group exists
|
||||||
|
if (groupData == null)
|
||||||
|
return ValidationResult.GROUP_DOES_NOT_EXIST;
|
||||||
|
|
||||||
|
Account leaver = getLeaver();
|
||||||
|
|
||||||
|
// Can't leave if group owner
|
||||||
|
if (leaver.getAddress().equals(groupData.getOwner()))
|
||||||
|
return ValidationResult.GROUP_OWNER_CANNOT_LEAVE;
|
||||||
|
|
||||||
|
if (!this.repository.getGroupRepository().memberExists(leaveGroupTransactionData.getGroupName(), leaver.getAddress()))
|
||||||
|
return ValidationResult.NOT_GROUP_MEMBER;
|
||||||
|
|
||||||
|
// Check fee is positive
|
||||||
|
if (leaveGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||||
|
return ValidationResult.NEGATIVE_FEE;
|
||||||
|
|
||||||
|
if (!Arrays.equals(leaver.getLastReference(), leaveGroupTransactionData.getReference()))
|
||||||
|
return ValidationResult.INVALID_REFERENCE;
|
||||||
|
|
||||||
|
// Check creator has enough funds
|
||||||
|
if (leaver.getConfirmedBalance(Asset.QORA).compareTo(leaveGroupTransactionData.getFee()) < 0)
|
||||||
|
return ValidationResult.NO_BALANCE;
|
||||||
|
|
||||||
|
return ValidationResult.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process() throws DataException {
|
||||||
|
// Update Group Membership
|
||||||
|
Group group = new Group(this.repository, leaveGroupTransactionData.getGroupName());
|
||||||
|
group.leave(leaveGroupTransactionData);
|
||||||
|
|
||||||
|
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||||
|
this.repository.getTransactionRepository().save(leaveGroupTransactionData);
|
||||||
|
|
||||||
|
// Update leaver's balance
|
||||||
|
Account leaver = getLeaver();
|
||||||
|
leaver.setConfirmedBalance(Asset.QORA, leaver.getConfirmedBalance(Asset.QORA).subtract(leaveGroupTransactionData.getFee()));
|
||||||
|
|
||||||
|
// Update leaver's reference
|
||||||
|
leaver.setLastReference(leaveGroupTransactionData.getSignature());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void orphan() throws DataException {
|
||||||
|
// Revert group membership
|
||||||
|
Group group = new Group(this.repository, leaveGroupTransactionData.getGroupName());
|
||||||
|
group.unleave(leaveGroupTransactionData);
|
||||||
|
|
||||||
|
// Delete this transaction itself
|
||||||
|
this.repository.getTransactionRepository().delete(leaveGroupTransactionData);
|
||||||
|
|
||||||
|
// Update leaver's balance
|
||||||
|
Account leaver = getLeaver();
|
||||||
|
leaver.setConfirmedBalance(Asset.QORA, leaver.getConfirmedBalance(Asset.QORA).add(leaveGroupTransactionData.getFee()));
|
||||||
|
|
||||||
|
// Update leaver's reference
|
||||||
|
leaver.setLastReference(leaveGroupTransactionData.getReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -129,6 +129,8 @@ public abstract class Transaction {
|
|||||||
GROUP_DOES_NOT_EXIST(49),
|
GROUP_DOES_NOT_EXIST(49),
|
||||||
INVALID_GROUP_OWNER(50),
|
INVALID_GROUP_OWNER(50),
|
||||||
ALREADY_GROUP_MEMBER(51),
|
ALREADY_GROUP_MEMBER(51),
|
||||||
|
GROUP_OWNER_CANNOT_LEAVE(52),
|
||||||
|
NOT_GROUP_MEMBER(53),
|
||||||
NOT_YET_RELEASED(1000);
|
NOT_YET_RELEASED(1000);
|
||||||
|
|
||||||
public final int value;
|
public final int value;
|
||||||
@ -237,6 +239,9 @@ public abstract class Transaction {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return new JoinGroupTransaction(repository, transactionData);
|
return new JoinGroupTransaction(repository, transactionData);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return new LeaveGroupTransaction(repository, transactionData);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unsupported transaction type [" + transactionData.getType().value + "] during fetch from repository");
|
throw new IllegalStateException("Unsupported transaction type [" + transactionData.getType().value + "] during fetch from repository");
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
package org.qora.transform.transaction;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.qora.account.PublicKeyAccount;
|
||||||
|
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||||
|
import org.qora.data.transaction.TransactionData;
|
||||||
|
import org.qora.group.Group;
|
||||||
|
import org.qora.transform.TransformationException;
|
||||||
|
import org.qora.utils.Serialization;
|
||||||
|
|
||||||
|
import com.google.common.base.Utf8;
|
||||||
|
import com.google.common.hash.HashCode;
|
||||||
|
import com.google.common.primitives.Ints;
|
||||||
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
|
public class LeaveGroupTransactionTransformer extends TransactionTransformer {
|
||||||
|
|
||||||
|
// Property lengths
|
||||||
|
private static final int JOINER_LENGTH = PUBLIC_KEY_LENGTH;
|
||||||
|
private static final int NAME_SIZE_LENGTH = INT_LENGTH;
|
||||||
|
|
||||||
|
private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + JOINER_LENGTH + NAME_SIZE_LENGTH;
|
||||||
|
|
||||||
|
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||||
|
long timestamp = byteBuffer.getLong();
|
||||||
|
|
||||||
|
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||||
|
byteBuffer.get(reference);
|
||||||
|
|
||||||
|
byte[] leaverPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||||
|
|
||||||
|
String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE);
|
||||||
|
|
||||||
|
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||||
|
|
||||||
|
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||||
|
byteBuffer.get(signature);
|
||||||
|
|
||||||
|
return new LeaveGroupTransactionData(leaverPublicKey, groupName, fee, timestamp, reference, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDataLength(TransactionData transactionData) throws TransformationException {
|
||||||
|
LeaveGroupTransactionData leaveGroupTransactionData = (LeaveGroupTransactionData) transactionData;
|
||||||
|
|
||||||
|
int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(leaveGroupTransactionData.getGroupName());
|
||||||
|
|
||||||
|
return dataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||||
|
try {
|
||||||
|
LeaveGroupTransactionData leaveGroupTransactionData = (LeaveGroupTransactionData) transactionData;
|
||||||
|
|
||||||
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
bytes.write(Ints.toByteArray(leaveGroupTransactionData.getType().value));
|
||||||
|
bytes.write(Longs.toByteArray(leaveGroupTransactionData.getTimestamp()));
|
||||||
|
bytes.write(leaveGroupTransactionData.getReference());
|
||||||
|
|
||||||
|
bytes.write(leaveGroupTransactionData.getCreatorPublicKey());
|
||||||
|
Serialization.serializeSizedString(bytes, leaveGroupTransactionData.getGroupName());
|
||||||
|
|
||||||
|
Serialization.serializeBigDecimal(bytes, leaveGroupTransactionData.getFee());
|
||||||
|
|
||||||
|
if (leaveGroupTransactionData.getSignature() != null)
|
||||||
|
bytes.write(leaveGroupTransactionData.getSignature());
|
||||||
|
|
||||||
|
return bytes.toByteArray();
|
||||||
|
} catch (IOException | ClassCastException e) {
|
||||||
|
throw new TransformationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static JSONObject toJSON(TransactionData transactionData) throws TransformationException {
|
||||||
|
JSONObject json = TransactionTransformer.getBaseJSON(transactionData);
|
||||||
|
|
||||||
|
try {
|
||||||
|
LeaveGroupTransactionData leaveGroupTransactionData = (LeaveGroupTransactionData) transactionData;
|
||||||
|
|
||||||
|
byte[] leaverPublicKey = leaveGroupTransactionData.getLeaverPublicKey();
|
||||||
|
|
||||||
|
json.put("leaver", PublicKeyAccount.getAddress(leaverPublicKey));
|
||||||
|
json.put("leaverPublicKey", HashCode.fromBytes(leaverPublicKey).toString());
|
||||||
|
|
||||||
|
json.put("groupName", leaveGroupTransactionData.getGroupName());
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new TransformationException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -103,6 +103,9 @@ public class TransactionTransformer extends Transformer {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return JoinGroupTransactionTransformer.fromByteBuffer(byteBuffer);
|
return JoinGroupTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return LeaveGroupTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TransformationException("Unsupported transaction type [" + type.value + "] during conversion from bytes");
|
throw new TransformationException("Unsupported transaction type [" + type.value + "] during conversion from bytes");
|
||||||
}
|
}
|
||||||
@ -173,6 +176,9 @@ public class TransactionTransformer extends Transformer {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return JoinGroupTransactionTransformer.getDataLength(transactionData);
|
return JoinGroupTransactionTransformer.getDataLength(transactionData);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return LeaveGroupTransactionTransformer.getDataLength(transactionData);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TransformationException("Unsupported transaction type [" + transactionData.getType().value + "] when requesting byte length");
|
throw new TransformationException("Unsupported transaction type [" + transactionData.getType().value + "] when requesting byte length");
|
||||||
}
|
}
|
||||||
@ -240,6 +246,9 @@ public class TransactionTransformer extends Transformer {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return JoinGroupTransactionTransformer.toBytes(transactionData);
|
return JoinGroupTransactionTransformer.toBytes(transactionData);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return LeaveGroupTransactionTransformer.toBytes(transactionData);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TransformationException("Unsupported transaction type [" + transactionData.getType().value + "] during conversion to bytes");
|
throw new TransformationException("Unsupported transaction type [" + transactionData.getType().value + "] during conversion to bytes");
|
||||||
}
|
}
|
||||||
@ -316,6 +325,9 @@ public class TransactionTransformer extends Transformer {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return JoinGroupTransactionTransformer.toBytesForSigningImpl(transactionData);
|
return JoinGroupTransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return LeaveGroupTransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TransformationException(
|
throw new TransformationException(
|
||||||
"Unsupported transaction type [" + transactionData.getType().value + "] during conversion to bytes for signing");
|
"Unsupported transaction type [" + transactionData.getType().value + "] during conversion to bytes for signing");
|
||||||
@ -404,6 +416,9 @@ public class TransactionTransformer extends Transformer {
|
|||||||
case JOIN_GROUP:
|
case JOIN_GROUP:
|
||||||
return JoinGroupTransactionTransformer.toJSON(transactionData);
|
return JoinGroupTransactionTransformer.toJSON(transactionData);
|
||||||
|
|
||||||
|
case LEAVE_GROUP:
|
||||||
|
return LeaveGroupTransactionTransformer.toJSON(transactionData);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new TransformationException("Unsupported transaction type [" + transactionData.getType().value + "] during conversion to JSON");
|
throw new TransformationException("Unsupported transaction type [" + transactionData.getType().value + "] during conversion to JSON");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user