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

create EndorsementController #41

Merged
merged 35 commits into from
Dec 31, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0fdea86
create EndorsementController
bhtibrewal Nov 23, 2023
9a89d07
add env to ignore
bhtibrewal Nov 23, 2023
0d0aa10
add DTO and DROs
bhtibrewal Nov 24, 2023
3175cc6
de.env
bhtibrewal Nov 25, 2023
c9af284
merge branch update_model
bhtibrewal Nov 25, 2023
e90b5f2
create EndorsementListController
bhtibrewal Nov 25, 2023
d1faad5
remove EndorsementListController
bhtibrewal Nov 26, 2023
c0e211e
add EndorsementServiceTest.java
bhtibrewal Nov 26, 2023
39cf6f9
Merge branch 'develop' into postEndorsementAPI
bhtibrewal Nov 26, 2023
1f6c2d4
add JsonManagedReference
bhtibrewal Dec 1, 2023
ca1b171
Merge remote-tracking branch 'origin/postEndorsementAPI' into postEnd…
bhtibrewal Dec 1, 2023
0fde179
address some review comments
bhtibrewal Dec 4, 2023
a8a2e5e
added validation checks
bhtibrewal Dec 5, 2023
e867d0f
remove extra entries in EndorsementDRO.java
bhtibrewal Dec 6, 2023
be11ae5
handle NoEntityException
bhtibrewal Dec 6, 2023
2b17be2
add DB_NAME variable in application.properties
bhtibrewal Dec 6, 2023
3cacabe
handle exceptions in one catch block
bhtibrewal Dec 6, 2023
2e8bbe0
made ApiResponse class
bhtibrewal Dec 6, 2023
2084c09
handle NoEntityException exception globally
bhtibrewal Dec 6, 2023
d89effd
remove default false
bhtibrewal Dec 7, 2023
ba72dd8
Merge branch 'develop' of https://github.com/Real-Dev-Squad/skill-tre…
bhtibrewal Dec 29, 2023
08bf445
merge the tests
bhtibrewal Dec 29, 2023
77f7110
delete usused files
bhtibrewal Dec 29, 2023
5742947
fix build, add missing imports
bhtibrewal Dec 29, 2023
c5a09ca
fix EndorsementListServiceTest
bhtibrewal Dec 30, 2023
f4cbbbd
fix testCreateEndorsement test
bhtibrewal Dec 30, 2023
05237e6
revert change
bhtibrewal Dec 30, 2023
717f24d
add integration test
bhtibrewal Dec 30, 2023
eae68d5
update integration test
bhtibrewal Dec 30, 2023
9ed6eb3
update integration test
bhtibrewal Dec 30, 2023
f3f9894
revert integration test
bhtibrewal Dec 30, 2023
bb7ae49
fix integration test
bhtibrewal Dec 31, 2023
2fab76d
use GenericResponse
bhtibrewal Dec 31, 2023
3acd3d5
fix return type
bhtibrewal Dec 31, 2023
d90443f
change endorsementModel to EndorsementDTO.toDto
bhtibrewal Dec 31, 2023
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
2 changes: 2 additions & 0 deletions skill-tree /.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ build/

### VS Code ###
.vscode/
ad/.env
/.env
4 changes: 4 additions & 0 deletions skill-tree /pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.RDS.skilltree.Endorsement;

