controllers fixed and updated for guest or host checks
This commit is contained in:
parent
a428d57fe1
commit
c6d5a1acd7
7 changed files with 128 additions and 111 deletions
|
@ -17,13 +17,26 @@ import org.springframework.web.bind.annotation.*;
|
||||||
@RestController
|
@RestController
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@RequestMapping("/dimmableLight")
|
@RequestMapping("/dimmableLight")
|
||||||
public class DimmableLightController {
|
public class DimmableLightController extends GuestEnabledController<DimmableLight> {
|
||||||
|
|
||||||
@Autowired private UserRepository userRepository;
|
private DimmableLightRepository dimmableLightRepository;
|
||||||
@Autowired private DimmableLightRepository dimmableLightRepository;
|
private SceneRepository sceneRepository;
|
||||||
@Autowired private SceneRepository sceneRepository;
|
private StateRepository<State<?>> stateRepository;
|
||||||
@Autowired private StateRepository<State<?>> stateRepository;
|
private DeviceService deviceService;
|
||||||
@Autowired private DeviceService deviceService;
|
|
||||||
|
@Autowired
|
||||||
|
public DimmableLightController(
|
||||||
|
UserRepository userRepository,
|
||||||
|
DimmableLightRepository dimmableLightRepository,
|
||||||
|
SceneRepository sceneRepository,
|
||||||
|
StateRepository<State<?>> stateRepository,
|
||||||
|
DeviceService deviceService) {
|
||||||
|
super(userRepository, dimmableLightRepository);
|
||||||
|
this.dimmableLightRepository = dimmableLightRepository;
|
||||||
|
this.sceneRepository = sceneRepository;
|
||||||
|
this.stateRepository = stateRepository;
|
||||||
|
this.deviceService = deviceService;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public List<DimmableLight> findAll() {
|
public List<DimmableLight> findAll() {
|
||||||
|
@ -60,31 +73,6 @@ public class DimmableLightController {
|
||||||
return save(new DimmableLight(), dl, principal.getName(), null);
|
return save(new DimmableLight(), dl, principal.getName(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DimmableLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId)
|
|
||||||
throws NotFoundException {
|
|
||||||
if (hostId == null) {
|
|
||||||
return dimmableLightRepository
|
|
||||||
.findByIdAndUsername(id, principal.getName())
|
|
||||||
.orElseThrow(NotFoundException::new);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Slightly less extremely verbose check through various repositories to control user/guest authorization.
|
|
||||||
*/
|
|
||||||
DimmableLight dl =
|
|
||||||
dimmableLightRepository
|
|
||||||
.findByIdAndUserId(id, hostId)
|
|
||||||
.orElseThrow(NotFoundException::new);
|
|
||||||
User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new);
|
|
||||||
User guest = userRepository.findByUsername(principal.getName());
|
|
||||||
dl.setFromHost(true);
|
|
||||||
if (!host.getGuests().contains(guest)) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
} else {
|
|
||||||
return dl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Logic for saving either as owner or guest is handled in method save of this controller
|
Logic for saving either as owner or guest is handled in method save of this controller
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
|
||||||
|
|
||||||
|
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.returnIfGuest;
|
||||||
|
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
public abstract class GuestEnabledController<T extends Device> {
|
||||||
|
|
||||||
|
private UserRepository userRepository;
|
||||||
|
private DeviceRepository<T> deviceRepository;
|
||||||
|
|
||||||
|
public GuestEnabledController(
|
||||||
|
final UserRepository userRepository, final DeviceRepository<T> deviceRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.deviceRepository = deviceRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId)
|
||||||
|
throws NotFoundException {
|
||||||
|
if (hostId == null) {
|
||||||
|
return deviceRepository
|
||||||
|
.findByIdAndUsername(id, principal.getName())
|
||||||
|
.orElseThrow(NotFoundException::new);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Slightly less extremely verbose check through various repositories to control user/guest authorization.
|
||||||
|
*/
|
||||||
|
T device =
|
||||||
|
deviceRepository
|
||||||
|
.findByIdAndUserId(id, hostId)
|
||||||
|
.orElseThrow(NotFoundException::new);
|
||||||
|
return returnIfGuest(userRepository, device, hostId, principal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,42 +25,35 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
@RestController
|
@RestController
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@RequestMapping("/regularLight")
|
@RequestMapping("/regularLight")
|
||||||
public class RegularLightController {
|
public class RegularLightController extends GuestEnabledController<RegularLight> {
|
||||||
|
|
||||||
@Autowired private UserRepository userRepository;
|
private RegularLightRepository regularLightRepository;
|
||||||
@Autowired private RegularLightRepository regularLightService;
|
private SceneRepository sceneRepository;
|
||||||
@Autowired private SceneRepository sceneRepository;
|
private StateRepository<State<?>> stateRepository;
|
||||||
@Autowired private StateRepository<State<?>> stateRepository;
|
private DeviceService deviceService;
|
||||||
@Autowired private DeviceService deviceService;
|
|
||||||
|
|
||||||
private RegularLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId)
|
@Autowired
|
||||||
throws NotFoundException {
|
public RegularLightController(
|
||||||
if (hostId == null) {
|
UserRepository userRepository,
|
||||||
return regularLightService.findById(id).orElseThrow(NotFoundException::new);
|
RegularLightRepository regularLightRepository,
|
||||||
} else {
|
SceneRepository sceneRepository,
|
||||||
RegularLight rl =
|
StateRepository<State<?>> stateRepository,
|
||||||
regularLightService
|
DeviceService deviceService) {
|
||||||
.findByIdAndUserId(id, hostId)
|
super(userRepository, regularLightRepository);
|
||||||
.orElseThrow(NotFoundException::new);
|
this.regularLightRepository = regularLightRepository;
|
||||||
User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new);
|
this.sceneRepository = sceneRepository;
|
||||||
User guest = userRepository.findByUsername(principal.getName());
|
this.stateRepository = stateRepository;
|
||||||
rl.setFromHost(true);
|
this.deviceService = deviceService;
|
||||||
if (!host.getGuests().contains(guest)) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
} else {
|
|
||||||
return rl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public List<RegularLight> findAll() {
|
public List<RegularLight> findAll() {
|
||||||
return toList(regularLightService.findAll());
|
return toList(regularLightRepository.findAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public RegularLight findById(@PathVariable("id") long id) throws NotFoundException {
|
public RegularLight findById(@PathVariable("id") long id) throws NotFoundException {
|
||||||
return regularLightService.findById(id).orElseThrow(NotFoundException::new);
|
return regularLightRepository.findById(id).orElseThrow(NotFoundException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegularLight save(
|
private RegularLight save(
|
||||||
|
@ -97,10 +90,10 @@ public class RegularLightController {
|
||||||
|
|
||||||
@DeleteMapping("/{id}")
|
@DeleteMapping("/{id}")
|
||||||
public void delete(@PathVariable("id") long id) {
|
public void delete(@PathVariable("id") long id) {
|
||||||
regularLightService.deleteById(id);
|
regularLightRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId}
|
// the full url should be: "/regularLight/{id}/state?sceneId={sceneId}
|
||||||
// however it is not necessary to specify the query in the mapping
|
// however it is not necessary to specify the query in the mapping
|
||||||
@PostMapping("/{id}/state")
|
@PostMapping("/{id}/state")
|
||||||
public State<? extends Switchable> sceneBinding(
|
public State<? extends Switchable> sceneBinding(
|
||||||
|
@ -109,7 +102,7 @@ public class RegularLightController {
|
||||||
final Principal principal)
|
final Principal principal)
|
||||||
throws NotFoundException, DuplicateStateException {
|
throws NotFoundException, DuplicateStateException {
|
||||||
RegularLight d =
|
RegularLight d =
|
||||||
regularLightService
|
regularLightRepository
|
||||||
.findByIdAndUsername(deviceId, principal.getName())
|
.findByIdAndUsername(deviceId, principal.getName())
|
||||||
.orElseThrow(NotFoundException::new);
|
.orElseThrow(NotFoundException::new);
|
||||||
State<? extends Switchable> s = d.cloneState();
|
State<? extends Switchable> s = d.cloneState();
|
||||||
|
|
|
@ -6,6 +6,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.RoomSaveRequest;
|
||||||
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.*;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
@ -37,13 +38,7 @@ public class RoomController {
|
||||||
if (hostId == null) {
|
if (hostId == null) {
|
||||||
return list;
|
return list;
|
||||||
} else {
|
} else {
|
||||||
User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
|
return Utils.returnIfGuest(userRepository, list, hostId, principal);
|
||||||
User guest = userRepository.findByUsername(principal.getName());
|
|
||||||
if (!host.getGuests().contains(guest)) {
|
|
||||||
throw new NotFoundException();
|
|
||||||
} else {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,16 @@ public abstract class Device {
|
||||||
|
|
||||||
@Transient @GsonExclude private boolean fromHost = false;
|
@Transient @GsonExclude private boolean fromHost = false;
|
||||||
|
|
||||||
|
@Transient @GsonExclude private boolean fromGuest = false;
|
||||||
|
|
||||||
|
public boolean isFromGuest() {
|
||||||
|
return fromGuest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromGuest(boolean fromGuest) {
|
||||||
|
this.fromGuest = fromGuest;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFromHost(boolean fromHost) {
|
public void setFromHost(boolean fromHost) {
|
||||||
this.fromHost = fromHost;
|
this.fromHost = fromHost;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package ch.usi.inf.sa4.sanmarinoes.smarthut.service;
|
package ch.usi.inf.sa4.sanmarinoes.smarthut.service;
|
||||||
|
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude;
|
|
||||||
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.Device;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.Device;
|
||||||
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.DeviceRepository;
|
||||||
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.socket.SensorSocketEndpoint;
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
|
||||||
import java.beans.Transient;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -16,56 +14,54 @@ import org.springframework.stereotype.Component;
|
||||||
public class DeviceService {
|
public class DeviceService {
|
||||||
// FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF)
|
// FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF)
|
||||||
|
|
||||||
@Autowired DeviceRepository<Device> deviceRepository;
|
@Autowired private DeviceRepository<Device> deviceRepository;
|
||||||
@Autowired UserRepository userRepository;
|
@Autowired private UserRepository userRepository;
|
||||||
@Autowired SensorSocketEndpoint endpoint;
|
@Autowired private SensorSocketEndpoint endpoint;
|
||||||
|
|
||||||
/*
|
public <T extends Device> T saveAsGuest(T device, String guestUsername, Long hostId)
|
||||||
TODO: remember to put a @Transient @GsonIgnore (but not @SocketGsonIgnore) property on device to signal a device update
|
|
||||||
TODO: coming from DeviceService.saveAsGuest()
|
|
||||||
*/
|
|
||||||
public <T extends Device> T saveAsGuest(
|
|
||||||
@Transient @GsonExclude T device, String guestUsername, Long hostId)
|
|
||||||
throws NotFoundException {
|
throws NotFoundException {
|
||||||
|
device = deviceRepository.save(device);
|
||||||
|
|
||||||
final User currentUser = userRepository.findByUsername(guestUsername);
|
final User currentUser = userRepository.findByUsername(guestUsername);
|
||||||
final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
|
final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
|
||||||
final Set<User> guests = host.getGuests();
|
final Set<User> guests = Set.copyOf(host.getGuests());
|
||||||
|
|
||||||
// filter out currentUser from guests as we do not want to broadcast an update to the
|
// We're telling the host that a guest has modified a device. Therefore, fromGuest becomes
|
||||||
// updating user itself
|
// true.
|
||||||
if (guests.contains(currentUser)) {
|
|
||||||
guests.remove(currentUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
// broadcasting from not a host
|
|
||||||
device.setFromHost(false);
|
device.setFromHost(false);
|
||||||
// broadcast device update for host
|
device.setFromGuest(true);
|
||||||
|
// broadcast device update to host
|
||||||
endpoint.queueDeviceUpdate(device, host);
|
endpoint.queueDeviceUpdate(device, host);
|
||||||
userRepository.save(host);
|
|
||||||
endpoint.flushDeviceUpdates();
|
// We're telling all guests that a higher entity has issued a device update. Therefore,
|
||||||
|
// fromHost becomes true.
|
||||||
|
device.setFromHost(true);
|
||||||
|
device.setFromGuest(false);
|
||||||
for (final User guest : guests) {
|
for (final User guest : guests) {
|
||||||
|
if (guest.equals(currentUser)) {
|
||||||
|
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);
|
||||||
userRepository.save(guest);
|
|
||||||
}
|
}
|
||||||
// broadcast device updates for all other guests
|
// broadcast device updates for all other guests
|
||||||
endpoint.flushDeviceUpdates();
|
return device;
|
||||||
return deviceRepository.save(device);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Device> T saveAsOwner(T device, String username) {
|
public <T extends Device> T saveAsOwner(T device, String username) {
|
||||||
|
device = deviceRepository.save(device);
|
||||||
|
|
||||||
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.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);
|
||||||
userRepository.save(guest);
|
|
||||||
}
|
}
|
||||||
// after queueing the device update for each user, flush them all in a single message
|
// after queueing the device update for each user, flush them all in a single message
|
||||||
// can be moved inside the foreach loop to send a single message for each update enqueued
|
// can be moved inside the foreach loop to send a single message for each update enqueued
|
||||||
endpoint.flushDeviceUpdates();
|
return device;
|
||||||
return deviceRepository.save(device);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package ch.usi.inf.sa4.sanmarinoes.smarthut.utils;
|
package ch.usi.inf.sa4.sanmarinoes.smarthut.utils;
|
||||||
|
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User;
|
||||||
|
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository;
|
||||||
|
import java.security.Principal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
@ -9,24 +12,19 @@ import java.util.stream.StreamSupport;
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
private Utils() {}
|
private Utils() {}
|
||||||
|
|
||||||
@FunctionalInterface
|
public static <U> U returnIfGuest(
|
||||||
public interface ConsumerWithException<T> {
|
UserRepository userRepository, U toReturn, Long hostId, Principal principal)
|
||||||
void apply(T input) throws Throwable;
|
throws NotFoundException {
|
||||||
|
User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
|
||||||
|
User guest = userRepository.findByUsername(principal.getName());
|
||||||
|
if (!host.getGuests().contains(guest)) {
|
||||||
|
throw new NotFoundException();
|
||||||
|
} else {
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> List<T> toList(Iterable<? extends T> iterable) {
|
public static <T> List<T> toList(Iterable<? extends T> iterable) {
|
||||||
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
|
return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> Predicate<T> didThrow(ConsumerWithException<T> consumer) {
|
|
||||||
return (t) -> {
|
|
||||||
try {
|
|
||||||
consumer.apply(t);
|
|
||||||
return true;
|
|
||||||
} catch (Throwable e) {
|
|
||||||
System.err.println(e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue