Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communication: Allow user to forward messages #9794

Open
wants to merge 121 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 99 commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
b09c320
consecutive message view with new reaction bar added
asliayk Oct 10, 2024
fedc900
renamed file
asliayk Oct 10, 2024
1113a4b
tests updated
asliayk Oct 10, 2024
df6a1fc
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 10, 2024
8a48723
tests updated
asliayk Oct 11, 2024
613e8d8
tests updated & refactor
asliayk Oct 11, 2024
72fefe2
minor fix
asliayk Oct 11, 2024
313dfef
refactored reaction bar style
asliayk Oct 12, 2024
252cedf
refactored reaction bar style
asliayk Oct 12, 2024
8f264b4
updated resolve button
asliayk Oct 12, 2024
a53c7ba
updated reaction bar style
asliayk Oct 12, 2024
f152661
Merge branch 'develop' into feature/communication/consecutive-message…
yassinsws Oct 13, 2024
e3c5384
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 17, 2024
9725c07
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 21, 2024
6794ca1
added dropdown
asliayk Oct 21, 2024
c9e7e6e
Merge remote-tracking branch 'origin/feature/communication/consecutiv…
asliayk Oct 21, 2024
8726cee
reply view added
asliayk Oct 21, 2024
f6d149c
adjusted timeframe to 5 minutes
asliayk Oct 21, 2024
bfec85d
added dropdown to posting directive
asliayk Oct 21, 2024
0cc49d9
updated strings
asliayk Oct 21, 2024
29a25c5
refactor code, fix pin/unpin string
asliayk Oct 22, 2024
2f73014
opened dropdown disables scrolling
asliayk Oct 23, 2024
c9d276a
fix pin styling, updated tests
asliayk Oct 23, 2024
7792212
updated tests
asliayk Oct 23, 2024
21e97e1
fixed styling
asliayk Oct 23, 2024
67ce6f0
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 23, 2024
eec93d9
directive test added
asliayk Oct 24, 2024
9287c3a
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 24, 2024
d355ce0
minor fix
asliayk Oct 24, 2024
64bae5f
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 26, 2024
f81ba93
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 27, 2024
c34b89f
adjusted dropdown/reaction bar position, added tests
asliayk Oct 27, 2024
daa405a
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Oct 29, 2024
47c5b04
conflicts resolved & adjusted dropdown position
asliayk Oct 29, 2024
73da6d8
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Nov 3, 2024
3d6beb7
refactor @if, fix confirm icon bug/dropdown options visibility
asliayk Nov 3, 2024
95850f1
refactor output variables
asliayk Nov 3, 2024
ba071a1
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Nov 3, 2024
5bf7f97
Merge branch 'develop' into feature/communication/consecutive-message…
asliayk Nov 3, 2024
12937ee
moved undo event to reaction bar directive
asliayk Nov 3, 2024
fe6537f
fix tests
asliayk Nov 3, 2024
ae47652
fix pin message option visibility on dropdown menu
asliayk Nov 3, 2024
7dba8e8
fix visibility of confirm icon for different user roles
asliayk Nov 4, 2024
25cf131
added forward related buttons
asliayk Nov 4, 2024
f83268b
added forward window
asliayk Nov 5, 2024
c9ffab7
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 5, 2024
984e0a5
updated forwarded message ui and endpoint
asliayk Nov 9, 2024
c05b4c6
refactor code according to reviews
asliayk Nov 15, 2024
9ba5b9c
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 15, 2024
2987e00
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 16, 2024
6086403
updated styling
asliayk Nov 16, 2024
c6a13f6
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 16, 2024
191f0f6
updated database column and endpoints
asliayk Nov 16, 2024
b731492
refactor
asliayk Nov 16, 2024
3f1432d
updated with bulk query
asliayk Nov 17, 2024
1931f8c
updated get forward messages, added some tests
asliayk Nov 17, 2024
d450214
added more tests & show more button, created forwardedmessage component
asliayk Nov 18, 2024
112c46e
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 20, 2024
5b30aaa
jump to message & string resources added
asliayk Nov 24, 2024
6230f97
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 24, 2024
4676eca
added more tests
asliayk Nov 24, 2024
5db13bd
added more tests
asliayk Nov 24, 2024
4844e06
added db changes & tests
asliayk Nov 25, 2024
0e8b124
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 25, 2024
f972cca
refactoring
asliayk Nov 25, 2024
a74afdd
refactoring
asliayk Nov 25, 2024
c35144f
added validation
asliayk Nov 25, 2024
d9d370b
refactor
asliayk Nov 25, 2024
b5957e8
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 27, 2024
4119f95
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 28, 2024
46da00e
remove duplication
asliayk Nov 29, 2024
9672950
used PostingType instead of SourceType to avoid duplication
asliayk Nov 29, 2024
8885148
refactor
asliayk Nov 29, 2024
3609731
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 29, 2024
69e1d96
added missing mockdirective
asliayk Nov 30, 2024
2238c7b
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Nov 30, 2024
a1a3adb
refactor after reviews
asliayk Nov 30, 2024
c32e1f5
refactor
asliayk Nov 30, 2024
1af9611
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Dec 2, 2024
afa524d
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Dec 9, 2024
cdcb11f
used signals
asliayk Dec 9, 2024
001e14b
minor fix
asliayk Dec 9, 2024
b72a1d3
add logic to create group chat if multiple users are selected to forw…
asliayk Dec 10, 2024
887afed
update tests
asliayk Dec 10, 2024
f1d78bb
update search user logic
asliayk Dec 10, 2024
3132759
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Dec 14, 2024
04ca1eb
refactor after reviews
asliayk Dec 14, 2024
339a9ea
refactor after reviews
asliayk Dec 16, 2024
9ab78e7
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Dec 16, 2024
0d85eb3
update test
asliayk Dec 16, 2024
2226f37
fix server test issue & refactor after reviews
asliayk Dec 18, 2024
0fe5f54
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Dec 18, 2024
0f4f544
fix server test issue
asliayk Dec 18, 2024
350e2bf
add more tests
asliayk Dec 18, 2024
80a41b8
refactor
asliayk Dec 18, 2024
1ec68a1
refactor
asliayk Dec 18, 2024
ccfc1b7
fix merge conflicts & upper case search input bug
asliayk Dec 25, 2024
af6ba8a
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Dec 25, 2024
d011d73
Merge branch 'develop' into feature/communication/forward-share-message
krusche Jan 5, 2025
5d6d941
added client tests
asliayk Jan 6, 2025
1d3bcf4
added client tests
asliayk Jan 6, 2025
4016e8c
Merge remote-tracking branch 'origin/feature/communication/forward-sh…
asliayk Jan 6, 2025
bd67892
updated test
asliayk Jan 6, 2025
d30e75e
added client tests
asliayk Jan 6, 2025
6c57468
added client tests
asliayk Jan 6, 2025
3505766
remove dayjs in test
asliayk Jan 6, 2025
1adb02a
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Jan 13, 2025
fb685fe
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Jan 13, 2025
d357be7
update standalone
asliayk Jan 13, 2025
92246f8
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Jan 13, 2025
6d5580c
add client tests
asliayk Jan 14, 2025
f642d65
add client tests
asliayk Jan 14, 2025
19b8497
add client test
asliayk Jan 14, 2025
06436eb
add client tests
asliayk Jan 14, 2025
bdde6e1
add client tests
asliayk Jan 16, 2025
bff0273
add client tests
asliayk Jan 16, 2025
bcf535a
Merge branch 'develop' into feature/communication/forward-share-message
asliayk Jan 16, 2025
960873a
fix hover color
asliayk Jan 17, 2025
7db29bc
resolve conflicts
asliayk Jan 20, 2025
e1dc800
fix eslint problems
asliayk Jan 20, 2025
36d436e
fix tests
asliayk Jan 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ public Boolean doesResolvePost() {
return resolvesPost;
}

