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

TRIB-289: adds AttributesApplyPhraseToUser DTO and in review notification #292

Merged
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
241de52
TRIB-289: adds AttributesApplyPhraseToUserDTO
mrsbluerose Oct 2, 2024
badf924
TRIB-289: refactors AttributesApplyPhraseToUserDTO
mrsbluerose Oct 2, 2024
3978b2b
TRIB-289: refactors return for PhraseService apply
mrsbluerose Oct 2, 2024
c4b6eb6
TRIB-289: refactors AttAPI applyPhrase return
mrsbluerose Oct 2, 2024
dfa3844
TRIB-289: refactors isPhraseValid back to boolean
mrsbluerose Oct 3, 2024
8b7bb84
TRIB-289: refactors PhraseServiceImplTest with DTO
mrsbluerose Oct 3, 2024
ea1682b
TRIB-289: removes outdated comments from tests
mrsbluerose Oct 3, 2024
1a5b26c
TRIB-289: removes test context from db migration
mrsbluerose Oct 3, 2024
7ae20a3
TRIB-289: updates notification_type table
mrsbluerose Oct 3, 2024
68bc69e
Revert "TRIB-289: removes test context from db migration"
mrsbluerose Oct 3, 2024
56f78b4
TRIB-289: adds in review to NotificationType ent
mrsbluerose Oct 3, 2024
3f219e1
TRIB-289: adds DTO creator to PhraseService intfc
mrsbluerose Oct 3, 2024
65dc7c7
TRIB-289: refactors AttributesAPI apply phrase
mrsbluerose Oct 3, 2024
0982ae1
TRIB-289: removes unused import
mrsbluerose Oct 3, 2024
2184847
TRIB-289: refactors AttributesAPIIT tests
mrsbluerose Oct 3, 2024
ad43785
TRIB-289: refactors PhraseService apply phrase
mrsbluerose Oct 3, 2024
f98973c
TRIB-289: adds PhraseServiceImpl tests for dto
mrsbluerose Oct 3, 2024
0321f8f
TRIB-289: adds PhraseService test for attDTO
mrsbluerose Oct 3, 2024
e96401b
TRIB-289: corrects typo in test names
mrsbluerose Oct 3, 2024
622248a
TRIB-289: updates Swagger doc for AttributesAPI
mrsbluerose Oct 3, 2024
0dcd0db
Merge branch 'feature/review-attributes-page' into TRIB-289
mrsbluerose Oct 4, 2024
3588302
TRIB-289: updates ids for notificationType types
mrsbluerose Oct 4, 2024
f09edc0
TRIB-289: removes isSuccess from AttributesApplyPhraseToUserDTO
mrsbluerose Oct 4, 2024
6f58a00
TRIB-289: removed merge conflict from DB master
mrsbluerose Oct 4, 2024
b0060bd
TRIB-289: removes isSuccess from AttributesApplyPhraseToUserDTO
mrsbluerose Oct 4, 2024
b53a881
TRIB-289: removes PhraseServiceTest helper tests
mrsbluerose Oct 4, 2024
916a788
Merge branch 'feature/review-attributes-page' into TRIB-289
haxwell Oct 25, 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 @@ -7,6 +7,7 @@
import com.savvato.tribeapp.controllers.dto.AttributesRequest;
import com.savvato.tribeapp.controllers.dto.PhraseSequenceRequest;
import com.savvato.tribeapp.dto.AttributeDTO;
import com.savvato.tribeapp.dto.AttributesApplyPhraseToUserDTO;
import com.savvato.tribeapp.dto.GenericResponseDTO;
import com.savvato.tribeapp.dto.ToBeReviewedDTO;
import com.savvato.tribeapp.entities.NotificationType;
Expand Down Expand Up @@ -90,25 +91,18 @@ public ResponseEntity<List<ToBeReviewedDTO>> getUserPhrasesToBeReviewed(

@ApplyPhraseToUser
@PostMapping
public ResponseEntity<GenericResponseDTO> applyPhraseToUser(@RequestBody @Valid AttributesRequest req) {
if (phraseService.isPhraseValid(req.adverb, req.verb, req.preposition, req.noun)) {
boolean isPhraseApplied =
phraseService.applyPhraseToUser(
req.userId, req.adverb, req.verb, req.preposition, req.noun);
if (isPhraseApplied) {
sendNotification(true, req.userId);
GenericResponseDTO rtn = GenericResponseService.createDTO(true);
return ResponseEntity.status(HttpStatus.OK).body(rtn);
} else {
sendNotification(false, req.userId);
GenericResponseDTO rtn = GenericResponseService.createDTO(false);
public ResponseEntity<AttributesApplyPhraseToUserDTO> applyPhraseToUser(@RequestBody @Valid AttributesRequest req) {

if (!phraseService.isPhraseValid(req.adverb, req.verb, req.preposition, req.noun)) {
AttributesApplyPhraseToUserDTO rtn = phraseService.constructAttributesApplyPhraseToUserDTO(false,true,false);
sendNotification(rtn, req.userId);
return ResponseEntity.status(HttpStatus.OK).body(rtn);
}
} else {
sendNotification(false, req.userId);
GenericResponseDTO rtn = GenericResponseService.createDTO(false);
return ResponseEntity.status(HttpStatus.OK).body(rtn);
}

AttributesApplyPhraseToUserDTO rtn = phraseService.applyPhraseToUser(req.userId, req.adverb, req.verb, req.preposition, req.noun);
sendNotification(rtn, req.userId);

return ResponseEntity.status(HttpStatus.OK).body(rtn);
}

///api/attributes/?phraseId=xx&userId=xx
Expand All @@ -119,15 +113,18 @@ public ResponseEntity deletePhraseFromUser(@Parameter(description = "Phrase ID o
return ResponseEntity.ok().build();
}

private void sendNotification(Boolean approved, Long userId) {
if (approved) {
private void sendNotification(AttributesApplyPhraseToUserDTO dto, Long userId) {
if (dto.isApproved) {
notificationService.createNotification(
NotificationType.ATTRIBUTE_REQUEST_APPROVED,
userId,
NotificationType.ATTRIBUTE_REQUEST_APPROVED.getName(),
"Your attribute has been approved!");

} else {
} else if (dto.isInReview) {
notificationService.createNotification(NotificationType.ATTRIBUTE_REQUEST_IN_REVIEW, userId, NotificationType.ATTRIBUTE_REQUEST_IN_REVIEW.getName(), "Your attribute will be reviewed.");

} else if (dto.isRejected) {
notificationService.createNotification(
NotificationType.ATTRIBUTE_REQUEST_REJECTED,
userId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.savvato.tribeapp.controllers.annotations.requests.DocumentedRequestBody;
import com.savvato.tribeapp.controllers.annotations.responses.Success;
import com.savvato.tribeapp.controllers.dto.AttributesRequest;
import com.savvato.tribeapp.dto.AttributesApplyPhraseToUserDTO;
import com.savvato.tribeapp.dto.ToBeReviewedDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import java.lang.annotation.*;
Expand All @@ -16,10 +18,5 @@
description = "Provided a valid AttributesRequest (see schemas), apply phrase to user.")
@DocumentedRequestBody(implementation = AttributesRequest.class)
@Success(
description = "Successfully applied phrase",
examples = {
@ExampleObject(name = "Phrase applied successfully", value = "true"),
@ExampleObject(name = "Failed to apply phrase", value = "false"),
@ExampleObject(name = "Phrase was invalid", value = "false")
})
description = "Successfully applied phrase", implementation = AttributesApplyPhraseToUserDTO.class)
public @interface ApplyPhraseToUser {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.savvato.tribeapp.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;

@Builder
@Schema(description = "Result of applying phrase to user")
public class AttributesApplyPhraseToUserDTO {

@Schema(example = "true")
public boolean isApproved;

@Schema(example = "true")
public boolean isRejected;

@Schema(example = "true")
public boolean isInReview;

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
public class NotificationType {

public static final NotificationType ATTRIBUTE_REQUEST_APPROVED = new NotificationType(1L, "Attribute request approved", null);
public static final NotificationType ATTRIBUTE_REQUEST_REJECTED = new NotificationType(1L, "Attribute request rejected", null);
public static final NotificationType ATTRIBUTE_REQUEST_REJECTED = new NotificationType(2L, "Attribute request rejected", null);
public static final NotificationType ATTRIBUTE_REQUEST_IN_REVIEW = new NotificationType(3L, "Attribute request in review", null);

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.savvato.tribeapp.services;

import com.savvato.tribeapp.dto.PhraseDTO;
import com.savvato.tribeapp.dto.AttributesApplyPhraseToUserDTO;

import java.util.Map;
import java.util.Optional;
Expand All @@ -9,9 +10,11 @@ public interface PhraseService {

boolean isPhraseValid(String adverb, String verb, String preposition, String noun);

boolean applyPhraseToUser(Long userId, String adverb, String verb, String preposition, String noun);
AttributesApplyPhraseToUserDTO applyPhraseToUser(Long userId, String adverb, String verb, String preposition, String noun);

Optional<Long> findPreviouslyApprovedPhraseId(String adverb, String verb, String preposition, String noun);

Optional<Map<PhraseDTO, Integer>> getPhraseInformationByUserId(Long userId);

AttributesApplyPhraseToUserDTO constructAttributesApplyPhraseToUserDTO(boolean approved, boolean rejected, boolean inReview);
}
18 changes: 15 additions & 3 deletions src/main/java/com/savvato/tribeapp/services/PhraseServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.savvato.tribeapp.constants.Constants;
import com.savvato.tribeapp.dto.PhraseDTO;
import com.savvato.tribeapp.dto.projections.PhraseWithUserCountDTO;
import com.savvato.tribeapp.dto.AttributesApplyPhraseToUserDTO;
import com.savvato.tribeapp.entities.*;
import com.savvato.tribeapp.repositories.*;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -128,7 +129,7 @@ public boolean isPhrasePreviouslyRejected(String adverb, String verb, String pre
}

@Override
public boolean applyPhraseToUser(Long userId, String adverb, String verb, String preposition, String noun) {
public AttributesApplyPhraseToUserDTO applyPhraseToUser(Long userId, String adverb, String verb, String preposition, String noun) {

String adverbLowerCase = adverb.isBlank() ? Constants.NULL_VALUE_WORD : changeToLowerCase(adverb);
String verbLowerCase = changeToLowerCase(verb);
Expand All @@ -144,7 +145,8 @@ public boolean applyPhraseToUser(Long userId, String adverb, String verb, String
userPhraseRepository.save(userPhrase);
log.info("Phrase added to user " + userId);

return true;
return constructAttributesApplyPhraseToUserDTO(true,false, false);

} else {
Optional<ToBeReviewed> toBeReviewedPhrase = toBeReviewedRepository.findByAdverbAndVerbAndNounAndPreposition(adverbLowerCase, verbLowerCase, nounLowerCase, prepositionLowerCase);

Expand All @@ -166,7 +168,7 @@ public boolean applyPhraseToUser(Long userId, String adverb, String verb, String
log.info("ToBeReviewed phrase has been mapped to user " + userId);
}

return false;
return constructAttributesApplyPhraseToUserDTO(false,false,true);
}
}

Expand Down Expand Up @@ -277,4 +279,14 @@ public PhraseDTO constructPhraseDTOFromPhraseInformation(Long phraseId, Long adv
.build();
}

@Override
public AttributesApplyPhraseToUserDTO constructAttributesApplyPhraseToUserDTO(boolean approved, boolean rejected, boolean inReview){
AttributesApplyPhraseToUserDTO rtn = AttributesApplyPhraseToUserDTO.builder()
.isApproved(approved)
.isRejected(rejected)
.isInReview(inReview)
.build();
return rtn;
}

}
16 changes: 16 additions & 0 deletions src/main/resources/db/migration/changelog-202410031119.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">

<changeSet author="audra" id="202410031119-01">
<insert tableName="notification_type">
<column name="id" value="3"/>
<column name="name" value="Attribute request in review"/>
<column name="icon_url" value="hourglass-outline"/>
</insert>
</changeSet>

</databaseChangeLog>
1 change: 1 addition & 0 deletions src/main/resources/db/migration/changelog-master.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<include file="changelog-202403270537.xml" relativeToChangelogFile="true"/>
<include file="changelog-202404091617.xml" relativeToChangelogFile="true"/>
<include file="changelog-202405071617.xml" relativeToChangelogFile="true"/>
<include file="changelog-202410031119.xml" relativeToChangelogFile="true"/>
<include file="changelog-202410040829.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

Original file line number Diff line number Diff line change
Expand Up @@ -156,29 +156,30 @@ public void applyPhraseToUserWhenPhraseValidAndApplicable() throws Exception {
attributesRequest.noun = NOUN1_WORD;
attributesRequest.preposition = PREPOSITION1_WORD;
String notificationContent = "Your attribute has been approved!";

AttributesApplyPhraseToUserDTO expectedDTO = AttributesApplyPhraseToUserDTO
.builder()
.isApproved(true)
.isRejected(false)
.isInReview(false)
.build();

when(phraseService.isPhraseValid(anyString(), anyString(), anyString(), anyString()))
.thenReturn(true);
when(phraseService.applyPhraseToUser(
anyLong(), anyString(), anyString(), anyString(), anyString()))
.thenReturn(true);
.thenReturn(expectedDTO);
when(notificationService.createNotification(
any(NotificationType.class), anyLong(), anyString(), anyString()))
.thenReturn(null);

final boolean boolResponse = true;
when(GenericResponseService.createDTO(
boolResponse))
.thenReturn(GenericResponseDTO.builder()
.booleanMessage(boolResponse)
.build());

ArgumentCaptor<NotificationType> notificationTypeCaptor =
ArgumentCaptor.forClass(NotificationType.class);
ArgumentCaptor<Long> userIdCaptor = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<String> notificationTypeNameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> notificationContentCaptor = ArgumentCaptor.forClass(String.class);

String expectedMessage = "{\"booleanMessage\":" + true + "}";
String expectedMessage = "{\"isApproved\": true, \"isRejected\": false, \"isInReview\": false}";

this.mockMvc
.perform(
Expand Down Expand Up @@ -219,29 +220,31 @@ public void applyPhraseToUserWhenPhraseValidButNotApplied() throws Exception {
attributesRequest.noun = NOUN1_WORD;
attributesRequest.preposition = PREPOSITION1_WORD;

AttributesApplyPhraseToUserDTO expectedDTO = AttributesApplyPhraseToUserDTO
.builder()
.isApproved(false)
.isRejected(false)
.isInReview(true)
.build();

when(phraseService.isPhraseValid(anyString(), anyString(), anyString(), anyString()))
.thenReturn(true);
when(phraseService.applyPhraseToUser(
anyLong(), anyString(), anyString(), anyString(), anyString()))
.thenReturn(false);
.thenReturn(expectedDTO);
when(notificationService.createNotification(
any(NotificationType.class), anyLong(), anyString(), anyString()))
.thenReturn(null);
final boolean boolResponse = false;
when(GenericResponseService.createDTO(
boolResponse))
.thenReturn(GenericResponseDTO.builder()
.booleanMessage(boolResponse)
.build());

ArgumentCaptor<NotificationType> notificationTypeCaptor =
ArgumentCaptor.forClass(NotificationType.class);
ArgumentCaptor<Long> userIdCaptor = ArgumentCaptor.forClass(Long.class);
ArgumentCaptor<String> notificationTypeNameCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> notificationContentCaptor = ArgumentCaptor.forClass(String.class);
String notificationContent =
"Your attribute was rejected. This attribute is unsuitable and cannot be applied to users.";
"Your attribute will be reviewed.";

String expectedMessage = "{\"booleanMessage\":" + false + "}";
String expectedMessage = "{\"isApproved\": false, \"isRejected\": false, \"isInReview\": true}";

this.mockMvc
.perform(
Expand All @@ -260,11 +263,11 @@ public void applyPhraseToUserWhenPhraseValidButNotApplied() throws Exception {
userIdCaptor.capture(),
notificationTypeNameCaptor.capture(),
notificationContentCaptor.capture());
assertThat(notificationTypeCaptor.getValue()).usingRecursiveComparison().isEqualTo(NotificationType.ATTRIBUTE_REQUEST_REJECTED);
assertThat(notificationTypeCaptor.getValue()).usingRecursiveComparison().isEqualTo(NotificationType.ATTRIBUTE_REQUEST_IN_REVIEW);
assertEquals(userIdCaptor.getValue(), userId);
assertEquals(
notificationTypeNameCaptor.getValue(),
NotificationType.ATTRIBUTE_REQUEST_REJECTED.getName());
NotificationType.ATTRIBUTE_REQUEST_IN_REVIEW.getName());
assertEquals(notificationContentCaptor.getValue(), notificationContent);
}

Expand All @@ -282,17 +285,20 @@ public void applyPhraseToUserWhenPhraseInvalid() throws Exception {
attributesRequest.noun = NOUN1_WORD;
attributesRequest.preposition = PREPOSITION1_WORD;

AttributesApplyPhraseToUserDTO expectedDTO = AttributesApplyPhraseToUserDTO
.builder()
.isApproved(false)
.isRejected(true)
.isInReview(false)
.build();

when(phraseService.isPhraseValid(anyString(), anyString(), anyString(), anyString()))
.thenReturn(false);
when((phraseService.constructAttributesApplyPhraseToUserDTO(anyBoolean(),anyBoolean(),anyBoolean()))).thenReturn(expectedDTO);
when(notificationService.createNotification(
any(NotificationType.class), anyLong(), anyString(), anyString()))
.thenReturn(null);
final boolean boolResponse = false;
when(GenericResponseService.createDTO(
boolResponse))
.thenReturn(GenericResponseDTO.builder()
.booleanMessage(boolResponse)
.build());

ArgumentCaptor<NotificationType> notificationTypeCaptor =
ArgumentCaptor.forClass(NotificationType.class);
ArgumentCaptor<Long> userIdCaptor = ArgumentCaptor.forClass(Long.class);
Expand All @@ -301,7 +307,7 @@ public void applyPhraseToUserWhenPhraseInvalid() throws Exception {
String notificationContent =
"Your attribute was rejected. This attribute is unsuitable and cannot be applied to users.";

String expectedMessage = "{\"booleanMessage\":" + false + "}";
String expectedMessage = "{\"isApproved\": false, \"isRejected\": true, \"isInReview\": false}";

this.mockMvc
.perform(
Expand Down
Loading
Loading