updates for zmanagement x4
All checks were successful
Build Org Backend / build (push) Successful in 17s

This commit is contained in:
2026-06-10 16:40:53 +01:00
parent 28d874edd8
commit 4bf7810206
8 changed files with 89 additions and 10 deletions

View File

@@ -2,17 +2,22 @@ package org.zaine.app.controller;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.zaine.app.dto.EveningCheckinRequest; import org.zaine.app.dto.EveningCheckinRequest;
import org.zaine.app.dto.MorningCheckinRequest; import org.zaine.app.dto.MorningCheckinRequest;
import org.zaine.app.dto.TodayStatusDTO; import org.zaine.app.dto.TodayStatusDTO;
import org.zaine.app.service.CheckinService; import org.zaine.app.service.CheckinService;
import java.time.LocalDate;
import java.util.List;
@RestController @RestController
@RequestMapping("/api/checkin") @RequestMapping("/api/checkin")
@Tag(name = "Check-in", description = "Daily morning and evening check-ins") @Tag(name = "Check-in", description = "Daily morning and evening check-ins")
@@ -30,6 +35,14 @@ public class CheckinController {
return checkinService.getTodayStatus(); return checkinService.getTodayStatus();
} }
@Operation(summary = "Get check-in history")
@GetMapping("/history")
public List<TodayStatusDTO> getHistory(
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
return checkinService.getHistory(from, to);
}
@Operation(summary = "Submit morning check-in") @Operation(summary = "Submit morning check-in")
@PostMapping("/morning") @PostMapping("/morning")
public ResponseEntity<TodayStatusDTO> submitMorning(@RequestBody MorningCheckinRequest request) { public ResponseEntity<TodayStatusDTO> submitMorning(@RequestBody MorningCheckinRequest request) {

View File

@@ -6,6 +6,9 @@ public record EveningCheckinRequest(
LocalDate date, LocalDate date,
Integer mood, Integer mood,
Integer stressLevel, Integer stressLevel,
Boolean duties,
Boolean zikr,
Boolean salah,
String reflection, String reflection,
String bestThingToday) { String bestThingToday) {
} }

View File

@@ -8,5 +8,8 @@ public record MorningCheckinRequest(
BigDecimal sleepHours, BigDecimal sleepHours,
Integer energyLevel, Integer energyLevel,
Integer mood, Integer mood,
Boolean fajr,
Boolean quran,
Boolean exercise,
String note) { String note) {
} }

View File

@@ -13,6 +13,13 @@ public record TodayStatusDTO(
Integer morningMoodLevel, Integer morningMoodLevel,
Integer eveningMoodLevel, Integer eveningMoodLevel,
Integer stressLevel, Integer stressLevel,
Boolean fajr,
Boolean quran,
Boolean exercise,
Boolean duties,
Boolean zikr,
Boolean salah,
String reflection,
OffsetDateTime morningCompletedAt, OffsetDateTime morningCompletedAt,
OffsetDateTime eveningCompletedAt) { OffsetDateTime eveningCompletedAt) {
} }

View File

