Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Jacob Salvi 2020-04-28 08:27:51 +02:00
commit 36c921320b
15 changed files with 208 additions and 32 deletions

View file

@ -1,5 +1,6 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config; package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.AutomationFastUpdateRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableState; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DimmableState;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.State;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableState; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SwitchableState;
@ -30,7 +31,18 @@ public class GsonConfig {
RuntimeTypeAdapterFactory.of(State.class, "kind") RuntimeTypeAdapterFactory.of(State.class, "kind")
.registerSubtype(SwitchableState.class, "switchableState") .registerSubtype(SwitchableState.class, "switchableState")
.registerSubtype(DimmableState.class, "dimmableState"); .registerSubtype(DimmableState.class, "dimmableState");
RuntimeTypeAdapterFactory<AutomationFastUpdateRequest.TriggerDTO>
runtimeTypeAdapterFactoryII =
RuntimeTypeAdapterFactory.of(
AutomationFastUpdateRequest.TriggerDTO.class, "kind")
.registerSubtype(
AutomationFastUpdateRequest.BooleanTriggerDTO.class,
"booleanTrigger")
.registerSubtype(
AutomationFastUpdateRequest.RangeTriggerDTO.class,
"rangeTrigger");
builder.registerTypeAdapterFactory(runtimeTypeAdapterFactory); builder.registerTypeAdapterFactory(runtimeTypeAdapterFactory);
builder.registerTypeAdapterFactory(runtimeTypeAdapterFactoryII);
return builder; return builder;
} }

View file

@ -82,6 +82,7 @@ public class SpringFoxConfig {
.or(PathSelectors.regex("/motionSensor.*")::apply) .or(PathSelectors.regex("/motionSensor.*")::apply)
.or(PathSelectors.regex("/curtains.*")::apply) .or(PathSelectors.regex("/curtains.*")::apply)
.or(PathSelectors.regex("/user.*")::apply) .or(PathSelectors.regex("/user.*")::apply)
.or(PathSelectors.regex("/automation.*")::apply)
.or(PathSelectors.regex("/auth/profile.*")::apply); .or(PathSelectors.regex("/auth/profile.*")::apply);
} }

View file

