diff --git a/src/main/java/org/qora/api/model/GroupWithMemberInfo.java b/src/main/java/org/qora/api/model/GroupWithMemberInfo.java index 85c669d4..25d523d2 100644 --- a/src/main/java/org/qora/api/model/GroupWithMemberInfo.java +++ b/src/main/java/org/qora/api/model/GroupWithMemberInfo.java @@ -25,14 +25,30 @@ public class GroupWithMemberInfo { @XmlElement(name = "admins") public List groupAdminAddresses; + @XmlAccessorType(XmlAccessType.FIELD) + @Schema(description = "Member info") + public static class MemberInfo { + public String member; + public long joined; + + // For JAX-RS + protected MemberInfo() { + } + + public MemberInfo(GroupMemberData groupMemberData) { + this.member = groupMemberData.getMember(); + this.joined = groupMemberData.getJoined(); + } + } + @XmlElement(name = "members") - public List groupMembers; + public List groupMembers; // For JAX-RS protected GroupWithMemberInfo() { } - public GroupWithMemberInfo(GroupData groupData, List groupAdminAddresses, List groupMembers, Integer memberCount) { + public GroupWithMemberInfo(GroupData groupData, List groupAdminAddresses, List groupMembers, Integer memberCount) { this.groupData = groupData; this.groupAdminAddresses = groupAdminAddresses; this.groupMembers = groupMembers; diff --git a/src/main/java/org/qora/api/resource/GroupsResource.java b/src/main/java/org/qora/api/resource/GroupsResource.java index f33fe661..1ee4b4f4 100644 --- a/src/main/java/org/qora/api/resource/GroupsResource.java +++ b/src/main/java/org/qora/api/resource/GroupsResource.java @@ -26,6 +26,7 @@ import org.qora.api.ApiError; import org.qora.api.ApiErrors; import org.qora.api.ApiExceptionFactory; import org.qora.api.model.GroupWithMemberInfo; +import org.qora.api.model.GroupWithMemberInfo.MemberInfo; import org.qora.crypto.Crypto; import org.qora.data.group.GroupAdminData; import org.qora.data.group.GroupBanData; @@ -39,7 +40,7 @@ import org.qora.data.transaction.CreateGroupTransactionData; import org.qora.data.transaction.GroupBanTransactionData; import org.qora.data.transaction.GroupInviteTransactionData; import org.qora.data.transaction.GroupKickTransactionData; -import org.qora.data.transaction.GroupUnbanTransactionData; +import org.qora.data.transaction.CancelGroupBanTransactionData; import org.qora.data.transaction.JoinGroupTransactionData; import org.qora.data.transaction.LeaveGroupTransactionData; import org.qora.data.transaction.RemoveGroupAdminTransactionData; @@ -56,7 +57,7 @@ import org.qora.transform.transaction.CreateGroupTransactionTransformer; import org.qora.transform.transaction.GroupBanTransactionTransformer; import org.qora.transform.transaction.GroupInviteTransactionTransformer; import org.qora.transform.transaction.GroupKickTransactionTransformer; -import org.qora.transform.transaction.GroupUnbanTransactionTransformer; +import org.qora.transform.transaction.CancelGroupBanTransactionTransformer; import org.qora.transform.transaction.JoinGroupTransactionTransformer; import org.qora.transform.transaction.LeaveGroupTransactionTransformer; import org.qora.transform.transaction.RemoveGroupAdminTransactionTransformer; @@ -101,7 +102,7 @@ public class GroupsResource { } @GET - @Path("/address/{address}") + @Path("/owner/{address}") @Operation( summary = "List all groups owned by address", responses = { @@ -115,12 +116,40 @@ public class GroupsResource { } ) @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) - public List getGroupsByAddress(@PathParam("address") String address) { - if (!Crypto.isValidAddress(address)) + public List getGroupsByOwner(@PathParam("address") String owner) { + if (!Crypto.isValidAddress(owner)) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); try (final Repository repository = RepositoryManager.getRepository()) { - List groups = repository.getGroupRepository().getGroupsByOwner(address); + List groups = repository.getGroupRepository().getGroupsByOwner(owner); + + return groups; + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } + } + + @GET + @Path("/member/{address}") + @Operation( + summary = "List all groups where address is a member", + responses = { + @ApiResponse( + description = "group info", + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + array = @ArraySchema(schema = @Schema(implementation = GroupData.class)) + ) + ) + } + ) + @ApiErrors({ApiError.INVALID_ADDRESS, ApiError.REPOSITORY_ISSUE}) + public List getGroupsWithMember(@PathParam("address") String member) { + if (!Crypto.isValidAddress(member)) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS); + + try (final Repository repository = RepositoryManager.getRepository()) { + List groups = repository.getGroupRepository().getGroupsWithMember(member); return groups; } catch (DataException e) { @@ -149,28 +178,28 @@ public class GroupsResource { if (groupData == null) throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.GROUP_UNKNOWN); - List groupMembers = null; + List members = null; Integer memberCount = null; if (includeMembers) { - groupMembers = repository.getGroupRepository().getGroupMembers(groupData.getGroupName()); + List groupMembers = repository.getGroupRepository().getGroupMembers(groupData.getGroupId()); - // Strip groupName from member info - groupMembers = groupMembers.stream().map(groupMemberData -> new GroupMemberData(null, groupMemberData.getMember(), groupMemberData.getJoined(), null)).collect(Collectors.toList()); + // Convert to MemberInfo + members = groupMembers.stream().map(groupMemberData -> new MemberInfo(groupMemberData)).collect(Collectors.toList()); - memberCount = groupMembers.size(); + memberCount = members.size(); } else { // Just count members instead - memberCount = repository.getGroupRepository().countGroupMembers(groupData.getGroupName()); + memberCount = repository.getGroupRepository().countGroupMembers(groupData.getGroupId()); } // Always include admins - List groupAdmins = repository.getGroupRepository().getGroupAdmins(groupData.getGroupName()); + List groupAdmins = repository.getGroupRepository().getGroupAdmins(groupData.getGroupId()); // We only need admin addresses - List groupAdminAddresses = groupAdmins.stream().map(groupAdminData -> groupAdminData.getAdmin()).collect(Collectors.toList()); + List adminAddresses = groupAdmins.stream().map(groupAdminData -> groupAdminData.getAdmin()).collect(Collectors.toList()); - return new GroupWithMemberInfo(groupData, groupAdminAddresses, groupMembers, memberCount); + return new GroupWithMemberInfo(groupData, adminAddresses, members, memberCount); } catch (DataException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } @@ -393,21 +422,21 @@ public class GroupsResource { } @POST - @Path("/unban") + @Path("/ban/cancel") @Operation( - summary = "Build raw, unsigned, GROUP_UNBAN transaction", + summary = "Build raw, unsigned, CANCEL_GROUP_BAN transaction", requestBody = @RequestBody( required = true, content = @Content( mediaType = MediaType.APPLICATION_JSON, schema = @Schema( - implementation = GroupUnbanTransactionData.class + implementation = CancelGroupBanTransactionData.class ) ) ), responses = { @ApiResponse( - description = "raw, unsigned, GROUP_UNBAN transaction encoded in Base58", + description = "raw, unsigned, CANCEL_GROUP_BAN transaction encoded in Base58", content = @Content( mediaType = MediaType.TEXT_PLAIN, schema = @Schema( @@ -418,7 +447,7 @@ public class GroupsResource { } ) @ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE}) - public String groupBan(GroupUnbanTransactionData transactionData) { + public String cancelGroupBan(CancelGroupBanTransactionData transactionData) { try (final Repository repository = RepositoryManager.getRepository()) { Transaction transaction = Transaction.fromData(repository, transactionData); @@ -426,7 +455,7 @@ public class GroupsResource { if (result != ValidationResult.OK) throw TransactionsResource.createTransactionInvalidException(request, result); - byte[] bytes = GroupUnbanTransactionTransformer.toBytes(transactionData); + byte[] bytes = CancelGroupBanTransactionTransformer.toBytes(transactionData); return Base58.encode(bytes); } catch (TransformationException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e); @@ -651,7 +680,7 @@ public class GroupsResource { } @GET - @Path("/invites/{groupname}") + @Path("/invites/{groupid}") @Operation( summary = "Pending group invites", responses = { @@ -665,16 +694,16 @@ public class GroupsResource { } ) @ApiErrors({ApiError.REPOSITORY_ISSUE}) - public List getInvites(@PathParam("groupname") String groupName) { + public List getInvites(@PathParam("groupid") int groupId) { try (final Repository repository = RepositoryManager.getRepository()) { - return repository.getGroupRepository().getGroupInvites(groupName); + return repository.getGroupRepository().getGroupInvites(groupId); } catch (DataException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @GET - @Path("/joinrequests/{groupname}") + @Path("/joinrequests/{groupid}") @Operation( summary = "Pending group join requests", responses = { @@ -688,16 +717,16 @@ public class GroupsResource { } ) @ApiErrors({ApiError.REPOSITORY_ISSUE}) - public List getJoinRequests(@PathParam("groupname") String groupName) { + public List getJoinRequests(@PathParam("groupid") int groupId) { try (final Repository repository = RepositoryManager.getRepository()) { - return repository.getGroupRepository().getGroupJoinRequests(groupName); + return repository.getGroupRepository().getGroupJoinRequests(groupId); } catch (DataException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } } @GET - @Path("/bans/{groupname}") + @Path("/bans/{groupid}") @Operation( summary = "Current group join bans", responses = { @@ -711,9 +740,9 @@ public class GroupsResource { } ) @ApiErrors({ApiError.REPOSITORY_ISSUE}) - public List getBans(@PathParam("groupname") String groupName) { + public List getBans(@PathParam("groupid") int groupId) { try (final Repository repository = RepositoryManager.getRepository()) { - return repository.getGroupRepository().getGroupBans(groupName); + return repository.getGroupRepository().getGroupBans(groupId); } catch (DataException e) { throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); } diff --git a/src/main/java/org/qora/data/group/GroupAdminData.java b/src/main/java/org/qora/data/group/GroupAdminData.java index e97347a6..d5803423 100644 --- a/src/main/java/org/qora/data/group/GroupAdminData.java +++ b/src/main/java/org/qora/data/group/GroupAdminData.java @@ -9,12 +9,12 @@ import javax.xml.bind.annotation.XmlTransient; public class GroupAdminData { // Properties - private String groupName; + private int groupId; private String admin; - /** Reference to transaction that triggered adminship */ + /** Reference to transaction that triggered adminship. Could be JOIN_GROUP, GROUP_INVITE, CREATE_GROUP or others... */ // No need to ever expose this via API @XmlTransient - private byte[] groupReference; + private byte[] reference; // Constructors @@ -22,28 +22,28 @@ public class GroupAdminData { protected GroupAdminData() { } - public GroupAdminData(String groupName, String admin, byte[] groupReference) { - this.groupName = groupName; + public GroupAdminData(int groupId, String admin, byte[] reference) { + this.groupId = groupId; this.admin = admin; - this.groupReference = groupReference; + this.reference = reference; } // Getters / setters - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getAdmin() { return this.admin; } - public byte[] getGroupReference() { - return this.groupReference; + public byte[] getReference() { + return this.reference; } - public void setGroupReference(byte[] groupReference) { - this.groupReference = groupReference; + public void setReference(byte[] reference) { + this.reference = reference; } } diff --git a/src/main/java/org/qora/data/group/GroupBanData.java b/src/main/java/org/qora/data/group/GroupBanData.java index 207d8f10..6f956acd 100644 --- a/src/main/java/org/qora/data/group/GroupBanData.java +++ b/src/main/java/org/qora/data/group/GroupBanData.java @@ -9,12 +9,13 @@ import javax.xml.bind.annotation.XmlTransient; public class GroupBanData { // Properties - private String groupName; + private int groupId; private String offender; private String admin; private long banned; private String reason; private Long expiry; + /** Reference to GROUP_BAN transaction, used to rebuild this ban during orphaning. */ // No need to ever expose this via API @XmlTransient private byte[] reference; @@ -25,8 +26,8 @@ public class GroupBanData { protected GroupBanData() { } - public GroupBanData(String groupName, String offender, String admin, long banned, String reason, Long expiry, byte[] reference) { - this.groupName = groupName; + public GroupBanData(int groupId, String offender, String admin, long banned, String reason, Long expiry, byte[] reference) { + this.groupId = groupId; this.offender = offender; this.admin = admin; this.banned = banned; @@ -37,8 +38,8 @@ public class GroupBanData { // Getters / setters - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getOffender() { diff --git a/src/main/java/org/qora/data/group/GroupData.java b/src/main/java/org/qora/data/group/GroupData.java index 7b777182..1662f834 100644 --- a/src/main/java/org/qora/data/group/GroupData.java +++ b/src/main/java/org/qora/data/group/GroupData.java @@ -9,13 +9,14 @@ import javax.xml.bind.annotation.XmlTransient; public class GroupData { // Properties + private Integer groupId; private String owner; private String groupName; private String description; private long created; private Long updated; private boolean isOpen; - /** Reference to transaction that created group */ + /** Reference to CREATE_GROUP or UPDATE_GROUP transaction, used to rebuild group during orphaning. */ // No need to ever expose this via API @XmlTransient private byte[] reference; @@ -26,7 +27,9 @@ public class GroupData { protected GroupData() { } - public GroupData(String owner, String name, String description, long created, Long updated, boolean isOpen, byte[] reference) { + /** Constructs new GroupData with nullable groupId and nullable updated [timestamp] */ + public GroupData(Integer groupId, String owner, String name, String description, long created, Long updated, boolean isOpen, byte[] reference) { + this.groupId = groupId; this.owner = owner; this.groupName = name; this.description = description; @@ -36,12 +39,21 @@ public class GroupData { this.reference = reference; } + /** Constructs new GroupData with unassigned groupId */ public GroupData(String owner, String name, String description, long created, boolean isOpen, byte[] reference) { - this(owner, name, description, created, null, isOpen, reference); + this(null, owner, name, description, created, null, isOpen, reference); } // Getters / setters + public Integer getGroupId() { + return this.groupId; + } + + public void setGroupId(Integer groupId) { + this.groupId = groupId; + } + public String getOwner() { return this.owner; } diff --git a/src/main/java/org/qora/data/group/GroupInviteData.java b/src/main/java/org/qora/data/group/GroupInviteData.java index 9e4acccb..735cb017 100644 --- a/src/main/java/org/qora/data/group/GroupInviteData.java +++ b/src/main/java/org/qora/data/group/GroupInviteData.java @@ -9,10 +9,11 @@ import javax.xml.bind.annotation.XmlTransient; public class GroupInviteData { // Properties - private String groupName; + private int groupId; private String inviter; private String invitee; private Long expiry; + /** Reference to GROUP_INVITE transaction, used to rebuild this invite during orphaning. */ // No need to ever expose this via API @XmlTransient private byte[] reference; @@ -23,8 +24,8 @@ public class GroupInviteData { protected GroupInviteData() { } - public GroupInviteData(String groupName, String inviter, String invitee, Long expiry, byte[] reference) { - this.groupName = groupName; + public GroupInviteData(int groupId, String inviter, String invitee, Long expiry, byte[] reference) { + this.groupId = groupId; this.inviter = inviter; this.invitee = invitee; this.expiry = expiry; @@ -33,8 +34,8 @@ public class GroupInviteData { // Getters / setters - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getInviter() { diff --git a/src/main/java/org/qora/data/group/GroupJoinRequestData.java b/src/main/java/org/qora/data/group/GroupJoinRequestData.java index 2c275c74..69c86301 100644 --- a/src/main/java/org/qora/data/group/GroupJoinRequestData.java +++ b/src/main/java/org/qora/data/group/GroupJoinRequestData.java @@ -2,14 +2,19 @@ package org.qora.data.group; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlTransient; // All properties to be converted to JSON via JAX-RS @XmlAccessorType(XmlAccessType.FIELD) public class GroupJoinRequestData { // Properties - private String groupName; + private int groupId; private String joiner; + /** Reference to JOIN_GROUP transaction, used to rebuild this join request during orphaning. */ + // No need to ever expose this via API + @XmlTransient + private byte[] reference; // Constructors @@ -17,19 +22,28 @@ public class GroupJoinRequestData { protected GroupJoinRequestData() { } - public GroupJoinRequestData(String groupName, String joiner) { - this.groupName = groupName; + public GroupJoinRequestData(int groupId, String joiner, byte[] reference) { + this.groupId = groupId; this.joiner = joiner; + this.reference = reference; } // Getters / setters - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getJoiner() { return this.joiner; } + public byte[] getReference() { + return this.reference; + } + + public void setReference(byte[] reference) { + this.reference = reference; + } + } diff --git a/src/main/java/org/qora/data/group/GroupMemberData.java b/src/main/java/org/qora/data/group/GroupMemberData.java index f81adac2..e1c048ff 100644 --- a/src/main/java/org/qora/data/group/GroupMemberData.java +++ b/src/main/java/org/qora/data/group/GroupMemberData.java @@ -9,13 +9,13 @@ import javax.xml.bind.annotation.XmlTransient; public class GroupMemberData { // Properties - private String groupName; + private int groupId; private String member; private long joined; - /** Reference to transaction that triggered membership */ + /** Reference to transaction that triggered membership. Could be JOIN_GROUP, GROUP_INVITE, CREATE_GROUP or others... */ // No need to ever expose this via API @XmlTransient - private byte[] groupReference; + private byte[] reference; // Constructors @@ -23,17 +23,17 @@ public class GroupMemberData { protected GroupMemberData() { } - public GroupMemberData(String groupName, String member, long joined, byte[] groupReference) { - this.groupName = groupName; + public GroupMemberData(int groupId, String member, long joined, byte[] reference) { + this.groupId = groupId; this.member = member; this.joined = joined; - this.groupReference = groupReference; + this.reference = reference; } // Getters / setters - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getMember() { @@ -44,12 +44,12 @@ public class GroupMemberData { return this.joined; } - public byte[] getGroupReference() { - return this.groupReference; + public byte[] getReference() { + return this.reference; } - public void setGroupReference(byte[] groupReference) { - this.groupReference = groupReference; + public void setReference(byte[] reference) { + this.reference = reference; } } diff --git a/src/main/java/org/qora/data/transaction/AddGroupAdminTransactionData.java b/src/main/java/org/qora/data/transaction/AddGroupAdminTransactionData.java index 12a1f916..876e2b48 100644 --- a/src/main/java/org/qora/data/transaction/AddGroupAdminTransactionData.java +++ b/src/main/java/org/qora/data/transaction/AddGroupAdminTransactionData.java @@ -18,8 +18,8 @@ public class AddGroupAdminTransactionData extends TransactionData { // Properties @Schema(description = "group owner's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") private byte[] ownerPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; + @Schema(description = "group ID") + private int groupId; @Schema(description = "member to promote to admin", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") private String member; @@ -34,26 +34,22 @@ public class AddGroupAdminTransactionData extends TransactionData { this.creatorPublicKey = this.ownerPublicKey; } - public AddGroupAdminTransactionData(byte[] ownerPublicKey, String groupName, String member, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public AddGroupAdminTransactionData(byte[] ownerPublicKey, int groupId, String member, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.ADD_GROUP_ADMIN, fee, ownerPublicKey, timestamp, reference, signature); this.ownerPublicKey = ownerPublicKey; - this.groupName = groupName; + this.groupId = groupId; this.member = member; } - public AddGroupAdminTransactionData(byte[] ownerPublicKey, String groupName, String member, BigDecimal fee, long timestamp, byte[] reference) { - this(ownerPublicKey, groupName, member, fee, timestamp, reference, null); - } - // Getters / setters public byte[] getOwnerPublicKey() { return this.ownerPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getMember() { diff --git a/src/main/java/org/qora/data/transaction/CancelGroupBanTransactionData.java b/src/main/java/org/qora/data/transaction/CancelGroupBanTransactionData.java new file mode 100644 index 00000000..4366a808 --- /dev/null +++ b/src/main/java/org/qora/data/transaction/CancelGroupBanTransactionData.java @@ -0,0 +1,78 @@ +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 CancelGroupBanTransactionData extends TransactionData { + + // Properties + @Schema(description = "admin's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") + private byte[] adminPublicKey; + @Schema(description = "group ID") + private int groupId; + @Schema(description = "member to unban from group", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") + private String member; + /** Reference to GROUP_BAN transaction, used to rebuild ban during orphaning. */ + // No need to ever expose this via API + @XmlTransient + private byte[] banReference; + + // Constructors + + // For JAX-RS + protected CancelGroupBanTransactionData() { + super(TransactionType.CANCEL_GROUP_BAN); + } + + public void afterUnmarshal(Unmarshaller u, Object parent) { + this.creatorPublicKey = this.adminPublicKey; + } + + public CancelGroupBanTransactionData(byte[] adminPublicKey, int groupId, String member, byte[] banReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + super(TransactionType.CANCEL_GROUP_BAN, fee, adminPublicKey, timestamp, reference, signature); + + this.adminPublicKey = adminPublicKey; + this.groupId = groupId; + this.member = member; + this.banReference = banReference; + } + + /** Constructor typically used after deserialization */ + public CancelGroupBanTransactionData(byte[] adminPublicKey, int groupId, String member, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + this(adminPublicKey, groupId, member, null, fee, timestamp, reference, signature); + } + + // Getters / setters + + public byte[] getAdminPublicKey() { + return this.adminPublicKey; + } + + public int getGroupId() { + return this.groupId; + } + + public String getMember() { + return this.member; + } + + public byte[] getBanReference() { + return this.banReference; + } + + public void setBanReference(byte[] banReference) { + this.banReference = banReference; + } + +} diff --git a/src/main/java/org/qora/data/transaction/CancelGroupInviteTransactionData.java b/src/main/java/org/qora/data/transaction/CancelGroupInviteTransactionData.java index cfd5b73f..02d17f46 100644 --- a/src/main/java/org/qora/data/transaction/CancelGroupInviteTransactionData.java +++ b/src/main/java/org/qora/data/transaction/CancelGroupInviteTransactionData.java @@ -19,13 +19,14 @@ public class CancelGroupInviteTransactionData extends TransactionData { // Properties @Schema(description = "admin's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") private byte[] adminPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; + @Schema(description = "group ID") + private int groupId; @Schema(description = "invitee's address", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") private String invitee; + /** Reference to GROUP_INVITE transaction, used to rebuild invite during orphaning. */ // No need to ever expose this via API @XmlTransient - private byte[] groupReference; + private byte[] inviteReference; // Constructors @@ -38,25 +39,18 @@ public class CancelGroupInviteTransactionData extends TransactionData { this.creatorPublicKey = this.adminPublicKey; } - public CancelGroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public CancelGroupInviteTransactionData(byte[] adminPublicKey, int groupId, String invitee, byte[] inviteReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.CANCEL_GROUP_INVITE, fee, adminPublicKey, timestamp, reference, signature); this.adminPublicKey = adminPublicKey; - this.groupName = groupName; + this.groupId = groupId; this.invitee = invitee; - this.groupReference = groupReference; + this.inviteReference = inviteReference; } - public CancelGroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, invitee, groupReference, fee, timestamp, reference, null); - } - - public CancelGroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(adminPublicKey, groupName, invitee, null, fee, timestamp, reference, signature); - } - - public CancelGroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, invitee, null, fee, timestamp, reference, null); + /** Constructor typically used after deserialization */ + public CancelGroupInviteTransactionData(byte[] adminPublicKey, int groupId, String invitee, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + this(adminPublicKey, groupId, invitee, null, fee, timestamp, reference, signature); } // Getters / setters @@ -65,20 +59,20 @@ public class CancelGroupInviteTransactionData extends TransactionData { return this.adminPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getInvitee() { return this.invitee; } - public byte[] getGroupReference() { - return this.groupReference; + public byte[] getInviteReference() { + return this.inviteReference; } - public void setGroupReference(byte[] groupReference) { - this.groupReference = groupReference; + public void setInviteReference(byte[] inviteReference) { + this.inviteReference = inviteReference; } } \ No newline at end of file diff --git a/src/main/java/org/qora/data/transaction/CreateGroupTransactionData.java b/src/main/java/org/qora/data/transaction/CreateGroupTransactionData.java index 12bad802..0a4e3a91 100644 --- a/src/main/java/org/qora/data/transaction/CreateGroupTransactionData.java +++ b/src/main/java/org/qora/data/transaction/CreateGroupTransactionData.java @@ -9,19 +9,43 @@ import javax.xml.bind.annotation.XmlElement; import org.qora.transaction.Transaction.TransactionType; import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema.AccessMode; // All properties to be converted to JSON via JAX-RS @XmlAccessorType(XmlAccessType.FIELD) -@Schema(allOf = { TransactionData.class }) +@Schema( + allOf = { + TransactionData.class + } +) public class CreateGroupTransactionData extends TransactionData { - @Schema(description = "group owner's address", example = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v") + // Properties + // groupId can be null but assigned during save() or during load from repository + @Schema( + accessMode = AccessMode.READ_ONLY, + description = "assigned group ID" + ) + private Integer groupId = null; + @Schema( + description = "group owner's address", + example = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v" + ) private String owner; - @Schema(description = "group name", example = "miner-group") + @Schema( + description = "group name", + example = "miner-group" + ) private String groupName; - @Schema(description = "short description of group", example = "this group is for block miners") + @Schema( + description = "short description of group", + example = "this group is for block miners" + ) private String description; - @Schema(description = "whether anyone can join group (open) or group is invite-only (closed)", example = "true") + @Schema( + description = "whether anyone can join group (open) or group is invite-only (closed)", + example = "true" + ) private boolean isOpen; // Constructors @@ -31,8 +55,8 @@ public class CreateGroupTransactionData extends TransactionData { super(TransactionType.CREATE_GROUP); } - public CreateGroupTransactionData(byte[] creatorPublicKey, String owner, String groupName, String description, boolean isOpen, BigDecimal fee, long timestamp, byte[] reference, - byte[] signature) { + public CreateGroupTransactionData(byte[] creatorPublicKey, String owner, String groupName, String description, boolean isOpen, Integer groupId, + BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.CREATE_GROUP, fee, creatorPublicKey, timestamp, reference, signature); this.creatorPublicKey = creatorPublicKey; @@ -40,10 +64,7 @@ public class CreateGroupTransactionData extends TransactionData { this.groupName = groupName; this.description = description; this.isOpen = isOpen; - } - - public CreateGroupTransactionData(byte[] creatorPublicKey, String owner, String groupName, String description, boolean isOpen, BigDecimal fee, long timestamp, byte[] reference) { - this(creatorPublicKey, owner, groupName, description, isOpen, fee, timestamp, reference, null); + this.groupId = groupId; } // Getters / setters @@ -64,15 +85,35 @@ public class CreateGroupTransactionData extends TransactionData { return this.isOpen; } + public Integer getGroupId() { + return this.groupId; + } + + public void setGroupId(Integer groupId) { + this.groupId = groupId; + } + // Re-expose creatorPublicKey for this transaction type for JAXB - @XmlElement(name = "creatorPublicKey") - @Schema(name = "creatorPublicKey", description = "group creator's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") + @XmlElement( + name = "creatorPublicKey" + ) + @Schema( + name = "creatorPublicKey", + description = "group creator's public key", + example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP" + ) public byte[] getGroupCreatorPublicKey() { return this.creatorPublicKey; } - @XmlElement(name = "creatorPublicKey") - @Schema(name = "creatorPublicKey", description = "group creator's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") + @XmlElement( + name = "creatorPublicKey" + ) + @Schema( + name = "creatorPublicKey", + description = "group creator's public key", + example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP" + ) public void setGroupCreatorPublicKey(byte[] creatorPublicKey) { this.creatorPublicKey = creatorPublicKey; } diff --git a/src/main/java/org/qora/data/transaction/GroupBanTransactionData.java b/src/main/java/org/qora/data/transaction/GroupBanTransactionData.java index f8013ad1..d0835f28 100644 --- a/src/main/java/org/qora/data/transaction/GroupBanTransactionData.java +++ b/src/main/java/org/qora/data/transaction/GroupBanTransactionData.java @@ -13,26 +13,48 @@ 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 }) +@Schema( + allOf = { + TransactionData.class + } +) public class GroupBanTransactionData extends TransactionData { // Properties - @Schema(description = "admin's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") + @Schema( + description = "admin's public key", + example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP" + ) private byte[] adminPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; - @Schema(description = "offender to ban from group", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") - private String offender; - @Schema(description = "reason for ban") + @Schema( + description = "group ID" + ) + private int groupId; + @Schema( + description = "offender to ban from group", + example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK" + ) + private String offender; + @Schema( + description = "reason for ban" + ) private String reason; - @Schema(description = "ban lifetime in seconds") + @Schema( + description = "ban lifetime in seconds" + ) private int timeToLive; + /** Reference to transaction that triggered membership. Could be JOIN_GROUP, GROUP_INVITE or UPDATE_GROUP transaction. */ // No need to ever expose this via API @XmlTransient private byte[] memberReference; + /** Reference to transaction that triggered adminship. */ // No need to ever expose this via API @XmlTransient private byte[] adminReference; + /** Reference to pending join-request or invite transaction that was deleted by this so it (invite/join-request) can be rebuilt during orphaning. */ + // No need to ever expose this via API + @XmlTransient + private byte[] joinInviteReference; // Constructors @@ -45,28 +67,24 @@ public class GroupBanTransactionData extends TransactionData { this.creatorPublicKey = this.adminPublicKey; } - public GroupBanTransactionData(byte[] adminPublicKey, String groupName, String member, String reason, int timeToLive, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public GroupBanTransactionData(byte[] adminPublicKey, int groupId, String member, String reason, int timeToLive, byte[] memberReference, + byte[] adminReference, byte[] joinInviteReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.GROUP_BAN, fee, adminPublicKey, timestamp, reference, signature); this.adminPublicKey = adminPublicKey; - this.groupName = groupName; + this.groupId = groupId; this.offender = member; this.reason = reason; this.timeToLive = timeToLive; this.memberReference = memberReference; this.adminReference = adminReference; + this.joinInviteReference = joinInviteReference; } - public GroupBanTransactionData(byte[] adminPublicKey, String groupName, String offender, String reason, int timeToLive, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(adminPublicKey, groupName, offender, reason, timeToLive, null, null, fee, timestamp, reference, signature); - } - - public GroupBanTransactionData(byte[] adminPublicKey, String groupName, String offender, String reason, int timeToLive, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, offender, reason, timeToLive, memberReference, adminReference, fee, timestamp, reference, null); - } - - public GroupBanTransactionData(byte[] adminPublicKey, String groupName, String offender, String reason, int timeToLive, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, offender, reason, timeToLive, null, null, fee, timestamp, reference, null); + /** Constructor typically used after deserialization */ + public GroupBanTransactionData(byte[] adminPublicKey, int groupId, String offender, String reason, int timeToLive, BigDecimal fee, long timestamp, + byte[] reference, byte[] signature) { + this(adminPublicKey, groupId, offender, reason, timeToLive, null, null, null, fee, timestamp, reference, signature); } // Getters / setters @@ -75,8 +93,8 @@ public class GroupBanTransactionData extends TransactionData { return this.adminPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getOffender() { @@ -107,4 +125,12 @@ public class GroupBanTransactionData extends TransactionData { this.adminReference = adminReference; } + public byte[] getJoinInviteReference() { + return this.joinInviteReference; + } + + public void setJoinInviteReference(byte[] reference) { + this.joinInviteReference = reference; + } + } diff --git a/src/main/java/org/qora/data/transaction/GroupInviteTransactionData.java b/src/main/java/org/qora/data/transaction/GroupInviteTransactionData.java index a15e79d7..c67fcc52 100644 --- a/src/main/java/org/qora/data/transaction/GroupInviteTransactionData.java +++ b/src/main/java/org/qora/data/transaction/GroupInviteTransactionData.java @@ -19,15 +19,16 @@ public class GroupInviteTransactionData extends TransactionData { // Properties @Schema(description = "admin's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") private byte[] adminPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; + @Schema(description = "group ID") + private int groupId; @Schema(description = "invitee's address", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") private String invitee; @Schema(description = "invitation lifetime in seconds") private int timeToLive; + /** Reference to JOIN_GROUP transaction, used to rebuild this join request during orphaning. */ // No need to ever expose this via API @XmlTransient - private byte[] groupReference; + private byte[] joinReference; // Constructors @@ -40,26 +41,19 @@ public class GroupInviteTransactionData extends TransactionData { this.creatorPublicKey = this.adminPublicKey; } - public GroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, int timeToLive, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public GroupInviteTransactionData(byte[] adminPublicKey, int groupId, String invitee, int timeToLive, byte[] joinReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.GROUP_INVITE, fee, adminPublicKey, timestamp, reference, signature); this.adminPublicKey = adminPublicKey; - this.groupName = groupName; + this.groupId = groupId; this.invitee = invitee; this.timeToLive = timeToLive; - this.groupReference = groupReference; + this.joinReference = joinReference; } - public GroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, int timeToLive, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, invitee, timeToLive, groupReference, fee, timestamp, reference, null); - } - - public GroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, int timeToLive, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(adminPublicKey, groupName, invitee, timeToLive, null, fee, timestamp, reference, signature); - } - - public GroupInviteTransactionData(byte[] adminPublicKey, String groupName, String invitee, int timeToLive, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, invitee, timeToLive, null, fee, timestamp, reference, null); + /** Constructor typically used after deserialization */ + public GroupInviteTransactionData(byte[] adminPublicKey, int groupId, String invitee, int timeToLive, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + this(adminPublicKey, groupId, invitee, timeToLive, null, fee, timestamp, reference, signature); } // Getters / setters @@ -68,8 +62,8 @@ public class GroupInviteTransactionData extends TransactionData { return this.adminPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getInvitee() { @@ -80,12 +74,12 @@ public class GroupInviteTransactionData extends TransactionData { return this.timeToLive; } - public byte[] getGroupReference() { - return this.groupReference; + public byte[] getJoinReference() { + return this.joinReference; } - public void setGroupReference(byte[] groupReference) { - this.groupReference = groupReference; + public void setJoinReference(byte[] joinReference) { + this.joinReference = joinReference; } } \ No newline at end of file diff --git a/src/main/java/org/qora/data/transaction/GroupKickTransactionData.java b/src/main/java/org/qora/data/transaction/GroupKickTransactionData.java index 7d465f07..b6fdcdaf 100644 --- a/src/main/java/org/qora/data/transaction/GroupKickTransactionData.java +++ b/src/main/java/org/qora/data/transaction/GroupKickTransactionData.java @@ -13,24 +13,45 @@ 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 }) +@Schema( + allOf = { + TransactionData.class + } +) public class GroupKickTransactionData extends TransactionData { // Properties - @Schema(description = "admin's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") + @Schema( + description = "admin's public key", + example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP" + ) private byte[] adminPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; - @Schema(description = "member to kick from group", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") - private String member; - @Schema(description = "reason for kick") + @Schema( + description = "group name", + example = "my-group" + ) + private int groupId; + @Schema( + description = "member to kick from group", + example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK" + ) + private String member; + @Schema( + description = "reason for kick" + ) private String reason; + /** Reference to transaction that triggered membership. */ // No need to ever expose this via API @XmlTransient private byte[] memberReference; + /** Reference to transaction that triggered adminship. */ // No need to ever expose this via API @XmlTransient private byte[] adminReference; + /** Reference to JOIN_GROUP transaction, used to rebuild this join request during orphaning. */ + // No need to ever expose this via API + @XmlTransient + private byte[] joinReference; // Constructors @@ -43,27 +64,23 @@ public class GroupKickTransactionData extends TransactionData { this.creatorPublicKey = this.adminPublicKey; } - public GroupKickTransactionData(byte[] adminPublicKey, String groupName, String member, String reason, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public GroupKickTransactionData(byte[] adminPublicKey, int groupId, String member, String reason, byte[] memberReference, byte[] adminReference, + byte[] joinReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.GROUP_KICK, fee, adminPublicKey, timestamp, reference, signature); this.adminPublicKey = adminPublicKey; - this.groupName = groupName; + this.groupId = groupId; this.member = member; this.reason = reason; this.memberReference = memberReference; this.adminReference = adminReference; + this.joinReference = joinReference; } - public GroupKickTransactionData(byte[] adminPublicKey, String groupName, String member, String reason, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(adminPublicKey, groupName, member, reason, null, null, fee, timestamp, reference, signature); - } - - public GroupKickTransactionData(byte[] adminPublicKey, String groupName, String member, String reason, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, member, reason, memberReference, adminReference, fee, timestamp, reference, null); - } - - public GroupKickTransactionData(byte[] adminPublicKey, String groupName, String member, String reason, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, member, reason, null, null, fee, timestamp, reference, null); + /** Constructor typically used after deserialization */ + public GroupKickTransactionData(byte[] adminPublicKey, int groupId, String member, String reason, BigDecimal fee, long timestamp, byte[] reference, + byte[] signature) { + this(adminPublicKey, groupId, member, reason, null, null, null, fee, timestamp, reference, signature); } // Getters / setters @@ -72,8 +89,8 @@ public class GroupKickTransactionData extends TransactionData { return this.adminPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getMember() { @@ -100,4 +117,12 @@ public class GroupKickTransactionData extends TransactionData { this.adminReference = adminReference; } + public byte[] getJoinReference() { + return this.joinReference; + } + + public void setJoinReference(byte[] joinReference) { + this.joinReference = joinReference; + } + } diff --git a/src/main/java/org/qora/data/transaction/GroupUnbanTransactionData.java b/src/main/java/org/qora/data/transaction/GroupUnbanTransactionData.java deleted file mode 100644 index c1ed94f1..00000000 --- a/src/main/java/org/qora/data/transaction/GroupUnbanTransactionData.java +++ /dev/null @@ -1,84 +0,0 @@ -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 GroupUnbanTransactionData extends TransactionData { - - // Properties - @Schema(description = "admin's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") - private byte[] adminPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; - @Schema(description = "member to unban from group", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") - private String member; - // No need to ever expose this via API - @XmlTransient - private byte[] groupReference; - - // Constructors - - // For JAX-RS - protected GroupUnbanTransactionData() { - super(TransactionType.GROUP_UNBAN); - } - - public void afterUnmarshal(Unmarshaller u, Object parent) { - this.creatorPublicKey = this.adminPublicKey; - } - - public GroupUnbanTransactionData(byte[] adminPublicKey, String groupName, String member, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - super(TransactionType.GROUP_UNBAN, fee, adminPublicKey, timestamp, reference, signature); - - this.adminPublicKey = adminPublicKey; - this.groupName = groupName; - this.member = member; - this.groupReference = groupReference; - } - - public GroupUnbanTransactionData(byte[] adminPublicKey, String groupName, String member, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, member, groupReference, fee, timestamp, reference, null); - } - - public GroupUnbanTransactionData(byte[] adminPublicKey, String groupName, String member, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(adminPublicKey, groupName, member, null, fee, timestamp, reference, signature); - } - - public GroupUnbanTransactionData(byte[] adminPublicKey, String groupName, String member, BigDecimal fee, long timestamp, byte[] reference) { - this(adminPublicKey, groupName, member, null, fee, timestamp, reference, null); - } - - // Getters / setters - - public byte[] getAdminPublicKey() { - return this.adminPublicKey; - } - - public String getGroupName() { - return this.groupName; - } - - public String getMember() { - return this.member; - } - - public byte[] getGroupReference() { - return this.groupReference; - } - - public void setGroupReference(byte[] groupReference) { - this.groupReference = groupReference; - } - -} diff --git a/src/main/java/org/qora/data/transaction/JoinGroupTransactionData.java b/src/main/java/org/qora/data/transaction/JoinGroupTransactionData.java index 111701ac..be156319 100644 --- a/src/main/java/org/qora/data/transaction/JoinGroupTransactionData.java +++ b/src/main/java/org/qora/data/transaction/JoinGroupTransactionData.java @@ -5,6 +5,7 @@ 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; @@ -19,7 +20,11 @@ public class JoinGroupTransactionData extends TransactionData { @Schema(description = "joiner's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") private byte[] joinerPublicKey; @Schema(description = "which group to join", example = "my-group") - private String groupName; + private int groupId; + /** Reference to GROUP_INVITE transaction, used to rebuild invite during orphaning. */ + // No need to ever expose this via API + @XmlTransient + private byte[] inviteReference; // Constructors @@ -32,15 +37,17 @@ public class JoinGroupTransactionData extends TransactionData { this.creatorPublicKey = this.joinerPublicKey; } - public JoinGroupTransactionData(byte[] joinerPublicKey, String groupName, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public JoinGroupTransactionData(byte[] joinerPublicKey, int groupId, byte[] inviteReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.JOIN_GROUP, fee, joinerPublicKey, timestamp, reference, signature); this.joinerPublicKey = joinerPublicKey; - this.groupName = groupName; + this.groupId = groupId; + this.inviteReference = inviteReference; } - public JoinGroupTransactionData(byte[] joinerPublicKey, String groupName, BigDecimal fee, long timestamp, byte[] reference) { - this(joinerPublicKey, groupName, fee, timestamp, reference, null); + /** Constructor typically used after deserialization */ + public JoinGroupTransactionData(byte[] joinerPublicKey, int groupId, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + this(joinerPublicKey, groupId, null, fee, timestamp, reference, signature); } // Getters / setters @@ -49,8 +56,16 @@ public class JoinGroupTransactionData extends TransactionData { return this.joinerPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; + } + + public byte[] getInviteReference() { + return this.inviteReference; + } + + public void setInviteReference(byte[] inviteReference) { + this.inviteReference = inviteReference; } } diff --git a/src/main/java/org/qora/data/transaction/LeaveGroupTransactionData.java b/src/main/java/org/qora/data/transaction/LeaveGroupTransactionData.java index 9570a6ce..6770621d 100644 --- a/src/main/java/org/qora/data/transaction/LeaveGroupTransactionData.java +++ b/src/main/java/org/qora/data/transaction/LeaveGroupTransactionData.java @@ -20,10 +20,12 @@ public class LeaveGroupTransactionData extends TransactionData { @Schema(description = "leaver's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") private byte[] leaverPublicKey; @Schema(description = "which group to leave", example = "my-group") - private String groupName; + private int groupId; + /** Reference to transaction that triggered membership. */ // No need to ever expose this via API @XmlTransient private byte[] memberReference; + /** Reference to transaction that triggered adminship. */ // No need to ever expose this via API @XmlTransient private byte[] adminReference; @@ -39,25 +41,18 @@ public class LeaveGroupTransactionData extends TransactionData { this.creatorPublicKey = this.leaverPublicKey; } - public LeaveGroupTransactionData(byte[] leaverPublicKey, String groupName, byte[] memberReference, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public LeaveGroupTransactionData(byte[] leaverPublicKey, int groupId, 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.groupId = groupId; 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); + /** Constructor typically used after deserialization */ + public LeaveGroupTransactionData(byte[] leaverPublicKey, int groupId, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + this(leaverPublicKey, groupId, null, null, fee, timestamp, reference, signature); } // Getters / setters @@ -66,8 +61,8 @@ public class LeaveGroupTransactionData extends TransactionData { return this.leaverPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public byte[] getMemberReference() { diff --git a/src/main/java/org/qora/data/transaction/RemoveGroupAdminTransactionData.java b/src/main/java/org/qora/data/transaction/RemoveGroupAdminTransactionData.java index 79e84ef2..d254cf55 100644 --- a/src/main/java/org/qora/data/transaction/RemoveGroupAdminTransactionData.java +++ b/src/main/java/org/qora/data/transaction/RemoveGroupAdminTransactionData.java @@ -19,14 +19,15 @@ public class RemoveGroupAdminTransactionData extends TransactionData { // Properties @Schema(description = "group owner's public key", example = "2tiMr5LTpaWCgbRvkPK8TFd7k63DyHJMMFFsz9uBf1ZP") private byte[] ownerPublicKey; - @Schema(description = "group name", example = "my-group") - private String groupName; + @Schema(description = "group ID") + private int groupId; @Schema(description = "admin to demote", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK") private String admin; + /** Reference to transaction that triggered adminship. */ // For internal use when orphaning @XmlTransient @Schema(hidden = true) - private byte[] groupReference; + private byte[] adminReference; // Constructors @@ -39,25 +40,18 @@ public class RemoveGroupAdminTransactionData extends TransactionData { this.creatorPublicKey = this.ownerPublicKey; } - public RemoveGroupAdminTransactionData(byte[] ownerPublicKey, String groupName, String admin, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + public RemoveGroupAdminTransactionData(byte[] ownerPublicKey, int groupId, String admin, byte[] adminReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.REMOVE_GROUP_ADMIN, fee, ownerPublicKey, timestamp, reference, signature); this.ownerPublicKey = ownerPublicKey; - this.groupName = groupName; + this.groupId = groupId; this.admin = admin; - this.groupReference = groupReference; + this.adminReference = adminReference; } - public RemoveGroupAdminTransactionData(byte[] ownerPublicKey, String groupName, String admin, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference) { - this(ownerPublicKey, groupName, admin, groupReference, fee, timestamp, reference, null); - } - - public RemoveGroupAdminTransactionData(byte[] ownerPublicKey, String groupName, String admin, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(ownerPublicKey, groupName, admin, null, fee, timestamp, reference, signature); - } - - public RemoveGroupAdminTransactionData(byte[] ownerPublicKey, String groupName, String admin, BigDecimal fee, long timestamp, byte[] reference) { - this(ownerPublicKey, groupName, admin, null, fee, timestamp, reference, null); + /** Constructor typically used after deserialization */ + public RemoveGroupAdminTransactionData(byte[] ownerPublicKey, int groupId, String admin, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { + this(ownerPublicKey, groupId, admin, null, fee, timestamp, reference, signature); } // Getters / setters @@ -66,20 +60,20 @@ public class RemoveGroupAdminTransactionData extends TransactionData { return this.ownerPublicKey; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getAdmin() { return this.admin; } - public byte[] getGroupReference() { - return this.groupReference; + public byte[] getAdminReference() { + return this.adminReference; } - public void setGroupReference(byte[] groupReference) { - this.groupReference = groupReference; + public void setAdminReference(byte[] adminReference) { + this.adminReference = adminReference; } } diff --git a/src/main/java/org/qora/data/transaction/TransactionData.java b/src/main/java/org/qora/data/transaction/TransactionData.java index 0b474752..1edfb061 100644 --- a/src/main/java/org/qora/data/transaction/TransactionData.java +++ b/src/main/java/org/qora/data/transaction/TransactionData.java @@ -35,7 +35,7 @@ import io.swagger.v3.oas.annotations.media.Schema.AccessMode; MultiPaymentTransactionData.class, DeployATTransactionData.class, MessageTransactionData.class, ATTransactionData.class, CreateGroupTransactionData.class, UpdateGroupTransactionData.class, AddGroupAdminTransactionData.class, RemoveGroupAdminTransactionData.class, - GroupBanTransactionData.class, GroupUnbanTransactionData.class, + GroupBanTransactionData.class, CancelGroupBanTransactionData.class, GroupKickTransactionData.class, GroupInviteTransactionData.class, JoinGroupTransactionData.class, LeaveGroupTransactionData.class }) diff --git a/src/main/java/org/qora/data/transaction/UpdateGroupTransactionData.java b/src/main/java/org/qora/data/transaction/UpdateGroupTransactionData.java index 19d66d22..7ff6502b 100644 --- a/src/main/java/org/qora/data/transaction/UpdateGroupTransactionData.java +++ b/src/main/java/org/qora/data/transaction/UpdateGroupTransactionData.java @@ -22,11 +22,12 @@ public class UpdateGroupTransactionData extends TransactionData { @Schema(description = "new owner's address", example = "QgV4s3xnzLhVBEJxcYui4u4q11yhUHsd9v") private String newOwner; @Schema(description = "which group to update", example = "my-group") - private String groupName; + private int groupId; @Schema(description = "replacement group description", example = "my group for accounts I like") private String newDescription; @Schema(description = "new group join policy", example = "true") private boolean newIsOpen; + /** Reference to CREATE_GROUP or UPDATE_GROUP transaction, used to rebuild group during orphaning. */ // For internal use when orphaning @XmlTransient @Schema(hidden = true) @@ -43,26 +44,22 @@ public class UpdateGroupTransactionData extends TransactionData { this.creatorPublicKey = this.ownerPublicKey; } - public UpdateGroupTransactionData(byte[] ownerPublicKey, String groupName, String newOwner, String newDescription, boolean newIsOpen, byte[] groupReference, BigDecimal fee, long timestamp, + public UpdateGroupTransactionData(byte[] ownerPublicKey, int groupId, String newOwner, String newDescription, boolean newIsOpen, byte[] groupReference, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { super(TransactionType.UPDATE_GROUP, fee, ownerPublicKey, timestamp, reference, signature); this.ownerPublicKey = ownerPublicKey; this.newOwner = newOwner; - this.groupName = groupName; + this.groupId = groupId; this.newDescription = newDescription; this.newIsOpen = newIsOpen; this.groupReference = groupReference; } - public UpdateGroupTransactionData(byte[] ownerPublicKey, String groupName, String newOwner, String newDescription, boolean newIsOpen, BigDecimal fee, long timestamp, byte[] reference, + /** Constructor typically used after deserialization */ + public UpdateGroupTransactionData(byte[] ownerPublicKey, int groupId, String newOwner, String newDescription, boolean newIsOpen, BigDecimal fee, long timestamp, byte[] reference, byte[] signature) { - this(ownerPublicKey, groupName, newOwner, newDescription, newIsOpen, null, fee, timestamp, reference, signature); - } - - public UpdateGroupTransactionData(byte[] ownerPublicKey, String groupName, String newOwner, String newDescription, boolean newIsOpen, byte[] groupReference, BigDecimal fee, long timestamp, - byte[] reference) { - this(ownerPublicKey, groupName, newOwner, newDescription, newIsOpen, groupReference, fee, timestamp, reference, null); + this(ownerPublicKey, groupId, newOwner, newDescription, newIsOpen, null, fee, timestamp, reference, signature); } // Getters / setters @@ -75,8 +72,8 @@ public class UpdateGroupTransactionData extends TransactionData { return this.newOwner; } - public String getGroupName() { - return this.groupName; + public int getGroupId() { + return this.groupId; } public String getNewDescription() { diff --git a/src/main/java/org/qora/group/Group.java b/src/main/java/org/qora/group/Group.java index e5ae41bb..7efdddd8 100644 --- a/src/main/java/org/qora/group/Group.java +++ b/src/main/java/org/qora/group/Group.java @@ -1,7 +1,6 @@ package org.qora.group; import java.util.Arrays; -import java.util.List; import org.qora.account.Account; import org.qora.account.PublicKeyAccount; @@ -17,7 +16,7 @@ import org.qora.data.transaction.CreateGroupTransactionData; import org.qora.data.transaction.GroupBanTransactionData; import org.qora.data.transaction.GroupInviteTransactionData; import org.qora.data.transaction.GroupKickTransactionData; -import org.qora.data.transaction.GroupUnbanTransactionData; +import org.qora.data.transaction.CancelGroupBanTransactionData; import org.qora.data.transaction.JoinGroupTransactionData; import org.qora.data.transaction.LeaveGroupTransactionData; import org.qora.data.transaction.RemoveGroupAdminTransactionData; @@ -31,13 +30,14 @@ public class Group { // Properties private Repository repository; + private GroupRepository groupRepository; private GroupData groupData; // Useful constants - public static final int MAX_NAME_SIZE = 400; - public static final int MAX_DESCRIPTION_SIZE = 4000; + public static final int MAX_NAME_SIZE = 32; + public static final int MAX_DESCRIPTION_SIZE = 128; /** Max size of kick/ban reason */ - public static final int MAX_REASON_SIZE = 400; + public static final int MAX_REASON_SIZE = 128; // Constructors @@ -49,6 +49,8 @@ public class Group { */ public Group(Repository repository, CreateGroupTransactionData createGroupTransactionData) { this.repository = repository; + this.groupRepository = repository.getGroupRepository(); + this.groupData = new GroupData(createGroupTransactionData.getOwner(), createGroupTransactionData.getGroupName(), createGroupTransactionData.getDescription(), createGroupTransactionData.getTimestamp(), createGroupTransactionData.getIsOpen(), createGroupTransactionData.getSignature()); @@ -58,16 +60,151 @@ public class Group { * Construct Group business object using existing group in repository. * * @param repository - * @param groupName + * @param groupId * @throws DataException */ - public Group(Repository repository, String groupName) throws DataException { + public Group(Repository repository, int groupId) throws DataException { this.repository = repository; - this.groupData = this.repository.getGroupRepository().fromGroupName(groupName); + this.groupRepository = repository.getGroupRepository(); + + this.groupData = this.repository.getGroupRepository().fromGroupId(groupId); + } + + // Getters / setters + + public GroupData getGroupData() { + return this.groupData; + } + + // Shortcuts to aid code clarity + + // Membership + + private GroupMemberData getMember(String member) throws DataException { + return groupRepository.getMember(this.groupData.getGroupId(), member); + } + + private boolean memberExists(String member) throws DataException { + return groupRepository.memberExists(this.groupData.getGroupId(), member); + } + + private void addMember(String member, long joined, byte[] reference) throws DataException { + GroupMemberData groupMemberData = new GroupMemberData(this.groupData.getGroupId(), member, joined, reference); + groupRepository.save(groupMemberData); + } + + private void addMember(String member, TransactionData transactionData) throws DataException { + this.addMember(member, transactionData.getTimestamp(), transactionData.getSignature()); + } + + private void rebuildMember(String member, byte[] reference) throws DataException { + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(reference); + this.addMember(member, transactionData); + } + + private void deleteMember(String member) throws DataException { + groupRepository.deleteMember(this.groupData.getGroupId(), member); + } + + // Adminship + + private GroupAdminData getAdmin(String admin) throws DataException { + return groupRepository.getAdmin(this.groupData.getGroupId(), admin); + } + + private boolean adminExists(String admin) throws DataException { + return groupRepository.adminExists(this.groupData.getGroupId(), admin); + } + + private void addAdmin(String admin, byte[] reference) throws DataException { + GroupAdminData groupAdminData = new GroupAdminData(this.groupData.getGroupId(), admin, reference); + groupRepository.save(groupAdminData); + } + + private void addAdmin(String admin, TransactionData transactionData) throws DataException { + this.addAdmin(admin, transactionData.getSignature()); + } + + private void rebuildAdmin(String admin, byte[] reference) throws DataException { + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(reference); + this.addAdmin(admin, transactionData); + } + + private void deleteAdmin(String admin) throws DataException { + groupRepository.deleteAdmin(this.groupData.getGroupId(), admin); + } + + // Join request + + private GroupJoinRequestData getJoinRequest(String joiner) throws DataException { + return groupRepository.getJoinRequest(this.groupData.getGroupId(), joiner); + } + + private void addJoinRequest(String joiner, byte[] reference) throws DataException { + GroupJoinRequestData groupJoinRequestData = new GroupJoinRequestData(this.groupData.getGroupId(), joiner, reference); + groupRepository.save(groupJoinRequestData); + } + + private void rebuildJoinRequest(String joiner, byte[] reference) throws DataException { + this.addJoinRequest(joiner, reference); + } + + private void deleteJoinRequest(String joiner) throws DataException { + groupRepository.deleteJoinRequest(this.groupData.getGroupId(), joiner); + } + + // Invites + + private GroupInviteData getInvite(String invitee) throws DataException { + return groupRepository.getInvite(this.groupData.getGroupId(), invitee); + } + + private void addInvite(GroupInviteTransactionData groupInviteTransactionData) throws DataException { + Account inviter = new PublicKeyAccount(this.repository, groupInviteTransactionData.getAdminPublicKey()); + String invitee = groupInviteTransactionData.getInvitee(); + Long expiry = null; + int timeToLive = groupInviteTransactionData.getTimeToLive(); + if (timeToLive != 0) + expiry = groupInviteTransactionData.getTimestamp() + timeToLive * 1000; + + GroupInviteData groupInviteData = new GroupInviteData(this.groupData.getGroupId(), inviter.getAddress(), invitee, expiry, + groupInviteTransactionData.getSignature()); + groupRepository.save(groupInviteData); + } + + private void rebuildInvite(String invitee, byte[] reference) throws DataException { + TransactionData previousTransactionData = this.repository.getTransactionRepository().fromSignature(reference); + this.addInvite((GroupInviteTransactionData) previousTransactionData); + } + + private void deleteInvite(String invitee) throws DataException { + groupRepository.deleteInvite(this.groupData.getGroupId(), invitee); + } + + // Bans + + private void addBan(GroupBanTransactionData groupBanTransactionData) throws DataException { + String offender = groupBanTransactionData.getOffender(); + Account admin = new PublicKeyAccount(this.repository, groupBanTransactionData.getAdminPublicKey()); + long banned = groupBanTransactionData.getTimestamp(); + String reason = groupBanTransactionData.getReason(); + + Long expiry = null; + int timeToLive = groupBanTransactionData.getTimeToLive(); + if (timeToLive != 0) + expiry = groupBanTransactionData.getTimestamp() + timeToLive * 1000; + + // Save reference to this banning transaction so cancel-ban can rebuild ban during orphaning. + byte[] reference = groupBanTransactionData.getSignature(); + + GroupBanData groupBanData = new GroupBanData(this.groupData.getGroupId(), offender, admin.getAddress(), banned, reason, expiry, reference); + groupRepository.save(groupBanData); } // Processing + // "un"-methods are the orphaning versions. e.g. "uncreate" undoes "create" processing. + /* * GroupData records can be changed by CREATE_GROUP or UPDATE_GROUP transactions. * @@ -75,7 +212,8 @@ public class Group { * in a field called "reference". * * During orphaning, "reference" is used to fetch the previous GroupData-changing transaction - * and that transaction's contents are used to restore the previous GroupData state. + * and that transaction's contents are used to restore the previous GroupData state, + * including GroupData's previous "reference" value. */ // CREATE GROUP @@ -84,19 +222,16 @@ public class Group { // Note: this.groupData already populated by our constructor above this.repository.getGroupRepository().save(this.groupData); - // Add owner as admin - GroupAdminData groupAdminData = new GroupAdminData(this.groupData.getGroupName(), this.groupData.getOwner(), createGroupTransactionData.getSignature()); - this.repository.getGroupRepository().save(groupAdminData); - // Add owner as member - GroupMemberData groupMemberData = new GroupMemberData(this.groupData.getGroupName(), this.groupData.getOwner(), this.groupData.getCreated(), - createGroupTransactionData.getSignature()); - this.repository.getGroupRepository().save(groupMemberData); + this.addMember(this.groupData.getOwner(), createGroupTransactionData); + + // Add owner as admin + this.addAdmin(this.groupData.getOwner(), createGroupTransactionData); } public void uncreate() throws DataException { // Repository takes care of cleaning up ancilliary data! - this.repository.getGroupRepository().delete(this.groupData.getGroupName()); + this.repository.getGroupRepository().delete(this.groupData.getGroupId()); } // UPDATE GROUP @@ -108,9 +243,6 @@ public class Group { */ public void updateGroup(UpdateGroupTransactionData updateGroupTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = updateGroupTransactionData.getGroupName(); - // Save GroupData's reference in our transaction data updateGroupTransactionData.setGroupReference(this.groupData.getReference()); @@ -129,25 +261,17 @@ public class Group { String newOwner = updateGroupTransactionData.getNewOwner(); // 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); - } + if (!this.memberExists(newOwner)) + this.addMember(newOwner, updateGroupTransactionData); // 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); - } + if (!this.adminExists(newOwner)) + this.addAdmin(newOwner, updateGroupTransactionData); // Previous owner retained as admin and member } public void unupdateGroup(UpdateGroupTransactionData updateGroupTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = updateGroupTransactionData.getGroupName(); - // Previous group reference is taken from this transaction's cached copy this.groupData.setReference(updateGroupTransactionData.getGroupReference()); @@ -159,21 +283,23 @@ public class Group { // 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); + GroupAdminData groupAdminData = this.getAdmin(newOwner); + if (Arrays.equals(groupAdminData.getReference(), updateGroupTransactionData.getSignature())) + this.deleteAdmin(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); + GroupMemberData groupMemberData = this.getMember(newOwner); + if (Arrays.equals(groupMemberData.getReference(), updateGroupTransactionData.getSignature())) + this.deleteMember(newOwner); } } + /** Reverts groupData using previous values stored in referenced transaction. */ private void revertGroupUpdate() throws DataException { TransactionData previousTransactionData = this.repository.getTransactionRepository().fromSignature(this.groupData.getReference()); if (previousTransactionData == null) @@ -204,47 +330,46 @@ public class Group { } public void promoteToAdmin(AddGroupAdminTransactionData addGroupAdminTransactionData) throws DataException { - GroupAdminData groupAdminData = new GroupAdminData(addGroupAdminTransactionData.getGroupName(), addGroupAdminTransactionData.getMember(), - addGroupAdminTransactionData.getSignature()); - this.repository.getGroupRepository().save(groupAdminData); + this.addAdmin(addGroupAdminTransactionData.getMember(), addGroupAdminTransactionData.getSignature()); } public void unpromoteToAdmin(AddGroupAdminTransactionData addGroupAdminTransactionData) throws DataException { - this.repository.getGroupRepository().deleteAdmin(addGroupAdminTransactionData.getGroupName(), addGroupAdminTransactionData.getMember()); + this.deleteAdmin(addGroupAdminTransactionData.getMember()); } public void demoteFromAdmin(RemoveGroupAdminTransactionData removeGroupAdminTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = removeGroupAdminTransactionData.getGroupName(); String admin = removeGroupAdminTransactionData.getAdmin(); - // Save admin's promotion transaction reference for orphaning purposes - GroupAdminData groupAdminData = groupRepository.getAdmin(groupName, admin); - removeGroupAdminTransactionData.setGroupReference(groupAdminData.getGroupReference()); + // Save reference to the transaction that caused adminship so we can revert if orphaning. + GroupAdminData groupAdminData = this.getAdmin(admin); + // Reference now part of this transaction but actually saved into repository by caller. + removeGroupAdminTransactionData.setAdminReference(groupAdminData.getReference()); // Demote - groupRepository.deleteAdmin(groupName, admin); + this.deleteAdmin(admin); } public void undemoteFromAdmin(RemoveGroupAdminTransactionData removeGroupAdminTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = removeGroupAdminTransactionData.getGroupName(); String admin = removeGroupAdminTransactionData.getAdmin(); - // Rebuild admin entry using stored promotion transaction reference - GroupAdminData groupAdminData = new GroupAdminData(groupName, admin, removeGroupAdminTransactionData.getGroupReference()); - groupRepository.save(groupAdminData); + // Rebuild admin entry using stored reference to transaction that causes adminship + this.rebuildAdmin(admin, removeGroupAdminTransactionData.getAdminReference()); + + // Clean cached reference in this transaction + removeGroupAdminTransactionData.setAdminReference(null); } public void kick(GroupKickTransactionData groupKickTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupKickTransactionData.getGroupName(); String member = groupKickTransactionData.getMember(); - // If pending join request then this is a essentially a deny response so delete join request and exit - if (groupRepository.joinRequestExists(groupName, member)) { + // If there is a pending join request then this is a essentially a deny response so delete join request and exit + GroupJoinRequestData groupJoinRequestData = this.getJoinRequest(member); + if (groupJoinRequestData != null) { + // Save reference to the transaction that created join request so we can rebuild join request during orphaning. + groupKickTransactionData.setJoinReference(groupJoinRequestData.getReference()); + // Delete join request - groupRepository.deleteJoinRequest(groupName, member); + this.deleteJoinRequest(member); // Make sure kick transaction's member/admin-references are null to indicate that there // was no existing member but actually only a join request. This should prevent orphaning code @@ -253,271 +378,298 @@ public class Group { groupKickTransactionData.setAdminReference(null); return; + } else { + // Clear any cached join reference + groupKickTransactionData.setJoinReference(null); } - // Store membership and (optionally) adminship transactions for orphaning purposes - GroupAdminData groupAdminData = groupRepository.getAdmin(groupName, member); + GroupAdminData groupAdminData = this.getAdmin(member); if (groupAdminData != null) { - groupKickTransactionData.setAdminReference(groupAdminData.getGroupReference()); + // Save reference to the transaction that caused adminship so we can rebuild adminship during orphaning. + groupKickTransactionData.setAdminReference(groupAdminData.getReference()); - groupRepository.deleteAdmin(groupName, member); + // Kicked, so no longer an admin + this.deleteAdmin(member); } else { - // Not an admin + // Not an admin so no reference groupKickTransactionData.setAdminReference(null); } - GroupMemberData groupMemberData = groupRepository.getMember(groupName, member); - groupKickTransactionData.setMemberReference(groupMemberData.getGroupReference()); + GroupMemberData groupMemberData = this.getMember(member); + // Save reference to the transaction that caused membership so we can rebuild membership during orphaning. + groupKickTransactionData.setMemberReference(groupMemberData.getReference()); - groupRepository.deleteMember(groupName, member); + // Kicked, so no longer a member + this.deleteMember(member); } public void unkick(GroupKickTransactionData groupKickTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupKickTransactionData.getGroupName(); String member = groupKickTransactionData.getMember(); - // If there's no member-reference then there wasn't an actual member, only a join request - if (groupKickTransactionData.getMemberReference() == null) { + // If there's no cached reference to the transaction that caused membership then the kick was only a deny response to a join-request. + byte[] joinReference = groupKickTransactionData.getJoinReference(); + if (joinReference != null) { // Rebuild join-request - GroupJoinRequestData groupJoinRequestData = new GroupJoinRequestData(groupName, member); - groupRepository.save(groupJoinRequestData); + this.rebuildJoinRequest(member, joinReference); return; } // Rebuild member entry using stored transaction reference - TransactionData membershipTransactionData = this.repository.getTransactionRepository().fromSignature(groupKickTransactionData.getMemberReference()); - GroupMemberData groupMemberData = new GroupMemberData(groupName, member, membershipTransactionData.getTimestamp(), - membershipTransactionData.getSignature()); - groupRepository.save(groupMemberData); + this.rebuildMember(member, groupKickTransactionData.getMemberReference()); - if (groupKickTransactionData.getAdminReference() != null) { + if (groupKickTransactionData.getAdminReference() != null) // Rebuild admin entry using stored transaction reference - GroupAdminData groupAdminData = new GroupAdminData(groupName, member, groupKickTransactionData.getAdminReference()); - groupRepository.save(groupAdminData); - } + this.rebuildAdmin(member, groupKickTransactionData.getAdminReference()); + + // Clean cached references to transactions used to rebuild member/admin info + groupKickTransactionData.setMemberReference(null); + groupKickTransactionData.setAdminReference(null); } public void ban(GroupBanTransactionData groupBanTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupBanTransactionData.getGroupName(); String offender = groupBanTransactionData.getOffender(); // Kick if member - if (groupRepository.memberExists(groupName, offender)) { - // Store membership and (optionally) adminship transactions for orphaning purposes - GroupAdminData groupAdminData = groupRepository.getAdmin(groupName, offender); + if (this.memberExists(offender)) { + GroupAdminData groupAdminData = this.getAdmin(offender); if (groupAdminData != null) { - groupBanTransactionData.setAdminReference(groupAdminData.getGroupReference()); + // Save reference to the transaction that caused adminship so we can revert if orphaning. + groupBanTransactionData.setAdminReference(groupAdminData.getReference()); - groupRepository.deleteAdmin(groupName, offender); + // Kicked, so no longer an admin + this.deleteAdmin(offender); } else { - // Not an admin + // Not an admin so no reference groupBanTransactionData.setAdminReference(null); } - GroupMemberData groupMemberData = groupRepository.getMember(groupName, offender); - groupBanTransactionData.setMemberReference(groupMemberData.getGroupReference()); + GroupMemberData groupMemberData = this.getMember(offender); + // Save reference to the transaction that caused membership so we can revert if orphaning. + groupBanTransactionData.setMemberReference(groupMemberData.getReference()); - groupRepository.deleteMember(groupName, offender); + // Kicked, so no longer a member + this.deleteMember(offender); } else { - groupBanTransactionData.setMemberReference(null); + // If there is a pending join request then this is a essentially a deny response so delete join request + GroupJoinRequestData groupJoinRequestData = this.getJoinRequest(offender); + if (groupJoinRequestData != null) { + // Save reference to join request so we can rebuild join request if orphaning, + // and differentiate between needing to rebuild join request and rebuild invite. + groupBanTransactionData.setJoinInviteReference(groupJoinRequestData.getReference()); - // XXX maybe set join-request reference here? - // XXX what about invites? - } + // Delete join request + this.deleteJoinRequest(offender); - // XXX Delete pending join request - // XXX Delete pending invites + // Make sure kick transaction's member/admin-references are null to indicate that there + // was no existing member but actually only a join request. This should prevent orphaning code + // from trying to incorrectly recreate a member/admin. + groupBanTransactionData.setMemberReference(null); + groupBanTransactionData.setAdminReference(null); + } else { + // No join request, but there could be a pending invite + GroupInviteData groupInviteData = this.getInvite(offender); + if (groupInviteData != null) { + // Save reference to invite so we can rebuild invite if orphaning, + // and differentiate between needing to rebuild join request and rebuild invite. + groupBanTransactionData.setJoinInviteReference(groupInviteData.getReference()); - // Ban - Account admin = new PublicKeyAccount(this.repository, groupBanTransactionData.getAdminPublicKey()); - long banned = groupBanTransactionData.getTimestamp(); - String reason = groupBanTransactionData.getReason(); + // Delete invite + this.deleteInvite(offender); - Long expiry = null; - int timeToLive = groupBanTransactionData.getTimeToLive(); - if (timeToLive != 0) - expiry = groupBanTransactionData.getTimestamp() + timeToLive * 1000; - - // Save reference to banning transaction for orphaning purposes - byte[] reference = groupBanTransactionData.getSignature(); - - GroupBanData groupBanData = new GroupBanData(groupName, offender, admin.getAddress(), banned, reason, expiry, reference); - groupRepository.save(groupBanData); - } - - public void unban(GroupBanTransactionData groupBanTransactionData) throws DataException { - // Orphaning version of "ban" - not actual "unban" - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupBanTransactionData.getGroupName(); - String offender = groupBanTransactionData.getOffender(); - - // If was kicked as part of ban then reinstate - if (groupBanTransactionData.getMemberReference() != null) { - // Rebuild member entry using stored transaction reference - TransactionData membershipTransactionData = this.repository.getTransactionRepository().fromSignature(groupBanTransactionData.getMemberReference()); - GroupMemberData groupMemberData = new GroupMemberData(groupName, offender, membershipTransactionData.getTimestamp(), - membershipTransactionData.getSignature()); - groupRepository.save(groupMemberData); - - if (groupBanTransactionData.getAdminReference() != null) { - // Rebuild admin entry using stored transaction reference - GroupAdminData groupAdminData = new GroupAdminData(groupName, offender, groupBanTransactionData.getAdminReference()); - groupRepository.save(groupAdminData); + // Make sure kick transaction's member/admin-references are null to indicate that there + // was no existing member but actually only a join request. This should prevent orphaning code + // from trying to incorrectly recreate a member/admin. + groupBanTransactionData.setMemberReference(null); + groupBanTransactionData.setAdminReference(null); + } } } - // XXX Reinstate pending join request - // XXX Reinstate pending invites - - // Delete ban - groupRepository.deleteBan(groupName, offender); + // Create ban + this.addBan(groupBanTransactionData); } - public void cancelBan(GroupUnbanTransactionData groupUnbanTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupUnbanTransactionData.getGroupName(); + public void unban(GroupBanTransactionData groupBanTransactionData) throws DataException { + // Orphaning version of "ban" - not "cancel-ban"! + String offender = groupBanTransactionData.getOffender(); + + // Delete ban + groupRepository.deleteBan(this.groupData.getGroupId(), offender); + + // If member was kicked as part of ban then reinstate + if (groupBanTransactionData.getMemberReference() != null) { + this.rebuildMember(offender, groupBanTransactionData.getMemberReference()); + + if (groupBanTransactionData.getAdminReference() != null) + // Rebuild admin entry using stored transaction reference + this.rebuildAdmin(offender, groupBanTransactionData.getAdminReference()); + } else { + // Do we need to reinstate pending invite or join-request? + byte[] groupReference = groupBanTransactionData.getJoinInviteReference(); + if (groupReference != null) { + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(groupReference); + + switch (transactionData.getType()) { + case GROUP_INVITE: + // Reinstate invite + this.rebuildInvite(offender, groupReference); + break; + + case JOIN_GROUP: + // Rebuild join-request + this.rebuildJoinRequest(offender, groupReference); + break; + + default: + throw new IllegalStateException("Unable to revert group transaction due to unsupported referenced transaction"); + } + } + } + } + + public void cancelBan(CancelGroupBanTransactionData groupUnbanTransactionData) throws DataException { String member = groupUnbanTransactionData.getMember(); - GroupBanData groupBanData = groupRepository.getBan(groupName, member); + GroupBanData groupBanData = groupRepository.getBan(this.groupData.getGroupId(), member); // Save reference to banning transaction for orphaning purposes - groupUnbanTransactionData.setGroupReference(groupBanData.getReference()); + groupUnbanTransactionData.setBanReference(groupBanData.getReference()); // Delete ban - groupRepository.deleteBan(groupName, member); + groupRepository.deleteBan(this.groupData.getGroupId(), member); } - public void uncancelBan(GroupUnbanTransactionData groupUnbanTransactionData) throws DataException { - // Reinstate ban - TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(groupUnbanTransactionData.getGroupReference()); - ban((GroupBanTransactionData) transactionData); + public void uncancelBan(CancelGroupBanTransactionData groupUnbanTransactionData) throws DataException { + // Reinstate ban using cached reference to banning transaction, stored in our transaction + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(groupUnbanTransactionData.getBanReference()); + this.addBan((GroupBanTransactionData) transactionData); - groupUnbanTransactionData.setGroupReference(null); + // Clear cached reference to banning transaction + groupUnbanTransactionData.setBanReference(null); } public void invite(GroupInviteTransactionData groupInviteTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupInviteTransactionData.getGroupName(); - Account inviter = new PublicKeyAccount(this.repository, groupInviteTransactionData.getAdminPublicKey()); + String invitee = groupInviteTransactionData.getInvitee(); // If there is a pending "join request" then add new group member - if (groupRepository.joinRequestExists(groupName, groupInviteTransactionData.getInvitee())) { - GroupMemberData groupMemberData = new GroupMemberData(groupName, groupInviteTransactionData.getInvitee(), groupInviteTransactionData.getTimestamp(), - groupInviteTransactionData.getSignature()); - groupRepository.save(groupMemberData); + GroupJoinRequestData groupJoinRequestData = this.getJoinRequest(invitee); + if (groupJoinRequestData != null) { + this.addMember(invitee, groupInviteTransactionData); + + // Save reference to transaction that created join request so we can rebuild join request during orphaning. + groupInviteTransactionData.setJoinReference(groupJoinRequestData.getReference()); // Delete join request - groupRepository.deleteJoinRequest(groupName, groupInviteTransactionData.getInvitee()); + this.deleteJoinRequest(invitee); return; } - Long expiry = null; - int timeToLive = groupInviteTransactionData.getTimeToLive(); - if (timeToLive != 0) - expiry = groupInviteTransactionData.getTimestamp() + timeToLive * 1000; - - GroupInviteData groupInviteData = new GroupInviteData(groupName, inviter.getAddress(), groupInviteTransactionData.getInvitee(), expiry, - groupInviteTransactionData.getSignature()); - groupRepository.save(groupInviteData); + this.addInvite(groupInviteTransactionData); } public void uninvite(GroupInviteTransactionData groupInviteTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupInviteTransactionData.getGroupName(); - Account inviter = new PublicKeyAccount(this.repository, groupInviteTransactionData.getAdminPublicKey()); String invitee = groupInviteTransactionData.getInvitee(); - // Put back any "join request" - if (groupRepository.memberExists(groupName, invitee)) { - GroupJoinRequestData groupJoinRequestData = new GroupJoinRequestData(groupName, invitee); - groupRepository.save(groupJoinRequestData); + // If member exists then they were added when invite matched join request + if (this.memberExists(invitee)) { + // Rebuild join request using cached reference to transaction that created join request. + this.rebuildJoinRequest(invitee, groupInviteTransactionData.getJoinReference()); // Delete member - groupRepository.deleteMember(groupName, invitee); + this.deleteMember(invitee); + + // Clear cached reference + groupInviteTransactionData.setJoinReference(null); } // Delete invite - groupRepository.deleteInvite(groupName, inviter.getAddress(), invitee); + this.deleteInvite(invitee); } public void cancelInvite(CancelGroupInviteTransactionData cancelGroupInviteTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = cancelGroupInviteTransactionData.getGroupName(); - Account inviter = new PublicKeyAccount(this.repository, cancelGroupInviteTransactionData.getAdminPublicKey()); String invitee = cancelGroupInviteTransactionData.getInvitee(); - // Save invite's transaction signature for orphaning purposes - GroupInviteData groupInviteData = groupRepository.getInvite(groupName, inviter.getAddress(), invitee); - cancelGroupInviteTransactionData.setGroupReference(groupInviteData.getReference()); + // Save reference to invite transaction so invite can be rebuilt during orphaning. + GroupInviteData groupInviteData = this.getInvite(invitee); + cancelGroupInviteTransactionData.setInviteReference(groupInviteData.getReference()); // Delete invite - groupRepository.deleteInvite(groupName, inviter.getAddress(), invitee); + this.deleteInvite(invitee); } public void uncancelInvite(CancelGroupInviteTransactionData cancelGroupInviteTransactionData) throws DataException { // Reinstate invite - TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(cancelGroupInviteTransactionData.getGroupReference()); - invite((GroupInviteTransactionData) transactionData); + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(cancelGroupInviteTransactionData.getInviteReference()); + this.addInvite((GroupInviteTransactionData) transactionData); - cancelGroupInviteTransactionData.setGroupReference(null); + // Clear cached reference to invite transaction + cancelGroupInviteTransactionData.setInviteReference(null); } public void join(JoinGroupTransactionData joinGroupTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = joinGroupTransactionData.getGroupName(); Account joiner = new PublicKeyAccount(this.repository, joinGroupTransactionData.getJoinerPublicKey()); - // Set invite transactions' group-reference to this transaction's signature so the invites can be put back if we orphan this join - // Delete any pending invites - List invites = groupRepository.getInvitesByInvitee(groupName, joiner.getAddress()); - for (GroupInviteData invite : invites) { - TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(invite.getReference()); - ((GroupInviteTransactionData) transactionData).setGroupReference(joinGroupTransactionData.getSignature()); + // Any pending invite? + GroupInviteData groupInviteData = this.getInvite(joiner.getAddress()); - groupRepository.deleteInvite(groupName, invite.getInviter(), joiner.getAddress()); - } - - // If there were no invites and this group is "closed" (i.e. invite-only) then + // If there is no invites and this group is "closed" (i.e. invite-only) then // this is now a pending "join request" - if (invites.isEmpty() && !groupData.getIsOpen()) { - GroupJoinRequestData groupJoinRequestData = new GroupJoinRequestData(groupName, joiner.getAddress()); - groupRepository.save(groupJoinRequestData); + if (groupInviteData == null && !groupData.getIsOpen()) { + // Save join request + this.addJoinRequest(joiner.getAddress(), joinGroupTransactionData.getSignature()); + + // Clear any reference to invite transaction to prevent invite rebuild during orphaning. + joinGroupTransactionData.setInviteReference(null); + return; } - // Actually add new member to group - GroupMemberData groupMemberData = new GroupMemberData(groupName, joiner.getAddress(), joinGroupTransactionData.getTimestamp(), - joinGroupTransactionData.getSignature()); - groupRepository.save(groupMemberData); + // Any invite? + if (groupInviteData != null) { + // Save reference to invite transaction so invite can be rebuilt during orphaning. + joinGroupTransactionData.setInviteReference(groupInviteData.getReference()); + // Delete invite + this.deleteInvite(joiner.getAddress()); + } else { + // Clear any reference to invite transaction to prevent invite rebuild during orphaning. + joinGroupTransactionData.setInviteReference(null); + } + + // Actually add new member to group + this.addMember(joiner.getAddress(), joinGroupTransactionData); } public void unjoin(JoinGroupTransactionData joinGroupTransactionData) throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = joinGroupTransactionData.getGroupName(); Account joiner = new PublicKeyAccount(this.repository, joinGroupTransactionData.getJoinerPublicKey()); - groupRepository.deleteMember(groupName, joiner.getAddress()); + byte[] inviteReference = joinGroupTransactionData.getInviteReference(); - // Put back any pending invites - List inviteTransactions = this.repository.getTransactionRepository() - .getInvitesWithGroupReference(joinGroupTransactionData.getSignature()); - for (GroupInviteTransactionData inviteTransaction : inviteTransactions) { - this.invite(inviteTransaction); + // Was this a join-request only? + if (inviteReference == null && !groupData.getIsOpen()) { + // Delete join request + this.deleteJoinRequest(joiner.getAddress()); - // Remove group-reference - inviteTransaction.setGroupReference(null); - this.repository.getTransactionRepository().save(inviteTransaction); + return; } + + // Any invite to rebuild? + if (inviteReference != null) { + // Rebuild invite using cache reference to invite transaction + TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(inviteReference); + this.addInvite((GroupInviteTransactionData) transactionData); + + // Clear cached reference to invite transaction + joinGroupTransactionData.setInviteReference(null); + } + + // Delete member + this.deleteMember(joiner.getAddress()); } 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. @@ -526,41 +678,35 @@ public class Group { // 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()); + GroupAdminData groupAdminData = this.getAdmin(leaver.getAddress()); if (groupAdminData != null) { - // Leaver is admin - use promotion transaction reference as restore-state reference - leaveGroupTransactionData.setAdminReference(groupAdminData.getGroupReference()); + // Save reference to transaction that caused adminship in our transaction so we can rebuild adminship during orphaning. + leaveGroupTransactionData.setAdminReference(groupAdminData.getReference()); // Remove as admin - groupRepository.deleteAdmin(groupName, leaver.getAddress()); + this.deleteAdmin(leaver.getAddress()); } } - // Save membership transaction reference - GroupMemberData groupMemberData = groupRepository.getMember(groupName, leaver.getAddress()); - leaveGroupTransactionData.setMemberReference(groupMemberData.getGroupReference()); + // Save reference to transaction that caused membership in our transaction so we can rebuild membership during orphaning. + GroupMemberData groupMemberData = this.getMember(leaver.getAddress()); + leaveGroupTransactionData.setMemberReference(groupMemberData.getReference()); // Remove as member - groupRepository.deleteMember(leaveGroupTransactionData.getGroupName(), leaver.getAddress()); + this.deleteMember(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())); + // Restore membership using cached reference to transaction that caused membership + this.rebuildMember(leaver.getAddress(), leaveGroupTransactionData.getMemberReference()); - // 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); - } + if (adminTransactionSignature != null) + // Restore adminship using cached reference to transaction that caused adminship + this.rebuildAdmin(leaver.getAddress(), adminTransactionSignature); } } diff --git a/src/main/java/org/qora/repository/GroupRepository.java b/src/main/java/org/qora/repository/GroupRepository.java index ad9ca555..05e5e6b6 100644 --- a/src/main/java/org/qora/repository/GroupRepository.java +++ b/src/main/java/org/qora/repository/GroupRepository.java @@ -13,81 +13,89 @@ public interface GroupRepository { // Groups + public GroupData fromGroupId(int groupId) throws DataException; + public GroupData fromGroupName(String groupName) throws DataException; + public boolean groupExists(int groupId) throws DataException; + public boolean groupExists(String groupName) throws DataException; public List getAllGroups() throws DataException; public List getGroupsByOwner(String address) throws DataException; + public List getGroupsWithMember(String member) throws DataException; + public void save(GroupData groupData) throws DataException; + public void delete(int groupId) throws DataException; + public void delete(String groupName) throws DataException; // Group Admins - public GroupAdminData getAdmin(String groupName, String address) throws DataException; + public GroupAdminData getAdmin(int groupId, String address) throws DataException; - public boolean adminExists(String groupName, String address) throws DataException; + public boolean adminExists(int groupId, String address) throws DataException; - public List getGroupAdmins(String groupName) throws DataException; + public List getGroupAdmins(int groupId) throws DataException; public void save(GroupAdminData groupAdminData) throws DataException; - public void deleteAdmin(String groupName, String address) throws DataException; + public void deleteAdmin(int groupId, String address) throws DataException; // Group Members - public GroupMemberData getMember(String groupName, String address) throws DataException; + public GroupMemberData getMember(int groupId, String address) throws DataException; - public boolean memberExists(String groupName, String address) throws DataException; + public boolean memberExists(int groupId, String address) throws DataException; - public List getGroupMembers(String groupName) throws DataException; + public List getGroupMembers(int groupId) throws DataException; /** Returns number of group members, or null if group doesn't exist */ - public Integer countGroupMembers(String groupName) throws DataException; + public Integer countGroupMembers(int groupId) throws DataException; public void save(GroupMemberData groupMemberData) throws DataException; - public void deleteMember(String groupName, String address) throws DataException; + public void deleteMember(int groupId, String address) throws DataException; // Group Invites - public GroupInviteData getInvite(String groupName, String inviter, String invitee) throws DataException; + public GroupInviteData getInvite(int groupId, String invitee) throws DataException; - public boolean inviteExists(String groupName, String invitee) throws DataException; + public boolean inviteExists(int groupId, String invitee) throws DataException; - public boolean inviteExists(String groupName, String inviter, String invitee) throws DataException; + public List getGroupInvites(int groupId) throws DataException; - public List getGroupInvites(String groupName) throws DataException; - - public List getInvitesByInvitee(String groupName, String invitee) throws DataException; + public List getInvitesByInvitee(String invitee) throws DataException; public void save(GroupInviteData groupInviteData) throws DataException; - public void deleteInvite(String groupName, String inviter, String invitee) throws DataException; + public void deleteInvite(int groupId, String invitee) throws DataException; // Group Join Requests - public boolean joinRequestExists(String groupName, String joiner) throws DataException; + public GroupJoinRequestData getJoinRequest(Integer groupId, String joiner) throws DataException; - public List getGroupJoinRequests(String groupName) throws DataException; + public boolean joinRequestExists(int groupId, String joiner) throws DataException; + + public List getGroupJoinRequests(int groupId) throws DataException; public void save(GroupJoinRequestData groupJoinRequestData) throws DataException; - public void deleteJoinRequest(String groupName, String joiner) throws DataException; + public void deleteJoinRequest(int groupId, String joiner) throws DataException; // Group Bans - public GroupBanData getBan(String groupName, String member) throws DataException; + public GroupBanData getBan(int groupId, String member) throws DataException; - public boolean banExists(String groupName, String offender) throws DataException; + public boolean banExists(int groupId, String offender) throws DataException; - public List getGroupBans(String groupName) throws DataException; + public List getGroupBans(int groupId) throws DataException; public void save(GroupBanData groupBanData) throws DataException; - public void deleteBan(String groupName, String offender) throws DataException; + public void deleteBan(int groupId, String offender) throws DataException; } \ No newline at end of file diff --git a/src/main/java/org/qora/repository/TransactionRepository.java b/src/main/java/org/qora/repository/TransactionRepository.java index 2ae7f0f0..afaffe69 100644 --- a/src/main/java/org/qora/repository/TransactionRepository.java +++ b/src/main/java/org/qora/repository/TransactionRepository.java @@ -2,7 +2,6 @@ package org.qora.repository; import java.util.List; -import org.qora.data.transaction.GroupInviteTransactionData; import org.qora.data.transaction.TransactionData; import org.qora.transaction.Transaction.TransactionType; @@ -53,8 +52,4 @@ public interface TransactionRepository { public void delete(TransactionData transactionData) throws DataException; - /** Returns transaction data for group invite transactions that have groupReference that matches passed value. - * @throws DataException */ - public List getInvitesWithGroupReference(byte[] groupReference) throws DataException; - } diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java index 4997addd..3be6a2da 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBDatabaseUpdates.java @@ -91,22 +91,27 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE TYPE QoraPublicKey AS VARBINARY(32)"); stmt.execute("CREATE TYPE QoraAmount AS DECIMAL(27, 8)"); stmt.execute("CREATE TYPE GenericDescription AS VARCHAR(4000)"); - stmt.execute("CREATE TYPE RegisteredName AS VARCHAR(400) COLLATE SQL_TEXT_NO_PAD"); + stmt.execute("CREATE TYPE RegisteredName AS VARCHAR(128) COLLATE SQL_TEXT_NO_PAD"); stmt.execute("CREATE TYPE NameData AS VARCHAR(4000)"); - stmt.execute("CREATE TYPE PollName AS VARCHAR(400) COLLATE SQL_TEXT_NO_PAD"); - stmt.execute("CREATE TYPE PollOption AS VARCHAR(400) COLLATE SQL_TEXT_UCC_NO_PAD"); + stmt.execute("CREATE TYPE MessageData AS VARBINARY(4000)"); + stmt.execute("CREATE TYPE PollName AS VARCHAR(128) COLLATE SQL_TEXT_NO_PAD"); + stmt.execute("CREATE TYPE PollOption AS VARCHAR(80) COLLATE SQL_TEXT_UCC_NO_PAD"); stmt.execute("CREATE TYPE PollOptionIndex AS INTEGER"); stmt.execute("CREATE TYPE DataHash AS VARBINARY(32)"); stmt.execute("CREATE TYPE AssetID AS BIGINT"); - stmt.execute("CREATE TYPE AssetName AS VARCHAR(400) COLLATE SQL_TEXT_NO_PAD"); + stmt.execute("CREATE TYPE AssetName AS VARCHAR(34) COLLATE SQL_TEXT_NO_PAD"); stmt.execute("CREATE TYPE AssetOrderID AS VARBINARY(64)"); - stmt.execute("CREATE TYPE ATName AS VARCHAR(200) COLLATE SQL_TEXT_UCC_NO_PAD"); - stmt.execute("CREATE TYPE ATType AS VARCHAR(200) COLLATE SQL_TEXT_UCC_NO_PAD"); + stmt.execute("CREATE TYPE ATName AS VARCHAR(32) COLLATE SQL_TEXT_UCC_NO_PAD"); + stmt.execute("CREATE TYPE ATType AS VARCHAR(32) COLLATE SQL_TEXT_UCC_NO_PAD"); + stmt.execute("CREATE TYPE ATTags AS VARCHAR(32) COLLATE SQL_TEXT_UCC_NO_PAD"); stmt.execute("CREATE TYPE ATCode AS BLOB(64K)"); // 16bit * 1 stmt.execute("CREATE TYPE ATState AS BLOB(1M)"); // 16bit * 8 + 16bit * 4 + 16bit * 4 + stmt.execute("CREATE TYPE ATCreationBytes AS BLOB(576K)"); // 16bit * 1 + 16bit * 8 stmt.execute("CREATE TYPE ATStateHash as VARBINARY(32)"); stmt.execute("CREATE TYPE ATMessage AS VARBINARY(256)"); + stmt.execute("CREATE TYPE GroupID AS INTEGER"); stmt.execute("CREATE TYPE GroupName AS VARCHAR(400) COLLATE SQL_TEXT_UCC_NO_PAD"); + stmt.execute("CREATE TYPE GroupReason AS VARCHAR(128) COLLATE SQL_TEXT_UCC_NO_PAD"); break; case 1: @@ -283,8 +288,8 @@ public class HSQLDBDatabaseUpdates { case 19: // Deploy CIYAM AT Transactions stmt.execute("CREATE TABLE DeployATTransactions (signature Signature, creator QoraPublicKey NOT NULL, AT_name ATName NOT NULL, " - + "description VARCHAR(2000) NOT NULL, AT_type ATType NOT NULL, AT_tags VARCHAR(200) NOT NULL, " - + "creation_bytes VARBINARY(100000) NOT NULL, amount QoraAmount NOT NULL, asset_id AssetID NOT NULL, AT_address QoraAddress, " + + "description GenericDescription NOT NULL, AT_type ATType NOT NULL, AT_tags ATTags NOT NULL, " + + "creation_bytes ATCreationBytes NOT NULL, amount QoraAmount NOT NULL, asset_id AssetID NOT NULL, AT_address QoraAddress, " + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); // For looking up the Deploy AT Transaction based on deployed AT address stmt.execute("CREATE INDEX DeployATAddressIndex on DeployATTransactions (AT_address)"); @@ -294,7 +299,7 @@ public class HSQLDBDatabaseUpdates { // Message Transactions stmt.execute( "CREATE TABLE MessageTransactions (signature Signature, version TINYINT NOT NULL, sender QoraPublicKey NOT NULL, recipient QoraAddress NOT NULL, " - + "is_text BOOLEAN NOT NULL, is_encrypted BOOLEAN NOT NULL, amount QoraAmount NOT NULL, asset_id AssetID NOT NULL, data VARBINARY(4000) NOT NULL, " + + "is_text BOOLEAN NOT NULL, is_encrypted BOOLEAN NOT NULL, amount QoraAmount NOT NULL, asset_id AssetID NOT NULL, data MessageData NOT NULL, " + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); break; @@ -303,7 +308,7 @@ public class HSQLDBDatabaseUpdates { stmt.execute("CREATE TABLE Assets (asset_id AssetID, owner QoraAddress NOT NULL, " + "asset_name AssetName NOT NULL, description GenericDescription NOT NULL, " + "quantity BIGINT NOT NULL, is_divisible BOOLEAN NOT NULL, reference Signature NOT NULL, PRIMARY KEY (asset_id))"); - // We need a corresponding trigger to make sure new asset_id values are assigned sequentially + // We need a corresponding trigger to make sure new asset_id values are assigned sequentially start from 0 stmt.execute( "CREATE TRIGGER Asset_ID_Trigger BEFORE INSERT ON Assets REFERENCING NEW ROW AS new_row FOR EACH ROW WHEN (new_row.asset_id IS NULL) " + "SET new_row.asset_id = (SELECT IFNULL(MAX(asset_id) + 1, 0) FROM Assets)"); @@ -359,10 +364,9 @@ public class HSQLDBDatabaseUpdates { case 26: // Registered Names - stmt.execute( - "CREATE TABLE Names (name RegisteredName, data VARCHAR(4000) NOT NULL, owner QoraAddress NOT NULL, " - + "registered TIMESTAMP WITH TIME ZONE NOT NULL, updated TIMESTAMP WITH TIME ZONE, reference Signature, is_for_sale BOOLEAN NOT NULL, sale_price QoraAmount, " - + "PRIMARY KEY (name))"); + stmt.execute("CREATE TABLE Names (name RegisteredName, data NameData NOT NULL, owner QoraAddress NOT NULL, " + + "registered TIMESTAMP WITH TIME ZONE NOT NULL, updated TIMESTAMP WITH TIME ZONE, reference Signature, is_for_sale BOOLEAN NOT NULL, sale_price QoraAmount, " + + "PRIMARY KEY (name))"); break; case 27: @@ -394,90 +398,106 @@ public class HSQLDBDatabaseUpdates { case 28: // Account groups - stmt.execute("CREATE TABLE AccountGroups (group_name GroupName, owner QoraAddress NOT NULL, description GenericDescription NOT NULL, " - + "created TIMESTAMP WITH TIME ZONE NOT NULL, updated TIMESTAMP WITH TIME ZONE, is_open BOOLEAN NOT NULL, " - + "reference Signature, PRIMARY KEY (group_name))"); + stmt.execute( + "CREATE TABLE Groups (group_id GroupID, owner QoraAddress NOT NULL, group_name GroupName, description GenericDescription NOT NULL, " + + "created TIMESTAMP WITH TIME ZONE NOT NULL, updated TIMESTAMP WITH TIME ZONE, is_open BOOLEAN NOT NULL, " + + "reference Signature, PRIMARY KEY (group_id))"); + // We need a corresponding trigger to make sure new group_id values are assigned sequentially starting from 1 + stmt.execute( + "CREATE TRIGGER Group_ID_Trigger BEFORE INSERT ON Groups REFERENCING NEW ROW AS new_row FOR EACH ROW WHEN (new_row.group_id IS NULL) " + + "SET new_row.group_id = (SELECT IFNULL(MAX(group_id) + 1, 1) FROM Groups)"); + // For when a user wants to lookup an group by name + stmt.execute("CREATE INDEX GroupNameIndex on Groups (group_name)"); // For finding groups by owner - stmt.execute("CREATE INDEX AccountGroupOwnerIndex ON AccountGroups (owner)"); + stmt.execute("CREATE INDEX GroupOwnerIndex ON Groups (owner)"); // Admins - stmt.execute("CREATE TABLE AccountGroupAdmins (group_name GroupName, admin QoraAddress, group_reference Signature NOT NULL, PRIMARY KEY (group_name, admin))"); + stmt.execute("CREATE TABLE GroupAdmins (group_id GroupID, admin QoraAddress, reference Signature NOT NULL, " + + "PRIMARY KEY (group_id, admin), FOREIGN KEY (group_id) REFERENCES Groups (group_id) ON DELETE CASCADE)"); // For finding groups that address administrates - stmt.execute("CREATE INDEX AccountGroupAdminIndex ON AccountGroupAdmins (admin)"); + stmt.execute("CREATE INDEX GroupAdminIndex ON GroupAdmins (admin)"); // Members - 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))"); + stmt.execute( + "CREATE TABLE GroupMembers (group_id GroupID, address QoraAddress, joined TIMESTAMP WITH TIME ZONE NOT NULL, reference Signature NOT NULL, " + + "PRIMARY KEY (group_id, address), FOREIGN KEY (group_id) REFERENCES Groups (group_id) ON DELETE CASCADE)"); // For finding groups that address is member - stmt.execute("CREATE INDEX AccountGroupMemberIndex ON AccountGroupMembers (address)"); + stmt.execute("CREATE INDEX GroupMemberIndex ON GroupMembers (address)"); // Invites - // PRIMARY KEY (invitee + group + inviter) because most queries will be "what have I been invited to?" from UI - stmt.execute("CREATE TABLE AccountGroupInvites (group_name GroupName, inviter QoraAddress, invitee QoraAddress, " - + "expiry TIMESTAMP WITH TIME ZONE NOT NULL, reference Signature, PRIMARY KEY (invitee, group_name, inviter))"); + stmt.execute("CREATE TABLE GroupInvites (group_id GroupID, inviter QoraAddress, invitee QoraAddress, " + + "expiry TIMESTAMP WITH TIME ZONE NOT NULL, reference Signature, " + + "PRIMARY KEY (group_id, invitee), FOREIGN KEY (group_id) REFERENCES Groups (group_id) ON DELETE CASCADE)"); // For finding invites sent by inviter - stmt.execute("CREATE INDEX AccountGroupSentInviteIndex ON AccountGroupInvites (inviter)"); + stmt.execute("CREATE INDEX GroupInviteInviterIndex ON GroupInvites (inviter)"); // For finding invites by group - stmt.execute("CREATE INDEX AccountGroupInviteIndex ON AccountGroupInvites (group_name)"); + stmt.execute("CREATE INDEX GroupInviteInviteeIndex ON GroupInvites (invitee)"); // For expiry maintenance - stmt.execute("CREATE INDEX AccountGroupInviteExpiryIndex ON AccountGroupInvites (expiry)"); + stmt.execute("CREATE INDEX GroupInviteExpiryIndex ON GroupInvites (expiry)"); // Pending "join requests" - stmt.execute("CREATE TABLE AccountGroupJoinRequests (group_name GroupName, joiner QoraAddress, " - + "PRIMARY KEY (group_name, joiner))"); + stmt.execute( + "CREATE TABLE GroupJoinRequests (group_id GroupID, joiner QoraAddress, reference Signature NOT NULL, PRIMARY KEY (group_id, joiner))"); // Bans // NULL expiry means does not expire! - stmt.execute("CREATE TABLE AccountGroupBans (group_name GroupName, offender QoraAddress, admin QoraAddress NOT NULL, banned TIMESTAMP WITH TIME ZONE NOT NULL, " - + "reason GenericDescription NOT NULL, expiry TIMESTAMP WITH TIME ZONE, reference Signature NOT NULL, " - + "PRIMARY KEY (group_name, offender))"); + stmt.execute( + "CREATE TABLE GroupBans (group_id GroupID, offender QoraAddress, admin QoraAddress NOT NULL, banned TIMESTAMP WITH TIME ZONE NOT NULL, " + + "reason GenericDescription NOT NULL, expiry TIMESTAMP WITH TIME ZONE, reference Signature NOT NULL, " + + "PRIMARY KEY (group_id, offender), FOREIGN KEY (group_id) REFERENCES Groups (group_id) ON DELETE CASCADE)"); // For expiry maintenance - stmt.execute("CREATE INDEX AccountGroupBanExpiryIndex ON AccountGroupBans (expiry)"); + stmt.execute("CREATE INDEX GroupBanExpiryIndex ON GroupBans (expiry)"); break; case 29: // Account group transactions stmt.execute("CREATE TABLE CreateGroupTransactions (signature Signature, creator QoraPublicKey NOT NULL, group_name GroupName NOT NULL, " - + "owner QoraAddress NOT NULL, description GenericDescription NOT NULL, is_open BOOLEAN NOT NULL, " + + "owner QoraAddress NOT NULL, description GenericDescription NOT NULL, is_open BOOLEAN NOT NULL, group_id GroupID, " + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); - 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_id GroupID NOT NULL, " + "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)"); // Account group add/remove admin transactions - stmt.execute("CREATE TABLE AddGroupAdminTransactions (signature Signature, owner QoraPublicKey NOT NULL, group_name GroupName NOT NULL, address QoraAddress NOT NULL, " - + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); - stmt.execute("CREATE TABLE RemoveGroupAdminTransactions (signature Signature, owner QoraPublicKey NOT NULL, group_name GroupName NOT NULL, admin QoraAddress NOT NULL, " - + "group_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + stmt.execute( + "CREATE TABLE AddGroupAdminTransactions (signature Signature, owner QoraPublicKey NOT NULL, group_id GroupID NOT NULL, address QoraAddress NOT NULL, " + + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + stmt.execute( + "CREATE TABLE RemoveGroupAdminTransactions (signature Signature, owner QoraPublicKey NOT NULL, group_id GroupID NOT NULL, admin QoraAddress NOT NULL, " + + "admin_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); // Account group join/leave transactions - 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)"); - stmt.execute("CREATE TABLE LeaveGroupTransactions (signature Signature, leaver QoraPublicKey NOT NULL, group_name GroupName NOT NULL, " + stmt.execute("CREATE TABLE JoinGroupTransactions (signature Signature, joiner QoraPublicKey NOT NULL, group_id GroupID NOT NULL, " + + "invite_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + stmt.execute("CREATE TABLE LeaveGroupTransactions (signature Signature, leaver QoraPublicKey NOT NULL, group_id GroupID NOT NULL, " + "member_reference Signature, admin_reference Signature, " + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); // Account group kick transaction - stmt.execute("CREATE TABLE GroupKickTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_name GroupName NOT NULL, address QoraAddress NOT NULL, " - + "reason VARCHAR(400), member_reference Signature, admin_reference Signature, " - + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + stmt.execute( + "CREATE TABLE GroupKickTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_id GroupID NOT NULL, address QoraAddress NOT NULL, " + + "reason GroupReason, member_reference Signature, admin_reference Signature, join_reference Signature, " + + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); // Account group invite/cancel-invite transactions - stmt.execute("CREATE TABLE GroupInviteTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_name GroupName NOT NULL, invitee QoraAddress NOT NULL, " - + "time_to_live INTEGER NOT NULL, group_reference Signature, " - + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); - // For finding invite transactions during orphaning - stmt.execute("CREATE INDEX GroupInviteTransactionReferenceIndex ON GroupInviteTransactions (group_reference)"); + stmt.execute( + "CREATE TABLE GroupInviteTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_id GroupID NOT NULL, invitee QoraAddress NOT NULL, " + + "time_to_live INTEGER NOT NULL, join_reference Signature, " + + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); // Cancel group invite - stmt.execute("CREATE TABLE CancelGroupInviteTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_name GroupName NOT NULL, invitee QoraAddress NOT NULL, " - + "group_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + stmt.execute( + "CREATE TABLE CancelGroupInviteTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_id GroupID NOT NULL, invitee QoraAddress NOT NULL, " + + "invite_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); - // Account ban/unban transactions - stmt.execute("CREATE TABLE GroupBanTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_name GroupName NOT NULL, address QoraAddress NOT NULL, " - + "reason VARCHAR(400), time_to_live INTEGER NOT NULL, member_reference Signature, admin_reference Signature, " - + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); - stmt.execute("CREATE TABLE GroupUnbanTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_name GroupName NOT NULL, address QoraAddress NOT NULL, " - + "group_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + // Account ban/cancel-ban transactions + stmt.execute( + "CREATE TABLE GroupBanTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_id GroupID NOT NULL, address QoraAddress NOT NULL, " + + "reason GroupReason, time_to_live INTEGER NOT NULL, " + + "member_reference Signature, admin_reference Signature, join_invite_reference Signature, " + + "PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); + stmt.execute( + "CREATE TABLE CancelGroupBanTransactions (signature Signature, admin QoraPublicKey NOT NULL, group_id GroupID NOT NULL, address QoraAddress NOT NULL, " + + "ban_reference Signature, PRIMARY KEY (signature), FOREIGN KEY (signature) REFERENCES Transactions (signature) ON DELETE CASCADE)"); break; default: diff --git a/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java b/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java index 493abd8e..33e4565f 100644 --- a/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/HSQLDBGroupRepository.java @@ -27,33 +27,68 @@ public class HSQLDBGroupRepository implements GroupRepository { // Groups @Override - public GroupData fromGroupName(String groupName) throws DataException { + public GroupData fromGroupId(int groupId) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT owner, description, created, updated, reference, is_open FROM AccountGroups WHERE group_name = ?", groupName)) { + .checkedExecute("SELECT group_name, owner, description, created, updated, reference, is_open FROM Groups WHERE group_id = ?", groupId)) { if (resultSet == null) return null; - String owner = resultSet.getString(1); - String description = resultSet.getString(2); - long created = resultSet.getTimestamp(3, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + String groupName = resultSet.getString(1); + String owner = resultSet.getString(2); + String description = resultSet.getString(3); + long created = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); // Special handling for possibly-NULL "updated" column - Timestamp updatedTimestamp = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)); + Timestamp updatedTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)); Long updated = resultSet.wasNull() ? null : updatedTimestamp.getTime(); - byte[] reference = resultSet.getBytes(5); - boolean isOpen = resultSet.getBoolean(6); + byte[] reference = resultSet.getBytes(6); + boolean isOpen = resultSet.getBoolean(7); - return new GroupData(owner, groupName, description, created, updated, isOpen, reference); + return new GroupData(groupId, owner, groupName, description, created, updated, isOpen, reference); } catch (SQLException e) { throw new DataException("Unable to fetch group info from repository", e); } } + @Override + public GroupData fromGroupName(String groupName) throws DataException { + try (ResultSet resultSet = this.repository + .checkedExecute("SELECT group_id, owner, description, created, updated, reference, is_open FROM Groups WHERE group_name = ?", groupName)) { + if (resultSet == null) + return null; + + int groupId = resultSet.getInt(1); + String owner = resultSet.getString(2); + String description = resultSet.getString(3); + long created = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + + // Special handling for possibly-NULL "updated" column + Timestamp updatedTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)); + Long updated = resultSet.wasNull() ? null : updatedTimestamp.getTime(); + + byte[] reference = resultSet.getBytes(6); + boolean isOpen = resultSet.getBoolean(7); + + return new GroupData(groupId, owner, groupName, description, created, updated, isOpen, reference); + } catch (SQLException e) { + throw new DataException("Unable to fetch group info from repository", e); + } + } + + @Override + public boolean groupExists(int groupId) throws DataException { + try { + return this.repository.exists("Groups", "group_id = ?", groupId); + } catch (SQLException e) { + throw new DataException("Unable to check for group in repository", e); + } + } + @Override public boolean groupExists(String groupName) throws DataException { try { - return this.repository.exists("AccountGroups", "group_name = ?", groupName); + return this.repository.exists("Groups", "group_name = ?", groupName); } catch (SQLException e) { throw new DataException("Unable to check for group in repository", e); } @@ -64,24 +99,25 @@ public class HSQLDBGroupRepository implements GroupRepository { List groups = new ArrayList<>(); try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_name, description, owner, created, updated, reference, is_open FROM AccountGroups")) { + .checkedExecute("SELECT group_id, owner, group_name, description, created, updated, reference, is_open FROM Groups")) { if (resultSet == null) return groups; do { - String groupName = resultSet.getString(1); - String description = resultSet.getString(2); - String owner = resultSet.getString(3); - long created = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + int groupId = resultSet.getInt(1); + String owner = resultSet.getString(2); + String groupName = resultSet.getString(3); + String description = resultSet.getString(4); + long created = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); // Special handling for possibly-NULL "updated" column - Timestamp updatedTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)); + Timestamp updatedTimestamp = resultSet.getTimestamp(6, Calendar.getInstance(HSQLDBRepository.UTC)); Long updated = resultSet.wasNull() ? null : updatedTimestamp.getTime(); - byte[] reference = resultSet.getBytes(6); - boolean isOpen = resultSet.getBoolean(7); + byte[] reference = resultSet.getBytes(7); + boolean isOpen = resultSet.getBoolean(8); - groups.add(new GroupData(owner, groupName, description, created, updated, isOpen, reference)); + groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, reference)); } while (resultSet.next()); return groups; @@ -95,23 +131,57 @@ public class HSQLDBGroupRepository implements GroupRepository { List groups = new ArrayList<>(); try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_name, description, created, updated, reference, is_open FROM AccountGroups WHERE owner = ?", owner)) { + .checkedExecute("SELECT group_id, group_name, description, created, updated, reference, is_open FROM Groups WHERE owner = ?", owner)) { if (resultSet == null) return groups; do { - String groupName = resultSet.getString(1); - String description = resultSet.getString(2); - long created = resultSet.getTimestamp(3, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + int groupId = resultSet.getInt(1); + String groupName = resultSet.getString(2); + String description = resultSet.getString(3); + long created = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); // Special handling for possibly-NULL "updated" column - Timestamp updatedTimestamp = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)); + Timestamp updatedTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)); Long updated = updatedTimestamp == null ? null : updatedTimestamp.getTime(); - byte[] reference = resultSet.getBytes(5); - boolean isOpen = resultSet.getBoolean(6); + byte[] reference = resultSet.getBytes(6); + boolean isOpen = resultSet.getBoolean(7); - groups.add(new GroupData(owner, groupName, description, created, updated, isOpen, reference)); + groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, reference)); + } while (resultSet.next()); + + return groups; + } catch (SQLException e) { + throw new DataException("Unable to fetch account's groups from repository", e); + } + } + + @Override + public List getGroupsWithMember(String member) throws DataException { + List groups = new ArrayList<>(); + + try (ResultSet resultSet = this.repository.checkedExecute( + "SELECT group_id, owner, group_name, description, created, updated, reference, is_open FROM Groups JOIN GroupMembers USING (group_id) WHERE address = ?", + member)) { + if (resultSet == null) + return groups; + + do { + int groupId = resultSet.getInt(1); + String owner = resultSet.getString(2); + String groupName = resultSet.getString(3); + String description = resultSet.getString(4); + long created = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + + // Special handling for possibly-NULL "updated" column + Timestamp updatedTimestamp = resultSet.getTimestamp(6, Calendar.getInstance(HSQLDBRepository.UTC)); + Long updated = updatedTimestamp == null ? null : updatedTimestamp.getTime(); + + byte[] reference = resultSet.getBytes(7); + boolean isOpen = resultSet.getBoolean(8); + + groups.add(new GroupData(groupId, owner, groupName, description, created, updated, isOpen, reference)); } while (resultSet.next()); return groups; @@ -122,36 +192,48 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public void save(GroupData groupData) throws DataException { - HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroups"); + HSQLDBSaver saveHelper = new HSQLDBSaver("Groups"); // Special handling for "updated" timestamp Long updated = groupData.getUpdated(); Timestamp updatedTimestamp = updated == null ? null : new Timestamp(updated); - saveHelper.bind("owner", groupData.getOwner()).bind("group_name", groupData.getGroupName()).bind("description", groupData.getDescription()) - .bind("created", new Timestamp(groupData.getCreated())).bind("updated", updatedTimestamp).bind("reference", groupData.getReference()) - .bind("is_open", groupData.getIsOpen()); + saveHelper.bind("group_id", groupData.getGroupId()).bind("owner", groupData.getOwner()).bind("group_name", groupData.getGroupName()) + .bind("description", groupData.getDescription()).bind("created", new Timestamp(groupData.getCreated())).bind("updated", updatedTimestamp) + .bind("reference", groupData.getReference()).bind("is_open", groupData.getIsOpen()); try { saveHelper.execute(this.repository); + + if (groupData.getGroupId() == null) { + // Fetch new groupId + try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id FROM Groups WHERE reference = ?", groupData.getReference())) { + if (resultSet == null) + throw new DataException("Unable to fetch new group ID from repository"); + + groupData.setGroupId(resultSet.getInt(1)); + } + } } catch (SQLException e) { throw new DataException("Unable to save group info into repository", e); } } + @Override + public void delete(int groupId) throws DataException { + try { + // Remove group + this.repository.delete("Groups", "group_id = ?", groupId); + } catch (SQLException e) { + throw new DataException("Unable to delete group info from repository", e); + } + } + @Override public void delete(String groupName) throws DataException { try { - // Remove invites - this.repository.delete("AccountGroupInvites", "group_name = ?", groupName); - // Remove bans - this.repository.delete("AccountGroupBans", "group_name = ?", groupName); - // Remove members - this.repository.delete("AccountGroupMembers", "group_name = ?", groupName); - // Remove admins - this.repository.delete("AccountGroupAdmins", "group_name = ?", groupName); // Remove group - this.repository.delete("AccountGroups", "group_name = ?", groupName); + this.repository.delete("Groups", "group_name = ?", groupName); } catch (SQLException e) { throw new DataException("Unable to delete group info from repository", e); } @@ -160,42 +242,42 @@ public class HSQLDBGroupRepository implements GroupRepository { // 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)) { + public GroupAdminData getAdmin(int groupId, String address) throws DataException { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT admin, reference FROM GroupAdmins WHERE group_id = ?", groupId)) { if (resultSet == null) return null; String admin = resultSet.getString(1); - byte[] groupReference = resultSet.getBytes(2); + byte[] reference = resultSet.getBytes(2); - return new GroupAdminData(groupName, admin, groupReference); + return new GroupAdminData(groupId, admin, reference); } catch (SQLException e) { throw new DataException("Unable to fetch group admin from repository", e); } } @Override - public boolean adminExists(String groupName, String address) throws DataException { + public boolean adminExists(int groupId, String address) throws DataException { try { - return this.repository.exists("AccountGroupAdmins", "group_name = ? AND admin = ?", groupName, address); + return this.repository.exists("GroupAdmins", "group_id = ? AND admin = ?", groupId, address); } catch (SQLException e) { throw new DataException("Unable to check for group admin in repository", e); } } @Override - public List getGroupAdmins(String groupName) throws DataException { + public List getGroupAdmins(int groupId) throws DataException { List admins = new ArrayList<>(); - try (ResultSet resultSet = this.repository.checkedExecute("SELECT admin, group_reference FROM AccountGroupAdmins WHERE group_name = ?", groupName)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT admin, reference FROM GroupAdmins WHERE group_id = ?", groupId)) { if (resultSet == null) return admins; do { String admin = resultSet.getString(1); - byte[] groupReference = resultSet.getBytes(2); + byte[] reference = resultSet.getBytes(2); - admins.add(new GroupAdminData(groupName, admin, groupReference)); + admins.add(new GroupAdminData(groupId, admin, reference)); } while (resultSet.next()); return admins; @@ -206,10 +288,9 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public void save(GroupAdminData groupAdminData) throws DataException { - HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupAdmins"); + HSQLDBSaver saveHelper = new HSQLDBSaver("GroupAdmins"); - saveHelper.bind("group_name", groupAdminData.getGroupName()).bind("admin", groupAdminData.getAdmin()).bind("group_reference", - groupAdminData.getGroupReference()); + saveHelper.bind("group_id", groupAdminData.getGroupId()).bind("admin", groupAdminData.getAdmin()).bind("reference", groupAdminData.getReference()); try { saveHelper.execute(this.repository); @@ -219,9 +300,9 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - public void deleteAdmin(String groupName, String address) throws DataException { + public void deleteAdmin(int groupId, String address) throws DataException { try { - this.repository.delete("AccountGroupAdmins", "group_name = ? AND admin = ?", groupName, address); + this.repository.delete("GroupAdmins", "group_id = ? AND admin = ?", groupId, address); } catch (SQLException e) { throw new DataException("Unable to delete group admin info from repository", e); } @@ -230,46 +311,44 @@ public class HSQLDBGroupRepository implements GroupRepository { // Group Members @Override - 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)) { + public GroupMemberData getMember(int groupId, String address) throws DataException { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT address, joined, reference FROM GroupMembers WHERE group_id = ?", groupId)) { 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); + byte[] reference = resultSet.getBytes(3); - return new GroupMemberData(groupName, member, joined, groupReference); + return new GroupMemberData(groupId, member, joined, reference); } catch (SQLException e) { throw new DataException("Unable to fetch group members from repository", e); } } @Override - public boolean memberExists(String groupName, String address) throws DataException { + public boolean memberExists(int groupId, String address) throws DataException { try { - return this.repository.exists("AccountGroupMembers", "group_name = ? AND address = ?", groupName, address); + return this.repository.exists("GroupMembers", "group_id = ? AND address = ?", groupId, address); } catch (SQLException e) { throw new DataException("Unable to check for group member in repository", e); } } @Override - public List getGroupMembers(String groupName) throws DataException { + public List getGroupMembers(int groupId) throws DataException { List members = new ArrayList<>(); - try (ResultSet resultSet = this.repository.checkedExecute("SELECT address, joined, group_reference FROM AccountGroupMembers WHERE group_name = ?", - groupName)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT address, joined, reference FROM GroupMembers WHERE group_id = ?", groupId)) { if (resultSet == null) return members; do { String member = resultSet.getString(1); long joined = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); - byte[] groupReference = resultSet.getBytes(3); + byte[] reference = resultSet.getBytes(3); - members.add(new GroupMemberData(groupName, member, joined, groupReference)); + members.add(new GroupMemberData(groupId, member, joined, reference)); } while (resultSet.next()); return members; @@ -279,9 +358,10 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - 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)) { + public Integer countGroupMembers(int groupId) throws DataException { + // "GROUP BY" clause required to avoid error "expression not in aggregate or GROUP BY columns: PUBLIC.GROUPS.GROUP_ID" + try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id, COUNT(*) FROM GroupMembers WHERE group_id = ? GROUP BY group_id", + groupId)) { if (resultSet == null) return null; @@ -293,10 +373,10 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public void save(GroupMemberData groupMemberData) throws DataException { - HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupMembers"); + HSQLDBSaver saveHelper = new HSQLDBSaver("GroupMembers"); - saveHelper.bind("group_name", groupMemberData.getGroupName()).bind("address", groupMemberData.getMember()) - .bind("joined", new Timestamp(groupMemberData.getJoined())).bind("group_reference", groupMemberData.getGroupReference()); + saveHelper.bind("group_id", groupMemberData.getGroupId()).bind("address", groupMemberData.getMember()) + .bind("joined", new Timestamp(groupMemberData.getJoined())).bind("reference", groupMemberData.getReference()); try { saveHelper.execute(this.repository); @@ -306,9 +386,9 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - public void deleteMember(String groupName, String address) throws DataException { + public void deleteMember(int groupId, String address) throws DataException { try { - this.repository.delete("AccountGroupMembers", "group_name = ? AND address = ?", groupName, address); + this.repository.delete("GroupMembers", "group_id = ? AND address = ?", groupId, address); } catch (SQLException e) { throw new DataException("Unable to delete group member info from repository", e); } @@ -317,46 +397,38 @@ public class HSQLDBGroupRepository implements GroupRepository { // Group Invites @Override - public GroupInviteData getInvite(String groupName, String inviter, String invitee) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT expiry, reference FROM AccountGroupInvites WHERE group_name = ?", groupName)) { + public GroupInviteData getInvite(int groupId, String invitee) throws DataException { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT inviter, expiry, reference FROM GroupInvites WHERE group_id = ? AND invitee = ?", + groupId, invitee)) { if (resultSet == null) return null; - Timestamp expiryTimestamp = resultSet.getTimestamp(1, Calendar.getInstance(HSQLDBRepository.UTC)); + String inviter = resultSet.getString(1); + Timestamp expiryTimestamp = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)); Long expiry = expiryTimestamp == null ? null : expiryTimestamp.getTime(); - byte[] reference = resultSet.getBytes(2); + byte[] reference = resultSet.getBytes(3); - return new GroupInviteData(groupName, inviter, invitee, expiry, reference); + return new GroupInviteData(groupId, inviter, invitee, expiry, reference); } catch (SQLException e) { throw new DataException("Unable to fetch group invite from repository", e); } } @Override - public boolean inviteExists(String groupName, String invitee) throws DataException { + public boolean inviteExists(int groupId, String invitee) throws DataException { try { - return this.repository.exists("AccountGroupInvites", "group_name = ? AND invitee = ?", groupName, invitee); + return this.repository.exists("GroupInvites", "group_id = ? AND invitee = ?", groupId, invitee); } catch (SQLException e) { throw new DataException("Unable to check for group invite in repository", e); } } @Override - public boolean inviteExists(String groupName, String inviter, String invitee) throws DataException { - try { - return this.repository.exists("AccountGroupInvites", "group_name = ? AND inviter = ? AND invitee = ?", groupName, inviter, invitee); - } catch (SQLException e) { - throw new DataException("Unable to check for group invite in repository", e); - } - } - - @Override - public List getGroupInvites(String groupName) throws DataException { + public List getGroupInvites(int groupId) throws DataException { List invites = new ArrayList<>(); - try (ResultSet resultSet = this.repository.checkedExecute("SELECT inviter, invitee, expiry, reference FROM AccountGroupInvites WHERE group_name = ?", - groupName)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT inviter, invitee, expiry, reference FROM GroupInvites WHERE group_id = ?", groupId)) { if (resultSet == null) return invites; @@ -369,7 +441,7 @@ public class HSQLDBGroupRepository implements GroupRepository { byte[] reference = resultSet.getBytes(4); - invites.add(new GroupInviteData(groupName, inviter, invitee, expiry, reference)); + invites.add(new GroupInviteData(groupId, inviter, invitee, expiry, reference)); } while (resultSet.next()); return invites; @@ -379,23 +451,23 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - public List getInvitesByInvitee(String groupName, String invitee) throws DataException { + public List getInvitesByInvitee(String invitee) throws DataException { List invites = new ArrayList<>(); - try (ResultSet resultSet = this.repository - .checkedExecute("SELECT inviter, expiry, reference FROM AccountGroupInvites WHERE group_name = ? AND invitee = ?", groupName, invitee)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id, inviter, expiry, reference FROM GroupInvites WHERE invitee = ?", invitee)) { if (resultSet == null) return invites; do { - String inviter = resultSet.getString(1); + int groupId = resultSet.getInt(1); + String inviter = resultSet.getString(2); - Timestamp expiryTimestamp = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)); + Timestamp expiryTimestamp = resultSet.getTimestamp(3, Calendar.getInstance(HSQLDBRepository.UTC)); Long expiry = expiryTimestamp == null ? null : expiryTimestamp.getTime(); - byte[] reference = resultSet.getBytes(3); + byte[] reference = resultSet.getBytes(4); - invites.add(new GroupInviteData(groupName, inviter, invitee, expiry, reference)); + invites.add(new GroupInviteData(groupId, inviter, invitee, expiry, reference)); } while (resultSet.next()); return invites; @@ -406,14 +478,14 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public void save(GroupInviteData groupInviteData) throws DataException { - HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupInvites"); + HSQLDBSaver saveHelper = new HSQLDBSaver("GroupInvites"); Timestamp expiryTimestamp = null; if (groupInviteData.getExpiry() != null) expiryTimestamp = new Timestamp(groupInviteData.getExpiry()); - saveHelper.bind("group_name", groupInviteData.getGroupName()).bind("inviter", groupInviteData.getInviter()) - .bind("invitee", groupInviteData.getInvitee()).bind("expiry", expiryTimestamp).bind("reference", groupInviteData.getReference()); + saveHelper.bind("group_id", groupInviteData.getGroupId()).bind("inviter", groupInviteData.getInviter()).bind("invitee", groupInviteData.getInvitee()) + .bind("expiry", expiryTimestamp).bind("reference", groupInviteData.getReference()); try { saveHelper.execute(this.repository); @@ -423,9 +495,9 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - public void deleteInvite(String groupName, String inviter, String invitee) throws DataException { + public void deleteInvite(int groupId, String invitee) throws DataException { try { - this.repository.delete("AccountGroupInvites", "group_name = ? AND inviter = ? AND invitee = ?", groupName, inviter, invitee); + this.repository.delete("GroupInvites", "group_id = ? AND invitee = ?", groupId, invitee); } catch (SQLException e) { throw new DataException("Unable to delete group invite from repository", e); } @@ -434,26 +506,42 @@ public class HSQLDBGroupRepository implements GroupRepository { // Group Join Requests @Override - public boolean joinRequestExists(String groupName, String joiner) throws DataException { + public GroupJoinRequestData getJoinRequest(Integer groupId, String joiner) throws DataException { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT reference FROM GroupJoinRequests WHERE group_id = ? AND joiner = ?", groupId, + joiner)) { + if (resultSet == null) + return null; + + byte[] reference = resultSet.getBytes(1); + + return new GroupJoinRequestData(groupId, joiner, reference); + } catch (SQLException e) { + throw new DataException("Unable to fetch group join requests from repository", e); + } + } + + @Override + public boolean joinRequestExists(int groupId, String joiner) throws DataException { try { - return this.repository.exists("AccountGroupJoinRequests", "group_name = ? AND joiner = ?", groupName, joiner); + return this.repository.exists("GroupJoinRequests", "group_id = ? AND joiner = ?", groupId, joiner); } catch (SQLException e) { throw new DataException("Unable to check for group join request in repository", e); } } @Override - public List getGroupJoinRequests(String groupName) throws DataException { + public List getGroupJoinRequests(int groupId) throws DataException { List joinRequests = new ArrayList<>(); - try (ResultSet resultSet = this.repository.checkedExecute("SELECT joiner FROM AccountGroupJoinRequests WHERE group_name = ?", groupName)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT joiner, reference FROM GroupJoinRequests WHERE group_id = ?", groupId)) { if (resultSet == null) return joinRequests; do { String joiner = resultSet.getString(1); + byte[] reference = resultSet.getBytes(2); - joinRequests.add(new GroupJoinRequestData(groupName, joiner)); + joinRequests.add(new GroupJoinRequestData(groupId, joiner, reference)); } while (resultSet.next()); return joinRequests; @@ -464,9 +552,10 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public void save(GroupJoinRequestData groupJoinRequestData) throws DataException { - HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupJoinRequests"); + HSQLDBSaver saveHelper = new HSQLDBSaver("GroupJoinRequests"); - saveHelper.bind("group_name", groupJoinRequestData.getGroupName()).bind("joiner", groupJoinRequestData.getJoiner()); + saveHelper.bind("group_id", groupJoinRequestData.getGroupId()).bind("joiner", groupJoinRequestData.getJoiner()).bind("reference", + groupJoinRequestData.getReference()); try { saveHelper.execute(this.repository); @@ -476,9 +565,9 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - public void deleteJoinRequest(String groupName, String joiner) throws DataException { + public void deleteJoinRequest(int groupId, String joiner) throws DataException { try { - this.repository.delete("AccountGroupJoinRequests", "group_name = ? AND joiner = ?", groupName, joiner); + this.repository.delete("GroupJoinRequests", "group_id = ? AND joiner = ?", groupId, joiner); } catch (SQLException e) { throw new DataException("Unable to delete group join request from repository", e); } @@ -487,40 +576,39 @@ public class HSQLDBGroupRepository implements GroupRepository { // Group Bans @Override - public GroupBanData getBan(String groupName, String member) throws DataException { + public GroupBanData getBan(int groupId, String offender) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT offender, admin, banned, reason, expiry, reference FROM AccountGroupBans WHERE group_name = ?", groupName)) { - String offender = resultSet.getString(1); - String admin = resultSet.getString(2); - long banned = resultSet.getTimestamp(3, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); - String reason = resultSet.getString(4); + .checkedExecute("SELECT admin, banned, reason, expiry, reference FROM GroupBans WHERE group_id = ? AND offender = ?", groupId, offender)) { + String admin = resultSet.getString(1); + long banned = resultSet.getTimestamp(2, Calendar.getInstance(HSQLDBRepository.UTC)).getTime(); + String reason = resultSet.getString(3); - Timestamp expiryTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC)); + Timestamp expiryTimestamp = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)); Long expiry = expiryTimestamp == null ? null : expiryTimestamp.getTime(); - byte[] reference = resultSet.getBytes(6); + byte[] reference = resultSet.getBytes(5); - return new GroupBanData(groupName, offender, admin, banned, reason, expiry, reference); + return new GroupBanData(groupId, offender, admin, banned, reason, expiry, reference); } catch (SQLException e) { throw new DataException("Unable to fetch group bans from repository", e); } } @Override - public boolean banExists(String groupName, String offender) throws DataException { + public boolean banExists(int groupId, String offender) throws DataException { try { - return this.repository.exists("AccountGroupBans", "group_name = ? AND offender = ?", groupName, offender); + return this.repository.exists("GroupBans", "group_id = ? AND offender = ?", groupId, offender); } catch (SQLException e) { throw new DataException("Unable to check for group ban in repository", e); } } @Override - public List getGroupBans(String groupName) throws DataException { + public List getGroupBans(int groupId) throws DataException { List bans = new ArrayList<>(); - try (ResultSet resultSet = this.repository - .checkedExecute("SELECT offender, admin, banned, reason, expiry, reference FROM AccountGroupBans WHERE group_name = ?", groupName)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT offender, admin, banned, reason, expiry, reference FROM GroupBans WHERE group_id = ?", + groupId)) { if (resultSet == null) return bans; @@ -535,7 +623,7 @@ public class HSQLDBGroupRepository implements GroupRepository { byte[] reference = resultSet.getBytes(6); - bans.add(new GroupBanData(groupName, offender, admin, banned, reason, expiry, reference)); + bans.add(new GroupBanData(groupId, offender, admin, banned, reason, expiry, reference)); } while (resultSet.next()); return bans; @@ -546,13 +634,13 @@ public class HSQLDBGroupRepository implements GroupRepository { @Override public void save(GroupBanData groupBanData) throws DataException { - HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupBans"); + HSQLDBSaver saveHelper = new HSQLDBSaver("GroupBans"); Timestamp expiryTimestamp = null; if (groupBanData.getExpiry() != null) expiryTimestamp = new Timestamp(groupBanData.getExpiry()); - saveHelper.bind("group_name", groupBanData.getGroupName()).bind("offender", groupBanData.getOffender()).bind("admin", groupBanData.getAdmin()) + saveHelper.bind("group_id", groupBanData.getGroupId()).bind("offender", groupBanData.getOffender()).bind("admin", groupBanData.getAdmin()) .bind("banned", new Timestamp(groupBanData.getBanned())).bind("reason", groupBanData.getReason()).bind("expiry", expiryTimestamp) .bind("reference", groupBanData.getReference()); @@ -564,9 +652,9 @@ public class HSQLDBGroupRepository implements GroupRepository { } @Override - public void deleteBan(String groupName, String offender) throws DataException { + public void deleteBan(int groupId, String offender) throws DataException { try { - this.repository.delete("AccountGroupBans", "group_name = ? AND offender = ?", groupName, offender); + this.repository.delete("GroupBans", "group_id = ? AND offender = ?", groupId, offender); } catch (SQLException e) { throw new DataException("Unable to delete group ban from repository", e); } diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBAddGroupAdminTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBAddGroupAdminTransactionRepository.java index 3eb76790..5388c184 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBAddGroupAdminTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBAddGroupAdminTransactionRepository.java @@ -17,14 +17,14 @@ public class HSQLDBAddGroupAdminTransactionRepository extends HSQLDBTransactionR } TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_name, address FROM AddGroupAdminTransactions WHERE signature = ?", signature)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id, address FROM AddGroupAdminTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String member = resultSet.getString(2); - return new AddGroupAdminTransactionData(creatorPublicKey, groupName, member, fee, timestamp, reference, signature); + return new AddGroupAdminTransactionData(creatorPublicKey, groupId, member, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch add group admin transaction from repository", e); } @@ -37,7 +37,7 @@ public class HSQLDBAddGroupAdminTransactionRepository extends HSQLDBTransactionR HSQLDBSaver saveHelper = new HSQLDBSaver("AddGroupAdminTransactions"); saveHelper.bind("signature", addGroupAdminTransactionData.getSignature()).bind("owner", addGroupAdminTransactionData.getOwnerPublicKey()) - .bind("group_name", addGroupAdminTransactionData.getGroupName()).bind("address", addGroupAdminTransactionData.getMember()); + .bind("group_id", addGroupAdminTransactionData.getGroupId()).bind("address", addGroupAdminTransactionData.getMember()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupUnbanTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupBanTransactionRepository.java similarity index 58% rename from src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupUnbanTransactionRepository.java rename to src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupBanTransactionRepository.java index 148896f1..605eab7b 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupUnbanTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupBanTransactionRepository.java @@ -4,29 +4,29 @@ import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; -import org.qora.data.transaction.GroupUnbanTransactionData; +import org.qora.data.transaction.CancelGroupBanTransactionData; 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 HSQLDBGroupUnbanTransactionRepository extends HSQLDBTransactionRepository { +public class HSQLDBCancelGroupBanTransactionRepository extends HSQLDBTransactionRepository { - public HSQLDBGroupUnbanTransactionRepository(HSQLDBRepository repository) { + public HSQLDBCancelGroupBanTransactionRepository(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, address, group_reference FROM GroupUnbanTransactions WHERE signature = ?", + try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id, address, ban_reference FROM CancelGroupBanTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String member = resultSet.getString(2); - byte[] groupReference = resultSet.getBytes(3); + byte[] banReference = resultSet.getBytes(3); - return new GroupUnbanTransactionData(creatorPublicKey, groupName, member, groupReference, fee, timestamp, reference, signature); + return new CancelGroupBanTransactionData(creatorPublicKey, groupId, member, banReference, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch group unban transaction from repository", e); } @@ -34,13 +34,13 @@ public class HSQLDBGroupUnbanTransactionRepository extends HSQLDBTransactionRepo @Override public void save(TransactionData transactionData) throws DataException { - GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) transactionData; + CancelGroupBanTransactionData groupUnbanTransactionData = (CancelGroupBanTransactionData) transactionData; - HSQLDBSaver saveHelper = new HSQLDBSaver("GroupUnbanTransactions"); + HSQLDBSaver saveHelper = new HSQLDBSaver("CancelGroupBanTransactions"); saveHelper.bind("signature", groupUnbanTransactionData.getSignature()).bind("admin", groupUnbanTransactionData.getAdminPublicKey()) - .bind("group_name", groupUnbanTransactionData.getGroupName()).bind("address", groupUnbanTransactionData.getMember()) - .bind("group_reference", groupUnbanTransactionData.getGroupReference()); + .bind("group_id", groupUnbanTransactionData.getGroupId()).bind("address", groupUnbanTransactionData.getMember()) + .bind("ban_reference", groupUnbanTransactionData.getBanReference()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupInviteTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupInviteTransactionRepository.java index aeae1ef4..a35a58c5 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupInviteTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCancelGroupInviteTransactionRepository.java @@ -18,14 +18,15 @@ public class HSQLDBCancelGroupInviteTransactionRepository extends HSQLDBTransact TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_name, invitee FROM CancelGroupInviteTransactions WHERE signature = ?", signature)) { + .checkedExecute("SELECT group_id, invitee, invite_reference FROM CancelGroupInviteTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String invitee = resultSet.getString(2); + byte[] inviteReference = resultSet.getBytes(3); - return new CancelGroupInviteTransactionData(creatorPublicKey, groupName, invitee, fee, timestamp, reference, signature); + return new CancelGroupInviteTransactionData(creatorPublicKey, groupId, invitee, inviteReference, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch cancel group invite transaction from repository", e); } @@ -38,7 +39,8 @@ public class HSQLDBCancelGroupInviteTransactionRepository extends HSQLDBTransact HSQLDBSaver saveHelper = new HSQLDBSaver("CancelGroupInviteTransactions"); saveHelper.bind("signature", cancelGroupInviteTransactionData.getSignature()).bind("admin", cancelGroupInviteTransactionData.getAdminPublicKey()) - .bind("group_name", cancelGroupInviteTransactionData.getGroupName()).bind("invitee", cancelGroupInviteTransactionData.getInvitee()); + .bind("group_id", cancelGroupInviteTransactionData.getGroupId()).bind("invitee", cancelGroupInviteTransactionData.getInvitee()) + .bind("invite_reference", cancelGroupInviteTransactionData.getInviteReference()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCreateGroupTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCreateGroupTransactionRepository.java index d51cd9d5..1d8b3c83 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCreateGroupTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBCreateGroupTransactionRepository.java @@ -17,8 +17,8 @@ public class HSQLDBCreateGroupTransactionRepository extends HSQLDBTransactionRep } TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT owner, group_name, description, is_open FROM CreateGroupTransactions WHERE signature = ?", - signature)) { + try (ResultSet resultSet = this.repository + .checkedExecute("SELECT owner, group_name, description, is_open, group_id FROM CreateGroupTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; @@ -27,7 +27,11 @@ public class HSQLDBCreateGroupTransactionRepository extends HSQLDBTransactionRep String description = resultSet.getString(3); boolean isOpen = resultSet.getBoolean(4); - return new CreateGroupTransactionData(creatorPublicKey, owner, groupName, description, isOpen, fee, timestamp, reference, signature); + Integer groupId = resultSet.getInt(5); + if (resultSet.wasNull()) + groupId = null; + + return new CreateGroupTransactionData(creatorPublicKey, owner, groupName, description, isOpen, groupId, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch create group transaction from repository", e); } @@ -41,7 +45,8 @@ public class HSQLDBCreateGroupTransactionRepository extends HSQLDBTransactionRep saveHelper.bind("signature", createGroupTransactionData.getSignature()).bind("creator", createGroupTransactionData.getCreatorPublicKey()) .bind("owner", createGroupTransactionData.getOwner()).bind("group_name", createGroupTransactionData.getGroupName()) - .bind("description", createGroupTransactionData.getDescription()).bind("is_open", createGroupTransactionData.getIsOpen()); + .bind("description", createGroupTransactionData.getDescription()).bind("is_open", createGroupTransactionData.getIsOpen()) + .bind("group_id", createGroupTransactionData.getGroupId()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupBanTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupBanTransactionRepository.java index 51dd2cc7..fe3806cf 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupBanTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupBanTransactionRepository.java @@ -18,20 +18,21 @@ public class HSQLDBGroupBanTransactionRepository extends HSQLDBTransactionReposi TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { try (ResultSet resultSet = this.repository.checkedExecute( - "SELECT group_name, address, reason, time_to_live, member_reference, admin_reference FROM GroupBanTransactions WHERE signature = ?", + "SELECT group_id, address, reason, time_to_live, member_reference, admin_reference, join_invite_reference FROM GroupBanTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String offender = resultSet.getString(2); String reason = resultSet.getString(3); int timeToLive = resultSet.getInt(4); byte[] memberReference = resultSet.getBytes(5); byte[] adminReference = resultSet.getBytes(6); + byte[] joinInviteReference = resultSet.getBytes(7); - return new GroupBanTransactionData(creatorPublicKey, groupName, offender, reason, timeToLive, memberReference, adminReference, fee, timestamp, - reference, signature); + return new GroupBanTransactionData(creatorPublicKey, groupId, offender, reason, timeToLive, memberReference, adminReference, joinInviteReference, + fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch group ban transaction from repository", e); } @@ -44,9 +45,10 @@ public class HSQLDBGroupBanTransactionRepository extends HSQLDBTransactionReposi HSQLDBSaver saveHelper = new HSQLDBSaver("GroupBanTransactions"); saveHelper.bind("signature", groupBanTransactionData.getSignature()).bind("admin", groupBanTransactionData.getAdminPublicKey()) - .bind("group_name", groupBanTransactionData.getGroupName()).bind("address", groupBanTransactionData.getOffender()) + .bind("group_id", groupBanTransactionData.getGroupId()).bind("address", groupBanTransactionData.getOffender()) .bind("reason", groupBanTransactionData.getReason()).bind("time_to_live", groupBanTransactionData.getTimeToLive()) - .bind("member_reference", groupBanTransactionData.getMemberReference()).bind("admin_reference", groupBanTransactionData.getAdminReference()); + .bind("member_reference", groupBanTransactionData.getMemberReference()).bind("admin_reference", groupBanTransactionData.getAdminReference()) + .bind("join_invite_reference", groupBanTransactionData.getJoinInviteReference()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupInviteTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupInviteTransactionRepository.java index 139ab603..d1fbe37c 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupInviteTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupInviteTransactionRepository.java @@ -3,8 +3,6 @@ package org.qora.repository.hsqldb.transaction; import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; import org.qora.data.transaction.GroupInviteTransactionData; import org.qora.data.transaction.TransactionData; @@ -20,16 +18,16 @@ public class HSQLDBGroupInviteTransactionRepository extends HSQLDBTransactionRep TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_name, invitee, time_to_live, group_reference FROM GroupInviteTransactions WHERE signature = ?", signature)) { + .checkedExecute("SELECT group_id, invitee, time_to_live, join_reference FROM GroupInviteTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String invitee = resultSet.getString(2); int timeToLive = resultSet.getInt(3); - byte[] groupReference = resultSet.getBytes(4); + byte[] joinReference = resultSet.getBytes(4); - return new GroupInviteTransactionData(creatorPublicKey, groupName, invitee, timeToLive, groupReference, fee, timestamp, reference, signature); + return new GroupInviteTransactionData(creatorPublicKey, groupId, invitee, timeToLive, joinReference, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch group invite transaction from repository", e); } @@ -42,8 +40,8 @@ public class HSQLDBGroupInviteTransactionRepository extends HSQLDBTransactionRep HSQLDBSaver saveHelper = new HSQLDBSaver("GroupInviteTransactions"); saveHelper.bind("signature", groupInviteTransactionData.getSignature()).bind("admin", groupInviteTransactionData.getAdminPublicKey()) - .bind("group_name", groupInviteTransactionData.getGroupName()).bind("invitee", groupInviteTransactionData.getInvitee()) - .bind("time_to_live", groupInviteTransactionData.getTimeToLive()).bind("group_reference", groupInviteTransactionData.getGroupReference()); + .bind("group_id", groupInviteTransactionData.getGroupId()).bind("invitee", groupInviteTransactionData.getInvitee()) + .bind("time_to_live", groupInviteTransactionData.getTimeToLive()).bind("join_reference", groupInviteTransactionData.getJoinReference()); try { saveHelper.execute(this.repository); @@ -52,25 +50,4 @@ public class HSQLDBGroupInviteTransactionRepository extends HSQLDBTransactionRep } } - @Override - public List getInvitesWithGroupReference(byte[] groupReference) throws DataException { - List invites = new ArrayList<>(); - - try (ResultSet resultSet = this.repository - .checkedExecute("SELECT signature FROM GroupInviteTransactions WHERE group_reference = ?", groupReference)) { - if (resultSet == null) - return invites; - - do { - byte[] signature = resultSet.getBytes(1); - - invites.add((GroupInviteTransactionData) this.repository.getTransactionRepository().fromSignature(signature)); - } while (resultSet.next()); - - return invites; - } catch (SQLException e) { - throw new DataException("Unable to fetch group invite transaction from repository", e); - } - } - } diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupKickTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupKickTransactionRepository.java index d2cf26bb..4b9c32e3 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupKickTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBGroupKickTransactionRepository.java @@ -18,18 +18,20 @@ public class HSQLDBGroupKickTransactionRepository extends HSQLDBTransactionRepos TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { try (ResultSet resultSet = this.repository.checkedExecute( - "SELECT group_name, address, reason, member_reference, admin_reference FROM GroupKickTransactions WHERE signature = ?", signature)) { + "SELECT group_id, address, reason, member_reference, admin_reference, join_reference FROM GroupKickTransactions WHERE signature = ?", + signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String member = resultSet.getString(2); String reason = resultSet.getString(3); byte[] memberReference = resultSet.getBytes(4); byte[] adminReference = resultSet.getBytes(5); + byte[] joinReference = resultSet.getBytes(6); - return new GroupKickTransactionData(creatorPublicKey, groupName, member, reason, memberReference, adminReference, fee, timestamp, reference, - signature); + return new GroupKickTransactionData(creatorPublicKey, groupId, member, reason, memberReference, adminReference, joinReference, fee, timestamp, + reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch group kick transaction from repository", e); } @@ -42,9 +44,9 @@ public class HSQLDBGroupKickTransactionRepository extends HSQLDBTransactionRepos HSQLDBSaver saveHelper = new HSQLDBSaver("GroupKickTransactions"); saveHelper.bind("signature", groupKickTransactionData.getSignature()).bind("admin", groupKickTransactionData.getAdminPublicKey()) - .bind("group_name", groupKickTransactionData.getGroupName()).bind("address", groupKickTransactionData.getMember()) + .bind("group_id", groupKickTransactionData.getGroupId()).bind("address", groupKickTransactionData.getMember()) .bind("reason", groupKickTransactionData.getReason()).bind("member_reference", groupKickTransactionData.getMemberReference()) - .bind("admin_reference", groupKickTransactionData.getAdminReference()); + .bind("admin_reference", groupKickTransactionData.getAdminReference()).bind("join_reference", groupKickTransactionData.getJoinReference()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBJoinGroupTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBJoinGroupTransactionRepository.java index 3db60d36..b54bef75 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBJoinGroupTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBJoinGroupTransactionRepository.java @@ -17,13 +17,15 @@ public class HSQLDBJoinGroupTransactionRepository extends HSQLDBTransactionRepos } TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_name FROM JoinGroupTransactions WHERE signature = ?", signature)) { + try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_id, invite_reference FROM JoinGroupTransactions WHERE signature = ?", + signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); + byte[] inviteReference = resultSet.getBytes(2); - return new JoinGroupTransactionData(creatorPublicKey, groupName, fee, timestamp, reference, signature); + return new JoinGroupTransactionData(creatorPublicKey, groupId, inviteReference, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch join group transaction from repository", e); } @@ -36,7 +38,7 @@ public class HSQLDBJoinGroupTransactionRepository extends HSQLDBTransactionRepos HSQLDBSaver saveHelper = new HSQLDBSaver("JoinGroupTransactions"); saveHelper.bind("signature", joinGroupTransactionData.getSignature()).bind("joiner", joinGroupTransactionData.getJoinerPublicKey()) - .bind("group_name", joinGroupTransactionData.getGroupName()); + .bind("group_id", joinGroupTransactionData.getGroupId()).bind("invite_reference", joinGroupTransactionData.getInviteReference()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBLeaveGroupTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBLeaveGroupTransactionRepository.java index 7bf66f08..872d119e 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBLeaveGroupTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBLeaveGroupTransactionRepository.java @@ -18,15 +18,15 @@ public class HSQLDBLeaveGroupTransactionRepository extends HSQLDBTransactionRepo 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)) { + .checkedExecute("SELECT group_id, member_reference, admin_reference FROM LeaveGroupTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); byte[] memberReference = resultSet.getBytes(2); byte[] adminReference = resultSet.getBytes(3); - return new LeaveGroupTransactionData(creatorPublicKey, groupName, memberReference, adminReference, fee, timestamp, reference, signature); + return new LeaveGroupTransactionData(creatorPublicKey, groupId, memberReference, adminReference, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch leave group transaction from repository", e); } @@ -39,7 +39,7 @@ public class HSQLDBLeaveGroupTransactionRepository extends HSQLDBTransactionRepo 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("group_id", leaveGroupTransactionData.getGroupId()).bind("member_reference", leaveGroupTransactionData.getMemberReference()) .bind("admin_reference", leaveGroupTransactionData.getAdminReference()); try { diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBRemoveGroupAdminTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBRemoveGroupAdminTransactionRepository.java index 45304d92..ca69996b 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBRemoveGroupAdminTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBRemoveGroupAdminTransactionRepository.java @@ -18,15 +18,15 @@ public class HSQLDBRemoveGroupAdminTransactionRepository extends HSQLDBTransacti TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { try (ResultSet resultSet = this.repository - .checkedExecute("SELECT group_name, admin, group_reference FROM RemoveGroupAdminTransactions WHERE signature = ?", signature)) { + .checkedExecute("SELECT group_id, admin, admin_reference FROM RemoveGroupAdminTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String admin = resultSet.getString(2); - byte[] groupReference = resultSet.getBytes(3); + byte[] adminReference = resultSet.getBytes(3); - return new RemoveGroupAdminTransactionData(creatorPublicKey, groupName, admin, groupReference, fee, timestamp, reference, signature); + return new RemoveGroupAdminTransactionData(creatorPublicKey, groupId, admin, adminReference, fee, timestamp, reference, signature); } catch (SQLException e) { throw new DataException("Unable to fetch remove group admin transaction from repository", e); } @@ -39,8 +39,8 @@ public class HSQLDBRemoveGroupAdminTransactionRepository extends HSQLDBTransacti HSQLDBSaver saveHelper = new HSQLDBSaver("RemoveGroupAdminTransactions"); saveHelper.bind("signature", removeGroupAdminTransactionData.getSignature()).bind("owner", removeGroupAdminTransactionData.getOwnerPublicKey()) - .bind("group_name", removeGroupAdminTransactionData.getGroupName()).bind("admin", removeGroupAdminTransactionData.getAdmin()) - .bind("group_reference", removeGroupAdminTransactionData.getGroupReference()); + .bind("group_id", removeGroupAdminTransactionData.getGroupId()).bind("admin", removeGroupAdminTransactionData.getAdmin()) + .bind("admin_reference", removeGroupAdminTransactionData.getAdminReference()); try { saveHelper.execute(this.repository); diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java index 44c450b0..d1402927 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBTransactionRepository.java @@ -11,7 +11,6 @@ import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qora.data.PaymentData; -import org.qora.data.transaction.GroupInviteTransactionData; import org.qora.data.transaction.TransactionData; import org.qora.repository.DataException; import org.qora.repository.TransactionRepository; @@ -47,7 +46,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { private HSQLDBAddGroupAdminTransactionRepository addGroupAdminTransactionRepository; private HSQLDBRemoveGroupAdminTransactionRepository removeGroupAdminTransactionRepository; private HSQLDBGroupBanTransactionRepository groupBanTransactionRepository; - private HSQLDBGroupUnbanTransactionRepository groupUnbanTransactionRepository; + private HSQLDBCancelGroupBanTransactionRepository groupUnbanTransactionRepository; private HSQLDBGroupKickTransactionRepository groupKickTransactionRepository; private HSQLDBGroupInviteTransactionRepository groupInviteTransactionRepository; private HSQLDBCancelGroupInviteTransactionRepository cancelGroupInviteTransactionRepository; @@ -79,7 +78,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { this.addGroupAdminTransactionRepository = new HSQLDBAddGroupAdminTransactionRepository(repository); this.removeGroupAdminTransactionRepository = new HSQLDBRemoveGroupAdminTransactionRepository(repository); this.groupBanTransactionRepository = new HSQLDBGroupBanTransactionRepository(repository); - this.groupUnbanTransactionRepository = new HSQLDBGroupUnbanTransactionRepository(repository); + this.groupUnbanTransactionRepository = new HSQLDBCancelGroupBanTransactionRepository(repository); this.groupKickTransactionRepository = new HSQLDBGroupKickTransactionRepository(repository); this.groupInviteTransactionRepository = new HSQLDBGroupInviteTransactionRepository(repository); this.cancelGroupInviteTransactionRepository = new HSQLDBCancelGroupInviteTransactionRepository(repository); @@ -226,7 +225,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { case GROUP_BAN: return this.groupBanTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee); - case GROUP_UNBAN: + case CANCEL_GROUP_BAN: return this.groupUnbanTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee); case GROUP_KICK: @@ -584,7 +583,7 @@ public class HSQLDBTransactionRepository implements TransactionRepository { this.groupBanTransactionRepository.save(transactionData); break; - case GROUP_UNBAN: + case CANCEL_GROUP_BAN: this.groupUnbanTransactionRepository.save(transactionData); break; @@ -629,10 +628,4 @@ public class HSQLDBTransactionRepository implements TransactionRepository { } } - @Override - public List getInvitesWithGroupReference(byte[] groupReference) throws DataException { - // Let specialized subclass handle this - return this.groupInviteTransactionRepository.getInvitesWithGroupReference(groupReference); - } - } diff --git a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java index 58c28728..3efb14c5 100644 --- a/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java +++ b/src/main/java/org/qora/repository/hsqldb/transaction/HSQLDBUpdateGroupTransactionRepository.java @@ -17,18 +17,19 @@ public class HSQLDBUpdateGroupTransactionRepository extends HSQLDBTransactionRep } TransactionData fromBase(byte[] signature, byte[] reference, byte[] creatorPublicKey, long timestamp, BigDecimal fee) throws DataException { - try (ResultSet resultSet = this.repository.checkedExecute("SELECT group_name, new_owner, new_description, new_is_open, group_reference FROM UpdateGroupTransactions WHERE signature = ?", - signature)) { + try (ResultSet resultSet = this.repository.checkedExecute( + "SELECT group_id, new_owner, new_description, new_is_open, group_reference FROM UpdateGroupTransactions WHERE signature = ?", signature)) { if (resultSet == null) return null; - String groupName = resultSet.getString(1); + int groupId = resultSet.getInt(1); String newOwner = resultSet.getString(2); String newDescription = resultSet.getString(3); boolean newIsOpen = resultSet.getBoolean(4); byte[] groupReference = resultSet.getBytes(5); - return new UpdateGroupTransactionData(creatorPublicKey, groupName, newOwner, newDescription, newIsOpen, groupReference, fee, timestamp, reference, signature); + return new UpdateGroupTransactionData(creatorPublicKey, groupId, newOwner, newDescription, newIsOpen, groupReference, fee, timestamp, reference, + signature); } catch (SQLException e) { throw new DataException("Unable to fetch update group transaction from repository", e); } @@ -41,7 +42,7 @@ public class HSQLDBUpdateGroupTransactionRepository extends HSQLDBTransactionRep HSQLDBSaver saveHelper = new HSQLDBSaver("UpdateGroupTransactions"); saveHelper.bind("signature", updateGroupTransactionData.getSignature()).bind("owner", updateGroupTransactionData.getOwnerPublicKey()) - .bind("group_name", updateGroupTransactionData.getGroupName()).bind("new_owner", updateGroupTransactionData.getNewOwner()) + .bind("group_id", updateGroupTransactionData.getGroupId()).bind("new_owner", updateGroupTransactionData.getNewOwner()) .bind("new_description", updateGroupTransactionData.getNewDescription()).bind("new_is_open", updateGroupTransactionData.getNewIsOpen()) .bind("group_reference", updateGroupTransactionData.getGroupReference()); diff --git a/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java b/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java index bfe620f8..4b703581 100644 --- a/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java +++ b/src/main/java/org/qora/transaction/AddGroupAdminTransaction.java @@ -16,8 +16,6 @@ import org.qora.group.Group; import org.qora.repository.DataException; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class AddGroupAdminTransaction extends Transaction { // Properties @@ -76,16 +74,11 @@ public class AddGroupAdminTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(addGroupAdminTransactionData.getGroupName()); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; + // Check member address is valid + if (!Crypto.isValidAddress(addGroupAdminTransactionData.getMember())) + return ValidationResult.INVALID_ADDRESS; - // Check group name is lowercase - if (!addGroupAdminTransactionData.getGroupName().equals(addGroupAdminTransactionData.getGroupName().toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = this.repository.getGroupRepository().fromGroupName(addGroupAdminTransactionData.getGroupName()); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(addGroupAdminTransactionData.getGroupId()); // Check group exists if (groupData == null) @@ -97,24 +90,21 @@ public class AddGroupAdminTransaction extends Transaction { if (!owner.getAddress().equals(groupData.getOwner())) return ValidationResult.INVALID_GROUP_OWNER; - // Check member address is valid - if (!Crypto.isValidAddress(addGroupAdminTransactionData.getMember())) - return ValidationResult.INVALID_ADDRESS; - Account member = getMember(); // Check address is a member - if (!this.repository.getGroupRepository().memberExists(addGroupAdminTransactionData.getGroupName(), member.getAddress())) + if (!this.repository.getGroupRepository().memberExists(addGroupAdminTransactionData.getGroupId(), member.getAddress())) return ValidationResult.NOT_GROUP_MEMBER; // Check member is not already an admin - if (this.repository.getGroupRepository().adminExists(addGroupAdminTransactionData.getGroupName(), member.getAddress())) + if (this.repository.getGroupRepository().adminExists(addGroupAdminTransactionData.getGroupId(), member.getAddress())) return ValidationResult.ALREADY_GROUP_ADMIN; // Check fee is positive if (addGroupAdminTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(owner.getLastReference(), addGroupAdminTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -128,7 +118,7 @@ public class AddGroupAdminTransaction extends Transaction { @Override public void process() throws DataException { // Update Group adminship - Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupName()); + Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupId()); group.promoteToAdmin(addGroupAdminTransactionData); // Save this transaction @@ -145,7 +135,7 @@ public class AddGroupAdminTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group adminship - Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupName()); + Group group = new Group(this.repository, addGroupAdminTransactionData.getGroupId()); group.unpromoteToAdmin(addGroupAdminTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/GroupUnbanTransaction.java b/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java similarity index 77% rename from src/main/java/org/qora/transaction/GroupUnbanTransaction.java rename to src/main/java/org/qora/transaction/CancelGroupBanTransaction.java index 641bacbd..79ccf456 100644 --- a/src/main/java/org/qora/transaction/GroupUnbanTransaction.java +++ b/src/main/java/org/qora/transaction/CancelGroupBanTransaction.java @@ -9,27 +9,24 @@ import org.qora.account.Account; import org.qora.account.PublicKeyAccount; import org.qora.asset.Asset; import org.qora.crypto.Crypto; -import org.qora.data.transaction.GroupUnbanTransactionData; +import org.qora.data.transaction.CancelGroupBanTransactionData; 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.GroupRepository; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - -public class GroupUnbanTransaction extends Transaction { +public class CancelGroupBanTransaction extends Transaction { // Properties - private GroupUnbanTransactionData groupUnbanTransactionData; + private CancelGroupBanTransactionData groupUnbanTransactionData; // Constructors - public GroupUnbanTransaction(Repository repository, TransactionData transactionData) { + public CancelGroupBanTransaction(Repository repository, TransactionData transactionData) { super(repository, transactionData); - this.groupUnbanTransactionData = (GroupUnbanTransactionData) this.transactionData; + this.groupUnbanTransactionData = (CancelGroupBanTransactionData) this.transactionData; } // More information @@ -77,43 +74,33 @@ public class GroupUnbanTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupUnbanTransactionData.getGroupName(); - // Check member address is valid if (!Crypto.isValidAddress(groupUnbanTransactionData.getMember())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(groupName); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!groupName.equals(groupName.toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = groupRepository.fromGroupName(groupName); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(groupUnbanTransactionData.getGroupId()); // Check group exists if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; Account admin = getAdmin(); - Account member = getMember(); // Can't unban if not an admin - if (!groupRepository.adminExists(groupName, admin.getAddress())) + if (!this.repository.getGroupRepository().adminExists(groupUnbanTransactionData.getGroupId(), admin.getAddress())) return ValidationResult.NOT_GROUP_ADMIN; + Account member = getMember(); + // Check ban actually exists - if (!groupRepository.banExists(groupName, member.getAddress())) + if (!this.repository.getGroupRepository().banExists(groupUnbanTransactionData.getGroupId(), member.getAddress())) return ValidationResult.BAN_UNKNOWN; // Check fee is positive if (groupUnbanTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(admin.getLastReference(), groupUnbanTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -127,7 +114,7 @@ public class GroupUnbanTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, groupUnbanTransactionData.getGroupName()); + Group group = new Group(this.repository, groupUnbanTransactionData.getGroupId()); group.cancelBan(groupUnbanTransactionData); // Save this transaction with updated member/admin references to transactions that can help restore state @@ -144,7 +131,7 @@ public class GroupUnbanTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, groupUnbanTransactionData.getGroupName()); + Group group = new Group(this.repository, groupUnbanTransactionData.getGroupId()); group.uncancelBan(groupUnbanTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java b/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java index bd97f75d..d4cbe20b 100644 --- a/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java +++ b/src/main/java/org/qora/transaction/CancelGroupInviteTransaction.java @@ -14,22 +14,19 @@ 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.GroupRepository; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class CancelGroupInviteTransaction extends Transaction { // Properties - private CancelGroupInviteTransactionData cancelCancelGroupInviteTransactionData; + private CancelGroupInviteTransactionData cancelGroupInviteTransactionData; // Constructors public CancelGroupInviteTransaction(Repository repository, TransactionData transactionData) { super(repository, transactionData); - this.cancelCancelGroupInviteTransactionData = (CancelGroupInviteTransactionData) this.transactionData; + this.cancelGroupInviteTransactionData = (CancelGroupInviteTransactionData) this.transactionData; } // More information @@ -66,55 +63,49 @@ public class CancelGroupInviteTransaction extends Transaction { // Navigation public Account getAdmin() throws DataException { - return new PublicKeyAccount(this.repository, this.cancelCancelGroupInviteTransactionData.getAdminPublicKey()); + return new PublicKeyAccount(this.repository, this.cancelGroupInviteTransactionData.getAdminPublicKey()); } public Account getInvitee() throws DataException { - return new Account(this.repository, this.cancelCancelGroupInviteTransactionData.getInvitee()); + return new Account(this.repository, this.cancelGroupInviteTransactionData.getInvitee()); } // Processing @Override public ValidationResult isValid() throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = cancelCancelGroupInviteTransactionData.getGroupName(); - - // Check member address is valid - if (!Crypto.isValidAddress(cancelCancelGroupInviteTransactionData.getInvitee())) + // Check invitee address is valid + if (!Crypto.isValidAddress(cancelGroupInviteTransactionData.getInvitee())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(groupName); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!groupName.equals(groupName.toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = groupRepository.fromGroupName(groupName); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(cancelGroupInviteTransactionData.getGroupId()); // Check group exists if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; Account admin = getAdmin(); + + // Check admin is actually an admin + if (!this.repository.getGroupRepository().adminExists(cancelGroupInviteTransactionData.getGroupId(), admin.getAddress())) + return ValidationResult.NOT_GROUP_ADMIN; + Account invitee = getInvitee(); // Check invite exists - if (!groupRepository.inviteExists(groupName, admin.getAddress(), invitee.getAddress())) + if (!this.repository.getGroupRepository().inviteExists(cancelGroupInviteTransactionData.getGroupId(), invitee.getAddress())) return ValidationResult.INVITE_UNKNOWN; // Check fee is positive - if (cancelCancelGroupInviteTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) + if (cancelGroupInviteTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; - if (!Arrays.equals(admin.getLastReference(), cancelCancelGroupInviteTransactionData.getReference())) + // Check reference + if (!Arrays.equals(admin.getLastReference(), cancelGroupInviteTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; // Check creator has enough funds - if (admin.getConfirmedBalance(Asset.QORA).compareTo(cancelCancelGroupInviteTransactionData.getFee()) < 0) + if (admin.getConfirmedBalance(Asset.QORA).compareTo(cancelGroupInviteTransactionData.getFee()) < 0) return ValidationResult.NO_BALANCE; return ValidationResult.OK; @@ -123,35 +114,35 @@ public class CancelGroupInviteTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, cancelCancelGroupInviteTransactionData.getGroupName()); - group.cancelInvite(cancelCancelGroupInviteTransactionData); + Group group = new Group(this.repository, cancelGroupInviteTransactionData.getGroupId()); + group.cancelInvite(cancelGroupInviteTransactionData); // Save this transaction with updated member/admin references to transactions that can help restore state - this.repository.getTransactionRepository().save(cancelCancelGroupInviteTransactionData); + this.repository.getTransactionRepository().save(cancelGroupInviteTransactionData); // Update admin's balance Account admin = getAdmin(); - admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(cancelCancelGroupInviteTransactionData.getFee())); + admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(cancelGroupInviteTransactionData.getFee())); // Update admin's reference - admin.setLastReference(cancelCancelGroupInviteTransactionData.getSignature()); + admin.setLastReference(cancelGroupInviteTransactionData.getSignature()); } @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, cancelCancelGroupInviteTransactionData.getGroupName()); - group.uncancelInvite(cancelCancelGroupInviteTransactionData); + Group group = new Group(this.repository, cancelGroupInviteTransactionData.getGroupId()); + group.uncancelInvite(cancelGroupInviteTransactionData); // Delete this transaction itself - this.repository.getTransactionRepository().delete(cancelCancelGroupInviteTransactionData); + this.repository.getTransactionRepository().delete(cancelGroupInviteTransactionData); // Update admin's balance Account admin = getAdmin(); - admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(cancelCancelGroupInviteTransactionData.getFee())); + admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(cancelGroupInviteTransactionData.getFee())); // Update admin's reference - admin.setLastReference(cancelCancelGroupInviteTransactionData.getReference()); + admin.setLastReference(cancelGroupInviteTransactionData.getReference()); } } diff --git a/src/main/java/org/qora/transaction/CreateGroupTransaction.java b/src/main/java/org/qora/transaction/CreateGroupTransaction.java index d2e1aaf5..5671469e 100644 --- a/src/main/java/org/qora/transaction/CreateGroupTransaction.java +++ b/src/main/java/org/qora/transaction/CreateGroupTransaction.java @@ -96,9 +96,9 @@ public class CreateGroupTransaction extends Transaction { if (createGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; - // Check reference is correct Account creator = getCreator(); + // Check reference is correct if (!Arrays.equals(creator.getLastReference(), createGroupTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -115,6 +115,9 @@ public class CreateGroupTransaction extends Transaction { Group group = new Group(this.repository, createGroupTransactionData); group.create(createGroupTransactionData); + // Note newly assigned group ID in our transaction record + createGroupTransactionData.setGroupId(group.getGroupData().getGroupId()); + // Save this transaction this.repository.getTransactionRepository().save(createGroupTransactionData); @@ -129,7 +132,7 @@ public class CreateGroupTransaction extends Transaction { @Override public void orphan() throws DataException { // Uncreate group - Group group = new Group(this.repository, createGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, createGroupTransactionData.getGroupId()); group.uncreate(); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/GroupBanTransaction.java b/src/main/java/org/qora/transaction/GroupBanTransaction.java index 911b6a9a..12bb4883 100644 --- a/src/main/java/org/qora/transaction/GroupBanTransaction.java +++ b/src/main/java/org/qora/transaction/GroupBanTransaction.java @@ -14,11 +14,8 @@ 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.GroupRepository; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class GroupBanTransaction extends Transaction { // Properties @@ -77,47 +74,38 @@ public class GroupBanTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupBanTransactionData.getGroupName(); - - // Check member address is valid + // Check offender address is valid if (!Crypto.isValidAddress(groupBanTransactionData.getOffender())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(groupName); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!groupName.equals(groupName.toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = groupRepository.fromGroupName(groupName); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(groupBanTransactionData.getGroupId()); // Check group exists if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; Account admin = getAdmin(); - Account member = getOffender(); // Can't ban if not an admin - if (!groupRepository.adminExists(groupName, admin.getAddress())) + if (!this.repository.getGroupRepository().adminExists(groupBanTransactionData.getGroupId(), admin.getAddress())) return ValidationResult.NOT_GROUP_ADMIN; + Account offender = getOffender(); + // Can't ban another admin unless the group owner - if (!admin.getAddress().equals(groupData.getOwner()) && groupRepository.adminExists(groupName, member.getAddress())) + if (!admin.getAddress().equals(groupData.getOwner()) + && this.repository.getGroupRepository().adminExists(groupBanTransactionData.getGroupId(), offender.getAddress())) return ValidationResult.INVALID_GROUP_OWNER; // Check fee is positive if (groupBanTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(admin.getLastReference(), groupBanTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; - // Check creator has enough funds + // Check admin has enough funds if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupBanTransactionData.getFee()) < 0) return ValidationResult.NO_BALANCE; @@ -127,7 +115,7 @@ public class GroupBanTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, groupBanTransactionData.getGroupName()); + Group group = new Group(this.repository, groupBanTransactionData.getGroupId()); group.ban(groupBanTransactionData); // Save this transaction with updated member/admin references to transactions that can help restore state @@ -144,7 +132,7 @@ public class GroupBanTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, groupBanTransactionData.getGroupName()); + Group group = new Group(this.repository, groupBanTransactionData.getGroupId()); group.unban(groupBanTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/GroupInviteTransaction.java b/src/main/java/org/qora/transaction/GroupInviteTransaction.java index f2ff1b55..47019cdc 100644 --- a/src/main/java/org/qora/transaction/GroupInviteTransaction.java +++ b/src/main/java/org/qora/transaction/GroupInviteTransaction.java @@ -14,11 +14,8 @@ 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.GroupRepository; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class GroupInviteTransaction extends Transaction { // Properties @@ -77,9 +74,6 @@ public class GroupInviteTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupInviteTransactionData.getGroupName(); - // Check time to live zero (infinite) or positive if (groupInviteTransactionData.getTimeToLive() < 0) return ValidationResult.INVALID_LIFETIME; @@ -88,36 +82,33 @@ public class GroupInviteTransaction extends Transaction { if (!Crypto.isValidAddress(groupInviteTransactionData.getInvitee())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(groupName); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!groupName.equals(groupName.toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = groupRepository.fromGroupName(groupName); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(groupInviteTransactionData.getGroupId()); // Check group exists if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; Account admin = getAdmin(); - Account invitee = getInvitee(); // Can't invite if not an admin - if (!groupRepository.adminExists(groupName, admin.getAddress())) + if (!this.repository.getGroupRepository().adminExists(groupInviteTransactionData.getGroupId(), admin.getAddress())) return ValidationResult.NOT_GROUP_ADMIN; + Account invitee = getInvitee(); + // Check invitee not already in group - if (groupRepository.memberExists(groupName, invitee.getAddress())) + if (this.repository.getGroupRepository().memberExists(groupInviteTransactionData.getGroupId(), invitee.getAddress())) return ValidationResult.ALREADY_GROUP_MEMBER; + // Check invitee is not banned + if (this.repository.getGroupRepository().banExists(groupInviteTransactionData.getGroupId(), invitee.getAddress())) + return ValidationResult.BANNED_FROM_GROUP; + // Check fee is positive if (groupInviteTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(admin.getLastReference(), groupInviteTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -131,7 +122,7 @@ public class GroupInviteTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, groupInviteTransactionData.getGroupName()); + Group group = new Group(this.repository, groupInviteTransactionData.getGroupId()); group.invite(groupInviteTransactionData); // Save this transaction with updated member/admin references to transactions that can help restore state @@ -148,7 +139,7 @@ public class GroupInviteTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, groupInviteTransactionData.getGroupName()); + Group group = new Group(this.repository, groupInviteTransactionData.getGroupId()); group.uninvite(groupInviteTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/GroupKickTransaction.java b/src/main/java/org/qora/transaction/GroupKickTransaction.java index f781a5b9..5063656e 100644 --- a/src/main/java/org/qora/transaction/GroupKickTransaction.java +++ b/src/main/java/org/qora/transaction/GroupKickTransaction.java @@ -17,8 +17,6 @@ import org.qora.repository.DataException; import org.qora.repository.GroupRepository; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class GroupKickTransaction extends Transaction { // Properties @@ -77,47 +75,39 @@ public class GroupKickTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { - GroupRepository groupRepository = this.repository.getGroupRepository(); - String groupName = groupKickTransactionData.getGroupName(); - // Check member address is valid if (!Crypto.isValidAddress(groupKickTransactionData.getMember())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(groupName); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!groupName.equals(groupName.toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = groupRepository.fromGroupName(groupName); + GroupRepository groupRepository = this.repository.getGroupRepository(); + int groupId = groupKickTransactionData.getGroupId(); + GroupData groupData = groupRepository.fromGroupId(groupId); // Check group exists if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; Account admin = getAdmin(); - Account member = getMember(); // Can't kick if not an admin - if (!groupRepository.adminExists(groupName, admin.getAddress())) + if (!groupRepository.adminExists(groupId, admin.getAddress())) return ValidationResult.NOT_GROUP_ADMIN; + Account member = getMember(); + // Check member actually in group UNLESS there's a pending join request - if (!groupRepository.joinRequestExists(groupName, member.getAddress()) && !groupRepository.memberExists(groupName, member.getAddress())) + if (!groupRepository.joinRequestExists(groupId, member.getAddress()) && !groupRepository.memberExists(groupId, member.getAddress())) return ValidationResult.NOT_GROUP_MEMBER; // Can't kick another admin unless the group owner - if (!admin.getAddress().equals(groupData.getOwner()) && groupRepository.adminExists(groupName, member.getAddress())) + if (!admin.getAddress().equals(groupData.getOwner()) && groupRepository.adminExists(groupId, member.getAddress())) return ValidationResult.INVALID_GROUP_OWNER; // Check fee is positive if (groupKickTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(admin.getLastReference(), groupKickTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -131,7 +121,7 @@ public class GroupKickTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, groupKickTransactionData.getGroupName()); + Group group = new Group(this.repository, groupKickTransactionData.getGroupId()); group.kick(groupKickTransactionData); // Save this transaction with updated member/admin references to transactions that can help restore state @@ -148,7 +138,7 @@ public class GroupKickTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, groupKickTransactionData.getGroupName()); + Group group = new Group(this.repository, groupKickTransactionData.getGroupId()); group.unkick(groupKickTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/IssueAssetTransaction.java b/src/main/java/org/qora/transaction/IssueAssetTransaction.java index 355469a3..f630ac0c 100644 --- a/src/main/java/org/qora/transaction/IssueAssetTransaction.java +++ b/src/main/java/org/qora/transaction/IssueAssetTransaction.java @@ -161,7 +161,7 @@ public class IssueAssetTransaction extends Transaction { Account owner = getOwner(); owner.deleteBalance(issueAssetTransactionData.getAssetId()); - // Issue asset + // Deissue asset Asset asset = new Asset(this.repository, issueAssetTransactionData.getAssetId()); asset.deissue(); diff --git a/src/main/java/org/qora/transaction/JoinGroupTransaction.java b/src/main/java/org/qora/transaction/JoinGroupTransaction.java index 204419f6..1368d4e0 100644 --- a/src/main/java/org/qora/transaction/JoinGroupTransaction.java +++ b/src/main/java/org/qora/transaction/JoinGroupTransaction.java @@ -15,8 +15,6 @@ import org.qora.group.Group; import org.qora.repository.DataException; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class JoinGroupTransaction extends Transaction { // Properties @@ -68,16 +66,7 @@ public class JoinGroupTransaction extends Transaction { @Override public ValidationResult isValid() throws DataException { - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(joinGroupTransactionData.getGroupName()); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!joinGroupTransactionData.getGroupName().equals(joinGroupTransactionData.getGroupName().toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = this.repository.getGroupRepository().fromGroupName(joinGroupTransactionData.getGroupName()); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(joinGroupTransactionData.getGroupId()); // Check group exists if (groupData == null) @@ -85,13 +74,17 @@ public class JoinGroupTransaction extends Transaction { Account joiner = getJoiner(); - if (this.repository.getGroupRepository().memberExists(joinGroupTransactionData.getGroupName(), joiner.getAddress())) + if (this.repository.getGroupRepository().memberExists(joinGroupTransactionData.getGroupId(), joiner.getAddress())) return ValidationResult.ALREADY_GROUP_MEMBER; // Check member is not banned - if (this.repository.getGroupRepository().banExists(joinGroupTransactionData.getGroupName(), joiner.getAddress())) + if (this.repository.getGroupRepository().banExists(joinGroupTransactionData.getGroupId(), joiner.getAddress())) return ValidationResult.BANNED_FROM_GROUP; + // Check join request doesn't already exist + if (this.repository.getGroupRepository().joinRequestExists(joinGroupTransactionData.getGroupId(), joiner.getAddress())) + return ValidationResult.JOIN_REQUEST_EXISTS; + // Check fee is positive if (joinGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; @@ -109,7 +102,7 @@ public class JoinGroupTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, joinGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, joinGroupTransactionData.getGroupId()); group.join(joinGroupTransactionData); // Save this transaction @@ -126,7 +119,7 @@ public class JoinGroupTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, joinGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, joinGroupTransactionData.getGroupId()); group.unjoin(joinGroupTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/LeaveGroupTransaction.java b/src/main/java/org/qora/transaction/LeaveGroupTransaction.java index f8c90d0c..6f79e42c 100644 --- a/src/main/java/org/qora/transaction/LeaveGroupTransaction.java +++ b/src/main/java/org/qora/transaction/LeaveGroupTransaction.java @@ -15,8 +15,6 @@ 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 @@ -68,16 +66,7 @@ public class LeaveGroupTransaction extends Transaction { @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()); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(leaveGroupTransactionData.getGroupId()); // Check group exists if (groupData == null) @@ -89,13 +78,15 @@ public class LeaveGroupTransaction extends Transaction { if (leaver.getAddress().equals(groupData.getOwner())) return ValidationResult.GROUP_OWNER_CANNOT_LEAVE; - if (!this.repository.getGroupRepository().memberExists(leaveGroupTransactionData.getGroupName(), leaver.getAddress())) + // Check leaver is actually a member of group + if (!this.repository.getGroupRepository().memberExists(leaveGroupTransactionData.getGroupId(), leaver.getAddress())) return ValidationResult.NOT_GROUP_MEMBER; // Check fee is positive if (leaveGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(leaver.getLastReference(), leaveGroupTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -109,7 +100,7 @@ public class LeaveGroupTransaction extends Transaction { @Override public void process() throws DataException { // Update Group Membership - Group group = new Group(this.repository, leaveGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, leaveGroupTransactionData.getGroupId()); group.leave(leaveGroupTransactionData); // Save this transaction with updated member/admin references to transactions that can help restore state @@ -126,7 +117,7 @@ public class LeaveGroupTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group membership - Group group = new Group(this.repository, leaveGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, leaveGroupTransactionData.getGroupId()); group.unleave(leaveGroupTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java b/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java index abc8501f..412c1969 100644 --- a/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java +++ b/src/main/java/org/qora/transaction/RemoveGroupAdminTransaction.java @@ -16,8 +16,6 @@ import org.qora.group.Group; import org.qora.repository.DataException; import org.qora.repository.Repository; -import com.google.common.base.Utf8; - public class RemoveGroupAdminTransaction extends Transaction { // Properties @@ -80,16 +78,7 @@ public class RemoveGroupAdminTransaction extends Transaction { if (!Crypto.isValidAddress(removeGroupAdminTransactionData.getAdmin())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(removeGroupAdminTransactionData.getGroupName()); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - - // Check group name is lowercase - if (!removeGroupAdminTransactionData.getGroupName().equals(removeGroupAdminTransactionData.getGroupName().toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = this.repository.getGroupRepository().fromGroupName(removeGroupAdminTransactionData.getGroupName()); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(removeGroupAdminTransactionData.getGroupId()); // Check group exists if (groupData == null) @@ -104,13 +93,14 @@ public class RemoveGroupAdminTransaction extends Transaction { Account admin = getAdmin(); // Check member is an admin - if (!this.repository.getGroupRepository().adminExists(removeGroupAdminTransactionData.getGroupName(), admin.getAddress())) + if (!this.repository.getGroupRepository().adminExists(removeGroupAdminTransactionData.getGroupId(), admin.getAddress())) return ValidationResult.NOT_GROUP_ADMIN; // Check fee is positive if (removeGroupAdminTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; + // Check reference if (!Arrays.equals(owner.getLastReference(), removeGroupAdminTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; @@ -124,7 +114,7 @@ public class RemoveGroupAdminTransaction extends Transaction { @Override public void process() throws DataException { // Update Group adminship - Group group = new Group(this.repository, removeGroupAdminTransactionData.getGroupName()); + Group group = new Group(this.repository, removeGroupAdminTransactionData.getGroupId()); group.demoteFromAdmin(removeGroupAdminTransactionData); // Save this transaction @@ -141,7 +131,7 @@ public class RemoveGroupAdminTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert group adminship - Group group = new Group(this.repository, removeGroupAdminTransactionData.getGroupName()); + Group group = new Group(this.repository, removeGroupAdminTransactionData.getGroupId()); group.undemoteFromAdmin(removeGroupAdminTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transaction/Transaction.java b/src/main/java/org/qora/transaction/Transaction.java index ab59f079..933e4a81 100644 --- a/src/main/java/org/qora/transaction/Transaction.java +++ b/src/main/java/org/qora/transaction/Transaction.java @@ -58,7 +58,7 @@ public abstract class Transaction { ADD_GROUP_ADMIN(24), REMOVE_GROUP_ADMIN(25), GROUP_BAN(26), - GROUP_UNBAN(27), + CANCEL_GROUP_BAN(27), GROUP_KICK(28), GROUP_INVITE(29), CANCEL_GROUP_INVITE(30), @@ -138,6 +138,7 @@ public abstract class Transaction { BAN_EXISTS(58), BAN_UNKNOWN(59), BANNED_FROM_GROUP(60), + JOIN_REQUEST_EXISTS(61), NOT_YET_RELEASED(1000); public final int value; @@ -252,8 +253,8 @@ public abstract class Transaction { case GROUP_BAN: return new GroupBanTransaction(repository, transactionData); - case GROUP_UNBAN: - return new GroupUnbanTransaction(repository, transactionData); + case CANCEL_GROUP_BAN: + return new CancelGroupBanTransaction(repository, transactionData); case GROUP_KICK: return new GroupKickTransaction(repository, transactionData); diff --git a/src/main/java/org/qora/transaction/UpdateGroupTransaction.java b/src/main/java/org/qora/transaction/UpdateGroupTransaction.java index 3af19fe7..ddd9b685 100644 --- a/src/main/java/org/qora/transaction/UpdateGroupTransaction.java +++ b/src/main/java/org/qora/transaction/UpdateGroupTransaction.java @@ -80,43 +80,39 @@ public class UpdateGroupTransaction extends Transaction { if (!Crypto.isValidAddress(updateGroupTransactionData.getNewOwner())) return ValidationResult.INVALID_ADDRESS; - // Check group name size bounds - int groupNameLength = Utf8.encodedLength(updateGroupTransactionData.getGroupName()); - if (groupNameLength < 1 || groupNameLength > Group.MAX_NAME_SIZE) - return ValidationResult.INVALID_NAME_LENGTH; - // Check new description size bounds int newDescriptionLength = Utf8.encodedLength(updateGroupTransactionData.getNewDescription()); if (newDescriptionLength < 1 || newDescriptionLength > Group.MAX_DESCRIPTION_SIZE) return ValidationResult.INVALID_DESCRIPTION_LENGTH; - // Check group name is lowercase - if (!updateGroupTransactionData.getGroupName().equals(updateGroupTransactionData.getGroupName().toLowerCase())) - return ValidationResult.NAME_NOT_LOWER_CASE; - - GroupData groupData = this.repository.getGroupRepository().fromGroupName(updateGroupTransactionData.getGroupName()); + GroupData groupData = this.repository.getGroupRepository().fromGroupId(updateGroupTransactionData.getGroupId()); // Check group exists if (groupData == null) return ValidationResult.GROUP_DOES_NOT_EXIST; - // Check transaction's public key matches group's current owner Account owner = getOwner(); + + // Check transaction's public key matches group's current owner if (!owner.getAddress().equals(groupData.getOwner())) return ValidationResult.INVALID_GROUP_OWNER; + Account newOwner = getNewOwner(); + + // Check new owner is not banned + if (this.repository.getGroupRepository().banExists(updateGroupTransactionData.getGroupId(), newOwner.getAddress())) + return ValidationResult.BANNED_FROM_GROUP; + // Check fee is positive if (updateGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0) return ValidationResult.NEGATIVE_FEE; // Check reference is correct - Account creator = getCreator(); - - if (!Arrays.equals(creator.getLastReference(), updateGroupTransactionData.getReference())) + if (!Arrays.equals(owner.getLastReference(), updateGroupTransactionData.getReference())) return ValidationResult.INVALID_REFERENCE; // Check creator has enough funds - if (creator.getConfirmedBalance(Asset.QORA).compareTo(updateGroupTransactionData.getFee()) < 0) + if (owner.getConfirmedBalance(Asset.QORA).compareTo(updateGroupTransactionData.getFee()) < 0) return ValidationResult.NO_BALANCE; return ValidationResult.OK; @@ -125,7 +121,7 @@ public class UpdateGroupTransaction extends Transaction { @Override public void process() throws DataException { // Update Group - Group group = new Group(this.repository, updateGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, updateGroupTransactionData.getGroupId()); group.updateGroup(updateGroupTransactionData); // Save this transaction, now with updated "group reference" to previous transaction that updated group @@ -142,7 +138,7 @@ public class UpdateGroupTransaction extends Transaction { @Override public void orphan() throws DataException { // Revert Group update - Group group = new Group(this.repository, updateGroupTransactionData.getGroupName()); + Group group = new Group(this.repository, updateGroupTransactionData.getGroupId()); group.unupdateGroup(updateGroupTransactionData); // Delete this transaction itself diff --git a/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java index ecf11357..d0145552 100644 --- a/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/AddGroupAdminTransactionTransformer.java @@ -9,11 +9,9 @@ import org.json.simple.JSONObject; import org.qora.account.PublicKeyAccount; import org.qora.data.transaction.AddGroupAdminTransactionData; 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; @@ -22,10 +20,10 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer // Property lengths private static final int OWNER_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int MEMBER_LENGTH = ADDRESS_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + NAME_SIZE_LENGTH + MEMBER_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + GROUPID_LENGTH + MEMBER_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -35,7 +33,7 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer byte[] ownerPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String member = Serialization.deserializeAddress(byteBuffer); @@ -44,15 +42,11 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new AddGroupAdminTransactionData(ownerPublicKey, groupName, member, fee, timestamp, reference, signature); + return new AddGroupAdminTransactionData(ownerPublicKey, groupId, member, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { - AddGroupAdminTransactionData addGroupAdminTransactionData = (AddGroupAdminTransactionData) transactionData; - - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(addGroupAdminTransactionData.getGroupName()); - - return dataLength; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { @@ -66,7 +60,7 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer bytes.write(addGroupAdminTransactionData.getReference()); bytes.write(addGroupAdminTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, addGroupAdminTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(addGroupAdminTransactionData.getGroupId())); Serialization.serializeAddress(bytes, addGroupAdminTransactionData.getMember()); Serialization.serializeBigDecimal(bytes, addGroupAdminTransactionData.getFee()); @@ -92,7 +86,7 @@ public class AddGroupAdminTransactionTransformer extends TransactionTransformer json.put("owner", PublicKeyAccount.getAddress(ownerPublicKey)); json.put("ownerPublicKey", HashCode.fromBytes(ownerPublicKey).toString()); - json.put("groupName", addGroupAdminTransactionData.getGroupName()); + json.put("groupId", addGroupAdminTransactionData.getGroupId()); json.put("member", addGroupAdminTransactionData.getMember()); } catch (ClassCastException e) { throw new TransformationException(e); diff --git a/src/main/java/org/qora/transform/transaction/GroupUnbanTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java similarity index 69% rename from src/main/java/org/qora/transform/transaction/GroupUnbanTransactionTransformer.java rename to src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java index 4061982b..673b3493 100644 --- a/src/main/java/org/qora/transform/transaction/GroupUnbanTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CancelGroupBanTransactionTransformer.java @@ -7,25 +7,23 @@ import java.nio.ByteBuffer; import org.json.simple.JSONObject; import org.qora.account.PublicKeyAccount; -import org.qora.data.transaction.GroupUnbanTransactionData; +import org.qora.data.transaction.CancelGroupBanTransactionData; 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 GroupUnbanTransactionTransformer extends TransactionTransformer { +public class CancelGroupBanTransactionTransformer extends TransactionTransformer { // Property lengths private static final int ADMIN_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int MEMBER_LENGTH = ADDRESS_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + NAME_SIZE_LENGTH + MEMBER_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + GROUPID_LENGTH + MEMBER_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -35,7 +33,7 @@ public class GroupUnbanTransactionTransformer extends TransactionTransformer { byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String member = Serialization.deserializeAddress(byteBuffer); @@ -44,20 +42,16 @@ public class GroupUnbanTransactionTransformer extends TransactionTransformer { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new GroupUnbanTransactionData(adminPublicKey, groupName, member, fee, timestamp, reference, signature); + return new CancelGroupBanTransactionData(adminPublicKey, groupId, member, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { - GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) transactionData; - - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(groupUnbanTransactionData.getGroupName()); - - return dataLength; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { try { - GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) transactionData; + CancelGroupBanTransactionData groupUnbanTransactionData = (CancelGroupBanTransactionData) transactionData; ByteArrayOutputStream bytes = new ByteArrayOutputStream(); @@ -66,7 +60,7 @@ public class GroupUnbanTransactionTransformer extends TransactionTransformer { bytes.write(groupUnbanTransactionData.getReference()); bytes.write(groupUnbanTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, groupUnbanTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(groupUnbanTransactionData.getGroupId())); Serialization.serializeAddress(bytes, groupUnbanTransactionData.getMember()); Serialization.serializeBigDecimal(bytes, groupUnbanTransactionData.getFee()); @@ -85,14 +79,14 @@ public class GroupUnbanTransactionTransformer extends TransactionTransformer { JSONObject json = TransactionTransformer.getBaseJSON(transactionData); try { - GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) transactionData; + CancelGroupBanTransactionData groupUnbanTransactionData = (CancelGroupBanTransactionData) transactionData; byte[] adminPublicKey = groupUnbanTransactionData.getAdminPublicKey(); json.put("admin", PublicKeyAccount.getAddress(adminPublicKey)); json.put("adminPublicKey", HashCode.fromBytes(adminPublicKey).toString()); - json.put("groupName", groupUnbanTransactionData.getGroupName()); + json.put("groupId", groupUnbanTransactionData.getGroupId()); json.put("member", groupUnbanTransactionData.getMember()); } catch (ClassCastException e) { throw new TransformationException(e); diff --git a/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java index 0ff0c7fb..7854e342 100644 --- a/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CancelGroupInviteTransactionTransformer.java @@ -9,11 +9,9 @@ import org.json.simple.JSONObject; import org.qora.account.PublicKeyAccount; import org.qora.data.transaction.CancelGroupInviteTransactionData; 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; @@ -22,10 +20,10 @@ public class CancelGroupInviteTransactionTransformer extends TransactionTransfor // Property lengths private static final int ADMIN_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int INVITEE_LENGTH = ADDRESS_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + NAME_SIZE_LENGTH + INVITEE_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + GROUPID_LENGTH + INVITEE_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -35,24 +33,20 @@ public class CancelGroupInviteTransactionTransformer extends TransactionTransfor byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String invitee = Serialization.deserializeAddress(byteBuffer); - + BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer); byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new CancelGroupInviteTransactionData(adminPublicKey, groupName, invitee, fee, timestamp, reference, signature); + return new CancelGroupInviteTransactionData(adminPublicKey, groupId, invitee, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { - CancelGroupInviteTransactionData cancelGroupInviteTransactionData = (CancelGroupInviteTransactionData) transactionData; - - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(cancelGroupInviteTransactionData.getGroupName()); - - return dataLength; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { @@ -66,7 +60,7 @@ public class CancelGroupInviteTransactionTransformer extends TransactionTransfor bytes.write(cancelGroupInviteTransactionData.getReference()); bytes.write(cancelGroupInviteTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, cancelGroupInviteTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(cancelGroupInviteTransactionData.getGroupId())); Serialization.serializeAddress(bytes, cancelGroupInviteTransactionData.getInvitee()); Serialization.serializeBigDecimal(bytes, cancelGroupInviteTransactionData.getFee()); @@ -92,7 +86,7 @@ public class CancelGroupInviteTransactionTransformer extends TransactionTransfor json.put("admin", PublicKeyAccount.getAddress(adminPublicKey)); json.put("adminPublicKey", HashCode.fromBytes(adminPublicKey).toString()); - json.put("groupName", cancelGroupInviteTransactionData.getGroupName()); + json.put("groupId", cancelGroupInviteTransactionData.getGroupId()); json.put("invitee", cancelGroupInviteTransactionData.getInvitee()); } catch (ClassCastException e) { throw new TransformationException(e); diff --git a/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java index 0f449a13..9b133aa4 100644 --- a/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/CreateGroupTransactionTransformer.java @@ -27,7 +27,8 @@ public class CreateGroupTransactionTransformer extends TransactionTransformer { private static final int DESCRIPTION_SIZE_LENGTH = INT_LENGTH; private static final int IS_OPEN_LENGTH = BOOLEAN_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + CREATOR_LENGTH + OWNER_LENGTH + NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH + IS_OPEN_LENGTH; + private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + CREATOR_LENGTH + OWNER_LENGTH + NAME_SIZE_LENGTH + DESCRIPTION_SIZE_LENGTH + + IS_OPEN_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -50,7 +51,7 @@ public class CreateGroupTransactionTransformer extends TransactionTransformer { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new CreateGroupTransactionData(creatorPublicKey, owner, groupName, description, isOpen, fee, timestamp, reference, signature); + return new CreateGroupTransactionData(creatorPublicKey, owner, groupName, description, isOpen, null, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { diff --git a/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java index 82cbdb43..df6098fe 100644 --- a/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GroupBanTransactionTransformer.java @@ -22,12 +22,12 @@ public class GroupBanTransactionTransformer extends TransactionTransformer { // Property lengths private static final int ADMIN_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int MEMBER_LENGTH = ADDRESS_LENGTH; private static final int REASON_SIZE_LENGTH = INT_LENGTH; private static final int TTL_LENGTH = INT_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + NAME_SIZE_LENGTH + MEMBER_LENGTH + REASON_SIZE_LENGTH + TTL_LENGTH; + private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + GROUPID_LENGTH + MEMBER_LENGTH + REASON_SIZE_LENGTH + TTL_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -37,7 +37,7 @@ public class GroupBanTransactionTransformer extends TransactionTransformer { byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String offender = Serialization.deserializeAddress(byteBuffer); @@ -50,14 +50,13 @@ public class GroupBanTransactionTransformer extends TransactionTransformer { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new GroupBanTransactionData(adminPublicKey, groupName, offender, reason, timeToLive, fee, timestamp, reference, signature); + return new GroupBanTransactionData(adminPublicKey, groupId, offender, reason, timeToLive, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { GroupBanTransactionData groupBanTransactionData = (GroupBanTransactionData) transactionData; - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(groupBanTransactionData.getGroupName()) - + Utf8.encodedLength(groupBanTransactionData.getReason()); + int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(groupBanTransactionData.getReason()); return dataLength; } @@ -73,7 +72,7 @@ public class GroupBanTransactionTransformer extends TransactionTransformer { bytes.write(groupBanTransactionData.getReference()); bytes.write(groupBanTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, groupBanTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(groupBanTransactionData.getGroupId())); Serialization.serializeAddress(bytes, groupBanTransactionData.getOffender()); Serialization.serializeSizedString(bytes, groupBanTransactionData.getReason()); bytes.write(Ints.toByteArray(groupBanTransactionData.getTimeToLive())); @@ -101,7 +100,7 @@ public class GroupBanTransactionTransformer extends TransactionTransformer { json.put("admin", PublicKeyAccount.getAddress(adminPublicKey)); json.put("adminPublicKey", HashCode.fromBytes(adminPublicKey).toString()); - json.put("groupName", groupBanTransactionData.getGroupName()); + json.put("groupId", groupBanTransactionData.getGroupId()); json.put("offender", groupBanTransactionData.getOffender()); json.put("reason", groupBanTransactionData.getReason()); json.put("timeToLive", groupBanTransactionData.getTimeToLive()); diff --git a/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java index 62172423..b5d65ccb 100644 --- a/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GroupInviteTransactionTransformer.java @@ -9,11 +9,9 @@ import org.json.simple.JSONObject; import org.qora.account.PublicKeyAccount; import org.qora.data.transaction.GroupInviteTransactionData; 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; @@ -22,11 +20,11 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer { // Property lengths private static final int ADMIN_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int INVITEE_LENGTH = ADDRESS_LENGTH; private static final int TTL_LENGTH = INT_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + NAME_SIZE_LENGTH + INVITEE_LENGTH + TTL_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + GROUPID_LENGTH + INVITEE_LENGTH + TTL_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -36,10 +34,10 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer { byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String invitee = Serialization.deserializeAddress(byteBuffer); - + int timeToLive = byteBuffer.getInt(); BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer); @@ -47,15 +45,11 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new GroupInviteTransactionData(adminPublicKey, groupName, invitee, timeToLive, fee, timestamp, reference, signature); + return new GroupInviteTransactionData(adminPublicKey, groupId, invitee, timeToLive, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { - GroupInviteTransactionData groupInviteTransactionData = (GroupInviteTransactionData) transactionData; - - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(groupInviteTransactionData.getGroupName()); - - return dataLength; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { @@ -69,7 +63,7 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer { bytes.write(groupInviteTransactionData.getReference()); bytes.write(groupInviteTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, groupInviteTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(groupInviteTransactionData.getGroupId())); Serialization.serializeAddress(bytes, groupInviteTransactionData.getInvitee()); bytes.write(Ints.toByteArray(groupInviteTransactionData.getTimeToLive())); @@ -96,7 +90,7 @@ public class GroupInviteTransactionTransformer extends TransactionTransformer { json.put("admin", PublicKeyAccount.getAddress(adminPublicKey)); json.put("adminPublicKey", HashCode.fromBytes(adminPublicKey).toString()); - json.put("groupName", groupInviteTransactionData.getGroupName()); + json.put("groupId", groupInviteTransactionData.getGroupId()); json.put("invitee", groupInviteTransactionData.getInvitee()); json.put("timeToLive", groupInviteTransactionData.getTimeToLive()); } catch (ClassCastException e) { diff --git a/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java index bf034d2a..0e95442b 100644 --- a/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/GroupKickTransactionTransformer.java @@ -22,11 +22,11 @@ public class GroupKickTransactionTransformer extends TransactionTransformer { // Property lengths private static final int ADMIN_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int MEMBER_LENGTH = ADDRESS_LENGTH; private static final int REASON_SIZE_LENGTH = INT_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + NAME_SIZE_LENGTH + MEMBER_LENGTH + REASON_SIZE_LENGTH; + private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + ADMIN_LENGTH + GROUPID_LENGTH + MEMBER_LENGTH + REASON_SIZE_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -36,7 +36,7 @@ public class GroupKickTransactionTransformer extends TransactionTransformer { byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String member = Serialization.deserializeAddress(byteBuffer); @@ -47,14 +47,13 @@ public class GroupKickTransactionTransformer extends TransactionTransformer { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new GroupKickTransactionData(adminPublicKey, groupName, member, reason, fee, timestamp, reference, signature); + return new GroupKickTransactionData(adminPublicKey, groupId, member, reason, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { GroupKickTransactionData groupKickTransactionData = (GroupKickTransactionData) transactionData; - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(groupKickTransactionData.getGroupName()) - + Utf8.encodedLength(groupKickTransactionData.getReason()); + int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(groupKickTransactionData.getReason()); return dataLength; } @@ -70,7 +69,7 @@ public class GroupKickTransactionTransformer extends TransactionTransformer { bytes.write(groupKickTransactionData.getReference()); bytes.write(groupKickTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, groupKickTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(groupKickTransactionData.getGroupId())); Serialization.serializeAddress(bytes, groupKickTransactionData.getMember()); Serialization.serializeSizedString(bytes, groupKickTransactionData.getReason()); @@ -97,7 +96,7 @@ public class GroupKickTransactionTransformer extends TransactionTransformer { json.put("admin", PublicKeyAccount.getAddress(adminPublicKey)); json.put("adminPublicKey", HashCode.fromBytes(adminPublicKey).toString()); - json.put("groupName", groupKickTransactionData.getGroupName()); + json.put("groupId", groupKickTransactionData.getGroupId()); json.put("member", groupKickTransactionData.getMember()); json.put("reason", groupKickTransactionData.getReason()); } catch (ClassCastException e) { diff --git a/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java index 4705cc62..e565e45a 100644 --- a/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/JoinGroupTransactionTransformer.java @@ -9,11 +9,9 @@ import org.json.simple.JSONObject; import org.qora.account.PublicKeyAccount; import org.qora.data.transaction.JoinGroupTransactionData; 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; @@ -22,9 +20,9 @@ public class JoinGroupTransactionTransformer 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 GROUPID_LENGTH = INT_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + JOINER_LENGTH + NAME_SIZE_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + JOINER_LENGTH + GROUPID_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -34,22 +32,18 @@ public class JoinGroupTransactionTransformer extends TransactionTransformer { byte[] joinerPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer); byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new JoinGroupTransactionData(joinerPublicKey, groupName, fee, timestamp, reference, signature); + return new JoinGroupTransactionData(joinerPublicKey, groupId, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { - JoinGroupTransactionData joinGroupTransactionData = (JoinGroupTransactionData) transactionData; - - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(joinGroupTransactionData.getGroupName()); - - return dataLength; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { @@ -63,7 +57,7 @@ public class JoinGroupTransactionTransformer extends TransactionTransformer { bytes.write(joinGroupTransactionData.getReference()); bytes.write(joinGroupTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, joinGroupTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(joinGroupTransactionData.getGroupId())); Serialization.serializeBigDecimal(bytes, joinGroupTransactionData.getFee()); @@ -88,7 +82,7 @@ public class JoinGroupTransactionTransformer extends TransactionTransformer { json.put("joiner", PublicKeyAccount.getAddress(joinerPublicKey)); json.put("joinerPublicKey", HashCode.fromBytes(joinerPublicKey).toString()); - json.put("groupName", joinGroupTransactionData.getGroupName()); + json.put("groupId", joinGroupTransactionData.getGroupId()); } catch (ClassCastException e) { throw new TransformationException(e); } diff --git a/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java index a02e7e4d..05b9a3c1 100644 --- a/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/LeaveGroupTransactionTransformer.java @@ -9,11 +9,9 @@ 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; @@ -22,9 +20,9 @@ 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 GROUPID_LENGTH = INT_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + JOINER_LENGTH + NAME_SIZE_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + JOINER_LENGTH + GROUPID_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -34,22 +32,18 @@ public class LeaveGroupTransactionTransformer extends TransactionTransformer { byte[] leaverPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer); byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new LeaveGroupTransactionData(leaverPublicKey, groupName, fee, timestamp, reference, signature); + return new LeaveGroupTransactionData(leaverPublicKey, groupId, 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; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { @@ -63,7 +57,7 @@ public class LeaveGroupTransactionTransformer extends TransactionTransformer { bytes.write(leaveGroupTransactionData.getReference()); bytes.write(leaveGroupTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, leaveGroupTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(leaveGroupTransactionData.getGroupId())); Serialization.serializeBigDecimal(bytes, leaveGroupTransactionData.getFee()); @@ -88,7 +82,7 @@ public class LeaveGroupTransactionTransformer extends TransactionTransformer { json.put("leaver", PublicKeyAccount.getAddress(leaverPublicKey)); json.put("leaverPublicKey", HashCode.fromBytes(leaverPublicKey).toString()); - json.put("groupName", leaveGroupTransactionData.getGroupName()); + json.put("groupId", leaveGroupTransactionData.getGroupId()); } catch (ClassCastException e) { throw new TransformationException(e); } diff --git a/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java index f9d8376f..a5cd920c 100644 --- a/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/RemoveGroupAdminTransactionTransformer.java @@ -9,11 +9,9 @@ import org.json.simple.JSONObject; import org.qora.account.PublicKeyAccount; import org.qora.data.transaction.RemoveGroupAdminTransactionData; 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; @@ -22,10 +20,10 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform // Property lengths private static final int OWNER_LENGTH = PUBLIC_KEY_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int MEMBER_LENGTH = ADDRESS_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + NAME_SIZE_LENGTH + MEMBER_LENGTH; + private static final int TYPELESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + GROUPID_LENGTH + MEMBER_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -35,7 +33,7 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform byte[] ownerPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String admin = Serialization.deserializeAddress(byteBuffer); @@ -44,15 +42,11 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new RemoveGroupAdminTransactionData(ownerPublicKey, groupName, admin, fee, timestamp, reference, signature); + return new RemoveGroupAdminTransactionData(ownerPublicKey, groupId, admin, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { - RemoveGroupAdminTransactionData removeGroupAdminTransactionData = (RemoveGroupAdminTransactionData) transactionData; - - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(removeGroupAdminTransactionData.getGroupName()); - - return dataLength; + return TYPE_LENGTH + TYPELESS_LENGTH; } public static byte[] toBytes(TransactionData transactionData) throws TransformationException { @@ -66,7 +60,7 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform bytes.write(removeGroupAdminTransactionData.getReference()); bytes.write(removeGroupAdminTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, removeGroupAdminTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(removeGroupAdminTransactionData.getGroupId())); Serialization.serializeAddress(bytes, removeGroupAdminTransactionData.getAdmin()); Serialization.serializeBigDecimal(bytes, removeGroupAdminTransactionData.getFee()); @@ -92,7 +86,7 @@ public class RemoveGroupAdminTransactionTransformer extends TransactionTransform json.put("owner", PublicKeyAccount.getAddress(ownerPublicKey)); json.put("ownerPublicKey", HashCode.fromBytes(ownerPublicKey).toString()); - json.put("groupName", removeGroupAdminTransactionData.getGroupName()); + json.put("groupId", removeGroupAdminTransactionData.getGroupId()); json.put("admin", removeGroupAdminTransactionData.getAdmin()); } catch (ClassCastException e) { throw new TransformationException(e); diff --git a/src/main/java/org/qora/transform/transaction/TransactionTransformer.java b/src/main/java/org/qora/transform/transaction/TransactionTransformer.java index a66b3e08..fe5b79ff 100644 --- a/src/main/java/org/qora/transform/transaction/TransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/TransactionTransformer.java @@ -109,8 +109,8 @@ public class TransactionTransformer extends Transformer { case GROUP_BAN: return GroupBanTransactionTransformer.fromByteBuffer(byteBuffer); - case GROUP_UNBAN: - return GroupUnbanTransactionTransformer.fromByteBuffer(byteBuffer); + case CANCEL_GROUP_BAN: + return CancelGroupBanTransactionTransformer.fromByteBuffer(byteBuffer); case GROUP_KICK: return GroupKickTransactionTransformer.fromByteBuffer(byteBuffer); @@ -203,8 +203,8 @@ public class TransactionTransformer extends Transformer { case GROUP_BAN: return GroupBanTransactionTransformer.getDataLength(transactionData); - case GROUP_UNBAN: - return GroupUnbanTransactionTransformer.getDataLength(transactionData); + case CANCEL_GROUP_BAN: + return CancelGroupBanTransactionTransformer.getDataLength(transactionData); case GROUP_KICK: return GroupKickTransactionTransformer.getDataLength(transactionData); @@ -294,8 +294,8 @@ public class TransactionTransformer extends Transformer { case GROUP_BAN: return GroupBanTransactionTransformer.toBytes(transactionData); - case GROUP_UNBAN: - return GroupUnbanTransactionTransformer.toBytes(transactionData); + case CANCEL_GROUP_BAN: + return CancelGroupBanTransactionTransformer.toBytes(transactionData); case GROUP_KICK: return GroupKickTransactionTransformer.toBytes(transactionData); @@ -394,8 +394,8 @@ public class TransactionTransformer extends Transformer { case GROUP_BAN: return GroupBanTransactionTransformer.toBytesForSigningImpl(transactionData); - case GROUP_UNBAN: - return GroupUnbanTransactionTransformer.toBytesForSigningImpl(transactionData); + case CANCEL_GROUP_BAN: + return CancelGroupBanTransactionTransformer.toBytesForSigningImpl(transactionData); case GROUP_KICK: return GroupKickTransactionTransformer.toBytesForSigningImpl(transactionData); @@ -506,8 +506,8 @@ public class TransactionTransformer extends Transformer { case GROUP_BAN: return GroupBanTransactionTransformer.toJSON(transactionData); - case GROUP_UNBAN: - return GroupUnbanTransactionTransformer.toJSON(transactionData); + case CANCEL_GROUP_BAN: + return CancelGroupBanTransactionTransformer.toJSON(transactionData); case GROUP_KICK: return GroupKickTransactionTransformer.toJSON(transactionData); diff --git a/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java b/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java index 9d741594..fa1f80ae 100644 --- a/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java +++ b/src/main/java/org/qora/transform/transaction/UpdateGroupTransactionTransformer.java @@ -22,12 +22,13 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer { // Property lengths private static final int OWNER_LENGTH = PUBLIC_KEY_LENGTH; + private static final int GROUPID_LENGTH = INT_LENGTH; private static final int NEW_OWNER_LENGTH = ADDRESS_LENGTH; - private static final int NAME_SIZE_LENGTH = INT_LENGTH; private static final int NEW_DESCRIPTION_SIZE_LENGTH = INT_LENGTH; private static final int NEW_IS_OPEN_LENGTH = BOOLEAN_LENGTH; - private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + NEW_OWNER_LENGTH + NAME_SIZE_LENGTH + NEW_DESCRIPTION_SIZE_LENGTH + NEW_IS_OPEN_LENGTH; + private static final int TYPELESS_DATALESS_LENGTH = BASE_TYPELESS_LENGTH + OWNER_LENGTH + GROUPID_LENGTH + NEW_OWNER_LENGTH + NEW_DESCRIPTION_SIZE_LENGTH + + NEW_IS_OPEN_LENGTH; static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException { long timestamp = byteBuffer.getLong(); @@ -37,7 +38,7 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer { byte[] ownerPublicKey = Serialization.deserializePublicKey(byteBuffer); - String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE); + int groupId = byteBuffer.getInt(); String newOwner = Serialization.deserializeAddress(byteBuffer); @@ -50,14 +51,13 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer { byte[] signature = new byte[SIGNATURE_LENGTH]; byteBuffer.get(signature); - return new UpdateGroupTransactionData(ownerPublicKey, groupName, newOwner, newDescription, newIsOpen, fee, timestamp, reference, signature); + return new UpdateGroupTransactionData(ownerPublicKey, groupId, newOwner, newDescription, newIsOpen, fee, timestamp, reference, signature); } public static int getDataLength(TransactionData transactionData) throws TransformationException { UpdateGroupTransactionData updateGroupTransactionData = (UpdateGroupTransactionData) transactionData; - int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(updateGroupTransactionData.getGroupName()) - + Utf8.encodedLength(updateGroupTransactionData.getNewDescription()); + int dataLength = TYPE_LENGTH + TYPELESS_DATALESS_LENGTH + Utf8.encodedLength(updateGroupTransactionData.getNewDescription()); return dataLength; } @@ -73,7 +73,7 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer { bytes.write(updateGroupTransactionData.getReference()); bytes.write(updateGroupTransactionData.getCreatorPublicKey()); - Serialization.serializeSizedString(bytes, updateGroupTransactionData.getGroupName()); + bytes.write(Ints.toByteArray(updateGroupTransactionData.getGroupId())); Serialization.serializeAddress(bytes, updateGroupTransactionData.getNewOwner()); Serialization.serializeSizedString(bytes, updateGroupTransactionData.getNewDescription()); @@ -103,7 +103,7 @@ public class UpdateGroupTransactionTransformer extends TransactionTransformer { json.put("owner", PublicKeyAccount.getAddress(ownerPublicKey)); json.put("ownerPublicKey", HashCode.fromBytes(ownerPublicKey).toString()); - json.put("groupName", updateGroupTransactionData.getGroupName()); + json.put("groupId", updateGroupTransactionData.getGroupId()); json.put("newOwner", updateGroupTransactionData.getNewOwner()); json.put("newDescription", updateGroupTransactionData.getNewDescription()); json.put("newIsOpen", updateGroupTransactionData.getNewIsOpen());