diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/controller/RouterController.java b/src/main/java/com/litoralregas/vpnprovisioner/router/controller/RouterController.java new file mode 100644 index 0000000..5e72479 --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/controller/RouterController.java @@ -0,0 +1,53 @@ +package com.litoralregas.vpnprovisioner.router.controller; + +import com.litoralregas.vpnprovisioner.router.dto.CreateRouterRequest; +import com.litoralregas.vpnprovisioner.router.dto.RouterResponse; +import com.litoralregas.vpnprovisioner.router.dto.UpdateRouterRequest; +import com.litoralregas.vpnprovisioner.router.service.RouterService; +import jakarta.validation.Valid; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController +@RequestMapping("/api/routers") +public class RouterController { + + private final RouterService routerService; + + public RouterController(RouterService routerService) { + this.routerService = routerService; + } + + @PostMapping + @ResponseStatus(HttpStatus.CREATED) + public RouterResponse create(@Valid @RequestBody CreateRouterRequest request) { + return routerService.create(request); + } + + @GetMapping + public List findAll() { + return routerService.findAll(); + } + + @GetMapping("/{id}") + public RouterResponse findById(@PathVariable UUID id) { + return routerService.findById(id); + } + + @PutMapping("/{id}") + public RouterResponse update( + @PathVariable UUID id, + @Valid @RequestBody UpdateRouterRequest request + ) { + return routerService.update(id, request); + } + + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void delete(@PathVariable UUID id) { + routerService.delete(id); + } +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/dto/CreateRouterRequest.java b/src/main/java/com/litoralregas/vpnprovisioner/router/dto/CreateRouterRequest.java new file mode 100644 index 0000000..7f5b247 --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/dto/CreateRouterRequest.java @@ -0,0 +1,10 @@ +package com.litoralregas.vpnprovisioner.router.dto; + +import jakarta.validation.constraints.NotBlank; + +public record CreateRouterRequest( + @NotBlank String name, + String hardwareModel, + String firmwareVersion +) { +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/dto/RouterResponse.java b/src/main/java/com/litoralregas/vpnprovisioner/router/dto/RouterResponse.java new file mode 100644 index 0000000..f176d34 --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/dto/RouterResponse.java @@ -0,0 +1,18 @@ +package com.litoralregas.vpnprovisioner.router.dto; + +import com.litoralregas.vpnprovisioner.router.entity.RouterStatus; + +import java.time.Instant; +import java.util.UUID; + +public record RouterResponse( + UUID id, + String name, + String hardwareModel, + String firmwareVersion, + RouterStatus status, + String vpnIp, + Instant createdAt, + Instant updatedAt +) { +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/dto/UpdateRouterRequest.java b/src/main/java/com/litoralregas/vpnprovisioner/router/dto/UpdateRouterRequest.java new file mode 100644 index 0000000..aa28c5a --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/dto/UpdateRouterRequest.java @@ -0,0 +1,10 @@ +package com.litoralregas.vpnprovisioner.router.dto; + +import jakarta.validation.constraints.NotBlank; + +public record UpdateRouterRequest( + @NotBlank String name, + String hardwareModel, + String firmwareVersion +) { +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/entity/Router.java b/src/main/java/com/litoralregas/vpnprovisioner/router/entity/Router.java new file mode 100644 index 0000000..76da5f1 --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/entity/Router.java @@ -0,0 +1,66 @@ +package com.litoralregas.vpnprovisioner.router.entity; + +import jakarta.persistence.*; + +import java.time.Instant; +import java.util.UUID; + +@Entity +@Table(name = "routers") +public class Router { + + @Id + private UUID id; + + @Column(nullable = false) + private String name; + + private String hardwareModel; + + private String firmwareVersion; + + @Enumerated(EnumType.STRING) + @Column(nullable = false) + private RouterStatus status; + + private String vpnIp; + + @Column(nullable = false) + private Instant createdAt; + + @Column(nullable = false) + private Instant updatedAt; + + protected Router() { + } + + public Router(String name, String hardwareModel, String firmwareVersion) { + this.id = UUID.randomUUID(); + this.name = name; + this.hardwareModel = hardwareModel; + this.firmwareVersion = firmwareVersion; + this.status = RouterStatus.PENDING; + this.createdAt = Instant.now(); + this.updatedAt = Instant.now(); + } + + @PreUpdate + public void preUpdate() { + this.updatedAt = Instant.now(); + } + + public UUID getId() { return id; } + public String getName() { return name; } + public String getHardwareModel() { return hardwareModel; } + public String getFirmwareVersion() { return firmwareVersion; } + public RouterStatus getStatus() { return status; } + public String getVpnIp() { return vpnIp; } + public Instant getCreatedAt() { return createdAt; } + public Instant getUpdatedAt() { return updatedAt; } + + public void updateDetails(String name, String hardwareModel, String firmwareVersion) { + this.name = name; + this.hardwareModel = hardwareModel; + this.firmwareVersion = firmwareVersion; + } +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/entity/RouterStatus.java b/src/main/java/com/litoralregas/vpnprovisioner/router/entity/RouterStatus.java new file mode 100644 index 0000000..e61752b --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/entity/RouterStatus.java @@ -0,0 +1,10 @@ +package com.litoralregas.vpnprovisioner.router.entity; + +public enum RouterStatus { + PENDING, + CONFIGURED, + PROVISIONING, + PROVISIONED, + FAILED, + REMOVED +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/repository/RouterRepository.java b/src/main/java/com/litoralregas/vpnprovisioner/router/repository/RouterRepository.java new file mode 100644 index 0000000..f4bab5e --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/repository/RouterRepository.java @@ -0,0 +1,9 @@ +package com.litoralregas.vpnprovisioner.router.repository; + +import com.litoralregas.vpnprovisioner.router.entity.Router; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface RouterRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/com/litoralregas/vpnprovisioner/router/service/RouterService.java b/src/main/java/com/litoralregas/vpnprovisioner/router/service/RouterService.java new file mode 100644 index 0000000..952832e --- /dev/null +++ b/src/main/java/com/litoralregas/vpnprovisioner/router/service/RouterService.java @@ -0,0 +1,85 @@ +package com.litoralregas.vpnprovisioner.router.service; + +import com.litoralregas.vpnprovisioner.router.dto.CreateRouterRequest; +import com.litoralregas.vpnprovisioner.router.dto.RouterResponse; +import com.litoralregas.vpnprovisioner.router.dto.UpdateRouterRequest; +import com.litoralregas.vpnprovisioner.router.entity.Router; +import com.litoralregas.vpnprovisioner.router.repository.RouterRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Service +public class RouterService { + + private final RouterRepository routerRepository; + + public RouterService(RouterRepository routerRepository) { + this.routerRepository = routerRepository; + } + + @Transactional + public RouterResponse create(CreateRouterRequest request) { + Router router = new Router( + request.name(), + request.hardwareModel(), + request.firmwareVersion() + ); + + Router saved = routerRepository.save(router); + return toResponse(saved); + } + + @Transactional(readOnly = true) + public List findAll() { + return routerRepository.findAll() + .stream() + .map(this::toResponse) + .toList(); + } + + @Transactional(readOnly = true) + public RouterResponse findById(UUID id) { + Router router = routerRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Router not found: " + id)); + + return toResponse(router); + } + + @Transactional + public RouterResponse update(UUID id, UpdateRouterRequest request) { + Router router = routerRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Router not found: " + id)); + + router.updateDetails( + request.name(), + request.hardwareModel(), + request.firmwareVersion() + ); + + return toResponse(router); + } + + @Transactional + public void delete(UUID id) { + Router router = routerRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Router not found: " + id)); + + routerRepository.delete(router); + } + + private RouterResponse toResponse(Router router) { + return new RouterResponse( + router.getId(), + router.getName(), + router.getHardwareModel(), + router.getFirmwareVersion(), + router.getStatus(), + router.getVpnIp(), + router.getCreatedAt(), + router.getUpdatedAt() + ); + } +} \ No newline at end of file