@ -1,14 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.AutomationFastUpdateRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.AutomationSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.AutomationSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Automation; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.AutomationRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ScenePriorityRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.SceneRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -28,8 +26,8 @@ import org.springframework.web.bind.annotation.RestController;
public class AutomationController { public class AutomationController {
@Autowired private AutomationRepository automationRepository; @Autowired private AutomationRepository automationRepository;
@Autowired private SceneRepository sceneRepository; @Autowired private ScenePriorityRepository sceneRepository;
@Autowired private ScenePriorityRepository scenePriorityRepository; @Autowired private TriggerRepository<Trigger<?>> triggerRepository;
@Autowired private UserRepository userService; @Autowired private UserRepository userService;
@GetMapping @GetMapping
@ -73,6 +71,46 @@ public class AutomationController {
principal); principal);
} }
@PutMapping("/fast")
public Automation fastUpdate(
@Valid @RequestBody AutomationFastUpdateRequest req, Principal principal)
throws NotFoundException {
final Automation a =
automationRepository
.findByIdAndUserId(
req.getId(),
userService.findByUsername(principal.getName()).getId())
.orElseThrow(NotFoundException::new);
a.setName(req.getName());
automationRepository.save(a);
triggerRepository.deleteAllByAutomationId(a.getId());
sceneRepository.deleteAllByAutomationId(a.getId());
Iterable<Trigger<?>> tt =
triggerRepository.saveAll(
req.getTriggers()
.stream()
.map(AutomationFastUpdateRequest.TriggerDTO::toModel)
.map(t -> t.setAutomationId(a.getId()))
.collect(Collectors.toList()));
Iterable<ScenePriority> ss =
sceneRepository.saveAll(
req.getScenes()
.stream()
.map(AutomationFastUpdateRequest.ScenePriorityDTO::toModel)
.map(t -> t.setAutomationId(a.getId()))
.collect(Collectors.toList()));
a.getScenes().clear();
a.getTriggers().clear();
ss.forEach(t -> a.getScenes().add(t));
tt.forEach(t -> a.getTriggers().add(t));
return a;
}
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable long id) { public void delete(@PathVariable long id) {
automationRepository.deleteById(id); automationRepository.deleteById(id);

View file

@ -29,6 +29,7 @@ public class ThermostatController {
newT.setId(t.getId()); newT.setId(t.getId());
newT.setName(t.getName()); newT.setName(t.getName());
newT.setRoomId(t.getRoomId()); newT.setRoomId(t.getRoomId());
newT.setMeasuredTemperature(t.getMeasuredTemperature());
newT.setUseExternalSensors(t.isUseExternalSensors()); newT.setUseExternalSensors(t.isUseExternalSensors());
newT.setOn(t.isTurnOn()); newT.setOn(t.isTurnOn());

View file

@ -0,0 +1,97 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.BooleanTrigger;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RangeTrigger;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.ScenePriority;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Trigger;
import java.util.List;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
public class AutomationFastUpdateRequest {
public abstract static class TriggerDTO {
@NotNull public long deviceId;
public abstract Trigger<?> toModel();
}
public static class BooleanTriggerDTO extends TriggerDTO {
@NotNull public boolean on;
@Override
public Trigger<?> toModel() {
BooleanTrigger<?> t = new BooleanTrigger<>();
t.setDeviceId(this.deviceId);
t.setOn(this.on);
return t;
}
}
public static class RangeTriggerDTO extends TriggerDTO {
@NotNull RangeTrigger.Operator operator;
@NotNull double range;
@Override
public Trigger<?> toModel() {
RangeTrigger<?> t = new RangeTrigger<>();
t.setDeviceId(this.deviceId);
t.setOperator(this.operator);
t.setRange(this.range);
return t;
}
}
public static class ScenePriorityDTO {
@NotNull public long sceneId;
@NotNull
@Min(0)
public Integer priority;
public ScenePriority toModel() {
ScenePriority s = new ScenePriority();
s.setSceneId(sceneId);
s.setPriority(priority);
return s;
}
}
@NotNull private List<ScenePriorityDTO> scenes;
@NotNull private List<TriggerDTO> triggers;
@NotNull private long id;
@NotNull @NotEmpty private String name;
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ScenePriorityDTO> getScenes() {
return scenes;
}
public void setScenes(List<ScenePriorityDTO> scenes) {
this.scenes = scenes;
}
public List<TriggerDTO> getTriggers() {
return triggers;
}
public void setTriggers(List<TriggerDTO> triggers) {
this.triggers = triggers;
}
public void setId(long id) {
this.id = id;
}
}

View file

@ -22,6 +22,8 @@ public class ThermostatSaveRequest {
@NotNull private boolean useExternalSensors; @NotNull private boolean useExternalSensors;
@NotNull private BigDecimal measuredTemperature;
/** State of this thermostat */ /** State of this thermostat */
@NotNull private boolean turnOn; @NotNull private boolean turnOn;
@ -72,4 +74,12 @@ public class ThermostatSaveRequest {
public void setId(long id) { public void setId(long id) {
this.id = id; this.id = id;
} }
public BigDecimal getMeasuredTemperature() {
return measuredTemperature;
}
public void setMeasuredTemperature(BigDecimal measuredTemperature) {
this.measuredTemperature = measuredTemperature;
}
} }

View file

@ -28,11 +28,9 @@ public class Automation {
private Long userId; private Long userId;
@OneToMany(mappedBy = "automation", orphanRemoval = true) @OneToMany(mappedBy = "automation", orphanRemoval = true)
@GsonExclude
private Set<Trigger<?>> triggers = new HashSet<>(); private Set<Trigger<?>> triggers = new HashSet<>();
@OneToMany(mappedBy = "automation", cascade = CascadeType.REMOVE) @OneToMany(mappedBy = "automation", cascade = CascadeType.REMOVE)
@GsonExclude
private Set<ScenePriority> scenes = new HashSet<>(); private Set<ScenePriority> scenes = new HashSet<>();
@NotNull @NotEmpty private String name; @NotNull @NotEmpty private String name;
@ -53,6 +51,10 @@ public class Automation {
return scenes; return scenes;
} }
public Set<Trigger<?>> getTriggers() {
return triggers;
}
public String getName() { public String getName() {
return name; return name;
} }

View file

@ -1,10 +1,15 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.List; import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
public interface AutomationRepository extends CrudRepository<Automation, Long> { public interface AutomationRepository extends CrudRepository<Automation, Long> {
@EntityGraph(attributePaths = {"scenes", "triggers"})
List<Automation> findAllByUserId(@Param("userId") long userId); List<Automation> findAllByUserId(@Param("userId") long userId);
@EntityGraph(attributePaths = {"scenes", "triggers"})
Optional<Automation> findByIdAndUserId(@Param("id") long id, @Param("userId") long userId);
} }

View file

@ -9,6 +9,10 @@ public class BooleanTrigger<D extends Device & BooleanTriggerable> extends Trigg
@Column(name = "switchable_on") @Column(name = "switchable_on")
private boolean on; private boolean on;
public BooleanTrigger() {
super("booleanTrigger");
}
public boolean isOn() { public boolean isOn() {
return on; return on;
} }

View file

@ -8,6 +8,10 @@ import javax.validation.constraints.NotNull;
@Entity @Entity
public class RangeTrigger<D extends Device & RangeTriggerable> extends Trigger<D> { public class RangeTrigger<D extends Device & RangeTriggerable> extends Trigger<D> {
public RangeTrigger() {
super("rangeTrigger");
}
@Override @Override
public boolean triggered() { public boolean triggered() {
double value = getDevice().readTriggerState(); double value = getDevice().readTriggerState();

View file

@ -65,8 +65,9 @@ public class ScenePriority {
return automationId; return automationId;
} }
public void setAutomationId(Long automationId) { public ScenePriority setAutomationId(Long automationId) {
this.automationId = automationId; this.automationId = automationId;
return this;
} }
public Scene getScene() { public Scene getScene() {

View file

@ -1,6 +1,7 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.List; import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
@ -8,7 +9,11 @@ public interface ScenePriorityRepository extends CrudRepository<ScenePriority, L
List<ScenePriority> findAllBySceneId(@Param("sceneId") long sceneId); List<ScenePriority> findAllBySceneId(@Param("sceneId") long sceneId);
@Transactional
void deleteBySceneId(@Param("sceneId") long sceneId); void deleteBySceneId(@Param("sceneId") long sceneId);
List<ScenePriority> findAllByAutomationId(@Param("automationId") long automationId); List<ScenePriority> findAllByAutomationId(@Param("automationId") long automationId);
@Transactional
void deleteAllByAutomationId(Long automationId);
} }

View file

@ -1,14 +1,9 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.SocketGsonExclude;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.OneToMany;
import javax.persistence.Transient; import javax.persistence.Transient;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@ -86,11 +81,6 @@ public class Thermostat extends Switchable implements BooleanTriggerable {
@Column private boolean useExternalSensors = false; @Column private boolean useExternalSensors = false;
@OneToMany(mappedBy = "scene", orphanRemoval = true)
@GsonExclude
@SocketGsonExclude
private Set<BooleanTrigger<? extends Device>> triggers = new HashSet<>();
/** Creates a thermostat with a temperature sensor and its initial OFF state */ /** Creates a thermostat with a temperature sensor and its initial OFF state */
public Thermostat() { public Thermostat() {
super("thermostat"); super("thermostat");

View file

@ -2,22 +2,23 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import javax.persistence.Column; import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PreRemove;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
@Entity @Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Trigger<D extends Device> { public abstract class Trigger<D extends Device> {
@Transient private String kind;
protected Trigger(String kind) {
this.kind = kind;
}
public String getKind() {
return kind;
}
public abstract boolean triggered(); public abstract boolean triggered();
@Id @Id
@ -84,8 +85,9 @@ public abstract class Trigger<D extends Device> {
return automationId; return automationId;
} }
public void setAutomationId(Long automationId) { public Trigger<D> setAutomationId(Long automationId) {
this.automationId = automationId; this.automationId = automationId;
return this;
} }
@PreRemove @PreRemove

View file

@ -1,10 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.models; package ch.usi.inf.sa4.sanmarinoes.smarthut.models;
import java.util.List; import java.util.List;
import javax.transaction.Transactional;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Param;
public interface TriggerRepository<T extends Trigger<?>> extends CrudRepository<T, Long> { public interface TriggerRepository<T extends Trigger<?>> extends CrudRepository<T, Long> {
List<T> findAllByDeviceId(@Param("deviceId") long deviceId); List<T> findAllByDeviceId(@Param("deviceId") long deviceId);
@Transactional
void deleteAllByAutomationId(Long automationId);
} }