Additional PatchHistory entities to expand the information stored.
This commit is contained in:
@@ -4,13 +4,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.dto.InstalledAppDTO;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.dto.PatchComplianceDTO;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.dto.SystemInfoDTO;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Client;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Devices;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.InstalledSoftware;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.WindowsUpdate;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.*;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.repository.ClientRepository;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.repository.InstalledSoftwareRepository;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.repository.WindowsUpdateRepository;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.repository.InstalledPatchRepository;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.repository.WindowsUpdateHistoryRepository;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.repository.PatchComplianceSummaryRepository;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.security.EncryptionService;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.security.JwtUtil;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.security.TokenResolver;
|
||||
@@ -45,7 +44,9 @@ public class SystemInfoController {
|
||||
|
||||
@Autowired private ClientRepository clientRepository;
|
||||
@Autowired private InstalledSoftwareRepository installedSoftwareRepository;
|
||||
@Autowired private WindowsUpdateRepository windowsUpdateRepository;
|
||||
@Autowired private InstalledPatchRepository installedPatchRepository;
|
||||
@Autowired private WindowsUpdateHistoryRepository windowsUpdateHistoryRepository;
|
||||
@Autowired private PatchComplianceSummaryRepository patchComplianceSummaryRepository;
|
||||
@Autowired private DeviceService deviceService;
|
||||
@Autowired private ObjectMapper objectMapper;
|
||||
|
||||
@@ -148,7 +149,7 @@ public class SystemInfoController {
|
||||
public ResponseEntity<Map<String, String>> receivePatchCompliance(
|
||||
@AuthenticationPrincipal Object currentUser,
|
||||
HttpServletRequest request,
|
||||
@RequestBody List<PatchComplianceDTO> patchData) {
|
||||
@RequestBody PatchComplianceDTO patchData) {
|
||||
|
||||
Map<String, String> response = new HashMap<>();
|
||||
|
||||
@@ -158,7 +159,7 @@ public class SystemInfoController {
|
||||
return errorResponse(response, "Invalid or expired token.", 403);
|
||||
}
|
||||
|
||||
if (patchData == null || patchData.isEmpty()) {
|
||||
if (patchData == null) {
|
||||
return errorResponse(response, "No patch data found in request body.", 400);
|
||||
}
|
||||
|
||||
@@ -168,35 +169,86 @@ public class SystemInfoController {
|
||||
Client client = clientRepository.findByClientIdentifier(clientIdentifier)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Client not registered"));
|
||||
|
||||
// Get the device associated with this client
|
||||
// Since we need to know which device this is for, we'll need the hostname
|
||||
// For now, we'll assume the most recently checked-in device for this client
|
||||
Devices device = deviceService.getMostRecentDeviceForClient(client);
|
||||
if (device == null) {
|
||||
return errorResponse(response, "No device found for this client.", 404);
|
||||
// Get device using hostname from the payload
|
||||
String hostname = patchData.getHostname();
|
||||
if (hostname == null || hostname.isEmpty()) {
|
||||
return errorResponse(response, "Hostname is required in patch compliance data.", 400);
|
||||
}
|
||||
|
||||
System.out.println("🔍 Processing " + patchData.size() + " Windows updates for device: " + device.getDeviceId());
|
||||
String hashedHostname = encryptionService.hashString(hostname);
|
||||
Devices device = deviceService.findOrCreateDevice(hostname, hashedHostname, client);
|
||||
|
||||
// Delete existing updates for this device to replace with fresh data
|
||||
windowsUpdateRepository.deleteByDevice(device);
|
||||
System.out.println("🔍 Processing patch compliance for device: " + device.getDeviceId() + " (" + hostname + ")");
|
||||
|
||||
// Save new updates
|
||||
for (PatchComplianceDTO dto : patchData) {
|
||||
if (dto.getUpdateId() == null) continue;
|
||||
// Step 1: Delete and insert installed patches
|
||||
installedPatchRepository.deleteByDevice(device);
|
||||
|
||||
WindowsUpdate update = new WindowsUpdate();
|
||||
update.setDevice(device);
|
||||
update.setDate(dto.getDate());
|
||||
update.setTitle(dto.getTitle());
|
||||
update.setUpdateId(dto.getUpdateId());
|
||||
int patchesProcessed = 0;
|
||||
if (patchData.getInstalledPatches() != null) {
|
||||
for (var patchDTO : patchData.getInstalledPatches()) {
|
||||
if (patchDTO.getHotFixId() == null) continue;
|
||||
|
||||
windowsUpdateRepository.save(update);
|
||||
InstalledPatch patch = new InstalledPatch();
|
||||
patch.setDevice(device);
|
||||
patch.setHotfixId(patchDTO.getHotFixId());
|
||||
patch.setCaption(patchDTO.getCaption());
|
||||
patch.setDescription(patchDTO.getDescription());
|
||||
patch.setInstalledBy(patchDTO.getInstalledBy());
|
||||
patch.setInstalledOn(patchDTO.getInstalledOn());
|
||||
patch.setRecordedAt(LocalDateTime.now());
|
||||
|
||||
installedPatchRepository.save(patch);
|
||||
patchesProcessed++;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Delete and insert update history
|
||||
windowsUpdateHistoryRepository.deleteByDevice(device);
|
||||
|
||||
int historyProcessed = 0;
|
||||
if (patchData.getRecentUpdateHistory() != null) {
|
||||
for (var historyDTO : patchData.getRecentUpdateHistory()) {
|
||||
WindowsUpdateHistory history = new WindowsUpdateHistory();
|
||||
history.setDevice(device);
|
||||
history.setUpdateDate(historyDTO.getDate());
|
||||
history.setTitle(historyDTO.getTitle());
|
||||
history.setUpdateId(historyDTO.getUpdateIdentity());
|
||||
history.setOperation(historyDTO.getOperation());
|
||||
history.setResultCode(historyDTO.getResultCode());
|
||||
history.setRecordedAt(LocalDateTime.now());
|
||||
|
||||
windowsUpdateHistoryRepository.save(history);
|
||||
historyProcessed++;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Update or insert summary
|
||||
long successfulUpdates = patchData.getRecentUpdateHistory() != null
|
||||
? patchData.getRecentUpdateHistory().stream()
|
||||
.filter(h -> "Succeeded".equalsIgnoreCase(h.getResultCode()))
|
||||
.count()
|
||||
: 0;
|
||||
|
||||
PatchComplianceSummary summary = patchComplianceSummaryRepository
|
||||
.findByDevice(device)
|
||||
.orElseGet(() -> {
|
||||
PatchComplianceSummary newSummary = new PatchComplianceSummary();
|
||||
newSummary.setDevice(device);
|
||||
return newSummary;
|
||||
});
|
||||
|
||||
summary.setTotalInstalledPatches(patchesProcessed);
|
||||
summary.setRecentSuccessfulUpdates((int) successfulUpdates);
|
||||
summary.setLastCollectedAt(LocalDateTime.now());
|
||||
summary.setRecordedAt(LocalDateTime.now());
|
||||
|
||||
patchComplianceSummaryRepository.save(summary);
|
||||
|
||||
response.put("status", "success");
|
||||
response.put("message", "Patch compliance data received and stored successfully.");
|
||||
response.put("updatesProcessed", String.valueOf(patchData.size()));
|
||||
response.put("patchesProcessed", String.valueOf(patchesProcessed));
|
||||
response.put("historyProcessed", String.valueOf(historyProcessed));
|
||||
response.put("successfulUpdates", String.valueOf(successfulUpdates));
|
||||
return ResponseEntity.ok(response);
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class InstalledPatchDTO {
|
||||
@JsonProperty("HotFixID")
|
||||
private String hotFixId;
|
||||
|
||||
@JsonProperty("Caption")
|
||||
private String caption;
|
||||
|
||||
@JsonProperty("Description")
|
||||
private String description;
|
||||
|
||||
@JsonProperty("InstalledBy")
|
||||
private String installedBy;
|
||||
|
||||
@JsonProperty("InstalledOn")
|
||||
private String installedOn;
|
||||
}
|
||||
@@ -3,10 +3,12 @@ package com.psg.dlsysinfo.dl_sysinfo_server.dto;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PatchComplianceDTO {
|
||||
private String date;
|
||||
private String title;
|
||||
private String updateId;
|
||||
private String hostname;
|
||||
private List<InstalledPatchDTO> installedPatches;
|
||||
private List<UpdateHistoryDTO> recentUpdateHistory;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class UpdateHistoryDTO {
|
||||
private String date;
|
||||
private String title;
|
||||
private String updateIdentity;
|
||||
private String operation;
|
||||
private String resultCode;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "installed_patches",
|
||||
uniqueConstraints = @UniqueConstraint(name = "unique_device_patch", columnNames = {"device_id", "hotfix_id"}),
|
||||
indexes = {
|
||||
@Index(name = "idx_device_hotfix", columnList = "device_id, hotfix_id"),
|
||||
@Index(name = "idx_installed_on", columnList = "installed_on")
|
||||
})
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class InstalledPatch {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "device_id", nullable = false)
|
||||
private Devices device;
|
||||
|
||||
@Column(name = "hotfix_id", nullable = false, length = 50)
|
||||
private String hotfixId;
|
||||
|
||||
@Column(name = "caption", length = 500)
|
||||
private String caption;
|
||||
|
||||
@Column(name = "description", length = 255)
|
||||
private String description;
|
||||
|
||||
@Column(name = "installed_by", length = 255)
|
||||
private String installedBy;
|
||||
|
||||
@Column(name = "installed_on", length = 50)
|
||||
private String installedOn;
|
||||
|
||||
@Column(name = "recorded_at", nullable = false)
|
||||
private LocalDateTime recordedAt = LocalDateTime.now();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "patch_compliance_summary",
|
||||
uniqueConstraints = @UniqueConstraint(name = "unique_device_summary", columnNames = {"device_id"}),
|
||||
indexes = {
|
||||
@Index(name = "idx_last_collected", columnList = "last_collected_at")
|
||||
})
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class PatchComplianceSummary {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "device_id", nullable = false)
|
||||
private Devices device;
|
||||
|
||||
@Column(name = "total_installed_patches", nullable = false)
|
||||
private Integer totalInstalledPatches = 0;
|
||||
|
||||
@Column(name = "recent_successful_updates", nullable = false)
|
||||
private Integer recentSuccessfulUpdates = 0;
|
||||
|
||||
@Column(name = "last_collected_at", nullable = false)
|
||||
private LocalDateTime lastCollectedAt;
|
||||
|
||||
@Column(name = "recorded_at", nullable = false)
|
||||
private LocalDateTime recordedAt = LocalDateTime.now();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.entity;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity
|
||||
@Table(name = "windows_update_history",
|
||||
indexes = {
|
||||
@Index(name = "idx_device_date", columnList = "device_id, update_date"),
|
||||
@Index(name = "idx_result_code", columnList = "result_code")
|
||||
})
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class WindowsUpdateHistory {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "device_id", nullable = false)
|
||||
private Devices device;
|
||||
|
||||
@Column(name = "update_date", length = 255)
|
||||
private String updateDate;
|
||||
|
||||
@Column(name = "title", length = 1000)
|
||||
private String title;
|
||||
|
||||
@Column(name = "update_id", length = 255)
|
||||
private String updateId;
|
||||
|
||||
@Column(name = "operation", length = 50)
|
||||
private String operation;
|
||||
|
||||
@Column(name = "result_code", length = 50)
|
||||
private String resultCode;
|
||||
|
||||
@Column(name = "recorded_at", nullable = false)
|
||||
private LocalDateTime recordedAt = LocalDateTime.now();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.repository;
|
||||
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Devices;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.InstalledPatch;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface InstalledPatchRepository extends JpaRepository<InstalledPatch, Long> {
|
||||
void deleteByDevice(Devices device);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.repository;
|
||||
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Devices;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.PatchComplianceSummary;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface PatchComplianceSummaryRepository extends JpaRepository<PatchComplianceSummary, Long> {
|
||||
Optional<PatchComplianceSummary> findByDevice(Devices device);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.psg.dlsysinfo.dl_sysinfo_server.repository;
|
||||
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Devices;
|
||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.WindowsUpdateHistory;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface WindowsUpdateHistoryRepository extends JpaRepository<WindowsUpdateHistory, Long> {
|
||||
void deleteByDevice(Devices device);
|
||||
}
|
||||
Reference in New Issue
Block a user