Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Thumbnail, new schema offers, enable changing visibility #25

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/java/com/example/backend/common/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
public enum ErrorCode {

APPLICATION_SETTING_NOT_FOUND("APPLICATION_SETTING_NOT_FOUND"),
CAR_IDS_REQUIRED("CAR_IDS_REQUIRED"),
INPUT_DATA_INVALID("INPUT_DATA_INVALID"),
SCHEME_DATA_INVALID("SCHEME_DATA_INVALID"),
SCHEME_DATA_REQUIRED("SCHEME_DATA_REQUIRED"),
SCHEME_NOT_FOUND("SCHEME_NOT_FOUND"),
SCHEME_NAME_REQUIRED("SCHEME_NAME_REQUIRED"),
STATUS_NOT_ALLOWED("STATUS_NOT_ALLOWED"),
USER_NOT_FOUND("USER_NOT_FOUND");

private String message;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/example/backend/scheme/CarStatus.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

public enum CarStatus {

FIRST_INITIALIZATION, NEW, DISPLAYED;
NEW, SEEN, FIRST_INITIALIZATION;

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@
import com.example.backend.page.TableDto;
import com.example.backend.exception.exceptions.EntityNotFoundException;
import com.example.backend.exception.exceptions.IllegalInputException;
import com.example.backend.scheme.dto.SchemeDisplayDto;
import com.example.backend.scheme.dto.SchemeDto;
import com.example.backend.scheme.dto.SchemeToCarDto;
import com.example.backend.scheme.serializer.SchemeSerializer;
import com.example.backend.scheme.service.SchemeService;
import com.example.backend.common.UserEmail;
import com.example.backend.scheme.model.Scheme;
import com.example.backend.scheme.service.SchemeToCarService;
import jakarta.validation.Valid;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.example.backend.scheme.serializer.SchemeSerializer.Task.BASE;
import static com.example.backend.scheme.serializer.SchemeSerializer.Task.CARS;
Expand All @@ -25,9 +30,11 @@
public class SchemeController {

private final SchemeService schemeService;
private final SchemeToCarService schemeToCarService;

public SchemeController(SchemeService schemeService) {
public SchemeController(SchemeService schemeService, SchemeToCarService schemeToCarService) {
this.schemeService = schemeService;
this.schemeToCarService = schemeToCarService;
}

@GetMapping
Expand All @@ -37,7 +44,11 @@ public TableDto<List<SchemeDto>> list(@UserEmail String email, Pageable pageable
PageSerializer.fromPageable(pageDto, pageable);
PageSerializer.fromPage(pageDto, schemas);

return new TableDto<>(pageDto, schemas.stream().map((scheme -> SchemeSerializer.serialize(scheme, BASE))).toList());
List<SchemeDto> schemeDtoList = new ArrayList<>(schemas.stream()
.map((scheme -> SchemeSerializer.serialize(scheme, BASE))).toList());
schemeService.checkNewOffersCount(schemeDtoList);

return new TableDto<>(pageDto, schemeDtoList);
}

@GetMapping("{id}")
Expand Down Expand Up @@ -65,4 +76,9 @@ public void delete(@UserEmail String email, @PathVariable("id") Long id) throws
schemeService.delete(id, email);
}

@PutMapping("visibility")
public List<SchemeToCarDto> changeVisibility(@RequestBody @Valid SchemeDisplayDto schemeDisplayDto) throws IllegalInputException {
return schemeToCarService.changeVisibility(schemeDisplayDto).stream().map(SchemeSerializer::schemeToCar).collect(Collectors.toList());
}

}
32 changes: 32 additions & 0 deletions src/main/java/com/example/backend/scheme/dto/SchemeDisplayDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.backend.scheme.dto;

import com.example.backend.scheme.CarStatus;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.Set;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class SchemeDisplayDto {

private Set<Long> ids;

private CarStatus status;

public Set<Long> getIds() {
return ids;
}

public void setIds(Set<Long> ids) {
this.ids = ids;
}

public CarStatus getStatus() {
return status;
}

public void setStatus(CarStatus status) {
this.status = status;
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/example/backend/scheme/dto/SchemeDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public class SchemeDto {
private Set<FilterValueDto> variables;
private UserDto user;
private Boolean notifications;
private String thumbnail;
private Boolean newOffers;
private List<SchemeToCarDto> cars;

public Long getId() {
Expand Down Expand Up @@ -77,4 +79,20 @@ public Boolean getNotifications() {
public void setNotifications(Boolean notifications) {
this.notifications = notifications;
}

public String getThumbnail() {
return thumbnail;
}

public void setThumbnail(String thumbnail) {
this.thumbnail = thumbnail;
}

public Boolean getNewOffers() {
return newOffers;
}

public void setNewOffers(Boolean newOffers) {
this.newOffers = newOffers;
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/example/backend/scheme/model/Scheme.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public class Scheme {
@Column(nullable = false)
private boolean notifications;

@Column(length = 512)
private String thumbnail;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;
Expand Down Expand Up @@ -77,4 +80,11 @@ public void setNotifications(boolean notifications) {
this.notifications = notifications;
}

public String getThumbnail() {
return thumbnail;
}

public void setThumbnail(String defaultThumbnail) {
this.thumbnail = defaultThumbnail;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.example.backend.scheme.repository;

import com.example.backend.scheme.model.Scheme;
import jakarta.transaction.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
Expand All @@ -14,4 +18,15 @@ public interface SchemeRepository extends JpaRepository<Scheme, Long> {

Page<Scheme> findAllByUserEmail(String email, Pageable pageable);

@Transactional
@Modifying
@Query("UPDATE Scheme s SET s.thumbnail = :thumbnail WHERE s.id = :id")
void updateSchemeById(@Param("id") Long id, @Param("thumbnail") String thumbnail);

@Query("SELECT s.id AS schemeId, CASE WHEN COUNT(stc.id) > 0 THEN true ELSE false END AS hasNewCars " +
"FROM Scheme s LEFT JOIN SchemeToCar stc ON s.id = stc.scheme.id " +
"AND stc.status IN(com.example.backend.scheme.CarStatus.NEW, com.example.backend.scheme.CarStatus.FIRST_INITIALIZATION) " +
"WHERE s.id IN :schemaIds GROUP BY s.id")
List<Object[]> haveNewCars(@Param("schemaIds") List<Long> schemaIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Set;

public interface SchemeToCarRepository extends JpaRepository<SchemeToCar, Long> {

List<SchemeToCar> findAllBySchemeId(Long id);

Page<SchemeToCar> findBySchemeId(Long id, Pageable pageable);

Set<SchemeToCar> findAllByIdIn(@Param("ids") Set<Long> ids);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.example.backend.scheme.dto.SchemeToCarDto;
import com.example.backend.scheme.dto.SchemeDto;
import com.example.backend.scheme.model.Scheme;
import com.example.backend.scheme.model.SchemeToCar;
import com.example.backend.timer.otomoto.request.FilterValueDto;
import com.example.backend.timer.otomoto.request.OtomotoDto;
import com.example.backend.timer.otomoto.request.VariablesDto;
Expand Down Expand Up @@ -43,6 +44,7 @@ private static void base(SchemeDto schemeDto, Scheme scheme) {
schemeDto.setId(scheme.getId());
schemeDto.setName(scheme.getName());
schemeDto.setNotifications(scheme.isNotifications());
schemeDto.setThumbnail(scheme.getThumbnail());
try {
OtomotoDto otomotoDto = OBJECT_MAPPER.readValue(scheme.getData(), OtomotoDto.class);
Set<FilterValueDto> filterList = Optional.ofNullable(otomotoDto).map(OtomotoDto::getVariables)
Expand All @@ -60,21 +62,21 @@ private static void user(SchemeDto schemeDto, Scheme scheme) {
}

private static void cars(SchemeDto schemeDto, Scheme scheme) {
List<SchemeToCarDto> cars = scheme.getSchemeToCars().stream().map((schemeToCar -> {
SchemeToCarDto schemeToCarDto = new SchemeToCarDto();
schemeToCarDto.setId(schemeToCar.getId());
schemeToCarDto.setCarId(schemeToCar.getCarId());
schemeToCarDto.setCreatedAt(schemeToCar.getCreatedAt());
try {
schemeToCarDto.setData(OBJECT_MAPPER.readValue(schemeToCar.getData(), NodeDto.class));
} catch (JsonProcessingException e) {
LOGGER.error("Error parsing SchemeToCar {} data!", schemeToCar.getId());
}
schemeToCarDto.setStatus(schemeToCar.getStatus());
return schemeToCarDto;
})).toList();

schemeDto.setCars(cars);
schemeDto.setCars(scheme.getSchemeToCars().stream().map(SchemeSerializer::schemeToCar).toList());
}

public static SchemeToCarDto schemeToCar(SchemeToCar schemeToCar) {
SchemeToCarDto schemeToCarDto = new SchemeToCarDto();
schemeToCarDto.setId(schemeToCar.getId());
schemeToCarDto.setCarId(schemeToCar.getCarId());
schemeToCarDto.setCreatedAt(schemeToCar.getCreatedAt());
try {
schemeToCarDto.setData(OBJECT_MAPPER.readValue(schemeToCar.getData(), NodeDto.class));
} catch (JsonProcessingException e) {
LOGGER.error("Error parsing SchemeToCar {} data!", schemeToCar.getId());
}
schemeToCarDto.setStatus(schemeToCar.getStatus());
return schemeToCarDto;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,19 @@ public String getTimerQuery() throws EntityNotFoundException {
}
}

public void checkNewOffersCount(List<SchemeDto> schemeDtoList) {
if (schemeDtoList.isEmpty()) return;

List<Object[]> results = schemeRepository.haveNewCars(schemeDtoList.stream().map(SchemeDto::getId).toList());

schemeDtoList.forEach(schemeDto -> {
results.stream()
.filter(result -> result[0] == schemeDto.getId())
.findFirst()
.ifPresent(result -> schemeDto.setNewOffers((Boolean) result[1]));
});
}

/**
* Prepare dto which will be sent to otomoto REST API
* and run loop searching for new cars.
Expand Down Expand Up @@ -274,6 +287,7 @@ private TimerResponse calculatePageWithOtomotoData(Scheme scheme, OtomotoRespons
// Save all new cars into the database
boolean firstInitialization = scheme.getSchemeToCars().isEmpty();
saveNewCarsToDatabase(carIdToNodeDtoMap, scheme, firstInitialization);
updateDefaultThumbnail(scheme);

if (firstInitialization)
return new TimerResponse(true, diff.size());
Expand Down Expand Up @@ -337,6 +351,39 @@ private void sendNotification(Scheme scheme, Integer count) {
}
}

private void updateDefaultThumbnail(Scheme scheme) {
if (!isNullOrEmpty(scheme.getThumbnail())) return;

List<SchemeToCar> schemeToCars = scheme.getSchemeToCars().stream()
.sorted(Comparator.comparing(SchemeToCar::getCreatedAt)).toList();
String defaultThumbnail = null;

for (SchemeToCar schemeToCar : schemeToCars) {
String thumbnail = getThumbnail(schemeToCar);
if (thumbnail != null) {
defaultThumbnail = thumbnail;
break;
}
}

schemeRepository.updateSchemeById(scheme.getId(), defaultThumbnail);
}

private String getThumbnail(SchemeToCar schemeToCar) {
try {
NodeDto schemeData = OBJECT_MAPPER.readValue(schemeToCar.getData(), NodeDto.class);

return Optional.ofNullable(schemeData)
.map(NodeDto::getThumbnail)
.flatMap(thumbnailDto -> Optional.ofNullable(thumbnailDto.getX2()).filter(set -> !set.isEmpty())
.or(() -> Optional.ofNullable(thumbnailDto.getX1())))
.orElse(null);
} catch (JsonProcessingException e) {
LOGGER.error("[{}] There was an error while parsing data.", TIMER_NAME, e);
return null;
}
}

private static class TimerResponse {

private final boolean shouldFinish;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.backend.scheme.service;

import com.example.backend.common.ErrorCode;
import com.example.backend.exception.exceptions.IllegalInputException;
import com.example.backend.scheme.CarStatus;
import com.example.backend.scheme.dto.SchemeDisplayDto;
import com.example.backend.scheme.model.SchemeToCar;
import com.example.backend.scheme.repository.SchemeToCarRepository;
import org.springframework.stereotype.Service;

import java.util.Set;

@Service
public class SchemeToCarService {

private final SchemeToCarRepository schemeToCarRepository;

public SchemeToCarService(SchemeToCarRepository schemeToCarRepository) {
this.schemeToCarRepository = schemeToCarRepository;
}

public Set<SchemeToCar> changeVisibility(SchemeDisplayDto schemeDisplayDto) throws IllegalInputException {
CarStatus status = schemeDisplayDto.getStatus();
Set<Long> schemeToCarIds = schemeDisplayDto.getIds();

if (status == null || CarStatus.FIRST_INITIALIZATION.equals(status))
throw new IllegalInputException(ErrorCode.STATUS_NOT_ALLOWED);

if (schemeToCarIds == null || schemeToCarIds.isEmpty())
throw new IllegalInputException(ErrorCode.CAR_IDS_REQUIRED);

Set<SchemeToCar> schemeToCars = schemeToCarRepository.findAllByIdIn(schemeToCarIds);
for (SchemeToCar schemeToCar : schemeToCars)
schemeToCar.setStatus(status);

schemeToCarRepository.saveAll(schemeToCars);
return schemeToCars;
}

}