Skip to content

Commit

Permalink
Merge pull request #140 from RitehWebTeam/websocket-image-upload
Browse files Browse the repository at this point in the history
Web - Chat image upload
  • Loading branch information
andrezz-b authored Jun 7, 2024
2 parents 744304b + 62e21c6 commit 69bf873
Show file tree
Hide file tree
Showing 47 changed files with 611 additions and 308 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
indent_size = 2
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class MyController {
@GetMapping("/")
public Map<String, String> getMessage() {
Map<String, String> response = new HashMap<>();
response.put("message", "Different message");
response.put("message", "Rimatch backend running!");
return response;
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,94 @@
package com.rimatch.rimatchbackend.controller;

import com.rimatch.rimatchbackend.model.Match;
import com.rimatch.rimatchbackend.model.Message;
import com.rimatch.rimatchbackend.model.User;
import com.rimatch.rimatchbackend.repository.MatchRepository;
import com.rimatch.rimatchbackend.repository.MessageRepository;
import com.rimatch.rimatchbackend.service.S3Service;
import com.rimatch.rimatchbackend.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.Optional;

@RestController
@RequestMapping("api/messages")
public class MessageController {

@Autowired MessageRepository messageRepository;
@Autowired private MessageRepository messageRepository;

@Autowired
private MongoTemplate mongoTemplate;
@Autowired private MatchRepository matchRepository;

@Autowired private UserService userService;

@Autowired private S3Service s3Service;

@PostMapping("/upload-image")
public ResponseEntity<?> uploadImage(@RequestBody MultipartFile photo,String chatId,HttpServletRequest request) throws Exception {
String authToken = request.getHeader("Authorization");
User user = userService.getUserByToken(authToken);
Optional<Match> match = matchRepository.findById(chatId);
if(match.isPresent()){
if(!userHasAccessToChat(match.get(),user.getId())){
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}else{
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return ResponseEntity.ok(s3Service.uploadImage(photo,chatId,"chats"));
}

/*@PostMapping("/upload-voice")
public ResponseEntity<?> uploadVoice(@RequestBody MultipartFile audio,String chatId,HttpServletRequest request) throws Exception {
String authToken = request.getHeader("Authorization");
Optional<Message> message = messageRepository.findById(chatId);
if(message.isPresent()){
if(!userHasAccessToChat(message.get(),authToken)){
ResponseEntity.status(400);
}
}
return ResponseEntity.ok(s3Service.uploadAudioFile(audio,chatId,"chats"));
}*/

@GetMapping("/{chatId}")
public Page<Message> getMessagesFromId(@PathVariable String chatId,
@RequestParam(required = false) Integer page,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String messageId) {
@RequestParam(required = false) String messageId,
HttpServletRequest request) {
String authToken = request.getHeader("Authorization");
if(page == null) page = 0;
if(pageSize == null) pageSize = 5;
Pageable p = PageRequest.of(page,pageSize);
if (messageId != null) {

Optional<Message> m = messageRepository.findById(messageId);
if(m.isPresent()){

//if(!userHasAccessToChat(m.get(),authToken)) return Page.empty(); //should be handled better but due to time left like this
return messageRepository.findByChatIdAndTimestampBeforeOrderByTimestampDesc(chatId,m.get().getTimestamp(), p);
}else{
return null;
}
}
return messageRepository.findByChatIdOrderByTimestampDesc(chatId,p);
}

private boolean userHasAccessToChat(Match match,String userId){
if(match.getFirstUserId().equals(userId) || match.getSecondUserId().equals(userId)){
if(match.isAccepted() && match.isFinished()){
return true;
}
return false;
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ public ResponseEntity<List<DisplayUserDto>> getAllBlockedUsers(HttpServletReques
}

@PostMapping("/me/setup")
public ResponseEntity<?> setupUser(@Valid @RequestPart("data") SetupDto setupDto, @RequestPart("photo") MultipartFile file, HttpServletRequest request) throws Exception {
public ResponseEntity<?> setupUser(@RequestParam("photo") MultipartFile file,@Valid @RequestPart("data") SetupDto setupDto, HttpServletRequest request) throws Exception {
String authToken = request.getHeader("Authorization");
User user = userService.getUserByToken(authToken);
System.out.println(file.getContentType());
if(user.isActive()){
Map<String,String> map = new HashMap<>();
map.put("message","Setup was already done!");
Expand All @@ -91,7 +92,7 @@ public ResponseEntity<?> setupUser(@Valid @RequestPart("data") SetupDto setupDto
if(setupDto.getPreferences().getAgeGroupMax() < setupDto.getPreferences().getAgeGroupMin()){
return ResponseEntity.badRequest().body(createErrorMap("ageGroupMax must be higher or equal to ageGroupMin"));
}
String url = s3Service.uploadFile(file);
String url = s3Service.uploadImage(file,user.getId(),"users");
setupDto.setProfileImageUrl(url);
user = userService.finishUserSetup(user,setupDto);
return ResponseEntity.ok(user);
Expand All @@ -117,7 +118,7 @@ public ResponseEntity<?> updatePreferences(@Valid @RequestBody PreferencesUpdate
return new ResponseEntity<>(HttpStatus.OK);
}

@PostMapping("/me/profilePicture")
@PostMapping("/me/profile-picture")
public ResponseEntity<?> changeProfilePicure(@RequestBody MultipartFile photo,HttpServletRequest request){
if (!photo.getContentType().startsWith("image/")) {
return ResponseEntity.badRequest().body(createErrorMap("File "+photo.getOriginalFilename()+" is not an image so it can't be used!"));
Expand All @@ -126,21 +127,21 @@ public ResponseEntity<?> changeProfilePicure(@RequestBody MultipartFile photo,Ht
User user = userService.getUserByToken(authToken);
String newProfileImageUrl;
try {
newProfileImageUrl = s3Service.uploadFile(photo);
newProfileImageUrl = s3Service.uploadImage(photo,user.getId(),"users");
} catch (Exception e) {
throw new RuntimeException(e);
}

String oldProfileImageUrl = user.getProfileImageUrl();
s3Service.removeImage(oldProfileImageUrl);

UserUpdateDTO update = new UserUpdateDTO();
update.setProfileImageUrl(newProfileImageUrl);
userService.updateUser(user,update);
return new ResponseEntity<>(HttpStatus.OK);
}

@PostMapping("/me/addPhotos")
@PostMapping("/me/add-photos")
public ResponseEntity<?> uploadPhotos(@RequestBody List<MultipartFile> photos,HttpServletRequest request) throws Exception {
for (MultipartFile photo : photos) {
if (!photo.getContentType().startsWith("image/")) {
Expand All @@ -151,14 +152,14 @@ public ResponseEntity<?> uploadPhotos(@RequestBody List<MultipartFile> photos,Ht
User user = userService.getUserByToken(authToken);
List<String> urls = new ArrayList<>();
for (MultipartFile photo : photos) {
String url = s3Service.uploadFile(photo);
String url = s3Service.uploadImage(photo,user.getId(),"users");
urls.add(url);
}
userService.addPhotos(user,urls);
return new ResponseEntity<>(HttpStatus.OK);
}

@PostMapping("/me/removePhotos")
@PostMapping("/me/remove-photos")
public ResponseEntity<?> removePhotos(@RequestBody List<String> urls, HttpServletRequest request){
String authToken = request.getHeader("Authorization");
User user = userService.getUserByToken(authToken);
Expand Down Expand Up @@ -200,4 +201,4 @@ private Map<String, String> createErrorMap(String errorMessage) {
return errorMap;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import com.rimatch.rimatchbackend.dto.MessageDTO;
import com.rimatch.rimatchbackend.model.Match;
import com.rimatch.rimatchbackend.model.Message;
import com.rimatch.rimatchbackend.model.MessageType;
import com.rimatch.rimatchbackend.model.User;
import com.rimatch.rimatchbackend.repository.MatchRepository;
import com.rimatch.rimatchbackend.repository.MessageRepository;
import com.rimatch.rimatchbackend.service.UserService;
import com.rimatch.rimatchbackend.util.JWTUtils;
import io.jsonwebtoken.JwtException;
import jakarta.validation.constraints.Null;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
Expand Down Expand Up @@ -41,7 +44,7 @@ public class WebSocketController {
@Autowired
private MatchRepository matchRepository;

@MessageMapping("/sendMessage")
@MessageMapping("/send-message")
public void sendMessage(@Payload MessageDTO messageDTO, @Header("Authorization") String token) {
try {
User sender = userService.getUserByToken(token.substring(7));
Expand All @@ -53,8 +56,14 @@ public void sendMessage(@Payload MessageDTO messageDTO, @Header("Authorization")
if(m.get().isFinished() && !m.get().isAccepted()) return; //"blocked"

String receiverId = messageDTO.getReceiverId();
Message message = new Message(messageDTO.getChatId(),sender.getId(),receiverId);
message.setContent(messageDTO.getContent());
Message message = new Message(messageDTO.getChatId(),sender.getId(),receiverId,messageDTO.getMessageType(),messageDTO.getContent());
if(messageDTO.getMessageType() == MessageType.REPLY){
if(!messageDTO.getReplyId().isEmpty()){
message.setReplyId(message.getReplyId());
}else{
return;
}
}
messageRepository.save(message);
messagingTemplate.convertAndSend(receiverId+"/queue/messages", message);
} catch (JwtException | IllegalArgumentException ex) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.rimatch.rimatchbackend.dto;

import com.rimatch.rimatchbackend.model.MessageType;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;

Expand All @@ -11,6 +12,11 @@ public class MessageDTO {
@NotBlank
private String chatId;

@NotBlank
private MessageType messageType;

@NotBlank
private String content;

private String replyId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ public class Match {
private boolean accepted = false;

private boolean finished = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ public class Message {
@NotNull
private String receiverId;

@NotBlank
@NotNull
private MessageType messageType;

@NotNull
private String content;

private String replyId;

private Date timestamp = new Date();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.rimatch.rimatchbackend.model;

public enum MessageType {
TEXT,
IMAGE,
VOICE,
REPLY
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;

@Service
Expand All @@ -31,13 +32,31 @@ public S3Service(S3Client s3Client) {
this.s3Client = s3Client;
}

public String uploadFile(MultipartFile file) throws Exception {
public String uploadImage(MultipartFile file,String chatOrUserId,String folder) throws Exception {
String extension = file.getContentType();
if (Arrays.asList("image/jpg", "image/jpeg", "image/png").contains(extension)) {
return uploadFile(file,"/images/",folder+'/'+chatOrUserId);
}else{
throw new Exception("File must be jpg, jpeg or png");
}
}

public String uploadAudioFile(MultipartFile file,String chatId,String folder) throws Exception {
String extension = file.getContentType();
if (Arrays.asList("audio/wav", "audio/mpeg").contains(extension)) {
return uploadFile(file,"/audio/",folder+'/'+chatId);
}else{
throw new Exception("File must be jpg,jpeg or png");
}
}

public String uploadFile(MultipartFile file,String folder,String chatorUserId) throws Exception {
String fileName = generateFileName(file);
try {

PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(bucketName)
.key(fileName)
.key(chatorUserId+folder+fileName)
.acl(ObjectCannedACL.PUBLIC_READ)
.build();

Expand All @@ -47,7 +66,7 @@ public String uploadFile(MultipartFile file) throws Exception {
}
GetUrlRequest getUrlRequest = GetUrlRequest.builder()
.bucket(bucketName)
.key(fileName)
.key(chatorUserId+folder+fileName)
.build();

return s3Client.utilities().getUrl(getUrlRequest).toString();
Expand Down
9 changes: 9 additions & 0 deletions frontend/frontend.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
Loading

0 comments on commit 69bf873

Please sign in to comment.