Merge branch 'guests-fix' into 'dev'
Guests fix See merge request sa4-2020/the-sanmarinoes/backend!109
This commit is contained in:
commit
cb2713afa5
25 changed files with 161 additions and 71 deletions
|
@ -75,6 +75,6 @@ public class ButtonDimmerController
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class CurtainsController {
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/state")
|
@PostMapping("/{id}/state")
|
||||||
|
|
|
@ -66,7 +66,9 @@ public class DimmableLightController extends GuestEnabledController<DimmableLigh
|
||||||
*/
|
*/
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public DimmableLight update(
|
public DimmableLight update(
|
||||||
@Valid @RequestBody DimmableSaveRequest sp, final Principal principal, Long hostId)
|
@Valid @RequestBody DimmableSaveRequest sp,
|
||||||
|
final Principal principal,
|
||||||
|
@RequestParam(value = "hostId", required = false) Long hostId)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
|
|
||||||
return save(
|
return save(
|
||||||
|
@ -79,7 +81,7 @@ public class DimmableLightController extends GuestEnabledController<DimmableLigh
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId}
|
// the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId}
|
||||||
|
|
|
@ -3,11 +3,16 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
|
||||||
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
|
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
|
||||||
|
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GuestPermissionsRequest;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GuestPermissionsRequest;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GuestsUpdateRequest;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.UserResponse;
|
||||||
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.EagerUserRepository;
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
|
||||||
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.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
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;
|
||||||
|
@ -18,23 +23,48 @@ import org.springframework.web.bind.annotation.*;
|
||||||
@RequestMapping("/user")
|
@RequestMapping("/user")
|
||||||
public class GuestController {
|
public class GuestController {
|
||||||
|
|
||||||
@Autowired private UserRepository userRepository;
|
@Autowired private EagerUserRepository userRepository;
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public List<User> findAll() {
|
public List<UserResponse> findAll() {
|
||||||
return toList(userRepository.findAll());
|
return StreamSupport.stream(userRepository.findAll().spliterator(), false)
|
||||||
|
.map(UserResponse::fromUser)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/guest")
|
@GetMapping("/hosts")
|
||||||
public User addUserAsGuest(@RequestParam("userId") long id, final Principal principal)
|
public List<UserResponse> findHosts(final Principal principal) {
|
||||||
|
final User u = userRepository.findByUsername(principal.getName());
|
||||||
|
return u.getHosts().stream().map(UserResponse::fromUser).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/guests")
|
||||||
|
public List<UserResponse> findGuests(final Principal principal) {
|
||||||
|
final User u = userRepository.findByUsername(principal.getName());
|
||||||
|
return u.getGuests().stream().map(UserResponse::fromUser).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/guests")
|
||||||
|
public List<User> setGuests(
|
||||||
|
@RequestBody @Valid GuestsUpdateRequest g, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
User guest = userRepository.findById(id).orElseThrow(NotFoundException::new);
|
Iterable<User> guests = userRepository.findAllById(g.ids);
|
||||||
User host = userRepository.findByUsername(principal.getName());
|
User host = userRepository.findByUsername(principal.getName());
|
||||||
|
|
||||||
host.addGuest(guest);
|
for (final User oldGuest : host.getGuests()) {
|
||||||
guest.addHost(host);
|
oldGuest.getHosts().remove(host);
|
||||||
userRepository.save(guest);
|
}
|
||||||
return userRepository.save(host);
|
|
||||||
|
final Set<User> oldGuests = Set.copyOf(host.getGuests());
|
||||||
|
|
||||||
|
for (final User guest : guests) {
|
||||||
|
host.addGuest(guest);
|
||||||
|
guest.addHost(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository.saveAll(oldGuests);
|
||||||
|
userRepository.save(host);
|
||||||
|
return toList(userRepository.saveAll(guests));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/permissions")
|
@PutMapping("/permissions")
|
||||||
|
@ -44,16 +74,4 @@ public class GuestController {
|
||||||
currentUser.setCameraEnabled(g.isCameraEnabled());
|
currentUser.setCameraEnabled(g.isCameraEnabled());
|
||||||
return userRepository.save(currentUser);
|
return userRepository.save(currentUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/guest")
|
|
||||||
public void removeUserAsGuest(@RequestParam("userId") long id, final Principal principal)
|
|
||||||
throws NotFoundException {
|
|
||||||
User guest = userRepository.findById(id).orElseThrow(NotFoundException::new);
|
|
||||||
User host = userRepository.findByUsername(principal.getName());
|
|
||||||
|
|
||||||
host.removeGuest(guest);
|
|
||||||
guest.getHosts().remove(host);
|
|
||||||
userRepository.save(host);
|
|
||||||
userRepository.save(guest);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,6 @@ public class KnobDimmerController extends InputDeviceConnectionController<KnobDi
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,6 @@ public class MotionSensorController {
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,9 @@ public class RegularLightController extends GuestEnabledController<RegularLight>
|
||||||
|
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public RegularLight update(
|
public RegularLight update(
|
||||||
@Valid @RequestBody SwitchableSaveRequest rl, final Principal principal, Long hostId)
|
@Valid @RequestBody SwitchableSaveRequest rl,
|
||||||
|
final Principal principal,
|
||||||
|
@RequestParam(value = "hostId", required = false) Long hostId)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
return save(
|
return save(
|
||||||
fetchIfOwnerOrGuest(principal, rl.getId(), hostId),
|
fetchIfOwnerOrGuest(principal, rl.getId(), hostId),
|
||||||
|
@ -92,7 +94,7 @@ public class RegularLightController extends GuestEnabledController<RegularLight>
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
// the full url should be: "/regularLight/{id}/state?sceneId={sceneId}
|
// the full url should be: "/regularLight/{id}/state?sceneId={sceneId}
|
||||||
|
|
|
@ -124,6 +124,11 @@ public class RoomController {
|
||||||
roomRepository
|
roomRepository
|
||||||
.findByIdAndUsername(id, principal.getName())
|
.findByIdAndUsername(id, principal.getName())
|
||||||
.orElseThrow(NotFoundException::new);
|
.orElseThrow(NotFoundException::new);
|
||||||
|
List<Device> devices = deviceService.findAll(r.getId(), null, principal.getName());
|
||||||
|
for (Device d : devices) {
|
||||||
|
deviceService.deleteByIdAsOwner(d.getId(), principal.getName());
|
||||||
|
}
|
||||||
|
|
||||||
roomRepository.delete(r);
|
roomRepository.delete(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class SecurityCameraController {
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id, final Principal principal)
|
public void delete(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/state")
|
@PostMapping("/{id}/state")
|
||||||
|
|
|
@ -57,6 +57,6 @@ public class SensorController {
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class SmartPlugController {
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/state")
|
@PostMapping("/{id}/state")
|
||||||
|
|
|
@ -81,6 +81,6 @@ public class SwitchController extends InputDeviceConnectionController<Switch, Sw
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class ThermostatController {
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
public void deleteById(@PathVariable("id") long id, final Principal principal)
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
deviceService.delete(id, principal.getName());
|
deviceService.deleteByIdAsOwner(id, principal.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/{id}/state")
|
@PostMapping("/{id}/state")
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
public class GuestsUpdateRequest {
|
||||||
|
@NotNull public List<Long> ids;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
|
||||||
|
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
|
||||||
|
|
||||||
|
public class UserResponse {
|
||||||
|
private Long id;
|
||||||
|
private String username;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private UserResponse() {}
|
||||||
|
|
||||||
|
public static UserResponse fromUser(User u) {
|
||||||
|
final UserResponse us = new UserResponse();
|
||||||
|
us.name = u.getName();
|
||||||
|
us.id = u.getId();
|
||||||
|
us.username = u.getUsername();
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ public class Automation {
|
||||||
@GsonExclude
|
@GsonExclude
|
||||||
private Long userId;
|
private Long userId;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "automation", orphanRemoval = true)
|
@OneToMany(mappedBy = "automation", orphanRemoval = true, cascade = CascadeType.REMOVE)
|
||||||
private Set<Trigger<?>> triggers = new HashSet<>();
|
private Set<Trigger<?>> triggers = new HashSet<>();
|
||||||
|
|
||||||
@OneToMany(mappedBy = "automation", cascade = CascadeType.REMOVE)
|
@OneToMany(mappedBy = "automation", cascade = CascadeType.REMOVE)
|
||||||
|
|
|
@ -71,14 +71,18 @@ public abstract class Device {
|
||||||
@SocketGsonExclude
|
@SocketGsonExclude
|
||||||
private Set<State<?>> states = new HashSet<>();
|
private Set<State<?>> states = new HashSet<>();
|
||||||
|
|
||||||
@Transient @GsonExclude private boolean fromHost = false;
|
@Transient @GsonExclude private Long fromHostId = null;
|
||||||
|
|
||||||
@Transient @GsonExclude private boolean fromGuest = false;
|
@Transient @GsonExclude private boolean fromGuest = false;
|
||||||
|
|
||||||
@Transient @GsonExclude private boolean deleted = false;
|
@Transient @GsonExclude private boolean deleted = false;
|
||||||
|
|
||||||
public boolean isFromHost() {
|
public Long getFromHostId() {
|
||||||
return fromHost;
|
return fromHostId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromHostId(Long fromHostId) {
|
||||||
|
this.fromHostId = fromHostId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDeleted() {
|
public boolean isDeleted() {
|
||||||
|
@ -97,10 +101,6 @@ public abstract class Device {
|
||||||
this.fromGuest = fromGuest;
|
this.fromGuest = fromGuest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFromHost(boolean fromHost) {
|
|
||||||
this.fromHost = fromHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getId() {
|
public long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,13 @@ import javax.persistence.*;
|
||||||
@Entity
|
@Entity
|
||||||
public class Switch extends InputDevice implements BooleanTriggerable {
|
public class Switch extends InputDevice implements BooleanTriggerable {
|
||||||
|
|
||||||
@ManyToMany(cascade = CascadeType.DETACH)
|
@ManyToMany(
|
||||||
|
cascade = {
|
||||||
|
CascadeType.DETACH,
|
||||||
|
CascadeType.MERGE,
|
||||||
|
CascadeType.REFRESH,
|
||||||
|
CascadeType.PERSIST
|
||||||
|
})
|
||||||
@GsonExclude
|
@GsonExclude
|
||||||
@SocketGsonExclude
|
@SocketGsonExclude
|
||||||
@JoinTable(
|
@JoinTable(
|
||||||
|
|
|
@ -14,7 +14,14 @@ public abstract class Switchable extends OutputDevice {
|
||||||
public static final Connector<Switch, Switchable> SWITCH_SWITCHABLE_CONNECTOR =
|
public static final Connector<Switch, Switchable> SWITCH_SWITCHABLE_CONNECTOR =
|
||||||
Connector.basic(Switch::getOutputs, Switchable::getSwitches);
|
Connector.basic(Switch::getOutputs, Switchable::getSwitches);
|
||||||
|
|
||||||
@ManyToMany(mappedBy = "switchables", cascade = CascadeType.DETACH)
|
@ManyToMany(
|
||||||
|
mappedBy = "switchables",
|
||||||
|
cascade = {
|
||||||
|
CascadeType.DETACH,
|
||||||
|
CascadeType.MERGE,
|
||||||
|
CascadeType.REFRESH,
|
||||||
|
CascadeType.PERSIST
|
||||||
|
})
|
||||||
@GsonExclude
|
@GsonExclude
|
||||||
@SocketGsonExclude
|
@SocketGsonExclude
|
||||||
private Set<Switch> inputs = new HashSet<>();
|
private Set<Switch> inputs = new HashSet<>();
|
||||||
|
|
|
@ -78,7 +78,7 @@ public class UpdateTasks {
|
||||||
c.forEach(
|
c.forEach(
|
||||||
s ->
|
s ->
|
||||||
sensorSocketEndpoint.queueDeviceUpdate(
|
sensorSocketEndpoint.queueDeviceUpdate(
|
||||||
s, sensorRepository.findUser(s.getId())));
|
s, sensorRepository.findUser(s.getId()), false, null, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends device updates through sensor socket in batch every one second */
|
/** Sends device updates through sensor socket in batch every one second */
|
||||||
|
|
|
@ -125,21 +125,17 @@ public class DeviceService {
|
||||||
|
|
||||||
// We're telling the host that a guest has modified a device. Therefore, fromGuest becomes
|
// We're telling the host that a guest has modified a device. Therefore, fromGuest becomes
|
||||||
// true.
|
// true.
|
||||||
device.setFromHost(false);
|
|
||||||
device.setFromGuest(true);
|
|
||||||
// broadcast device update to host
|
// broadcast device update to host
|
||||||
endpoint.queueDeviceUpdate(device, host);
|
endpoint.queueDeviceUpdate(device, host, true, null, false);
|
||||||
|
|
||||||
// We're telling all guests that a higher entity has issued a device update. Therefore,
|
// We're telling all guests that a higher entity has issued a device update. Therefore,
|
||||||
// fromHost becomes true.
|
// fromHost becomes true.
|
||||||
device.setFromHost(true);
|
|
||||||
device.setFromGuest(false);
|
|
||||||
for (final User guest : guests) {
|
for (final User guest : guests) {
|
||||||
if (guest.equals(currentUser)) {
|
if (guest.equals(currentUser)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// enqueue all device updates for all other guests
|
// enqueue all device updates for all other guests
|
||||||
endpoint.queueDeviceUpdate(device, guest);
|
endpoint.queueDeviceUpdate(device, guest, false, host.getId(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return device;
|
return device;
|
||||||
|
@ -157,15 +153,13 @@ public class DeviceService {
|
||||||
final User user = userRepository.findByUsername(username);
|
final User user = userRepository.findByUsername(username);
|
||||||
final Set<User> guests = user.getGuests();
|
final Set<User> guests = user.getGuests();
|
||||||
// make sure we're broadcasting from host
|
// make sure we're broadcasting from host
|
||||||
device.setFromHost(true);
|
|
||||||
device.setFromGuest(false);
|
|
||||||
for (final User guest : guests) {
|
for (final User guest : guests) {
|
||||||
// broadcast to endpoint the object device, with receiving user set to guest
|
// broadcast to endpoint the object device, with receiving user set to guest
|
||||||
endpoint.queueDeviceUpdate(device, guest);
|
endpoint.queueDeviceUpdate(device, guest, false, user.getId(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (causedByTrigger) {
|
if (causedByTrigger) {
|
||||||
endpoint.queueDeviceUpdate(device, user);
|
endpoint.queueDeviceUpdate(device, user, false, user.getId(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,13 +206,20 @@ public class DeviceService {
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(Long id, String username) throws NotFoundException {
|
public void deleteByIdAsOwner(Long id, String username) throws NotFoundException {
|
||||||
Device device =
|
Device d =
|
||||||
deviceRepository
|
deviceRepository
|
||||||
.findByIdAndUsername(id, username)
|
.findByIdAndUsername(id, username)
|
||||||
.orElseThrow(NotFoundException::new);
|
.orElseThrow(NotFoundException::new);
|
||||||
deviceRepository.delete(device);
|
|
||||||
|
|
||||||
propagateUpdateAsOwner(device, username, false);
|
final User user = userRepository.findByUsername(username);
|
||||||
|
final Set<User> guests = user.getGuests();
|
||||||
|
// make sure we're broadcasting from host
|
||||||
|
for (final User guest : guests) {
|
||||||
|
// broadcast to endpoint the object device, with receiving user set to guest
|
||||||
|
endpoint.queueDeviceUpdate(d, guest, false, user.getId(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceRepository.delete(d);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class MotionSensorService {
|
||||||
@Autowired private MotionSensorRepository motionSensorRepository;
|
@Autowired private MotionSensorRepository motionSensorRepository;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates detection status of given motion sensor and propagates update throgh socket
|
* Updates detection status of given motion sensor and propagates update through socket
|
||||||
*
|
*
|
||||||
* @param sensor the motion sensor to update
|
* @param sensor the motion sensor to update
|
||||||
* @param detected the new detection status
|
* @param detected the new detection status
|
||||||
|
@ -26,7 +26,7 @@ public class MotionSensorService {
|
||||||
final MotionSensor toReturn = deviceService.saveAsOwner(sensor, username);
|
final MotionSensor toReturn = deviceService.saveAsOwner(sensor, username);
|
||||||
|
|
||||||
sensorSocketEndpoint.queueDeviceUpdate(
|
sensorSocketEndpoint.queueDeviceUpdate(
|
||||||
sensor, motionSensorRepository.findUser(sensor.getId()));
|
sensor, motionSensorRepository.findUser(sensor.getId()), false, null, false);
|
||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,8 @@ public class SensorService {
|
||||||
sensor =
|
sensor =
|
||||||
deviceService.saveAsOwner(
|
deviceService.saveAsOwner(
|
||||||
sensor, sensorRepository.findUser(sensor.getId()).getUsername());
|
sensor, sensorRepository.findUser(sensor.getId()).getUsername());
|
||||||
endpoint.queueDeviceUpdate(sensor, sensorRepository.findUser(sensor.getId()));
|
endpoint.queueDeviceUpdate(
|
||||||
|
sensor, sensorRepository.findUser(sensor.getId()), false, null, false);
|
||||||
return sensor;
|
return sensor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class ThermostatService {
|
||||||
this.computeState(t);
|
this.computeState(t);
|
||||||
|
|
||||||
deviceService.saveAsOwner(t, thermostatRepository.findUser(t.getId()).getUsername());
|
deviceService.saveAsOwner(t, thermostatRepository.findUser(t.getId()).getUsername());
|
||||||
endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId()));
|
endpoint.queueDeviceUpdate(t, thermostatRepository.findUser(t.getId()), false, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateStates() {
|
public void updateStates() {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.config.JWTTokenUtils;
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device;
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService;
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Multimaps;
|
import com.google.common.collect.Multimaps;
|
||||||
|
@ -21,6 +22,8 @@ public class SensorSocketEndpoint extends Endpoint {
|
||||||
|
|
||||||
private Gson gson = GsonConfig.socketGson();
|
private Gson gson = GsonConfig.socketGson();
|
||||||
|
|
||||||
|
@Autowired private DeviceService deviceService;
|
||||||
|
|
||||||
private UserRepository userRepository;
|
private UserRepository userRepository;
|
||||||
|
|
||||||
private JWTTokenUtils jwtTokenUtils;
|
private JWTTokenUtils jwtTokenUtils;
|
||||||
|
@ -28,7 +31,10 @@ public class SensorSocketEndpoint extends Endpoint {
|
||||||
private Multimap<User, Session> authorizedClients =
|
private Multimap<User, Session> authorizedClients =
|
||||||
Multimaps.synchronizedMultimap(HashMultimap.create());
|
Multimaps.synchronizedMultimap(HashMultimap.create());
|
||||||
|
|
||||||
private final Map<User, Map<Long, Device>> messages = new HashMap<>();
|
// messages are now stored as strings as a "hack" to capture and clone the state of the device,
|
||||||
|
// since
|
||||||
|
// fromHost and fromGuest are just mutable properties and hibernate caches the object.
|
||||||
|
private final Map<User, Map<Long, String>> messages = new HashMap<>();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public SensorSocketEndpoint(UserRepository userRepository, JWTTokenUtils jwtTokenUtils) {
|
public SensorSocketEndpoint(UserRepository userRepository, JWTTokenUtils jwtTokenUtils) {
|
||||||
|
@ -41,18 +47,33 @@ public class SensorSocketEndpoint extends Endpoint {
|
||||||
*
|
*
|
||||||
* @param device the device update to be sent
|
* @param device the device update to be sent
|
||||||
* @param u the user the device belongs
|
* @param u the user the device belongs
|
||||||
|
* @param fromGuest value for device.fromGuest. This will be put in the device passed.
|
||||||
|
* @param fromHostId value for device.fromHostId. This will be put in the device passed.
|
||||||
|
* @param deleted value for device.deleted. This will be put in the device passed.
|
||||||
*/
|
*/
|
||||||
public void queueDeviceUpdate(Device device, User u) {
|
public void queueDeviceUpdate(
|
||||||
|
Device device, User u, boolean fromGuest, Long fromHostId, boolean deleted) {
|
||||||
synchronized (messages) {
|
synchronized (messages) {
|
||||||
|
device.setFromGuest(fromGuest);
|
||||||
|
device.setFromHostId(fromHostId);
|
||||||
|
device.setDeleted(deleted);
|
||||||
|
|
||||||
|
// sort of an hack: force the population of thermostat measureTemperature and other
|
||||||
|
// possible
|
||||||
|
// computed fields in the future. This should already be done by the callers of this
|
||||||
|
// method but for
|
||||||
|
// whatever reason they don't do it.
|
||||||
|
deviceService.populateComputedFields(List.of(device));
|
||||||
|
|
||||||
messages.putIfAbsent(u, new HashMap<>());
|
messages.putIfAbsent(u, new HashMap<>());
|
||||||
messages.get(u).put(device.getId(), device);
|
messages.get(u).put(device.getId(), gson.toJson(device));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sends all device updates queued to be sent in a unique WebSocket message */
|
/** Sends all device updates queued to be sent in a unique WebSocket message */
|
||||||
public void flushDeviceUpdates() {
|
public void flushDeviceUpdates() {
|
||||||
synchronized (messages) {
|
synchronized (messages) {
|
||||||
for (Map.Entry<User, Map<Long, Device>> batchForUser : messages.entrySet()) {
|
for (Map.Entry<User, Map<Long, String>> batchForUser : messages.entrySet()) {
|
||||||
broadcast(batchForUser.getKey(), batchForUser.getValue().values());
|
broadcast(batchForUser.getKey(), batchForUser.getValue().values());
|
||||||
batchForUser.getValue().clear();
|
batchForUser.getValue().clear();
|
||||||
}
|
}
|
||||||
|
@ -66,13 +87,13 @@ public class SensorSocketEndpoint extends Endpoint {
|
||||||
* @param messages the message batch to send
|
* @param messages the message batch to send
|
||||||
* @param u the user to which to send the message
|
* @param u the user to which to send the message
|
||||||
*/
|
*/
|
||||||
private void broadcast(User u, Collection<?> messages) {
|
private void broadcast(User u, Collection<String> messages) {
|
||||||
if (messages.isEmpty()) return;
|
if (messages.isEmpty()) return;
|
||||||
final HashSet<Session> sessions = new HashSet<>(authorizedClients.get(u));
|
final HashSet<Session> sessions = new HashSet<>(authorizedClients.get(u));
|
||||||
for (Session s : sessions) {
|
for (Session s : sessions) {
|
||||||
try {
|
try {
|
||||||
if (s.isOpen()) {
|
if (s.isOpen()) {
|
||||||
s.getBasicRemote().sendText(gson.toJson(messages));
|
s.getBasicRemote().sendText("[" + String.join(",", messages) + "]");
|
||||||
} else {
|
} else {
|
||||||
authorizedClients.remove(u, s);
|
authorizedClients.remove(u, s);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue