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

Add register student use case #60

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package tv.codely.apps.mooc.backend.controller.students;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import tv.codely.mooc.students.application.register.RegisterStudentRequest;
import tv.codely.mooc.students.application.register.StudentRegistrar;

@RestController
public final class StudentsPutController {

private final StudentRegistrar registrar;

public StudentsPutController(StudentRegistrar registrar) {
this.registrar = registrar;
}

@PutMapping(value = "/students/{id}")
public ResponseEntity<String> index(@PathVariable String id, @RequestBody Request request) {
registrar.register(new RegisterStudentRequest(id, request.name(), request.surname(), request.email()));
return new ResponseEntity<>(HttpStatus.CREATED);
}
}

final class Request {
private String name;
private String surname;
private String email;

String name() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String surname() {
return surname;
}

public void setSurname(String surname) {
this.surname = surname;
}

public String email() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package tv.codely.apps.mooc.backend.controller.students;

import org.junit.jupiter.api.Test;
import tv.codely.apps.mooc.MoocApplicationTestCase;

public final class StudentsPutControllerShould extends MoocApplicationTestCase {
@Test
void register_a_valid_non_existing_student() throws Exception {
assertRequestWithBody(
"PUT",
"/students/1bab45ba-3c7a-4344-8936-78466eca17fa",
"{\"name\": \"some-name\", \"surname\": \"some-surname\", \"email\": \"[email protected]\"}",
201
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ public StudentResponse(String id, String name, String surname, String email) {
}

public static StudentResponse fromAggregate(Student student) {
return new StudentResponse(student.id().value(), student.name(), student.surname(), student.email());
return new StudentResponse(
student.id().value(),
student.name().value(),
student.surname().value(),
student.email().value()
);
}

public String id() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package tv.codely.mooc.students.application.register;

public final class RegisterStudentRequest {
private final String id;
private final String name;
private final String surname;
private final String email;

public RegisterStudentRequest(String id, String name, String surname, String email) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}

public String id() {
return id;
}

public String name() {
return name;
}

public String surname() {
return surname;
}

public String email() {
return email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tv.codely.mooc.students.application.register;

import tv.codely.mooc.students.domain.*;
import tv.codely.shared.domain.Service;

@Service
public class StudentRegistrar {
private final StudentRepository repository;

public StudentRegistrar(StudentRepository repository) {
this.repository = repository;
}

public void register(RegisterStudentRequest request) {
Student student = Student.create(
new StudentId(request.id()),
new StudentName(request.name()),
new StudentSurname(request.surname()),
new StudentEmail(request.email())
);
repository.register(student);
}
}
38 changes: 30 additions & 8 deletions src/mooc/main/tv/codely/mooc/students/domain/Student.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,53 @@
package tv.codely.mooc.students.domain;

import java.util.Objects;

public final class Student {
private final StudentId id;
private final String name;
private final String surname;
private final String email;
private final StudentId id;
private final StudentName name;
private final StudentSurname surname;
private final StudentEmail email;

public Student(StudentId id, String name, String surname, String email) {
public Student(StudentId id, StudentName name, StudentSurname surname, StudentEmail email) {
this.id = id;
this.name = name;
this.surname = surname;
this.email = email;
}

public static Student create(StudentId id, StudentName name, StudentSurname surname, StudentEmail email) {
return new Student(id, name, surname, email);
}

public StudentId id() {
return id;
}

public String name() {
public StudentName name() {
return name;
}

public String surname() {
public StudentSurname surname() {
return surname;
}

public String email() {
public StudentEmail email() {
return email;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return id.equals(student.id) &&
name.equals(student.name) &&
surname.equals(student.surname) &&
email.equals(student.email);
}

@Override
public int hashCode() {
return Objects.hash(id, name, surname, email);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tv.codely.mooc.students.domain;

import tv.codely.shared.domain.EmailValueObject;

public final class StudentEmail extends EmailValueObject {
public StudentEmail(String email) {
super(email);
}
}
9 changes: 9 additions & 0 deletions src/mooc/main/tv/codely/mooc/students/domain/StudentName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tv.codely.mooc.students.domain;

import tv.codely.shared.domain.StringValueObject;

public final class StudentName extends StringValueObject {
public StudentName(String value) {
super(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
import java.util.List;

public interface StudentRepository {
void register(Student student);
List<Student> searchAll();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tv.codely.mooc.students.domain;

import tv.codely.shared.domain.StringValueObject;

public final class StudentSurname extends StringValueObject {
public StudentSurname(String value) {
super(value);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package tv.codely.mooc.students.infrastructure;

import tv.codely.mooc.students.domain.Student;
import tv.codely.mooc.students.domain.StudentId;
import tv.codely.mooc.students.domain.StudentRepository;
import tv.codely.mooc.students.domain.*;
import tv.codely.shared.domain.Service;
import tv.codely.shared.domain.UuidGenerator;

Expand All @@ -20,8 +18,22 @@ public InMemoryStudentRepository(UuidGenerator generator) {
@Override
public List<Student> searchAll() {
return Arrays.asList(
new Student(new StudentId(generator.generate()), "name", "surname", "[email protected]"),
new Student(new StudentId(generator.generate()), "Other name", "Other surname", "[email protected]")
new Student(
new StudentId(generator.generate()),
new StudentName("name"),
new StudentSurname("surname"),
new StudentEmail("[email protected]")
),
new Student(
new StudentId(generator.generate()),
new StudentName("Other name"),
new StudentSurname("Other surname"),
new StudentEmail("[email protected]")
)
);
}

@Override
public void register(Student student) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package tv.codely.mooc.students.application.register;

import org.junit.jupiter.api.Test;
import tv.codely.mooc.students.domain.*;
import tv.codely.shared.domain.UuidMother;

import static org.mockito.Mockito.*;

final class StudentRegistrarTestShould {
@Test
void register_a_valid_student() {
StudentRepository repository = mock(StudentRepository.class);
StudentRegistrar registrar = new StudentRegistrar(repository);

StudentId id = new StudentId(UuidMother.random());
StudentName name = new StudentName("name");
StudentSurname surname = new StudentSurname("surname");
StudentEmail email = new StudentEmail("[email protected]");

RegisterStudentRequest request = new RegisterStudentRequest(
id.value(), name.value(), surname.value(), email.value()
);

Student student = new Student(id, name, surname, email);

registrar.register(request);

verify(repository, atLeastOnce()).register(student);
}
}
47 changes: 47 additions & 0 deletions src/shared/main/tv/codely/shared/domain/EmailValueObject.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package tv.codely.shared.domain;

import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;

import java.util.Objects;

public abstract class EmailValueObject {
private static final EmailValidator emailValidator = new EmailValidator();
Copy link
Author

@OctaviPascual OctaviPascual Nov 10, 2020

Choose a reason for hiding this comment

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

I think a better approach would be to create an EmailValidator interface to not contaminate our domain with this dependency, but I tried to do it and I didn't manage to inject the implementation into this abstract class. Is it possible to do it?

private final String email;

public EmailValueObject(String email) {
ensureValidEmail(email);
this.email = email;
}

public String value() {
return email;
}

private void ensureValidEmail(String value) {
if (!emailValidator.isValid(value, null)) {
throw new InvalidEmail(value);
}
}

@Override
public String toString() {
return this.value();
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof EmailValueObject)) {
return false;
}
EmailValueObject that = (EmailValueObject) o;
return Objects.equals(email, that.email);
}

@Override
public int hashCode() {
return Objects.hash(email);
}
}
7 changes: 7 additions & 0 deletions src/shared/main/tv/codely/shared/domain/InvalidEmail.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package tv.codely.shared.domain;

public final class InvalidEmail extends DomainError {
public InvalidEmail(String email) {
super("invalid_email", String.format("The email <%s> is invalid", email));
}
}