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 main #647

Merged
merged 52 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
6708f64
Fix code exec. response
EnesBaserr Dec 6, 2024
d5a3cec
Fix question related endpoints to retrieve difficulty level.
EnesBaserr Dec 6, 2024
199e6a0
Merge pull request #625 from bounswe/backend/bugfix/603-backend-fix-c…
EnesBaserr Dec 6, 2024
dce3fb9
Merge pull request #626 from bounswe/backend/bugfix/611-backend-retur…
EnesBaserr Dec 6, 2024
c8b9817
Add followed tags to users' profile responses.
EnesBaserr Dec 6, 2024
7d88548
Merge pull request #628 from bounswe/backend/feature/604-backend-get-…
EnesBaserr Dec 6, 2024
baee837
feat(mobile): add menu to navigate bookmarks
atakanyasar Dec 6, 2024
69768d7
feat(mobile): implement bookmarks page and API integration
atakanyasar Dec 6, 2024
50990a8
successfully added executable code snippets in question page.
NazireAta Dec 7, 2024
f560373
successfully added preview option to description in question creation…
NazireAta Dec 7, 2024
fcec00d
successfully added preview option to description in question creation…
NazireAta Dec 7, 2024
1a96bdf
Merge pull request #632 from bounswe/frontend/feature/add_code_snippe…
NazireAta Dec 7, 2024
64ae886
Merge branch 'develop' into frontend/feature/add_preview_to_question
mmtftr Dec 7, 2024
164bedc
Merge pull request #634 from bounswe/frontend/feature/add_preview_to_…
NazireAta Dec 7, 2024
e5cbd88
feat(backend): get bookmarked questions
atakanyasar Dec 7, 2024
eed961e
test(backend): add unit test for get bookmark
atakanyasar Dec 7, 2024
d84e414
add /questions/bookmarked api to openapi.yml
atakanyasar Dec 7, 2024
e8ce487
Merge pull request #635 from bounswe/feature/630-get-bookmarked-quest…
atakanyasar Dec 7, 2024
f351a33
Add rating for level of difficulty of a question
EnesBaserr Dec 7, 2024
b0edc4b
Fix endpoint naming
EnesBaserr Dec 7, 2024
1823d6a
Fix endpoint naming
EnesBaserr Dec 7, 2024
326c94f
Merge pull request #637 from bounswe/backend/feature/590-backend-ques…
EnesBaserr Dec 7, 2024
1db41c8
Update openapi.yml
EnesBaserr Dec 7, 2024
699ee73
feat(mobile): add bookmark button in question screen
atakanyasar Dec 7, 2024
2f3b41e
Merge remote-tracking branch 'origin/develop' into feature/608-bookma…
atakanyasar Dec 7, 2024
f54c8f9
fix(backend): don't allow duplicate bookmarks
atakanyasar Dec 7, 2024
7b6bc18
Merge remote-tracking branch 'origin/fix/638-bookmark' into feature/6…
atakanyasar Dec 7, 2024
8a23227
feat(mobile): detect if already bookmarked at initialization
atakanyasar Dec 7, 2024
33e80e0
fix(mobile): use className instead of style={}
atakanyasar Dec 8, 2024
1202d28
update api files for mobile
atakanyasar Dec 8, 2024
751a7ef
update api files for frontend
atakanyasar Dec 8, 2024
30efc22
Merge pull request #639 from bounswe/fix/638-bookmark
atakanyasar Dec 8, 2024
2cad263
Merge pull request #640 from bounswe/feature/608-bookmark-button
atakanyasar Dec 8, 2024
7b8a145
Implemented reputationPoints flow.
EnesBaserr Dec 8, 2024
556fe29
Changed reputation policy
EnesBaserr Dec 8, 2024
5f0396f
Merge pull request #643 from bounswe/backend/feature/642-backend-impl…
EnesBaserr Dec 8, 2024
6dd138a
added diffuculty rating form and bar
NazireAta Dec 9, 2024
502527b
added diffuculty rating form and bar
NazireAta Dec 9, 2024
0970bb6
added diffuculty rating form and bar
NazireAta Dec 9, 2024
8f41d54
feat(frontend): add followed tags section
mmtftr Dec 9, 2024
f80d4c5
fix question route
mmtftr Dec 9, 2024
3d4abc3
empty commit to rerun checks
mmtftr Dec 9, 2024
4c3fc7e
added diffuculty rating form and bar
NazireAta Dec 9, 2024
4ea0043
added diffuculty rating form and bar
NazireAta Dec 9, 2024
267e3e1
added diffuculty rating form and bar
NazireAta Dec 9, 2024
23a85a9
added diffuculty rating form and bar
NazireAta Dec 9, 2024
202f882
added diffuculty rating form and bar
NazireAta Dec 9, 2024
eec3a17
added diffuculty rating form and bar
NazireAta Dec 9, 2024
8da7d47
Merge pull request #645 from bounswe/frontend/feature/add_difficulty_…
NazireAta Dec 9, 2024
3f2168f
Merge branch 'develop' into feature/frontend/followed-tags-in-profile
mmtftr Dec 9, 2024
d9cc470
fix tests
mmtftr Dec 9, 2024
07f6fa6
Merge pull request #646 from bounswe/feature/frontend/followed-tags-i…
mmtftr Dec 9, 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 @@ -28,13 +28,15 @@ protected void configure() {
skip(destination.getPassword());
skip(destination.getFollowers());
skip(destination.getFollowing());

}
});
modelMapper.addMappings(new PropertyMap<User, SelfProfileResponseDto>() {
@Override
protected void configure() {
skip(destination.getQuestions());
skip(destination.getAnswers());
map(source.getReputationPoints(), destination.getReputationPoints());
}
});
modelMapper.addMappings(new PropertyMap <UserProfileResponseDto,User>() {
Expand All @@ -46,6 +48,14 @@ protected void configure() {

}
});
modelMapper.addMappings(new PropertyMap <User,UserProfileResponseDto>() {
@Override
protected void configure() {
skip(destination.getFollowedTags());
map(source.getReputationPoints(), destination.getReputationPoints());

}
});
modelMapper.addMappings(new PropertyMap<Question, GetQuestionWithTagDto>() {
@Override
protected void configure() {
Expand Down Expand Up @@ -87,6 +97,54 @@ protected void configure() {
}
});

modelMapper.addMappings(new PropertyMap<User, AuthorDto>() {
@Override
protected void configure() {
map(source.getId(), destination.getId());
map(source.getUsername(), destination.getUsername());
map(source.getReputationPoints(), destination.getReputationPoints());

using(context -> {
User user = (User) context.getSource();
String firstName = user.getFirstName() != null ? user.getFirstName() : "";
String lastName = user.getLastName() != null ? user.getLastName() : "";
return (firstName + " " + lastName).trim();
}).map(source, destination.getName());

map().setProfilePicture(null); // Set a default value for profile picture
}
});


modelMapper.addMappings(new PropertyMap<Question, QuestionSummaryDto>() {
@Override
protected void configure() {
map(source.getId(), destination.getId());
map(source.getTitle(), destination.getTitle());
map(source.getQuestionBody(), destination.getContent());
map(source.getDifficulty(), destination.getDifficulty());
map(source.getUpvoteCount(), destination.getUpvoteCount());
map(source.getDownvoteCount(), destination.getDownvoteCount());
map(source.getCommentCount(), destination.getAnswerCount());
using(context -> modelMapper.map(context.getSource(), AuthorDto.class))
.map(source.getAskedBy(), destination.getAuthor());
map(source.getTags(), destination.getTags());

}
});

modelMapper.addMappings(new PropertyMap<Question, BookmarkQuestionResponseDto>() {
@Override
protected void configure() {
map(source.getId(), destination.getId());
map(source.getTitle(), destination.getTitle());
map(source.getUpvoteCount(), destination.getUpvoteCount());
map(source.getDownvoteCount(), destination.getDownvoteCount());
}
});



return modelMapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public static class QuestionEndpoints {
public static final String QUESTION_DELETE_UPVOTE = QUESTION_ID + "/deleteUpvote";
public static final String QUESTION_DELETE_DOWNVOTE = QUESTION_ID + "/deleteDownvote";
public static final String QUESTION_ANSWERS = BASE_PATH + "/{questionId}/answers";
public static final String QUESTION_DIFFICULTY_VOTE = QUESTION_ID + "/vote-difficulty";
}

public static class AnswerEndpoints {
Expand All @@ -56,6 +57,7 @@ public static class TagEndpoints {
public static class BookmarkEndpoints {
public static final String BASE_PATH = "/questions/{questionId}/bookmarks";
public static final String BOOKMARK_DELETE = BASE_PATH;
public static final String BOOKMARK_GET = "/questions/bookmarked";
}

public static class SearchEndpoints {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public static class SparqlConstants {
(SAMPLE(?officialWebSite) AS ?officialWebSiteS)\s
(SAMPLE(?stackExchangeTag) AS ?stackExchangeTagS)
WHERE {
?library wdt:P31 wd:Q188860.
?library wdt:P31 wd:Q188860.

FILTER (
EXISTS { ?library wdt:P154 ?logoImage }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@

import com.group1.programminglanguagesforum.Constants.EndpointConstants;
import com.group1.programminglanguagesforum.DTOs.Responses.BookmarkQuestionResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.ErrorResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.QuestionSummaryDto;
import com.group1.programminglanguagesforum.DTOs.Responses.GenericApiResponse;
import com.group1.programminglanguagesforum.Exceptions.UnauthorizedAccessException;
import com.group1.programminglanguagesforum.Exceptions.ExceptionResponseHandler;
import com.group1.programminglanguagesforum.Services.BookmarkService;
import com.group1.programminglanguagesforum.Util.ApiResponseBuilder;

import jakarta.persistence.EntityExistsException;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;

@RequestMapping("api/v1")
Expand All @@ -36,29 +40,12 @@ public ResponseEntity<GenericApiResponse<BookmarkQuestionResponseDto>> bookmarkQ
bookmarkQuestionResponseDto
);
return buildResponse(genericApiResponse, HttpStatus.OK);


} catch (NoSuchElementException e) {
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<BookmarkQuestionResponseDto> genericApiResponse = ApiResponseBuilder.buildErrorResponse(
BookmarkQuestionResponseDto.class,
"An error occurred while bookmarking the question",
HttpStatus.NOT_FOUND.value(),
errorResponse
);
return buildResponse(genericApiResponse, HttpStatus.NOT_FOUND);
return ExceptionResponseHandler.NoSuchElementException(e);
} catch (UnauthorizedAccessException e) {
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<BookmarkQuestionResponseDto> response = ApiResponseBuilder
.buildErrorResponse(BookmarkQuestionResponseDto.class, e.getMessage(), 401, errorResponse);
return buildResponse(response, HttpStatus.UNAUTHORIZED);

return ExceptionResponseHandler.UnauthorizedAccessException(e);
} catch (EntityExistsException e) {
return ExceptionResponseHandler.EntityExistsException(e);
}
}

Expand All @@ -73,27 +60,27 @@ public ResponseEntity<GenericApiResponse<BookmarkQuestionResponseDto>> removeBoo
bookmarkQuestionResponseDto
);
return buildResponse(genericApiResponse, HttpStatus.OK);
} catch (NoSuchElementException e) {
return ExceptionResponseHandler.NoSuchElementException(e);
} catch (UnauthorizedAccessException e) {
return ExceptionResponseHandler.UnauthorizedAccessException(e);
}
catch (NoSuchElementException e) {
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<BookmarkQuestionResponseDto> genericApiResponse = ApiResponseBuilder.buildErrorResponse(
BookmarkQuestionResponseDto.class,
"An error occurred while deleting the bookmark",
HttpStatus.NOT_FOUND.value(),
errorResponse
}

@GetMapping(value = EndpointConstants.BookmarkEndpoints.BOOKMARK_GET)
public ResponseEntity<GenericApiResponse<List<QuestionSummaryDto>>> getBookmarkedQuestions() {
try {
List<QuestionSummaryDto> bookmarkedQuestions = bookmarkService.getBookmarkedQuestions();
GenericApiResponse<List<QuestionSummaryDto>> genericApiResponse = ApiResponseBuilder.buildSuccessResponse(
QuestionSummaryDto.class,
"Bookmarked questions retrieved successfully",
200,
bookmarkedQuestions
);
return buildResponse(genericApiResponse, HttpStatus.NOT_FOUND);
return buildResponse(genericApiResponse, HttpStatus.OK);
} catch (UnauthorizedAccessException e) {
ErrorResponse errorResponse = ErrorResponse.builder()
.errorMessage(e.getMessage())
.stackTrace(Arrays.toString(e.getStackTrace()))
.build();
GenericApiResponse<BookmarkQuestionResponseDto> response = ApiResponseBuilder
.buildErrorResponse(BookmarkQuestionResponseDto.class, e.getMessage(), 401, errorResponse);
return buildResponse(response, HttpStatus.UNAUTHORIZED);
}
return ExceptionResponseHandler.UnauthorizedAccessException(e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public ResponseEntity<GenericApiResponse<CodeExecutionResponseDTO>> executeCode(
) {
try {
CodeExecutionResponseDTO responseDTO = codeExecutionService.executeCode(requestDto.getCode(), requestDto.getLanguage(), requestDto.getInput());
int status = responseDTO.getStatus().equals("Accepted") ? HttpStatus.OK.value() : HttpStatus.INTERNAL_SERVER_ERROR.value();
if (status == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
throw new Exception(responseDTO.getStatus());
}
GenericApiResponse<CodeExecutionResponseDTO> response =
ApiResponseBuilder.buildSuccessResponse(
responseDTO.getClass(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@

import com.group1.programminglanguagesforum.Constants.EndpointConstants;
import com.group1.programminglanguagesforum.DTOs.Requests.CreateQuestionRequestDto;
import com.group1.programminglanguagesforum.DTOs.Requests.DifficultyLevelRequestDto;
import com.group1.programminglanguagesforum.DTOs.Requests.UpdateQuestionRequestDto;
import com.group1.programminglanguagesforum.DTOs.Responses.CreateQuestionResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.ErrorResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.GenericApiResponse;
import com.group1.programminglanguagesforum.DTOs.Responses.*;
import com.group1.programminglanguagesforum.Exceptions.ExceptionResponseHandler;
import com.group1.programminglanguagesforum.DTOs.Responses.GetQuestionDetailsResponseDto;
import com.group1.programminglanguagesforum.DTOs.Responses.QuestionSummaryDto;
import com.group1.programminglanguagesforum.Entities.DifficultyLevel;
import com.group1.programminglanguagesforum.Entities.Question;
import com.group1.programminglanguagesforum.Exceptions.UnauthorizedAccessException;
import com.group1.programminglanguagesforum.Services.QuestionDifficultyRateService;
import com.group1.programminglanguagesforum.Services.QuestionService;
import com.group1.programminglanguagesforum.Util.ApiResponseBuilder;
import lombok.RequiredArgsConstructor;
Expand All @@ -32,6 +30,7 @@
@RequiredArgsConstructor
public class QuestionController extends BaseController {
private final QuestionService questionService;
private final QuestionDifficultyRateService questionDifficultyRateService;

@PostMapping(value = EndpointConstants.QuestionEndpoints.BASE_PATH)
public ResponseEntity<GenericApiResponse<CreateQuestionResponseDto>> createQuestion(
Expand Down Expand Up @@ -132,4 +131,21 @@ public ResponseEntity<GenericApiResponse<Map<String, Object>>> searchQuestions(
HttpStatus.OK);
}

@PostMapping(value = EndpointConstants.QuestionEndpoints.QUESTION_DIFFICULTY_VOTE)
public ResponseEntity<GenericApiResponse<QuestionRateResponseDto>> rateQuestion(
@PathVariable(value = "id") Long id,
@RequestBody DifficultyLevelRequestDto dto) {
try {
GenericApiResponse<QuestionRateResponseDto> response = ApiResponseBuilder.buildSuccessResponse(
QuestionRateResponseDto.class, "Question rated successfully", 200,
questionDifficultyRateService.rateQuestion(id, dto.getDifficulty()));
return buildResponse(response, org.springframework.http.HttpStatus.OK);
} catch (NoSuchElementException e) {
return ExceptionResponseHandler.NoSuchElementException(e);
}
catch (UnauthorizedAccessException e) {
return ExceptionResponseHandler.UnauthorizedAccessException(e);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
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.Services.*;
import com.group1.programminglanguagesforum.Util.ApiResponseBuilder;
import lombok.RequiredArgsConstructor;
import org.modelmapper.ModelMapper;
Expand All @@ -33,6 +30,7 @@ public class UserController extends BaseController {
private final ModelMapper modelMapper;
private final QuestionService questionService;
private final AnswerService answerService;
private final TagService tagService;

@GetMapping(value = EndpointConstants.UserEndpoints.USER_ME)
public ResponseEntity<GenericApiResponse<SelfProfileResponseDto>> getUser() {
Expand All @@ -43,6 +41,10 @@ public ResponseEntity<GenericApiResponse<SelfProfileResponseDto>> getUser() {
SelfProfileResponseDto.class);
List<QuestionSummaryDto> questions = questionService.findByAuthorId(user.getId());
List<GetAnswerDtoForProfile> answers = answerService.findByAnsweredBy(user.getId());
selfProfileResponseDto.setFollowedTags(
tagService.getFollowedTags(user.getId())
);
selfProfileResponseDto.setReputationPoints(userService.calculateReputation(user));
selfProfileResponseDto.setQuestionCount((long) questions.size());
selfProfileResponseDto.setQuestions(
questions);
Expand Down Expand Up @@ -80,7 +82,12 @@ public ResponseEntity<GenericApiResponse<UserProfileResponseDto>> getUserById(
if (user.isPresent()) {
UserProfileResponseDto userProfileResponseDto = modelMapper.map(user.get(),
UserProfileResponseDto.class);
userProfileResponseDto.setReputationPoints(userService.calculateReputation(user.get()));
userProfileResponseDto.setSelfFollowing(userService.selfFollowing(user.get()));
userProfileResponseDto.setFollowedTags(
tagService.getFollowedTags(user.get().getId())
);


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

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

@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class DifficultyLevelRequestDto {
private DifficultyLevel difficulty;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.group1.programminglanguagesforum.DTOs.Requests;

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

import java.util.List;
Expand All @@ -13,4 +14,5 @@ public class UpdateQuestionRequestDto {
private String title;
private String content;
private List<Long> tags;
private DifficultyLevel difficulty;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.group1.programminglanguagesforum.DTOs.Responses;

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

import java.util.ArrayList;
Expand All @@ -18,6 +19,7 @@ public class GetQuestionDetailsResponseDto {
private Long dislikeCount;
private Long commentCount;
private Boolean selfQuestion;
private DifficultyLevel difficulty;
private Integer selfVoted;
private String createdAt;
@Builder.Default
Expand All @@ -30,5 +32,10 @@ public class GetQuestionDetailsResponseDto {
private Long answerCount = 0L;
@Builder.Default
private boolean bookmarked = false;
@Builder.Default
private DifficultyLevel selfDifficultyVote =null;
private Long easyCount;
private Long mediumCount;
private Long hardCount;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.group1.programminglanguagesforum.DTOs.Responses;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class QuestionRateResponseDto {
private Long questionId;
private Long easyCount;
private Long mediumCount;
private Long hardCount;
private Long totalCount;
}
Loading
Loading