Skip to content
Extraits de code Groupes Projets
Valider 46fa6376 rédigé par anas.roukny's avatar anas.roukny
Parcourir les fichiers

implement CRUD operations for Sessions & ActivityHistory

parent 0d64aabd
Branches
1 requête de fusion!6MLC-251/implement CRUD operations for Sessions & ActivityHistory
Affichage de
avec 485 ajouts et 1 suppression
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.marketingconfort</groupId>
......
......@@ -16,4 +16,15 @@ public class Message {
public static final String PASSWORD_TOO_SHORT = "Le mot de passe doit contenir au moins 8 caractères.";
public static final String USER_NOT_FOUND = "User not found with ID: ";
public static final String ACTIVITY_ACTION_EMPTY = "Activity action cannot be empty";
public static final String USER_ID_NULL = "User ID cannot be null";
public static final String LIMIT_INVALID = "Limit must be greater than 0";
public static final String SESSION_DEVICE_EMPTY = "Session device cannot be empty";
public static final String SESSION_BROWSER_EMPTY = "Session browser cannot be empty";
public static final String SESSION_ID_NULL = "Session ID cannot be null";
public static final String SESSION_NOT_FOUND = "Session not found with ID: ";
public static final String SESSION_NO_CURRENT_SESSION = "No current session found for user ID: ";
}
\ No newline at end of file
......@@ -30,4 +30,15 @@ public class Paths {
public static final String AGENCY_EXISTS = "/exists/{agencyId}";
public static final String SESSION_URL = "/api/sessions";
public static final String SESSION_BY_USER_ID = "/user/{userId}";
public static final String SESSION_CURRENT_BY_USER_ID = "/user/{userId}/current";
public static final String SESSION_INVALIDATE_BY_ID = "/{sessionId}/invalidate";
public static final String ACTIVITY_URL = "/api/activities";
public static final String ACTIVITY_BY_USER_ID = "/user/{userId}";
public static final String RECENT_ACTIVITY = "recent";
}
package com.marketingconfort.mobiloca.controller;
import com.marketingconfort.mobiloca.common.User.models.ActivityHistory;
import com.marketingconfort.mobiloca.common.User.models.User;
import com.marketingconfort.mobiloca.dto.ActivityHistoryDTO;
import com.marketingconfort.mobiloca.mapper.ActivityHistoryMapper;
import com.marketingconfort.mobiloca.repository.UserRepository;
import com.marketingconfort.mobiloca.service.ActivityHistoryService;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.marketingconfort.mobiloca.constants.Paths;
import java.util.List;
@RestController
@RequestMapping(Paths.ACTIVITY_URL)
@RequiredArgsConstructor
public class ActivityHistoryController {
private final ActivityHistoryService activityHistoryService;
@PostMapping
public ResponseEntity<ActivityHistoryDTO> logActivity(@RequestBody ActivityHistoryDTO activityHistoryDTO) throws FunctionalException {
ActivityHistoryDTO logged = activityHistoryService.logActivity(activityHistoryDTO);
return ResponseEntity.status(HttpStatus.CREATED).body(logged);
}
@GetMapping(Paths.ACTIVITY_BY_USER_ID)
public ResponseEntity<List<ActivityHistoryDTO>> getActivitiesByUserId(@PathVariable Long userId) throws FunctionalException {
List<ActivityHistoryDTO> activities = activityHistoryService.getActivitiesByUserId(userId);
return ResponseEntity.ok(activities);
}
@GetMapping(Paths.RECENT_ACTIVITY)
public ResponseEntity<List<ActivityHistoryDTO>> getRecentActivities(@RequestParam(defaultValue = "10") int limit) throws FunctionalException {
List<ActivityHistoryDTO> activities = activityHistoryService.getRecentActivities(limit);
return ResponseEntity.ok(activities);
}
}
\ No newline at end of file
package com.marketingconfort.mobiloca.controller;
import com.marketingconfort.mobiloca.dto.SessionDTO;
import com.marketingconfort.mobiloca.service.SessionService;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.marketingconfort.mobiloca.constants.Paths;
import java.util.List;
@RestController
@RequestMapping(Paths.SESSION_URL)
@RequiredArgsConstructor
public class SessionController {
private final SessionService sessionService;
@PostMapping
public ResponseEntity<SessionDTO> createSession(@RequestBody SessionDTO sessionDTO) throws FunctionalException {
SessionDTO created = sessionService.createSession(sessionDTO);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@GetMapping(Paths.SESSION_BY_USER_ID)
public ResponseEntity<List<SessionDTO>> getSessionsByUserId(@PathVariable Long userId) throws FunctionalException {
List<SessionDTO> sessions = sessionService.getSessionsByUserId(userId);
return ResponseEntity.ok(sessions);
}
@GetMapping(Paths.SESSION_CURRENT_BY_USER_ID)
public ResponseEntity<SessionDTO> getCurrentSession(@PathVariable Long userId) throws FunctionalException {
SessionDTO currentSession = sessionService.getCurrentSession(userId);
return ResponseEntity.ok(currentSession);
}
@PostMapping(Paths.SESSION_INVALIDATE_BY_ID)
public ResponseEntity<Void> invalidateSession(@PathVariable Long sessionId) throws FunctionalException {
sessionService.invalidateSession(sessionId);
return ResponseEntity.ok().build();
}
}
\ No newline at end of file
package com.marketingconfort.mobiloca.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ActivityHistoryDTO {
private Long id;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime date;
private String action;
private String details;
private Long userId;
}
\ No newline at end of file
package com.marketingconfort.mobiloca.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.time.LocalDateTime;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class SessionDTO {
private Long id;
private String device;
private String browser;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime lastActive;
@JsonProperty("isCurrent")
private boolean isCurrent;
private Long userId;
}
\ No newline at end of file
package com.marketingconfort.mobiloca.mapper;
import com.marketingconfort.mobiloca.common.User.models.ActivityHistory;
import com.marketingconfort.mobiloca.dto.ActivityHistoryDTO;
import com.marketingconfort.mobiloca.common.User.models.User;
import java.time.LocalDateTime;
public class ActivityHistoryMapper {
public static ActivityHistoryDTO toDTO(ActivityHistory activity) {
ActivityHistoryDTO dto = new ActivityHistoryDTO();
dto.setId(activity.getId());
dto.setDate(activity.getDate());
dto.setAction(activity.getAction());
dto.setDetails(activity.getDetails());
dto.setUserId(activity.getUser().getId());
return dto;
}
public static ActivityHistory toEntity(ActivityHistoryDTO dto, User user) {
ActivityHistory activity = new ActivityHistory();
activity.setId(dto.getId());
activity.setDate(dto.getDate() != null ? dto.getDate() : LocalDateTime.now());
activity.setAction(dto.getAction());
activity.setDetails(dto.getDetails());
activity.setUser(user);
return activity;
}
}
\ No newline at end of file
package com.marketingconfort.mobiloca.mapper;
import com.marketingconfort.mobiloca.common.User.models.Session;
import com.marketingconfort.mobiloca.dto.SessionDTO;
import com.marketingconfort.mobiloca.common.User.models.User;
import java.time.LocalDateTime;
public class SessionMapper {
public static SessionDTO toDTO(Session session) {
if (session == null) {
return null;
}
SessionDTO dto = new SessionDTO();
dto.setId(session.getId());
dto.setDevice(session.getDevice());
dto.setBrowser(session.getBrowser());
dto.setLastActive(session.getLastActive());
dto.setCurrent(session.isCurrent());
if (session.getUser() != null) {
dto.setUserId(session.getUser().getId());
}
return dto;
}
public static Session toEntity(SessionDTO dto, User user) {
if (dto == null) {
return null;
}
Session session = new Session();
session.setId(dto.getId());
session.setDevice(dto.getDevice());
session.setBrowser(dto.getBrowser());
session.setLastActive(dto.getLastActive() != null ? dto.getLastActive() : LocalDateTime.now());
session.setCurrent(dto.isCurrent());
session.setUser(user);
return session;
}
}
\ No newline at end of file
package com.marketingconfort.mobiloca.repository;
import com.marketingconfort.mobiloca.common.User.models.ActivityHistory;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ActivityHistoryRepository extends JpaRepository<ActivityHistory, Long> {
List<ActivityHistory> findByUserId(Long userId);
@Query("SELECT a FROM ActivityHistory a ORDER BY a.date DESC")
List<ActivityHistory> findAllOrderByDateDesc(Pageable pageable); // Added Pageable parameter
@Query("SELECT a FROM ActivityHistory a WHERE a.user.id = :userId ORDER BY a.date DESC")
List<ActivityHistory> findByUserIdOrderByDateDesc(@Param("userId") Long userId);
}
\ No newline at end of file
package com.marketingconfort.mobiloca.repository;
import com.marketingconfort.mobiloca.common.User.models.Session;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface SessionRepository extends JpaRepository<Session, Long> {
List<Session> findByUserId(Long userId);
Optional<Session> findByUserIdAndIsCurrentTrue(Long userId);
}
\ No newline at end of file
package com.marketingconfort.mobiloca.service;
import com.marketingconfort.mobiloca.dto.ActivityHistoryDTO;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import java.util.List;
public interface ActivityHistoryService {
ActivityHistoryDTO logActivity(ActivityHistoryDTO activityHistoryDTO) throws FunctionalException;
List<ActivityHistoryDTO> getActivitiesByUserId(Long userId) throws FunctionalException;
List<ActivityHistoryDTO> getRecentActivities(int limit) throws FunctionalException;
}
\ No newline at end of file
package com.marketingconfort.mobiloca.service;
import com.marketingconfort.mobiloca.dto.SessionDTO;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import java.util.List;
public interface SessionService {
SessionDTO createSession(SessionDTO sessionDTO) throws FunctionalException;
List<SessionDTO> getSessionsByUserId(Long userId) throws FunctionalException;
SessionDTO getCurrentSession(Long userId) throws FunctionalException;
void invalidateSession(Long sessionId) throws FunctionalException;
}
\ No newline at end of file
package com.marketingconfort.mobiloca.service.impl;
import com.marketingconfort.mobiloca.common.User.models.ActivityHistory;
import com.marketingconfort.mobiloca.common.User.models.User;
import com.marketingconfort.mobiloca.dto.ActivityHistoryDTO;
import com.marketingconfort.mobiloca.mapper.ActivityHistoryMapper;
import com.marketingconfort.mobiloca.repository.ActivityHistoryRepository;
import com.marketingconfort.mobiloca.repository.UserRepository;
import com.marketingconfort.mobiloca.service.ActivityHistoryService;
import com.marketingconfort.mobiloca.constants.Message;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ActivityHistoryServiceImpl implements ActivityHistoryService {
private final ActivityHistoryRepository activityHistoryRepository;
private final UserRepository userRepository;
private void validateActivityData(ActivityHistoryDTO dto) throws FunctionalException {
if (dto.getAction() == null || dto.getAction().isBlank()) {
throw new FunctionalException(Message.ACTIVITY_ACTION_EMPTY);
}
if (dto.getUserId() == null) {
throw new FunctionalException(Message.USER_ID_NULL);
}
}
@Override
@Transactional
public ActivityHistoryDTO logActivity(ActivityHistoryDTO activityHistoryDTO) throws FunctionalException {
validateActivityData(activityHistoryDTO);
User user = userRepository.findById(activityHistoryDTO.getUserId())
.orElseThrow(() -> new FunctionalException(Message.USER_NOT_FOUND + activityHistoryDTO.getUserId()));
ActivityHistory activity = ActivityHistoryMapper.toEntity(activityHistoryDTO, user);
if (activity.getDate() == null) {
activity.setDate(LocalDateTime.now());
}
ActivityHistory savedActivity = activityHistoryRepository.save(activity);
return ActivityHistoryMapper.toDTO(savedActivity);
}
@Override
public List<ActivityHistoryDTO> getActivitiesByUserId(Long userId) throws FunctionalException {
if (userId == null) {
throw new FunctionalException(Message.USER_ID_NULL);
}
// Check if user exists
userRepository.findById(userId)
.orElseThrow(() -> new FunctionalException(Message.USER_NOT_FOUND + userId));
List<ActivityHistory> activities = activityHistoryRepository.findByUserIdOrderByDateDesc(userId);
return activities.stream()
.map(ActivityHistoryMapper::toDTO)
.toList();
}
@Override
public List<ActivityHistoryDTO> getRecentActivities(int limit) throws FunctionalException {
if (limit <= 0) {
throw new FunctionalException(Message.LIMIT_INVALID);
}
Pageable pageable = PageRequest.of(0, limit);
List<ActivityHistory> activities = activityHistoryRepository.findAllOrderByDateDesc(pageable);
return activities.stream()
.map(ActivityHistoryMapper::toDTO)
.toList();
}
}
\ No newline at end of file
package com.marketingconfort.mobiloca.service.impl;
import com.marketingconfort.mobiloca.common.User.models.Session;
import com.marketingconfort.mobiloca.common.User.models.User;
import com.marketingconfort.mobiloca.dto.SessionDTO;
import com.marketingconfort.mobiloca.mapper.SessionMapper;
import com.marketingconfort.mobiloca.repository.SessionRepository;
import com.marketingconfort.mobiloca.repository.UserRepository;
import com.marketingconfort.mobiloca.service.SessionService;
import com.marketingconfort.mobiloca.constants.Message;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import org.springframework.transaction.annotation.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
@Service
@RequiredArgsConstructor
public class SessionServiceImpl implements SessionService {
private final SessionRepository sessionRepository;
private final UserRepository userRepository;
private void validateSessionData(SessionDTO dto) throws FunctionalException {
if (dto.getUserId() == null) {
throw new FunctionalException(Message.USER_ID_NULL);
}
if (dto.getDevice() == null || dto.getDevice().isBlank()) {
throw new FunctionalException(Message.SESSION_DEVICE_EMPTY);
}
if (dto.getBrowser() == null || dto.getBrowser().isBlank()) {
throw new FunctionalException(Message.SESSION_BROWSER_EMPTY);
}
}
@Override
@Transactional
public SessionDTO createSession(SessionDTO sessionDTO) throws FunctionalException {
validateSessionData(sessionDTO);
User user = userRepository.findById(sessionDTO.getUserId())
.orElseThrow(() -> new FunctionalException(Message.USER_NOT_FOUND + sessionDTO.getUserId()));
Session session = SessionMapper.toEntity(sessionDTO, user);
session.setLastActive(LocalDateTime.now());
session.setCurrent(true);
// Invalidate any existing current session for this user
sessionRepository.findByUserIdAndIsCurrentTrue(user.getId())
.ifPresent(existingSession -> {
existingSession.setCurrent(false);
sessionRepository.save(existingSession);
});
Session savedSession = sessionRepository.save(session);
return SessionMapper.toDTO(savedSession);
}
@Override
public List<SessionDTO> getSessionsByUserId(Long userId) throws FunctionalException {
if (userId == null) {
throw new FunctionalException(Message.USER_ID_NULL);
}
// Check if user exists
userRepository.findById(userId)
.orElseThrow(() -> new FunctionalException(Message.USER_NOT_FOUND + userId));
List<Session> sessions = sessionRepository.findByUserId(userId);
return sessions.stream()
.map(SessionMapper::toDTO)
.toList();
}
@Override
public SessionDTO getCurrentSession(Long userId) throws FunctionalException {
if (userId == null) {
throw new FunctionalException(Message.USER_ID_NULL);
}
// Check if user exists
userRepository.findById(userId)
.orElseThrow(() -> new FunctionalException(Message.USER_NOT_FOUND + userId));
Session currentSession = sessionRepository.findByUserIdAndIsCurrentTrue(userId)
.orElseThrow(() -> new FunctionalException(Message.SESSION_NO_CURRENT_SESSION + userId));
return SessionMapper.toDTO(currentSession);
}
@Override
@Transactional
public void invalidateSession(Long sessionId) throws FunctionalException {
if (sessionId == null) {
throw new FunctionalException(Message.SESSION_ID_NULL);
}
Session session = sessionRepository.findById(sessionId)
.orElseThrow(() -> new FunctionalException(Message.SESSION_NOT_FOUND + sessionId));
session.setCurrent(false);
sessionRepository.save(session);
}
}
\ No newline at end of file
0% ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter