Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@
<artifactId>loki-logback-appender</artifactId>
<version>1.5.2</version>
</dependency> -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.patinanetwork.patchats.api.member.dto.CreateMemberRequest;
import org.patinanetwork.patchats.api.member.dto.MemberDto;
import org.patinanetwork.patchats.api.member.dto.UpdateMemberRequest;
import org.patinanetwork.patchats.common.dto.ApiResponder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -26,13 +30,12 @@ public ResponseEntity<ApiResponder<MemberDto>> createMember(@Valid @RequestBody
return ResponseEntity.ok(ApiResponder.success("Member created successfully", response));
}

// TODO: Implement these endpoints after createMember is fully functional and tested
// @PatchMapping("/{id}")
// public ResponseEntity<ApiResponder<MemberDto>> updateMember(
// @Valid @RequestBody final UpdateMemberRequest request, @PathVariable final UUID id) {
// final MemberDto response = memberService.updateMember(request, id);
// return ResponseEntity.ok(ApiResponder.success("Member updated successfully", response));
// }
@PatchMapping("/{id}")
public ResponseEntity<ApiResponder<MemberDto>> updateMember(
@Valid @RequestBody final UpdateMemberRequest request, @PathVariable final UUID id) {
final MemberDto response = memberService.updateMember(request, id);
return ResponseEntity.ok(ApiResponder.success("Member updated successfully", response));
}

// @GetMapping("/{id}")
// public ResponseEntity<ApiResponder<MemberDto>> getMember(@PathVariable final UUID id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.patinanetwork.patchats.api.member;

import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import lombok.RequiredArgsConstructor;
import org.patinanetwork.patchats.api.member.db.models.Member;
import org.patinanetwork.patchats.api.member.db.repos.MemberRepo;
Expand All @@ -10,6 +12,7 @@
import org.patinanetwork.patchats.api.member.dto.UpdateMemberRequest;
import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException;
import org.patinanetwork.patchats.common.web.exception.MemberNotFoundException;
import org.patinanetwork.patchats.common.web.exception.ValidationException;
import org.springframework.stereotype.Service;

@Service
Expand Down Expand Up @@ -48,40 +51,53 @@ public List<MemberDto> getMembers() {
public MemberDto updateMember(UpdateMemberRequest request, UUID id) {
Member member = memberRepo.getMemberById(id).orElseThrow(() -> new MemberNotFoundException(id));

if (request.firstName() != null) {
member.setFirstName(request.firstName());
}
if (request.lastName() != null) {
member.setLastName(request.lastName());
}
if (request.email() != null) {
member.setEmail(request.email());
}
if (request.linkedInUrl() != null) {
member.setLinkedInUrl(request.linkedInUrl());
}
if (request.introduction() != null) {
member.setIntroduction(request.introduction());
}
if (request.matchPref() != null) {
member.setMatchPref(request.matchPref());
}
if (request.industryPref() != null) {
member.setIndustryPref(request.industryPref());
}
if (request.rolePref() != null) {
member.setRolePref(request.rolePref());
}
if (request.topics() != null) {
member.setTopics(request.topics());
}
if (request.extraNotes() != null) {
member.setExtraNotes(request.extraNotes());
}
validateAndUpdateRequired(member, request);
updateOptional(member, request);

Member updatedMember = memberRepo.updateMember(member).orElseThrow(() -> new MemberNotFoundException(id));
return MemberDto.from(updatedMember);
}

private void validateAndUpdateRequired(Member member, UpdateMemberRequest request) {
validateAndUpdate(request.firstName(), member::setFirstName, "firstName");
validateAndUpdate(request.lastName(), member::setLastName, "lastName");
validateAndUpdateEmail(member, request);
validateAndUpdate(request.introduction(), member::setIntroduction, "introduction");
}

private void validateAndUpdate(Optional<String> field, Consumer<String> setter, String fieldName) {
if (field.isPresent()) {
String value = field.get();
if (value.isBlank()) {
throw new ValidationException(fieldName + " cannot be empty");
}
setter.accept(value);
}
}

private void validateAndUpdateEmail(Member member, UpdateMemberRequest request) {
if (request.email().isPresent()) {
String email = request.email().get();
if (email.isBlank()) {
throw new ValidationException("email cannot be empty");
}
if (!email.equals(member.getEmail())
&& memberRepo.getMemberByEmail(email).isPresent()) {
throw new MemberDuplicateException(email);
}
member.setEmail(email);
}
}

private void updateOptional(Member member, UpdateMemberRequest request) {
request.linkedInUrl().ifPresent(member::setLinkedInUrl);
request.matchPref().ifPresent(member::setMatchPref);
request.industryPref().ifPresent(member::setIndustryPref);
request.rolePref().ifPresent(member::setRolePref);
request.topics().ifPresent(member::setTopics);
request.extraNotes().ifPresent(member::setExtraNotes);
}

// TODO: Implement these methods after createMember and updateMember is fully functional and tested
// public MemberDto getMemberById(UUID id) {
// return memberRepo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,22 @@ private Member parseResultSetToMember(final ResultSet rs) throws SQLException {
.build();
}

private JdbcClient.StatementSpec bindMemberParams(JdbcClient.StatementSpec spec, Member member) {
return spec.param("id", member.getId())
.param("first_name", member.getFirstName())
.param("last_name", member.getLastName())
.param("email", member.getEmail())
.param("linked_in_url", member.getLinkedInUrl())
.param("introduction", member.getIntroduction())
.param("referral_source", member.getReferralSource())
.param("active", member.isActive())
.param("match_pref", member.getMatchPref())
.param("industry_pref", member.getIndustryPref())
.param("role_pref", member.getRolePref())
.param("topics", member.getTopics())
.param("extra_notes", member.getExtraNotes());
}

@Override
public Member createMember(Member member) {
String sql = """
Expand Down Expand Up @@ -73,20 +89,7 @@ public Member createMember(Member member) {
RETURNING
*
""";
return jdbc.sql(sql)
.param("id", member.getId())
.param("first_name", member.getFirstName())
.param("last_name", member.getLastName())
.param("email", member.getEmail())
.param("linked_in_url", member.getLinkedInUrl())
.param("introduction", member.getIntroduction())
.param("referral_source", member.getReferralSource())
.param("active", member.isActive())
.param("match_pref", member.getMatchPref())
.param("industry_pref", member.getIndustryPref())
.param("role_pref", member.getRolePref())
.param("topics", member.getTopics())
.param("extra_notes", member.getExtraNotes())
return bindMemberParams(jdbc.sql(sql), member)
.query((rs, rowNum) -> parseResultSetToMember(rs))
.single();
}
Expand All @@ -99,12 +102,36 @@ public List<Member> getMembers() {

@Override
public Optional<Member> updateMember(Member member) {
throw new UnsupportedOperationException("Not implemented yet");
String sql = """
UPDATE "members" SET
"first_name" = :first_name,
"last_name" = :last_name,
"email" = :email,
"linked_in_url" = :linked_in_url,
"introduction" = :introduction,
"referral_source" = :referral_source,
"active" = :active,
"match_pref" = :match_pref,
"industry_pref" = :industry_pref,
"role_pref" = :role_pref,
"topics" = :topics,
"extra_notes" = :extra_notes,
"updated_at" = NOW()
WHERE "id" = :id
RETURNING *
""";
return bindMemberParams(jdbc.sql(sql), member)
.query((rs, rowNum) -> parseResultSetToMember(rs))
.optional();
}

@Override
public Optional<Member> getMemberById(UUID id) {
throw new UnsupportedOperationException("Not implemented yet");
String sql = "SELECT * FROM members WHERE id = :id";
return jdbc.sql(sql)
.param("id", id)
.query((rs, rowNum) -> parseResultSetToMember(rs))
.optional();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package org.patinanetwork.patchats.api.member.dto;

import jakarta.validation.constraints.Email;
import java.util.Optional;

public record UpdateMemberRequest(
String firstName,
String lastName,
// TODO: Changes to email require verification after authentication is implemented
@Email String email,
String linkedInUrl,
String introduction,
String matchPref,
String industryPref,
String rolePref,
String topics,
String extraNotes) {}
Optional<String> firstName,
Optional<String> lastName,
Optional<@Email String> email,
Optional<String> linkedInUrl,
Optional<String> introduction,
Optional<String> matchPref,
Optional<String> industryPref,
Optional<String> rolePref,
Optional<String> topics,
Optional<String> extraNotes) {}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.patinanetwork.patchats.common.dto.ApiResponder;
import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException;
import org.patinanetwork.patchats.common.web.exception.MemberNotFoundException;
import org.patinanetwork.patchats.common.web.exception.ValidationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
Expand Down Expand Up @@ -34,6 +35,11 @@ public ResponseEntity<ApiResponder<Void>> handleMemberDuplicate(final MemberDupl
return ResponseEntity.status(HttpStatus.CONFLICT).body(ApiResponder.failure(ex.getMessage()));
}

@ExceptionHandler(ValidationException.class)
public ResponseEntity<ApiResponder<Void>> handleValidation(ValidationException ex) {
return ResponseEntity.badRequest().body(ApiResponder.failure(ex.getMessage()));
}

private String formatError(final FieldError error) {
return error.getField() + " " + error.getDefaultMessage();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.patinanetwork.patchats.common.web.exception;

public class ValidationException extends RuntimeException {
public ValidationException(String message) {
super(message);
}

public ValidationException(String message, Throwable cause) {
super(message, cause);
}
}
Loading
Loading