import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1")
public class EndorsementController {
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
@Autowired
private EndorsementService endorsementService;


@PostMapping("/endorsement")
public ResponseEntity<?> postEndorsement(@RequestBody @Valid EndorsementDRO endorsementDRO) {
try {
EndorsementModel endorsementModel = endorsementService.createEndorsement(endorsementDRO);
if (endorsementModel != null)
return new ResponseEntity<>(endorsementModel, HttpStatus.CREATED);
return new ResponseEntity<>("Failed to create endorsement", HttpStatus.BAD_REQUEST);

} catch (IllegalArgumentException e) {
String message = e.getMessage();
return new ResponseEntity<>(message, HttpStatus.NOT_FOUND);
}
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.RDS.skilltree.Endorsement;

import com.RDS.skilltree.EndorsementList.EndorsementType;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.UUID;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class EndorsementDRO {
@NotNull(message = "user id cannot be null")
private UUID userId;
@NotNull(message = "skill id cannot be null")
private UUID skillId;
private String description;
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
private UUID endorsementId;
private UUID endorserId;
private EndorsementType type;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.RDS.skilltree.Endorsement;

import com.RDS.skilltree.EndorsementList.EndorsementListModel;
import com.RDS.skilltree.Skill.SkillModel;
import com.RDS.skilltree.User.UserModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.UUID;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class EndorsementDTO {
bhtibrewal marked this conversation as resolved.
Show resolved Hide resolved

private UUID id;
private UserModel endorseId;
private SkillModel skill;
private List<EndorsementListModel> endorsersList;
private EndorsementStatus status;
private UserModel createdBy;

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.RDS.skilltree.Skill.SkillModel;
import com.RDS.skilltree.User.UserModel;
import com.RDS.skilltree.utils.TrackedProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
Expand Down Expand Up @@ -32,7 +33,9 @@ public class EndorsementModel extends TrackedProperties {
@JoinColumn(name = "skill_id", referencedColumnName = "id")
private SkillModel skill;

@OneToMany(mappedBy = "endorsement")
@OneToMany()
@JoinColumn(name = "endorsement_id", referencedColumnName = "id")
@JsonManagedReference
private List<EndorsementListModel> endorsersList = new ArrayList<>();

@Column(name = "endorsement_status")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.RDS.skilltree.Endorsement;

import com.RDS.skilltree.Exceptions.NoEntityException;
import com.RDS.skilltree.Skill.SkillModel;
import com.RDS.skilltree.Skill.SkillRepository;
import com.RDS.skilltree.User.UserModel;
import com.RDS.skilltree.User.UserRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.UUID;

@Service
public class EndorsementService {
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
private final EndorsementRepository endorsementRepository;
private final UserRepository userRepository;
private final SkillRepository skillRepository;

public EndorsementService(EndorsementRepository endorsementRepository, UserRepository userRepository, SkillRepository skillRepository) {
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
this.endorsementRepository = endorsementRepository;
this.userRepository = userRepository;
this.skillRepository = skillRepository;
}

public EndorsementModel createEndorsement(EndorsementDRO endorsementDRO) {
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
UUID userId = endorsementDRO.getUserId();
UUID skillId = endorsementDRO.getSkillId();
Optional<UserModel> userOptional = userRepository.findById(userId);
Optional<SkillModel> skillOptional = skillRepository.findById(skillId);
EndorsementModel endorsementModel = new EndorsementModel();
if (userOptional.isPresent() && skillOptional.isPresent()) {
endorsementModel.setUser(userOptional.get());
endorsementModel.setSkill(skillOptional.get());
return endorsementRepository.save(endorsementModel);
} else {
if (userOptional.isEmpty())
throw new NoEntityException("User with id:" + userId + " not found");
throw new NoEntityException("Skill with id:" + skillId + " not found");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.RDS.skilltree.EndorsementList;

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

import java.util.UUID;

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class EndorsementListDRO {
private String description;
private UUID endorsementId;
private UUID endorserId;
private EndorsementType type;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.RDS.skilltree.EndorsementList;

import com.RDS.skilltree.User.UserModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.util.UUID;

@Builder
@Data
@AllArgsConstructor
public class EndorsementListDTO {
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
private UUID id;
private String description;
private UserModel endorser;
private EndorsementType type;

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.RDS.skilltree.Endorsement.EndorsementModel;
import com.RDS.skilltree.User.UserModel;
import com.RDS.skilltree.utils.TrackedProperties;
import com.fasterxml.jackson.annotation.JsonBackReference;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
Expand All @@ -23,6 +24,7 @@ public class EndorsementListModel extends TrackedProperties {

@JoinColumn(name = "endorsement_id", referencedColumnName = "id")
@ManyToOne(targetEntity = EndorsementModel.class, cascade = CascadeType.ALL)
@JsonBackReference
private EndorsementModel endorsement;

@JoinColumn(name = "user_id", referencedColumnName = "id")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.RDS.skilltree.EndorsementList;

import com.RDS.skilltree.Endorsement.EndorsementModel;
import com.RDS.skilltree.Endorsement.EndorsementRepository;
import com.RDS.skilltree.Exceptions.NoEntityException;
import com.RDS.skilltree.User.UserModel;
import com.RDS.skilltree.User.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.UUID;

@Service
public class EndorsementListService {
@Autowired
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
private final EndorsementListRepository endorsementListRepository;
private final EndorsementRepository endorsementRepository;
private final UserRepository userRepository;

public EndorsementListService(EndorsementListRepository endorsementListRepository, EndorsementRepository endorsementRepository, UserRepository userRepository) {
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
this.endorsementListRepository = endorsementListRepository;
this.endorsementRepository = endorsementRepository;
this.userRepository = userRepository;
}


public EndorsementListModel createEndorsementListEntry(EndorsementListDRO endorsementListDRO) {
EndorsementListModel endorsementListEntry = new EndorsementListModel();

UUID endorserId = endorsementListDRO.getEndorserId();
UUID endorsementId = endorsementListDRO.getEndorsementId();
Optional<UserModel> endorserOptional = userRepository.findById(endorserId);
Optional<EndorsementModel> endorsementOptional = endorsementRepository.findById(endorsementId);
if (endorserOptional.isPresent() && endorsementOptional.isPresent()) {

endorsementListEntry.setEndorser(endorserOptional.get());
endorsementListEntry.setEndorsement(endorsementOptional.get());
endorsementListEntry.setDescription(endorsementListDRO.getDescription());
endorsementListEntry.setType(endorsementListDRO.getType());
endorsementListRepository.save(endorsementListEntry);
return endorsementListEntry;

} else {
if (endorserOptional.isEmpty())
throw new NoEntityException("User with id:" + endorserId + " not found");
throw new NoEntityException("Endorsement with id:" + endorsementId + " not found");
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.RDS.skilltree.Exceptions;

import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
Map<String, List<String>> body = new HashMap<>();

List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.toList());

body.put("errors", errors);

return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.RDS.skilltree.Exceptions;

public class NoEntityException extends RuntimeException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why this is a RuntimeException and not Exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An Exception is checked, and a RuntimeException is unchecked.

Checked means that the compiler requires that you handle the exception in a catch, or declare your method as throwing it (or one of its superclasses).

Generally, throw a checked exception if the caller of the API is expected to handle the exception, and an unchecked exception if it is something the caller would not normally be able to handle, such as an error with one of the parameters, i.e. a programming mistake.

So here we are using these error to throw error for things the caller API couldn't have checked before hand like, "no user foiund for this user id " etc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bhtibrewal and @debanjanc01 what about overwriting the stack trace in case of check and un-checked (question for both)

Copy link
Contributor

@debanjanc01 debanjanc01 Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iamitprakash if you're talking about custom exceptions, then in my opinion it depends on how the exception is being used.

If it's Exceptions that ultimately propagates directly to the Controller and is handled by a global exception handler, then the stack trace can be suppressed. The assumption here is that the exception handler will be sending the correct response to the API caller.

If it's Exceptions that are being used internally, and handled via Catch statements, we might want to error log with the stacktrace.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't the knowledge on this topic, need to read more


public NoEntityException(String message) {
super(message);
}

public NoEntityException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class SkillModel extends TrackedProperties {
private SkillType type = SkillType.ATOMIC;

@Column(name = "is_deleted", nullable = false)
private boolean deleted;
private boolean deleted = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't boolean false by default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes thanks for pointing out wasn't aware, removed it


@JsonBackReference
@JsonIgnore
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.RDS.skilltree.User;

public class UserController {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any use for this class?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is there in different PR, we can remove this @bhtibrewal

}
4 changes: 2 additions & 2 deletions skill-tree /src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/skilltree
iamitprakash marked this conversation as resolved.
Show resolved Hide resolved
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.datasource.username=${MYSQL_DB_USERNAME}
spring.datasource.password=${MYSQL_DB_PASSWORD}
spring.datasource.username=${MYSQL_USERNAME}
spring.datasource.password=${MYSQL_PASSWORD}
spring.jpa.hibernate.ddl-auto=update

Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.RDS.skilltree;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.springframework.beans.factory.annotation.Autowired;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;

public class EndorsementsIntegrationTests {
@Autowired
private ObjectMapper objectMapper;

@Before
public void setup() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package com.RDS.skilltree;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class SkillTreeApplicationTests {

@Test
void contextLoads() {
}

}
Loading