Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements & Enhancements #32

Merged
merged 8 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import de.unipassau.fim.fsinfo.prost.service.AuthenticationService;
import de.unipassau.fim.fsinfo.prost.service.FileStorageService;
import de.unipassau.fim.fsinfo.prost.service.ShopService;
import de.unipassau.fim.fsinfo.prost.service.UserService;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -36,14 +37,17 @@ public class ShopController {
private final AuthenticationService authService;

private final ShopItemRepository itemRepository;
private final UserService userService;

@Autowired
public ShopController(FileStorageService fileStorageService, ShopService shopService,
ShopItemRepository itemRepository, AuthenticationService authService) {
ShopItemRepository itemRepository, AuthenticationService authService,
UserService userService) {
this.fileStorageService = fileStorageService;
this.shopService = shopService;
this.itemRepository = itemRepository;
this.authService = authService;
this.userService = userService;
}

@GetMapping("/item/list")
Expand Down Expand Up @@ -89,6 +93,7 @@ public ResponseEntity<String> consume(@RequestParam String id, @RequestParam Str
}

CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
String bearerId = userDetails.getUsername();

Collection<UserAccessRole> roles = authService.getRoles(authentication);

Expand All @@ -98,7 +103,7 @@ public ResponseEntity<String> consume(@RequestParam String id, @RequestParam Str
Optional<UserAccessRole> highestPermission = authService.getHighestRole(roles);

if (highestPermission.isPresent() && highestPermission.get().equals(UserAccessRole.FSINFO)) {
if (userId.equals(userDetails.getUsername())) {
if (userId.equals(bearerId)) {
permitted = true;
} else {
// 🙃🫖
Expand All @@ -107,11 +112,20 @@ public ResponseEntity<String> consume(@RequestParam String id, @RequestParam Str
}
}

if (permitted && shopService.consume(id, userId,
(n == null ? 1 : n), userDetails.getUsername())) {
if (!permitted) {
return ResponseEntity.badRequest().body(permitted + " " + highestPermission);
}

if (shopService.hasBearerCooldown(bearerId)) {
return ResponseEntity.badRequest().body("on cooldown");
}

if (shopService.consume(id, userId,
(n == null ? 1 : n), bearerId)) {
return ResponseEntity.ok().build();
}
return ResponseEntity.badRequest().body(permitted + " " + highestPermission);

return ResponseEntity.badRequest().body("Could not consume!");

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,34 @@
import de.unipassau.fim.fsinfo.prost.data.repositories.ShopItemRepository;
import de.unipassau.fim.fsinfo.prost.data.repositories.UserRepository;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.HashMap;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ShopService {

final ShopItemRepository itemRepository;
final ShopItemHistoryRepository historyRepository;
final UserRepository userRepository;
final private ShopItemRepository itemRepository;
final private ShopItemHistoryRepository historyRepository;
final private UserRepository userRepository;

final TransactionService transactionService;
final private TransactionService transactionService;

final static int MAX_NAME_LENGTH = 20;
final static BigDecimal MAX_PRICE = new BigDecimal(100);
final static BigDecimal MIN_PRICE = BigDecimal.ZERO;

@Value("${BUY_COOLDOWN:10000}")
Long buyCooldownTime;

/**
* Authorized User-ID, Unix-Timestamp
*/
final private HashMap<String, Long> bearerLastBuy = new HashMap<>();

@Autowired
public ShopService(ShopItemRepository itemRepository, ShopItemHistoryRepository historyRepository,
UserRepository userRepository, TransactionService transactionService) {
Expand All @@ -37,6 +47,14 @@ public ShopService(ShopItemRepository itemRepository, ShopItemHistoryRepository
this.transactionService = transactionService;
}

public boolean hasBearerCooldown(String userId) {
if (bearerLastBuy.containsKey(userId)) {
Long lastTime = bearerLastBuy.get(userId);
return lastTime + buyCooldownTime > Instant.now().toEpochMilli();
}
return false;
}

@Transactional
public boolean consume(String itemId, String userId, int amount, String bearerId) {
Optional<ShopItem> itemO = itemRepository.findById(itemId);
Expand All @@ -47,6 +65,10 @@ public boolean consume(String itemId, String userId, int amount, String bearerId
return false;
}

if (hasBearerCooldown(bearerId)) {
return false;
}

if (userO.isEmpty() || itemO.isEmpty() || bearerUser.isEmpty()) {
System.out.println(userO + " " + itemO + " " + bearerUser);
return false;
Expand All @@ -69,6 +91,7 @@ public boolean consume(String itemId, String userId, int amount, String bearerId
historyRepository.save(
new ShopItemHistoryEntry(transaction.get(), item.getId(), item.getPrice(),
amount));
bearerLastBuy.put(bearerId, Instant.now().toEpochMilli());
return true;
} else {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import de.unipassau.fim.fsinfo.prost.data.repositories.ShopItemRepository;
import de.unipassau.fim.fsinfo.prost.data.repositories.UserRepository;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -107,6 +108,69 @@ public void testConsume_SuccessfulTransaction_ReturnsTrue() {
assertTrue(result);
}

@Test
public void testConsume_UnsuccessfulSecondTransactionWithoutPause_ReturnsFalse()
throws InterruptedException {
shopService.buyCooldownTime = 10L;

TransactionEntry transaction = new TransactionEntry(null, prostUser.getId(), prostUser.getId(),
TransactionType.BUY, null, shopItem.getPrice());
when(itemRepository.findById(shopItem.getId())).thenReturn(Optional.of(shopItem));
when(userRepository.findById(prostUser.getId())).thenReturn(Optional.of(prostUser));
when(userRepository.findById(prostUser.getId())).thenReturn(Optional.of(prostUser));
when(transactionService.moneyTransfer(any(), anyString(), anyString(), any(),
any(TransactionType.class)))
.thenReturn(Optional.of(transaction));

boolean result = shopService.consume(shopItem.getId(), prostUser.getId(), 1, prostUser.getId());
assertTrue(result);
assertTrue(shopService.hasBearerCooldown(prostUser.getId()));

// second buy
TransactionEntry transaction2 = new TransactionEntry(null, prostUser.getId(), prostUser.getId(),
TransactionType.BUY, null, shopItem.getPrice());

boolean result2 = shopService.consume(shopItem.getId(), prostUser.getId(), 1,
prostUser.getId());
assertFalse(result2);
assertTrue(shopService.hasBearerCooldown(prostUser.getId()));
}

@Test
public void testConsume_SuccessfulSecondTransactionWithPause_ReturnsTrue()
throws InterruptedException {
shopService.buyCooldownTime = 10L;

TransactionEntry transaction = new TransactionEntry(null, prostUser.getId(), prostUser.getId(),
TransactionType.BUY, null, shopItem.getPrice());
when(itemRepository.findById(shopItem.getId())).thenReturn(Optional.of(shopItem));
when(userRepository.findById(prostUser.getId())).thenReturn(Optional.of(prostUser));
when(userRepository.findById(prostUser.getId())).thenReturn(Optional.of(prostUser));
when(transactionService.moneyTransfer(any(), anyString(), anyString(), any(),
any(TransactionType.class)))
.thenReturn(Optional.of(transaction));

boolean result = shopService.consume(shopItem.getId(), prostUser.getId(), 1, prostUser.getId());
long lastTransaction = Instant.now().toEpochMilli();
assertTrue(result);
assertTrue(shopService.hasBearerCooldown(prostUser.getId()));

Thread.sleep(shopService.buyCooldownTime + 1);
assertFalse(shopService.hasBearerCooldown(prostUser.getId()));

// second buy
TransactionEntry transaction2 = new TransactionEntry(null, prostUser.getId(), prostUser.getId(),
TransactionType.BUY, null, shopItem.getPrice());
when(transactionService.moneyTransfer(any(), anyString(), anyString(), any(),
any(TransactionType.class)))
.thenReturn(Optional.of(transaction2));

boolean result2 = shopService.consume(shopItem.getId(), prostUser.getId(), 1,
prostUser.getId());
assertTrue(result2);
assertTrue(shopService.hasBearerCooldown(prostUser.getId()));
}

@Test
public void testCreateItem_InvalidData_ReturnsEmpty() {
Optional<ShopItem> result = shopService.createItem("", "Item 1", "Category 1",
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ services:
context: backend
environment:
LDAP_URI: ldap://ldap:1389/dc=fsinfo,dc=fim,dc=uni-passau,dc=de
# BUY_COOLDOWN: 60000
# PORT: 8081
# MAIL_USER_NAME: test@localhost
# MAIL_USER_PASSWORD: p455w0rd
Expand Down
49 changes: 28 additions & 21 deletions frontend/public/styles/mc.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,26 @@ h1 {
color: #ffffff;
}

.site-data-info {
border-radius: 0px;
#site-data-info {
border-radius: 0;
}
#theme-switch {
border-radius: 0;
}

.Input {
color: #ffffff;
border: 3px solid #ffffff;
background-color: #000000;
border-radius: 0px;
border-radius: 0;
}
.Input:focus {
border: 3px solid var(--on-focus);
}

.CheckBox {
background-color: var(--element-bg);
border-radius: 0px;
border-radius: 0;
border: 2px solid var(--on-focus);
}
.CheckBox:hover {
Expand All @@ -61,7 +64,7 @@ h1 {
background-color: rgba(0, 0, 0, 0);
box-shadow: 0 2px 10px var(--shadow);
border: none;
border-radius: 0px;
border-radius: 0;
padding: 1.4rem 2rem;
}

Expand Down Expand Up @@ -91,19 +94,19 @@ h1 {
color: #ffffff;
}
.CheckoutCounter > Button {
border-radius: 0px;
border-radius: 0;
}

#Checkout-Complete {
border-radius: 0px;
border-radius: 0;
}

.Scrollbar {
background: var(--shadow);
}
.ScrollbarThumb {
background: var(--element-border);
border-radius: 0px;
border-radius: 0;
}

/* Search */
Expand All @@ -112,7 +115,7 @@ h1 {
color: #ffffff;
border: 4px solid #ffffff;
background-color: #000000;
border-radius: 0px;
border-radius: 0;
box-shadow: 0 2px 18px var(--shadow);
}
#main-search:focus {
Expand All @@ -125,7 +128,7 @@ h1 {

.CheckBox {
background-color: var(--shadow);
border-radius: 0px;
border-radius: 0;
box-shadow: none;
border: 2px solid var(--shadow);
}
Expand All @@ -138,6 +141,10 @@ h1 {
box-shadow: none;
}

.ItemGroup > h2{
color: #ffffff;
}

/*
Tabs
*/
Expand All @@ -155,13 +162,13 @@ Tabs
color: #ffffff;
}
.TabsTrigger:first-child {
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 4px solid #000000;
}
.TabsTrigger:last-child {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: 4px solid #000000;
}

Expand Down Expand Up @@ -206,7 +213,7 @@ a.Button:visited {
background-repeat: no-repeat;
color: #ffffff;
border: none;
border-radius: 0px;
border-radius: 0;
}
.Button:hover {
background-image: url(../img/mc/settings-button-hovered.png);
Expand Down Expand Up @@ -236,7 +243,7 @@ a.Button:visited {
color: #ffffff;
border: 4px solid rgba(0, 0, 0, 0);
box-shadow: none;
border-radius: 0px;
border-radius: 0;
}
.PageButton:hover {
background-image: url(../img/mc/settings-button-square-hovered.png);
Expand All @@ -251,7 +258,7 @@ a.Button:visited {
/* Table */

.Table {
border-radius: 0px;
border-radius: 0;
border-collapse: collapse;

color: #ffffff;
Expand All @@ -277,22 +284,22 @@ Switch
box-shadow: 0 2px 10px var(--shadow);
-webkit-tap-highlight-color: var(--shadow);
border: 4 solid var(--primary);
border-radius: 0px;
border-radius: 0;
}
.SwitchRoot[data-state="checked"] {
background-color: #ffffff;
border-radius: 0px;
border-radius: 0;
}
.SwitchThumb {
background-color: var(--element-bg);
border-radius: 0px;
border-radius: 0;
}

/*
Progress
*/
.progress-bar {
border-radius: 0px;
border-radius: 0;
}

.progress-bar-background {
Expand Down
Loading
Loading