forked from Qortal/qortal
Group ban/unban & pre-conversion to groupID & pre-tidy/refactor
This commit is contained in:
parent
90f1676c7c
commit
3b4c12da56
@ -28,6 +28,7 @@ import org.qora.api.ApiExceptionFactory;
|
||||
import org.qora.api.model.GroupWithMemberInfo;
|
||||
import org.qora.crypto.Crypto;
|
||||
import org.qora.data.group.GroupAdminData;
|
||||
import org.qora.data.group.GroupBanData;
|
||||
import org.qora.data.group.GroupData;
|
||||
import org.qora.data.group.GroupInviteData;
|
||||
import org.qora.data.group.GroupJoinRequestData;
|
||||
@ -35,8 +36,10 @@ import org.qora.data.group.GroupMemberData;
|
||||
import org.qora.data.transaction.AddGroupAdminTransactionData;
|
||||
import org.qora.data.transaction.CancelGroupInviteTransactionData;
|
||||
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.JoinGroupTransactionData;
|
||||
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||
import org.qora.data.transaction.RemoveGroupAdminTransactionData;
|
||||
@ -50,8 +53,10 @@ import org.qora.transform.TransformationException;
|
||||
import org.qora.transform.transaction.AddGroupAdminTransactionTransformer;
|
||||
import org.qora.transform.transaction.CancelGroupInviteTransactionTransformer;
|
||||
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.JoinGroupTransactionTransformer;
|
||||
import org.qora.transform.transaction.LeaveGroupTransactionTransformer;
|
||||
import org.qora.transform.transaction.RemoveGroupAdminTransactionTransformer;
|
||||
@ -344,6 +349,92 @@ public class GroupsResource {
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/ban")
|
||||
@Operation(
|
||||
summary = "Build raw, unsigned, GROUP_BAN transaction",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
schema = @Schema(
|
||||
implementation = GroupBanTransactionData.class
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "raw, unsigned, GROUP_BAN transaction encoded in Base58",
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "string"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||
public String groupBan(GroupBanTransactionData transactionData) {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
|
||||
ValidationResult result = transaction.isValidUnconfirmed();
|
||||
if (result != ValidationResult.OK)
|
||||
throw TransactionsResource.createTransactionInvalidException(request, result);
|
||||
|
||||
byte[] bytes = GroupBanTransactionTransformer.toBytes(transactionData);
|
||||
return Base58.encode(bytes);
|
||||
} catch (TransformationException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e);
|
||||
} catch (DataException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/unban")
|
||||
@Operation(
|
||||
summary = "Build raw, unsigned, GROUP_UNBAN transaction",
|
||||
requestBody = @RequestBody(
|
||||
required = true,
|
||||
content = @Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
schema = @Schema(
|
||||
implementation = GroupUnbanTransactionData.class
|
||||
)
|
||||
)
|
||||
),
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "raw, unsigned, GROUP_UNBAN transaction encoded in Base58",
|
||||
content = @Content(
|
||||
mediaType = MediaType.TEXT_PLAIN,
|
||||
schema = @Schema(
|
||||
type = "string"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.TRANSACTION_INVALID, ApiError.TRANSFORMATION_ERROR, ApiError.REPOSITORY_ISSUE})
|
||||
public String groupBan(GroupUnbanTransactionData transactionData) {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
Transaction transaction = Transaction.fromData(repository, transactionData);
|
||||
|
||||
ValidationResult result = transaction.isValidUnconfirmed();
|
||||
if (result != ValidationResult.OK)
|
||||
throw TransactionsResource.createTransactionInvalidException(request, result);
|
||||
|
||||
byte[] bytes = GroupUnbanTransactionTransformer.toBytes(transactionData);
|
||||
return Base58.encode(bytes);
|
||||
} catch (TransformationException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.TRANSFORMATION_ERROR, e);
|
||||
} catch (DataException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
||||
}
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/kick")
|
||||
@Operation(
|
||||
@ -588,7 +679,7 @@ public class GroupsResource {
|
||||
summary = "Pending group join requests",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "group jon requests",
|
||||
description = "group join requests",
|
||||
content = @Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
schema = @Schema(implementation = GroupJoinRequestData.class)
|
||||
@ -605,4 +696,27 @@ public class GroupsResource {
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/bans/{groupname}")
|
||||
@Operation(
|
||||
summary = "Current group join bans",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "group bans",
|
||||
content = @Content(
|
||||
mediaType = MediaType.APPLICATION_JSON,
|
||||
schema = @Schema(implementation = GroupJoinRequestData.class)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
@ApiErrors({ApiError.REPOSITORY_ISSUE})
|
||||
public List<GroupBanData> getBans(@PathParam("groupname") String groupName) {
|
||||
try (final Repository repository = RepositoryManager.getRepository()) {
|
||||
return repository.getGroupRepository().getGroupBans(groupName);
|
||||
} catch (DataException e) {
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
72
src/main/java/org/qora/data/group/GroupBanData.java
Normal file
72
src/main/java/org/qora/data/group/GroupBanData.java
Normal file
@ -0,0 +1,72 @@
|
||||
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 GroupBanData {
|
||||
|
||||
// Properties
|
||||
private String groupName;
|
||||
private String offender;
|
||||
private String admin;
|
||||
private long banned;
|
||||
private String reason;
|
||||
private Long expiry;
|
||||
// No need to ever expose this via API
|
||||
@XmlTransient
|
||||
private byte[] reference;
|
||||
|
||||
// Constructors
|
||||
|
||||
// necessary for JAX-RS serialization
|
||||
protected GroupBanData() {
|
||||
}
|
||||
|
||||
public GroupBanData(String groupName, String offender, String admin, long banned, String reason, Long expiry, byte[] reference) {
|
||||
this.groupName = groupName;
|
||||
this.offender = offender;
|
||||
this.admin = admin;
|
||||
this.banned = banned;
|
||||
this.reason = reason;
|
||||
this.expiry = expiry;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
|
||||
public String getGroupName() {
|
||||
return this.groupName;
|
||||
}
|
||||
|
||||
public String getOffender() {
|
||||
return this.offender;
|
||||
}
|
||||
|
||||
public String getAdmin() {
|
||||
return this.admin;
|
||||
}
|
||||
|
||||
public long getBanned() {
|
||||
return this.banned;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return this.reason;
|
||||
}
|
||||
|
||||
public Long getExpiry() {
|
||||
return this.expiry;
|
||||
}
|
||||
|
||||
public byte[] getReference() {
|
||||
return this.reference;
|
||||
}
|
||||
|
||||
public void setReference(byte[] reference) {
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
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 GroupBanTransactionData 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 = "offender to ban from group", example = "QixPbJUwsaHsVEofJdozU9zgVqkK6aYhrK")
|
||||
private String offender;
|
||||
@Schema(description = "reason for ban")
|
||||
private String reason;
|
||||
@Schema(description = "ban lifetime in seconds")
|
||||
private int timeToLive;
|
||||
// No need to ever expose this via API
|
||||
@XmlTransient
|
||||
private byte[] memberReference;
|
||||
// No need to ever expose this via API
|
||||
@XmlTransient
|
||||
private byte[] adminReference;
|
||||
|
||||
// Constructors
|
||||
|
||||
// For JAX-RS
|
||||
protected GroupBanTransactionData() {
|
||||
super(TransactionType.GROUP_BAN);
|
||||
}
|
||||
|
||||
public void afterUnmarshal(Unmarshaller u, Object parent) {
|
||||
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) {
|
||||
super(TransactionType.GROUP_BAN, fee, adminPublicKey, timestamp, reference, signature);
|
||||
|
||||
this.adminPublicKey = adminPublicKey;
|
||||
this.groupName = groupName;
|
||||
this.offender = member;
|
||||
this.reason = reason;
|
||||
this.timeToLive = timeToLive;
|
||||
this.memberReference = memberReference;
|
||||
this.adminReference = adminReference;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Getters / setters
|
||||
|
||||
public byte[] getAdminPublicKey() {
|
||||
return this.adminPublicKey;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return this.groupName;
|
||||
}
|
||||
|
||||
public String getOffender() {
|
||||
return this.offender;
|
||||
}
|
||||
|
||||
public String getReason() {
|
||||
return this.reason;
|
||||
}
|
||||
|
||||
public int getTimeToLive() {
|
||||
return this.timeToLive;
|
||||
}
|
||||
|
||||
public byte[] getMemberReference() {
|
||||
return this.memberReference;
|
||||
}
|
||||
|
||||
public void setMemberReference(byte[] memberReference) {
|
||||
this.memberReference = memberReference;
|
||||
}
|
||||
|
||||
public byte[] getAdminReference() {
|
||||
return this.adminReference;
|
||||
}
|
||||
|
||||
public void setAdminReference(byte[] adminReference) {
|
||||
this.adminReference = adminReference;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -35,6 +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,
|
||||
GroupKickTransactionData.class, GroupInviteTransactionData.class,
|
||||
JoinGroupTransactionData.class, LeaveGroupTransactionData.class
|
||||
})
|
||||
|
@ -6,6 +6,7 @@ import java.util.List;
|
||||
import org.qora.account.Account;
|
||||
import org.qora.account.PublicKeyAccount;
|
||||
import org.qora.data.group.GroupAdminData;
|
||||
import org.qora.data.group.GroupBanData;
|
||||
import org.qora.data.group.GroupData;
|
||||
import org.qora.data.group.GroupInviteData;
|
||||
import org.qora.data.group.GroupJoinRequestData;
|
||||
@ -13,8 +14,10 @@ import org.qora.data.group.GroupMemberData;
|
||||
import org.qora.data.transaction.AddGroupAdminTransactionData;
|
||||
import org.qora.data.transaction.CancelGroupInviteTransactionData;
|
||||
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.JoinGroupTransactionData;
|
||||
import org.qora.data.transaction.LeaveGroupTransactionData;
|
||||
import org.qora.data.transaction.RemoveGroupAdminTransactionData;
|
||||
@ -65,16 +68,30 @@ public class Group {
|
||||
|
||||
// Processing
|
||||
|
||||
/*
|
||||
* GroupData records can be changed by CREATE_GROUP or UPDATE_GROUP transactions.
|
||||
*
|
||||
* GroupData stores the signature of the last transaction that caused a change to its contents
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// CREATE GROUP
|
||||
|
||||
public void create(CreateGroupTransactionData createGroupTransactionData) throws DataException {
|
||||
// Note: this.groupData already populated by our constructor above
|
||||
this.repository.getGroupRepository().save(this.groupData);
|
||||
|
||||
// Add owner as admin too
|
||||
this.repository.getGroupRepository()
|
||||
.save(new GroupAdminData(this.groupData.getGroupName(), this.groupData.getOwner(), createGroupTransactionData.getSignature()));
|
||||
// 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 too
|
||||
this.repository.getGroupRepository().save(new GroupMemberData(this.groupData.getGroupName(), this.groupData.getOwner(), this.groupData.getCreated(),
|
||||
createGroupTransactionData.getSignature()));
|
||||
// Add owner as member
|
||||
GroupMemberData groupMemberData = new GroupMemberData(this.groupData.getGroupName(), this.groupData.getOwner(), this.groupData.getCreated(),
|
||||
createGroupTransactionData.getSignature());
|
||||
this.repository.getGroupRepository().save(groupMemberData);
|
||||
}
|
||||
|
||||
public void uncreate() throws DataException {
|
||||
@ -82,43 +99,22 @@ public class Group {
|
||||
this.repository.getGroupRepository().delete(this.groupData.getGroupName());
|
||||
}
|
||||
|
||||
private void revert() throws DataException {
|
||||
TransactionData previousTransactionData = this.repository.getTransactionRepository().fromSignature(this.groupData.getReference());
|
||||
if (previousTransactionData == null)
|
||||
throw new DataException("Unable to revert group transaction as referenced transaction not found in repository");
|
||||
// UPDATE GROUP
|
||||
|
||||
switch (previousTransactionData.getType()) {
|
||||
case CREATE_GROUP:
|
||||
CreateGroupTransactionData previousCreateGroupTransactionData = (CreateGroupTransactionData) previousTransactionData;
|
||||
this.groupData.setOwner(previousCreateGroupTransactionData.getOwner());
|
||||
this.groupData.setDescription(previousCreateGroupTransactionData.getDescription());
|
||||
this.groupData.setIsOpen(previousCreateGroupTransactionData.getIsOpen());
|
||||
this.groupData.setUpdated(null);
|
||||
break;
|
||||
/*
|
||||
* In UPDATE_GROUP transactions we store the current GroupData's "reference" in the
|
||||
* transaction's field "group_reference" and update GroupData's "reference" to
|
||||
* our transaction's signature to form an undo chain.
|
||||
*/
|
||||
|
||||
case UPDATE_GROUP:
|
||||
UpdateGroupTransactionData previousUpdateGroupTransactionData = (UpdateGroupTransactionData) previousTransactionData;
|
||||
this.groupData.setOwner(previousUpdateGroupTransactionData.getNewOwner());
|
||||
this.groupData.setDescription(previousUpdateGroupTransactionData.getNewDescription());
|
||||
this.groupData.setIsOpen(previousUpdateGroupTransactionData.getNewIsOpen());
|
||||
this.groupData.setUpdated(previousUpdateGroupTransactionData.getTimestamp());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unable to revert group transaction due to unsupported referenced transaction");
|
||||
}
|
||||
|
||||
// Previous owner will still be admin and member at this point
|
||||
}
|
||||
|
||||
public void update(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
||||
public void updateGroup(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
||||
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||
String groupName = updateGroupTransactionData.getGroupName();
|
||||
|
||||
// Update reference in transaction data
|
||||
// Save GroupData's reference in our transaction data
|
||||
updateGroupTransactionData.setGroupReference(this.groupData.getReference());
|
||||
|
||||
// New group reference is this transaction's signature
|
||||
// Update GroupData's reference to this transaction's signature
|
||||
this.groupData.setReference(updateGroupTransactionData.getSignature());
|
||||
|
||||
// Update Group's owner and description
|
||||
@ -148,7 +144,7 @@ public class Group {
|
||||
// Previous owner retained as admin and member
|
||||
}
|
||||
|
||||
public void revert(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
||||
public void unupdateGroup(UpdateGroupTransactionData updateGroupTransactionData) throws DataException {
|
||||
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||
String groupName = updateGroupTransactionData.getGroupName();
|
||||
|
||||
@ -156,7 +152,7 @@ public class Group {
|
||||
this.groupData.setReference(updateGroupTransactionData.getGroupReference());
|
||||
|
||||
// Previous Group's owner and/or description taken from referenced transaction
|
||||
this.revert();
|
||||
this.revertGroupUpdate();
|
||||
|
||||
// Save reverted group data
|
||||
groupRepository.save(this.groupData);
|
||||
@ -178,6 +174,35 @@ public class Group {
|
||||
}
|
||||
}
|
||||
|
||||
private void revertGroupUpdate() throws DataException {
|
||||
TransactionData previousTransactionData = this.repository.getTransactionRepository().fromSignature(this.groupData.getReference());
|
||||
if (previousTransactionData == null)
|
||||
throw new DataException("Unable to revert group transaction as referenced transaction not found in repository");
|
||||
|
||||
switch (previousTransactionData.getType()) {
|
||||
case CREATE_GROUP:
|
||||
CreateGroupTransactionData previousCreateGroupTransactionData = (CreateGroupTransactionData) previousTransactionData;
|
||||
this.groupData.setOwner(previousCreateGroupTransactionData.getOwner());
|
||||
this.groupData.setDescription(previousCreateGroupTransactionData.getDescription());
|
||||
this.groupData.setIsOpen(previousCreateGroupTransactionData.getIsOpen());
|
||||
this.groupData.setUpdated(null);
|
||||
break;
|
||||
|
||||
case UPDATE_GROUP:
|
||||
UpdateGroupTransactionData previousUpdateGroupTransactionData = (UpdateGroupTransactionData) previousTransactionData;
|
||||
this.groupData.setOwner(previousUpdateGroupTransactionData.getNewOwner());
|
||||
this.groupData.setDescription(previousUpdateGroupTransactionData.getNewDescription());
|
||||
this.groupData.setIsOpen(previousUpdateGroupTransactionData.getNewIsOpen());
|
||||
this.groupData.setUpdated(previousUpdateGroupTransactionData.getTimestamp());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unable to revert group transaction due to unsupported referenced transaction");
|
||||
}
|
||||
|
||||
// Previous owner will still be admin and member at this point
|
||||
}
|
||||
|
||||
public void promoteToAdmin(AddGroupAdminTransactionData addGroupAdminTransactionData) throws DataException {
|
||||
GroupAdminData groupAdminData = new GroupAdminData(addGroupAdminTransactionData.getGroupName(), addGroupAdminTransactionData.getMember(),
|
||||
addGroupAdminTransactionData.getSignature());
|
||||
@ -216,12 +241,29 @@ public class Group {
|
||||
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)) {
|
||||
// Delete join request
|
||||
groupRepository.deleteJoinRequest(groupName, 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
|
||||
// from trying to incorrectly recreate a member/admin.
|
||||
groupKickTransactionData.setMemberReference(null);
|
||||
groupKickTransactionData.setAdminReference(null);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Store membership and (optionally) adminship transactions for orphaning purposes
|
||||
GroupAdminData groupAdminData = groupRepository.getAdmin(groupName, member);
|
||||
if (groupAdminData != null) {
|
||||
groupKickTransactionData.setAdminReference(groupAdminData.getGroupReference());
|
||||
|
||||
groupRepository.deleteAdmin(groupName, member);
|
||||
} else {
|
||||
// Not an admin
|
||||
groupKickTransactionData.setAdminReference(null);
|
||||
}
|
||||
|
||||
GroupMemberData groupMemberData = groupRepository.getMember(groupName, member);
|
||||
@ -235,6 +277,15 @@ public class Group {
|
||||
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) {
|
||||
// Rebuild join-request
|
||||
GroupJoinRequestData groupJoinRequestData = new GroupJoinRequestData(groupName, member);
|
||||
groupRepository.save(groupJoinRequestData);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Rebuild member entry using stored transaction reference
|
||||
TransactionData membershipTransactionData = this.repository.getTransactionRepository().fromSignature(groupKickTransactionData.getMemberReference());
|
||||
GroupMemberData groupMemberData = new GroupMemberData(groupName, member, membershipTransactionData.getTimestamp(),
|
||||
@ -248,6 +299,105 @@ public class Group {
|
||||
}
|
||||
}
|
||||
|
||||
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 (groupAdminData != null) {
|
||||
groupBanTransactionData.setAdminReference(groupAdminData.getGroupReference());
|
||||
|
||||
groupRepository.deleteAdmin(groupName, offender);
|
||||
} else {
|
||||
// Not an admin
|
||||
groupBanTransactionData.setAdminReference(null);
|
||||
}
|
||||
|
||||
GroupMemberData groupMemberData = groupRepository.getMember(groupName, offender);
|
||||
groupBanTransactionData.setMemberReference(groupMemberData.getGroupReference());
|
||||
|
||||
groupRepository.deleteMember(groupName, offender);
|
||||
} else {
|
||||
groupBanTransactionData.setMemberReference(null);
|
||||
|
||||
// XXX maybe set join-request reference here?
|
||||
// XXX what about invites?
|
||||
}
|
||||
|
||||
// XXX Delete pending join request
|
||||
// XXX Delete pending invites
|
||||
|
||||
// Ban
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Reinstate pending join request
|
||||
// XXX Reinstate pending invites
|
||||
|
||||
// Delete ban
|
||||
groupRepository.deleteBan(groupName, offender);
|
||||
}
|
||||
|
||||
public void cancelBan(GroupUnbanTransactionData groupUnbanTransactionData) throws DataException {
|
||||
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||
String groupName = groupUnbanTransactionData.getGroupName();
|
||||
String member = groupUnbanTransactionData.getMember();
|
||||
|
||||
GroupBanData groupBanData = groupRepository.getBan(groupName, member);
|
||||
|
||||
// Save reference to banning transaction for orphaning purposes
|
||||
groupUnbanTransactionData.setGroupReference(groupBanData.getReference());
|
||||
|
||||
// Delete ban
|
||||
groupRepository.deleteBan(groupName, member);
|
||||
}
|
||||
|
||||
public void uncancelBan(GroupUnbanTransactionData groupUnbanTransactionData) throws DataException {
|
||||
// Reinstate ban
|
||||
TransactionData transactionData = this.repository.getTransactionRepository().fromSignature(groupUnbanTransactionData.getGroupReference());
|
||||
ban((GroupBanTransactionData) transactionData);
|
||||
|
||||
groupUnbanTransactionData.setGroupReference(null);
|
||||
}
|
||||
|
||||
public void invite(GroupInviteTransactionData groupInviteTransactionData) throws DataException {
|
||||
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||
String groupName = groupInviteTransactionData.getGroupName();
|
||||
@ -265,12 +415,10 @@ public class Group {
|
||||
return;
|
||||
}
|
||||
|
||||
Long expiry;
|
||||
Long expiry = null;
|
||||
int timeToLive = groupInviteTransactionData.getTimeToLive();
|
||||
if (timeToLive == 0)
|
||||
expiry = null;
|
||||
else
|
||||
expiry = groupInviteTransactionData.getTimestamp() + timeToLive;
|
||||
if (timeToLive != 0)
|
||||
expiry = groupInviteTransactionData.getTimestamp() + timeToLive * 1000;
|
||||
|
||||
GroupInviteData groupInviteData = new GroupInviteData(groupName, inviter.getAddress(), groupInviteTransactionData.getInvitee(), expiry,
|
||||
groupInviteTransactionData.getSignature());
|
||||
|
@ -3,6 +3,7 @@ package org.qora.repository;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.data.group.GroupAdminData;
|
||||
import org.qora.data.group.GroupBanData;
|
||||
import org.qora.data.group.GroupData;
|
||||
import org.qora.data.group.GroupInviteData;
|
||||
import org.qora.data.group.GroupJoinRequestData;
|
||||
@ -55,7 +56,7 @@ public interface GroupRepository {
|
||||
|
||||
public GroupInviteData getInvite(String groupName, String inviter, String invitee) throws DataException;
|
||||
|
||||
public boolean hasInvite(String groupName, String invitee) throws DataException;
|
||||
public boolean inviteExists(String groupName, String invitee) throws DataException;
|
||||
|
||||
public boolean inviteExists(String groupName, String inviter, String invitee) throws DataException;
|
||||
|
||||
@ -77,4 +78,16 @@ public interface GroupRepository {
|
||||
|
||||
public void deleteJoinRequest(String groupName, String joiner) throws DataException;
|
||||
|
||||
// Group Bans
|
||||
|
||||
public GroupBanData getBan(String groupName, String member) throws DataException;
|
||||
|
||||
public boolean banExists(String groupName, String offender) throws DataException;
|
||||
|
||||
public List<GroupBanData> getGroupBans(String groupName) throws DataException;
|
||||
|
||||
public void save(GroupBanData groupBanData) throws DataException;
|
||||
|
||||
public void deleteBan(String groupName, String offender) throws DataException;
|
||||
|
||||
}
|
@ -429,7 +429,8 @@ public class HSQLDBDatabaseUpdates {
|
||||
// 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, PRIMARY KEY (group_name, offender))");
|
||||
+ "reason GenericDescription NOT NULL, expiry TIMESTAMP WITH TIME ZONE, reference Signature NOT NULL, "
|
||||
+ "PRIMARY KEY (group_name, offender))");
|
||||
// For expiry maintenance
|
||||
stmt.execute("CREATE INDEX AccountGroupBanExpiryIndex ON AccountGroupBans (expiry)");
|
||||
break;
|
||||
@ -470,6 +471,13 @@ public class HSQLDBDatabaseUpdates {
|
||||
// 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)");
|
||||
|
||||
// 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)");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -8,6 +8,7 @@ import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.data.group.GroupAdminData;
|
||||
import org.qora.data.group.GroupBanData;
|
||||
import org.qora.data.group.GroupData;
|
||||
import org.qora.data.group.GroupInviteData;
|
||||
import org.qora.data.group.GroupJoinRequestData;
|
||||
@ -317,8 +318,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
|
||||
@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)) {
|
||||
try (ResultSet resultSet = this.repository.checkedExecute("SELECT expiry, reference FROM AccountGroupInvites WHERE group_name = ?", groupName)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
@ -334,7 +334,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasInvite(String groupName, String invitee) throws DataException {
|
||||
public boolean inviteExists(String groupName, String invitee) throws DataException {
|
||||
try {
|
||||
return this.repository.exists("AccountGroupInvites", "group_name = ? AND invitee = ?", groupName, invitee);
|
||||
} catch (SQLException e) {
|
||||
@ -408,10 +408,8 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
public void save(GroupInviteData groupInviteData) throws DataException {
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupInvites");
|
||||
|
||||
Timestamp expiryTimestamp;
|
||||
if (groupInviteData.getExpiry() == null)
|
||||
expiryTimestamp = null;
|
||||
else
|
||||
Timestamp expiryTimestamp = null;
|
||||
if (groupInviteData.getExpiry() != null)
|
||||
expiryTimestamp = new Timestamp(groupInviteData.getExpiry());
|
||||
|
||||
saveHelper.bind("group_name", groupInviteData.getGroupName()).bind("inviter", groupInviteData.getInviter())
|
||||
@ -448,8 +446,7 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
public List<GroupJoinRequestData> getGroupJoinRequests(String groupName) throws DataException {
|
||||
List<GroupJoinRequestData> 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 FROM AccountGroupJoinRequests WHERE group_name = ?", groupName)) {
|
||||
if (resultSet == null)
|
||||
return joinRequests;
|
||||
|
||||
@ -487,4 +484,92 @@ public class HSQLDBGroupRepository implements GroupRepository {
|
||||
}
|
||||
}
|
||||
|
||||
// Group Bans
|
||||
|
||||
@Override
|
||||
public GroupBanData getBan(String groupName, String member) 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);
|
||||
|
||||
Timestamp expiryTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC));
|
||||
Long expiry = expiryTimestamp == null ? null : expiryTimestamp.getTime();
|
||||
|
||||
byte[] reference = resultSet.getBytes(6);
|
||||
|
||||
return new GroupBanData(groupName, 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 {
|
||||
try {
|
||||
return this.repository.exists("AccountGroupBans", "group_name = ? AND offender = ?", groupName, offender);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to check for group ban in repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GroupBanData> getGroupBans(String groupName) throws DataException {
|
||||
List<GroupBanData> bans = new ArrayList<>();
|
||||
|
||||
try (ResultSet resultSet = this.repository
|
||||
.checkedExecute("SELECT offender, admin, banned, reason, expiry, reference FROM AccountGroupBans WHERE group_name = ?", groupName)) {
|
||||
if (resultSet == null)
|
||||
return bans;
|
||||
|
||||
do {
|
||||
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);
|
||||
|
||||
Timestamp expiryTimestamp = resultSet.getTimestamp(5, Calendar.getInstance(HSQLDBRepository.UTC));
|
||||
Long expiry = expiryTimestamp == null ? null : expiryTimestamp.getTime();
|
||||
|
||||
byte[] reference = resultSet.getBytes(6);
|
||||
|
||||
bans.add(new GroupBanData(groupName, offender, admin, banned, reason, expiry, reference));
|
||||
} while (resultSet.next());
|
||||
|
||||
return bans;
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch group bans from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(GroupBanData groupBanData) throws DataException {
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountGroupBans");
|
||||
|
||||
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())
|
||||
.bind("banned", new Timestamp(groupBanData.getBanned())).bind("reason", groupBanData.getReason()).bind("expiry", expiryTimestamp)
|
||||
.bind("reference", groupBanData.getReference());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save group ban into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteBan(String groupName, String offender) throws DataException {
|
||||
try {
|
||||
this.repository.delete("AccountGroupBans", "group_name = ? AND offender = ?", groupName, offender);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete group ban from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
package org.qora.repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.qora.data.transaction.GroupBanTransactionData;
|
||||
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 HSQLDBGroupBanTransactionRepository extends HSQLDBTransactionRepository {
|
||||
|
||||
public HSQLDBGroupBanTransactionRepository(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, reason, time_to_live, member_reference, admin_reference FROM GroupBanTransactions WHERE signature = ?",
|
||||
signature)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
String groupName = resultSet.getString(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);
|
||||
|
||||
return new GroupBanTransactionData(creatorPublicKey, groupName, offender, reason, timeToLive, memberReference, adminReference, fee, timestamp,
|
||||
reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch group ban transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
GroupBanTransactionData groupBanTransactionData = (GroupBanTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("GroupBanTransactions");
|
||||
|
||||
saveHelper.bind("signature", groupBanTransactionData.getSignature()).bind("admin", groupBanTransactionData.getAdminPublicKey())
|
||||
.bind("group_name", groupBanTransactionData.getGroupName()).bind("address", groupBanTransactionData.getOffender())
|
||||
.bind("reason", groupBanTransactionData.getReason()).bind("time_to_live", groupBanTransactionData.getTimeToLive())
|
||||
.bind("member_reference", groupBanTransactionData.getMemberReference()).bind("admin_reference", groupBanTransactionData.getAdminReference());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save group ban transaction into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.qora.repository.hsqldb.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.qora.data.transaction.GroupUnbanTransactionData;
|
||||
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 HSQLDBGroupUnbanTransactionRepository(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 = ?",
|
||||
signature)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
String groupName = resultSet.getString(1);
|
||||
String member = resultSet.getString(2);
|
||||
byte[] groupReference = resultSet.getBytes(3);
|
||||
|
||||
return new GroupUnbanTransactionData(creatorPublicKey, groupName, member, groupReference, fee, timestamp, reference, signature);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch group unban transaction from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(TransactionData transactionData) throws DataException {
|
||||
GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) transactionData;
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("GroupUnbanTransactions");
|
||||
|
||||
saveHelper.bind("signature", groupUnbanTransactionData.getSignature()).bind("admin", groupUnbanTransactionData.getAdminPublicKey())
|
||||
.bind("group_name", groupUnbanTransactionData.getGroupName()).bind("address", groupUnbanTransactionData.getMember())
|
||||
.bind("group_reference", groupUnbanTransactionData.getGroupReference());
|
||||
|
||||
try {
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save group unban transaction into repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -46,6 +46,8 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
private HSQLDBUpdateGroupTransactionRepository updateGroupTransactionRepository;
|
||||
private HSQLDBAddGroupAdminTransactionRepository addGroupAdminTransactionRepository;
|
||||
private HSQLDBRemoveGroupAdminTransactionRepository removeGroupAdminTransactionRepository;
|
||||
private HSQLDBGroupBanTransactionRepository groupBanTransactionRepository;
|
||||
private HSQLDBGroupUnbanTransactionRepository groupUnbanTransactionRepository;
|
||||
private HSQLDBGroupKickTransactionRepository groupKickTransactionRepository;
|
||||
private HSQLDBGroupInviteTransactionRepository groupInviteTransactionRepository;
|
||||
private HSQLDBCancelGroupInviteTransactionRepository cancelGroupInviteTransactionRepository;
|
||||
@ -76,6 +78,8 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.updateGroupTransactionRepository = new HSQLDBUpdateGroupTransactionRepository(repository);
|
||||
this.addGroupAdminTransactionRepository = new HSQLDBAddGroupAdminTransactionRepository(repository);
|
||||
this.removeGroupAdminTransactionRepository = new HSQLDBRemoveGroupAdminTransactionRepository(repository);
|
||||
this.groupBanTransactionRepository = new HSQLDBGroupBanTransactionRepository(repository);
|
||||
this.groupUnbanTransactionRepository = new HSQLDBGroupUnbanTransactionRepository(repository);
|
||||
this.groupKickTransactionRepository = new HSQLDBGroupKickTransactionRepository(repository);
|
||||
this.groupInviteTransactionRepository = new HSQLDBGroupInviteTransactionRepository(repository);
|
||||
this.cancelGroupInviteTransactionRepository = new HSQLDBCancelGroupInviteTransactionRepository(repository);
|
||||
@ -219,6 +223,12 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return this.removeGroupAdminTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case GROUP_BAN:
|
||||
return this.groupBanTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return this.groupUnbanTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
case GROUP_KICK:
|
||||
return this.groupKickTransactionRepository.fromBase(signature, reference, creatorPublicKey, timestamp, fee);
|
||||
|
||||
@ -570,6 +580,14 @@ public class HSQLDBTransactionRepository implements TransactionRepository {
|
||||
this.removeGroupAdminTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case GROUP_BAN:
|
||||
this.groupBanTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case GROUP_UNBAN:
|
||||
this.groupUnbanTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
||||
case GROUP_KICK:
|
||||
this.groupKickTransactionRepository.save(transactionData);
|
||||
break;
|
||||
|
161
src/main/java/org/qora/transaction/GroupBanTransaction.java
Normal file
161
src/main/java/org/qora/transaction/GroupBanTransaction.java
Normal file
@ -0,0 +1,161 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
import org.qora.account.PublicKeyAccount;
|
||||
import org.qora.asset.Asset;
|
||||
import org.qora.crypto.Crypto;
|
||||
import org.qora.data.transaction.GroupBanTransactionData;
|
||||
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
|
||||
private GroupBanTransactionData groupBanTransactionData;
|
||||
|
||||
// Constructors
|
||||
|
||||
public GroupBanTransaction(Repository repository, TransactionData transactionData) {
|
||||
super(repository, transactionData);
|
||||
|
||||
this.groupBanTransactionData = (GroupBanTransactionData) this.transactionData;
|
||||
}
|
||||
|
||||
// More information
|
||||
|
||||
@Override
|
||||
public List<Account> getRecipientAccounts() throws DataException {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvolved(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
|
||||
if (address.equals(this.getAdmin().getAddress()))
|
||||
return true;
|
||||
|
||||
if (address.equals(this.getOffender().getAddress()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getAmount(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
BigDecimal amount = BigDecimal.ZERO.setScale(8);
|
||||
|
||||
if (address.equals(this.getAdmin().getAddress()))
|
||||
amount = amount.subtract(this.transactionData.getFee());
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getAdmin() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, this.groupBanTransactionData.getAdminPublicKey());
|
||||
}
|
||||
|
||||
public Account getOffender() throws DataException {
|
||||
return new Account(this.repository, this.groupBanTransactionData.getOffender());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@Override
|
||||
public ValidationResult isValid() throws DataException {
|
||||
GroupRepository groupRepository = this.repository.getGroupRepository();
|
||||
String groupName = groupBanTransactionData.getGroupName();
|
||||
|
||||
// Check member 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);
|
||||
|
||||
// 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()))
|
||||
return ValidationResult.NOT_GROUP_ADMIN;
|
||||
|
||||
// Can't ban another admin unless the group owner
|
||||
if (!admin.getAddress().equals(groupData.getOwner()) && groupRepository.adminExists(groupName, member.getAddress()))
|
||||
return ValidationResult.INVALID_GROUP_OWNER;
|
||||
|
||||
// Check fee is positive
|
||||
if (groupBanTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
if (!Arrays.equals(admin.getLastReference(), groupBanTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupBanTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update Group Membership
|
||||
Group group = new Group(this.repository, groupBanTransactionData.getGroupName());
|
||||
group.ban(groupBanTransactionData);
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupBanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupBanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupBanTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Revert group membership
|
||||
Group group = new Group(this.repository, groupBanTransactionData.getGroupName());
|
||||
group.unban(groupBanTransactionData);
|
||||
|
||||
// Delete this transaction itself
|
||||
this.repository.getTransactionRepository().delete(groupBanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupBanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupBanTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
@ -106,8 +106,8 @@ public class GroupKickTransaction extends Transaction {
|
||||
if (!groupRepository.adminExists(groupName, admin.getAddress()))
|
||||
return ValidationResult.NOT_GROUP_ADMIN;
|
||||
|
||||
// Check member actually in group
|
||||
if (!groupRepository.memberExists(groupName, member.getAddress()))
|
||||
// Check member actually in group UNLESS there's a pending join request
|
||||
if (!groupRepository.joinRequestExists(groupName, member.getAddress()) && !groupRepository.memberExists(groupName, member.getAddress()))
|
||||
return ValidationResult.NOT_GROUP_MEMBER;
|
||||
|
||||
// Can't kick another admin unless the group owner
|
||||
|
161
src/main/java/org/qora/transaction/GroupUnbanTransaction.java
Normal file
161
src/main/java/org/qora/transaction/GroupUnbanTransaction.java
Normal file
@ -0,0 +1,161 @@
|
||||
package org.qora.transaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.qora.account.Account;
|
||||
import org.qora.account.PublicKeyAccount;
|
||||
import org.qora.asset.Asset;
|
||||
import org.qora.crypto.Crypto;
|
||||
import org.qora.data.transaction.GroupUnbanTransactionData;
|
||||
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 {
|
||||
|
||||
// Properties
|
||||
private GroupUnbanTransactionData groupUnbanTransactionData;
|
||||
|
||||
// Constructors
|
||||
|
||||
public GroupUnbanTransaction(Repository repository, TransactionData transactionData) {
|
||||
super(repository, transactionData);
|
||||
|
||||
this.groupUnbanTransactionData = (GroupUnbanTransactionData) this.transactionData;
|
||||
}
|
||||
|
||||
// More information
|
||||
|
||||
@Override
|
||||
public List<Account> getRecipientAccounts() throws DataException {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvolved(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
|
||||
if (address.equals(this.getAdmin().getAddress()))
|
||||
return true;
|
||||
|
||||
if (address.equals(this.getMember().getAddress()))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getAmount(Account account) throws DataException {
|
||||
String address = account.getAddress();
|
||||
BigDecimal amount = BigDecimal.ZERO.setScale(8);
|
||||
|
||||
if (address.equals(this.getAdmin().getAddress()))
|
||||
amount = amount.subtract(this.transactionData.getFee());
|
||||
|
||||
return amount;
|
||||
}
|
||||
|
||||
// Navigation
|
||||
|
||||
public Account getAdmin() throws DataException {
|
||||
return new PublicKeyAccount(this.repository, this.groupUnbanTransactionData.getAdminPublicKey());
|
||||
}
|
||||
|
||||
public Account getMember() throws DataException {
|
||||
return new Account(this.repository, this.groupUnbanTransactionData.getMember());
|
||||
}
|
||||
|
||||
// Processing
|
||||
|
||||
@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);
|
||||
|
||||
// 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()))
|
||||
return ValidationResult.NOT_GROUP_ADMIN;
|
||||
|
||||
// Check ban actually exists
|
||||
if (!groupRepository.banExists(groupName, member.getAddress()))
|
||||
return ValidationResult.BAN_UNKNOWN;
|
||||
|
||||
// Check fee is positive
|
||||
if (groupUnbanTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
return ValidationResult.NEGATIVE_FEE;
|
||||
|
||||
if (!Arrays.equals(admin.getLastReference(), groupUnbanTransactionData.getReference()))
|
||||
return ValidationResult.INVALID_REFERENCE;
|
||||
|
||||
// Check creator has enough funds
|
||||
if (admin.getConfirmedBalance(Asset.QORA).compareTo(groupUnbanTransactionData.getFee()) < 0)
|
||||
return ValidationResult.NO_BALANCE;
|
||||
|
||||
return ValidationResult.OK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() throws DataException {
|
||||
// Update Group Membership
|
||||
Group group = new Group(this.repository, groupUnbanTransactionData.getGroupName());
|
||||
group.cancelBan(groupUnbanTransactionData);
|
||||
|
||||
// Save this transaction with updated member/admin references to transactions that can help restore state
|
||||
this.repository.getTransactionRepository().save(groupUnbanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).subtract(groupUnbanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupUnbanTransactionData.getSignature());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void orphan() throws DataException {
|
||||
// Revert group membership
|
||||
Group group = new Group(this.repository, groupUnbanTransactionData.getGroupName());
|
||||
group.uncancelBan(groupUnbanTransactionData);
|
||||
|
||||
// Delete this transaction itself
|
||||
this.repository.getTransactionRepository().delete(groupUnbanTransactionData);
|
||||
|
||||
// Update admin's balance
|
||||
Account admin = getAdmin();
|
||||
admin.setConfirmedBalance(Asset.QORA, admin.getConfirmedBalance(Asset.QORA).add(groupUnbanTransactionData.getFee()));
|
||||
|
||||
// Update admin's reference
|
||||
admin.setLastReference(groupUnbanTransactionData.getReference());
|
||||
}
|
||||
|
||||
}
|
@ -88,7 +88,9 @@ public class JoinGroupTransaction extends Transaction {
|
||||
if (this.repository.getGroupRepository().memberExists(joinGroupTransactionData.getGroupName(), joiner.getAddress()))
|
||||
return ValidationResult.ALREADY_GROUP_MEMBER;
|
||||
|
||||
// XXX Check member is not banned
|
||||
// Check member is not banned
|
||||
if (this.repository.getGroupRepository().banExists(joinGroupTransactionData.getGroupName(), joiner.getAddress()))
|
||||
return ValidationResult.BANNED_FROM_GROUP;
|
||||
|
||||
// Check fee is positive
|
||||
if (joinGroupTransactionData.getFee().compareTo(BigDecimal.ZERO) <= 0)
|
||||
|
@ -135,6 +135,9 @@ public abstract class Transaction {
|
||||
NOT_GROUP_ADMIN(55),
|
||||
INVALID_LIFETIME(56),
|
||||
INVITE_UNKNOWN(57),
|
||||
BAN_EXISTS(58),
|
||||
BAN_UNKNOWN(59),
|
||||
BANNED_FROM_GROUP(60),
|
||||
NOT_YET_RELEASED(1000);
|
||||
|
||||
public final int value;
|
||||
@ -246,6 +249,12 @@ public abstract class Transaction {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return new RemoveGroupAdminTransaction(repository, transactionData);
|
||||
|
||||
case GROUP_BAN:
|
||||
return new GroupBanTransaction(repository, transactionData);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return new GroupUnbanTransaction(repository, transactionData);
|
||||
|
||||
case GROUP_KICK:
|
||||
return new GroupKickTransaction(repository, transactionData);
|
||||
|
||||
|
@ -126,7 +126,7 @@ public class UpdateGroupTransaction extends Transaction {
|
||||
public void process() throws DataException {
|
||||
// Update Group
|
||||
Group group = new Group(this.repository, updateGroupTransactionData.getGroupName());
|
||||
group.update(updateGroupTransactionData);
|
||||
group.updateGroup(updateGroupTransactionData);
|
||||
|
||||
// Save this transaction, now with updated "group reference" to previous transaction that updated group
|
||||
this.repository.getTransactionRepository().save(updateGroupTransactionData);
|
||||
@ -143,7 +143,7 @@ public class UpdateGroupTransaction extends Transaction {
|
||||
public void orphan() throws DataException {
|
||||
// Revert Group update
|
||||
Group group = new Group(this.repository, updateGroupTransactionData.getGroupName());
|
||||
group.revert(updateGroupTransactionData);
|
||||
group.unupdateGroup(updateGroupTransactionData);
|
||||
|
||||
// Delete this transaction itself
|
||||
this.repository.getTransactionRepository().delete(updateGroupTransactionData);
|
||||
|
@ -0,0 +1,115 @@
|
||||
package org.qora.transform.transaction;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.qora.account.PublicKeyAccount;
|
||||
import org.qora.data.transaction.GroupBanTransactionData;
|
||||
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 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 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;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE);
|
||||
|
||||
String offender = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
String reason = Serialization.deserializeSizedString(byteBuffer, Group.MAX_REASON_SIZE);
|
||||
|
||||
int timeToLive = byteBuffer.getInt();
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||
byteBuffer.get(signature);
|
||||
|
||||
return new GroupBanTransactionData(adminPublicKey, groupName, 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());
|
||||
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
try {
|
||||
GroupBanTransactionData groupBanTransactionData = (GroupBanTransactionData) transactionData;
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Ints.toByteArray(groupBanTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(groupBanTransactionData.getTimestamp()));
|
||||
bytes.write(groupBanTransactionData.getReference());
|
||||
|
||||
bytes.write(groupBanTransactionData.getCreatorPublicKey());
|
||||
Serialization.serializeSizedString(bytes, groupBanTransactionData.getGroupName());
|
||||
Serialization.serializeAddress(bytes, groupBanTransactionData.getOffender());
|
||||
Serialization.serializeSizedString(bytes, groupBanTransactionData.getReason());
|
||||
bytes.write(Ints.toByteArray(groupBanTransactionData.getTimeToLive()));
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, groupBanTransactionData.getFee());
|
||||
|
||||
if (groupBanTransactionData.getSignature() != null)
|
||||
bytes.write(groupBanTransactionData.getSignature());
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException | ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JSONObject toJSON(TransactionData transactionData) throws TransformationException {
|
||||
JSONObject json = TransactionTransformer.getBaseJSON(transactionData);
|
||||
|
||||
try {
|
||||
GroupBanTransactionData groupBanTransactionData = (GroupBanTransactionData) transactionData;
|
||||
|
||||
byte[] adminPublicKey = groupBanTransactionData.getAdminPublicKey();
|
||||
|
||||
json.put("admin", PublicKeyAccount.getAddress(adminPublicKey));
|
||||
json.put("adminPublicKey", HashCode.fromBytes(adminPublicKey).toString());
|
||||
|
||||
json.put("groupName", groupBanTransactionData.getGroupName());
|
||||
json.put("offender", groupBanTransactionData.getOffender());
|
||||
json.put("reason", groupBanTransactionData.getReason());
|
||||
json.put("timeToLive", groupBanTransactionData.getTimeToLive());
|
||||
} catch (ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package org.qora.transform.transaction;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.qora.account.PublicKeyAccount;
|
||||
import org.qora.data.transaction.GroupUnbanTransactionData;
|
||||
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 {
|
||||
|
||||
// Property lengths
|
||||
private static final int ADMIN_LENGTH = PUBLIC_KEY_LENGTH;
|
||||
private static final int NAME_SIZE_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;
|
||||
|
||||
static TransactionData fromByteBuffer(ByteBuffer byteBuffer) throws TransformationException {
|
||||
long timestamp = byteBuffer.getLong();
|
||||
|
||||
byte[] reference = new byte[REFERENCE_LENGTH];
|
||||
byteBuffer.get(reference);
|
||||
|
||||
byte[] adminPublicKey = Serialization.deserializePublicKey(byteBuffer);
|
||||
|
||||
String groupName = Serialization.deserializeSizedString(byteBuffer, Group.MAX_NAME_SIZE);
|
||||
|
||||
String member = Serialization.deserializeAddress(byteBuffer);
|
||||
|
||||
BigDecimal fee = Serialization.deserializeBigDecimal(byteBuffer);
|
||||
|
||||
byte[] signature = new byte[SIGNATURE_LENGTH];
|
||||
byteBuffer.get(signature);
|
||||
|
||||
return new GroupUnbanTransactionData(adminPublicKey, groupName, 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;
|
||||
}
|
||||
|
||||
public static byte[] toBytes(TransactionData transactionData) throws TransformationException {
|
||||
try {
|
||||
GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) transactionData;
|
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
bytes.write(Ints.toByteArray(groupUnbanTransactionData.getType().value));
|
||||
bytes.write(Longs.toByteArray(groupUnbanTransactionData.getTimestamp()));
|
||||
bytes.write(groupUnbanTransactionData.getReference());
|
||||
|
||||
bytes.write(groupUnbanTransactionData.getCreatorPublicKey());
|
||||
Serialization.serializeSizedString(bytes, groupUnbanTransactionData.getGroupName());
|
||||
Serialization.serializeAddress(bytes, groupUnbanTransactionData.getMember());
|
||||
|
||||
Serialization.serializeBigDecimal(bytes, groupUnbanTransactionData.getFee());
|
||||
|
||||
if (groupUnbanTransactionData.getSignature() != null)
|
||||
bytes.write(groupUnbanTransactionData.getSignature());
|
||||
|
||||
return bytes.toByteArray();
|
||||
} catch (IOException | ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static JSONObject toJSON(TransactionData transactionData) throws TransformationException {
|
||||
JSONObject json = TransactionTransformer.getBaseJSON(transactionData);
|
||||
|
||||
try {
|
||||
GroupUnbanTransactionData groupUnbanTransactionData = (GroupUnbanTransactionData) 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("member", groupUnbanTransactionData.getMember());
|
||||
} catch (ClassCastException e) {
|
||||
throw new TransformationException(e);
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
@ -106,6 +106,12 @@ public class TransactionTransformer extends Transformer {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return RemoveGroupAdminTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case GROUP_BAN:
|
||||
return GroupBanTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return GroupUnbanTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
case GROUP_KICK:
|
||||
return GroupKickTransactionTransformer.fromByteBuffer(byteBuffer);
|
||||
|
||||
@ -194,6 +200,12 @@ public class TransactionTransformer extends Transformer {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return RemoveGroupAdminTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case GROUP_BAN:
|
||||
return GroupBanTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return GroupUnbanTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
case GROUP_KICK:
|
||||
return GroupKickTransactionTransformer.getDataLength(transactionData);
|
||||
|
||||
@ -279,6 +291,12 @@ public class TransactionTransformer extends Transformer {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return RemoveGroupAdminTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case GROUP_BAN:
|
||||
return GroupBanTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return GroupUnbanTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
case GROUP_KICK:
|
||||
return GroupKickTransactionTransformer.toBytes(transactionData);
|
||||
|
||||
@ -373,6 +391,12 @@ public class TransactionTransformer extends Transformer {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return RemoveGroupAdminTransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
case GROUP_BAN:
|
||||
return GroupBanTransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return GroupUnbanTransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
case GROUP_KICK:
|
||||
return GroupKickTransactionTransformer.toBytesForSigningImpl(transactionData);
|
||||
|
||||
@ -479,6 +503,12 @@ public class TransactionTransformer extends Transformer {
|
||||
case REMOVE_GROUP_ADMIN:
|
||||
return RemoveGroupAdminTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case GROUP_BAN:
|
||||
return GroupBanTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case GROUP_UNBAN:
|
||||
return GroupUnbanTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
case GROUP_KICK:
|
||||
return GroupKickTransactionTransformer.toJSON(transactionData);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user