Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/bounswe/bounswe2024group1
Browse files Browse the repository at this point in the history
…into 529-backend-implement-question-search-endpoint

# Conflicts:
#	backend/src/main/java/com/group1/programminglanguagesforum/Controllers/QuestionController.java
#	backend/src/main/java/com/group1/programminglanguagesforum/Services/QuestionService.java
  • Loading branch information
EnesBaserr committed Nov 23, 2024
2 parents f3199e8 + d839675 commit 71d5255
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws
.requestMatchers(HttpMethod.POST, API_BASE + "/**").authenticated()// Permit signin without authentication// All POSTs need authentication
.requestMatchers(HttpMethod.PUT, API_BASE + "/**").authenticated() // All PUTs need authentication
.requestMatchers(HttpMethod.DELETE, API_BASE + "/**").authenticated()// All DELETEs need authentication
.requestMatchers(HttpMethod.GET,API_BASE + EndpointConstants.QuestionEndpoints.QUESTION_ID).authenticated()
.requestMatchers(HttpMethod.GET, "/**").permitAll() // General GET requests, allow everything else
.anyRequest().authenticated()
.anyRequest().permitAll()
)
.anonymous(anonymous -> anonymous.disable())
.sessionManagement(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.group1.programminglanguagesforum.DTOs.Responses.CreateAnswerResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.ErrorResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.GenericApiResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.GetAnswersResponseDto;
import com.group1.programminglanguagesforum.Exceptions.UnauthorizedAccessException;
import com.group1.programminglanguagesforum.Services.AnswerService;
import com.group1.programminglanguagesforum.Util.ApiResponseBuilder;
Expand Down Expand Up @@ -65,5 +66,14 @@ public ResponseEntity<GenericApiResponse<String>> deleteAnswer(@PathVariable(val
return buildResponse(ApiResponseBuilder.buildErrorResponse(String.class, "An error occurred", 500, errorResponse), HttpStatus.INTERNAL_SERVER_ERROR);
}
}

@GetMapping(value=EndpointConstants.QuestionEndpoints.QUESTION_ANSWERS)
public ResponseEntity<GenericApiResponse<GetAnswersResponseDto>>getAnswersForQuestion(@PathVariable(value = "questionId") Long questionId) throws UnauthorizedAccessException {
GetAnswersResponseDto response = answerService.getAnswersForQuestion(questionId);
GenericApiResponse<GetAnswersResponseDto> apiResponse = GenericApiResponse.<GetAnswersResponseDto>builder()
.status(200)
.message("Answers retrieved successfully")
.data(response)
.build();
return buildResponse(apiResponse, HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,13 @@ public ResponseEntity<GenericApiResponse<GetQuestionDetailsResponseDto>> getQues
questionService.getQuestion(id));
return buildResponse(response, org.springframework.http.HttpStatus.OK);

} catch (UnauthorizedAccessException e) {
} catch (NoSuchElementException e) {
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<GetQuestionDetailsResponseDto> response = ApiResponseBuilder
.buildErrorResponse(GetQuestionDetailsResponseDto.class, e.getMessage(), 401, errorResponse);
return buildResponse(response, org.springframework.http.HttpStatus.UNAUTHORIZED);

GenericApiResponse<GetQuestionDetailsResponseDto> response = ApiResponseBuilder.buildErrorResponse(GetQuestionDetailsResponseDto.class, e.getMessage(), 404, errorResponse);
return buildResponse(response, org.springframework.http.HttpStatus.NOT_FOUND);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.group1.programminglanguagesforum.Constants.EndpointConstants;
import com.group1.programminglanguagesforum.DTOs.Responses.*;
import com.group1.programminglanguagesforum.Exceptions.ExceptionResponseHandler;
import com.group1.programminglanguagesforum.Exceptions.QuestionAlreadyVotedException;
import com.group1.programminglanguagesforum.Exceptions.UnauthorizedAccessException;
import com.group1.programminglanguagesforum.Services.VoteService;
import com.group1.programminglanguagesforum.Util.ApiResponseBuilder;
Expand Down Expand Up @@ -59,6 +60,19 @@ public ResponseEntity<GenericApiResponse<QuestionUpvoteResponseDto>> upvoteQuest
);
return buildResponse(response, HttpStatus.valueOf(response.getStatus()));
}
catch (QuestionAlreadyVotedException e){
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<QuestionUpvoteResponseDto> response = ApiResponseBuilder.buildErrorResponse(
UserProfileResponseDto.class,
e.getMessage(),
HttpStatus.BAD_REQUEST.value(),
errorResponse
);
return buildResponse(response, HttpStatus.valueOf(response.getStatus()));
}
}

