From 3921fe13308f54b61f22cd81f032766120e2d1b6 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Fri, 17 Apr 2020 14:58:26 +0200 Subject: [PATCH 01/16] started invitation relationship --- .../sanmarinoes/smarthut/models/Invited.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java new file mode 100644 index 0000000..d56a55b --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java @@ -0,0 +1,38 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.models; + +import java.util.Set; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.validation.constraints.NotNull; + +/** Represents a recursive invitation relationship between two users. */ +@Entity +public class Invited { + + /** A host user who can invite guests to their smart house */ + @OneToMany private Set host; + + /** Guests that have been invited to the host's house */ + @OneToMany(mappedBy = "host", orphanRemoval = true) + private Set guest; + + /** Host ID */ + @Id + @Column(nullable = false) + private int hostId; + + /** + * Probably unnecessary, Invited can be identified through the Host ID and the IDs from the + * guests collection which we can query for + */ + // @Id @Column + // private int guestId; + + /** Determines whether a guest can access security cameras */ + @Column @NotNull private boolean cameraEnabled; + + /** Determines whether a guest can access scenes */ + @Column @NotNull private boolean sceneEnabled; +} From 6e36d7d306e143050a0ca0a6cc22c1db571d2bb9 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Fri, 17 Apr 2020 15:24:06 +0200 Subject: [PATCH 02/16] updated onetomany relationship --- .../sa4/sanmarinoes/smarthut/models/Invited.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java index d56a55b..c389e18 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java @@ -1,10 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import java.util.Set; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.OneToMany; +import javax.persistence.*; import javax.validation.constraints.NotNull; /** Represents a recursive invitation relationship between two users. */ @@ -12,11 +9,13 @@ import javax.validation.constraints.NotNull; public class Invited { /** A host user who can invite guests to their smart house */ - @OneToMany private Set host; + @OneToMany(mappedBy = "host") + private Set host; /** Guests that have been invited to the host's house */ - @OneToMany(mappedBy = "host", orphanRemoval = true) - private Set guest; + @ManyToOne + @JoinColumn(name = "guests") + private User guest; /** Host ID */ @Id From d2aaa45a8b95475f47a8a26042ba7c925e9bc728 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Sat, 18 Apr 2020 14:11:21 +0200 Subject: [PATCH 03/16] hopefully fixed invited relationship --- .../ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java | 5 ----- .../ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java index c389e18..63cf553 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java @@ -1,6 +1,5 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; -import java.util.Set; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -8,10 +7,6 @@ import javax.validation.constraints.NotNull; @Entity public class Invited { - /** A host user who can invite guests to their smart house */ - @OneToMany(mappedBy = "host") - private Set host; - /** Guests that have been invited to the host's house */ @ManyToOne @JoinColumn(name = "guests") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index 60aad17..8ad844d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -3,6 +3,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import io.swagger.annotations.ApiModelProperty; import java.util.Objects; +import java.util.Set; import javax.persistence.*; /** A user of the Smarthut application */ @@ -35,6 +36,10 @@ public class User { @Column(nullable = false, unique = true) private String email; + /** A host user who can invite guests to their smart house */ + @OneToMany(mappedBy = "host") + private Set guests; + @Column(nullable = false) @GsonExclude private Boolean isEnabled = false; From 262dbf12e793c47ed1a7e1a23722cd030f5a896a Mon Sep 17 00:00:00 2001 From: tommi27 Date: Sat, 18 Apr 2020 14:52:11 +0200 Subject: [PATCH 04/16] hopefully fixed invited relationship II: The Revenge --- .../java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index 8ad844d..67ba0a0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -37,7 +37,7 @@ public class User { private String email; /** A host user who can invite guests to their smart house */ - @OneToMany(mappedBy = "host") + @OneToMany(mappedBy = "guest") private Set guests; @Column(nullable = false) From 566a2e72e3a378f0044be0628c582842e1a5dac9 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Sat, 18 Apr 2020 15:35:04 +0200 Subject: [PATCH 05/16] invited model finally works --- .../sanmarinoes/smarthut/models/Device.java | 2 +- .../sanmarinoes/smarthut/models/Invited.java | 32 ------------------- .../sa4/sanmarinoes/smarthut/models/User.java | 27 ++++++++++++++-- 3 files changed, 25 insertions(+), 36 deletions(-) delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 0114ac3..9b0cc2d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -61,7 +61,7 @@ public abstract class Device { @OneToMany(mappedBy = "device", orphanRemoval = true) @GsonExclude - private Set states = new HashSet<>(); + private Set> states = new HashSet<>(); public long getId() { return id; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java deleted file mode 100644 index 63cf553..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Invited.java +++ /dev/null @@ -1,32 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.models; - -import javax.persistence.*; -import javax.validation.constraints.NotNull; - -/** Represents a recursive invitation relationship between two users. */ -@Entity -public class Invited { - - /** Guests that have been invited to the host's house */ - @ManyToOne - @JoinColumn(name = "guests") - private User guest; - - /** Host ID */ - @Id - @Column(nullable = false) - private int hostId; - - /** - * Probably unnecessary, Invited can be identified through the Host ID and the IDs from the - * guests collection which we can query for - */ - // @Id @Column - // private int guestId; - - /** Determines whether a guest can access security cameras */ - @Column @NotNull private boolean cameraEnabled; - - /** Determines whether a guest can access scenes */ - @Column @NotNull private boolean sceneEnabled; -} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index 67ba0a0..23e8217 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -2,9 +2,11 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; import io.swagger.annotations.ApiModelProperty; +import java.util.HashSet; import java.util.Objects; import java.util.Set; import javax.persistence.*; +import javax.validation.constraints.NotNull; /** A user of the Smarthut application */ @Entity(name = "smarthutuser") @@ -36,9 +38,28 @@ public class User { @Column(nullable = false, unique = true) private String email; - /** A host user who can invite guests to their smart house */ - @OneToMany(mappedBy = "guest") - private Set guests; + /** Guests invited by this user */ + @ManyToMany(cascade = CascadeType.DETACH) + @JoinTable( + name = "invited", + joinColumns = @JoinColumn(name = "host_id"), + inverseJoinColumns = @JoinColumn(name = "guest_id")) + @GsonExclude + private Set guests = new HashSet<>(); + + @ManyToMany(cascade = CascadeType.DETACH) + @JoinTable( + name = "invited", + joinColumns = @JoinColumn(name = "guest_id"), + inverseJoinColumns = @JoinColumn(name = "host_id")) + @GsonExclude + private Set hosts = new HashSet<>(); + + /** Determines whether a guest can access security cameras */ + @Column @NotNull private boolean cameraEnabled; + + /** Determines whether a guest can access scenes */ + @Column @NotNull private boolean sceneEnabled; @Column(nullable = false) @GsonExclude From 36a7a649d5dcef94c94d38234e475cca82293b9e Mon Sep 17 00:00:00 2001 From: tommi27 Date: Sat, 18 Apr 2020 17:35:14 +0200 Subject: [PATCH 06/16] started guest controllers (WIP) --- .../smarthut/controller/GuestController.java | 39 +++++++++++++++++++ .../smarthut/controller/SceneController.java | 10 +++-- .../smarthut/dto/GuestUserResponse.java | 14 +++++++ .../smarthut/dto/SceneSaveRequest.java | 12 ++++++ .../sanmarinoes/smarthut/models/Scene.java | 11 ++++++ .../sa4/sanmarinoes/smarthut/models/User.java | 26 ++++++++++--- 6 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java new file mode 100644 index 0000000..ab47121 --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java @@ -0,0 +1,39 @@ +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.GuestUserResponse; +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.web.bind.annotation.*; + +public class GuestController { + + @Autowired private UserRepository userRepository; + + @GetMapping + public List findAll() { + return toList(userRepository.findAll()); + } + + @PostMapping + public void addUserAsGuest(long id, final Principal principal) throws NotFoundException { + User guest = userRepository.findById(id).orElseThrow(NotFoundException::new); + User host = userRepository.findByUsername(principal.getName()); + + host.addGuest(guest); + userRepository.save(guest); + userRepository.save(host); + } + + @PutMapping + public void updatePermissions(@Valid @RequestBody GuestUserResponse g, Principal principal) {} + + @DeleteMapping + public void removeUserAsGuest(long id) {} +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java index 2b4c9c1..a4da945 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -26,10 +26,10 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/scene") public class SceneController { - @Autowired SceneRepository sceneService; - @Autowired UserRepository userService; - @Autowired StateRepository> stateService; - @Autowired DeviceRepository deviceRepository; + @Autowired private SceneRepository sceneService; + @Autowired private UserRepository userService; + @Autowired private StateRepository> stateService; + @Autowired private DeviceRepository deviceRepository; @GetMapping public List findAll(Principal principal) { @@ -91,6 +91,8 @@ public class SceneController { newScene.setName(s.getName()); } + newScene.setGuestAccessEnabled(s.isGuestAccessEnabled()); + return sceneService.save(newScene); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java new file mode 100644 index 0000000..1afec1e --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java @@ -0,0 +1,14 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; + + +public class GuestUserResponse { + private boolean cameraEnabled; + + public boolean isCameraEnabled() { + return cameraEnabled; + } + + public void setCameraEnabled(boolean cameraEnabled) { + this.cameraEnabled = cameraEnabled; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java index ea3c6bd..080ea2b 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/SceneSaveRequest.java @@ -1,6 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; import com.sun.istack.NotNull; +import javax.persistence.Column; public class SceneSaveRequest { @@ -10,6 +11,17 @@ public class SceneSaveRequest { /** The user given name of this room (e.g. 'Master bedroom') */ @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() { return id; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java index e762087..8c18e3c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Scene.java @@ -39,6 +39,17 @@ public class Scene { @Column(nullable = false) 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() { return name; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index 23e8217..4f98f0f 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -6,7 +6,6 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; import javax.persistence.*; -import javax.validation.constraints.NotNull; /** A user of the Smarthut application */ @Entity(name = "smarthutuser") @@ -56,10 +55,7 @@ public class User { private Set hosts = new HashSet<>(); /** Determines whether a guest can access security cameras */ - @Column @NotNull private boolean cameraEnabled; - - /** Determines whether a guest can access scenes */ - @Column @NotNull private boolean sceneEnabled; + @Column private boolean cameraEnabled; @Column(nullable = false) @GsonExclude @@ -113,6 +109,26 @@ public class User { isEnabled = enabled; } + public Set getGuests() { + return guests; + } + + public Set getHosts() { + return hosts; + } + + public boolean isCameraEnabled() { + return cameraEnabled; + } + + public void addGuest(User guest) { + this.guests.add(guest); + } + + public void setCameraEnabled(boolean cameraEnabled) { + this.cameraEnabled = cameraEnabled; + } + @Override public String toString() { return "User{" From 7b80b52f9e5bed582e4c35f7ab1b37cc6b595f9c Mon Sep 17 00:00:00 2001 From: tommi27 Date: Sun, 19 Apr 2020 17:10:42 +0200 Subject: [PATCH 07/16] guest controller should be finished, must be reviewed --- .../smarthut/controller/GuestController.java | 40 +++++++++-- .../smarthut/dto/GuestUserResponse.java | 66 +++++++++++++++++++ .../sa4/sanmarinoes/smarthut/models/User.java | 10 +++ 3 files changed, 111 insertions(+), 5 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java index ab47121..a986fe9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java @@ -22,18 +22,48 @@ public class GuestController { } @PostMapping - public void addUserAsGuest(long id, final Principal principal) throws NotFoundException { + public User addUserAsGuest(long id, final Principal principal) throws NotFoundException { User guest = userRepository.findById(id).orElseThrow(NotFoundException::new); User host = userRepository.findByUsername(principal.getName()); host.addGuest(guest); - userRepository.save(guest); - userRepository.save(host); + /** Not sure if this is useful. userRepository.save(guest); */ + return userRepository.save(host); + } + + public User save(GuestUserResponse g, User newGuest) { + newGuest.setCameraEnabled(g.isCameraEnabled()); + newGuest.setEmail(g.getEmail()); + newGuest.setId(g.getId()); + newGuest.setName(g.getName()); + newGuest.setUsername(g.getUsername()); + newGuest.setPassword(g.getPassword()); + newGuest.setEnabled(g.getEnabled()); + + for (User guest : g.getGuests()) { + newGuest.addGuest(guest); + } + + for (User host : g.getHosts()) { + newGuest.addHost(host); + } + + return userRepository.save(newGuest); } @PutMapping - public void updatePermissions(@Valid @RequestBody GuestUserResponse g, Principal principal) {} + public User updatePermissions(@Valid @RequestBody GuestUserResponse g) + throws NotFoundException { + return this.save(g, userRepository.findById(g.getId()).orElseThrow(NotFoundException::new)); + } @DeleteMapping - public void removeUserAsGuest(long id) {} + public void removeUserAsGuest(long id, final Principal principal) throws NotFoundException { + User guest = userRepository.findById(id).orElseThrow(NotFoundException::new); + User host = userRepository.findByUsername(principal.getName()); + + host.removeGuest(guest); + userRepository.deleteById(id); + userRepository.save(host); + } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java index 1afec1e..19984a6 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java @@ -1,8 +1,74 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; +import java.util.Set; public class GuestUserResponse { private boolean cameraEnabled; + private long id; + private String name; + private String username; + private String password; + private String email; + private Set hosts; + private Set guests; + private Boolean isEnabled = false; + + public Boolean getEnabled() { + return isEnabled; + } + + public void setEnabled(Boolean enabled) { + isEnabled = enabled; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Set getHosts() { + return hosts; + } + + public Set getGuests() { + return guests; + } public boolean isCameraEnabled() { return cameraEnabled; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index 4f98f0f..5880ec6 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -125,6 +125,16 @@ public class User { this.guests.add(guest); } + public void addHost(User host) { + this.hosts.add(host); + } + + public void removeGuest(User guest) { + if (this.guests.contains(guest)) { + this.guests.remove(guest); + } + } + public void setCameraEnabled(boolean cameraEnabled) { this.cameraEnabled = cameraEnabled; } From db102f75e44dee80c55afa262381671928443c2f Mon Sep 17 00:00:00 2001 From: tommi27 Date: Mon, 20 Apr 2020 16:41:11 +0200 Subject: [PATCH 08/16] light and room controller routes check for guest authorization --- .../controller/DimmableLightController.java | 35 +++++++++-- .../controller/RegularLightController.java | 33 +++++++++-- .../smarthut/controller/RoomController.java | 58 +++++++++++++++++-- .../sa4/sanmarinoes/smarthut/models/Room.java | 1 - 4 files changed, 108 insertions(+), 19 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index cb7cc00..9a36125 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -8,6 +8,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; +import java.util.Optional; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -18,6 +19,8 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/dimmableLight") public class DimmableLightController { + @Autowired private UserRepository userRepository; + @Autowired private RoomRepository roomRepository; @Autowired private DimmableLightRepository dimmableLightService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; @@ -47,13 +50,33 @@ public class DimmableLightController { @PutMapping public DimmableLight update( - @Valid @RequestBody DimmableSaveRequest sp, final Principal principal) + @Valid @RequestBody DimmableSaveRequest sp, + final Principal principal, + Optional guestId) throws NotFoundException { - return save( - dimmableLightService - .findByIdAndUsername(sp.getId(), principal.getName()) - .orElseThrow(NotFoundException::new), - sp); + + /** + * Extremely verbose check through various repositories to control user/guest authorization. + */ + if (guestId.isPresent() + && userRepository + .findById( + roomRepository + .findById(sp.getRoomId().longValue()) + .get() + .getUserId() + .longValue()) + .get() + .getGuests() + .contains(userRepository.findById(guestId.get().longValue()))) { + return save( + dimmableLightService + .findByIdAndUsername(sp.getId(), principal.getName()) + .orElseThrow(NotFoundException::new), + sp); + } else { + throw new Error("401: Unauthorized user. Not a guest."); + } } @DeleteMapping("/{id}") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java index ac0fd47..7016030 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java @@ -8,6 +8,7 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; +import java.util.Optional; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -26,6 +27,8 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/regularLight") public class RegularLightController { + @Autowired private UserRepository userRepository; + @Autowired private RoomRepository roomRepository; @Autowired private RegularLightRepository regularLightService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; @@ -55,13 +58,31 @@ public class RegularLightController { @PutMapping public RegularLight update( - @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) + @Valid @RequestBody SwitchableSaveRequest rl, + final Principal principal, + Optional guestId) throws NotFoundException { - return save( - regularLightService - .findByIdAndUsername(rl.getId(), principal.getName()) - .orElseThrow(NotFoundException::new), - rl); + + /** Extremely verbose check for guest/user authorization */ + if (guestId.isPresent() + && userRepository + .findById( + roomRepository + .findById(rl.getRoomId()) + .get() + .getUserId() + .longValue()) + .get() + .getGuests() + .contains(userRepository.findById(guestId.get().longValue()))) { + return save( + regularLightService + .findByIdAndUsername(rl.getId(), principal.getName()) + .orElseThrow(NotFoundException::new), + rl); + } else { + throw new Error("401: Unauthorized user. Not a guest."); + } } @DeleteMapping("/{id}") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java index 9474fd4..734ecce 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java @@ -33,13 +33,38 @@ public class RoomController { @Autowired private ThermostatService thermostatService; @GetMapping - public List findAll() { - return toList(roomRepository.findAll()); + public List findAll(Optional guestId) { + + List rooms = toList(roomRepository.findAll()); + + if (guestId.isPresent() + && !rooms.isEmpty() + && userRepository + .findById(rooms.get(0).getUserId()) + .get() + .getGuests() + .contains(userRepository.findById(guestId.get().longValue()))) { + return rooms; + } else { + throw new Error("401: Unauthorized user. Not a guest."); + } } @GetMapping("/{id}") - public @ResponseBody Room findById(@PathVariable("id") long id) throws NotFoundException { - return roomRepository.findById(id).orElseThrow(NotFoundException::new); + public @ResponseBody Room findById(@PathVariable("id") long id, Optional guestId) + throws NotFoundException { + Room room = roomRepository.findById(id).orElseThrow(NotFoundException::new); + + if (guestId.isPresent() + && userRepository + .findById(room.getUserId().longValue()) + .get() + .getGuests() + .contains(userRepository.findById(guestId.get()))) { + return room; + } else { + throw new Error("401: Unauthorized user. Not a guest."); + } } @PostMapping @@ -101,13 +126,34 @@ public class RoomController { * id). */ @GetMapping(path = "/{roomId}/devices") - public List getDevices(@PathVariable("roomId") long roomid) { + public List getDevices(@PathVariable("roomId") long roomid, Optional guestId) { Iterable devices = deviceRepository.findByRoomId(roomid); for (Device d : devices) { if (d instanceof Thermostat) { thermostatService.populateMeasuredTemperature((Thermostat) d); } } - return toList(devices); + List dl = toList(devices); + + /** + * Extremely verbose method calls to find the current user and check if the optional user is + * one of their guests + */ + if (guestId.isPresent() + && !dl.isEmpty() + && userRepository + .findById( + roomRepository + .findById(dl.get(0).getRoomId().longValue()) + .get() + .getUserId() + .longValue()) + .get() + .getGuests() + .contains(userRepository.findById(guestId.get().longValue()))) { + return dl; + } else { + throw new Error("401: Unauthorized user. Not a guest."); + } } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java index 4f0f592..34f3824 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Room.java @@ -145,7 +145,6 @@ public class Room { */ @NotNull @Column(name = "user_id", nullable = false) - @GsonExclude private Long userId; /** The user given name of this room (e.g. 'Master bedroom') */ From cfe3848d7e4ef6814e57a2d16a642d119a901f59 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Tue, 21 Apr 2020 14:06:56 +0200 Subject: [PATCH 09/16] Done method to get dimmable light if owner or guest --- .../controller/DimmableLightController.java | 54 +++++++++---------- .../smarthut/models/DeviceRepository.java | 10 ++++ 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index 9a36125..bde6bef 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -8,7 +8,6 @@ import ch.usi.inf.sa4.sanmarinoes.smarthut.error.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; import java.security.Principal; import java.util.List; -import java.util.Optional; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -20,7 +19,6 @@ import org.springframework.web.bind.annotation.*; public class DimmableLightController { @Autowired private UserRepository userRepository; - @Autowired private RoomRepository roomRepository; @Autowired private DimmableLightRepository dimmableLightService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; @@ -48,35 +46,35 @@ public class DimmableLightController { return save(new DimmableLight(), dl); } + private DimmableLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) + throws NotFoundException { + if (hostId == null) { + return dimmableLightService + .findByIdAndUsername(id, principal.getName()) + .orElseThrow(NotFoundException::new); + } else { + /* + * Slightly less extremely verbose check through various repositories to control user/guest authorization. + */ + DimmableLight dl = + dimmableLightService + .findByIdAndUserId(id, hostId) + .orElseThrow(NotFoundException::new); + User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new); + User guest = userRepository.findByUsername(principal.getName()); + if (!host.getGuests().contains(guest)) { + throw new NotFoundException(); + } else { + return dl; + } + } + } + @PutMapping public DimmableLight update( - @Valid @RequestBody DimmableSaveRequest sp, - final Principal principal, - Optional guestId) + @Valid @RequestBody DimmableSaveRequest sp, final Principal principal, Long hostId) throws NotFoundException { - - /** - * Extremely verbose check through various repositories to control user/guest authorization. - */ - if (guestId.isPresent() - && userRepository - .findById( - roomRepository - .findById(sp.getRoomId().longValue()) - .get() - .getUserId() - .longValue()) - .get() - .getGuests() - .contains(userRepository.findById(guestId.get().longValue()))) { - return save( - dimmableLightService - .findByIdAndUsername(sp.getId(), principal.getName()) - .orElseThrow(NotFoundException::new), - sp); - } else { - throw new Error("401: Unauthorized user. Not a guest."); - } + return save(fetchIfOwnerOrGuest(principal, sp.getId(), hostId), sp); } @DeleteMapping("/{id}") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java index 2496029..cf5c004 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/DeviceRepository.java @@ -25,6 +25,16 @@ public interface DeviceRepository extends CrudRepository 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 findByIdAndUserId(Long id, Long userId); + /** * Finds all devices belonging to a user * From 6317ac99e43abfa0ef59416a6266a9aec08b592d Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Tue, 21 Apr 2020 14:25:42 +0200 Subject: [PATCH 10/16] Code review --- .../smarthut/controller/GuestController.java | 36 +++------ .../smarthut/controller/SceneController.java | 2 + .../smarthut/dto/GuestPermissionsRequest.java | 14 ++++ .../smarthut/dto/GuestUserResponse.java | 80 ------------------- 4 files changed, 28 insertions(+), 104 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestPermissionsRequest.java delete mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java index a986fe9..e0fc3e9 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java @@ -2,7 +2,7 @@ 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.GuestUserResponse; +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; @@ -27,34 +27,21 @@ public class GuestController { User host = userRepository.findByUsername(principal.getName()); host.addGuest(guest); - /** Not sure if this is useful. userRepository.save(guest); */ + guest.addHost(host); + userRepository.save(guest); + /* Not sure if this is useful. userRepository.save(guest); */ return userRepository.save(host); } - public User save(GuestUserResponse g, User newGuest) { - newGuest.setCameraEnabled(g.isCameraEnabled()); - newGuest.setEmail(g.getEmail()); - newGuest.setId(g.getId()); - newGuest.setName(g.getName()); - newGuest.setUsername(g.getUsername()); - newGuest.setPassword(g.getPassword()); - newGuest.setEnabled(g.getEnabled()); - - for (User guest : g.getGuests()) { - newGuest.addGuest(guest); - } - - for (User host : g.getHosts()) { - newGuest.addHost(host); - } - - return userRepository.save(newGuest); + public User save(GuestPermissionsRequest g, User currentUser) { + currentUser.setCameraEnabled(g.isCameraEnabled()); + return userRepository.save(currentUser); } @PutMapping - public User updatePermissions(@Valid @RequestBody GuestUserResponse g) - throws NotFoundException { - return this.save(g, userRepository.findById(g.getId()).orElseThrow(NotFoundException::new)); + public User updatePermissions( + @Valid @RequestBody GuestPermissionsRequest g, final Principal principal) { + return this.save(g, userRepository.findByUsername(principal.getName())); } @DeleteMapping @@ -63,7 +50,8 @@ public class GuestController { User host = userRepository.findByUsername(principal.getName()); host.removeGuest(guest); - userRepository.deleteById(id); + guest.getHosts().remove(host); userRepository.save(host); + userRepository.save(guest); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java index a4da945..f5dd1a2 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SceneController.java @@ -56,6 +56,8 @@ public class SceneController { newScene.setUserId(userId); newScene.setName(s.getName()); + newScene.setGuestAccessEnabled(s.isGuestAccessEnabled()); + return sceneService.save(newScene); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestPermissionsRequest.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestPermissionsRequest.java new file mode 100644 index 0000000..781a10e --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestPermissionsRequest.java @@ -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; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java deleted file mode 100644 index 19984a6..0000000 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/dto/GuestUserResponse.java +++ /dev/null @@ -1,80 +0,0 @@ -package ch.usi.inf.sa4.sanmarinoes.smarthut.dto; - -import ch.usi.inf.sa4.sanmarinoes.smarthut.models.User; -import java.util.Set; - -public class GuestUserResponse { - private boolean cameraEnabled; - private long id; - private String name; - private String username; - private String password; - private String email; - private Set hosts; - private Set guests; - private Boolean isEnabled = false; - - public Boolean getEnabled() { - return isEnabled; - } - - public void setEnabled(Boolean enabled) { - isEnabled = enabled; - } - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public Set getHosts() { - return hosts; - } - - public Set getGuests() { - return guests; - } - - public boolean isCameraEnabled() { - return cameraEnabled; - } - - public void setCameraEnabled(boolean cameraEnabled) { - this.cameraEnabled = cameraEnabled; - } -} From eef0887da1924f5a8f4aa67cfc6553d17ace361f Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Tue, 21 Apr 2020 14:57:11 +0200 Subject: [PATCH 11/16] Code review --- .../smarthut/config/GsonConfig.java | 28 +++++++++++++- .../smarthut/config/SocketGsonExclude.java | 10 +++++ .../controller/DimmableLightController.java | 37 +++++++++++++------ .../sanmarinoes/smarthut/models/Device.java | 9 +++++ .../smarthut/service/DeviceService.java | 35 ++++++++++++++++++ .../smarthut/socket/SensorSocketEndpoint.java | 25 ++++--------- 6 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SocketGsonExclude.java create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java index 67b25dc..08c3e60 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/GsonConfig.java @@ -23,15 +23,26 @@ public class GsonConfig { return converter; } - public static Gson gson() { + private static GsonBuilder configureBuilder() { final GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Json.class, new SpringfoxJsonToGsonAdapter()); - builder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy()); RuntimeTypeAdapterFactory runtimeTypeAdapterFactory = RuntimeTypeAdapterFactory.of(State.class, "kind") .registerSubtype(SwitchableState.class, "switchableState") .registerSubtype(DimmableState.class, "dimmableState"); 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(); } } @@ -56,3 +67,16 @@ class AnnotationExclusionStrategy implements ExclusionStrategy { 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; + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SocketGsonExclude.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SocketGsonExclude.java new file mode 100644 index 0000000..e9806bc --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SocketGsonExclude.java @@ -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 {} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index bde6bef..8c3265a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -6,6 +6,7 @@ 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.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -19,37 +20,43 @@ import org.springframework.web.bind.annotation.*; public class DimmableLightController { @Autowired private UserRepository userRepository; - @Autowired private DimmableLightRepository dimmableLightService; + @Autowired private DimmableLightRepository dimmableLightRepository; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; + @Autowired private DeviceService deviceService; @GetMapping public List findAll() { - return toList(dimmableLightService.findAll()); + return toList(dimmableLightRepository.findAll()); } @GetMapping("/{id}") public DimmableLight findById(@PathVariable("id") long id) throws NotFoundException { - return dimmableLightService.findById(id).orElseThrow(NotFoundException::new); + return dimmableLightRepository.findById(id).orElseThrow(NotFoundException::new); } - private DimmableLight save(DimmableLight initial, DimmableSaveRequest dl) { + private DimmableLight save(DimmableLight initial, DimmableSaveRequest dl, String username) { initial.setIntensity(dl.getIntensity()); initial.setName(dl.getName()); initial.setRoomId(dl.getRoomId()); - return dimmableLightService.save(initial); + return deviceService.saveAsOwner(initial, username); } + /* + Assume that only the host can create a device + Here save always as host, but remember to propagate change to guests (DeviceService.saveAsOwner()) + */ @PostMapping - public DimmableLight create(@Valid @RequestBody DimmableSaveRequest dl) { - return save(new DimmableLight(), dl); + public DimmableLight create( + @Valid @RequestBody DimmableSaveRequest dl, final Principal principal) { + return save(new DimmableLight(), dl, principal.getName()); } private DimmableLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) throws NotFoundException { if (hostId == null) { - return dimmableLightService + return dimmableLightRepository .findByIdAndUsername(id, principal.getName()) .orElseThrow(NotFoundException::new); } else { @@ -57,11 +64,12 @@ public class DimmableLightController { * Slightly less extremely verbose check through various repositories to control user/guest authorization. */ DimmableLight dl = - dimmableLightService + 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 { @@ -70,16 +78,21 @@ public class DimmableLightController { } } + /* + Here you must behave differently if hostId is given or not: + - if not given, assume the owner of the device wants to update the device. In this case, save with DeviceService.saveAsOwner(); + - if given, assume a guest wants to update the intensity of this light. In this case, save with DeviceService.saveAsGuest(); + */ @PutMapping public DimmableLight update( @Valid @RequestBody DimmableSaveRequest sp, final Principal principal, Long hostId) throws NotFoundException { - return save(fetchIfOwnerOrGuest(principal, sp.getId(), hostId), sp); + return save(fetchIfOwnerOrGuest(principal, sp.getId(), hostId), sp, principal.getName()); } @DeleteMapping("/{id}") public void delete(@PathVariable("id") long id) { - dimmableLightService.deleteById(id); + dimmableLightRepository.deleteById(id); } // the full url should be: "/dimmableLight/{id}/state?sceneId={sceneId} @@ -92,7 +105,7 @@ public class DimmableLightController { throws NotFoundException, DuplicateStateException { DimmableLight d = - dimmableLightService + dimmableLightRepository .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); State s = d.cloneState(); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 9b0cc2d..4629779 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -1,6 +1,7 @@ package ch.usi.inf.sa4.sanmarinoes.smarthut.models; import ch.usi.inf.sa4.sanmarinoes.smarthut.config.GsonExclude; +import ch.usi.inf.sa4.sanmarinoes.smarthut.config.SocketGsonExclude; import com.google.gson.annotations.SerializedName; import io.swagger.annotations.ApiModelProperty; import java.util.HashSet; @@ -32,6 +33,7 @@ public abstract class Device { @ManyToOne @JoinColumn(name = "room_id", updatable = false, insertable = false) @GsonExclude + @SocketGsonExclude private Room room; /** @@ -61,8 +63,15 @@ public abstract class Device { @OneToMany(mappedBy = "device", orphanRemoval = true) @GsonExclude + @SocketGsonExclude private Set> states = new HashSet<>(); + @Transient @GsonExclude private boolean fromHost = false; + + public void setFromHost(boolean fromHost) { + this.fromHost = fromHost; + } + public long getId() { return id; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java new file mode 100644 index 0000000..a4502ec --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -0,0 +1,35 @@ +package ch.usi.inf.sa4.sanmarinoes.smarthut.service; + +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.User; +import ch.usi.inf.sa4.sanmarinoes.smarthut.models.UserRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +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 DeviceRepository deviceRepository; + @Autowired UserRepository userRepository; + @Autowired SensorSocketEndpoint endpoint; + + /* + TODO: remember to put a @Transient @GsonIgnore (but not @SocketGsonIgnore) property on device to signal a device update + TODO: coming from DeviceService.saveAsGuest() + */ + + // TODO: create saveAsGuest(device, guestUsername, hostId) + + public T saveAsOwner(T device, String username) { + final User user = userRepository.findByUsername(username); + final Set guests = user.getGuests(); + for (final User guest : guests) { + // set set from host true + // broadcast to endpoint the object device, with recieving user set to guest + } + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java index b222cf5..b68cb25 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/socket/SensorSocketEndpoint.java @@ -9,25 +9,17 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.google.gson.Gson; - import java.io.IOException; import java.util.*; 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.security.core.parameters.P; 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 public class SensorSocketEndpoint extends Endpoint { - private Gson gson = GsonConfig.gson(); + private Gson gson = GsonConfig.socketGson(); private UserRepository userRepository; @@ -46,6 +38,7 @@ public class SensorSocketEndpoint extends Endpoint { /** * Queues a single device update for a certain user to be sent + * * @param device the device update to be sent * @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() { synchronized (messages) { for (Map.Entry> batchForUser : messages.entrySet()) { @@ -69,11 +60,11 @@ public class SensorSocketEndpoint extends Endpoint { } /** - * Given a collection of messages and a user, broadcasts that message in json to all - * associated clients + * Given a collection of messages and a user, broadcasts that message in json to all associated + * clients * * @param messages the message batch to send - * @param u the user to which to send the message + * @param u the user to which to send the message */ private void broadcast(User u, Collection messages) { if (messages.isEmpty()) return; @@ -95,7 +86,7 @@ public class SensorSocketEndpoint extends Endpoint { * Handles the opening of a socket session with a client * * @param session the newly born session - * @param config endpoint configuration + * @param config endpoint configuration */ @Override public void onOpen(Session session, EndpointConfig config) { From c4f295d7d9b1931fd12b2aa4848e266a92bc8167 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Tue, 21 Apr 2020 17:09:11 +0200 Subject: [PATCH 12/16] refactored controllers code --- .../controller/RegularLightController.java | 65 ++++++++------- .../smarthut/controller/RoomController.java | 80 +++++++------------ 2 files changed, 63 insertions(+), 82 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java index 7016030..06fccfb 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java @@ -6,9 +6,9 @@ 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.NotFoundException; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.*; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService; import java.security.Principal; import java.util.List; -import java.util.Optional; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -28,10 +28,30 @@ import org.springframework.web.bind.annotation.RestController; public class RegularLightController { @Autowired private UserRepository userRepository; - @Autowired private RoomRepository roomRepository; @Autowired private RegularLightRepository regularLightService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; + @Autowired private DeviceService deviceService; + + private RegularLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) + throws NotFoundException { + if (hostId == null) { + return regularLightService.findById(id).orElseThrow(NotFoundException::new); + } else { + RegularLight rl = + regularLightService + .findByIdAndUserId(id, hostId) + .orElseThrow(NotFoundException::new); + User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new); + User guest = userRepository.findByUsername(principal.getName()); + rl.setFromHost(true); + if (!host.getGuests().contains(guest)) { + throw new NotFoundException(); + } else { + return rl; + } + } + } @GetMapping public List findAll() { @@ -43,46 +63,25 @@ public class RegularLightController { return regularLightService.findById(id).orElseThrow(NotFoundException::new); } - private RegularLight save(RegularLight newRL, SwitchableSaveRequest rl) { - newRL.setName(rl.getName()); - newRL.setRoomId(rl.getRoomId()); - newRL.setOn(rl.isOn()); + private RegularLight save(RegularLight initial, SwitchableSaveRequest rl, String username) { + initial.setName(rl.getName()); + initial.setRoomId(rl.getRoomId()); + initial.setOn(rl.isOn()); - return regularLightService.save(newRL); + return deviceService.saveAsOwner(initial, username); } @PostMapping - public RegularLight create(@Valid @RequestBody SwitchableSaveRequest rl) { - return save(new RegularLight(), rl); + public RegularLight create( + @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) { + return save(new RegularLight(), rl, principal.getName()); } @PutMapping public RegularLight update( - @Valid @RequestBody SwitchableSaveRequest rl, - final Principal principal, - Optional guestId) + @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal, Long hostId) throws NotFoundException { - - /** Extremely verbose check for guest/user authorization */ - if (guestId.isPresent() - && userRepository - .findById( - roomRepository - .findById(rl.getRoomId()) - .get() - .getUserId() - .longValue()) - .get() - .getGuests() - .contains(userRepository.findById(guestId.get().longValue()))) { - return save( - regularLightService - .findByIdAndUsername(rl.getId(), principal.getName()) - .orElseThrow(NotFoundException::new), - rl); - } else { - throw new Error("401: Unauthorized user. Not a guest."); - } + return save(fetchIfOwnerOrGuest(principal, rl.getId(), hostId), rl, principal.getName()); } @DeleteMapping("/{id}") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java index 734ecce..03a115f 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java @@ -32,39 +32,39 @@ public class RoomController { @Autowired private ThermostatService thermostatService; - @GetMapping - public List findAll(Optional guestId) { - - List rooms = toList(roomRepository.findAll()); - - if (guestId.isPresent() - && !rooms.isEmpty() - && userRepository - .findById(rooms.get(0).getUserId()) - .get() - .getGuests() - .contains(userRepository.findById(guestId.get().longValue()))) { - return rooms; + private List fetchOwnerOrGuest( + final List list, Long hostId, final Principal principal) throws NotFoundException { + if (hostId == null) { + return list; } else { - throw new Error("401: Unauthorized user. Not a guest."); + User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); + User guest = userRepository.findByUsername(principal.getName()); + if (!host.getGuests().contains(guest)) { + throw new NotFoundException(); + } else { + return list; + } } } + @GetMapping + public List findAll(Long hostId, final Principal principal) throws NotFoundException { + + List rooms = toList(roomRepository.findAll()); + return fetchOwnerOrGuest(rooms, hostId, principal); + } + @GetMapping("/{id}") - public @ResponseBody Room findById(@PathVariable("id") long id, Optional guestId) + public @ResponseBody Room findById( + @PathVariable("id") long id, final Principal principal, Long hostId) throws NotFoundException { Room room = roomRepository.findById(id).orElseThrow(NotFoundException::new); - - if (guestId.isPresent() - && userRepository - .findById(room.getUserId().longValue()) - .get() - .getGuests() - .contains(userRepository.findById(guestId.get()))) { - return room; - } else { - throw new Error("401: Unauthorized user. Not a guest."); - } + /* 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 @@ -126,34 +126,16 @@ public class RoomController { * id). */ @GetMapping(path = "/{roomId}/devices") - public List getDevices(@PathVariable("roomId") long roomid, Optional guestId) { + public List getDevices( + @PathVariable("roomId") long roomid, final Principal principal, Long hostId) + throws NotFoundException { Iterable devices = deviceRepository.findByRoomId(roomid); for (Device d : devices) { if (d instanceof Thermostat) { thermostatService.populateMeasuredTemperature((Thermostat) d); } } - List dl = toList(devices); - - /** - * Extremely verbose method calls to find the current user and check if the optional user is - * one of their guests - */ - if (guestId.isPresent() - && !dl.isEmpty() - && userRepository - .findById( - roomRepository - .findById(dl.get(0).getRoomId().longValue()) - .get() - .getUserId() - .longValue()) - .get() - .getGuests() - .contains(userRepository.findById(guestId.get().longValue()))) { - return dl; - } else { - throw new Error("401: Unauthorized user. Not a guest."); - } + List deviceList = toList(devices); + return fetchOwnerOrGuest(deviceList, hostId, principal); } } From a428d57fe11556ef1e975bf7d60110137f9cb421 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Wed, 22 Apr 2020 15:30:23 +0200 Subject: [PATCH 13/16] WIP: controllers check for owner or guest, device service needs review --- .../controller/DimmableLightController.java | 26 ++++++++---- .../controller/RegularLightController.java | 21 +++++++--- .../smarthut/service/DeviceService.java | 42 +++++++++++++++++-- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index 8c3265a..eaace7a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -35,12 +35,18 @@ public class DimmableLightController { return dimmableLightRepository.findById(id).orElseThrow(NotFoundException::new); } - private DimmableLight save(DimmableLight initial, DimmableSaveRequest dl, String username) { + private DimmableLight save( + DimmableLight initial, DimmableSaveRequest dl, String username, Long hostId) + throws NotFoundException { initial.setIntensity(dl.getIntensity()); initial.setName(dl.getName()); initial.setRoomId(dl.getRoomId()); - return deviceService.saveAsOwner(initial, username); + if (hostId == null) { + return deviceService.saveAsOwner(initial, username); + } else { + return deviceService.saveAsGuest(initial, username, hostId); + } } /* @@ -49,8 +55,9 @@ public class DimmableLightController { */ @PostMapping public DimmableLight create( - @Valid @RequestBody DimmableSaveRequest dl, final Principal principal) { - return save(new DimmableLight(), dl, principal.getName()); + @Valid @RequestBody DimmableSaveRequest dl, final Principal principal) + throws NotFoundException { + return save(new DimmableLight(), dl, principal.getName(), null); } private DimmableLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) @@ -79,15 +86,18 @@ public class DimmableLightController { } /* - Here you must behave differently if hostId is given or not: - - if not given, assume the owner of the device wants to update the device. In this case, save with DeviceService.saveAsOwner(); - - if given, assume a guest wants to update the intensity of this light. In this case, save with DeviceService.saveAsGuest(); + Logic for saving either as owner or guest is handled in method save of this controller */ @PutMapping public DimmableLight update( @Valid @RequestBody DimmableSaveRequest sp, final Principal principal, Long hostId) throws NotFoundException { - return save(fetchIfOwnerOrGuest(principal, sp.getId(), hostId), sp, principal.getName()); + + return save( + fetchIfOwnerOrGuest(principal, sp.getId(), hostId), + sp, + principal.getName(), + hostId); } @DeleteMapping("/{id}") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java index 06fccfb..b73bff3 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java @@ -63,25 +63,36 @@ public class RegularLightController { return regularLightService.findById(id).orElseThrow(NotFoundException::new); } - private RegularLight save(RegularLight initial, SwitchableSaveRequest rl, String username) { + private RegularLight save( + RegularLight initial, SwitchableSaveRequest rl, String username, Long hostId) + throws NotFoundException { initial.setName(rl.getName()); initial.setRoomId(rl.getRoomId()); initial.setOn(rl.isOn()); - return deviceService.saveAsOwner(initial, username); + if (hostId == null) { + return deviceService.saveAsOwner(initial, username); + } else { + return deviceService.saveAsGuest(initial, username, hostId); + } } @PostMapping public RegularLight create( - @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) { - return save(new RegularLight(), rl, principal.getName()); + @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal) + throws NotFoundException { + return save(new RegularLight(), rl, principal.getName(), null); } @PutMapping public RegularLight update( @Valid @RequestBody SwitchableSaveRequest rl, final Principal principal, Long hostId) throws NotFoundException { - return save(fetchIfOwnerOrGuest(principal, rl.getId(), hostId), rl, principal.getName()); + return save( + fetchIfOwnerOrGuest(principal, rl.getId(), hostId), + rl, + principal.getName(), + hostId); } @DeleteMapping("/{id}") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index a4502ec..da2614b 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -1,10 +1,13 @@ 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.models.Device; 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.UserRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; +import java.beans.Transient; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -21,15 +24,48 @@ public class DeviceService { 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 saveAsGuest( + @Transient @GsonExclude T device, String guestUsername, Long hostId) + throws NotFoundException { + final User currentUser = userRepository.findByUsername(guestUsername); + final User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); + final Set guests = host.getGuests(); - // TODO: create saveAsGuest(device, guestUsername, hostId) + // filter out currentUser from guests as we do not want to broadcast an update to the + // updating user itself + if (guests.contains(currentUser)) { + guests.remove(currentUser); + } + + // broadcasting from not a host + device.setFromHost(false); + // broadcast device update for host + endpoint.queueDeviceUpdate(device, host); + userRepository.save(host); + endpoint.flushDeviceUpdates(); + for (final User guest : guests) { + // enqueue all device updates for all other guests + endpoint.queueDeviceUpdate(device, guest); + userRepository.save(guest); + } + // broadcast device updates for all other guests + endpoint.flushDeviceUpdates(); + return deviceRepository.save(device); + } public T saveAsOwner(T device, String username) { final User user = userRepository.findByUsername(username); final Set guests = user.getGuests(); + // make sure we're broadcasting from host + device.setFromHost(true); for (final User guest : guests) { - // set set from host true - // broadcast to endpoint the object device, with recieving user set to guest + // broadcast to endpoint the object device, with receiving user set to guest + endpoint.queueDeviceUpdate(device, guest); + userRepository.save(guest); } + // 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 + endpoint.flushDeviceUpdates(); + return deviceRepository.save(device); } } From c6d5a1acd79c4b35b954099a11156cbfdfdbe624 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Wed, 22 Apr 2020 17:17:07 +0200 Subject: [PATCH 14/16] controllers fixed and updated for guest or host checks --- .../controller/DimmableLightController.java | 50 +++++++----------- .../controller/GuestEnabledController.java | 37 +++++++++++++ .../controller/RegularLightController.java | 51 ++++++++---------- .../smarthut/controller/RoomController.java | 9 +--- .../sanmarinoes/smarthut/models/Device.java | 10 ++++ .../smarthut/service/DeviceService.java | 52 +++++++++---------- .../sa4/sanmarinoes/smarthut/utils/Utils.java | 30 +++++------ 7 files changed, 128 insertions(+), 111 deletions(-) create mode 100644 src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index eaace7a..3a714e8 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -17,13 +17,26 @@ import org.springframework.web.bind.annotation.*; @RestController @EnableAutoConfiguration @RequestMapping("/dimmableLight") -public class DimmableLightController { +public class DimmableLightController extends GuestEnabledController { - @Autowired private UserRepository userRepository; - @Autowired private DimmableLightRepository dimmableLightRepository; - @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository> stateRepository; - @Autowired private DeviceService deviceService; + private DimmableLightRepository dimmableLightRepository; + private SceneRepository sceneRepository; + private StateRepository> stateRepository; + private DeviceService deviceService; + + @Autowired + public DimmableLightController( + UserRepository userRepository, + DimmableLightRepository dimmableLightRepository, + SceneRepository sceneRepository, + StateRepository> stateRepository, + DeviceService deviceService) { + super(userRepository, dimmableLightRepository); + this.dimmableLightRepository = dimmableLightRepository; + this.sceneRepository = sceneRepository; + this.stateRepository = stateRepository; + this.deviceService = deviceService; + } @GetMapping public List findAll() { @@ -60,31 +73,6 @@ public class DimmableLightController { 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 */ diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java new file mode 100644 index 0000000..1aa2e7c --- /dev/null +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestEnabledController.java @@ -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 { + + private UserRepository userRepository; + private DeviceRepository deviceRepository; + + public GuestEnabledController( + final UserRepository userRepository, final DeviceRepository 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); + } + } +} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java index b73bff3..308b8ee 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java @@ -25,42 +25,35 @@ import org.springframework.web.bind.annotation.RestController; @RestController @EnableAutoConfiguration @RequestMapping("/regularLight") -public class RegularLightController { +public class RegularLightController extends GuestEnabledController { - @Autowired private UserRepository userRepository; - @Autowired private RegularLightRepository regularLightService; - @Autowired private SceneRepository sceneRepository; - @Autowired private StateRepository> stateRepository; - @Autowired private DeviceService deviceService; + private RegularLightRepository regularLightRepository; + private SceneRepository sceneRepository; + private StateRepository> stateRepository; + private DeviceService deviceService; - private RegularLight fetchIfOwnerOrGuest(final Principal principal, Long id, Long hostId) - throws NotFoundException { - if (hostId == null) { - return regularLightService.findById(id).orElseThrow(NotFoundException::new); - } else { - RegularLight rl = - regularLightService - .findByIdAndUserId(id, hostId) - .orElseThrow(NotFoundException::new); - User host = userRepository.findById(hostId).orElseThrow(IllegalStateException::new); - User guest = userRepository.findByUsername(principal.getName()); - rl.setFromHost(true); - if (!host.getGuests().contains(guest)) { - throw new NotFoundException(); - } else { - return rl; - } - } + @Autowired + public RegularLightController( + UserRepository userRepository, + RegularLightRepository regularLightRepository, + SceneRepository sceneRepository, + StateRepository> stateRepository, + DeviceService deviceService) { + super(userRepository, regularLightRepository); + this.regularLightRepository = regularLightRepository; + this.sceneRepository = sceneRepository; + this.stateRepository = stateRepository; + this.deviceService = deviceService; } @GetMapping public List findAll() { - return toList(regularLightService.findAll()); + return toList(regularLightRepository.findAll()); } @GetMapping("/{id}") 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( @@ -97,10 +90,10 @@ public class RegularLightController { @DeleteMapping("/{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 @PostMapping("/{id}/state") public State sceneBinding( @@ -109,7 +102,7 @@ public class RegularLightController { final Principal principal) throws NotFoundException, DuplicateStateException { RegularLight d = - regularLightService + regularLightRepository .findByIdAndUsername(deviceId, principal.getName()) .orElseThrow(NotFoundException::new); State s = d.cloneState(); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java index 03a115f..7de58db 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java @@ -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.models.*; import ch.usi.inf.sa4.sanmarinoes.smarthut.service.ThermostatService; +import ch.usi.inf.sa4.sanmarinoes.smarthut.utils.Utils; import java.security.Principal; import java.util.*; import javax.validation.Valid; @@ -37,13 +38,7 @@ public class RoomController { if (hostId == null) { return list; } else { - User host = userRepository.findById(hostId).orElseThrow(NotFoundException::new); - User guest = userRepository.findByUsername(principal.getName()); - if (!host.getGuests().contains(guest)) { - throw new NotFoundException(); - } else { - return list; - } + return Utils.returnIfGuest(userRepository, list, hostId, principal); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 4629779..3b681c5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -68,6 +68,16 @@ public abstract class Device { @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) { this.fromHost = fromHost; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index da2614b..4bf6cca 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -1,13 +1,11 @@ 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.models.Device; 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.UserRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; -import java.beans.Transient; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -16,56 +14,54 @@ import org.springframework.stereotype.Component; public class DeviceService { // FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF) - @Autowired DeviceRepository deviceRepository; - @Autowired UserRepository userRepository; - @Autowired SensorSocketEndpoint endpoint; + @Autowired private DeviceRepository deviceRepository; + @Autowired private UserRepository userRepository; + @Autowired private SensorSocketEndpoint endpoint; - /* - 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 saveAsGuest( - @Transient @GsonExclude T device, String guestUsername, Long hostId) + public 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 guests = host.getGuests(); + final Set guests = Set.copyOf(host.getGuests()); - // filter out currentUser from guests as we do not want to broadcast an update to the - // updating user itself - if (guests.contains(currentUser)) { - guests.remove(currentUser); - } - - // broadcasting from not a host + // We're telling the host that a guest has modified a device. Therefore, fromGuest becomes + // true. device.setFromHost(false); - // broadcast device update for host + device.setFromGuest(true); + // broadcast device update to 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) { + if (guest.equals(currentUser)) { + continue; + } // enqueue all device updates for all other guests endpoint.queueDeviceUpdate(device, guest); - userRepository.save(guest); } // broadcast device updates for all other guests - endpoint.flushDeviceUpdates(); - return deviceRepository.save(device); + return device; } public T saveAsOwner(T device, String username) { + device = deviceRepository.save(device); + final User user = userRepository.findByUsername(username); final Set 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); - userRepository.save(guest); } // 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 - endpoint.flushDeviceUpdates(); - return deviceRepository.save(device); + return device; } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java index 319a8e3..050afa5 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/utils/Utils.java @@ -1,7 +1,10 @@ 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.function.Predicate; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -9,24 +12,19 @@ import java.util.stream.StreamSupport; public final class Utils { private Utils() {} - @FunctionalInterface - public interface ConsumerWithException { - void apply(T input) throws Throwable; + public static U returnIfGuest( + UserRepository userRepository, U toReturn, Long hostId, Principal principal) + 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 List toList(Iterable iterable) { return StreamSupport.stream(iterable.spliterator(), false).collect(Collectors.toList()); } - - public static Predicate didThrow(ConsumerWithException consumer) { - return (t) -> { - try { - consumer.apply(t); - return true; - } catch (Throwable e) { - System.err.println(e.getMessage()); - return false; - } - }; - } } From 389af7c04d675a6eac0a9355dc31de1f6f978145 Mon Sep 17 00:00:00 2001 From: tommi27 Date: Wed, 22 Apr 2020 18:13:06 +0200 Subject: [PATCH 15/16] all device controllers have been updated with device service --- .../controller/ButtonDimmerController.java | 35 ++++++++----------- .../controller/CurtainsController.java | 34 ++++++++---------- .../smarthut/controller/DeviceController.java | 4 ++- .../controller/DimmableLightController.java | 17 ++------- .../controller/KnobDimmerController.java | 32 ++++++----------- .../controller/MotionSensorController.java | 28 ++++++--------- .../controller/RegularLightController.java | 5 +-- .../controller/SecurityCameraController.java | 33 +++++++---------- .../smarthut/controller/SensorController.java | 33 ++++++----------- .../controller/SmartPlugController.java | 31 +++++++--------- .../smarthut/controller/SwitchController.java | 30 +++++++--------- .../controller/ThermostatController.java | 35 +++++++------------ .../sanmarinoes/smarthut/models/Device.java | 14 ++++++++ .../smarthut/service/DeviceService.java | 24 +++++++++++-- 14 files changed, 152 insertions(+), 203 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java index 1870abc..01f453c 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/ButtonDimmerController.java @@ -1,13 +1,12 @@ 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.GenericDeviceSaveReguest; 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.DeviceService; import java.security.Principal; -import java.util.List; import java.util.Set; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; @@ -19,37 +18,30 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/buttonDimmer") public class ButtonDimmerController extends InputDeviceConnectionController { + + private DeviceService deviceService; private ButtonDimmerRepository buttonDimmerRepository; private DimmableRepository dimmableRepository; @Autowired protected ButtonDimmerController( - ButtonDimmerRepository inputRepository, DimmableRepository outputRepository) { - super( - inputRepository, - outputRepository, - DimmableLight.BUTTON_DIMMER_DIMMABLE_CONNECTOR); + ButtonDimmerRepository inputRepository, + DimmableRepository outputRepository, + DeviceService deviceService) { + super(inputRepository, outputRepository, DimmableLight.BUTTON_DIMMER_DIMMABLE_CONNECTOR); + this.deviceService = deviceService; this.buttonDimmerRepository = inputRepository; this.dimmableRepository = outputRepository; } - @GetMapping - public List findAll() { - return toList(buttonDimmerRepository.findAll()); - } - - @GetMapping("/{id}") - public ButtonDimmer findById(@PathVariable("id") long id) throws NotFoundException { - return buttonDimmerRepository.findById(id).orElseThrow(NotFoundException::new); - } - @PostMapping - public ButtonDimmer create(@Valid @RequestBody final GenericDeviceSaveReguest bd) { + public ButtonDimmer create( + @Valid @RequestBody final GenericDeviceSaveReguest bd, final Principal principal) { ButtonDimmer newBD = new ButtonDimmer(); newBD.setName(bd.getName()); newBD.setRoomId(bd.getRoomId()); - return buttonDimmerRepository.save(newBD); + return deviceService.saveAsOwner(newBD, principal.getName()); } @PutMapping("/dim") @@ -76,7 +68,8 @@ public class ButtonDimmerController } @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - buttonDimmerRepository.deleteById(id); + public void delete(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java index 5eb00be..3e1872a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/CurtainsController.java @@ -1,13 +1,12 @@ 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.error.DuplicateStateException; 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.DeviceService; 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; @@ -17,44 +16,39 @@ import org.springframework.web.bind.annotation.*; @EnableAutoConfiguration @RequestMapping("/curtains") public class CurtainsController { + @Autowired private DeviceService deviceService; @Autowired private CurtainsRepository curtainsService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; - @GetMapping - public List 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) { + private Curtains save(Curtains newRL, DimmableSaveRequest s, final Principal principal) { newRL.setName(s.getName()); newRL.setRoomId(s.getRoomId()); newRL.setIntensity(s.getIntensity()); - return curtainsService.save(newRL); + return deviceService.saveAsOwner(newRL, principal.getName()); } @PostMapping - public Curtains create(@Valid @RequestBody DimmableSaveRequest curtain) { - return save(new Curtains(), curtain); + public Curtains create( + @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) { + return save(new Curtains(), curtain, principal); } @PutMapping - public Curtains update(@Valid @RequestBody DimmableSaveRequest curtain) + public Curtains update( + @Valid @RequestBody DimmableSaveRequest curtain, final Principal principal) throws NotFoundException { return save( curtainsService.findById(curtain.getId()).orElseThrow(NotFoundException::new), - curtain); + curtain, + principal); } @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - curtainsService.deleteById(id); + public void delete(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } @PostMapping("/{id}/state") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java index 17bdec7..ac1acd4 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java @@ -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.DeviceRepository; import ch.usi.inf.sa4.sanmarinoes.smarthut.models.RoomRepository; +import ch.usi.inf.sa4.sanmarinoes.smarthut.service.DeviceService; import java.security.Principal; import java.util.List; import javax.validation.Valid; @@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/device") public class DeviceController { + @Autowired private DeviceService deviceService; @Autowired private DeviceRepository deviceRepository; @Autowired private RoomRepository roomRepository; @@ -43,7 +45,7 @@ public class DeviceController { d.setRoomId(deviceSaveRequest.getRoomId()); d.setName(deviceSaveRequest.getName()); - deviceRepository.save(d); + deviceService.saveAsOwner(d, principal.getName()); return d; } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java index 3a714e8..3c80b39 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DimmableLightController.java @@ -1,6 +1,5 @@ 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.error.DuplicateStateException; @@ -8,7 +7,6 @@ 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.DeviceService; 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; @@ -38,16 +36,6 @@ public class DimmableLightController extends GuestEnabledController findAll() { - return toList(dimmableLightRepository.findAll()); - } - - @GetMapping("/{id}") - public DimmableLight findById(@PathVariable("id") long id) throws NotFoundException { - return dimmableLightRepository.findById(id).orElseThrow(NotFoundException::new); - } - private DimmableLight save( DimmableLight initial, DimmableSaveRequest dl, String username, Long hostId) throws NotFoundException { @@ -89,8 +77,9 @@ public class DimmableLightController extends GuestEnabledController { +public class KnobDimmerController extends InputDeviceConnectionController { + @Autowired private DeviceService deviceService; @Autowired private KnobDimmerRepository knobDimmerRepository; @Autowired private DimmableRepository dimmableRepository; @Autowired protected KnobDimmerController( KnobDimmerRepository inputRepository, DimmableRepository outputRepository) { - super( - inputRepository, - outputRepository, - Dimmable.KNOB_DIMMER_DIMMABLE_CONNECTOR); + super(inputRepository, outputRepository, Dimmable.KNOB_DIMMER_DIMMABLE_CONNECTOR); this.knobDimmerRepository = inputRepository; this.dimmableRepository = outputRepository; } - @GetMapping - public List findAll() { - return toList(knobDimmerRepository.findAll()); - } - - @GetMapping("/{id}") - public KnobDimmer findById(@PathVariable("id") long id) throws NotFoundException { - return knobDimmerRepository.findById(id).orElseThrow(NotFoundException::new); - } - @PostMapping - public KnobDimmer create(@Valid @RequestBody GenericDeviceSaveReguest kd) { + public KnobDimmer create( + @Valid @RequestBody GenericDeviceSaveReguest kd, final Principal principal) { KnobDimmer newKD = new KnobDimmer(); newKD.setName(kd.getName()); newKD.setRoomId(kd.getRoomId()); - return knobDimmerRepository.save(newKD); + return deviceService.saveAsOwner(newKD, principal.getName()); } @PutMapping("/dimTo") @@ -69,7 +56,8 @@ public class KnobDimmerController } @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - knobDimmerRepository.deleteById(id); + public void delete(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java index c349aa2..1d0c70e 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/MotionSensorController.java @@ -1,14 +1,13 @@ 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.error.NotFoundException; 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.service.DeviceService; import ch.usi.inf.sa4.sanmarinoes.smarthut.socket.SensorSocketEndpoint; 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; @@ -19,27 +18,20 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/motionSensor") public class MotionSensorController { + @Autowired private DeviceService deviceService; + @Autowired private MotionSensorRepository motionSensorService; @Autowired private SensorSocketEndpoint sensorSocketEndpoint; - @GetMapping - public List findAll() { - return toList(motionSensorService.findAll()); - } - - @GetMapping("/{id}") - public MotionSensor findById(@PathVariable("id") long id) throws NotFoundException { - return motionSensorService.findById(id).orElseThrow(NotFoundException::new); - } - @PostMapping - public MotionSensor create(@Valid @RequestBody GenericDeviceSaveReguest ms) { + public MotionSensor create( + @Valid @RequestBody GenericDeviceSaveReguest ms, final Principal principal) { MotionSensor newMS = new MotionSensor(); newMS.setName(ms.getName()); newMS.setRoomId(ms.getRoomId()); - return motionSensorService.save(newMS); + return deviceService.saveAsOwner(newMS, principal.getName()); } /** @@ -53,7 +45,8 @@ public class MotionSensorController { sensor.setDetected(detected); final MotionSensor toReturn = motionSensorService.save(sensor); - sensorSocketEndpoint.queueDeviceUpdate(sensor, motionSensorService.findUser(sensor.getId())); + sensorSocketEndpoint.queueDeviceUpdate( + sensor, motionSensorService.findUser(sensor.getId())); return toReturn; } @@ -73,7 +66,8 @@ public class MotionSensorController { } @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - motionSensorService.deleteById(id); + public void delete(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java index 308b8ee..47d98d0 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RegularLightController.java @@ -89,8 +89,9 @@ public class RegularLightController extends GuestEnabledController } @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - regularLightRepository.deleteById(id); + public void delete(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } // the full url should be: "/regularLight/{id}/state?sceneId={sceneId} diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java index d7fdc8e..c03c430 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SecurityCameraController.java @@ -1,18 +1,16 @@ 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.error.DuplicateStateException; 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.DeviceService; 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; @@ -26,31 +24,24 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/securityCamera") public class SecurityCameraController { + @Autowired DeviceService deviceService; @Autowired SecurityCameraRepository securityCameraService; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; - @GetMapping - public List findAll() { - 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) { + private SecurityCamera save( + SecurityCamera newSC, SwitchableSaveRequest sc, final Principal principal) { newSC.setName(sc.getName()); newSC.setRoomId(sc.getRoomId()); newSC.setOn(sc.isOn()); - return securityCameraService.save(newSC); + return deviceService.saveAsOwner(newSC, principal.getName()); } @PostMapping - public SecurityCamera create(@Valid @RequestBody SwitchableSaveRequest sc) { - return save(new SecurityCamera(), sc); + public SecurityCamera create( + @Valid @RequestBody SwitchableSaveRequest sc, final Principal principal) { + return save(new SecurityCamera(), sc, principal); } @PutMapping @@ -61,12 +52,14 @@ public class SecurityCameraController { securityCameraService .findByIdAndUsername(sc.getId(), principal.getName()) .orElseThrow(NotFoundException::new), - sc); + sc, + principal); } @DeleteMapping("/{id}") - public void delete(@PathVariable("id") long id) { - securityCameraService.deleteById(id); + public void delete(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } @PostMapping("/{id}/state") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java index b56fd60..5c14f07 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SensorController.java @@ -1,19 +1,16 @@ 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.error.NotFoundException; 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.socket.SensorSocketEndpoint; - import java.math.BigDecimal; import java.security.Principal; import java.util.*; -import java.util.List; import javax.validation.Valid; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; import org.springframework.web.bind.annotation.*; @@ -23,34 +20,23 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/sensor") public class SensorController { - @Autowired - private SensorRepository sensorRepository; + @Autowired private DeviceService deviceService; - @Autowired - private SensorSocketEndpoint sensorSocketEndpoint; + @Autowired private SensorRepository sensorRepository; - @Autowired - private SensorService sensorService; + @Autowired private SensorSocketEndpoint sensorSocketEndpoint; - @GetMapping - public List findAll() { - return toList(sensorRepository.findAll()); - } - - @GetMapping("/{id}") - public Sensor findById(@PathVariable("id") long id) throws NotFoundException { - return sensorRepository.findById(id).orElseThrow(NotFoundException::new); - } + @Autowired private SensorService sensorService; @PostMapping - public Sensor create(@Valid @RequestBody SensorSaveRequest s) { + public Sensor create(@Valid @RequestBody SensorSaveRequest s, final Principal principal) { Sensor newSensor = new Sensor(); newSensor.setSensor(s.getSensor()); newSensor.setName(s.getName()); newSensor.setRoomId(s.getRoomId()); newSensor.setValue(s.getValue()); - return sensorRepository.save(newSensor); + return deviceService.saveAsOwner(newSensor, principal.getName()); } @PutMapping("/{id}/value") @@ -67,7 +53,8 @@ public class SensorController { } @DeleteMapping("/{id}") - public void deleteById(@PathVariable("id") long id) { - sensorRepository.deleteById(id); + public void deleteById(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java index d90c9ac..32fb300 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SmartPlugController.java @@ -1,13 +1,12 @@ 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.error.DuplicateStateException; 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.DeviceService; import java.security.Principal; -import java.util.List; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; @@ -18,32 +17,24 @@ import org.springframework.web.bind.annotation.*; @RequestMapping("/smartPlug") public class SmartPlugController { + @Autowired private DeviceService deviceService; @Autowired private SmartPlugRepository smartPlugRepository; @Autowired private SceneRepository sceneRepository; @Autowired private StateRepository> stateRepository; - @GetMapping - public List 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) { + private SmartPlug save(SmartPlug newSP, SwitchableSaveRequest sp, final Principal principal) { newSP.setOn(sp.isOn()); newSP.setId(sp.getId()); newSP.setName(sp.getName()); newSP.setRoomId(sp.getRoomId()); - return smartPlugRepository.save(newSP); + return deviceService.saveAsOwner(newSP, principal.getName()); } @PostMapping - public SmartPlug create(@Valid @RequestBody SwitchableSaveRequest sp) { - return save(new SmartPlug(), sp); + public SmartPlug create( + @Valid @RequestBody SwitchableSaveRequest sp, final Principal principal) { + return save(new SmartPlug(), sp, principal); } @PutMapping @@ -53,7 +44,8 @@ public class SmartPlugController { smartPlugRepository .findByIdAndUsername(sp.getId(), principal.getName()) .orElseThrow(NotFoundException::new), - sp); + sp, + principal); } @DeleteMapping("/{id}/meter") @@ -69,8 +61,9 @@ public class SmartPlugController { } @DeleteMapping("/{id}") - public void deleteById(@PathVariable("id") long id) { - smartPlugRepository.deleteById(id); + public void deleteById(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } @PostMapping("/{id}/state") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java index 3a87b18..eecd86e 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/SwitchController.java @@ -1,15 +1,13 @@ 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.SwitchOperationRequest; 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.DeviceService; import java.security.Principal; import java.util.*; -import java.util.List; -import java.util.stream.Collectors; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.*; @@ -22,6 +20,7 @@ public class SwitchController extends InputDeviceConnectionController switchableRepository; + private DeviceService deviceService; /** * Contstructs the controller by requiring essential object for the controller implementation @@ -31,29 +30,23 @@ public class SwitchController extends InputDeviceConnectionController outputRepository) { + SwitchRepository inputRepository, + SwitchableRepository outputRepository, + DeviceService deviceService) { super(inputRepository, outputRepository, Switchable.SWITCH_SWITCHABLE_CONNECTOR); + this.deviceService = deviceService; this.switchRepository = inputRepository; this.switchableRepository = outputRepository; } - @GetMapping - public List findAll() { - return toList(switchRepository.findAll()); - } - - @GetMapping("/{id}") - public Switch findById(@PathVariable("id") long id) throws NotFoundException { - return switchRepository.findById(id).orElseThrow(NotFoundException::new); - } - @PostMapping - public Switch create(@Valid @RequestBody GenericDeviceSaveReguest s) { + public Switch create( + @Valid @RequestBody GenericDeviceSaveReguest s, final Principal principal) { Switch newSwitch = new Switch(); newSwitch.setName(s.getName()); newSwitch.setRoomId(s.getRoomId()); - return switchRepository.save(newSwitch); + return deviceService.saveAsOwner(newSwitch, principal.getName()); } @PutMapping("/operate") @@ -83,7 +76,8 @@ public class SwitchController extends InputDeviceConnectionController> stateRepository; - @GetMapping - public List 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) { + private Thermostat save(Thermostat newT, ThermostatSaveRequest t, final Principal principal) { newT.setTargetTemperature(t.getTargetTemperature()); newT.setId(t.getId()); newT.setName(t.getName()); @@ -45,14 +31,15 @@ public class ThermostatController { newT.setUseExternalSensors(t.isUseExternalSensors()); newT.setOn(t.isTurnOn()); - newT = thermostatRepository.save(newT); + newT = deviceService.saveAsOwner(newT, principal.getName()); thermostatService.populateMeasuredTemperature(newT); return newT; } @PostMapping - public Thermostat create(@Valid @RequestBody ThermostatSaveRequest t) { - return save(new Thermostat(), t); + public Thermostat create( + @Valid @RequestBody ThermostatSaveRequest t, final Principal principal) { + return save(new Thermostat(), t, principal); } @PutMapping @@ -62,12 +49,14 @@ public class ThermostatController { thermostatRepository .findByIdAndUsername(t.getId(), principal.getName()) .orElseThrow(NotFoundException::new), - t); + t, + principal); } @DeleteMapping("/{id}") - public void deleteById(@PathVariable("id") long id) { - thermostatRepository.deleteById(id); + public void deleteById(@PathVariable("id") long id, final Principal principal) + throws NotFoundException { + deviceService.delete(id, principal.getName()); } @PostMapping("/{id}/state") diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java index 3b681c5..dfc852d 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/Device.java @@ -70,6 +70,20 @@ public abstract class Device { @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; } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index 4bf6cca..1ed0ea4 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -44,7 +44,7 @@ public class DeviceService { // enqueue all device updates for all other guests endpoint.queueDeviceUpdate(device, guest); } - // broadcast device updates for all other guests + return device; } @@ -60,8 +60,26 @@ public class DeviceService { // broadcast to endpoint the object device, with receiving user set to guest endpoint.queueDeviceUpdate(device, guest); } - // 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 + 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 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); + } + } } From 3894fa14a9b9f04ebe79a6bce44d5d92681079a0 Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Wed, 22 Apr 2020 22:54:34 +0200 Subject: [PATCH 16/16] Code review --- .../smarthut/config/SpringFoxConfig.java | 1 + .../smarthut/controller/DeviceController.java | 6 +- .../smarthut/controller/GuestController.java | 26 ++++---- .../smarthut/controller/RoomController.java | 25 ++++---- .../sa4/sanmarinoes/smarthut/models/User.java | 18 +++--- .../smarthut/service/DeviceService.java | 60 +++++++++++++++++-- 6 files changed, 95 insertions(+), 41 deletions(-) diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java index 2f45d22..d09adfb 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/config/SpringFoxConfig.java @@ -81,6 +81,7 @@ public class SpringFoxConfig { .or(PathSelectors.regex("/switch.*")::apply) .or(PathSelectors.regex("/motionSensor.*")::apply) .or(PathSelectors.regex("/curtains.*")::apply) + .or(PathSelectors.regex("/user.*")::apply) .or(PathSelectors.regex("/auth/profile.*")::apply); } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java index ac1acd4..b53b0af 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/DeviceController.java @@ -24,8 +24,10 @@ public class DeviceController { @Autowired private RoomRepository roomRepository; @GetMapping - public List getAll(final Principal user) { - return deviceRepository.findAllByUsername(user.getName()); + public List getAll( + @RequestParam(value = "hostId", required = false) Long hostId, final Principal user) + throws NotFoundException { + return deviceService.findAll(hostId, user.getName()); } @PutMapping diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java index e0fc3e9..b0994a1 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/GuestController.java @@ -10,8 +10,12 @@ 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; @@ -21,31 +25,29 @@ public class GuestController { return toList(userRepository.findAll()); } - @PostMapping - public User addUserAsGuest(long id, final Principal principal) throws NotFoundException { + @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); - /* Not sure if this is useful. userRepository.save(guest); */ return userRepository.save(host); } - public User save(GuestPermissionsRequest g, User currentUser) { + @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); } - @PutMapping - public User updatePermissions( - @Valid @RequestBody GuestPermissionsRequest g, final Principal principal) { - return this.save(g, userRepository.findByUsername(principal.getName())); - } - - @DeleteMapping - public void removeUserAsGuest(long id, final Principal principal) throws NotFoundException { + @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()); diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java index 7de58db..136446a 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/controller/RoomController.java @@ -5,6 +5,7 @@ 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.error.NotFoundException; 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.utils.Utils; import java.security.Principal; @@ -23,7 +24,7 @@ public class RoomController { @Autowired private UserRepository userRepository; - @Autowired private DeviceRepository deviceRepository; + @Autowired private DeviceService deviceService; @Autowired private SwitchRepository switchRepository; @@ -43,7 +44,10 @@ public class RoomController { } @GetMapping - public List findAll(Long hostId, final Principal principal) throws NotFoundException { + public List findAll( + @RequestParam(value = "hostId", required = false) Long hostId, + final Principal principal) + throws NotFoundException { List rooms = toList(roomRepository.findAll()); return fetchOwnerOrGuest(rooms, hostId, principal); @@ -51,7 +55,9 @@ public class RoomController { @GetMapping("/{id}") public @ResponseBody Room findById( - @PathVariable("id") long id, final Principal principal, Long hostId) + @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, @@ -122,15 +128,10 @@ public class RoomController { */ @GetMapping(path = "/{roomId}/devices") public List getDevices( - @PathVariable("roomId") long roomid, final Principal principal, Long hostId) + @PathVariable("roomId") long roomId, + final Principal principal, + @RequestParam(value = "hostId", required = false) Long hostId) throws NotFoundException { - Iterable devices = deviceRepository.findByRoomId(roomid); - for (Device d : devices) { - if (d instanceof Thermostat) { - thermostatService.populateMeasuredTemperature((Thermostat) d); - } - } - List deviceList = toList(devices); - return fetchOwnerOrGuest(deviceList, hostId, principal); + return deviceService.findAll(roomId, hostId, principal.getName()); } } diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java index 5880ec6..b58e383 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/models/User.java @@ -38,11 +38,7 @@ public class User { private String email; /** Guests invited by this user */ - @ManyToMany(cascade = CascadeType.DETACH) - @JoinTable( - name = "invited", - joinColumns = @JoinColumn(name = "host_id"), - inverseJoinColumns = @JoinColumn(name = "guest_id")) + @ManyToMany(mappedBy = "hosts", cascade = CascadeType.DETACH) @GsonExclude private Set guests = new HashSet<>(); @@ -55,7 +51,8 @@ public class User { private Set hosts = new HashSet<>(); /** Determines whether a guest can access security cameras */ - @Column private boolean cameraEnabled; + @Column(nullable = false) + private boolean cameraEnabled; @Column(nullable = false) @GsonExclude @@ -130,9 +127,7 @@ public class User { } public void removeGuest(User guest) { - if (this.guests.contains(guest)) { - this.guests.remove(guest); - } + this.guests.remove(guest); } public void setCameraEnabled(boolean cameraEnabled) { @@ -141,8 +136,7 @@ public class User { @Override public String toString() { - return "User{" - + "id=" + return "User{id=" + id + ", name='" + name @@ -156,6 +150,8 @@ public class User { + ", email='" + email + '\'' + + ", cameraEnabled=" + + cameraEnabled + ", isEnabled=" + isEnabled + '}'; diff --git a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java index 1ed0ea4..f95cb21 100644 --- a/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java +++ b/src/main/java/ch/usi/inf/sa4/sanmarinoes/smarthut/service/DeviceService.java @@ -1,11 +1,11 @@ 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.Device; -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.UserRepository; +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; @@ -15,8 +15,60 @@ public class DeviceService { // FIXME: TO BE MERGED WITH USER STORY 5 (MATTEO'S STUFF) @Autowired private DeviceRepository deviceRepository; + @Autowired private RoomRepository roomRepository; @Autowired private UserRepository userRepository; @Autowired private SensorSocketEndpoint endpoint; + @Autowired private ThermostatService thermostatService; + + public List findAll(Long hostId, String username) throws NotFoundException { + return findAll(null, hostId, username); + } + + public List findAll(Long roomId, Long hostId, String username) + throws NotFoundException { + try { + Iterable 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 saveAsGuest(T device, String guestUsername, Long hostId) throws NotFoundException {