User suspension added

This commit is contained in:
Sidharth Prabhu
2026-04-21 14:37:34 +05:30
parent 21c581b7eb
commit b4bf6ebeb3
13 changed files with 301 additions and 24 deletions

View File

@@ -14,7 +14,7 @@ public class WebConfig {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedOriginPatterns("http://*", "https://*", "file://*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);

View File

@@ -138,4 +138,18 @@ public class UserController {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
/**
* Toggle user suspension status.
* PATCH /api/auth/users/{id}/suspend
*/
@PatchMapping("/users/{id}/suspend")
public ResponseEntity<LoginResponse.UserDto> toggleSuspension(@PathVariable Long id) {
LoginResponse.UserDto updated = userService.toggleSuspension(id);
if (updated != null) {
return ResponseEntity.ok(updated);
} else {
return ResponseEntity.notFound().build();
}
}
}

View File

@@ -8,10 +8,11 @@ public class DashboardStats {
private double growth;
private long totalExpenses;
private long periodExpenses;
private long suspendedUserCount;
public DashboardStats() {}
public DashboardStats(long totalSales, long periodRevenue, int activeOrders, int dailyCustomers, double growth, long totalExpenses, long periodExpenses) {
public DashboardStats(long totalSales, long periodRevenue, int activeOrders, int dailyCustomers, double growth, long totalExpenses, long periodExpenses, long suspendedUserCount) {
this.totalSales = totalSales;
this.periodRevenue = periodRevenue;
this.activeOrders = activeOrders;
@@ -19,6 +20,7 @@ public class DashboardStats {
this.growth = growth;
this.totalExpenses = totalExpenses;
this.periodExpenses = periodExpenses;
this.suspendedUserCount = suspendedUserCount;
}
public long getTotalSales() { return totalSales; }
@@ -41,4 +43,7 @@ public class DashboardStats {
public long getPeriodExpenses() { return periodExpenses; }
public void setPeriodExpenses(long periodExpenses) { this.periodExpenses = periodExpenses; }
public long getSuspendedUserCount() { return suspendedUserCount; }
public void setSuspendedUserCount(long suspendedUserCount) { this.suspendedUserCount = suspendedUserCount; }
}

View File

@@ -43,15 +43,17 @@ public class LoginResponse {
private String mobileNumber;
private String name;
private boolean isLoggedIn;
private boolean isSuspended;
private java.math.BigDecimal ritzTokenBalance;
public UserDto() {}
public UserDto(Long id, String mobileNumber, String name, boolean isLoggedIn, java.math.BigDecimal ritzTokenBalance) {
public UserDto(Long id, String mobileNumber, String name, boolean isLoggedIn, boolean isSuspended, java.math.BigDecimal ritzTokenBalance) {
this.id = id;
this.mobileNumber = mobileNumber;
this.name = name;
this.isLoggedIn = isLoggedIn;
this.isSuspended = isSuspended;
this.ritzTokenBalance = ritzTokenBalance;
}
@@ -67,6 +69,9 @@ public class LoginResponse {
public boolean isLoggedIn() { return isLoggedIn; }
public void setLoggedIn(boolean loggedIn) { this.isLoggedIn = loggedIn; }
public boolean isSuspended() { return isSuspended; }
public void setSuspended(boolean suspended) { isSuspended = suspended; }
public java.math.BigDecimal getRitzTokenBalance() { return ritzTokenBalance; }
public void setRitzTokenBalance(java.math.BigDecimal ritzTokenBalance) { this.ritzTokenBalance = ritzTokenBalance; }
}

View File

@@ -37,6 +37,9 @@ public class User {
@Column(nullable = false)
private java.math.BigDecimal ritzTokenBalance = java.math.BigDecimal.ZERO;
@Column(nullable = false, columnDefinition = "boolean default false")
private boolean isSuspended = false;
@Column(nullable = true)
private LocalDateTime lastLoginAt;
@@ -54,6 +57,9 @@ public class User {
public java.math.BigDecimal getRitzTokenBalance() { return ritzTokenBalance; }
public void setRitzTokenBalance(java.math.BigDecimal ritzTokenBalance) { this.ritzTokenBalance = ritzTokenBalance; }
public boolean isSuspended() { return isSuspended; }
public void setSuspended(boolean suspended) { isSuspended = suspended; }
public String getPinHash() { return pinHash; }
public void setPinHash(String pinHash) { this.pinHash = pinHash; }

View File

@@ -19,4 +19,6 @@ public interface UserRepository extends JpaRepository<User, Long> {
@org.springframework.data.jpa.repository.Lock(jakarta.persistence.LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT u FROM User u WHERE u.id = :id")
Optional<User> findByIdWithLock(@org.springframework.data.repository.query.Param("id") Long id);
long countByIsSuspended(boolean isSuspended);
}

View File

@@ -61,7 +61,7 @@ public class UserService {
userRepository.save(user);
LoginResponse.UserDto userDto = new LoginResponse.UserDto(
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.getRitzTokenBalance()
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance()
);
return new LoginResponse(true, "Registration successful. You are now logged in.", userDto);
@@ -79,6 +79,10 @@ public class UserService {
User user = userOpt.get();
if (user.isSuspended()) {
return new LoginResponse(false, "Your account has been suspended. Please contact the administrator.");
}
if (!passwordEncoder.matches(pin, user.getPinHash())) {
return new LoginResponse(false, "Incorrect PIN. Please try again.");
}
@@ -88,7 +92,7 @@ public class UserService {
userRepository.save(user);
LoginResponse.UserDto userDto = new LoginResponse.UserDto(
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.getRitzTokenBalance()
user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance()
);
return new LoginResponse(true, "Login successful.", userDto);
@@ -154,7 +158,7 @@ public class UserService {
return null;
}
User user = userOpt.get();
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.getRitzTokenBalance());
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance());
}
/**
@@ -173,6 +177,7 @@ public class UserService {
user.getMobileNumber(),
user.getName(),
user.isLoggedIn(),
user.isSuspended(),
user.getRitzTokenBalance()
));
}
@@ -212,7 +217,28 @@ public class UserService {
}
userRepository.save(user);
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.getRitzTokenBalance());
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance());
}
/**
* Toggle the suspension status of a user.
*/
public LoginResponse.UserDto toggleSuspension(Long userId) {
Optional<User> userOpt = userRepository.findById(userId);
if (userOpt.isEmpty()) {
return null;
}
User user = userOpt.get();
user.setSuspended(!user.isSuspended());
// If suspended, forcefully log them out
if (user.isSuspended()) {
user.setLoggedIn(false);
}
userRepository.save(user);
return new LoginResponse.UserDto(user.getId(), user.getMobileNumber(), user.getName(), user.isLoggedIn(), user.isSuspended(), user.getRitzTokenBalance());
}
/**