You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-20 07:26:18 +00:00
fix(catalog): claim vouchers before rewards
Move voucher exhaustion checks and history persistence behind a synchronized per-voucher claim path. Rewards are now applied only after the history row is inserted successfully, preventing duplicate or failed-claim redemption from granting credits, points, or catalog items. Adds a contract test for claim ordering. Maven verification was attempted but blocked by sandbox network/plugin resolution after escalation usage was exhausted; diff --check passes.
This commit is contained in:
@@ -711,18 +711,22 @@ public class CatalogManager {
|
||||
return;
|
||||
}
|
||||
|
||||
if (voucher.isExhausted()) {
|
||||
client.sendResponse(new RedeemVoucherErrorComposer(Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher) ? RedeemVoucherErrorComposer.INVALID_CODE : RedeemVoucherErrorComposer.TECHNICAL_ERROR));
|
||||
return;
|
||||
Voucher.ClaimResult claimResult = voucher.claimForUser(habbo.getHabboInfo().getId());
|
||||
switch (claimResult) {
|
||||
case CLAIMED:
|
||||
break;
|
||||
case EXHAUSTED:
|
||||
client.sendResponse(new RedeemVoucherErrorComposer(Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher) ? RedeemVoucherErrorComposer.INVALID_CODE : RedeemVoucherErrorComposer.TECHNICAL_ERROR));
|
||||
return;
|
||||
case USER_LIMIT:
|
||||
client.sendResponse(new ModToolIssueHandledComposer("You have exceeded the limit for redeeming this voucher."));
|
||||
return;
|
||||
case FAILED:
|
||||
default:
|
||||
client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.TECHNICAL_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
if (voucher.hasUserExhausted(habbo.getHabboInfo().getId())) {
|
||||
client.sendResponse(new ModToolIssueHandledComposer("You have exceeded the limit for redeeming this voucher."));
|
||||
return;
|
||||
}
|
||||
|
||||
voucher.addHistoryEntry(habbo.getHabboInfo().getId());
|
||||
|
||||
if (voucher.points > 0) {
|
||||
client.getHabbo().givePoints(voucher.pointsType, voucher.points);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,13 @@ import java.util.List;
|
||||
public class Voucher {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Voucher.class);
|
||||
|
||||
public enum ClaimResult {
|
||||
CLAIMED,
|
||||
EXHAUSTED,
|
||||
USER_LIMIT,
|
||||
FAILED
|
||||
}
|
||||
|
||||
public final int id;
|
||||
public final String code;
|
||||
public final int credits;
|
||||
@@ -58,18 +65,34 @@ public class Voucher {
|
||||
return this.amount > 0 && this.history.size() >= this.amount;
|
||||
}
|
||||
|
||||
public void addHistoryEntry(int userId) {
|
||||
int timestamp = Emulator.getIntUnixTimestamp();
|
||||
this.history.add(new VoucherHistoryEntry(this.id, userId, timestamp));
|
||||
public synchronized ClaimResult claimForUser(int userId) {
|
||||
if (this.isExhausted()) {
|
||||
return ClaimResult.EXHAUSTED;
|
||||
}
|
||||
|
||||
if (this.hasUserExhausted(userId)) {
|
||||
return ClaimResult.USER_LIMIT;
|
||||
}
|
||||
|
||||
int timestamp = Emulator.getIntUnixTimestamp();
|
||||
if (!this.insertHistoryEntry(userId, timestamp)) {
|
||||
return ClaimResult.FAILED;
|
||||
}
|
||||
|
||||
this.history.add(new VoucherHistoryEntry(this.id, userId, timestamp));
|
||||
return ClaimResult.CLAIMED;
|
||||
}
|
||||
|
||||
private boolean insertHistoryEntry(int userId, int timestamp) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO voucher_history (`voucher_id`, `user_id`, `timestamp`) VALUES (?, ?, ?)")) {
|
||||
statement.setInt(1, this.id);
|
||||
statement.setInt(2, userId);
|
||||
statement.setInt(3, timestamp);
|
||||
|
||||
statement.execute();
|
||||
return statement.executeUpdate() > 0;
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user