@Column(name = "has_forwarded_messages")
private boolean hasForwardedMessages;

public boolean getHasForwardedMessages() {
return hasForwardedMessages;
}

public void setHasForwardedMessages(boolean hasForwardedMessages) {
this.hasForwardedMessages = hasForwardedMessages;
}

public void setResolvesPost(Boolean resolvesPost) {
this.resolvesPost = resolvesPost;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package de.tum.cit.aet.artemis.communication.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Enumerated;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotNull;

import org.hibernate.annotations.Check;

import com.fasterxml.jackson.annotation.JsonIncludeProperties;

import de.tum.cit.aet.artemis.core.domain.DomainObject;

@Entity
@Table(name = "forwarded_message")
@Check(constraints = "((destination_post_id IS NOT NULL AND destination_answer_id IS NULL) OR (destination_post_id IS NULL AND destination_answer_id IS NOT NULL))")
public class ForwardedMessage extends DomainObject {

@Column(name = "source_id", nullable = false)
private long sourceId;

@NotNull
@Enumerated
@Column(name = "source_type", nullable = false)
private PostingType sourceType;
asliayk marked this conversation as resolved.
Show resolved Hide resolved

@ManyToOne
@JoinColumn(name = "destination_post_id")
@JsonIncludeProperties({ "id" })
private Post destinationPost;

@ManyToOne
@JoinColumn(name = "destination_answer_id")
@JsonIncludeProperties({ "id" })
private AnswerPost destinationAnswerPost;

public ForwardedMessage() {
}

public ForwardedMessage(Long sourceId, PostingType sourceType, Post destinationPost, AnswerPost destinationAnswerPost) {
if (sourceId == null) {
throw new IllegalArgumentException("sourceId cannot be null");
}
if (sourceType == null) {
throw new IllegalArgumentException("sourceType cannot be null");
}
if ((destinationPost == null && destinationAnswerPost == null) || (destinationPost != null && destinationAnswerPost != null)) {
throw new IllegalArgumentException("Exactly one destination must be non-null");
}
this.sourceId = sourceId;
this.sourceType = sourceType;
this.destinationPost = destinationPost;
this.destinationAnswerPost = destinationAnswerPost;
}

public long getSourceId() {
return sourceId;
}

public void setSourceId(long sourceId) {
this.sourceId = sourceId;
}

public PostingType getSourceType() {
return sourceType;
}

public void setSourceType(PostingType sourceType) {
if (sourceType == null) {
throw new IllegalArgumentException("sourceType cannot be null");
}
this.sourceType = sourceType;
}

public Post getDestinationPost() {
return destinationPost;
}

public void setDestinationPost(Post post) {
if (post != null && this.destinationAnswerPost != null) {
throw new IllegalStateException("Cannot set both destination post and answer post");
}
this.destinationPost = post;
}

public AnswerPost getDestinationAnswerPost() {
return destinationAnswerPost;
}

public void setDestinationAnswerPost(AnswerPost answerPost) {
if (answerPost != null && this.destinationPost != null) {
throw new IllegalStateException("Cannot set both destination post and answer post");
}
this.destinationAnswerPost = answerPost;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ public class Post extends Posting {
@Transient
private boolean isSaved = false;

@Column(name = "has_forwarded_messages")
private boolean hasForwardedMessages;

public Post() {
}

Expand All @@ -124,6 +127,14 @@ public void setTitle(String title) {
this.title = title;
}

public boolean getHasForwardedMessages() {
return hasForwardedMessages;
}

public void setHasForwardedMessages(boolean hasForwardedMessages) {
this.hasForwardedMessages = hasForwardedMessages;
}

public Boolean isVisibleForStudents() {
return visibleForStudents;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package de.tum.cit.aet.artemis.communication.dto;

import java.util.Optional;

import com.fasterxml.jackson.annotation.JsonInclude;

import de.tum.cit.aet.artemis.communication.domain.AnswerPost;
import de.tum.cit.aet.artemis.communication.domain.ForwardedMessage;
import de.tum.cit.aet.artemis.communication.domain.Post;
import de.tum.cit.aet.artemis.communication.domain.PostingType;

/**
* Data Transfer Object for ForwardedMessage.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record ForwardedMessageDTO(Long id, Long sourceId, PostingType sourceType, Long destinationPostId, Long destinationAnswerPostId) {

/**
* Constructs a ForwardedMessageDTO from a ForwardedMessage entity.
*
* @param message the ForwardedMessage entity
*/
public ForwardedMessageDTO(ForwardedMessage message) {
this(message.getId(), message.getSourceId(), message.getSourceType(), Optional.ofNullable(message.getDestinationPost()).map(Post::getId).orElse(null),
Optional.ofNullable(message.getDestinationAnswerPost()).map(AnswerPost::getId).orElse(null));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package de.tum.cit.aet.artemis.communication.dto;

import java.util.Set;

import com.fasterxml.jackson.annotation.JsonInclude;

/**
* Data Transfer Object for grouping Forwarded Messages by ID.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record ForwardedMessagesGroupDTO(Long id, Set<ForwardedMessageDTO> messages) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.tum.cit.aet.artemis.communication.repository;

import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;

import java.util.Set;

import org.springframework.context.annotation.Profile;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import de.tum.cit.aet.artemis.communication.domain.ForwardedMessage;
import de.tum.cit.aet.artemis.core.repository.base.ArtemisJpaRepository;

@Profile(PROFILE_CORE)
@Repository
public interface ForwardedMessageRepository extends ArtemisJpaRepository<ForwardedMessage, Long> {

@Query("SELECT fm FROM ForwardedMessage fm WHERE fm.destinationPost.id IN :destinationPostIds")
Set<ForwardedMessage> findAllByDestinationPostIds(@Param("destinationPostIds") Set<Long> destinationPostIds);

@Query("SELECT fm FROM ForwardedMessage fm WHERE fm.destinationAnswerPost.id IN :destinationAnswerPostIds")
Set<ForwardedMessage> findAllByDestinationAnswerPostIds(@Param("destinationAnswerPostIds") Set<Long> destinationAnswerPostIds);

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -230,6 +231,10 @@ public AnswerPost findById(Long answerMessageId) {
return answerPostRepository.findAnswerMessageByIdElseThrow(answerMessageId);
}

public List<AnswerPost> findByIdIn(List<Long> answerMessageIds) {
return answerPostRepository.findByIdIn(answerMessageIds);
}
asliayk marked this conversation as resolved.
Show resolved Hide resolved

/**
* Checks if the requesting user is authorized in the course context,
* i.e. user has to be the author of original message associated with the answer message or at least teaching assistant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static de.tum.cit.aet.artemis.core.config.Constants.PROFILE_CORE;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -40,6 +41,7 @@
import de.tum.cit.aet.artemis.communication.dto.PostDTO;
import de.tum.cit.aet.artemis.communication.repository.ConversationMessageRepository;
import de.tum.cit.aet.artemis.communication.repository.ConversationParticipantRepository;
import de.tum.cit.aet.artemis.communication.repository.PostRepository;
import de.tum.cit.aet.artemis.communication.repository.SavedPostRepository;
import de.tum.cit.aet.artemis.communication.repository.SingleUserNotificationRepository;
import de.tum.cit.aet.artemis.communication.service.conversation.ConversationService;
Expand Down Expand Up @@ -76,11 +78,13 @@ public class ConversationMessagingService extends PostingService {

private final SingleUserNotificationRepository singleUserNotificationRepository;

private final PostRepository postRepository;

protected ConversationMessagingService(CourseRepository courseRepository, ExerciseRepository exerciseRepository, LectureRepository lectureRepository,
ConversationMessageRepository conversationMessageRepository, AuthorizationCheckService authorizationCheckService, WebsocketMessagingService websocketMessagingService,
UserRepository userRepository, ConversationService conversationService, ConversationParticipantRepository conversationParticipantRepository,
ConversationNotificationService conversationNotificationService, ChannelAuthorizationService channelAuthorizationService, SavedPostRepository savedPostRepository,
GroupNotificationService groupNotificationService, SingleUserNotificationRepository singleUserNotificationRepository) {
GroupNotificationService groupNotificationService, SingleUserNotificationRepository singleUserNotificationRepository, PostRepository postRepository) {
super(courseRepository, userRepository, exerciseRepository, lectureRepository, authorizationCheckService, websocketMessagingService, conversationParticipantRepository,
savedPostRepository);
this.conversationService = conversationService;
Expand All @@ -89,6 +93,7 @@ protected ConversationMessagingService(CourseRepository courseRepository, Exerci
this.channelAuthorizationService = channelAuthorizationService;
this.groupNotificationService = groupNotificationService;
this.singleUserNotificationRepository = singleUserNotificationRepository;
this.postRepository = postRepository;
}

/**
Expand Down Expand Up @@ -409,6 +414,10 @@ public Post changeDisplayPriority(Long courseId, Long postId, DisplayPriority di
return updatedMessage;
}

public List<Post> getMessageByIds(List<Long> sourcePostIds) {
return postRepository.findByIdIn(sourcePostIds);
}
asliayk marked this conversation as resolved.
Show resolved Hide resolved

private Conversation mayUpdateOrDeleteMessageElseThrow(Post existingMessagePost, User user) {
if (existingMessagePost.getConversation() == null) {
throw new BadRequestAlertException("The post does not belong to a conversation", METIS_POST_ENTITY_NAME, "conversationnotset");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import de.tum.cit.aet.artemis.communication.domain.AnswerPost;
Expand Down Expand Up @@ -92,4 +95,11 @@ public ResponseEntity<Void> deleteAnswerMessage(@PathVariable Long courseId, @Pa
// deletion of answerMessages should not trigger alert
return ResponseEntity.ok().build();
}

@GetMapping("courses/{courseId}/answer-messages/source-answer-posts")
@EnforceAtLeastStudent
public ResponseEntity<List<AnswerPost>> getSourceAnswerPostsByIds(@PathVariable Long courseId, @RequestParam List<Long> answerPostIds) {
List<AnswerPost> answerPosts = answerMessageService.findByIdIn(answerPostIds);
return ResponseEntity.ok().body(answerPosts);
}
asliayk marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,19 @@ public ResponseEntity<Post> updateDisplayPriority(@PathVariable Long courseId, @
Post postWithUpdatedDisplayPriority = conversationMessagingService.changeDisplayPriority(courseId, postId, displayPriority);
return ResponseEntity.ok().body(postWithUpdatedDisplayPriority);
}

/**
* GET /courses/{courseId}/messages/source-posts : Retrieve posts by their IDs
*
* @param courseId id of the course the posts belong to
* @param postIds list of IDs of the posts to retrieve
* @return ResponseEntity with status 200 (OK) containing the list of posts in the response body,
* or with status 400 (Bad Request) if the checks on user, course or post validity fail
*/
@GetMapping("courses/{courseId}/messages/source-posts")
@EnforceAtLeastStudent
public ResponseEntity<List<Post>> getSourcePostsByIds(@PathVariable Long courseId, @RequestParam List<Long> postIds) {
List<Post> posts = conversationMessagingService.getMessageByIds(postIds);
return ResponseEntity.ok().body(posts);
}
}
Loading
Loading