Merge branch '56-users-can-invite-guests' into 'dev'

Resolve "Users can invite guests"

Closes #56

See merge request sa4-2020/the-sanmarinoes/backend!79
This commit is contained in:
Claudio Maggioni 2020-04-22 22:58:11 +02:00
commit 8a1dc8674a
29 changed files with 677 additions and 290 deletions

View file

@ -23,15 +23,26 @@ public class GsonConfig {
return converter; return converter;
} }
public static Gson gson() { private static GsonBuilder configureBuilder() {
final GsonBuilder builder = new GsonBuilder(); final GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter()); builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter());
builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());
RuntimeTypeAdapterFactory<State> runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory<State> runtimeTypeAdapterFactory =
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");
builder.registerTypeAdapterFactory(runtimeTypeAdapterFactory); builder.registerTypeAdapterFactory(runtimeTypeAdapterFactory);
return builder;
}
public static Gson gson() {
final GsonBuilder builder = configureBuilder();
builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());
return builder.create();
}
public static Gson socketGson() {
final GsonBuilder builder = configureBuilder();
builder.addSerializationExclusionStrategy(new SocketAnnotationExclusionStrategy());
return builder.create(); return builder.create();
} }
} }
@ -56,3 +67,16 @@ class AnnotationExclusionStrategy implements ExclusionStrategy {
return false; return false;
} }
} }
/** GSON exclusion strategy to exclude attributes with @SocketGsonExclude */
class SocketAnnotationExclusionStrategy implements ExclusionStrategy {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(SocketGsonExclude.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}

View file

@ -0,0 +1,10 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.config;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SocketGsonExclude {}

View file

@ -81,6 +81,7 @@ public class SpringFoxConfig {
.or(PathSelectors.regex("/switch.*")::apply) .or(PathSelectors.regex("/switch.*")::apply)
.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("/auth/profile.*")::apply); .or(PathSelectors.regex("/auth/profile.*")::apply);
} }

View file

