Merge branch 'AttachmentsToChat'
This commit is contained in:
@@ -17,9 +17,9 @@ import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 20)
|
||||
public class ActivityLoggingFilter extends OncePerRequestFilter {
|
||||
@Component
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 20)
|
||||
public class ActivityLoggingFilter extends OncePerRequestFilter {
|
||||
|
||||
private final ActivityLogService activityLogService;
|
||||
|
||||
@@ -30,13 +30,8 @@ import java.io.IOException;
|
||||
@Override
|
||||
protected boolean shouldNotFilter(HttpServletRequest request) {
|
||||
String uri = request.getRequestURI();
|
||||
if (uri == null || uri.isBlank()) {
|
||||
return true;
|
||||
}
|
||||
if (!uri.startsWith("/api/")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uri == null || uri.isBlank()) return true;
|
||||
if (!uri.startsWith("/api/")) return true;
|
||||
String lower = uri.toLowerCase(java.util.Locale.ROOT);
|
||||
return lower.startsWith("/api/v1/health")
|
||||
|| lower.startsWith("/api/v1/activity-logs")
|
||||
@@ -46,16 +41,15 @@ import java.io.IOException;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
filterChain.doFilter(request, response);
|
||||
recordActivity(request, response);
|
||||
}
|
||||
|
||||
private void recordActivity(HttpServletRequest request, HttpServletResponse response) {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null || !authentication.isAuthenticated()) {
|
||||
return;
|
||||
}
|
||||
if (authentication == null || !authentication.isAuthenticated()) return;
|
||||
|
||||
Long userId = null;
|
||||
User.Role role = null;
|
||||
@@ -69,11 +63,136 @@ import java.io.IOException;
|
||||
role = appPrincipal.getRole();
|
||||
}
|
||||
|
||||
if (userId == null || role == null || role == User.Role.CUSTOMER) {
|
||||
return;
|
||||
}
|
||||
if (userId == null || role == null) return;
|
||||
if ("GET".equalsIgnoreCase(request.getMethod())) return;
|
||||
|
||||
String method = request.getMethod();
|
||||
String uri = request.getRequestURI();
|
||||
int status = response.getStatus();
|
||||
|
||||
String technical = method + " " + uri + " → " + status;
|
||||
String description = describe(method, uri, status);
|
||||
String activity = description != null ? description + " | " + technical : technical;
|
||||
|
||||
String activity = String.format("%s %s -> %d", request.getMethod(), request.getRequestURI(), response.getStatus());
|
||||
activityLogService.record(userId, activity);
|
||||
}
|
||||
|
||||
private String describe(String method, String rawUri, int status) {
|
||||
String uri = rawUri.contains("?") ? rawUri.substring(0, rawUri.indexOf('?')) : rawUri;
|
||||
String[] parts = uri.replaceFirst("^/+", "").split("/");
|
||||
if (parts.length < 3) return null;
|
||||
|
||||
String r = parts[2];
|
||||
String seg3 = parts.length > 3 ? parts[3] : null;
|
||||
String seg4 = parts.length > 4 ? parts[4] : null;
|
||||
String seg5 = parts.length > 5 ? parts[5] : null;
|
||||
|
||||
boolean seg3IsId = seg3 != null && seg3.matches("\\d+");
|
||||
boolean seg4IsId = seg4 != null && seg4.matches("\\d+");
|
||||
String id = seg3IsId ? seg3 : null;
|
||||
String sub = seg3IsId ? seg4 : seg3;
|
||||
String subsub = seg3IsId ? seg5 : seg4;
|
||||
|
||||
boolean isGet = "GET".equalsIgnoreCase(method);
|
||||
boolean isPost = "POST".equalsIgnoreCase(method);
|
||||
boolean isPut = "PUT".equalsIgnoreCase(method);
|
||||
boolean isPatch = "PATCH".equalsIgnoreCase(method);
|
||||
boolean isDelete = "DELETE".equalsIgnoreCase(method);
|
||||
boolean failed = status >= 400;
|
||||
|
||||
switch (r) {
|
||||
case "auth" -> {
|
||||
if ("login".equals(seg3) && isPost) return failed ? "Failed login attempt" : "Logged in";
|
||||
if ("logout".equals(seg3) && isPost) return "Logged out";
|
||||
if ("register".equals(seg3) && isPost) return failed ? "Failed registration attempt" : "Registered a new account";
|
||||
if ("forgot-password".equals(seg3) && isPost) return "Requested a password reset";
|
||||
if ("reset-password".equals(seg3) && isPost) return "Reset their password";
|
||||
if ("me".equals(seg3) && isPut) return "Updated their profile";
|
||||
if ("me".equals(seg3) && "avatar".equals(sub) && isPost) return "Uploaded a profile picture";
|
||||
if ("me".equals(seg3) && "avatar".equals(sub) && isDelete) return "Removed their profile picture";
|
||||
}
|
||||
case "cart" -> {
|
||||
if ("add".equals(seg3) && isPost) return "Added an item to cart";
|
||||
if ("update".equals(seg3) && isPut) return "Updated a cart item";
|
||||
if ("remove".equals(seg3) && isDelete) return "Removed an item from cart";
|
||||
if ("clear".equals(seg3) && isDelete) return "Cleared their cart";
|
||||
if ("apply-coupon".equals(seg3) && isPost) return "Applied a coupon to cart";
|
||||
if ("checkout".equals(seg3)) {
|
||||
if ("complete".equals(seg4) && isPost) return "Completed a purchase";
|
||||
if ("cancel".equals(seg4) && isPost) return "Cancelled checkout";
|
||||
if (isPost) return "Started checkout";
|
||||
}
|
||||
}
|
||||
case "chat" -> {
|
||||
if ("conversations".equals(seg3) && isPost && seg4 == null) return "Started a new chat conversation";
|
||||
if ("conversations".equals(seg3) && seg4IsId) {
|
||||
String convId = seg4;
|
||||
String chatSub = parts.length > 5 ? parts[5] : null;
|
||||
if ("messages".equals(seg5) && isPost) return "Sent a chat message";
|
||||
if ("attachments".equals(seg5) && isPost) return "Sent a file in chat";
|
||||
if ("request-human".equals(seg5) && isPost) return "Requested human support in chat";
|
||||
if (chatSub == null && isPut) return "Updated chat conversation #" + convId;
|
||||
}
|
||||
}
|
||||
case "ai-chat" -> {
|
||||
if ("message".equals(seg3) && isPost) return "Sent a message to the AI assistant";
|
||||
}
|
||||
case "product-suppliers" -> {
|
||||
if (isPost && seg3 == null) return "Linked a product to a supplier";
|
||||
if (seg3IsId && seg4IsId && isPut) return "Updated product-supplier link";
|
||||
if (seg3IsId && seg4IsId && isDelete) return "Removed product-supplier link";
|
||||
if (isDelete && !seg3IsId) return "Removed multiple product-supplier links";
|
||||
}
|
||||
}
|
||||
|
||||
String label = resourceLabel(r);
|
||||
if (label == null) return null;
|
||||
|
||||
if ("image".equals(sub) && id != null) {
|
||||
if (isPost) return "Uploaded image for " + label + " #" + id;
|
||||
if (isDelete) return "Removed image from " + label + " #" + id;
|
||||
}
|
||||
|
||||
if ("cancel".equals(sub) && id != null && isPatch) return "Cancelled " + label + " #" + id;
|
||||
|
||||
if (isPost && id == null) {
|
||||
if ("request".equals(seg3)) return "Submitted an adoption request";
|
||||
if ("bulk-delete".equals(seg3)) return "Deleted multiple " + plural(label);
|
||||
return "Created a new " + label;
|
||||
}
|
||||
if ((isPut || isPatch) && id != null && sub == null) return "Updated " + label + " #" + id;
|
||||
if (isDelete && id != null && sub == null) return "Deleted " + label + " #" + id;
|
||||
if (isDelete && id == null) return "Deleted multiple " + plural(label);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resourceLabel(String resource) {
|
||||
return switch (resource) {
|
||||
case "products" -> "product";
|
||||
case "categories" -> "category";
|
||||
case "customers" -> "customer";
|
||||
case "employees" -> "employee";
|
||||
case "users" -> "user";
|
||||
case "pets" -> "pet";
|
||||
case "my-pets" -> "pet";
|
||||
case "appointments" -> "appointment";
|
||||
case "adoptions" -> "adoption";
|
||||
case "sales" -> "sale";
|
||||
case "refunds" -> "refund";
|
||||
case "inventory" -> "inventory record";
|
||||
case "services" -> "service";
|
||||
case "suppliers" -> "supplier";
|
||||
case "purchase-orders" -> "purchase order";
|
||||
case "coupons" -> "coupon";
|
||||
case "stores" -> "store";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private String plural(String label) {
|
||||
if (label.endsWith("y")) return label.substring(0, label.length() - 1) + "ies";
|
||||
if (label.endsWith("s")) return label + "es";
|
||||
return label + "s";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class AuthController {
|
||||
|
||||
String token = jwtUtil.generateToken(user);
|
||||
if (user.getRole() != User.Role.CUSTOMER) {
|
||||
activityLogService.record(user.getId(), "POST /api/v1/auth/login -> 200");
|
||||
activityLogService.record(user.getId(), "Logged in | POST /api/v1/auth/login → 200");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(new LoginResponse(
|
||||
|
||||
@@ -158,10 +158,10 @@ public class EmailService {
|
||||
.html(html)
|
||||
.build();
|
||||
resend.emails().send(options);
|
||||
activityLogService.record(recipientUserId, "Email sent: " + subject + " → " + to);
|
||||
activityLogService.record(recipientUserId, "Sent an email | Email sent: " + subject + " → " + to);
|
||||
} catch (Exception ex) {
|
||||
log.error("Failed to send email '{}' to {}: {}", subject, to, ex.getMessage());
|
||||
activityLogService.record(recipientUserId, "Email failed: " + subject + " → " + to);
|
||||
activityLogService.record(recipientUserId, "Failed to send email | Email failed: " + subject + " → " + to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user