@PostMapping (EndpointConstants.QuestionEndpoints.QUESTION_DOWNVOTE)
Expand Down Expand Up @@ -100,6 +114,19 @@ public ResponseEntity<GenericApiResponse<QuestionDownvoteResponseDto>> downvote
);
return buildResponse(response, HttpStatus.valueOf(response.getStatus()));
}
catch (QuestionAlreadyVotedException e){
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<QuestionDownvoteResponseDto> response = ApiResponseBuilder.buildErrorResponse(
UserProfileResponseDto.class,
e.getMessage(),
HttpStatus.BAD_REQUEST.value(),
errorResponse
);
return buildResponse(response, HttpStatus.valueOf(response.getStatus()));
}
}

@DeleteMapping(EndpointConstants.QuestionEndpoints.QUESTION_DELETE_UPVOTE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.group1.programminglanguagesforum.DTOs.Responses;

import lombok.*;

import java.util.List;

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GetAnswersResponseDto {
private List<AnswerResponseDto> items;
private int totalItems;
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class AnswerResponseDto {
private Long id;
private String content;
private AuthorDto author;
private String createdAt;
private String updatedAt;
private Long upvoteCount;
private Long downvoteCount;
private boolean selfAnswer;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class Question {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User askedBy;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@ManyToMany( fetch = FetchType.EAGER)
@JoinTable(name = "question_tags", // Name of the join table
joinColumns = @JoinColumn(name = "question_id"), inverseJoinColumns = @JoinColumn(name = "tag_id"))
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.group1.programminglanguagesforum.Exceptions;

public class QuestionAlreadyVotedException extends Exception{
public QuestionAlreadyVotedException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@
public interface VoteRepository extends JpaRepository<Vote,Long> {
Optional<Vote> findByUserAndQuestionAndIsUpvote(User user, Question question, boolean isUpvote);
Optional<Vote> findByUserAndAnswer(User user, Answer answer);

Optional<Vote> findByUserAndAnswerAndIsUpvote(User user, Answer answer, boolean b);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.group1.programminglanguagesforum.DTOs.Requests.CreateAnswerRequestDto;
import com.group1.programminglanguagesforum.DTOs.Responses.AuthorDto;
import com.group1.programminglanguagesforum.DTOs.Responses.CreateAnswerResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.GetAnswersResponseDto;
import com.group1.programminglanguagesforum.Entities.Answer;
import com.group1.programminglanguagesforum.Entities.Question;
import com.group1.programminglanguagesforum.Entities.User;
Expand All @@ -11,7 +12,6 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Date;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -70,4 +70,29 @@ public CreateAnswerResponseDto updateAnswer(Long answerId, CreateAnswerRequestDt
.updatedAt(answer.getUpdatedAt())
.build();
}

public GetAnswersResponseDto getAnswersForQuestion(Long questionId) throws UnauthorizedAccessException {
Question question = questionService.findById(questionId).orElseThrow();
User currentUser = userContextService.getCurrentUser();
return GetAnswersResponseDto.builder()
.items(question.getAnswers().stream().map(answer -> GetAnswersResponseDto.AnswerResponseDto.builder()
.id(answer.getId())
.content(answer.getAnswerBody())
.author(
AuthorDto.builder()
.id(answer.getAnsweredBy().getId())
.username(answer.getAnsweredBy().getUsername())
.reputationPoints(answer.getAnsweredBy().getReputationPoints())
.name(answer.getAnsweredBy().getFirstName() + " " + answer.getAnsweredBy().getLastName())
.build()
)
.createdAt(answer.getCreatedAt())
.updatedAt(answer.getUpdatedAt())
.upvoteCount(answer.getUpvoteCount())
.downvoteCount(answer.getDownvoteCount())
.selfAnswer(currentUser!=null && currentUser.getId().equals(answer.getAnsweredBy().getId()))
.build()).toList())
.totalItems(question.getAnswers().size())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,40 +80,51 @@ public CreateQuestionResponseDto createQuestion(CreateQuestionRequestDto dto)

}

public GetQuestionDetailsResponseDto getQuestion(Long id) throws UnauthorizedAccessException {
Optional<Question> questionOptional = questionRepository.findById(id);
if (questionOptional.isEmpty()) {
throw new UnauthorizedAccessException("Question not found");
}
Question question = questionOptional.get();
User currentUser = userContextService.getCurrentUser();
boolean selfQuestion = currentUser.getId().equals(question.getAskedBy().getId());
public GetQuestionDetailsResponseDto getQuestion(Long id) throws NoSuchElementException {
Optional<Question> questionOptional = questionRepository.findById(id);
if (questionOptional.isEmpty()) {
throw new NoSuchElementException("Question not found");
}
Question question = questionOptional.get();
boolean selfQuestion;
try {
User currentUser = userContextService.getCurrentUser();
selfQuestion = currentUser.getId().equals(question.getAskedBy().getId());
} catch (UnauthorizedAccessException e) {
selfQuestion = false;
}

return GetQuestionDetailsResponseDto.builder()
.id(question.getId())
.title(question.getTitle())
.content(question.getQuestionBody())
.likeCount(question.getUpvoteCount())
.dislikeCount(question.getDownvoteCount())
.commentCount(question.getCommentCount())
.selfQuestion(selfQuestion)
.createdAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(question.getCreatedAt()))
.updatedAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(question.getUpdatedAt()))
.author(AuthorDto.builder()
.id(question.getAskedBy().getId())
.username(question.getAskedBy().getUsername())
.reputationPoints(question.getAskedBy().getReputationPoints())
.name(question.getAskedBy().getFirstName() + " "
+ question.getAskedBy().getLastName())
.build())
.rating(0L)
.tags(question.getTags().stream().map(tag -> TagDto.builder()
.id(tag.getId())
.name(tag.getTagName())
.build()).toList())
.answerCount((long) question.getAnswers().size())
.bookmarked(isBookmarked(id))
.build();
boolean isBookmarked;
try {
isBookmarked = isBookmarked(id);
} catch (UnauthorizedAccessException e) {
isBookmarked = false;
}

return GetQuestionDetailsResponseDto.builder()
.id(question.getId())
.title(question.getTitle())
.content(question.getQuestionBody())
.likeCount(question.getUpvoteCount())
.dislikeCount(question.getDownvoteCount())
.commentCount(question.getCommentCount())
.selfQuestion(selfQuestion)
.createdAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(question.getCreatedAt()))
.updatedAt(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(question.getUpdatedAt()))
.author(AuthorDto.builder()
.id(question.getAskedBy().getId())
.username(question.getAskedBy().getUsername())
.reputationPoints(question.getAskedBy().getReputationPoints())
.name(question.getAskedBy().getFirstName() + " " + question.getAskedBy().getLastName())
.build())
.rating(0L)
.tags(question.getTags().stream().map(tag -> TagDto.builder()
.id(tag.getId())
.name(tag.getTagName())
.build()).toList())
.answerCount((long) question.getAnswers().size())
.bookmarked(isBookmarked)
.build();

}

Expand Down
Loading

0 comments on commit 71d5255

Please sign in to comment.