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

[Deploy] Deploy to Production #623

Merged
merged 27 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f9038a5
create lab-8 branch
mmtftr Dec 3, 2024
4a543a5
Added unit-testing related dependency (report-generator etc.)
EnesBaserr Dec 3, 2024
39c5727
Added postman use-guide.
EnesBaserr Dec 3, 2024
7f7d43e
Merge pull request #582 from bounswe/lab-8/pr
mmtftr Dec 3, 2024
f721597
Bugfix for questionCount.
EnesBaserr Dec 4, 2024
6a5384b
Merge pull request #597 from bounswe/backend/bugfix/591-backend-fix-i…
EnesBaserr Dec 4, 2024
5d6697a
Get Questions and Answers for UserProfile
EnesBaserr Dec 4, 2024
d55df31
Merge pull request #599 from bounswe/backend/feature/598-backend-retr…
EnesBaserr Dec 4, 2024
deeaa54
feat(frontend): add difficulty filter to tag page
mmtftr Dec 6, 2024
555c844
feat(frontend): add info popover for create answer
mmtftr Dec 6, 2024
11bbceb
feat(frontend): add question search
mmtftr Dec 6, 2024
7c8399d
chore(devops): add type checking
mmtftr Dec 6, 2024
85c5d81
Merge pull request #613 from bounswe/feature/frontend/user-guiding
mmtftr Dec 6, 2024
34f7471
feat(frontend/mobile): add difficulty level display to question card
mmtftr Dec 6, 2024
25761a5
fix(backend): make question dto consistent
mmtftr Dec 6, 2024
2df3354
Merge branch 'feature/frontend/tag-page-difficulty' into feature/fron…
mmtftr Dec 6, 2024
b002dc7
Merge pull request #612 from bounswe/feature/frontend/tag-page-diffic…
mmtftr Dec 6, 2024
9ae684f
Merge pull request #615 from bounswe/feature/frontend/search-questions
mmtftr Dec 6, 2024
df45ef6
Merge pull request #618 from bounswe/feature/frontend/difficulty-in-q…
mmtftr Dec 6, 2024
c0c5700
Merge pull request #616 from bounswe/feature/devops/frontend-tsc
mmtftr Dec 6, 2024
1824603
feat(frontend): add difficulty filter in question search page
mmtftr Dec 6, 2024
845295e
Merge branch 'develop' into fix/backend/question-dto
mmtftr Dec 6, 2024
e944af2
fix(frontend): type errors
mmtftr Dec 6, 2024
170bc04
fix(frontend): layout in feed
mmtftr Dec 6, 2024
37fce75
Merge pull request #620 from bounswe/fix/backend/question-dto
mmtftr Dec 6, 2024
0567ae3
Merge branch 'develop' into frontend/feature/difficulty-filter-in-q-s…
mmtftr Dec 6, 2024
06bf7b1
Merge pull request #621 from bounswe/frontend/feature/difficulty-filt…
mmtftr Dec 6, 2024
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
3 changes: 3 additions & 0 deletions .github/workflows/frontend_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ jobs:

- name: Run tests
run: yarn test

