Merge branch '69-7-fixes-to-guest-user-story' into 'dev'

Resolve "7: fixes to guest user story"

Closes #69

See merge request sa4-2020/the-sanmarinoes/backend!112
This commit is contained in:
Claudio Maggioni 2020-05-04 17:15:29 +02:00
commit 38c703e521
4 changed files with 83 additions and 40 deletions

View file

@ -6,20 +6,13 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.dto.SceneSaveRequest;
import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException;
import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*;
import ch.usi.inf.sa4.sanmarinoes.smarthut.service.SceneService;
import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils;
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.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
@ -27,21 +20,20 @@ import org.springframework.web.bind.annotation.RestController;
public class SceneController {
@Autowired private SceneRepository sceneRepository;
@Autowired private UserRepository userRepository;
@Autowired private SceneService sceneService;
@Autowired private UserRepository userService;
@Autowired private StateRepository<State<?>> stateService;
@Autowired private StateRepository<State<?>> stateRepository;
@GetMapping
public List<Scene> findAll(Principal principal) {
return toList(sceneRepository.findByUsername(principal.getName()));
}
@GetMapping("/{id}")
public @ResponseBody Scene findById(@PathVariable("id") long id, Principal principal)
public List<Scene> findAll(
Principal principal, @RequestParam(value = "hostId", required = false) Long hostId)
throws NotFoundException {
return sceneRepository
.findByIdAndUsername(id, principal.getName())
.orElseThrow(NotFoundException::new);
if (hostId == null) {
return toList(sceneRepository.findByUsername(principal.getName()));
} else {
Utils.returnIfGuest(userRepository, null, hostId, principal);
return sceneRepository.findByHostId(hostId);
}
}
@PostMapping
@ -49,7 +41,7 @@ public class SceneController {
@Valid @RequestBody SceneSaveRequest s, final Principal principal) {
final String username = principal.getName();
final Long userId = userService.findByUsername(username).getId();
final Long userId = userRepository.findByUsername(username).getId();
final Scene newScene = new Scene();
@ -62,14 +54,27 @@ public class SceneController {
}
@PostMapping("/{id}/apply")
public @ResponseBody List<Device> apply(@PathVariable("id") long id, final Principal principal)
public @ResponseBody List<Device> apply(
@PathVariable("id") long id,
final Principal principal,
@RequestParam(value = "hostId", required = false) Long hostId)
throws NotFoundException {
final Scene newScene =
sceneRepository
.findByIdAndUsername(id, principal.getName())
.orElseThrow(NotFoundException::new);
return sceneService.apply(newScene, principal.getName(), false);
if (hostId == null) {
return sceneService.apply(
sceneRepository
.findByIdAndUsername(id, principal.getName())
.orElseThrow(NotFoundException::new),
principal.getName(),
false);
} else {
Utils.returnIfGuest(userRepository, null, hostId, principal);
return sceneService.applyAsGuest(
sceneRepository
.findByIdAndUserId(id, hostId)
.orElseThrow(NotFoundException::new),
principal.getName(),
hostId);
}
}
@PostMapping("/{id}/copyFrom/{copyId}")
@ -112,7 +117,7 @@ public class SceneController {
@DeleteMapping("/{id}")
public void deleteById(@PathVariable("id") long id) {
stateService.deleteAllBySceneId(id);
stateRepository.deleteAllBySceneId(id);
sceneRepository.deleteById(id);
}
@ -122,7 +127,7 @@ public class SceneController {
*/
@GetMapping(path = "/{sceneId}/states")
public List<State<?>> getDevices(@PathVariable("sceneId") long sceneId) {
Iterable<State<?>> states = stateService.findBySceneId(sceneId);
Iterable<State<?>> states = stateRepository.findBySceneId(sceneId);
return toList(states);
}
}

View file

@ -19,4 +19,9 @@ public interface SceneRepository extends CrudRepository<Scene, Long> {
@Query("SELECT s FROM Scene s JOIN s.user u WHERE u.username = ?1")
List<Scene> findByUsername(String username);
@Query("SELECT s FROM Scene s JOIN s.user u WHERE u.id = ?1 AND s.guestAccessEnabled = true")
List<Scene> findByHostId(Long hostId);
Optional<Scene> findByIdAndUserId(Long id, Long userId);
}

View file

@ -9,6 +9,8 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -68,6 +70,7 @@ public class DeviceService {
throws NotFoundException {
try {
Iterable<Device> devices;
User host = null;
if (hostId == null) {
if (roomId != null) {
roomRepository
@ -79,8 +82,7 @@ public class DeviceService {
}
} else {
final User guest = userRepository.findByUsername(username);
final User host =
userRepository.findById(hostId).orElseThrow(NotFoundException::new);
host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
if (!guest.getHosts().contains(host)) {
throw new NotFoundException();
@ -99,7 +101,13 @@ public class DeviceService {
populateComputedFields(devices);
return toList(devices);
if (host != null && !host.isCameraEnabled()) {
return StreamSupport.stream(devices.spliterator(), true)
.filter(d -> !(d instanceof SecurityCamera))
.collect(Collectors.toList());
} else {
return toList(devices);
}
} catch (NotFoundException e) {
e.printStackTrace();
throw e;
@ -120,7 +128,13 @@ public class DeviceService {
final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new);
if (!host.getGuests().contains(currentUser)) throw new NotFoundException();
renameIfDuplicate(device, host.getUsername());
device = deviceRepository.save(device);
propagateUpdateAsGuest(device, host, currentUser);
return device;
}
private void propagateUpdateAsGuest(Device device, User host, User guest) {
final Set<User> guests = Set.copyOf(host.getGuests());
// We're telling the host that a guest has modified a device. Therefore, fromGuest becomes
@ -130,15 +144,22 @@ public class DeviceService {
// We're telling all guests that a higher entity has issued a device update. Therefore,
// fromHost becomes true.
for (final User guest : guests) {
if (guest.equals(currentUser)) {
for (final User aGuest : guests) {
if (aGuest.equals(guest)) {
continue;
}
// enqueue all device updates for all other guests
endpoint.queueDeviceUpdate(device, guest, false, host.getId(), false);
endpoint.queueDeviceUpdate(device, aGuest, false, host.getId(), false);
}
}
return device;
List<Device> saveAllAsGuestSceneApplication(
List<Device> devices, String guestUsername, Long hostId) {
final User guest = userRepository.findByUsername(guestUsername);
final User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new);
deviceRepository.saveAll(devices);
devices.forEach(d -> this.propagateUpdateAsGuest(d, host, guest));
return devices;
}
/**

View file

@ -13,18 +13,30 @@ public class SceneService {
@Autowired private DeviceService deviceService;
@Autowired private StateRepository<State<?>> stateRepository;
public List<Device> apply(Scene newScene, String username, boolean fromTrigger) {
private List<Device> copyStatesToDevices(Scene fromScene) {
final List<Device> updated = new ArrayList<>();
for (final State<?> s : newScene.getStates()) {
for (final State<?> s : fromScene.getStates()) {
s.apply();
updated.add(s.getDevice());
}
deviceService.saveAllAsOwner(updated, username, true, fromTrigger);
deviceService.populateComputedFields(updated);
return updated;
}
public List<Device> apply(Scene newScene, String username, boolean fromTrigger) {
List<Device> updated = copyStatesToDevices(newScene);
deviceService.saveAllAsOwner(updated, username, true, fromTrigger);
return updated;
}
public List<Device> applyAsGuest(Scene newScene, String username, Long hostId) {
List<Device> updated = copyStatesToDevices(newScene);
deviceService.saveAllAsGuestSceneApplication(updated, username, hostId);
return updated;
}
public List<State<?>> copyStates(Scene to, Scene from) {
final ArrayList<State<?>> states = new ArrayList<>();
for (final State<?> s : from.getStates()) {