This commit is contained in:
zaine
2026-03-19 17:30:04 +00:00
parent 4a2171c38d
commit c5bb58888a
11 changed files with 248 additions and 6 deletions

View File

@@ -1,7 +1,5 @@
package org.zaine.app.controller;
import java.lang.System.Logger;
import java.util.List;
import java.util.Map;
import org.zaine.app.dto.CompetenciesDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
@@ -17,7 +15,7 @@ import org.zaine.app.service.CompetenciesService;
@RestController
@RequestMapping("/api/competencies")
public class CompetenciesController {
private static final Logger logger = System.getLogger(CompetenciesController.class.getName());
//private static final Logger logger = System.getLogger(CompetenciesController.class.getName());
@Autowired
private CompetenciesService competenciesService;

View File

@@ -0,0 +1,78 @@
package org.zaine.app.controller;
import java.lang.System.Logger;
import java.time.LocalDate;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.zaine.app.dto.WirdEntryDTO;
import org.zaine.app.model.WirdEntry;
import org.zaine.app.service.WirdService;
@RestController
@RequestMapping("/api/wird")
public class WirdController {
private static final Logger logger = System.getLogger(WirdController.class.getName());
@Autowired
private WirdService wirdService;
/**
* GET /api/wird/entries
* Returns all entries, newest first. Used by history table and today cards.
*/
@GetMapping("/entries")
public List<WirdEntry> getAllEntries() {
logger.log(Logger.Level.INFO, "Fetching all wird entries");
return wirdService.getAllEntries();
}
/**
* GET /api/wird/entries/today
* Convenience endpoint for today's entries only.
*/
@GetMapping("/entries/today")
public List<WirdEntry> getTodayEntries() {
return wirdService.getTodayEntries();
}
/**
* GET /api/wird/entries/range?from=2025-01-01&to=2025-01-31
* Used by trend chart to fetch a date window.
*/
@GetMapping("/entries/range")
public List<WirdEntry> getEntriesInRange(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
return wirdService.getEntriesInRange(from, to);
}
/**
* GET /api/wird/entries/range?from=...&to=...&type=durood
* Filtered by wird type — useful if you want to extend the chart later.
*/
@GetMapping("/entries/type/{type}")
public List<WirdEntry> getEntriesByType(
@PathVariable String type,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
return wirdService.getEntriesByTypeInRange(type, from, to);
}
/**
* POST /api/wird/entries
* Body: { wirdType, date, value, notes }
* Creates a new log entry.
*/
@PostMapping("/entries")
public ResponseEntity<WirdEntry> createEntry(@RequestBody WirdEntryDTO dto) {
logger.log(Logger.Level.INFO, "Creating wird entry: {0} on {1}", dto.getWirdType(), dto.getDate());
WirdEntry saved = wirdService.createEntry(dto);
return ResponseEntity.ok(saved);
}
}

View File

@@ -0,0 +1,20 @@
package org.zaine.app.dto;
import java.math.BigDecimal;
import java.time.LocalDate;
public class WirdEntryDTO {
private String wirdType;
private LocalDate date;
private BigDecimal value;
private String notes;
public String getWirdType() { return wirdType; }
public void setWirdType(String t) { this.wirdType = t; }
public LocalDate getDate() { return date; }
public void setDate(LocalDate d) { this.date = d; }
public BigDecimal getValue() { return value; }
public void setValue(BigDecimal v) { this.value = v; }
public String getNotes() { return notes; }
public void setNotes(String n) { this.notes = n; }
}

View File

@@ -0,0 +1,43 @@
package org.zaine.app.model;
import jakarta.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.OffsetDateTime;
@Entity
@Table(name = "wird_entries")
public class WirdEntry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "wird_type", nullable = false)
private String wirdType;
@Column(nullable = false)
private LocalDate date;
@Column(nullable = false, precision = 10, scale = 2)
private BigDecimal value;
@Column
private String notes;
@Column(name = "created_at", insertable = false, updatable = false)
private OffsetDateTime createdAt;
// ── Getters & Setters ─────────────────────────────────── //
public Long getId() { return id; }
public String getWirdType() { return wirdType; }
public void setWirdType(String t) { this.wirdType = t; }
public LocalDate getDate() { return date; }
public void setDate(LocalDate d) { this.date = d; }
public BigDecimal getValue() { return value; }
public void setValue(BigDecimal v) { this.value = v; }
public String getNotes() { return notes; }
public void setNotes(String n) { this.notes = n; }
public OffsetDateTime getCreatedAt() { return createdAt; }
}

View File

