Skip to content

Feature/polling in chat#236

Open
Navila48 wants to merge 6 commits into
Vault-Web:mainfrom
Navila48:feature/polling_in_chat
Open

Feature/polling in chat#236
Navila48 wants to merge 6 commits into
Vault-Web:mainfrom
Navila48:feature/polling_in_chat

Conversation

@Navila48

Copy link
Copy Markdown
Contributor

Summary

Added necessary changes for the backend part

  • Added separate controller for Group and Private chat and have a common or shared service

Linked issue

218

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the backend chat system so polls can be created and consumed as first-class chat elements in both group chats and private chats, by persisting poll creation as ChatMessage entries and exposing dedicated poll endpoints.

Changes:

  • Generalize poll ownership via PollContext and extend Poll to optionally belong to either a Group or a PrivateChat.
  • Introduce MessageType and extend ChatMessage/ChatMessageDto so messages can represent either encrypted text or an embedded poll payload.
  • Add a private-chat poll controller and refactor existing chat/poll controllers to use shared PollService / ChatService DTO mapping.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
backend/src/main/java/vaultWeb/services/PollService.java Adds private-chat poll support and persists poll creation into the chat message stream.
backend/src/main/java/vaultWeb/services/ChatService.java Adds messageType handling and DTO conversion for TEXT vs POLL messages.
backend/src/main/java/vaultWeb/repositories/PollRepository.java Adds query method to fetch polls by private chat.
backend/src/main/java/vaultWeb/models/PollContext.java New record to model poll ownership context (group vs private chat).
backend/src/main/java/vaultWeb/models/Poll.java Extends poll entity to optionally reference a private chat.
backend/src/main/java/vaultWeb/models/enums/MessageType.java Introduces message type enum (TEXT, POLL).
backend/src/main/java/vaultWeb/models/ChatMessage.java Adds messageType and optional poll reference on chat messages.
backend/src/main/java/vaultWeb/dtos/ChatMessageDto.java Adds messageType and poll fields for message stream integration.
backend/src/main/java/vaultWeb/controllers/PrivateChatPollController.java New REST controller for polls inside private chats.
backend/src/main/java/vaultWeb/controllers/PrivateChatController.java Refactors message DTO mapping to use ChatService.toDto(...).
backend/src/main/java/vaultWeb/controllers/GroupController.java No functional changes; appears to be formatting-only adjustments.
backend/src/main/java/vaultWeb/controllers/GroupChatPollController.java Updates group poll endpoints to use PollContext + shared service methods.
backend/src/main/java/vaultWeb/controllers/ChatController.java Refactors WebSocket responses to use ChatService.toDto(...).
Comments suppressed due to low confidence (1)

backend/src/main/java/vaultWeb/controllers/GroupChatPollController.java:122

  • groupId is part of the URL (/groups/{groupId}/polls/...) but is not bound/used in vote/update/delete endpoints anymore, so the API no longer verifies that pollId actually belongs to the {groupId} in the path. This is a regression from the previous version and can lead to confusing/incorrect URLs being accepted.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +87 to +96
if (dto.getMessageType() == MessageType.TEXT) {
if (dto.getE2eePayload() == null
|| dto.getE2eePayload().isBlank()
|| dto.getSenderDeviceId() == null
|| dto.getSenderDeviceId().isBlank()) {
throw new IllegalArgumentException(
"Missing end-to-end encrypted payload or sender device ID");
}
}

Comment on lines +136 to +155
dto.setMessageType(message.getMessageType());

if (message.getGroup() != null) {

dto.setGroupId(message.getGroup().getId());
}

if (message.getPrivateChat() != null) {

dto.setPrivateChatId(message.getPrivateChat().getId());
}

if (message.getMessageType() == MessageType.TEXT) {

dto.setE2eePayload(message.getE2eePayload());

} else if (message.getMessageType() == MessageType.POLL) {

dto.setPoll(pollService.toResponseDto(message.getPoll()));
}
Comment on lines +129 to +139
public List<Poll> getPollsByPrivateChat(Long privateChatId, User currentUser) {
PrivateChat privateChat =
privateChatRepository
.findById(privateChatId)
.orElseThrow(
() ->
new GroupNotFoundException(
"Private chat with id " + privateChatId + " not found"));

return pollRepository.findByPrivateChatId(privateChatId);
}
Comment on lines +276 to +280
if (!poll.getAuthor().getId().equals(user.getId())) {
throw new UnauthorizedException("Only the author can delete the poll");
}

