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] Test deploy #699

Merged
merged 65 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
490bcd6
Add return questions, answers and followed tags to GET users/{userId}
Cgtycolak Dec 10, 2024
6d146ac
Revert "Add return questions, answers and followed tags to GET users/…
Cgtycolak Dec 10, 2024
a7a7071
Merge branch 'develop' into 627-backend-get-usersuserid-should-return…
Cgtycolak Dec 10, 2024
be1a66e
Reapply "Add return questions, answers and followed tags to GET users…
Cgtycolak Dec 10, 2024
a48ac3c
refactor(mobile): rename FollowButton to FollowUserButton
atakanyasar Dec 10, 2024
5740867
fix(api): change tagId type from string to number
atakanyasar Dec 10, 2024
c0ee434
feat(mobile): add follow tag feature
atakanyasar Dec 10, 2024
4742d69
Add reputation points to profile page
ozdentarikcan Dec 12, 2024
ed029b1
Implement bookmarked page
ozdentarikcan Dec 14, 2024
1ee28c5
Remove unused vars
ozdentarikcan Dec 14, 2024
0bf9326
Add bookmarked page button to profile
ozdentarikcan Dec 14, 2024
c89f78a
Added default profile picture.
NazireAta Dec 14, 2024
4042738
fixed test
NazireAta Dec 14, 2024
2e044d7
fix(backend): return follower count correctly in tags
mmtftr Dec 14, 2024
c8c2179
fix backend tests
mmtftr Dec 14, 2024
6882536
fixed based on review
NazireAta Dec 14, 2024
c297af3
Merge pull request #680 from bounswe/frontend/feature/add_default_pro…
NazireAta Dec 14, 2024
ae392a5
Add bookmark page tests
ozdentarikcan Dec 14, 2024
43f64b3
Merge remote-tracking branch 'origin/develop' into frontend/feature/5…
mmtftr Dec 14, 2024
be4aff2
Merge branch 'develop' into 627-backend-get-usersuserid-should-return…
Cgtycolak Dec 14, 2024
9acbce7
Match latest changes in develop
ozdentarikcan Dec 14, 2024
69b1cf3
Fix issues from feedback
ozdentarikcan Dec 14, 2024
7794988
Fix test text field
ozdentarikcan Dec 14, 2024
ebfd970
added link to tag page
NazireAta Dec 14, 2024
5261e27
added link to tag page
NazireAta Dec 14, 2024
fc09387
added link to tag page
NazireAta Dec 14, 2024
8951b26
Merge pull request #688 from bounswe/frontend/feature/fix_tag_badge_r…
NazireAta Dec 14, 2024
686ef30
Merge pull request #682 from bounswe/fix/backend/tag-follower-count
mmtftr Dec 15, 2024
9e0cf7a
Merge pull request #684 from bounswe/frontend/feature/594/bookmark-page
ozdentarikcan Dec 15, 2024
27fb4cc
Update reputation points and add test
ozdentarikcan Dec 15, 2024
e9cfbe3
Add recommendation query
ozdentarikcan Dec 16, 2024
9564344
Resolve import issues
ozdentarikcan Dec 16, 2024
9ee8728
Add api info
ozdentarikcan Dec 16, 2024
0cb4752
Integrate with frontend
ozdentarikcan Dec 16, 2024
b1b4606
fix(mobile): update new backend URL
atakanyasar Dec 16, 2024
9b4009d
Merge pull request #668 from bounswe/feature/650-follow-tag
atakanyasar Dec 16, 2024
c8d0bb0
Add sortBy to parameters
ozdentarikcan Dec 16, 2024
44e3453
Fix sortBy
ozdentarikcan Dec 16, 2024
a7bc926
Use sr-only for non-button non-anchor elements
ozdentarikcan Dec 16, 2024
80dce92
Make loading messages visible
ozdentarikcan Dec 16, 2024
d94be23
Merge pull request #686 from bounswe/frontend/feature/592/reputation-…
ozdentarikcan Dec 16, 2024
5acc44c
Get User from UserContextService
ozdentarikcan Dec 16, 2024
1286231
feat(mobile): add reputation and followed tags to profile page
atakanyasar Dec 16, 2024
4cae533
add glossary and tag type pages
asligook Dec 16, 2024
d20138e
Merge pull request #685 from bounswe/627-backend-get-usersuserid-shou…
Cgtycolak Dec 16, 2024
a103f21
add glossary test
asligook Dec 16, 2024
2922eda
update glossary.tsx
asligook Dec 16, 2024
fb0b528
add comments on changed files
asligook Dec 16, 2024
13744f8
feat(mobile): update user profile components
atakanyasar Dec 16, 2024
1e84295
Merge pull request #694 from bounswe/frontend/feature/glossary-tag-types
asligook Dec 16, 2024
0c1d2c9
Update sortBy parameter and conditions
ozdentarikcan Dec 16, 2024
0cc94c6
Fix typo
ozdentarikcan Dec 16, 2024
5a522b4
fix(frontend): bookmarks not being shown
mmtftr Dec 16, 2024
e639be8
Merge pull request #696 from bounswe/fix/frontend/bookmarks-page
mmtftr Dec 16, 2024
79eb06b
Merge pull request #691 from bounswe/backend/feature/689/sort-questio…
ozdentarikcan Dec 16, 2024
e3493f1
Add loading while taking long
ozdentarikcan Dec 16, 2024
48fb101
feat(frontend): use recommended questions in the home page
mmtftr Dec 16, 2024
52c8b2b
Merge pull request #695 from bounswe/feature/666-mobile-profile-page
atakanyasar Dec 16, 2024
db045ce
Merge pull request #692 from bounswe/frontend/accessibility/609/sr-on…
ozdentarikcan Dec 16, 2024
b803c0f
Add loading screen
ozdentarikcan Dec 16, 2024
c2b2333
feat(frontend): improve UX for difficulty bar
mmtftr Dec 16, 2024
a431ed6
Merge pull request #697 from bounswe/frontend/tagtype-page-infinite-s…
ozdentarikcan Dec 16, 2024
efc15ff
fix: not showing self vote on first load
mmtftr Dec 16, 2024
fd22ad6
fix: frontend tests
mmtftr Dec 16, 2024
42aae89
Merge pull request #698 from bounswe/feature/frontend/ux-improvements
mmtftr Dec 16, 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
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ public ResponseEntity<GenericApiResponse<Map<String, Object>>> searchQuestions(
@RequestParam(required = false) String tags,
@RequestParam(required = false) DifficultyLevel difficulty,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "20") int pageSize) {
@RequestParam(defaultValue = "20") int pageSize,
@RequestParam(defaultValue = "recommended") String sortBy) {

Page<Question> questionPage = questionService.searchQuestions(query, tags, difficulty, page, pageSize);
Page<Question> questionPage = questionService.searchQuestions(query, tags, difficulty, page, pageSize, sortBy);

List<QuestionSummaryDto> questionSummaries = questionPage.getContent().stream()
.map(QuestionService::mapToQuestionSummary)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,14 @@ public ResponseEntity<GenericApiResponse<SelfProfileResponseDto>> getUser() {
List<QuestionSummaryDto> questions = questionService.findByAuthorId(user.getId());
List<GetAnswerDtoForProfile> answers = answerService.findByAnsweredBy(user.getId());
selfProfileResponseDto.setFollowedTags(
tagService.getFollowedTags(user.getId())
);
tagService.getFollowedTags(user.getId()));
selfProfileResponseDto.setReputationPoints(userService.calculateReputation(user));
selfProfileResponseDto.setQuestionCount((long) questions.size());
selfProfileResponseDto.setQuestions(
questions);
questions);
selfProfileResponseDto.setAnswerCount((long) answers.size());
selfProfileResponseDto.setAnswers(
answers);

