From 7d4877ac2d0ad04a6591d19d740ea769d1c99d07 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Tue, 17 Oct 2023 08:43:29 +0200 Subject: [PATCH 1/7] add logs to find out why message creation is slow --- .../service/metis/ConversationMessagingService.java | 12 +++++++----- .../metis/conversation/ConversationService.java | 2 +- .../web/rest/metis/ConversationMessageResource.java | 3 +++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java index c1210490f282..418e8bf16d0b 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java @@ -85,13 +85,15 @@ public Post createMessage(Long courseId, Post newMessage) { throw new BadRequestAlertException("A new message post must have a conversation", METIS_POST_ENTITY_NAME, "conversationnotset"); } - var author = this.userRepository.getUserWithGroupsAndAuthorities(); + var author = userRepository.getUserWithGroupsAndAuthorities(); newMessage.setAuthor(author); newMessage.setDisplayPriority(DisplayPriority.NONE); conversationService.isMemberElseThrow(newMessage.getConversation().getId(), author.getId()); + log.info(" createMessage:conversationService.isMemberElseThrow DONE"); var conversation = conversationRepository.findByIdElseThrow(newMessage.getConversation().getId()); + log.info(" createMessage:conversationRepository.findByIdElseThrow DONE"); // IMPORTANT we don't need it in the conversation any more, so we reduce the amount of data sent to clients conversation.setConversationParticipants(Set.of()); var course = preCheckUserAndCourseForMessaging(author, courseId); @@ -100,9 +102,9 @@ public Post createMessage(Long courseId, Post newMessage) { if (conversation instanceof Channel channel) { channelAuthorizationService.isAllowedToCreateNewPostInChannel(channel, author); } - + log.info(" createMessage:additional authorization DONE"); Set mentionedUsers = parseUserMentions(course, newMessage.getContent()); - + log.info(" createMessage:parseUserMentions DONE"); // update last message date of conversation conversation.setLastMessageDate(ZonedDateTime.now()); conversation.setCourse(course); @@ -119,10 +121,10 @@ public Post createMessage(Long courseId, Post newMessage) { if (createdMessage.getConversation() != null) { createdMessage.getConversation().hideDetails(); } - + log.info(" conversationMessageRepository.save DONE"); // TODO: we should consider invoking the following method async to avoid that authors wait for the message creation if many notifications are sent notifyAboutMessageCreation(author, savedConversation, course, createdMessage, mentionedUsers); - + log.info(" notifyAboutMessageCreation DONE"); return createdMessage; } diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/conversation/ConversationService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/conversation/ConversationService.java index 5db5b8df1c9a..02d834ae65f7 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/conversation/ConversationService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/conversation/ConversationService.java @@ -236,7 +236,7 @@ public void deregisterUsersFromAConversation(Course course, Set users, Con var remainingUsers = existingUsers.stream().filter(user -> !usersToBeDeregistered.contains(user)).collect(Collectors.toSet()); var participantsToRemove = conversationParticipantRepository.findConversationParticipantsByConversationIdAndUserIds(conversation.getId(), usersToBeDeregistered.stream().map(User::getId).collect(Collectors.toSet())); - if (participantsToRemove.size() > 0) { + if (!participantsToRemove.isEmpty()) { conversationParticipantRepository.deleteAll(participantsToRemove); broadcastOnConversationMembershipChannel(course, MetisCrudAction.DELETE, conversation, usersToBeDeregistered); broadcastOnConversationMembershipChannel(course, MetisCrudAction.UPDATE, conversation, remainingUsers); diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java index 792ba1eef2e6..2fb571f689ab 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java @@ -51,7 +51,10 @@ public ConversationMessageResource(ConversationMessagingService conversationMess @PostMapping("courses/{courseId}/messages") @EnforceAtLeastStudent public ResponseEntity createMessage(@PathVariable Long courseId, @Valid @RequestBody Post post) throws URISyntaxException { + log.info("POST createMessage invoked for course {} with post {}", courseId, post.getContent()); + long start = System.nanoTime(); Post createdMessage = conversationMessagingService.createMessage(courseId, post); + log.info("createMessage took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.created(new URI("/api/courses/" + courseId + "/messages/" + createdMessage.getId())).body(createdMessage); } From 29d4414ab78b28d35f82cb8839715273ead5b3b7 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Tue, 17 Oct 2023 08:53:26 +0200 Subject: [PATCH 2/7] add more time logs --- .../service/metis/AnswerPostService.java | 2 +- .../web/rest/metis/AnswerMessageResource.java | 22 ++++++++++++++----- .../web/rest/metis/AnswerPostResource.java | 18 +++++++++++---- .../metis/ConversationMessageResource.java | 8 ++++++- .../artemis/web/rest/metis/PostResource.java | 14 ++++++++++++ 5 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/AnswerPostService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/AnswerPostService.java index 63e682a89d20..71892690feda 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/AnswerPostService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/AnswerPostService.java @@ -84,7 +84,7 @@ public AnswerPost createAnswerPost(Long courseId, AnswerPost answerPost) { AnswerPost savedAnswerPost = answerPostRepository.save(answerPost); postRepository.save(post); - this.preparePostAndBroadcast(savedAnswerPost, course); + preparePostAndBroadcast(savedAnswerPost, course); sendNotification(post, answerPost, course); return savedAnswerPost; diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java index 7d2ff4e1d739..4f53f1285dbd 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java @@ -3,6 +3,8 @@ import java.net.URI; import java.net.URISyntaxException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -10,11 +12,14 @@ import de.tum.in.www1.artemis.domain.metis.AnswerPost; import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastStudent; import de.tum.in.www1.artemis.service.metis.AnswerMessageService; +import de.tum.in.www1.artemis.service.util.TimeLogUtil; @RestController @RequestMapping("/api") public class AnswerMessageResource { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final AnswerMessageService answerMessageService; public AnswerMessageResource(AnswerMessageService answerMessageService) { @@ -31,10 +36,12 @@ public AnswerMessageResource(AnswerMessageService answerMessageService) { */ @PostMapping("courses/{courseId}/answer-messages") @EnforceAtLeastStudent - public ResponseEntity createAnswerPost(@PathVariable Long courseId, @RequestBody AnswerPost answerMessage) throws URISyntaxException { + public ResponseEntity createAnswerMessage(@PathVariable Long courseId, @RequestBody AnswerPost answerMessage) throws URISyntaxException { + log.info("POST createAnswerMessage invoked for course {} with message {}", courseId, answerMessage.getContent()); + long start = System.nanoTime(); AnswerPost createdAnswerMessage = answerMessageService.createAnswerMessage(courseId, answerMessage); - // creation of answerMessage should not trigger alert + log.info("createAnswerMessage took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.created(new URI("/api/courses" + courseId + "/answer-messages/" + createdAnswerMessage.getId())).body(createdAnswerMessage); } @@ -49,8 +56,11 @@ public ResponseEntity createAnswerPost(@PathVariable Long courseId, */ @PutMapping("courses/{courseId}/answer-messages/{answerMessageId}") @EnforceAtLeastStudent - public ResponseEntity updateAnswerPost(@PathVariable Long courseId, @PathVariable Long answerMessageId, @RequestBody AnswerPost answerMessage) { + public ResponseEntity updateAnswerMessage(@PathVariable Long courseId, @PathVariable Long answerMessageId, @RequestBody AnswerPost answerMessage) { + log.info("PUT updateAnswerMessage invoked for course {} with message {}", courseId, answerMessage.getContent()); + long start = System.nanoTime(); AnswerPost updatedAnswerMessage = answerMessageService.updateAnswerMessage(courseId, answerMessageId, answerMessage); + log.info("updateAnswerMessage took {}", TimeLogUtil.formatDurationFrom(start)); return new ResponseEntity<>(updatedAnswerMessage, null, HttpStatus.OK); } @@ -64,9 +74,11 @@ public ResponseEntity updateAnswerPost(@PathVariable Long courseId, */ @DeleteMapping("courses/{courseId}/answer-messages/{answerMessageId}") @EnforceAtLeastStudent - public ResponseEntity deleteAnswerPost(@PathVariable Long courseId, @PathVariable Long answerMessageId) { + public ResponseEntity deleteAnswerMessage(@PathVariable Long courseId, @PathVariable Long answerMessageId) { + log.info("PUT deleteAnswerMessage invoked for course {} on message {}", courseId, answerMessageId); + long start = System.nanoTime(); answerMessageService.deleteAnswerMessageById(courseId, answerMessageId); - + log.info("deleteAnswerMessage took {}", TimeLogUtil.formatDurationFrom(start)); // deletion of answerMessages should not trigger alert return ResponseEntity.ok().build(); } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java index 923c0711f999..37916a34abe1 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java @@ -3,7 +3,8 @@ import java.net.URI; import java.net.URISyntaxException; -import org.springframework.beans.factory.annotation.Value; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -11,6 +12,7 @@ import de.tum.in.www1.artemis.domain.metis.AnswerPost; import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastStudent; import de.tum.in.www1.artemis.service.metis.AnswerPostService; +import de.tum.in.www1.artemis.service.util.TimeLogUtil; /** * REST controller for managing AnswerPost. @@ -19,10 +21,9 @@ @RequestMapping("/api") public class AnswerPostResource { - private final AnswerPostService answerPostService; + private final Logger log = LoggerFactory.getLogger(getClass()); - @Value("${jhipster.clientApp.name}") - private String applicationName; + private final AnswerPostService answerPostService; public AnswerPostResource(AnswerPostService answerPostService) { this.answerPostService = answerPostService; @@ -39,7 +40,10 @@ public AnswerPostResource(AnswerPostService answerPostService) { @PostMapping("courses/{courseId}/answer-posts") @EnforceAtLeastStudent public ResponseEntity createAnswerPost(@PathVariable Long courseId, @RequestBody AnswerPost answerPost) throws URISyntaxException { + log.info("POST createAnswerPost invoked for course {} with post {}", courseId, answerPost.getContent()); + long start = System.nanoTime(); AnswerPost createdAnswerPost = answerPostService.createAnswerPost(courseId, answerPost); + log.info("createAnswerPost took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.created(new URI("/api/courses" + courseId + "/answer-posts/" + createdAnswerPost.getId())).body(createdAnswerPost); } @@ -55,7 +59,10 @@ public ResponseEntity createAnswerPost(@PathVariable Long courseId, @PutMapping("courses/{courseId}/answer-posts/{answerPostId}") @EnforceAtLeastStudent public ResponseEntity updateAnswerPost(@PathVariable Long courseId, @PathVariable Long answerPostId, @RequestBody AnswerPost answerPost) { + log.info("PUT updateAnswerPost invoked for course {} with post {}", courseId, answerPost.getContent()); + long start = System.nanoTime(); AnswerPost updatedAnswerPost = answerPostService.updateAnswerPost(courseId, answerPostId, answerPost); + log.info("updatedAnswerPost took {}", TimeLogUtil.formatDurationFrom(start)); return new ResponseEntity<>(updatedAnswerPost, null, HttpStatus.OK); } @@ -70,7 +77,10 @@ public ResponseEntity updateAnswerPost(@PathVariable Long courseId, @DeleteMapping("courses/{courseId}/answer-posts/{answerPostId}") @EnforceAtLeastStudent public ResponseEntity deleteAnswerPost(@PathVariable Long courseId, @PathVariable Long answerPostId) { + log.info("PUT deleteAnswerPost invoked for course {} on post {}", courseId, answerPostId); + long start = System.nanoTime(); answerPostService.deleteAnswerPostById(courseId, answerPostId); + log.info("deleteAnswerPost took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java index 2fb571f689ab..4987f3add555 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java @@ -32,7 +32,7 @@ @RequestMapping("/api") public class ConversationMessageResource { - private final Logger log = LoggerFactory.getLogger(this.getClass()); + private final Logger log = LoggerFactory.getLogger(getClass()); private final ConversationMessagingService conversationMessagingService; @@ -106,7 +106,10 @@ private void logDuration(List posts, Principal principal, long timeNanoSta @PutMapping("courses/{courseId}/messages/{messageId}") @EnforceAtLeastStudent public ResponseEntity updateMessage(@PathVariable Long courseId, @PathVariable Long messageId, @RequestBody Post messagePost) { + log.info("PUT updateMessage invoked for course {} with post {}", courseId, messagePost.getContent()); + long start = System.nanoTime(); Post updatedMessagePost = conversationMessagingService.updateMessage(courseId, messageId, messagePost); + log.info("updateMessage took {}", TimeLogUtil.formatDurationFrom(start)); return new ResponseEntity<>(updatedMessagePost, null, HttpStatus.OK); } @@ -121,8 +124,11 @@ public ResponseEntity updateMessage(@PathVariable Long courseId, @PathVari @DeleteMapping("courses/{courseId}/messages/{messageId}") @EnforceAtLeastStudent public ResponseEntity deleteMessage(@PathVariable Long courseId, @PathVariable Long messageId) { + log.info("DELETE deleteMessage invoked for course {} on message {}", courseId, messageId); + long start = System.nanoTime(); conversationMessagingService.deleteMessageById(courseId, messageId); // deletion of message posts should not trigger entity deletion alert + log.info("deleteMessage took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java index c36fe572d627..18e9502cd413 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java @@ -6,6 +6,8 @@ import javax.validation.Valid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -20,6 +22,7 @@ import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastStudent; import de.tum.in.www1.artemis.security.annotations.EnforceAtLeastTutor; import de.tum.in.www1.artemis.service.metis.PostService; +import de.tum.in.www1.artemis.service.util.TimeLogUtil; import de.tum.in.www1.artemis.web.rest.dto.PostContextFilter; import de.tum.in.www1.artemis.web.rest.util.HeaderUtil; import io.swagger.annotations.ApiParam; @@ -32,6 +35,8 @@ @RequestMapping("/api") public class PostResource { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final PostService postService; @Value("${jhipster.clientApp.name}") @@ -52,7 +57,10 @@ public PostResource(PostService postService) { @PostMapping("courses/{courseId}/posts") @EnforceAtLeastStudent public ResponseEntity createPost(@PathVariable Long courseId, @Valid @RequestBody Post post) throws URISyntaxException { + log.info("POST createPost invoked for course {} with post {}", courseId, post.getContent()); + long start = System.nanoTime(); Post createdPost = postService.createPost(courseId, post); + log.info("createPost took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.created(new URI("/api/courses/" + courseId + "/posts/" + createdPost.getId())).body(createdPost); } @@ -68,7 +76,10 @@ public ResponseEntity createPost(@PathVariable Long courseId, @Valid @Requ @PutMapping("courses/{courseId}/posts/{postId}") @EnforceAtLeastStudent public ResponseEntity updatePost(@PathVariable Long courseId, @PathVariable Long postId, @RequestBody Post post) { + log.info("PUT updatePost invoked for course {} with post {}", courseId, post.getContent()); + long start = System.nanoTime(); Post updatedPost = postService.updatePost(courseId, postId, post); + log.info("updatePost took {}", TimeLogUtil.formatDurationFrom(start)); return new ResponseEntity<>(updatedPost, null, HttpStatus.OK); } @@ -133,7 +144,10 @@ public ResponseEntity> getPostsInCourse(@ApiParam Pageable pageable, @DeleteMapping("courses/{courseId}/posts/{postId}") @EnforceAtLeastStudent public ResponseEntity deletePost(@PathVariable Long courseId, @PathVariable Long postId) { + log.info("DELETE deletePost invoked for course {} on post {}", courseId, postId); + long start = System.nanoTime(); postService.deletePostById(courseId, postId); + log.info("deletePost took {}", TimeLogUtil.formatDurationFrom(start)); return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, postService.getEntityName(), postId.toString())).build(); } From 7a295b58cd2ae91c163799682ff07db4dbc4e570 Mon Sep 17 00:00:00 2001 From: Stephan Krusche Date: Tue, 17 Oct 2023 10:20:56 +0200 Subject: [PATCH 3/7] add more detailed logs --- .../artemis/service/metis/ConversationMessagingService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java index 418e8bf16d0b..8cb90ef0e5ad 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java @@ -130,12 +130,14 @@ public Post createMessage(Long courseId, Post newMessage) { private void notifyAboutMessageCreation(User author, Conversation conversation, Course course, Post createdMessage, Set mentionedUsers) { Set webSocketRecipients = getWebSocketRecipients(conversation).collect(Collectors.toSet()); + log.info(" getWebSocketRecipients DONE"); Set broadcastRecipients = webSocketRecipients.stream().map(ConversationWebSocketRecipientSummary::user).collect(Collectors.toSet()); // Add all mentioned users, including the author (if mentioned). Since working with sets, there are no duplicate user entries broadcastRecipients.addAll(mentionedUsers); // Websocket notification 1: this notifies everyone including the author that there is a new message broadcastForPost(new PostDTO(createdMessage, MetisCrudAction.CREATE), course, broadcastRecipients); + log.info(" broadcastForPost DONE"); if (conversation instanceof OneToOneChat) { var getNumberOfPosts = conversationMessageRepository.countByConversationId(conversation.getId()); @@ -145,17 +147,20 @@ private void notifyAboutMessageCreation(User author, Conversation conversation, } } conversationParticipantRepository.incrementUnreadMessagesCountOfParticipants(conversation.getId(), author.getId()); + log.info(" incrementUnreadMessagesCountOfParticipants DONE"); // ToDo: Optimization Idea: Maybe we can save this websocket call and instead get the last message date from the conversation object in the post somehow? // send conversation with updated last message date to participants. This is necessary to show the unread messages badge in the client // TODO: why do we need notification 2 and 3? we should definitely re-work this! // Websocket notification 2 conversationService.notifyAllConversationMembersAboutNewMessage(course, conversation, broadcastRecipients); + log.info(" conversationService.notifyAllConversationMembersAboutNewMessage DONE"); // creation of message posts should not trigger entity creation alert // Websocket notification 3 Set notificationRecipients = filterNotificationRecipients(author, conversation, webSocketRecipients, mentionedUsers); conversationNotificationService.notifyAboutNewMessage(createdMessage, notificationRecipients, course); + log.info(" conversationNotificationService.notifyAboutNewMessage DONE"); } /** From 273fcde60b9adfe75d41cc1a567073cd3537794a Mon Sep 17 00:00:00 2001 From: Lennart Keller <44754405+lennart-keller@users.noreply.github.com> Date: Tue, 17 Oct 2023 12:16:24 +0200 Subject: [PATCH 4/7] Remove join with course from query to retrieve WebSocket recipients --- .../in/www1/artemis/repository/UserRepository.java | 14 +++++--------- .../www1/artemis/service/metis/PostingService.java | 4 +++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java index 4cdf3ef5505d..80eb5980c976 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java @@ -125,20 +125,16 @@ OR lower(user.login) = lower(:#{#searchInput})) SELECT NEW de.tum.in.www1.artemis.domain.ConversationWebSocketRecipientSummary ( user, CASE WHEN cp.isHidden = true THEN true ELSE false END, - CASE WHEN atLeastTutors.id IS NOT null THEN true ELSE false END + CASE WHEN ug.group = :teachingAssistantGroupName OR ug.group = :editorGroupName OR ug.group = :instructorGroupName THEN true ELSE false END ) FROM User user JOIN UserGroup ug ON ug.userId = user.id - LEFT JOIN Course students ON ug.group = students.studentGroupName - LEFT JOIN Course atLeastTutors ON (atLeastTutors.teachingAssistantGroupName = ug.group - OR atLeastTutors.editorGroupName = ug.group - OR atLeastTutors.instructorGroupName = ug.group - ) LEFT JOIN ConversationParticipant cp ON cp.user.id = user.id AND cp.conversation.id = :conversationId - WHERE user.isDeleted = false - AND (students.id = :courseId OR atLeastTutors.id = :courseId) + WHERE user.isDeleted = false AND (ug.group = :studentGroupName OR ug.group = :teachingAssistantGroupName OR ug.group = :editorGroupName OR ug.group = :instructorGroupName) """) - Set findAllWebSocketRecipientsInCourseForConversation(@Param("courseId") Long courseId, @Param("conversationId") Long conversationId); + Set findAllWebSocketRecipientsInCourseForConversation(@Param("conversationId") Long conversationId, + @Param("studentGroupName") String studentGroupName, @Param("teachingAssistantGroupName") String teachingAssistantGroupName, + @Param("editorGroupName") String editorGroupName, @Param("instructorGroupName") String instructorGroupName); /** * Searches for users in a group by their login or full name. diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java index 14a5cb90fa8c..86964441a1e9 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java @@ -128,7 +128,9 @@ else if (postConversation != null) { */ protected Stream getWebSocketRecipients(Conversation conversation) { if (conversation instanceof Channel channel && channel.getIsCourseWide()) { - return userRepository.findAllWebSocketRecipientsInCourseForConversation(conversation.getCourse().getId(), conversation.getId()).stream(); + Course course = conversation.getCourse(); + return userRepository.findAllWebSocketRecipientsInCourseForConversation(conversation.getId(), course.getStudentGroupName(), course.getTeachingAssistantGroupName(), + course.getEditorGroupName(), course.getInstructorGroupName()).stream(); } return conversationParticipantRepository.findConversationParticipantWithUserGroupsByConversationId(conversation.getId()).stream() From cb074b073f4164de9b3fefc579defaa9ec144acc Mon Sep 17 00:00:00 2001 From: Lennart Keller <44754405+lennart-keller@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:24:52 +0200 Subject: [PATCH 5/7] Return only userId and userLogin from query --- .../domain/ConversationWebSocketRecipientSummary.java | 5 +++-- src/main/java/de/tum/in/www1/artemis/domain/User.java | 10 ++++++++++ .../tum/in/www1/artemis/repository/UserRepository.java | 3 ++- .../service/metis/ConversationMessagingService.java | 10 ++++++---- .../in/www1/artemis/service/metis/PostingService.java | 3 ++- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/ConversationWebSocketRecipientSummary.java b/src/main/java/de/tum/in/www1/artemis/domain/ConversationWebSocketRecipientSummary.java index a687b0642094..1e2dfde09891 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/ConversationWebSocketRecipientSummary.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/ConversationWebSocketRecipientSummary.java @@ -4,9 +4,10 @@ * Stores the user of a conversation participant, who is supposed to receive a websocket message and stores whether * the corresponding conversation is hidden by the user. * - * @param user the user who is a member of the conversation + * @param userId the id of the user who is a member of the conversation + * @param userLogin the login of the user who is a member of the conversation * @param isConversationHidden true if the user has hidden the conversation * @param isAtLeastTutorInCourse true if the user is at least a tutor in the course */ -public record ConversationWebSocketRecipientSummary(User user, boolean isConversationHidden, boolean isAtLeastTutorInCourse) { +public record ConversationWebSocketRecipientSummary(Long userId, String userLogin, boolean isConversationHidden, boolean isAtLeastTutorInCourse) { } diff --git a/src/main/java/de/tum/in/www1/artemis/domain/User.java b/src/main/java/de/tum/in/www1/artemis/domain/User.java index ac4c2b8af51e..70c89abf4c24 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/User.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/User.java @@ -185,6 +185,16 @@ public class User extends AbstractAuditingEntity implements Participant { @Column(name = "iris_accepted") private ZonedDateTime irisAccepted = null; + public User() { + super(); + } + + public User(Long id, String login) { + super(); + this.setId(id); + this.login = login; + } + public String getLogin() { return login; } diff --git a/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java b/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java index 80eb5980c976..84adb42192a9 100644 --- a/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java +++ b/src/main/java/de/tum/in/www1/artemis/repository/UserRepository.java @@ -123,7 +123,8 @@ OR lower(user.login) = lower(:#{#searchInput})) @Query(""" SELECT NEW de.tum.in.www1.artemis.domain.ConversationWebSocketRecipientSummary ( - user, + user.id, + user.login, CASE WHEN cp.isHidden = true THEN true ELSE false END, CASE WHEN ug.group = :teachingAssistantGroupName OR ug.group = :editorGroupName OR ug.group = :instructorGroupName THEN true ELSE false END ) diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java index 8cb90ef0e5ad..fc56c9252e52 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java @@ -131,8 +131,9 @@ public Post createMessage(Long courseId, Post newMessage) { private void notifyAboutMessageCreation(User author, Conversation conversation, Course course, Post createdMessage, Set mentionedUsers) { Set webSocketRecipients = getWebSocketRecipients(conversation).collect(Collectors.toSet()); log.info(" getWebSocketRecipients DONE"); - Set broadcastRecipients = webSocketRecipients.stream().map(ConversationWebSocketRecipientSummary::user).collect(Collectors.toSet()); + Set broadcastRecipients = webSocketRecipients.stream().map(summary -> new User(summary.userId(), summary.userLogin())).collect(Collectors.toSet()); // Add all mentioned users, including the author (if mentioned). Since working with sets, there are no duplicate user entries + mentionedUsers = mentionedUsers.stream().map(user -> new User(user.getId(), user.getLogin())).collect(Collectors.toSet()); broadcastRecipients.addAll(mentionedUsers); // Websocket notification 1: this notifies everyone including the author that there is a new message @@ -179,12 +180,13 @@ private void notifyAboutMessageCreation(User author, Conversation conversation, private Set filterNotificationRecipients(User author, Conversation conversation, Set webSocketRecipients, Set mentionedUsers) { // Initialize filter with check for author - Predicate filter = recipientSummary -> !Objects.equals(recipientSummary.user().getId(), author.getId()); + Predicate filter = recipientSummary -> !Objects.equals(recipientSummary.userId(), author.getId()); if (conversation instanceof Channel channel) { // If a channel is not an announcement channel, filter out users, that hid the conversation if (!channel.getIsAnnouncementChannel()) { - filter = filter.and(recipientSummary -> !recipientSummary.isConversationHidden() || mentionedUsers.contains(recipientSummary.user())); + filter = filter.and( + recipientSummary -> !recipientSummary.isConversationHidden() || mentionedUsers.contains(new User(recipientSummary.userId(), recipientSummary.userLogin()))); } // If a channel is not visible to students, filter out participants that are only students @@ -196,7 +198,7 @@ private Set filterNotificationRecipients(User author, Conversation convers filter = filter.and(recipientSummary -> !recipientSummary.isConversationHidden()); } - return webSocketRecipients.stream().filter(filter).map(ConversationWebSocketRecipientSummary::user).collect(Collectors.toSet()); + return webSocketRecipients.stream().filter(filter).map(summary -> new User(summary.userId(), summary.userLogin())).collect(Collectors.toSet()); } /** diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java index 86964441a1e9..02fafd96f552 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/PostingService.java @@ -134,7 +134,8 @@ protected Stream getWebSocketRecipients(C } return conversationParticipantRepository.findConversationParticipantWithUserGroupsByConversationId(conversation.getId()).stream() - .map(participant -> new ConversationWebSocketRecipientSummary(participant.getUser(), participant.getIsHidden() != null && participant.getIsHidden(), + .map(participant -> new ConversationWebSocketRecipientSummary(participant.getUser().getId(), participant.getUser().getLogin(), + participant.getIsHidden() != null && participant.getIsHidden(), authorizationCheckService.isAtLeastTeachingAssistantInCourse(conversation.getCourse(), participant.getUser()))); } From c6a1fd036f0a684aa7d4088d0120a918015c5bd7 Mon Sep 17 00:00:00 2001 From: Lennart Keller <44754405+lennart-keller@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:43:56 +0200 Subject: [PATCH 6/7] Replace log.info with log.debug, except time duration logs --- .../metis/ConversationMessagingService.java | 18 +++++++++--------- .../web/rest/metis/AnswerMessageResource.java | 6 +++--- .../web/rest/metis/AnswerPostResource.java | 6 +++--- .../metis/ConversationMessageResource.java | 6 +++--- .../artemis/web/rest/metis/PostResource.java | 6 +++--- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java index fc56c9252e52..78b2428d8fff 100644 --- a/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java +++ b/src/main/java/de/tum/in/www1/artemis/service/metis/ConversationMessagingService.java @@ -102,9 +102,9 @@ public Post createMessage(Long courseId, Post newMessage) { if (conversation instanceof Channel channel) { channelAuthorizationService.isAllowedToCreateNewPostInChannel(channel, author); } - log.info(" createMessage:additional authorization DONE"); + log.debug(" createMessage:additional authorization DONE"); Set mentionedUsers = parseUserMentions(course, newMessage.getContent()); - log.info(" createMessage:parseUserMentions DONE"); + log.debug(" createMessage:parseUserMentions DONE"); // update last message date of conversation conversation.setLastMessageDate(ZonedDateTime.now()); conversation.setCourse(course); @@ -121,16 +121,16 @@ public Post createMessage(Long courseId, Post newMessage) { if (createdMessage.getConversation() != null) { createdMessage.getConversation().hideDetails(); } - log.info(" conversationMessageRepository.save DONE"); + log.debug(" conversationMessageRepository.save DONE"); // TODO: we should consider invoking the following method async to avoid that authors wait for the message creation if many notifications are sent notifyAboutMessageCreation(author, savedConversation, course, createdMessage, mentionedUsers); - log.info(" notifyAboutMessageCreation DONE"); + log.debug(" notifyAboutMessageCreation DONE"); return createdMessage; } private void notifyAboutMessageCreation(User author, Conversation conversation, Course course, Post createdMessage, Set mentionedUsers) { Set webSocketRecipients = getWebSocketRecipients(conversation).collect(Collectors.toSet()); - log.info(" getWebSocketRecipients DONE"); + log.debug(" getWebSocketRecipients DONE"); Set broadcastRecipients = webSocketRecipients.stream().map(summary -> new User(summary.userId(), summary.userLogin())).collect(Collectors.toSet()); // Add all mentioned users, including the author (if mentioned). Since working with sets, there are no duplicate user entries mentionedUsers = mentionedUsers.stream().map(user -> new User(user.getId(), user.getLogin())).collect(Collectors.toSet()); @@ -138,7 +138,7 @@ private void notifyAboutMessageCreation(User author, Conversation conversation, // Websocket notification 1: this notifies everyone including the author that there is a new message broadcastForPost(new PostDTO(createdMessage, MetisCrudAction.CREATE), course, broadcastRecipients); - log.info(" broadcastForPost DONE"); + log.debug(" broadcastForPost DONE"); if (conversation instanceof OneToOneChat) { var getNumberOfPosts = conversationMessageRepository.countByConversationId(conversation.getId()); @@ -148,20 +148,20 @@ private void notifyAboutMessageCreation(User author, Conversation conversation, } } conversationParticipantRepository.incrementUnreadMessagesCountOfParticipants(conversation.getId(), author.getId()); - log.info(" incrementUnreadMessagesCountOfParticipants DONE"); + log.debug(" incrementUnreadMessagesCountOfParticipants DONE"); // ToDo: Optimization Idea: Maybe we can save this websocket call and instead get the last message date from the conversation object in the post somehow? // send conversation with updated last message date to participants. This is necessary to show the unread messages badge in the client // TODO: why do we need notification 2 and 3? we should definitely re-work this! // Websocket notification 2 conversationService.notifyAllConversationMembersAboutNewMessage(course, conversation, broadcastRecipients); - log.info(" conversationService.notifyAllConversationMembersAboutNewMessage DONE"); + log.debug(" conversationService.notifyAllConversationMembersAboutNewMessage DONE"); // creation of message posts should not trigger entity creation alert // Websocket notification 3 Set notificationRecipients = filterNotificationRecipients(author, conversation, webSocketRecipients, mentionedUsers); conversationNotificationService.notifyAboutNewMessage(createdMessage, notificationRecipients, course); - log.info(" conversationNotificationService.notifyAboutNewMessage DONE"); + log.debug(" conversationNotificationService.notifyAboutNewMessage DONE"); } /** diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java index 4f53f1285dbd..87ff10ed392d 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerMessageResource.java @@ -37,7 +37,7 @@ public AnswerMessageResource(AnswerMessageService answerMessageService) { @PostMapping("courses/{courseId}/answer-messages") @EnforceAtLeastStudent public ResponseEntity createAnswerMessage(@PathVariable Long courseId, @RequestBody AnswerPost answerMessage) throws URISyntaxException { - log.info("POST createAnswerMessage invoked for course {} with message {}", courseId, answerMessage.getContent()); + log.debug("POST createAnswerMessage invoked for course {} with message {}", courseId, answerMessage.getContent()); long start = System.nanoTime(); AnswerPost createdAnswerMessage = answerMessageService.createAnswerMessage(courseId, answerMessage); // creation of answerMessage should not trigger alert @@ -57,7 +57,7 @@ public ResponseEntity createAnswerMessage(@PathVariable Long courseI @PutMapping("courses/{courseId}/answer-messages/{answerMessageId}") @EnforceAtLeastStudent public ResponseEntity updateAnswerMessage(@PathVariable Long courseId, @PathVariable Long answerMessageId, @RequestBody AnswerPost answerMessage) { - log.info("PUT updateAnswerMessage invoked for course {} with message {}", courseId, answerMessage.getContent()); + log.debug("PUT updateAnswerMessage invoked for course {} with message {}", courseId, answerMessage.getContent()); long start = System.nanoTime(); AnswerPost updatedAnswerMessage = answerMessageService.updateAnswerMessage(courseId, answerMessageId, answerMessage); log.info("updateAnswerMessage took {}", TimeLogUtil.formatDurationFrom(start)); @@ -75,7 +75,7 @@ public ResponseEntity updateAnswerMessage(@PathVariable Long courseI @DeleteMapping("courses/{courseId}/answer-messages/{answerMessageId}") @EnforceAtLeastStudent public ResponseEntity deleteAnswerMessage(@PathVariable Long courseId, @PathVariable Long answerMessageId) { - log.info("PUT deleteAnswerMessage invoked for course {} on message {}", courseId, answerMessageId); + log.debug("PUT deleteAnswerMessage invoked for course {} on message {}", courseId, answerMessageId); long start = System.nanoTime(); answerMessageService.deleteAnswerMessageById(courseId, answerMessageId); log.info("deleteAnswerMessage took {}", TimeLogUtil.formatDurationFrom(start)); diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java index 37916a34abe1..8c2d6a4f527b 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/AnswerPostResource.java @@ -40,7 +40,7 @@ public AnswerPostResource(AnswerPostService answerPostService) { @PostMapping("courses/{courseId}/answer-posts") @EnforceAtLeastStudent public ResponseEntity createAnswerPost(@PathVariable Long courseId, @RequestBody AnswerPost answerPost) throws URISyntaxException { - log.info("POST createAnswerPost invoked for course {} with post {}", courseId, answerPost.getContent()); + log.debug("POST createAnswerPost invoked for course {} with post {}", courseId, answerPost.getContent()); long start = System.nanoTime(); AnswerPost createdAnswerPost = answerPostService.createAnswerPost(courseId, answerPost); log.info("createAnswerPost took {}", TimeLogUtil.formatDurationFrom(start)); @@ -59,7 +59,7 @@ public ResponseEntity createAnswerPost(@PathVariable Long courseId, @PutMapping("courses/{courseId}/answer-posts/{answerPostId}") @EnforceAtLeastStudent public ResponseEntity updateAnswerPost(@PathVariable Long courseId, @PathVariable Long answerPostId, @RequestBody AnswerPost answerPost) { - log.info("PUT updateAnswerPost invoked for course {} with post {}", courseId, answerPost.getContent()); + log.debug("PUT updateAnswerPost invoked for course {} with post {}", courseId, answerPost.getContent()); long start = System.nanoTime(); AnswerPost updatedAnswerPost = answerPostService.updateAnswerPost(courseId, answerPostId, answerPost); log.info("updatedAnswerPost took {}", TimeLogUtil.formatDurationFrom(start)); @@ -77,7 +77,7 @@ public ResponseEntity updateAnswerPost(@PathVariable Long courseId, @DeleteMapping("courses/{courseId}/answer-posts/{answerPostId}") @EnforceAtLeastStudent public ResponseEntity deleteAnswerPost(@PathVariable Long courseId, @PathVariable Long answerPostId) { - log.info("PUT deleteAnswerPost invoked for course {} on post {}", courseId, answerPostId); + log.debug("PUT deleteAnswerPost invoked for course {} on post {}", courseId, answerPostId); long start = System.nanoTime(); answerPostService.deleteAnswerPostById(courseId, answerPostId); log.info("deleteAnswerPost took {}", TimeLogUtil.formatDurationFrom(start)); diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java index 4987f3add555..52ee02c10665 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/ConversationMessageResource.java @@ -51,7 +51,7 @@ public ConversationMessageResource(ConversationMessagingService conversationMess @PostMapping("courses/{courseId}/messages") @EnforceAtLeastStudent public ResponseEntity createMessage(@PathVariable Long courseId, @Valid @RequestBody Post post) throws URISyntaxException { - log.info("POST createMessage invoked for course {} with post {}", courseId, post.getContent()); + log.debug("POST createMessage invoked for course {} with post {}", courseId, post.getContent()); long start = System.nanoTime(); Post createdMessage = conversationMessagingService.createMessage(courseId, post); log.info("createMessage took {}", TimeLogUtil.formatDurationFrom(start)); @@ -106,7 +106,7 @@ private void logDuration(List posts, Principal principal, long timeNanoSta @PutMapping("courses/{courseId}/messages/{messageId}") @EnforceAtLeastStudent public ResponseEntity updateMessage(@PathVariable Long courseId, @PathVariable Long messageId, @RequestBody Post messagePost) { - log.info("PUT updateMessage invoked for course {} with post {}", courseId, messagePost.getContent()); + log.debug("PUT updateMessage invoked for course {} with post {}", courseId, messagePost.getContent()); long start = System.nanoTime(); Post updatedMessagePost = conversationMessagingService.updateMessage(courseId, messageId, messagePost); log.info("updateMessage took {}", TimeLogUtil.formatDurationFrom(start)); @@ -124,7 +124,7 @@ public ResponseEntity updateMessage(@PathVariable Long courseId, @PathVari @DeleteMapping("courses/{courseId}/messages/{messageId}") @EnforceAtLeastStudent public ResponseEntity deleteMessage(@PathVariable Long courseId, @PathVariable Long messageId) { - log.info("DELETE deleteMessage invoked for course {} on message {}", courseId, messageId); + log.debug("DELETE deleteMessage invoked for course {} on message {}", courseId, messageId); long start = System.nanoTime(); conversationMessagingService.deleteMessageById(courseId, messageId); // deletion of message posts should not trigger entity deletion alert diff --git a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java index 18e9502cd413..5d2edd87e7b5 100644 --- a/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java +++ b/src/main/java/de/tum/in/www1/artemis/web/rest/metis/PostResource.java @@ -57,7 +57,7 @@ public PostResource(PostService postService) { @PostMapping("courses/{courseId}/posts") @EnforceAtLeastStudent public ResponseEntity createPost(@PathVariable Long courseId, @Valid @RequestBody Post post) throws URISyntaxException { - log.info("POST createPost invoked for course {} with post {}", courseId, post.getContent()); + log.debug("POST createPost invoked for course {} with post {}", courseId, post.getContent()); long start = System.nanoTime(); Post createdPost = postService.createPost(courseId, post); log.info("createPost took {}", TimeLogUtil.formatDurationFrom(start)); @@ -76,7 +76,7 @@ public ResponseEntity createPost(@PathVariable Long courseId, @Valid @Requ @PutMapping("courses/{courseId}/posts/{postId}") @EnforceAtLeastStudent public ResponseEntity updatePost(@PathVariable Long courseId, @PathVariable Long postId, @RequestBody Post post) { - log.info("PUT updatePost invoked for course {} with post {}", courseId, post.getContent()); + log.debug("PUT updatePost invoked for course {} with post {}", courseId, post.getContent()); long start = System.nanoTime(); Post updatedPost = postService.updatePost(courseId, postId, post); log.info("updatePost took {}", TimeLogUtil.formatDurationFrom(start)); @@ -144,7 +144,7 @@ public ResponseEntity> getPostsInCourse(@ApiParam Pageable pageable, @DeleteMapping("courses/{courseId}/posts/{postId}") @EnforceAtLeastStudent public ResponseEntity deletePost(@PathVariable Long courseId, @PathVariable Long postId) { - log.info("DELETE deletePost invoked for course {} on post {}", courseId, postId); + log.debug("DELETE deletePost invoked for course {} on post {}", courseId, postId); long start = System.nanoTime(); postService.deletePostById(courseId, postId); log.info("deletePost took {}", TimeLogUtil.formatDurationFrom(start)); From 86d51a30d304b3a61ff2b402f77b814210f1a76f Mon Sep 17 00:00:00 2001 From: Lennart Keller <44754405+lennart-keller@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:58:38 +0200 Subject: [PATCH 7/7] Remove super() from constructors --- src/main/java/de/tum/in/www1/artemis/domain/User.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/de/tum/in/www1/artemis/domain/User.java b/src/main/java/de/tum/in/www1/artemis/domain/User.java index 70c89abf4c24..a9f1617370d0 100644 --- a/src/main/java/de/tum/in/www1/artemis/domain/User.java +++ b/src/main/java/de/tum/in/www1/artemis/domain/User.java @@ -186,11 +186,9 @@ public class User extends AbstractAuditingEntity implements Participant { private ZonedDateTime irisAccepted = null; public User() { - super(); } public User(Long id, String login) { - super(); this.setId(id); this.login = login; }