- name: Run type-check
run: yarn tsc
26 changes: 26 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,32 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- JaCoCo Plugin for Coverage -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.10</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Surefire Plugin for Test Execution -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
</plugin>
</plugins>
</build>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ protected void configure() {
skip(destination.getFollowing());
}
});
modelMapper.addMappings(new PropertyMap<User, SelfProfileResponseDto>() {
@Override
protected void configure() {
skip(destination.getQuestions());
skip(destination.getAnswers());
}
});
modelMapper.addMappings(new PropertyMap <UserProfileResponseDto,User>() {
@Override
protected void configure() {
Expand All @@ -39,12 +46,19 @@ protected void configure() {

}
});
modelMapper.addMappings(new PropertyMap<Question, GetQuestionWithTagDto>() {
@Override
protected void configure() {
map(source.getQuestionBody(), destination.getContent());
}
});
modelMapper.addMappings(new PropertyMap< GetQuestionWithTagDto,Question>() {
@Override
protected void configure() {
skip(destination.getTags());
skip(destination.getVotes());
skip(destination.getAskedBy());
map(source.getContent(), destination.getQuestionBody());
}
});
modelMapper.addMappings(new PropertyMap<ProgrammingLanguagesTag, GetProgrammingLanguageTagResponseDto>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

import com.group1.programminglanguagesforum.Constants.EndpointConstants;
import com.group1.programminglanguagesforum.DTOs.Requests.UserProfileUpdateRequestDto;
import com.group1.programminglanguagesforum.DTOs.Responses.ErrorResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.GenericApiResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.SelfProfileResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.UserProfileResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.UserSummaryDto;
import com.group1.programminglanguagesforum.DTOs.Responses.*;
import com.group1.programminglanguagesforum.Entities.User;
import com.group1.programminglanguagesforum.Exceptions.UnauthorizedAccessException;
import com.group1.programminglanguagesforum.Exceptions.UserNotFoundException;
import com.group1.programminglanguagesforum.Services.AnswerService;
import com.group1.programminglanguagesforum.Services.QuestionService;
import com.group1.programminglanguagesforum.Services.UserContextService;
import com.group1.programminglanguagesforum.Services.UserService;
import com.group1.programminglanguagesforum.Util.ApiResponseBuilder;
Expand All @@ -33,6 +31,8 @@ public class UserController extends BaseController {
private final UserContextService userContextService;
private final UserService userService;
private final ModelMapper modelMapper;
private final QuestionService questionService;
private final AnswerService answerService;

@GetMapping(value = EndpointConstants.UserEndpoints.USER_ME)
public ResponseEntity<GenericApiResponse<SelfProfileResponseDto>> getUser() {
Expand All @@ -41,6 +41,16 @@ public ResponseEntity<GenericApiResponse<SelfProfileResponseDto>> getUser() {
User user = userContextService.getCurrentUser();
SelfProfileResponseDto selfProfileResponseDto = modelMapper.map(user,
SelfProfileResponseDto.class);
List<QuestionSummaryDto> questions = questionService.findByAuthorId(user.getId());
List<GetAnswerDtoForProfile> answers = answerService.findByAnsweredBy(user.getId());
selfProfileResponseDto.setQuestionCount((long) questions.size());
selfProfileResponseDto.setQuestions(
questions);
selfProfileResponseDto.setAnswerCount((long) answers.size());
selfProfileResponseDto.setAnswers(
answers);


GenericApiResponse<SelfProfileResponseDto> response = ApiResponseBuilder.buildSuccessResponse(
selfProfileResponseDto.getClass(),
"User retrieved successfully",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.group1.programminglanguagesforum.DTOs.Responses;

import lombok.*;

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class GetAnswerDtoForProfile {
private Long id;
private String content;
private AuthorDto author;
private String createdAt;
private String updatedAt;
private Long upvoteCount;
private Long downvoteCount;
private boolean selfAnswer;
private Integer selfVoted;
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class QuesitonInfoForAnswer {
private Long id;
private String title;
}
private QuesitonInfoForAnswer question;

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
public class GetQuestionWithTagDto {
private Long id;
private String title;
private String questionBody;
private String content;
@Builder.Default
private Long likeCount = 0L;
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import com.group1.programminglanguagesforum.Entities.ExperienceLevel;
import lombok.*;

import java.util.List;

@Builder
@NoArgsConstructor
@AllArgsConstructor
Expand All @@ -19,5 +21,8 @@ public class SelfProfileResponseDto {
private int followersCount;
private int followingCount;
private int reputationPoints;
private Long questionCount;
private ExperienceLevel experienceLevel;
private List<QuestionSummaryDto> questions;
private List<GetAnswerDtoForProfile> answers;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package com.group1.programminglanguagesforum.Repositories;

import com.group1.programminglanguagesforum.Entities.Answer;
import com.group1.programminglanguagesforum.Entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface AnswerRepository extends JpaRepository<Answer,Long> {

@Query("SELECT a FROM Answer a WHERE a.answeredBy.id = :userId")
List<Answer> findByAnsweredBy(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ Page<Question> searchQuestions(
@Param("tagIds") List<Long> tagIds,
@Param("difficulty") DifficultyLevel difficulty,
Pageable pageable);
@Query("SELECT q FROM Question q WHERE q.askedBy.id = :author")
List<Question> findByAuthorId(@Param("author") Long authorId);
}
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.GetAnswerDtoForProfile;
import com.group1.programminglanguagesforum.DTOs.Responses.GetAnswersResponseDto;
import com.group1.programminglanguagesforum.Entities.Answer;
import com.group1.programminglanguagesforum.Entities.Question;
Expand All @@ -23,6 +24,13 @@ public class AnswerService {
private final QuestionService questionService;
private final VoteRepository voteRepository;


public java.util.List<GetAnswerDtoForProfile> findByAnsweredBy(Long userId) {
return answerRepository.findByAnsweredBy(userId).stream()
.map(this::mapAnswerToProfileDto)
.toList();
}

public CreateAnswerResponseDto createAnswer(Long questionId, CreateAnswerRequestDto createAnswerRequestDto) throws UnauthorizedAccessException {
User currentUser = userContextService.getCurrentUser();
Question question = questionService.findById(questionId).orElseThrow();
Expand Down Expand Up @@ -101,6 +109,32 @@ public GetAnswersResponseDto getAnswersForQuestion(Long questionId) {
.build();
}

public GetAnswerDtoForProfile mapAnswerToProfileDto(Answer answer){
final User currentUser = getCurrentUserOrNull();
return GetAnswerDtoForProfile.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()))
.selfVoted(currentUser != null && voteRepository.findByUserAndAnswer(currentUser, answer).isPresent() ? voteRepository.findByUserAndAnswer(currentUser, answer).get().isUpvote()? 1 : -1 : 0)
.question(GetAnswerDtoForProfile.QuesitonInfoForAnswer.builder()
.id(answer.getQuestion().getId())
.title(answer.getQuestion().getTitle())
.build())
.build();
}

private User getCurrentUserOrNull() {
try {
return userContextService.getCurrentUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public class QuestionService {
public Optional<Question> findById(Long id) {
return questionRepository.findById(id);
}
public List<QuestionSummaryDto> findByAuthorId(Long authorId) {
return questionRepository.findByAuthorId(authorId).stream()
.map(this::mapToQuestionSummary)
.collect(Collectors.toList());
}

public CreateQuestionResponseDto createQuestion(CreateQuestionRequestDto dto)
throws UnauthorizedAccessException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,20 +70,23 @@ public GetTagDetailsResponseDto getTagDetails(Long tagId) {
List<GetQuestionWithTagDto> relatedQuestions = questions.stream()
.map(question -> modelMapper.map(question, GetQuestionWithTagDto.class))
.toList();
Long questionCount = (long) questions.size();

if (tagType == TagType.PROGRAMMING_LANGUAGE) {
ProgrammingLanguagesTag languageTag = (ProgrammingLanguagesTag) tagEntity;
GetProgrammingLanguageTagResponseDto responseDto = modelMapper.map(languageTag,
GetProgrammingLanguageTagResponseDto.class);
responseDto.setTagType(tagType.toString());
responseDto.setRelatedQuestions(relatedQuestions);
responseDto.setQuestionCount(questionCount);
return responseDto;
} else if (tagType == TagType.PROGRAMMING_PARADIGM) {
ProgrammingParadigmTag paradigmTag = (ProgrammingParadigmTag) tagEntity;
GetProgrammingParadigmResponseDto responseDto = modelMapper.map(paradigmTag,
GetProgrammingParadigmResponseDto.class);
responseDto.setTagType(tagType.toString());
responseDto.setRelatedQuestions(relatedQuestions);
responseDto.setQuestionCount(questionCount);
return responseDto;
}

Expand All @@ -93,6 +96,7 @@ public GetTagDetailsResponseDto getTagDetails(Long tagId) {
.description(tagEntity.getTagDescription())
.tagType(getTagType(tagEntity).toString())
.relatedQuestions(relatedQuestions)
.questionCount(questionCount)

.build();

Expand All @@ -102,6 +106,7 @@ public Page<GetTagDetailsResponseDto> searchTags(String q, Pageable pageable) {
Page<Tag> tags = tagRepository.findTagsByTagNameContainingIgnoreCase(q, pageable);
return tags.map(tag -> GetTagDetailsResponseDto.builder()
.tagId(tag.getId())
.questionCount((long) questionRepository.findQuestionsByTagId(tag.getId()).size())
.name(tag.getTagName())
.description(tag.getTagDescription())
.tagType(getTagType(tag).toString())
Expand Down
Loading
Loading