@@ -0,0 +1,35 @@
package org.zaine.app.repositories;
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 org.zaine.app.model.WirdEntry;
import java.time.LocalDate;
import java.util.List;
@Repository
public interface WirdEntryRepository extends JpaRepository<WirdEntry, Long> {
// All entries ordered newest first (for history table)
List<WirdEntry> findAllByOrderByDateDescCreatedAtDesc();
// Entries for a specific date (today's cards)
List<WirdEntry> findByDateOrderByCreatedAtDesc(LocalDate date);
// Entries within a date range for a specific wird type (trend chart)
@Query("SELECT e FROM WirdEntry e WHERE e.wirdType = :type AND e.date BETWEEN :from AND :to ORDER BY e.date ASC")
List<WirdEntry> findByTypeAndDateRange(
@Param("type") String type,
@Param("from") LocalDate from,
@Param("to") LocalDate to
);
// All entries for a date range (bulk fetch for chart, avoids N+1)
@Query("SELECT e FROM WirdEntry e WHERE e.date BETWEEN :from AND :to ORDER BY e.date ASC, e.wirdType ASC")
List<WirdEntry> findByDateRange(
@Param("from") LocalDate from,
@Param("to") LocalDate to
);
}

View File

@@ -32,6 +32,10 @@ public class CommentsService {
public Comments getCommentById(Integer id) {
logger.log(System.Logger.Level.INFO, "Entering getCommentById with id: " + id);
if (id == null) {
logger.log(System.Logger.Level.WARNING, "Comment id is null. Operation aborted.");
return null;
}
return commentsRepository.findById(id).get();
}

View File

@@ -26,6 +26,10 @@ public class CompetenciesService {
public Competencies getCompetencyById(Integer id) {
logger.log(System.Logger.Level.INFO, "Entering getCompetencyById with id: " + id);
if (id == null) {
logger.log(System.Logger.Level.WARNING, "Competency id is null. Operation aborted.");
return null;
}
return competenciesRepository.findById(id).get();
}

View File

@@ -0,0 +1,42 @@
package org.zaine.app.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zaine.app.dto.WirdEntryDTO;
import org.zaine.app.model.WirdEntry;
import org.zaine.app.repositories.WirdEntryRepository;
import java.time.LocalDate;
import java.util.List;
@Service
public class WirdService {
@Autowired
private WirdEntryRepository repo;
public List<WirdEntry> getAllEntries() {
return repo.findAllByOrderByDateDescCreatedAtDesc();
}
public List<WirdEntry> getTodayEntries() {
return repo.findByDateOrderByCreatedAtDesc(LocalDate.now());
}
public List<WirdEntry> getEntriesInRange(LocalDate from, LocalDate to) {
return repo.findByDateRange(from, to);
}
public List<WirdEntry> getEntriesByTypeInRange(String type, LocalDate from, LocalDate to) {
return repo.findByTypeAndDateRange(type, from, to);
}
public WirdEntry createEntry(WirdEntryDTO dto) {
WirdEntry entry = new WirdEntry();
entry.setWirdType(dto.getWirdType());
entry.setDate(dto.getDate() != null ? dto.getDate() : LocalDate.now());
entry.setValue(dto.getValue());
entry.setNotes(dto.getNotes());
return repo.save(entry);
}
}

View File

@@ -1,8 +1,5 @@
package org.zaine.app;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class ApplicationTest {

View File

@@ -4,6 +4,8 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.Arrays;
import java.util.List;
import java.lang.System.Logger;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -14,6 +16,9 @@ import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class CommentsServiceTest {
private static final Logger logger = System.getLogger(CompetenciesService.class.getName());
@InjectMocks
private CommentsService commentsService;
@@ -58,6 +63,10 @@ public class CommentsServiceTest {
public void testGetCommentByIdReturnsComment() {
Comments comment = new Comments();
Integer id = comment.getId();
if (id == null) {
logger.log(System.Logger.Level.WARNING, "Comment id is null. Operation aborted.");
return;
}
when(commentsRepository.findById(id)).thenReturn(java.util.Optional.of(comment));
Comments result = commentsService.getCommentById(id);

View File

@@ -11,12 +11,16 @@ import org.zaine.app.model.Competencies;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.lang.System.Logger;
import java.util.Arrays;
import java.util.Optional;
@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class)
public class CompetenciesServiceTest {
private static final Logger logger = System.getLogger(CompetenciesService.class.getName());
@InjectMocks
private CompetenciesService competenciesService;
@@ -41,6 +45,10 @@ public class CompetenciesServiceTest {
public void testGetCompetencyByIdReturnsCompetency() {
Competencies comp = new Competencies();
@NotNull Integer id = comp.getId();
if (id == null) {
logger.log(System.Logger.Level.WARNING, "Competency id is null. Operation aborted.");
return;
}
when(competenciesRepository.findById(id)).thenReturn(Optional.of(comp));
@@ -53,6 +61,10 @@ public class CompetenciesServiceTest {
public void testUpdateCompetencyStatusUpdatesCorrectly() {
Competencies comp = new Competencies();
@NotNull Integer id = comp.getId();
if (id == null) {
logger.log(System.Logger.Level.WARNING, "Competency id is null. Operation aborted.");
return;
}
when(competenciesRepository.findById(id)).thenReturn(Optional.of(comp));
competenciesService.updateCompetencyState(id, "completed");