@@ -36,6 +36,15 @@ public class DailyCheckin {
@Column(name = "morning_note") @Column(name = "morning_note")
private String morningNote; private String morningNote;
@Column(name = "fajr")
private Boolean fajr;
@Column(name = "quran")
private Boolean quran;
@Column(name = "exercise")
private Boolean exercise;
@Column(name = "morning_completed_at") @Column(name = "morning_completed_at")
private OffsetDateTime morningCompletedAt; private OffsetDateTime morningCompletedAt;
@@ -51,6 +60,15 @@ public class DailyCheckin {
@Column(name = "best_thing_today") @Column(name = "best_thing_today")
private String bestThingToday; private String bestThingToday;
@Column(name = "duties")
private Boolean duties;
@Column(name = "zikr")
private Boolean zikr;
@Column(name = "salah")
private Boolean salah;
@Column(name = "evening_completed_at") @Column(name = "evening_completed_at")
private OffsetDateTime eveningCompletedAt; private OffsetDateTime eveningCompletedAt;
@@ -83,6 +101,12 @@ public class DailyCheckin {
public void setMorningMoodLevel(Integer morningMoodLevel) { this.morningMoodLevel = morningMoodLevel; } public void setMorningMoodLevel(Integer morningMoodLevel) { this.morningMoodLevel = morningMoodLevel; }
public String getMorningNote() { return morningNote; } public String getMorningNote() { return morningNote; }
public void setMorningNote(String morningNote) { this.morningNote = morningNote; } public void setMorningNote(String morningNote) { this.morningNote = morningNote; }
public Boolean getFajr() { return fajr; }
public void setFajr(Boolean fajr) { this.fajr = fajr; }
public Boolean getQuran() { return quran; }
public void setQuran(Boolean quran) { this.quran = quran; }
public Boolean getExercise() { return exercise; }
public void setExercise(Boolean exercise) { this.exercise = exercise; }
public OffsetDateTime getMorningCompletedAt() { return morningCompletedAt; } public OffsetDateTime getMorningCompletedAt() { return morningCompletedAt; }
public void setMorningCompletedAt(OffsetDateTime morningCompletedAt) { this.morningCompletedAt = morningCompletedAt; } public void setMorningCompletedAt(OffsetDateTime morningCompletedAt) { this.morningCompletedAt = morningCompletedAt; }
public Integer getEveningMoodLevel() { return eveningMoodLevel; } public Integer getEveningMoodLevel() { return eveningMoodLevel; }
@@ -93,6 +117,12 @@ public class DailyCheckin {
public void setReflection(String reflection) { this.reflection = reflection; } public void setReflection(String reflection) { this.reflection = reflection; }
public String getBestThingToday() { return bestThingToday; } public String getBestThingToday() { return bestThingToday; }
public void setBestThingToday(String bestThingToday) { this.bestThingToday = bestThingToday; } public void setBestThingToday(String bestThingToday) { this.bestThingToday = bestThingToday; }
public Boolean getDuties() { return duties; }
public void setDuties(Boolean duties) { this.duties = duties; }
public Boolean getZikr() { return zikr; }
public void setZikr(Boolean zikr) { this.zikr = zikr; }
public Boolean getSalah() { return salah; }
public void setSalah(Boolean salah) { this.salah = salah; }
public OffsetDateTime getEveningCompletedAt() { return eveningCompletedAt; } public OffsetDateTime getEveningCompletedAt() { return eveningCompletedAt; }
public void setEveningCompletedAt(OffsetDateTime eveningCompletedAt) { this.eveningCompletedAt = eveningCompletedAt; } public void setEveningCompletedAt(OffsetDateTime eveningCompletedAt) { this.eveningCompletedAt = eveningCompletedAt; }
public OffsetDateTime getCreatedAt() { return createdAt; } public OffsetDateTime getCreatedAt() { return createdAt; }

View File

@@ -4,8 +4,10 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.zaine.app.model.DailyCheckin; import org.zaine.app.model.DailyCheckin;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface DailyCheckinRepository extends JpaRepository<DailyCheckin, Long> { public interface DailyCheckinRepository extends JpaRepository<DailyCheckin, Long> {
Optional<DailyCheckin> findByDate(LocalDate date); Optional<DailyCheckin> findByDate(LocalDate date);
List<DailyCheckin> findByDateBetweenOrderByDateDesc(LocalDate from, LocalDate to);
} }

View File

@@ -12,6 +12,7 @@ import org.zaine.app.repositories.DailyCheckinRepository;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List;
@Service @Service
public class CheckinService { public class CheckinService {
@@ -26,16 +27,27 @@ public class CheckinService {
return toStatus(getOrCreate(LocalDate.now())); return toStatus(getOrCreate(LocalDate.now()));
} }
public List<TodayStatusDTO> getHistory(LocalDate from, LocalDate to) {
if (to.isBefore(from)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "to must be on or after from");
}
return dailyCheckinRepository.findByDateBetweenOrderByDateDesc(from, to)
.stream()
.map(this::toStatus)
.toList();
}
public TodayStatusDTO saveMorning(MorningCheckinRequest request) { public TodayStatusDTO saveMorning(MorningCheckinRequest request) {
LocalDate date = request.date() == null ? LocalDate.now() : request.date(); LocalDate date = request.date() == null ? LocalDate.now() : request.date();
validateScore(request.energyLevel(), "energyLevel");
validateScore(request.mood(), "mood");
validateSleepHours(request.sleepHours()); validateSleepHours(request.sleepHours());
DailyCheckin checkin = getOrCreate(date); DailyCheckin checkin = getOrCreate(date);
checkin.setSleepHours(request.sleepHours()); checkin.setSleepHours(request.sleepHours());
checkin.setMorningEnergyLevel(request.energyLevel()); checkin.setMorningEnergyLevel(request.energyLevel());
checkin.setMorningMoodLevel(request.mood()); checkin.setMorningMoodLevel(request.mood());
checkin.setFajr(request.fajr());
checkin.setQuran(request.quran());
checkin.setExercise(request.exercise());
checkin.setMorningNote(blankToNull(request.note())); checkin.setMorningNote(blankToNull(request.note()));
checkin.setMorningCompletedAt(OffsetDateTime.now()); checkin.setMorningCompletedAt(OffsetDateTime.now());
@@ -44,12 +56,13 @@ public class CheckinService {
public TodayStatusDTO saveEvening(EveningCheckinRequest request) { public TodayStatusDTO saveEvening(EveningCheckinRequest request) {
LocalDate date = request.date() == null ? LocalDate.now() : request.date(); LocalDate date = request.date() == null ? LocalDate.now() : request.date();
validateScore(request.mood(), "mood");
validateScore(request.stressLevel(), "stressLevel");
DailyCheckin checkin = getOrCreate(date); DailyCheckin checkin = getOrCreate(date);
checkin.setEveningMoodLevel(request.mood()); checkin.setEveningMoodLevel(request.mood());
checkin.setStressLevel(request.stressLevel()); checkin.setStressLevel(request.stressLevel());
checkin.setDuties(request.duties());
checkin.setZikr(request.zikr());
checkin.setSalah(request.salah());
checkin.setReflection(blankToNull(request.reflection())); checkin.setReflection(blankToNull(request.reflection()));
checkin.setBestThingToday(blankToNull(request.bestThingToday())); checkin.setBestThingToday(blankToNull(request.bestThingToday()));
checkin.setEveningCompletedAt(OffsetDateTime.now()); checkin.setEveningCompletedAt(OffsetDateTime.now());
@@ -75,16 +88,17 @@ public class CheckinService {
checkin.getMorningMoodLevel(), checkin.getMorningMoodLevel(),
checkin.getEveningMoodLevel(), checkin.getEveningMoodLevel(),
checkin.getStressLevel(), checkin.getStressLevel(),
checkin.getFajr(),
checkin.getQuran(),
checkin.getExercise(),
checkin.getDuties(),
checkin.getZikr(),
checkin.getSalah(),
checkin.getReflection(),
checkin.getMorningCompletedAt(), checkin.getMorningCompletedAt(),
checkin.getEveningCompletedAt()); checkin.getEveningCompletedAt());
} }
private void validateScore(Integer value, String fieldName) {
if (value == null || value < 1 || value > 10) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, fieldName + " must be between 1 and 10");
}
}
private void validateSleepHours(BigDecimal sleepHours) { private void validateSleepHours(BigDecimal sleepHours) {
if (sleepHours == null || sleepHours.compareTo(BigDecimal.ZERO) < 0 || sleepHours.compareTo(new BigDecimal("24")) > 0) { if (sleepHours == null || sleepHours.compareTo(BigDecimal.ZERO) < 0 || sleepHours.compareTo(new BigDecimal("24")) > 0) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "sleepHours must be between 0 and 24"); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "sleepHours must be between 0 and 24");

View File

@@ -0,0 +1,7 @@
ALTER TABLE daily_checkins
ADD COLUMN IF NOT EXISTS fajr BOOLEAN,
ADD COLUMN IF NOT EXISTS quran BOOLEAN,
ADD COLUMN IF NOT EXISTS exercise BOOLEAN,
ADD COLUMN IF NOT EXISTS duties BOOLEAN,
ADD COLUMN IF NOT EXISTS zikr BOOLEAN,
ADD COLUMN IF NOT EXISTS salah BOOLEAN;