answers);

GenericApiResponse<SelfProfileResponseDto> response = ApiResponseBuilder.buildSuccessResponse(
selfProfileResponseDto.getClass(),
Expand Down Expand Up @@ -84,10 +82,13 @@ public ResponseEntity<GenericApiResponse<UserProfileResponseDto>> getUserById(
UserProfileResponseDto.class);
userProfileResponseDto.setReputationPoints(userService.calculateReputation(user.get()));
userProfileResponseDto.setSelfFollowing(userService.selfFollowing(user.get()));
userProfileResponseDto.setFollowedTags(
tagService.getFollowedTags(user.get().getId())
);

List<QuestionSummaryDto> questions = questionService.findByAuthorId(id);
userProfileResponseDto.setQuestions(questions);
userProfileResponseDto.setQuestionCount((long) questions.size());
List<GetAnswerDtoForProfile> answers = answerService.findByAnsweredBy(id);
userProfileResponseDto.setAnswers(answers);
userProfileResponseDto.setAnswerCount((long) answers.size());
userProfileResponseDto.setFollowedTags(tagService.getFollowedTags(id));

GenericApiResponse<UserProfileResponseDto> response = ApiResponseBuilder.buildSuccessResponse(
userProfileResponseDto.getClass(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package com.group1.programminglanguagesforum.DTOs.Responses;

import com.group1.programminglanguagesforum.Entities.ExperienceLevel;
import lombok.*;

Expand All @@ -25,5 +26,7 @@ public class UserProfileResponseDto {
private ExperienceLevel experienceLevel;
@Builder.Default
private List<SelfProfileResponseDto.FollowedTags> followedTags = new ArrayList<>();

private Long questionCount;
private List<QuestionSummaryDto> questions;
private List<GetAnswerDtoForProfile> answers;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ Page<Question> searchQuestions(
@Param("difficulty") DifficultyLevel difficulty,
Pageable pageable);

@Query("SELECT DISTINCT q FROM Question q " +
"LEFT JOIN q.tags t " +
"WHERE (:query IS NULL OR " +
" LOWER(q.title) LIKE LOWER(CONCAT('%', :query, '%')) OR " +
" LOWER(q.questionBody) LIKE LOWER(CONCAT('%', :query, '%'))) " +
"AND (:tagIds IS NULL OR t.id IN :tagIds) " +
"AND (:difficulty IS NULL OR q.difficulty = :difficulty) " +
"ORDER BY " +
" CASE WHEN :authorIds IS NOT NULL AND q.askedBy.id IN :authorIds THEN 1 ELSE 0 END DESC")
Page<Question> searchQuestionsByRecommended(
@Param("query") String query,
@Param("authorIds") List<Long> authorIds,
@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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.Objects;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
Expand Down Expand Up @@ -218,17 +219,32 @@ public Page<Question> searchQuestions(
String tagIdsStr,
DifficultyLevel difficulty,
int page,
int pageSize) {
int pageSize,
String sortBy) {

List<Long> tagIds = null;
if (tagIdsStr != null && !tagIdsStr.isEmpty()) {
tagIds = Arrays.stream(tagIdsStr.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
}
User currentUser;
try {
currentUser = userContextService.getCurrentUser();
} catch (UnauthorizedAccessException e) {
currentUser = null;
}

PageRequest pageable = PageRequest.of(page - 1, pageSize);
return questionRepository.searchQuestions(query, tagIds, difficulty, pageable);
if (Objects.equals(sortBy, "default") || Objects.equals(sortBy, null) || Objects.equals(currentUser, null)) {
return questionRepository.searchQuestions(query, tagIds, difficulty, pageable);
} else {
List<Long> authorIds = currentUser.getFollowing().stream()
.map(User::getId) // Map each User to its ID
.collect(Collectors.toList()); // Collect the IDs into a List
return questionRepository.searchQuestionsByRecommended(query, authorIds, tagIds, difficulty, pageable);
}

}

public static QuestionSummaryDto mapToQuestionSummary(Question question) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,16 @@ public GetTagDetailsResponseDto getTagDetails(Long tagId) {
following = false;
}

Long followerCount = (long) tagEntity.getFollowers().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);
responseDto.setFollowerCount(followerCount);
responseDto.setFollowing(following);
return responseDto;
} else if (tagType == TagType.PROGRAMMING_PARADIGM) {
Expand All @@ -117,6 +120,7 @@ public GetTagDetailsResponseDto getTagDetails(Long tagId) {
responseDto.setTagType(tagType.toString());
responseDto.setRelatedQuestions(relatedQuestions);
responseDto.setQuestionCount(questionCount);
responseDto.setFollowerCount(followerCount);
responseDto.setFollowing(following);
return responseDto;
}
Expand All @@ -128,6 +132,7 @@ public GetTagDetailsResponseDto getTagDetails(Long tagId) {
.tagType(getTagType(tagEntity).toString())
.relatedQuestions(relatedQuestions)
.questionCount(questionCount)
.followerCount(followerCount)
.following(following)
.build();

Expand All @@ -149,6 +154,7 @@ public Page<GetTagDetailsResponseDto> searchTags(String q, Pageable pageable) {
return tags.map(tag -> GetTagDetailsResponseDto.builder()
.tagId(tag.getId())
.questionCount((long) questionRepository.findQuestionsByTagId(tag.getId()).size())
.followerCount((long) tag.getFollowers().size())
.name(tag.getTagName())
.description(tag.getTagDescription())
.tagType(getTagType(tag).toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,5 @@ public Page<User> searchUsers(String query, int page, int pageSize) {
public List<User> getFollowing(User user) {
return user.getFollowing().stream().toList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
Expand Down Expand Up @@ -111,7 +112,7 @@ void testGetTagDetails_Success() {
.reputationPoints(0L)
.build();

Tag mockTag = new Tag(1L, null, "Tag1", "Description1", null);
Tag mockTag = new Tag(1L, null, "Tag1", "Description1", new HashSet<>());

Question q1 = Question.builder()
.id(1L)
Expand Down
3 changes: 3 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-aspect-ratio": "^1.0.3",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-collapsible": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
Expand All @@ -33,6 +34,8 @@
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-toggle": "^1.1.1",
"@radix-ui/react-toggle-group": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.3",
"@tailwindcss/typography": "^0.5.15",
"@tanstack/react-query": "^5.35.1",
Expand Down
Binary file added frontend/src/assets/placeholder_profile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion frontend/src/components/AnswerCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Card } from "@/components/ui/card";
import { ArrowRight, CornerDownRight, Star } from "lucide-react";
import React from "react";
import { Link } from "react-router-dom";
import placeholderProfile from "@/assets/placeholder_profile.png";

interface AnswerCardProps {
id: number;
Expand Down Expand Up @@ -48,7 +49,8 @@ export const AnswerCard: React.FC<AnswerCardProps> = ({
<div className="flex items-center justify-between">
<Link to={`/users/${author.id}`} className="h-10 w-10">
<img
src={author.profilePicture}
src={author?.profilePicture ||
placeholderProfile}
alt={"Profile picture"}
className="rounded-full object-cover"
/>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/AnswerItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ThumbsDown, ThumbsUp } from "lucide-react";
import React from "react";
import { Link } from "react-router-dom";
import { ContentWithSnippets } from "./ContentWithSnippets";
import placeholderProfile from "@/assets/placeholder_profile.png";

interface AnswerItemProps {
answer: AnswerDetails;
Expand Down Expand Up @@ -61,8 +62,7 @@ export const AnswerItem: React.FC<AnswerItemProps> = ({
>
<img
src={
answer.author?.profilePicture ||
"https://placehold.co/100x100"
answer.author?.profilePicture || placeholderProfile
}
alt={"Profile picture"}
className="h-8 w-8 rounded-full object-cover"
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/components/Answers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ export function Answers({ questionId }: AnswersProps) {
onDownvote={() => handleVote(answer.id, -1)}
/>
))}
{answers.length === 0 && (
<span>
{" "}
This question doesn't have an answer yet. Contribute to the discussion
by answering this question.
</span>
)}
</div>
);
}
Loading
Loading