diff --git a/src/main/java/com/harmlessprince/ecommerceApi/Utils.java b/src/main/java/com/harmlessprince/ecommerceApi/Utils.java index 5155652..c811a1a 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/Utils.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/Utils.java @@ -4,6 +4,7 @@ import com.harmlessprince.ecommerceApi.custom.AllowedKey; import com.harmlessprince.ecommerceApi.exceptions.CustomBadRequestException; import com.harmlessprince.ecommerceApi.user.User; +import com.harmlessprince.ecommerceApi.user.UserService; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; @@ -76,19 +77,18 @@ public static Sort.Direction getSortDirectionFiled(String input) { public static Query getTenantAwareQuery() { Query query = new Query(); - - User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - if (user != null && TenantContext.getCurrentTenant() != null) { - query.addCriteria(Criteria.where("tenant_id").is(TenantContext.getCurrentTenant())); - } - return query; + return getTenantAwareQuery(query); } public static Query getTenantAwareQuery(Criteria criteria) { Query query = new Query(criteria); - User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - if (user != null && TenantContext.getCurrentTenant() != null) { - query.addCriteria(Criteria.where("tenantId").is(TenantContext.getCurrentTenantID())); + return getTenantAwareQuery(query); + } + + public static Query getTenantAwareQuery(Query query) { + if (TenantContext.getCurrentTenant() == null) { + throw new CustomBadRequestException("Tenant not set"); } + query.addCriteria(Criteria.where("tenantId").is(TenantContext.getCurrentTenantID())); return query; } } diff --git a/src/main/java/com/harmlessprince/ecommerceApi/configs/JwtAuthenticationFilter.java b/src/main/java/com/harmlessprince/ecommerceApi/configs/JwtAuthenticationFilter.java index 54b007d..4be5c7c 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/configs/JwtAuthenticationFilter.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/configs/JwtAuthenticationFilter.java @@ -1,6 +1,7 @@ package com.harmlessprince.ecommerceApi.configs; import com.harmlessprince.ecommerceApi.jwt.JwtService; +import com.harmlessprince.ecommerceApi.tenant.TenantService; import com.harmlessprince.ecommerceApi.user.User; import com.harmlessprince.ecommerceApi.user.UserService; import com.harmlessprince.ecommerceApi.custom.AppConstants; @@ -33,13 +34,15 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtService jwtService; private final UserDetailsService userDetailsService; private final UserService userService; + private final TenantService tenantService; - JwtAuthenticationFilter(HandlerExceptionResolver handlerExceptionResolver, JwtService jwtService, UserDetailsService userDetailsService, UserService userService) { + JwtAuthenticationFilter(HandlerExceptionResolver handlerExceptionResolver, JwtService jwtService, UserDetailsService userDetailsService, UserService userService, TenantService tenantService) { this.handlerExceptionResolver = handlerExceptionResolver; this.jwtService = jwtService; this.userDetailsService = userDetailsService; this.userService = userService; + this.tenantService = tenantService; } @@ -66,11 +69,9 @@ protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull Ht Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null && userId != null) { User userDetails = userService.findById(userId); - request.setAttribute(AppConstants.CURRENT_USER_TENANT_ID, tenantId); request.setAttribute(AppConstants.CURRENT_USER_TENANT_CODE, tenantCode); request.setAttribute(AppConstants.CURRENT_USER_ROLE_NAME, role); - Collection userAuthorities = userService.getAuthorities(userDetails.getRole()); if (jwtService.isTokenValid(token, userDetails)) { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userAuthorities); diff --git a/src/main/java/com/harmlessprince/ecommerceApi/custom/AppConstants.java b/src/main/java/com/harmlessprince/ecommerceApi/custom/AppConstants.java index af7bd1b..027baed 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/custom/AppConstants.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/custom/AppConstants.java @@ -16,6 +16,7 @@ public class AppConstants { //PREFIX public static final String TENANT_PREFIX = "tao_commerce_tenant_:"; + public static final String TENANT_ID_PREFIX = "tao_commerce_tenant_id:"; //Session diff --git a/src/main/java/com/harmlessprince/ecommerceApi/interceptors/TenantInterceptor.java b/src/main/java/com/harmlessprince/ecommerceApi/interceptors/TenantInterceptor.java index 5564ee3..10b282c 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/interceptors/TenantInterceptor.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/interceptors/TenantInterceptor.java @@ -37,16 +37,22 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons } String currentUserRole = (String) request.getAttribute(AppConstants.CURRENT_USER_ROLE_NAME); - String finalTenantId = tenantResolver.resolveTenantIdentifier(request); + String tenantCode = tenantResolver.resolveTenantIdentifier(request); - if (!StringUtils.hasText(finalTenantId) && !Objects.equals(currentUserRole, AppConstants.SUPER_ADMIN)) { + if (!StringUtils.hasText(tenantCode) && !Objects.equals(currentUserRole, AppConstants.SUPER_ADMIN)) { throw new CustomBadRequestException("Tenant ID is missing from headers"); } - tenantService.validateTenantId(finalTenantId); - TenantContext.setCurrentTenant(finalTenantId); - TenantContext.setCurrentTenantId(request.getAttribute(AppConstants.CURRENT_USER_TENANT_ID).toString()); - MDC.put("tenantId", finalTenantId); + tenantService.validateTenantId(tenantCode); + TenantContext.setCurrentTenant(tenantCode); + Object currentTenantId = request.getAttribute(AppConstants.CURRENT_USER_TENANT_ID); + if (currentTenantId != null) { + TenantContext.setCurrentTenantId(currentTenantId.toString()); + }else{ + String tenantId = tenantService.getTenantIdByCode(tenantCode); + TenantContext.setCurrentTenantId(tenantId); + } + MDC.put("tenantId", tenantCode); return true; } diff --git a/src/main/java/com/harmlessprince/ecommerceApi/product/CustomProductRepositoryImpl.java b/src/main/java/com/harmlessprince/ecommerceApi/product/CustomProductRepositoryImpl.java index c782c6e..6737199 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/product/CustomProductRepositoryImpl.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/product/CustomProductRepositoryImpl.java @@ -1,5 +1,6 @@ package com.harmlessprince.ecommerceApi.product; +import com.harmlessprince.ecommerceApi.Utils; import com.harmlessprince.ecommerceApi.review.RatingAggregationResult; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,8 +21,8 @@ public class CustomProductRepositoryImpl implements CustomProductRepository { @Override public List findSimilarProductsByCategory(String category, int limit) { - Query query = new Query(); - query.addCriteria(Criteria.where("category").is(category)); + Criteria criteria = Criteria.where("category").is(category); + Query query = Utils.getTenantAwareQuery(criteria); query.limit(limit); return mongoTemplate.find(query, Product.class); } diff --git a/src/main/java/com/harmlessprince/ecommerceApi/product/ProductController.java b/src/main/java/com/harmlessprince/ecommerceApi/product/ProductController.java index fb316e2..b633df1 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/product/ProductController.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/product/ProductController.java @@ -116,7 +116,7 @@ public ResponseEntity> updateProduct( public ResponseEntity> showProduct( @PathVariable String productId ) { - Product product = productService.findById(productId); + Product product = productService.findByIdAndTenantId(productId, TenantContext.getCurrentTenantID()); return ResponseEntity.ok(new CustomSuccessResponse<>(productMapper.fromEntity(product), "Product retrieved")); } @@ -125,7 +125,7 @@ public ResponseEntity>> getSimilarPr @PathVariable String productId, @RequestParam(defaultValue = "4") int limit ) { - Product product = productService.findById(productId); + Product product = productService.findByIdAndTenantId(productId, TenantContext.getCurrentTenantID()); List products = productService.findAllSimilarProducts(product, limit); List productResponse = productMapper.fromEntityList(products); return ResponseEntity.ok(new CustomSuccessResponse<>(productResponse, "Product retrieved")); diff --git a/src/main/java/com/harmlessprince/ecommerceApi/product/ProductRepository.java b/src/main/java/com/harmlessprince/ecommerceApi/product/ProductRepository.java index 8cda231..87a57c9 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/product/ProductRepository.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/product/ProductRepository.java @@ -19,4 +19,5 @@ public interface ProductRepository extends MongoRepository, Cus Optional findFirstByNameAndTenantId(String slug, String tenantId); Boolean existsBySlugAndBrand(String name, String brand); + Optional findFirstByIdAndTenantId(String id, String tenantId); } \ No newline at end of file diff --git a/src/main/java/com/harmlessprince/ecommerceApi/product/ProductService.java b/src/main/java/com/harmlessprince/ecommerceApi/product/ProductService.java index 1865c10..c9eda86 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/product/ProductService.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/product/ProductService.java @@ -31,6 +31,10 @@ public Product findById(String id) { return productRepository.findById(id).orElseThrow(() -> new CustomResourceNotFoundException("Product not found")); } + public Product findByIdAndTenantId(String id, String tenantId) { + return productRepository.findFirstByIdAndTenantId(id, tenantId).orElseThrow(() -> new CustomResourceNotFoundException("Product not found")); + } + public Product findByName(String name) { return productRepository.findByName(name).orElseThrow(() -> new CustomResourceNotFoundException("Product not found")); } diff --git a/src/main/java/com/harmlessprince/ecommerceApi/tenant/TenantService.java b/src/main/java/com/harmlessprince/ecommerceApi/tenant/TenantService.java index ff25913..5855776 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/tenant/TenantService.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/tenant/TenantService.java @@ -48,14 +48,25 @@ public Optional findByUser(User user) { public void validateTenantId(String value) { String key = AppConstants.TENANT_PREFIX + value; - String tenantId = valueOperations.get(key); + String tenantCode = valueOperations.get(key); log.debug("Tenant id is {}", value); - if (!StringUtils.hasText(tenantId)) { + if (!StringUtils.hasText(tenantCode)) { this.tenantRepository.findFirstByCode(value).orElseThrow(() -> new CustomBadRequestException("Invalid tenant id")); valueOperations.set(key, value, 12, TimeUnit.HOURS); } } + public String getTenantIdByCode(String code) { + String key = AppConstants.TENANT_ID_PREFIX + code; + String tenantId = valueOperations.get(key); + if (!StringUtils.hasText(tenantId)) { + Tenant tenant = this.tenantRepository.findFirstByCode(code).orElseThrow(() -> new CustomBadRequestException("Invalid tenant id")); + tenantId = tenant.getId(); + valueOperations.set(key, tenant.getId(), 12, TimeUnit.HOURS); + } + return tenantId; + } + public String generateTenantId(String name) { // Normalize name to remove special characters and convert to lowercase diff --git a/src/main/java/com/harmlessprince/ecommerceApi/user/UserService.java b/src/main/java/com/harmlessprince/ecommerceApi/user/UserService.java index 854d8e4..b7d42c9 100644 --- a/src/main/java/com/harmlessprince/ecommerceApi/user/UserService.java +++ b/src/main/java/com/harmlessprince/ecommerceApi/user/UserService.java @@ -4,6 +4,7 @@ import com.harmlessprince.ecommerceApi.permission.Permission; import com.harmlessprince.ecommerceApi.role.Role; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; @@ -16,6 +17,7 @@ import java.util.*; import java.util.stream.Collectors; +@Slf4j @Service @AllArgsConstructor public class UserService { @@ -47,18 +49,20 @@ public User findById(String id) { public static User getAuthenticatedUser() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - return (User) authentication.getPrincipal(); + if (authentication.getPrincipal() instanceof User) { + return (User) authentication.getPrincipal(); + } + return null; } public Collection getAuthorities(Role role) { Set authorities = new HashSet<>(); // Query to fetch the role along with its permissions Query roleQuery = new Query(); - if(role == null) { + if (role == null) { return authorities; } roleQuery.addCriteria(Criteria.where("id").is(role.getId())); - // Assuming Role has a field "permissions" (embedded or referenced) Role fetchedRole = mongoTemplate.findOne(roleQuery, Role.class); if (fetchedRole == null) { @@ -68,7 +72,6 @@ public Collection getAuthorities(Role role) { String userRole = fetchedRole.getSlug(); - // Construct the authorities authorities.add(new SimpleGrantedAuthority(userRole));