Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added backend/backend-error.txt
Binary file not shown.
24 changes: 23 additions & 1 deletion backend/src/main/java/com/project/model/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.time.Instant;

@Entity
@Table(name = "messages")
@Table(name = "messages", indexes = @Index(name = "idx_messages_room_client_id", columnList = "room_id,client_message_id"))
@EntityListeners(AuditingEntityListener.class)
public class Message {

Expand All @@ -33,6 +33,12 @@ public class Message {
@Column(name = "user_image", columnDefinition = "TEXT")
private String userImage;

@Column(name = "payload", columnDefinition = "TEXT")
private String payload;

@Column(name = "client_message_id")
private String clientMessageId;

@CreatedDate
@Column(name = "created_at", updatable = false, columnDefinition = "TIMESTAMP")
private Instant createdAt;
Expand Down Expand Up @@ -100,6 +106,22 @@ public void setUserImage(String userImage) {
this.userImage = userImage;
}

public String getPayload() {
return payload;
}

public void setPayload(String payload) {
this.payload = payload;
}

public String getClientMessageId() {
return clientMessageId;
}

public void setClientMessageId(String clientMessageId) {
this.clientMessageId = clientMessageId;
}

public Instant getCreatedAt() {
return createdAt;
}
Expand Down
70 changes: 70 additions & 0 deletions backend/src/main/java/com/project/model/PinnedNote.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.project.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;

import java.time.Instant;

@Entity
@Table(
name = "pinned_notes",
indexes = @Index(name = "idx_pinned_notes_room_pinned", columnList = "room_id,pinned_at"),
uniqueConstraints = @UniqueConstraint(
name = "uk_pinned_notes_room_note",
columnNames = {"room_id", "note_id"}
)
)
public class PinnedNote {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private String id;

@Column(name = "room_id", nullable = false)
private String roomId;

@Column(name = "note_id", nullable = false)
private String noteId;

@Column(name = "payload", nullable = false, columnDefinition = "TEXT")
private String payload;

@Column(name = "pinned_at", nullable = false)
private Instant pinnedAt;

public PinnedNote() {
}

public PinnedNote(String roomId, String noteId, String payload, Instant pinnedAt) {
this.roomId = roomId;
this.noteId = noteId;
this.payload = payload;
this.pinnedAt = pinnedAt;
}

public String getId() {
return id;
}

public String getRoomId() {
return roomId;
}

public String getNoteId() {
return noteId;
}

public String getPayload() {
return payload;
}

public Instant getPinnedAt() {
return pinnedAt;
}
}
11 changes: 11 additions & 0 deletions backend/src/main/java/com/project/model/Room.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public class Room {
@Column(name = "is_private")
private boolean isPrivate = false;

@Column(name = "is_closed", nullable = false, columnDefinition = "boolean not null default false")
private boolean isClosed = false;

@Column(name = "password")
private String password;

Expand Down Expand Up @@ -80,6 +83,14 @@ public void setPrivate(boolean aPrivate) {
isPrivate = aPrivate;
}

public boolean isClosed() {
return isClosed;
}

public void setClosed(boolean closed) {
isClosed = closed;
}

public String getPassword() {
return password;
}
Expand Down
34 changes: 34 additions & 0 deletions backend/src/main/java/com/project/model/RoomMediaState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.project.model;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "room_media_state")
public class RoomMediaState {

@Id
@Column(name = "room_id", nullable = false)
private String roomId;

@Column(name = "payload", nullable = false, columnDefinition = "TEXT")
private String payload;

public RoomMediaState() {
}

public RoomMediaState(String roomId, String payload) {
this.roomId = roomId;
this.payload = payload;
}

public String getRoomId() {
return roomId;
}

public String getPayload() {
return payload;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;

@Repository
public interface MessageRepository extends JpaRepository<Message, String> {
List<Message> findByRoomIdOrderByCreatedAtAsc(String roomId);
List<Message> findTop500ByRoomIdOrderByCreatedAtDesc(String roomId);
Optional<Message> findFirstByRoomIdAndClientMessageId(String roomId, String clientMessageId);
List<Message> findTop500ByRoomIdAndUserIdOrderByCreatedAtDesc(String roomId, String userId);
void deleteByRoomId(String roomId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.project.repository;

import com.project.model.PinnedNote;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface PinnedNoteRepository extends JpaRepository<PinnedNote, String> {
List<PinnedNote> findByRoomIdOrderByPinnedAtDesc(String roomId);
void deleteByRoomIdAndNoteId(String roomId, String noteId);
void deleteByRoomId(String roomId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.project.repository;

import com.project.model.RoomMediaState;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface RoomMediaStateRepository extends JpaRepository<RoomMediaState, String> {
}
3 changes: 3 additions & 0 deletions backend/src/main/java/com/project/service/RoomService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
public interface RoomService {
RoomResponse getRoom(String roomId);
RoomResponse createRoom(RoomCreateRequest request);
boolean prepareRoomForJoin(String roomId, String ownerId);
boolean isRoomCreator(String roomId, String userId);
boolean closeRoom(String roomId, String ownerId);
}
76 changes: 75 additions & 1 deletion backend/src/main/java/com/project/service/RoomServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,34 @@
import com.project.exception.BadRequestException;
import com.project.exception.ResourceNotFoundException;
import com.project.model.Room;
import com.project.repository.MessageRepository;
import com.project.repository.PinnedNoteRepository;
import com.project.repository.RoomRepository;
import com.project.repository.RoomMediaStateRepository;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Optional;

@Service
public class RoomServiceImpl implements RoomService {

private final RoomRepository roomRepository;
private final PasswordEncoder passwordEncoder;
private final MessageRepository messageRepository;
private final PinnedNoteRepository pinnedNoteRepository;
private final RoomMediaStateRepository roomMediaStateRepository;

public RoomServiceImpl(RoomRepository roomRepository, PasswordEncoder passwordEncoder) {
public RoomServiceImpl(RoomRepository roomRepository, PasswordEncoder passwordEncoder,
MessageRepository messageRepository, PinnedNoteRepository pinnedNoteRepository,
RoomMediaStateRepository roomMediaStateRepository) {
this.roomRepository = roomRepository;
this.passwordEncoder = passwordEncoder;
this.messageRepository = messageRepository;
this.pinnedNoteRepository = pinnedNoteRepository;
this.roomMediaStateRepository = roomMediaStateRepository;
}

@Override
Expand All @@ -31,9 +44,70 @@ public RoomResponse getRoom(String roomId) {
Room room = roomRepository.findByRoomId(roomId.trim())
.orElseThrow(() -> new ResourceNotFoundException("Room not found"));

if (room.isClosed()) {
throw new ResourceNotFoundException("Room not found");
}

return toResponse(room);
}

@Override
@Transactional
public synchronized boolean prepareRoomForJoin(String roomId, String ownerId) {
if (roomId == null || roomId.isBlank() || ownerId == null || ownerId.isBlank()) {
return false;
}

String normalizedRoomId = roomId.trim();
return roomRepository.findByRoomId(normalizedRoomId)
.map(room -> !room.isClosed())
.orElseGet(() -> {
Room room = new Room(normalizedRoomId, ownerId.trim(), false, null);
Instant now = Instant.now();
room.setCreatedAt(now);
room.setUpdatedAt(now);
roomRepository.save(room);
return true;
});
}

@Override
public boolean isRoomCreator(String roomId, String userId) {
if (roomId == null || roomId.isBlank() || userId == null || userId.isBlank()) {
return false;
}

return roomRepository.findByRoomId(roomId.trim())
.filter(room -> !room.isClosed())
.map(room -> userId.trim().equals(room.getOwnerId()))
.orElse(false);
}

@Override
@Transactional
public synchronized boolean closeRoom(String roomId, String ownerId) {
if (roomId == null || roomId.isBlank() || ownerId == null || ownerId.isBlank()) {
return false;
}

Optional<Room> roomOptional = roomRepository.findByRoomId(roomId.trim());
if (roomOptional.isEmpty()) {
return false;
}

Room room = roomOptional.get();
if (room.isClosed() || !ownerId.trim().equals(room.getOwnerId())) {
return false;
}

room.setClosed(true);
roomRepository.save(room);
messageRepository.deleteByRoomId(room.getRoomId());
pinnedNoteRepository.deleteByRoomId(room.getRoomId());
roomMediaStateRepository.deleteById(room.getRoomId());
return true;
}

@Override
public RoomResponse createRoom(RoomCreateRequest request) {
if (request.getRoomId() == null || request.getRoomId().isBlank()) {
Expand Down
Loading
Loading