Skip to content
Snippets Groups Projects
Commit ad57ceb5 authored by Lukas Karsch's avatar Lukas Karsch
Browse files

#3

createdAt date in GardenEntry works now. Sort feature implementation started. Started work on custom query to calculate next possible Plant / harvest date (garden service). More plants in CommandLineRunner
parent f1e13b4d
No related branches found
No related tags found
1 merge request!12#3 merge fully implemented garden branch into main
### Get all plants ### Get all plants
GET http://localhost:8080/api/v1/plants GET http://localhost:8080/api/v1/plants
\ No newline at end of file
### Garden
### Add plant to garden
POST http://localhost:8080/api/v1/garden/add/1
### Get plants from garden
GET http://localhost:8080/api/v1/garden/
### Get plants from garden, sort
GET http://localhost:8080/api/v1/garden/?sort=harvestDate
\ No newline at end of file
...@@ -9,9 +9,13 @@ import org.springframework.boot.CommandLineRunner; ...@@ -9,9 +9,13 @@ import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import java.util.List;
@SpringBootApplication @SpringBootApplication
@EnableJpaAuditing
public class GrowBrosApplication { public class GrowBrosApplication {
private static final Logger log = LoggerFactory.getLogger(GrowBrosApplication.class); private static final Logger log = LoggerFactory.getLogger(GrowBrosApplication.class);
...@@ -22,15 +26,19 @@ public class GrowBrosApplication { ...@@ -22,15 +26,19 @@ public class GrowBrosApplication {
@Bean @Bean
public CommandLineRunner plants(PlantsService plantsService) { public CommandLineRunner plants(PlantsService plantsService) {
return (args) -> { return (args) -> {
String jsonString = """ List<String> json = List.of("""
{"name":"Salat (Gartensalat)","latinName":"Lactuca sativa var. crispa","growingTips":"Salate eignen sich sehr gut als ‚Lückenfüller‘. Sie benötigen ausreichend Feuchtigkeit und haben einen vergleichsweise geringen Nährstoffbedarf. Durch eine geschickte Auswahl lassen sich Salate das ganze Jahr über anbauen: im Frühjahr und Frühsommer Kopf- und Schnitt-/Pflücksalate; im Sommer und Herbst Zichoriensalate und Eissalate sowie Feldsalat (v.a. im Herbst, Winter). Für eine kontinuierliche Ernte am besten in zeitlichen Abständen säen bzw. pflanzen. Arten und Sorten müssen dabei an die jeweilige Jahreszeit angepasst sein, z.B. beginnen Frühjahrssorten bei zu viel Hitze zu schießen. Dabei bildet sich ein langer Stiel und die Blätter werden bitter. Nach einigen Wochen kommen oben kleine Blüten zum Vorschein, woraus sich viele halbmondförmige Samen bilden. Diese können für das Folgejahr abgesammelt werden oder verteilen sich selbst im Beet, wenn du sie stehen lässt.\\n","description":"Salat steht als Überbegriff für viele Blattgemüse. Kopfsalate bilden - wie der Name schon sagt - einen Kopf und werden am Stück geerntet. Pflücksalate kann man kontinuierlich ernten, wenn man jeweils nur einzelne Blätter abpflückt. ","origin":"Gartensalate sind gezüchtete Lattichgewächse (Lactuca sativa) mit Urpsrung in Südeuropa, Nordafrika und Indien. Darunter fallen Kopfsalate (Batavia, Eissalat), Schnitt-/Pflücksalate (Lollo Rosso/Bionda, Eichblatt) und Römersalate.","plantWeekStart":12,"plantWeekEnd":35,"harvestWeekStart":15,"harvestWeekEnd":44,"growthDuration":6,"nutrientDemand":"MEDIUM","lightingDemand":"MEDIUM","waterDemand":"WET","groundType":null,"imageUrl":"https://d3t240q2dksnz7.cloudfront.net/a4cbb94a099179235fdd5696ae5f3833.jpg"} {"name":"Salat (Gartensalat)","latinName":"Lactuca sativa var. crispa","growingTips":"Salate eignen sich sehr gut als ‚Lückenfüller‘. Sie benötigen ausreichend Feuchtigkeit und haben einen vergleichsweise geringen Nährstoffbedarf. Durch eine geschickte Auswahl lassen sich Salate das ganze Jahr über anbauen: im Frühjahr und Frühsommer Kopf- und Schnitt-/Pflücksalate; im Sommer und Herbst Zichoriensalate und Eissalate sowie Feldsalat (v.a. im Herbst, Winter). Für eine kontinuierliche Ernte am besten in zeitlichen Abständen säen bzw. pflanzen. Arten und Sorten müssen dabei an die jeweilige Jahreszeit angepasst sein, z.B. beginnen Frühjahrssorten bei zu viel Hitze zu schießen. Dabei bildet sich ein langer Stiel und die Blätter werden bitter. Nach einigen Wochen kommen oben kleine Blüten zum Vorschein, woraus sich viele halbmondförmige Samen bilden. Diese können für das Folgejahr abgesammelt werden oder verteilen sich selbst im Beet, wenn du sie stehen lässt.\\n","description":"Salat steht als Überbegriff für viele Blattgemüse. Kopfsalate bilden - wie der Name schon sagt - einen Kopf und werden am Stück geerntet. Pflücksalate kann man kontinuierlich ernten, wenn man jeweils nur einzelne Blätter abpflückt. ","origin":"Gartensalate sind gezüchtete Lattichgewächse (Lactuca sativa) mit Urpsrung in Südeuropa, Nordafrika und Indien. Darunter fallen Kopfsalate (Batavia, Eissalat), Schnitt-/Pflücksalate (Lollo Rosso/Bionda, Eichblatt) und Römersalate.","plantWeekStart":12,"plantWeekEnd":35,"harvestWeekStart":15,"harvestWeekEnd":44,"growthDuration":6,"nutrientDemand":"MEDIUM","lightingDemand":"MEDIUM","waterDemand":"WET","groundType":null,"imageUrl":"https://d3t240q2dksnz7.cloudfront.net/a4cbb94a099179235fdd5696ae5f3833.jpg"}
"""; """, """
{"name":"Kirschgroße gelbe Traube","latinName":"","description":"Ein Massenträger mit gigantischen Klumpentrauben von teils mehr als 100 Früchten.Nahezu kirschgroß, gelb, leicht oval und gut platzfest. Saftig würzig und süß schmeckend. Vermutlich Verbesserung einer Wildform.\\nÜber 2m hoch wachsend. Gleicht etwas 'Aurianticum' und 'Mirabell Gelb'. Relativ früh reifend.","origin":null,"plantWeekStart":20,"plantWeekEnd":22,"harvestWeekStart":26,"harvestWeekEnd":41,"growthDuration":12.5,"nutrientDemand":null,"lightingDemand":null,"waterDemand":null,"groundType":null,"imageUrl":"https://d3t240q2dksnz7.cloudfront.net/a214162d7e999d9fbb19ab75c69a0bdf.jpg"}
""");
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
try { try {
Plant plant = objectMapper.readValue(jsonString, Plant.class); for (String s : json) {
plantsService.createPlant(plant); Plant plant = objectMapper.readValue(s, Plant.class);
plantsService.createPlant(plant);
}
log.info("Saved mock plants"); log.info("Saved mock plants");
} catch (Exception e) { } catch (Exception e) {
log.error(e.getMessage()); log.error(e.getMessage());
......
package hdm.mi.growbros.controllers; package hdm.mi.growbros.controllers;
import hdm.mi.growbros.models.GardenEntry; import hdm.mi.growbros.models.plant.Plant;
import hdm.mi.growbros.service.GardenService; import hdm.mi.growbros.service.GardenService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
...@@ -14,9 +14,13 @@ public class GardenController { ...@@ -14,9 +14,13 @@ public class GardenController {
private final GardenService gardenService; private final GardenService gardenService;
@GetMapping("/") @GetMapping("/")
public List<GardenEntry> getPlantsInGarden(@RequestParam(value = "sort", required = false) String sort) { public List<Plant> getPlantsInGarden(@RequestParam(value = "sort", required = false) String sort) {
//TODO: get the user by adding (Authentication authentication) as params
/*
* Sort: name of plants, added to list on, next possible planting date, next possible harvest
*/
System.out.println(sort); System.out.println(sort);
return null; return gardenService.getUserPlants(0L, sort);
} }
@PostMapping("/add/{plantId}") @PostMapping("/add/{plantId}")
......
package hdm.mi.growbros.models; package hdm.mi.growbros.models;
import hdm.mi.growbros.models.plant.Plant; import hdm.mi.growbros.models.plant.Plant;
import jakarta.persistence.Entity; import jakarta.persistence.*;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime; import java.util.Date;
@Entity @Entity
@EntityListeners(AuditingEntityListener.class)
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
...@@ -27,6 +26,6 @@ public class GardenEntry { ...@@ -27,6 +26,6 @@ public class GardenEntry {
// @ManyToOne(optional = false) // @ManyToOne(optional = false)
// private User user; // private User user;
@LastModifiedDate @CreatedDate
private LocalDateTime modifiedAt; private Date createdAt;
} }
...@@ -2,8 +2,17 @@ package hdm.mi.growbros.repositories; ...@@ -2,8 +2,17 @@ package hdm.mi.growbros.repositories;
import hdm.mi.growbros.models.GardenEntry; import hdm.mi.growbros.models.GardenEntry;
import org.springframework.data.jpa.repository.JpaRepository; 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.springframework.stereotype.Repository;
import java.util.List;
@Repository @Repository
public interface GardenRepository extends JpaRepository<GardenEntry, Long> { public interface GardenRepository extends JpaRepository<GardenEntry, Long> {
@Query("""
SELECT e FROM GardenEntry e
ORDER BY ABS(:week - e.plant.harvestWeekStart) ASC
""")
List<GardenEntry> findNearestHarvestWeek(@Param("week") int currentWeek);
} }
...@@ -4,6 +4,9 @@ import hdm.mi.growbros.models.plant.Plant; ...@@ -4,6 +4,9 @@ import hdm.mi.growbros.models.plant.Plant;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List;
@Repository @Repository
public interface PlantRepository extends JpaRepository<Plant, Long> { public interface PlantRepository extends JpaRepository<Plant, Long> {
List<Plant> findByNameIsLike(String name);
} }
...@@ -6,9 +6,11 @@ import hdm.mi.growbros.models.plant.Plant; ...@@ -6,9 +6,11 @@ import hdm.mi.growbros.models.plant.Plant;
import hdm.mi.growbros.repositories.GardenRepository; import hdm.mi.growbros.repositories.GardenRepository;
import hdm.mi.growbros.repositories.PlantRepository; import hdm.mi.growbros.repositories.PlantRepository;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collection;
import java.util.List;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
...@@ -16,12 +18,14 @@ public class GardenService { ...@@ -16,12 +18,14 @@ public class GardenService {
private final GardenRepository gardenRepository; private final GardenRepository gardenRepository;
private final PlantRepository plantRepository; private final PlantRepository plantRepository;
public Collection<Plant> getUserPlants(Long userId) { public List<Plant> getUserPlants(Long userId, String sort) {
return gardenRepository if (sort == null) return getAllPlantsOrderedByName();
.findAll() return switch (sort) {
.stream() case "createdAt" -> getAllPlantsOrderedByCreatedDate();
.map(GardenEntry::getPlant) case "plantDate" -> getALlPlantsOrderedByNextPossiblePlantDate();
.toList(); case "harvestDate" -> getALlPlantsOrderedByNextPossibleHarvest();
default -> getAllPlantsOrderedByName();
};
} }
public void addPlantToGarden(Long plantId, Long userId) { public void addPlantToGarden(Long plantId, Long userId) {
...@@ -33,12 +37,53 @@ public class GardenService { ...@@ -33,12 +37,53 @@ public class GardenService {
} }
public void removeFromGarden(Long entryId) { public void removeFromGarden(Long entryId) {
//TODO: only allow this if the authenticated user created the entry
gardenRepository.deleteById(entryId); gardenRepository.deleteById(entryId);
} }
public Long clearGarden() { public Long clearGarden() {
//TODO: this needs to be filtered by user
Long deleted = gardenRepository.count(); Long deleted = gardenRepository.count();
gardenRepository.deleteAll(); gardenRepository.deleteAll();
return deleted; return deleted;
} }
private List<Plant> getAllPlantsOrderedByName() {
return mapGardenEntriesToPlants(
gardenRepository.findAll(Sort.by("plant.name"))
);
}
private List<Plant> getAllPlantsOrderedByCreatedDate() {
return mapGardenEntriesToPlants(
gardenRepository.findAll(Sort.by("createdDate"))
);
}
private List<Plant> getALlPlantsOrderedByNextPossiblePlantDate() {
return null;
}
private List<Plant> getALlPlantsOrderedByNextPossibleHarvest() {
return mapGardenEntriesToPlants(
gardenRepository.findNearestHarvestWeek(10)
);
}
private List<Plant> mapGardenEntriesToPlants(Collection<GardenEntry> entries) {
return entries
.stream()
.map(GardenEntry::getPlant)
.toList();
}
private Sort getSort(String sort) {
if (sort == null) return Sort.by("plant.name");
return switch (sort) {
case "createdAt" -> Sort.by("createdAt");
case "harvestDate" -> Sort.by("plant.harvestWeekStart");
case "plantDate" -> Sort.by("plant.plantWeekStart");
default -> Sort.by("plant.name");
};
}
} }
...@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory; ...@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collection;
import java.util.List;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
...@@ -24,4 +25,8 @@ public class PlantsService { ...@@ -24,4 +25,8 @@ public class PlantsService {
log.info("Saving plant '{}' to repository.", plant.getName()); log.info("Saving plant '{}' to repository.", plant.getName());
plantRepository.save(plant); plantRepository.save(plant);
} }
public List<Plant> search(String search) {
return plantRepository.findByNameIsLike(search);
}
} }
package hdm.mi.growbros.util;
import java.time.LocalDate;
import java.time.temporal.ChronoField;
public class DateTimeUtils {
public static int getCurrentWeekForToday() {
return getCurrentWeekFromDate(LocalDate.now());
}
public static int getCurrentWeekFromDate(LocalDate date) {
return date.get(ChronoField.ALIGNED_WEEK_OF_YEAR);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment