diff --git a/src/main/java/de/thm/arsnova/controller/v2/CommentController.java b/src/main/java/de/thm/arsnova/controller/v2/CommentController.java index dc7a9fc5bd1d05b4cb0b43121e3b3697c69bad74..e117619c30aaf3b422e3b6d09fbab963ab4fc803 100644 --- a/src/main/java/de/thm/arsnova/controller/v2/CommentController.java +++ b/src/main/java/de/thm/arsnova/controller/v2/CommentController.java @@ -18,13 +18,14 @@ package de.thm.arsnova.controller.v2; import de.thm.arsnova.controller.PaginationController; -import de.thm.arsnova.entities.UserProfile; +import de.thm.arsnova.entities.Room; import de.thm.arsnova.entities.migration.FromV2Migrator; import de.thm.arsnova.entities.migration.ToV2Migrator; import de.thm.arsnova.entities.migration.v2.Comment; import de.thm.arsnova.entities.migration.v2.CommentReadingCount; import de.thm.arsnova.exceptions.BadRequestException; import de.thm.arsnova.services.CommentService; +import de.thm.arsnova.services.RoomService; import de.thm.arsnova.services.UserService; import de.thm.arsnova.web.DeprecatedApi; import de.thm.arsnova.web.Pagination; @@ -44,6 +45,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import java.io.IOException; import java.util.List; import java.util.stream.Collectors; @@ -58,6 +60,9 @@ public class CommentController extends PaginationController { @Autowired private CommentService commentService; + @Autowired + private RoomService roomService; + @Autowired private UserService userService; @@ -97,7 +102,7 @@ public class CommentController extends PaginationController { @ApiOperation(value = "Retrieves an Comment", nickname = "getComment") @RequestMapping(value = "/{commentId}", method = RequestMethod.GET) - public Comment getComment(@ApiParam(value = "ID of the Comment that needs to be deleted", required = true) @PathVariable final String commentId) { + public Comment getComment(@ApiParam(value = "ID of the Comment that needs to be deleted", required = true) @PathVariable final String commentId) throws IOException { return toV2Migrator.migrate(commentService.getAndMarkRead(commentId)); } @@ -112,8 +117,10 @@ public class CommentController extends PaginationController { @ApiParam(value = "Room-Key from current room", required = true) @RequestParam("sessionkey") final String roomShortId, @ApiParam(value = "the body from the new comment", required = true) @RequestBody final Comment comment ) { - UserProfile profile = userService.getByUsername(comment.getCreator()); - if (commentService.save(fromV2Migrator.migrate(comment, profile))) { + de.thm.arsnova.entities.Comment commentV3 = fromV2Migrator.migrate(comment); + Room roomV3 = roomService.getByShortId(roomShortId); + commentV3.setRoomId(roomV3.getId()); + if (commentService.save(commentV3)) { return; } diff --git a/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java b/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java index cb515d59465854da113f4246bf9b2c8b22698d4a..0ba594b316a0558096e1b3e048d390c27577059c 100644 --- a/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java +++ b/src/main/java/de/thm/arsnova/entities/migration/FromV2Migrator.java @@ -22,6 +22,7 @@ import de.thm.arsnova.entities.ChoiceQuestionContent; import de.thm.arsnova.entities.TextAnswer; import de.thm.arsnova.entities.UserProfile; import de.thm.arsnova.entities.migration.v2.*; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; import java.util.Arrays; @@ -221,14 +222,17 @@ public class FromV2Migrator { return to; } - public de.thm.arsnova.entities.Comment migrate(final Comment from, final UserProfile creator) { - if (!creator.getLoginId().equals(from.getCreator())) { + public de.thm.arsnova.entities.Comment migrate(final Comment from, @Nullable final UserProfile creator) { + if (creator == null && from.getCreator() != null || + creator != null && !creator.getLoginId().equals(from.getCreator())) { throw new IllegalArgumentException("Username of creator object does not match comment creator."); } final de.thm.arsnova.entities.Comment to = new de.thm.arsnova.entities.Comment(); copyCommonProperties(from, to); to.setRoomId(from.getSessionId()); - to.setCreatorId(creator.getId()); + if (creator != null) { + to.setCreatorId(creator.getId()); + } to.setSubject(from.getSubject()); to.setBody(from.getText()); to.setTimestamp(new Date(from.getTimestamp())); @@ -237,6 +241,11 @@ public class FromV2Migrator { return to; } + + public de.thm.arsnova.entities.Comment migrate(final Comment from) { + return migrate(from, null); + } + public de.thm.arsnova.entities.Motd migrate(final Motd from) { final de.thm.arsnova.entities.Motd to = new de.thm.arsnova.entities.Motd(); copyCommonProperties(from, to); diff --git a/src/main/java/de/thm/arsnova/entities/migration/v2/Comment.java b/src/main/java/de/thm/arsnova/entities/migration/v2/Comment.java index 3aa5afc1cc0c53f8bf97116984304f29531843cf..1856bedb7f0d52e7b0ab0c72237e0f5c17ec962d 100644 --- a/src/main/java/de/thm/arsnova/entities/migration/v2/Comment.java +++ b/src/main/java/de/thm/arsnova/entities/migration/v2/Comment.java @@ -17,6 +17,7 @@ */ package de.thm.arsnova.entities.migration.v2; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonView; import de.thm.arsnova.entities.UserAuthentication; import de.thm.arsnova.entities.serialization.View; @@ -43,6 +44,7 @@ public class Comment implements Entity { private String creator; @JsonView({View.Persistence.class, View.Public.class}) + @JsonProperty("_id") public String getId() { return id; } @@ -62,6 +64,13 @@ public class Comment implements Entity { return rev; } + /* Need because of an inconsistency in the v2 API */ + @JsonView(View.Public.class) + @JsonProperty("id") + public String getApiId() { + return id; + } + @ApiModelProperty(required = true, value = "is read") @JsonView({View.Persistence.class, View.Public.class}) public boolean isRead() { diff --git a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java index 56c314fbe964939e3965feacacc6158c9878c1fc..9d37ecd9ef1281ac2004e320cf20768e586a4703 100644 --- a/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java +++ b/src/main/java/de/thm/arsnova/persistance/couchdb/CouchDbCommentRepository.java @@ -52,8 +52,8 @@ public class CouchDbCommentRepository extends CouchDbCrudRepository<Comment> imp @Override public CommentReadingCount countReadingByRoomIdAndUser(final String roomId, final UserAuthentication user) { final ViewResult result = db.queryView(createQuery("by_roomid_creatorid_read") - .startKey(ComplexKey.of(roomId, user.getUsername())) - .endKey(ComplexKey.of(roomId, user.getUsername(), ComplexKey.emptyObject())) + .startKey(ComplexKey.of(roomId, user.getId())) + .endKey(ComplexKey.of(roomId, user.getId(), ComplexKey.emptyObject())) .reduce(true) .group(true)); return calculateReadingCount(result); diff --git a/src/main/java/de/thm/arsnova/services/CommentService.java b/src/main/java/de/thm/arsnova/services/CommentService.java index 083ac7a9aba3a3afc786acd59be25f41d6bf20cb..713a912ccceb939fa1d9658e4b1ee898fc729a73 100644 --- a/src/main/java/de/thm/arsnova/services/CommentService.java +++ b/src/main/java/de/thm/arsnova/services/CommentService.java @@ -1,9 +1,9 @@ package de.thm.arsnova.services; import de.thm.arsnova.entities.Comment; -import de.thm.arsnova.entities.UserAuthentication; import de.thm.arsnova.entities.migration.v2.CommentReadingCount; +import java.io.IOException; import java.util.List; public interface CommentService extends EntityService<Comment> { @@ -15,9 +15,7 @@ public interface CommentService extends EntityService<Comment> { List<Comment> getByRoomShortId(String roomShortId, int offset, int limit); - Comment getAndMarkRead(String commentId); - - Comment getAndMarkReadInternal(String commentId, UserAuthentication user); + Comment getAndMarkRead(String commentId) throws IOException; void delete(String commentId); diff --git a/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java b/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java index 048d126768040177a8bb334422566b96239b1159..59f0891252726099b6370b6e3673da00a882a50b 100644 --- a/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java +++ b/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java @@ -18,8 +18,11 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import java.io.IOException; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Performs all comment related operations. @@ -53,9 +56,8 @@ public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implem @Override @PreAuthorize("isAuthenticated()") public boolean save(final Comment comment) { - final Room room = roomRepository.findByShortId(comment.getRoomId()); + final Room room = roomRepository.findOne(comment.getRoomId()); final UserAuthentication user = userService.getCurrentUser(); - comment.setRoomId(room.getId()); comment.setCreatorId(user.getId()); comment.setRead(false); if (comment.getTimestamp() == null) { @@ -138,30 +140,16 @@ public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implem } @Override - @PreAuthorize("isAuthenticated()") - public Comment getAndMarkRead(final String commentId) { - final UserAuthentication user = userService.getCurrentUser(); - return this.getAndMarkReadInternal(commentId, user); - } - - /* - * The "internal" suffix means it is called by internal services that have no authentication! - * TODO: Find a better way of doing this... - */ - @Override - public Comment getAndMarkReadInternal(final String commentId, UserAuthentication user) { + @PreAuthorize("hasPermission(#commentId, 'comment', 'update')") + public Comment getAndMarkRead(final String commentId) throws IOException { final Comment comment = commentRepository.findOne(commentId); if (comment == null) { throw new NotFoundException(); } - final Room room = roomRepository.findOne(comment.getRoomId()); - if (!comment.getCreatorId().equals(user.getId()) && !room.getOwnerId().equals(user.getId())) { - throw new UnauthorizedException(); - } - if (room.getOwnerId().equals(user.getId())) { - comment.setRead(true); - save(comment); - } + Map<String, Object> changes = new HashMap<>(); + changes.put("read", true); + patch(comment, changes); + return comment; } diff --git a/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java b/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java index d62fdb3d185e7fcff350dcdc8ebc074c2876936f..51390f4001f944ee13e7f05d00015aa734c10916 100644 --- a/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java +++ b/src/main/java/de/thm/arsnova/websocket/ArsnovaSocketioServerImpl.java @@ -53,6 +53,7 @@ import org.springframework.stereotype.Component; import javax.annotation.PreDestroy; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collections; @@ -196,8 +197,8 @@ public class ArsnovaSocketioServerImpl implements ArsnovaSocketioServer, Arsnova AckRequest ackRequest) { final UserAuthentication user = userService.getUserToSocketId(client.getSessionId()); try { - commentService.getAndMarkReadInternal(comment.getId(), user); - } catch (NotFoundException | UnauthorizedException e) { + commentService.getAndMarkRead(comment.getId()); + } catch (IOException | NotFoundException | UnauthorizedException e) { logger.error("Loading of comment {} failed for user {} with exception {}", comment.getId(), user, e.getMessage()); } }