pollRepository.delete(poll);
Comment on lines +4 to +8
public PollContext {
if (isGroup() && isPrivateChat()) {
throw new IllegalArgumentException("PollConext must contain either group or private chat");
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isGroup() and isPrivateChat() already checking the null, basically do the same thing. I will only fix the typo here for the exception msg

import vaultWeb.services.auth.AuthService;

@RestController
@RequestMapping("/private-chats/{privateChatId}/polls")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am planning to have a base from the configuration. Can be a future task. Okay?

Comment on lines +84 to +87
public ResponseEntity<Void> vote(@PathVariable Long pollId, @PathVariable Long optionId) {
User currentUser = authService.getCurrentUser();
pollService.vote(pollId, optionId, currentUser);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
privateChatRepository
.findById(dto.getPrivateChatId())
.orElseThrow(() -> new PrivateChatNotFoundException("Private chat not found"));
message.setMessageType(dto.getMessageType());
* specified group/private chat does not exist.
* @throws IllegalArgumentException if encrypted payload metadata is missing.
*/
public ChatMessage saveMessage(ChatMessageDto dto) {

@DenizAltunkapan DenizAltunkapan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Navila48 thanks a lot for this! Splitting the polls into separate group and private chat controllers with a shared service looks like a clean approach.

Before I can approve, could you please fix the failing workflows? The Spotless check is red because the files were rewritten with CRLF line endings — that's also why the diff shows every file fully deleted and re-added instead of just the real changes. Running mvn spotless:apply and normalizing the line endings back to LF should fix both the CI and the noisy diff.

Also please have a look at Copilot's comments on the message type handling and the private chat poll access — those are worth addressing too. Left a couple of small notes below.

} else if (pollContext.isPrivateChat()) {
PrivateChat privateChat = pollContext.privateChat();
boolean isChatParticipant =
(privateChat.getUser1().getId().equals(user.getId()))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small thing: getUser1() / getUser2() could be null here, so this would throw a NullPointerException instead of the intended UnauthorizedException. Could you add a null check like we do in getAuthorizedPrivateChat() in PrivateChatController?

public record PollContext(Group group, PrivateChat privateChat) {
public PollContext {
if (isGroup() && isPrivateChat()) {
throw new IllegalArgumentException("PollConext must contain either group or private chat");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny typo: "PollConext" -> "PollContext" : )

@Navila48

Navila48 commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@Navila48 thanks a lot for this! Splitting the polls into separate group and private chat controllers with a shared service looks like a clean approach.

Before I can approve, could you please fix the failing workflows? The Spotless check is red because the files were rewritten with CRLF line endings — that's also why the diff shows every file fully deleted and re-added instead of just the real changes. Running mvn spotless:apply and normalizing the line endings back to LF should fix both the CI and the noisy diff.

Also please have a look at Copilot's comments on the message type handling and the private chat poll access — those are worth addressing too. Left a couple of small notes below.

Hi,
@DenizAltunkapan This is really strange because before committing I run the spotless:apply command as I used to do for all of my PR. After your comment, I have checked again and one thing can be the reason that recently I have changed my IDE from Intellij Ultimate version 25.* (license expired now) to Intellij Idea 2026 version and I noticed some change in the settings and I fixed those settings like this:

image

After that I have added the follwing changes on .gitAttributes file

# Normalize ALL text files in repo to LF
* text=auto eol=lf

# Windows scripts
*.cmd text eol=crlf
*.bat text eol=crlf

# Maven wrapper (important on Windows/Linux mix)
mvnw text eol=lf
mvnw.cmd text eol=crlf

# Java explicitly LF (optional but safe)
*.java text eol=lf

Then run the command : git add --renormalize .

Then after restarting the IDE, I again apply spotless and unfortunately the same issue persist like it detects the whole file as modified, so it deleted(red marked) and rewritted(grren marked) it.

image

I have tried all the possible options to fix this but no luck.

@DenizAltunkapan

Copy link
Copy Markdown
Member

Hey @Navila48, thanks for digging into this! 🙏

Your likely problem: the repo has no .gitattributes and Spotless doesn't pin line endings, so it falls back to platform native — which on your new IntelliJ 2026 / Windows setup means CRLF. So spotless:apply keeps rewriting the files back to CRLF, and since your earlier commits already stored CRLF blobs, the diff shows every file fully deleted + re-added. git add --renormalize alone can't win against that.

The reliable fix is to pin LF so it no longer depends on anyone's OS/IDE. In backend/pom.xml, inside the Spotless <configuration>:

<configuration>
    <lineEndings>UNIX</lineEndings>
    <java>
    ...

Then clean up the branch:

git config core.autocrlf false
git config core.eol lf
git add .gitattributes && git commit -m "chore: add .gitattributes (LF)"
git add --renormalize .
git commit -m "chore: normalize line endings to LF"
mvn -pl backend spotless:apply && git commit -am "style: spotless"

To verify it's clean (should print nothing):

git ls-files --eol backend/src | grep crlf

After that the diff should collapse down to your real changes. 👍

@Navila48

Copy link
Copy Markdown
Contributor Author

Hey @Navila48, thanks for digging into this! 🙏

Your likely problem: the repo has no .gitattributes and Spotless doesn't pin line endings, so it falls back to platform native — which on your new IntelliJ 2026 / Windows setup means CRLF. So spotless:apply keeps rewriting the files back to CRLF, and since your earlier commits already stored CRLF blobs, the diff shows every file fully deleted + re-added. git add --renormalize alone can't win against that.

The reliable fix is to pin LF so it no longer depends on anyone's OS/IDE. In backend/pom.xml, inside the Spotless <configuration>:

<configuration>
    <lineEndings>UNIX</lineEndings>
    <java>
    ...

Then clean up the branch:

git config core.autocrlf false
git config core.eol lf
git add .gitattributes && git commit -m "chore: add .gitattributes (LF)"
git add --renormalize .
git commit -m "chore: normalize line endings to LF"
mvn -pl backend spotless:apply && git commit -am "style: spotless"

To verify it's clean (should print nothing):

git ls-files --eol backend/src | grep crlf

After that the diff should collapse down to your real changes. 👍

Thanks a lot. You are the best 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants