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.InstalledAppDTO;
|
||||||
import com.psg.dlsysinfo.dl_sysinfo_server.dto.PatchComplianceDTO;
|
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.dto.SystemInfoDTO;
|
||||||
import com.psg.dlsysinfo.dl_sysinfo_server.entity.Client;
|
import com.psg.dlsysinfo.dl_sysinfo_server.entity.*;
|
||||||
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.repository.ClientRepository;
|
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.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.EncryptionService;
|
||||||
import com.psg.dlsysinfo.dl_sysinfo_server.security.JwtUtil;
|
import com.psg.dlsysinfo.dl_sysinfo_server.security.JwtUtil;
|
||||||
import com.psg.dlsysinfo.dl_sysinfo_server.security.TokenResolver;
|
import com.psg.dlsysinfo.dl_sysinfo_server.security.TokenResolver;
|
||||||
@@ -45,7 +44,9 @@ public class SystemInfoController {
|
|||||||
|
|
||||||
@Autowired private ClientRepository clientRepository;
|
@Autowired private ClientRepository clientRepository;
|
||||||
@Autowired private InstalledSoftwareRepository installedSoftwareRepository;
|
@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 DeviceService deviceService;
|
||||||
@Autowired private ObjectMapper objectMapper;
|
@Autowired private ObjectMapper objectMapper;
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ public class SystemInfoController {
|
|||||||
public ResponseEntity<Map<String, String>> receivePatchCompliance(
|
public ResponseEntity<Map<String, String>> receivePatchCompliance(
|
||||||
@AuthenticationPrincipal Object currentUser,
|
@AuthenticationPrincipal Object currentUser,
|
||||||
HttpServletRequest request,
|
HttpServletRequest request,
|
||||||
@RequestBody List<PatchComplianceDTO> patchData) {
|
@RequestBody PatchComplianceDTO patchData) {
|
||||||
|
|
||||||
Map<String, String> response = new HashMap<>();
|
Map<String, String> response = new HashMap<>();
|
||||||
|
|
||||||
@@ -158,7 +159,7 @@ public class SystemInfoController {
|
|||||||
return errorResponse(response, "Invalid or expired token.", 403);
|
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);
|
return errorResponse(response, "No patch data found in request body.", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,35 +169,86 @@ public class SystemInfoController {
|
|||||||
Client client = clientRepository.findByClientIdentifier(clientIdentifier)
|
Client client = clientRepository.findByClientIdentifier(clientIdentifier)
|
||||||
.orElseThrow(() -> new IllegalArgumentException("Client not registered"));
|
.orElseThrow(() -> new IllegalArgumentException("Client not registered"));
|
||||||
|
|
||||||
// Get the device associated with this client
|
// Get device using hostname from the payload
|
||||||
// Since we need to know which device this is for, we'll need the hostname
|
String hostname = patchData.getHostname();
|
||||||
// For now, we'll assume the most recently checked-in device for this client
|
if (hostname == null || hostname.isEmpty()) {
|
||||||
Devices device = deviceService.getMostRecentDeviceForClient(client);
|
return errorResponse(response, "Hostname is required in patch compliance data.", 400);
|
||||||
if (device == null) {
|
|
||||||
return errorResponse(response, "No device found for this client.", 404);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
System.out.println("🔍 Processing patch compliance for device: " + device.getDeviceId() + " (" + hostname + ")");
|
||||||
windowsUpdateRepository.deleteByDevice(device);
|
|
||||||
|
|
||||||
// Save new updates
|
// Step 1: Delete and insert installed patches
|
||||||
for (PatchComplianceDTO dto : patchData) {
|
installedPatchRepository.deleteByDevice(device);
|
||||||
if (dto.getUpdateId() == null) continue;
|
|
||||||
|
|
||||||
WindowsUpdate update = new WindowsUpdate();
|
int patchesProcessed = 0;
|
||||||
update.setDevice(device);
|
if (patchData.getInstalledPatches() != null) {
|
||||||
update.setDate(dto.getDate());
|
for (var patchDTO : patchData.getInstalledPatches()) {
|
||||||
update.setTitle(dto.getTitle());
|
if (patchDTO.getHotFixId() == null) continue;
|
||||||
update.setUpdateId(dto.getUpdateId());
|
|
||||||
|
|
||||||
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("status", "success");
|
||||||
response.put("message", "Patch compliance data received and stored successfully.");
|
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);
|
return ResponseEntity.ok(response);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} 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.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class PatchComplianceDTO {
|
public class PatchComplianceDTO {
|
||||||
private String date;
|
private String hostname;
|
||||||
private String title;
|
private List<InstalledPatchDTO> installedPatches;
|
||||||
private String updateId;
|
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