You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
fix(marketplace): only pay out claimed offers after detach
MarketPlace.getCredits previously removed sold offers from memory and granted credits before knowing whether marketplace_items.user_id had been detached in the database. If that update failed, the same sold offer could be loaded as claimable again later. Make removeUser report success, keep the offer claimable on failure, and only grant credits after the database detach succeeds.
This commit is contained in:
@@ -398,11 +398,12 @@ public class MarketPlace {
|
||||
synchronized (client.getHabbo().getInventory()) {
|
||||
for (MarketPlaceOffer offer : offers) {
|
||||
if (offer.getState().equals(MarketPlaceState.SOLD)) {
|
||||
client.getHabbo().getInventory().removeMarketplaceOffer(offer);
|
||||
credits += offer.getPrice();
|
||||
removeUser(offer);
|
||||
offer.needsUpdate(true);
|
||||
Emulator.getThreading().run(offer);
|
||||
if (removeUser(offer)) {
|
||||
client.getHabbo().getInventory().removeMarketplaceOffer(offer);
|
||||
credits += offer.getPrice();
|
||||
offer.needsUpdate(true);
|
||||
Emulator.getThreading().run(offer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,13 +417,14 @@ public class MarketPlace {
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeUser(MarketPlaceOffer offer) {
|
||||
private static boolean removeUser(MarketPlaceOffer offer) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("UPDATE marketplace_items SET user_id = ? WHERE id = ?")) {
|
||||
statement.setInt(1, -1);
|
||||
statement.setInt(2, offer.getOfferId());
|
||||
statement.execute();
|
||||
return statement.executeUpdate() > 0;
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.eu.habbo.habbohotel.catalog.marketplace;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class MarketPlaceCreditClaimContractTest {
|
||||
private static String marketPlaceSource() throws Exception {
|
||||
return Files.readString(Path.of("src/main/java/com/eu/habbo/habbohotel/catalog/marketplace/MarketPlace.java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void soldOfferIsDetachedBeforeCreditsAreGranted() throws Exception {
|
||||
String source = marketPlaceSource();
|
||||
int getCreditsStart = source.indexOf("public static void getCredits");
|
||||
int removeUserCall = source.indexOf("removeUser(offer)", getCreditsStart);
|
||||
int creditAccumulator = source.indexOf("credits += offer.getPrice()", getCreditsStart);
|
||||
int inventoryRemoval = source.indexOf("removeMarketplaceOffer(offer)", getCreditsStart);
|
||||
|
||||
assertTrue(getCreditsStart > -1, "MarketPlace.getCredits must exist");
|
||||
assertTrue(removeUserCall > -1, "Sold marketplace offers must be detached in the database");
|
||||
assertTrue(removeUserCall < creditAccumulator,
|
||||
"Credits must not be granted until the sold offer is detached from the seller in the database");
|
||||
assertTrue(removeUserCall < inventoryRemoval,
|
||||
"The in-memory sold offer should remain claimable if the database detach fails");
|
||||
}
|
||||
|
||||
@Test
|
||||
void detachFailureIsObservableByCaller() throws Exception {
|
||||
String source = marketPlaceSource();
|
||||
|
||||
assertTrue(source.contains("private static boolean removeUser"),
|
||||
"removeUser must report whether the marketplace ownership update succeeded");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user