@ -1,13 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerDimRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ButtonDimmerDimRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -19,37 +18,30 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/buttonDimmer") @RequestMapping("/buttonDimmer")
public class ButtonDimmerController public class ButtonDimmerController
extends InputDeviceConnectionController<ButtonDimmer, Dimmable> { extends InputDeviceConnectionController<ButtonDimmer, Dimmable> {
private DeviceService deviceService;
private ButtonDimmerRepository buttonDimmerRepository; private ButtonDimmerRepository buttonDimmerRepository;
private DimmableRepository<Dimmable> dimmableRepository; private DimmableRepository<Dimmable> dimmableRepository;
@Autowired @Autowired
protected ButtonDimmerController( protected ButtonDimmerController(
ButtonDimmerRepository inputRepository, DimmableRepository<Dimmable> outputRepository) { ButtonDimmerRepository inputRepository,
super( DimmableRepository<Dimmable> outputRepository,
inputRepository, DeviceService deviceService) {
outputRepository, super(inputRepository, outputRepository, DimmableLight.BUTTON_DIMMER_DIMMABLE_CONNECTOR);
DimmableLight.BUTTON_DIMMER_DIMMABLE_CONNECTOR); this.deviceService = deviceService;
this.buttonDimmerRepository = inputRepository; this.buttonDimmerRepository = inputRepository;
this.dimmableRepository = outputRepository; this.dimmableRepository = outputRepository;
} }
@GetMapping
public List<ButtonDimmer> findAll() {
return toList(buttonDimmerRepository.findAll());
}
@GetMapping("/{id}")
public ButtonDimmer findById(@PathVariable("id") long id) throws NotFoundException {
return buttonDimmerRepository.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping @PostMapping
public ButtonDimmer create(@Valid @RequestBody final GenericDeviceSaveReguest bd) { public ButtonDimmer create(
@Valid @RequestBody final GenericDeviceSaveReguest bd, final Principal principal) {
ButtonDimmer newBD = new ButtonDimmer(); ButtonDimmer newBD = new ButtonDimmer();
newBD.setName(bd.getName()); newBD.setName(bd.getName());
newBD.setRoomId(bd.getRoomId()); newBD.setRoomId(bd.getRoomId());
return buttonDimmerRepository.save(newBD); return deviceService.saveAsOwner(newBD, principal.getName());
} }
@PutMapping("/dim") @PutMapping("/dim")
@ -76,7 +68,8 @@ public class ButtonDimmerController
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
buttonDimmerRepository.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
} }

View file

@ -1,13 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
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;
@ -17,44 +16,39 @@ import org.springframework.web.bind.annotation.*;
@EnableAutoConfiguration @EnableAutoConfiguration
@RequestMapping("/curtains") @RequestMapping("/curtains")
public class CurtainsController { public class CurtainsController {
@Autowired private DeviceService deviceService;
@Autowired private CurtainsRepository curtainsService; @Autowired private CurtainsRepository curtainsService;
@Autowired private SceneRepository sceneRepository; @Autowired private SceneRepository sceneRepository;
@Autowired private StateRepository<State<?>> stateRepository; @Autowired private StateRepository<State<?>> stateRepository;
@GetMapping private Curtains save(Curtains newRL, DimmableSaveRequest s, final Principal principal) {
public List<Curtains> findAll() {
return toList(curtainsService.findAll());
}
@GetMapping("/{id}")
public Curtains findById(@PathVariable("id") long id) throws NotFoundException {
return curtainsService.findById(id).orElseThrow(NotFoundException::new);
}
private Curtains save(Curtains newRL, DimmableSaveRequest s) {
newRL.setName(s.getName()); newRL.setName(s.getName());
newRL.setRoomId(s.getRoomId()); newRL.setRoomId(s.getRoomId());
newRL.setIntensity(s.getIntensity()); newRL.setIntensity(s.getIntensity());
return curtainsService.save(newRL); return deviceService.saveAsOwner(newRL, principal.getName());
} }
@PostMapping @PostMapping
public Curtains create(@Valid @RequestBody DimmableSaveRequest curtain) { public Curtains create(
return save(new Curtains(), curtain); @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) {
return save(new Curtains(), curtain, principal);
} }
@PutMapping @PutMapping
public Curtains update(@Valid @RequestBody DimmableSaveRequest curtain) public Curtains update(
@Valid @RequestBody DimmableSaveRequest curtain, final Principal principal)
throws NotFoundException { throws NotFoundException {
return save( return save(
curtainsService.findById(curtain.getId()).orElseThrow(NotFoundException::new), curtainsService.findById(curtain.getId()).orElseThrow(NotFoundException::new),
curtain); curtain,
principal);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
curtainsService.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
@PostMapping("/{id}/state") @PostMapping("/{id}/state")

View file

@ -6,6 +6,7 @@ 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.RoomRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RoomRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
import javax.validation.Valid; import javax.validation.Valid;
@ -18,12 +19,15 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/device") @RequestMapping("/device")
public class DeviceController { public class DeviceController {
@Autowired private DeviceService deviceService;
@Autowired private DeviceRepository<Device> deviceRepository; @Autowired private DeviceRepository<Device> deviceRepository;
@Autowired private RoomRepository roomRepository; @Autowired private RoomRepository roomRepository;
@GetMapping @GetMapping
public List<Device> getAll(final Principal user) { public List<Device> getAll(
return deviceRepository.findAllByUsername(user.getName()); @RequestParam(value = "hostId", required = false) Long hostId, final Principal user)
throws NotFoundException {
return deviceService.findAll(hostId, user.getName());
} }
@PutMapping @PutMapping
@ -43,7 +47,7 @@ public class DeviceController {
d.setRoomId(deviceSaveRequest.getRoomId()); d.setRoomId(deviceSaveRequest.getRoomId());
d.setName(deviceSaveRequest.getName()); d.setName(deviceSaveRequest.getName());
deviceRepository.save(d); deviceService.saveAsOwner(d, principal.getName());
return d; return d;
} }
} }

View file

@ -1,13 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.DimmableSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
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;
@ -16,49 +15,71 @@ 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 DimmableLightRepository dimmableLightService; private DimmableLightRepository dimmableLightRepository;
@Autowired private SceneRepository sceneRepository; private SceneRepository sceneRepository;
@Autowired private StateRepository<State<?>> stateRepository; private StateRepository<State<?>> stateRepository;
private DeviceService deviceService;
@GetMapping @Autowired
public List<DimmableLight> findAll() { public DimmableLightController(
return toList(dimmableLightService.findAll()); 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("/{id}") private DimmableLight save(
public DimmableLight findById(@PathVariable("id") long id) throws NotFoundException { DimmableLight initial, DimmableSaveRequest dl, String username, Long hostId)
return dimmableLightService.findById(id).orElseThrow(NotFoundException::new); throws NotFoundException {
}
private DimmableLight save(DimmableLight initial, DimmableSaveRequest dl) {
initial.setIntensity(dl.getIntensity()); initial.setIntensity(dl.getIntensity());
initial.setName(dl.getName()); initial.setName(dl.getName());
initial.setRoomId(dl.getRoomId()); initial.setRoomId(dl.getRoomId());
return dimmableLightService.save(initial); if (hostId == null) {
return deviceService.saveAsOwner(initial, username);
} else {
return deviceService.saveAsGuest(initial, username, hostId);
}
} }
/*
Assume that only the host can create a device
Here save always as host, but remember to propagate change to guests (DeviceService.saveAsOwner())
*/
@PostMapping @PostMapping
public DimmableLight create(@Valid @RequestBody DimmableSaveRequest dl) { public DimmableLight create(
return save(new DimmableLight(), dl); @Valid @RequestBody DimmableSaveRequest dl, final Principal principal)
throws NotFoundException {
return save(new DimmableLight(), dl, principal.getName(), null);
} }
/*
Logic for saving either as owner or guest is handled in method save of this controller
*/
@PutMapping @PutMapping
public DimmableLight update( public DimmableLight update(
@Valid @RequestBody DimmableSaveRequest sp, final Principal principal) @Valid @RequestBody DimmableSaveRequest sp, final Principal principal, Long hostId)
throws NotFoundException { throws NotFoundException {
return save( return save(
dimmableLightService fetchIfOwnerOrGuest(principal, sp.getId(), hostId),
.findByIdAndUsername(sp.getId(), principal.getName()) sp,
.orElseThrow(NotFoundException::new), principal.getName(),
sp); hostId);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
dimmableLightService.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
// the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId}
@ -71,7 +92,7 @@ public class DimmableLightController {
throws NotFoundException, DuplicateStateException { throws NotFoundException, DuplicateStateException {
DimmableLight d = DimmableLight d =
dimmableLightService dimmableLightRepository
.findByIdAndUsername(deviceId, principal.getName()) .findByIdAndUsername(deviceId, principal.getName())
.orElseThrow(NotFoundException::new); .orElseThrow(NotFoundException::new);
State<? extends Dimmable> s = d.cloneState(); State<? extends Dimmable> s = d.cloneState();

View file

@ -0,0 +1,59 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
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.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 javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@RequestMapping("/user")
public class GuestController {
@Autowired private UserRepository userRepository;
@GetMapping
public List<User> findAll() {
return toList(userRepository.findAll());
}
@PostMapping("/guest")
public User addUserAsGuest(@RequestParam("userId") long id, final Principal principal)
throws NotFoundException {
User guest = userRepository.findById(id).orElseThrow(NotFoundException::new);
User host = userRepository.findByUsername(principal.getName());
host.addGuest(guest);
guest.addHost(host);
userRepository.save(guest);
return userRepository.save(host);
}
@PutMapping("/permissions")
public User updatePermissions(
@Valid @RequestBody GuestPermissionsRequest g, final Principal principal) {
final User currentUser = userRepository.findByUsername(principal.getName());
currentUser.setCameraEnabled(g.isCameraEnabled());
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);
}
}

View file

@ -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);
}
}
}

View file

@ -1,13 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerDimRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.KnobDimmerDimRequest;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
import java.util.Set; import java.util.Set;
import javax.validation.Valid; import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -17,40 +16,28 @@ import org.springframework.web.bind.annotation.*;
@RestController @RestController
@EnableAutoConfiguration @EnableAutoConfiguration
@RequestMapping("/knobDimmer") @RequestMapping("/knobDimmer")
public class KnobDimmerController public class KnobDimmerController extends InputDeviceConnectionController<KnobDimmer, Dimmable> {
extends InputDeviceConnectionController<KnobDimmer, Dimmable> {
@Autowired private DeviceService deviceService;
@Autowired private KnobDimmerRepository knobDimmerRepository; @Autowired private KnobDimmerRepository knobDimmerRepository;
@Autowired private DimmableRepository<Dimmable> dimmableRepository; @Autowired private DimmableRepository<Dimmable> dimmableRepository;
@Autowired @Autowired
protected KnobDimmerController( protected KnobDimmerController(
KnobDimmerRepository inputRepository, DimmableRepository<Dimmable> outputRepository) { KnobDimmerRepository inputRepository, DimmableRepository<Dimmable> outputRepository) {
super( super(inputRepository, outputRepository, Dimmable.KNOB_DIMMER_DIMMABLE_CONNECTOR);
inputRepository,
outputRepository,
Dimmable.KNOB_DIMMER_DIMMABLE_CONNECTOR);
this.knobDimmerRepository = inputRepository; this.knobDimmerRepository = inputRepository;
this.dimmableRepository = outputRepository; this.dimmableRepository = outputRepository;
} }
@GetMapping
public List<KnobDimmer> findAll() {
return toList(knobDimmerRepository.findAll());
}
@GetMapping("/{id}")
public KnobDimmer findById(@PathVariable("id") long id) throws NotFoundException {
return knobDimmerRepository.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping @PostMapping
public KnobDimmer create(@Valid @RequestBody GenericDeviceSaveReguest kd) { public KnobDimmer create(
@Valid @RequestBody GenericDeviceSaveReguest kd, final Principal principal) {
KnobDimmer newKD = new KnobDimmer(); KnobDimmer newKD = new KnobDimmer();
newKD.setName(kd.getName()); newKD.setName(kd.getName());
newKD.setRoomId(kd.getRoomId()); newKD.setRoomId(kd.getRoomId());
return knobDimmerRepository.save(newKD); return deviceService.saveAsOwner(newKD, principal.getName());
} }
@PutMapping("/dimTo") @PutMapping("/dimTo")
@ -69,7 +56,8 @@ public class KnobDimmerController
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
knobDimmerRepository.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
} }

View file

@ -1,14 +1,13 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
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.MotionSensor; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensor;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.MotionSensorRepository;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.security.Principal; import java.security.Principal;
import java.util.List;
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;
@ -19,27 +18,20 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/motionSensor") @RequestMapping("/motionSensor")
public class MotionSensorController { public class MotionSensorController {
@Autowired private DeviceService deviceService;
@Autowired private MotionSensorRepository motionSensorService; @Autowired private MotionSensorRepository motionSensorService;
@Autowired private SensorSocketEndpoint sensorSocketEndpoint; @Autowired private SensorSocketEndpoint sensorSocketEndpoint;
@GetMapping
public List<MotionSensor> findAll() {
return toList(motionSensorService.findAll());
}
@GetMapping("/{id}")
public MotionSensor findById(@PathVariable("id") long id) throws NotFoundException {
return motionSensorService.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping @PostMapping
public MotionSensor create(@Valid @RequestBody GenericDeviceSaveReguest ms) { public MotionSensor create(
@Valid @RequestBody GenericDeviceSaveReguest ms, final Principal principal) {
MotionSensor newMS = new MotionSensor(); MotionSensor newMS = new MotionSensor();
newMS.setName(ms.getName()); newMS.setName(ms.getName());
newMS.setRoomId(ms.getRoomId()); newMS.setRoomId(ms.getRoomId());
return motionSensorService.save(newMS); return deviceService.saveAsOwner(newMS, principal.getName());
} }
/** /**
@ -53,7 +45,8 @@ public class MotionSensorController {
sensor.setDetected(detected); sensor.setDetected(detected);
final MotionSensor toReturn = motionSensorService.save(sensor); final MotionSensor toReturn = motionSensorService.save(sensor);
sensorSocketEndpoint.queueDeviceUpdate(sensor, motionSensorService.findUser(sensor.getId())); sensorSocketEndpoint.queueDeviceUpdate(
sensor, motionSensorService.findUser(sensor.getId()));
return toReturn; return toReturn;
} }
@ -73,7 +66,8 @@ public class MotionSensorController {
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
motionSensorService.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
} }

View file

@ -6,6 +6,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
import javax.validation.Valid; import javax.validation.Valid;
@ -24,52 +25,76 @@ 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 RegularLightRepository regularLightService; private RegularLightRepository regularLightRepository;
@Autowired private SceneRepository sceneRepository; private SceneRepository sceneRepository;
@Autowired private StateRepository<State<?>> stateRepository; private StateRepository<State<?>> stateRepository;
private DeviceService deviceService;
@Autowired
public RegularLightController(
UserRepository userRepository,
RegularLightRepository regularLightRepository,
SceneRepository sceneRepository,
StateRepository<State<?>> stateRepository,
DeviceService deviceService) {
super(userRepository, regularLightRepository);
this.regularLightRepository = regularLightRepository;
this.sceneRepository = sceneRepository;
this.stateRepository = stateRepository;
this.deviceService = deviceService;
}
@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(RegularLight newRL, SwitchableSaveRequest rl) { private RegularLight save(
newRL.setName(rl.getName()); RegularLight initial, SwitchableSaveRequest rl, String username, Long hostId)
newRL.setRoomId(rl.getRoomId()); throws NotFoundException {
newRL.setOn(rl.isOn()); initial.setName(rl.getName());
initial.setRoomId(rl.getRoomId());
initial.setOn(rl.isOn());
return regularLightService.save(newRL); if (hostId == null) {
return deviceService.saveAsOwner(initial, username);
} else {
return deviceService.saveAsGuest(initial, username, hostId);
}
} }
@PostMapping @PostMapping
public RegularLight create(@Valid @RequestBody SwitchableSaveRequest rl) { public RegularLight create(
return save(new RegularLight(), rl); @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal)
throws NotFoundException {
return save(new RegularLight(), rl, principal.getName(), null);
} }
@PutMapping @PutMapping
public RegularLight update( public RegularLight update(
@Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal, Long hostId)
throws NotFoundException { throws NotFoundException {
return save( return save(
regularLightService fetchIfOwnerOrGuest(principal, rl.getId(), hostId),
.findByIdAndUsername(rl.getId(), principal.getName()) rl,
.orElseThrow(NotFoundException::new), principal.getName(),
rl); hostId);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
regularLightService.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
// 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(
@ -78,7 +103,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();

View file

@ -5,7 +5,9 @@ import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.RoomSaveRequest; 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.DeviceService;
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;
@ -22,7 +24,7 @@ public class RoomController {
@Autowired private UserRepository userRepository; @Autowired private UserRepository userRepository;
@Autowired private DeviceRepository<Device> deviceRepository; @Autowired private DeviceService deviceService;
@Autowired private SwitchRepository switchRepository; @Autowired private SwitchRepository switchRepository;
@ -32,14 +34,38 @@ public class RoomController {
@Autowired private ThermostatService thermostatService; @Autowired private ThermostatService thermostatService;
private <T> List<T> fetchOwnerOrGuest(
final List<T> list, Long hostId, final Principal principal) throws NotFoundException {
if (hostId == null) {
return list;
} else {
return Utils.returnIfGuest(userRepository, list, hostId, principal);
}
}
@GetMapping @GetMapping
public List<Room> findAll() { public List<Room> findAll(
return toList(roomRepository.findAll()); @RequestParam(value = "hostId", required = false) Long hostId,
final Principal principal)
throws NotFoundException {
List<Room> rooms = toList(roomRepository.findAll());
return fetchOwnerOrGuest(rooms, hostId, principal);
} }
@GetMapping("/{id}") @GetMapping("/{id}")
public @ResponseBody Room findById(@PathVariable("id") long id) throws NotFoundException { public @ResponseBody Room findById(
return roomRepository.findById(id).orElseThrow(NotFoundException::new); @PathVariable("id") long id,
final Principal principal,
@RequestParam(value = "hostId", required = false) Long hostId)
throws NotFoundException {
Room room = roomRepository.findById(id).orElseThrow(NotFoundException::new);
/* Very ugly way of avoiding code duplication. If this method call throws no exception,
* we can return the room safely. I pass null as I do not return a list in this case.
* Refer to fetchOwnerOrGuest for further information.
*/
fetchOwnerOrGuest(null, hostId, principal);
return room;
} }
@PostMapping @PostMapping
@ -101,13 +127,11 @@ public class RoomController {
* id). * id).
*/ */
@GetMapping(path = "/{roomId}/devices") @GetMapping(path = "/{roomId}/devices")
public List<Device> getDevices(@PathVariable("roomId") long roomid) { public List<Device> getDevices(
Iterable<Device> devices = deviceRepository.findByRoomId(roomid); @PathVariable("roomId") long roomId,
for (Device d : devices) { final Principal principal,
if (d instanceof Thermostat) { @RequestParam(value = "hostId", required = false) Long hostId)
thermostatService.populateMeasuredTemperature((Thermostat) d); throws NotFoundException {
} return deviceService.findAll(roomId, hostId, principal.getName());
}
return toList(devices);
} }
} }

View file

@ -26,10 +26,10 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/scene") @RequestMapping("/scene")
public class SceneController { public class SceneController {
@Autowired SceneRepository sceneService; @Autowired private SceneRepository sceneService;
@Autowired UserRepository userService; @Autowired private UserRepository userService;
@Autowired StateRepository<State<?>> stateService; @Autowired private StateRepository<State<?>> stateService;
@Autowired DeviceRepository<Device> deviceRepository; @Autowired private DeviceRepository<Device> deviceRepository;
@GetMapping @GetMapping
public List<Scene> findAll(Principal principal) { public List<Scene> findAll(Principal principal) {
@ -56,6 +56,8 @@ public class SceneController {
newScene.setUserId(userId); newScene.setUserId(userId);
newScene.setName(s.getName()); newScene.setName(s.getName());
newScene.setGuestAccessEnabled(s.isGuestAccessEnabled());
return sceneService.save(newScene); return sceneService.save(newScene);
} }
@ -91,6 +93,8 @@ public class SceneController {
newScene.setName(s.getName()); newScene.setName(s.getName());
} }
newScene.setGuestAccessEnabled(s.isGuestAccessEnabled());
return sceneService.save(newScene); return sceneService.save(newScene);
} }

View file

@ -1,18 +1,16 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
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;
import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.PutMapping;
@ -26,31 +24,24 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/securityCamera") @RequestMapping("/securityCamera")
public class SecurityCameraController { public class SecurityCameraController {
@Autowired DeviceService deviceService;
@Autowired SecurityCameraRepository securityCameraService; @Autowired SecurityCameraRepository securityCameraService;
@Autowired private SceneRepository sceneRepository; @Autowired private SceneRepository sceneRepository;
@Autowired private StateRepository<State<?>> stateRepository; @Autowired private StateRepository<State<?>> stateRepository;
@GetMapping private SecurityCamera save(
public List<SecurityCamera> findAll() { SecurityCamera newSC, SwitchableSaveRequest sc, final Principal principal) {
return toList(securityCameraService.findAll());
}
@GetMapping("/{id}")
public SecurityCamera findById(@PathVariable("id") long id) throws NotFoundException {
return securityCameraService.findById(id).orElseThrow(NotFoundException::new);
}
private SecurityCamera save(SecurityCamera newSC, SwitchableSaveRequest sc) {
newSC.setName(sc.getName()); newSC.setName(sc.getName());
newSC.setRoomId(sc.getRoomId()); newSC.setRoomId(sc.getRoomId());
newSC.setOn(sc.isOn()); newSC.setOn(sc.isOn());
return securityCameraService.save(newSC); return deviceService.saveAsOwner(newSC, principal.getName());
} }
@PostMapping @PostMapping
public SecurityCamera create(@Valid @RequestBody SwitchableSaveRequest sc) { public SecurityCamera create(
return save(new SecurityCamera(), sc); @Valid @RequestBody SwitchableSaveRequest sc, final Principal principal) {
return save(new SecurityCamera(), sc, principal);
} }
@PutMapping @PutMapping
@ -61,12 +52,14 @@ public class SecurityCameraController {
securityCameraService securityCameraService
.findByIdAndUsername(sc.getId(), principal.getName()) .findByIdAndUsername(sc.getId(), principal.getName())
.orElseThrow(NotFoundException::new), .orElseThrow(NotFoundException::new),
sc); sc,
principal);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void delete(@PathVariable("id") long id) { public void delete(@PathVariable("id") long id, final Principal principal)
securityCameraService.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
@PostMapping("/{id}/state") @PostMapping("/{id}/state")

View file

@ -1,19 +1,16 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SensorSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SensorSaveRequest;
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.DeviceService;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SensorService; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SensorService;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.security.Principal; import java.security.Principal;
import java.util.*; import java.util.*;
import java.util.List;
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.*; import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -23,34 +20,23 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/sensor") @RequestMapping("/sensor")
public class SensorController { public class SensorController {
@Autowired @Autowired private DeviceService deviceService;
private SensorRepository sensorRepository;
@Autowired @Autowired private SensorRepository sensorRepository;
private SensorSocketEndpoint sensorSocketEndpoint;
@Autowired @Autowired private SensorSocketEndpoint sensorSocketEndpoint;
private SensorService sensorService;
@GetMapping @Autowired private SensorService sensorService;
public List<Sensor> findAll() {
return toList(sensorRepository.findAll());
}
@GetMapping("/{id}")
public Sensor findById(@PathVariable("id") long id) throws NotFoundException {
return sensorRepository.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping @PostMapping
public Sensor create(@Valid @RequestBody SensorSaveRequest s) { public Sensor create(@Valid @RequestBody SensorSaveRequest s, final Principal principal) {
Sensor newSensor = new Sensor(); Sensor newSensor = new Sensor();
newSensor.setSensor(s.getSensor()); newSensor.setSensor(s.getSensor());
newSensor.setName(s.getName()); newSensor.setName(s.getName());
newSensor.setRoomId(s.getRoomId()); newSensor.setRoomId(s.getRoomId());
newSensor.setValue(s.getValue()); newSensor.setValue(s.getValue());
return sensorRepository.save(newSensor); return deviceService.saveAsOwner(newSensor, principal.getName());
} }
@PutMapping("/{id}/value") @PutMapping("/{id}/value")
@ -67,7 +53,8 @@ public class SensorController {
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) { public void deleteById(@PathVariable("id") long id, final Principal principal)
sensorRepository.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
} }

View file

@ -1,13 +1,12 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchableSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
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.*; import org.springframework.boot.autoconfigure.*;
@ -18,32 +17,24 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/smartPlug") @RequestMapping("/smartPlug")
public class SmartPlugController { public class SmartPlugController {
@Autowired private DeviceService deviceService;
@Autowired private SmartPlugRepository smartPlugRepository; @Autowired private SmartPlugRepository smartPlugRepository;
@Autowired private SceneRepository sceneRepository; @Autowired private SceneRepository sceneRepository;
@Autowired private StateRepository<State<?>> stateRepository; @Autowired private StateRepository<State<?>> stateRepository;
@GetMapping private SmartPlug save(SmartPlug newSP, SwitchableSaveRequest sp, final Principal principal) {
public List<SmartPlug> findAll() {
return toList(smartPlugRepository.findAll());
}
@GetMapping("/{id}")
public SmartPlug findById(@PathVariable("id") long id) throws NotFoundException {
return smartPlugRepository.findById(id).orElseThrow(NotFoundException::new);
}
private SmartPlug save(SmartPlug newSP, SwitchableSaveRequest sp) {
newSP.setOn(sp.isOn()); newSP.setOn(sp.isOn());
newSP.setId(sp.getId()); newSP.setId(sp.getId());
newSP.setName(sp.getName()); newSP.setName(sp.getName());
newSP.setRoomId(sp.getRoomId()); newSP.setRoomId(sp.getRoomId());
return smartPlugRepository.save(newSP); return deviceService.saveAsOwner(newSP, principal.getName());
} }
@PostMapping @PostMapping
public SmartPlug create(@Valid @RequestBody SwitchableSaveRequest sp) { public SmartPlug create(
return save(new SmartPlug(), sp); @Valid @RequestBody SwitchableSaveRequest sp, final Principal principal) {
return save(new SmartPlug(), sp, principal);
} }
@PutMapping @PutMapping
@ -53,7 +44,8 @@ public class SmartPlugController {
smartPlugRepository smartPlugRepository
.findByIdAndUsername(sp.getId(), principal.getName()) .findByIdAndUsername(sp.getId(), principal.getName())
.orElseThrow(NotFoundException::new), .orElseThrow(NotFoundException::new),
sp); sp,
principal);
} }
@DeleteMapping("/{id}/meter") @DeleteMapping("/{id}/meter")
@ -69,8 +61,9 @@ public class SmartPlugController {
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) { public void deleteById(@PathVariable("id") long id, final Principal principal)
smartPlugRepository.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
@PostMapping("/{id}/state") @PostMapping("/{id}/state")

View file

@ -1,15 +1,13 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.controller; package ch.usi.inf.sa4.sanmarinoes.smarthut.controller;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.GenericDeviceSaveReguest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchOperationRequest; import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SwitchOperationRequest;
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.DeviceService;
import java.security.Principal; import java.security.Principal;
import java.util.*; import java.util.*;
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.*; import org.springframework.boot.autoconfigure.*;
@ -22,6 +20,7 @@ public class SwitchController extends InputDeviceConnectionController<Switch, Sw
private SwitchRepository switchRepository; private SwitchRepository switchRepository;
private SwitchableRepository<Switchable> switchableRepository; private SwitchableRepository<Switchable> switchableRepository;
private DeviceService deviceService;
/** /**
* Contstructs the controller by requiring essential object for the controller implementation * Contstructs the controller by requiring essential object for the controller implementation
@ -31,29 +30,23 @@ public class SwitchController extends InputDeviceConnectionController<Switch, Sw
*/ */
@Autowired @Autowired
protected SwitchController( protected SwitchController(
SwitchRepository inputRepository, SwitchableRepository<Switchable> outputRepository) { SwitchRepository inputRepository,
SwitchableRepository<Switchable> outputRepository,
DeviceService deviceService) {
super(inputRepository, outputRepository, Switchable.SWITCH_SWITCHABLE_CONNECTOR); super(inputRepository, outputRepository, Switchable.SWITCH_SWITCHABLE_CONNECTOR);
this.deviceService = deviceService;
this.switchRepository = inputRepository; this.switchRepository = inputRepository;
this.switchableRepository = outputRepository; this.switchableRepository = outputRepository;
} }
@GetMapping
public List<Switch> findAll() {
return toList(switchRepository.findAll());
}
@GetMapping("/{id}")
public Switch findById(@PathVariable("id") long id) throws NotFoundException {
return switchRepository.findById(id).orElseThrow(NotFoundException::new);
}
@PostMapping @PostMapping
public Switch create(@Valid @RequestBody GenericDeviceSaveReguest s) { public Switch create(
@Valid @RequestBody GenericDeviceSaveReguest s, final Principal principal) {
Switch newSwitch = new Switch(); Switch newSwitch = new Switch();
newSwitch.setName(s.getName()); newSwitch.setName(s.getName());
newSwitch.setRoomId(s.getRoomId()); newSwitch.setRoomId(s.getRoomId());
return switchRepository.save(newSwitch); return deviceService.saveAsOwner(newSwitch, principal.getName());
} }
@PutMapping("/operate") @PutMapping("/operate")
@ -83,7 +76,8 @@ public class SwitchController extends InputDeviceConnectionController<Switch, Sw
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) { public void deleteById(@PathVariable("id") long id, final Principal principal)
switchRepository.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
} }

View file

@ -4,9 +4,9 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.ThermostatSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException; import ch.usi.inf.sa4.sanmarinoes.smarthut.error.DuplicateStateException;
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.DeviceService;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService;
import java.security.Principal; import java.security.Principal;
import java.util.List;
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.*; import org.springframework.boot.autoconfigure.*;
@ -17,27 +17,13 @@ import org.springframework.web.bind.annotation.*;
@RequestMapping("/thermostat") @RequestMapping("/thermostat")
public class ThermostatController { public class ThermostatController {
@Autowired private DeviceService deviceService;
@Autowired private ThermostatRepository thermostatRepository; @Autowired private ThermostatRepository thermostatRepository;
@Autowired private ThermostatService thermostatService; @Autowired private ThermostatService thermostatService;
@Autowired private SceneRepository sceneRepository; @Autowired private SceneRepository sceneRepository;
@Autowired private StateRepository<State<?>> stateRepository; @Autowired private StateRepository<State<?>> stateRepository;
@GetMapping private Thermostat save(Thermostat newT, ThermostatSaveRequest t, final Principal principal) {
public List<Thermostat> findAll(Principal user) {
return thermostatService.findAll(user.getName());
}
@GetMapping("/{id}")
public Thermostat findById(@PathVariable("id") long id, Principal principal)
throws NotFoundException {
return thermostatService
.findById(id, principal.getName())
.orElseThrow(NotFoundException::new);
}
private Thermostat save(Thermostat newT, ThermostatSaveRequest t) {
newT.setTargetTemperature(t.getTargetTemperature()); newT.setTargetTemperature(t.getTargetTemperature());
newT.setId(t.getId()); newT.setId(t.getId());
newT.setName(t.getName()); newT.setName(t.getName());
@ -45,14 +31,15 @@ public class ThermostatController {
newT.setUseExternalSensors(t.isUseExternalSensors()); newT.setUseExternalSensors(t.isUseExternalSensors());
newT.setOn(t.isTurnOn()); newT.setOn(t.isTurnOn());
newT = thermostatRepository.save(newT); newT = deviceService.saveAsOwner(newT, principal.getName());
thermostatService.populateMeasuredTemperature(newT); thermostatService.populateMeasuredTemperature(newT);
return newT; return newT;
} }
@PostMapping @PostMapping
public Thermostat create(@Valid @RequestBody ThermostatSaveRequest t) { public Thermostat create(
return save(new Thermostat(), t); @Valid @RequestBody ThermostatSaveRequest t, final Principal principal) {
return save(new Thermostat(), t, principal);
} }
@PutMapping @PutMapping
@ -62,12 +49,14 @@ public class ThermostatController {
thermostatRepository thermostatRepository
.findByIdAndUsername(t.getId(), principal.getName()) .findByIdAndUsername(t.getId(), principal.getName())
.orElseThrow(NotFoundException::new), .orElseThrow(NotFoundException::new),
t); t,
principal);
} }
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) { public void deleteById(@PathVariable("id") long id, final Principal principal)
thermostatRepository.deleteById(id); throws NotFoundException {
deviceService.delete(id, principal.getName());
} }
@PostMapping("/{id}/state") @PostMapping("/{id}/state")

View file

@ -0,0 +1,14 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
public class GuestPermissionsRequest {
private boolean cameraEnabled;
public boolean isCameraEnabled() {
return cameraEnabled;
}
public void setCameraEnabled(boolean cameraEnabled) {
this.cameraEnabled = cameraEnabled;
}
}

View file

@ -1,6 +1,7 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; package ch.usi.inf.sa4.sanmarinoes.smarthut.dto;
import com.sun.istack.NotNull; import com.sun.istack.NotNull;
import javax.persistence.Column;
public class SceneSaveRequest { public class SceneSaveRequest {
@ -10,6 +11,17 @@ public class SceneSaveRequest {
/** The user given name of this room (e.g. 'Master bedroom') */ /** The user given name of this room (e.g. 'Master bedroom') */
@NotNull private String name; @NotNull private String name;
/** Determines whether a guest can access this scene */
@Column @NotNull private boolean guestAccessEnabled;
public boolean isGuestAccessEnabled() {
return guestAccessEnabled;
}
public void setGuestAccessEnabled(boolean guestAccessEnabled) {
this.guestAccessEnabled = guestAccessEnabled;
}
public long getId() { public long getId() {
return id; return id;
} }

View file

@ -1,6 +1,7 @@
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.GsonExclude;
import ch.usi.inf.sa4.sanmarinoes.smarthut.config.SocketGsonExclude;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.util.HashSet; import java.util.HashSet;
@ -32,6 +33,7 @@ public abstract class Device {
@ManyToOne @ManyToOne
@JoinColumn(name = "room_id", updatable = false, insertable = false) @JoinColumn(name = "room_id", updatable = false, insertable = false)
@GsonExclude @GsonExclude
@SocketGsonExclude
private Room room; private Room room;
/** /**
@ -61,7 +63,38 @@ public abstract class Device {
@OneToMany(mappedBy = "device", orphanRemoval = true) @OneToMany(mappedBy = "device", orphanRemoval = true)
@GsonExclude @GsonExclude
private Set<State> states = new HashSet<>(); @SocketGsonExclude
private Set<State<?>> states = new HashSet<>();
@Transient @GsonExclude private boolean fromHost = false;
@Transient @GsonExclude private boolean fromGuest = false;
@Transient @GsonExclude private boolean deleted = false;
public boolean isFromHost() {
return fromHost;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public boolean isFromGuest() {
return fromGuest;
}
public void setFromGuest(boolean fromGuest) {
this.fromGuest = fromGuest;
}
public void setFromHost(boolean fromHost) {
this.fromHost = fromHost;
}
public long getId() { public long getId() {
return id; return id;

View file

@ -25,6 +25,16 @@ public interface DeviceRepository<T extends Device> extends CrudRepository<T, Lo
@Query("SELECT d FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1 AND u.username = ?2") @Query("SELECT d FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1 AND u.username = ?2")
Optional<T> findByIdAndUsername(Long id, String username); Optional<T> findByIdAndUsername(Long id, String username);
/**
* Finds devices by their id and a user id
*
* @param id the device id
* @param userId a User's id
* @return an optional device, empty if none found
*/
@Query("SELECT d FROM Device d JOIN d.room r JOIN r.user u WHERE d.id = ?1 AND u.id = ?2")
Optional<T> findByIdAndUserId(Long id, Long userId);
/** /**
* Finds all devices belonging to a user * Finds all devices belonging to a user
* *

View file

@ -145,7 +145,6 @@ public class Room {
*/ */
@NotNull @NotNull
@Column(name = "user_id", nullable = false) @Column(name = "user_id", nullable = false)
@GsonExclude
private Long userId; private Long userId;
/** The user given name of this room (e.g. 'Master bedroom') */ /** The user given name of this room (e.g. 'Master bedroom') */

View file

@ -39,6 +39,17 @@ public class Scene {
@Column(nullable = false) @Column(nullable = false)
private String name; private String name;
/** Determines whether a guest can access this scene */
@Column private boolean guestAccessEnabled;
public boolean isGuestAccessEnabled() {
return guestAccessEnabled;
}
public void setGuestAccessEnabled(boolean guestAccessEnabled) {
this.guestAccessEnabled = guestAccessEnabled;
}
public String getName() { public String getName() {
return name; return name;
} }

View file

@ -2,7 +2,9 @@ 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 java.util.HashSet;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import javax.persistence.*; import javax.persistence.*;
/** A user of the Smarthut application */ /** A user of the Smarthut application */
@ -35,6 +37,23 @@ public class User {
@Column(nullable = false, unique = true) @Column(nullable = false, unique = true)
private String email; private String email;
/** Guests invited by this user */
@ManyToMany(mappedBy = "hosts", cascade = CascadeType.DETACH)
@GsonExclude
private Set<User> guests = new HashSet<>();
@ManyToMany(cascade = CascadeType.DETACH)
@JoinTable(
name = "invited",
joinColumns = @JoinColumn(name = "guest_id"),
inverseJoinColumns = @JoinColumn(name = "host_id"))
@GsonExclude
private Set<User> hosts = new HashSet<>();
/** Determines whether a guest can access security cameras */
@Column(nullable = false)
private boolean cameraEnabled;
@Column(nullable = false) @Column(nullable = false)
@GsonExclude @GsonExclude
private Boolean isEnabled = false; private Boolean isEnabled = false;
@ -87,10 +106,37 @@ public class User {
isEnabled = enabled; isEnabled = enabled;
} }
public Set<User> getGuests() {
return guests;
}
public Set<User> getHosts() {
return hosts;
}
public boolean isCameraEnabled() {
return cameraEnabled;
}
public void addGuest(User guest) {
this.guests.add(guest);
}
public void addHost(User host) {
this.hosts.add(host);
}
public void removeGuest(User guest) {
this.guests.remove(guest);
}
public void setCameraEnabled(boolean cameraEnabled) {
this.cameraEnabled = cameraEnabled;
}
@Override @Override
public String toString() { public String toString() {
return "User{" return "User{id="
+ "id="
+ id + id
+ ", name='" + ", name='"
+ name + name
@ -104,6 +150,8 @@ public class User {
+ ", email='" + ", email='"
+ email + email
+ '\'' + '\''
+ ", cameraEnabled="
+ cameraEnabled
+ ", isEnabled=" + ", isEnabled="
+ isEnabled + isEnabled
+ '}'; + '}';

View file

@ -0,0 +1,137 @@
package ch.usi.inf.sa4.sanmarinoes.smarthut.service;
import static ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils.toList;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DeviceService {
// FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF)
@Autowired private DeviceRepository<Device> deviceRepository;
@Autowired private RoomRepository roomRepository;
@Autowired private UserRepository userRepository;
@Autowired private SensorSocketEndpoint endpoint;
@Autowired private ThermostatService thermostatService;
public List<Device> findAll(Long hostId, String username) throws NotFoundException {
return findAll(null, hostId, username);
}
public List<Device> findAll(Long roomId, Long hostId, String username)
throws NotFoundException {
try {
Iterable<Device> devices;
if (hostId == null) {
if (roomId != null) {
roomRepository
.findByIdAndUsername(roomId, username)
.orElseThrow(NotFoundException::new);
devices = deviceRepository.findByRoomId(roomId);
} else {
devices = deviceRepository.findAllByUsername(username);
}
} else {
final User guest = userRepository.findByUsername(username);
final User host =
userRepository.findById(hostId).orElseThrow(NotFoundException::new);
if (!guest.getHosts().contains(host)) {
throw new NotFoundException();
}
if (roomId != null) {
Room r = roomRepository.findById(roomId).orElseThrow(NotFoundException::new);
if (!r.getUserId().equals(hostId)) {
throw new NotFoundException();
}
devices = deviceRepository.findByRoomId(roomId);
} else {
devices = deviceRepository.findAllByUsername(host.getUsername());
}
}
for (Device d : devices) {
if (d instanceof Thermostat) {
thermostatService.populateMeasuredTemperature((Thermostat) d);
}
}
return toList(devices);
} catch (NotFoundException e) {
e.printStackTrace();
throw e;
}
}
public <T extends Device> T saveAsGuest(T device, String guestUsername, Long hostId)
throws NotFoundException {
device = deviceRepository.save(device);
final User currentUser = userRepository.findByUsername(guestUsername);
final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
final Set<User> guests = Set.copyOf(host.getGuests());
// We're telling the host that a guest has modified a device. Therefore, fromGuest becomes
// true.
device.setFromHost(false);
device.setFromGuest(true);
// broadcast device update to host
endpoint.queueDeviceUpdate(device, host);
// 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) {
if (guest.equals(currentUser)) {
continue;
}
// enqueue all device updates for all other guests
endpoint.queueDeviceUpdate(device, guest);
}
return device;
}
public <T extends Device> T saveAsOwner(T device, String username) {
device = deviceRepository.save(device);
final User user = userRepository.findByUsername(username);
final Set<User> guests = user.getGuests();
// make sure we're broadcasting from host
device.setFromHost(true);
device.setFromGuest(false);
for (final User guest : guests) {
// broadcast to endpoint the object device, with receiving user set to guest
endpoint.queueDeviceUpdate(device, guest);
}
return device;
}
public void delete(Long id, String username) throws NotFoundException {
Device device =
deviceRepository
.findByIdAndUsername(id, username)
.orElseThrow(NotFoundException::new);
deviceRepository.delete(device);
final User user = userRepository.findByUsername(username);
final Set<User> guests = user.getGuests();
device.setFromHost(true);
device.setFromGuest(false);
device.setDeleted(true);
for (final User guest : guests) {
// broadcast to endpoint the object device, with receiving user set to guest
endpoint.queueDeviceUpdate(device, guest);
}
}
}

View file

@ -9,25 +9,17 @@ 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;
import com.google.gson.Gson; import com.google.gson.Gson;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import javax.websocket.*; import javax.websocket.*;
import com.google.gson.JsonObject;
import io.jsonwebtoken.ExpiredJwtException;
import org.hibernate.annotations.common.reflection.XProperty;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /** Endpoint of socket at URL /sensor-socket used to update the client with sensor information */
* Endpoint of socket at URL /sensor-socket used to update the client with sensor information
*/
@Component @Component
public class SensorSocketEndpoint extends Endpoint { public class SensorSocketEndpoint extends Endpoint {
private Gson gson = GsonConfig.gson(); private Gson gson = GsonConfig.socketGson();
private UserRepository userRepository; private UserRepository userRepository;
@ -46,6 +38,7 @@ public class SensorSocketEndpoint extends Endpoint {
/** /**
* Queues a single device update for a certain user to be sent * Queues a single device update for a certain user to be sent
*
* @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
*/ */
@ -56,9 +49,7 @@ public class SensorSocketEndpoint extends Endpoint {
} }
} }
/** /** 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, Device>> batchForUser : messages.entrySet()) {
@ -69,8 +60,8 @@ public class SensorSocketEndpoint extends Endpoint {
} }
/** /**
* Given a collection of messages and a user, broadcasts that message in json to all * Given a collection of messages and a user, broadcasts that message in json to all associated
* associated clients * clients
* *
* @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

View file

@ -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;
}
};
}
} }