diff --git a/apps/main/tv/codely/apps/mooc/controller/students/Request.java b/apps/main/tv/codely/apps/mooc/controller/students/Request.java new file mode 100644 index 00000000..1ba67907 --- /dev/null +++ b/apps/main/tv/codely/apps/mooc/controller/students/Request.java @@ -0,0 +1,22 @@ +package tv.codely.apps.mooc.controller.students; + +public class Request { + private String name; + private String email; + + public String name() { + return name; + } + + public String email() { + return email; + } + + public void setEmail(String surname) { + this.email = surname; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/apps/main/tv/codely/apps/mooc/controller/students/StudentsPutController.java b/apps/main/tv/codely/apps/mooc/controller/students/StudentsPutController.java new file mode 100644 index 00000000..afe34168 --- /dev/null +++ b/apps/main/tv/codely/apps/mooc/controller/students/StudentsPutController.java @@ -0,0 +1,29 @@ +package tv.codely.apps.mooc.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.create.StudentCreator; +import tv.codely.mooc.students.application.create.StudentCreatorRequest; + +@RestController +public class StudentsPutController { + + private final StudentCreator creator; + + public StudentsPutController(StudentCreator creator) { + this.creator = creator; + } + + @PutMapping("/students/{id}") + public ResponseEntity create(@PathVariable String id, @RequestBody Request request) { + StudentCreatorRequest studentCreatorRequest = new StudentCreatorRequest(id, request.name(), request.email()); + + creator.create(studentCreatorRequest); + + return new ResponseEntity<>(HttpStatus.CREATED); + } +} diff --git a/apps/test/tv/codely/apps/mooc/controller/students/StudentsPutControllerShould.java b/apps/test/tv/codely/apps/mooc/controller/students/StudentsPutControllerShould.java new file mode 100644 index 00000000..28229b3e --- /dev/null +++ b/apps/test/tv/codely/apps/mooc/controller/students/StudentsPutControllerShould.java @@ -0,0 +1,17 @@ +package tv.codely.apps.mooc.controller.students; + +import org.junit.jupiter.api.Test; +import tv.codely.apps.mooc.controller.RequestTestCase; + +public class StudentsPutControllerShould extends RequestTestCase { + + @Test + public void create_a_valid_non_existing_student() throws Exception { + assertRequestWithBody( + "PUT", + "/students/1aab45ba-3c7a-4344-8936-78466eca77fa", + "{\"name\": \"The best student\", \"email\": \"example@example.com\"}", + 201); + } + +} diff --git a/src/mooc/main/tv/codely/mooc/students/application/create/StudentCreator.java b/src/mooc/main/tv/codely/mooc/students/application/create/StudentCreator.java new file mode 100644 index 00000000..9355a15b --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/application/create/StudentCreator.java @@ -0,0 +1,22 @@ +package tv.codely.mooc.students.application.create; + +import tv.codely.mooc.courses.domain.Course; +import tv.codely.mooc.students.domain.*; +import tv.codely.shared.domain.Service; + +@Service +public class StudentCreator { + private final StudentRepository repository; + + public StudentCreator(StudentRepository repository) { + this.repository = repository; + } + + public void create(StudentCreatorRequest request) { + StudentId id = new StudentId(request.id()); + StudentName name = new StudentName(request.name()); + StudentEmail email = new StudentEmail(request.email()); + + repository.save(new Student(id, name, email)); + } +} diff --git a/src/mooc/main/tv/codely/mooc/students/application/create/StudentCreatorRequest.java b/src/mooc/main/tv/codely/mooc/students/application/create/StudentCreatorRequest.java new file mode 100644 index 00000000..f5c1d43b --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/application/create/StudentCreatorRequest.java @@ -0,0 +1,25 @@ +package tv.codely.mooc.students.application.create; + +public class StudentCreatorRequest { + private final String id; + private final String name; + private final String email; + + public StudentCreatorRequest(String id, String name, String email) { + this.id = id; + this.name = name; + this.email = email; + } + + public String id() { + return id; + } + + public String name() { + return name; + } + + public String email() { + return email; + } +} diff --git a/src/mooc/main/tv/codely/mooc/students/domain/Student.java b/src/mooc/main/tv/codely/mooc/students/domain/Student.java new file mode 100644 index 00000000..afcf0c5a --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/domain/Student.java @@ -0,0 +1,40 @@ +package tv.codely.mooc.students.domain; + +public class Student { + private StudentId id; + private StudentName name; + private StudentEmail email; + + public Student(StudentId id, StudentName name, StudentEmail email) { + this.id = id; + this.name = name; + this.email = email; + } + + public StudentId id() { + return id; + } + + public StudentName name() { + return name; + } + + public StudentEmail email() { + return email; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Student)) return false; + + Student student = (Student) o; + + return id.equals(student.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/src/mooc/main/tv/codely/mooc/students/domain/StudentEmail.java b/src/mooc/main/tv/codely/mooc/students/domain/StudentEmail.java new file mode 100644 index 00000000..65db052b --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/domain/StudentEmail.java @@ -0,0 +1,9 @@ +package tv.codely.mooc.students.domain; + +import tv.codely.shared.domain.EmailValueObject; + +public class StudentEmail extends EmailValueObject { + public StudentEmail(String value) { + super(value); + } +} diff --git a/src/mooc/main/tv/codely/mooc/students/domain/StudentId.java b/src/mooc/main/tv/codely/mooc/students/domain/StudentId.java new file mode 100644 index 00000000..bf4eb9d9 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/domain/StudentId.java @@ -0,0 +1,9 @@ +package tv.codely.mooc.students.domain; + +import tv.codely.shared.domain.Identifier; + +public class StudentId extends Identifier { + public StudentId(String value) { + super(value); + } +} diff --git a/src/mooc/main/tv/codely/mooc/students/domain/StudentName.java b/src/mooc/main/tv/codely/mooc/students/domain/StudentName.java new file mode 100644 index 00000000..8cf59f64 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/domain/StudentName.java @@ -0,0 +1,9 @@ +package tv.codely.mooc.students.domain; + +import tv.codely.shared.domain.StringValueObject; + +public class StudentName extends StringValueObject { + public StudentName(String value) { + super(value); + } +} diff --git a/src/mooc/main/tv/codely/mooc/students/domain/StudentRepository.java b/src/mooc/main/tv/codely/mooc/students/domain/StudentRepository.java new file mode 100644 index 00000000..e6f3bbe9 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/domain/StudentRepository.java @@ -0,0 +1,9 @@ +package tv.codely.mooc.students.domain; + +import java.util.Optional; + +public interface StudentRepository { + void save(Student student); + + Optional search(StudentId id); +} diff --git a/src/mooc/main/tv/codely/mooc/students/infrastructure/persistence/InMemoryStudentRepository.java b/src/mooc/main/tv/codely/mooc/students/infrastructure/persistence/InMemoryStudentRepository.java new file mode 100644 index 00000000..df93eda2 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/students/infrastructure/persistence/InMemoryStudentRepository.java @@ -0,0 +1,23 @@ +package tv.codely.mooc.students.infrastructure.persistence; + +import tv.codely.mooc.students.domain.Student; +import tv.codely.mooc.students.domain.StudentId; +import tv.codely.mooc.students.domain.StudentRepository; +import tv.codely.shared.domain.Service; + +import java.util.HashMap; +import java.util.Optional; + +@Service +public class InMemoryStudentRepository implements StudentRepository { + private final HashMap students = new HashMap<>(); + + public void save(Student student) { + students.put(student.id().value(), student); + } + + @Override + public Optional search(StudentId id) { + return Optional.ofNullable(students.get(id.value())); + } +} diff --git a/src/mooc/test/tv/codely/mooc/students/application/create/StudentCreatorTest.java b/src/mooc/test/tv/codely/mooc/students/application/create/StudentCreatorTest.java new file mode 100644 index 00000000..d9546c79 --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/students/application/create/StudentCreatorTest.java @@ -0,0 +1,29 @@ +package tv.codely.mooc.students.application.create; + +import org.junit.jupiter.api.Test; +import tv.codely.mooc.students.domain.*; + +import static org.mockito.Mockito.*; +public class StudentCreatorTest { + + @Test + public void create_a_valid_student() { + StudentRepository repository = mock(StudentRepository.class); + StudentCreator creator = new StudentCreator(repository); + StudentCreatorRequest creatorRequest = new StudentCreatorRequest( + "decf33ca-81a7-419f-a07a-74f214e928e5", + "name", + "example@example.com"); + + Student student = new Student( + new StudentId(creatorRequest.id()), + new StudentName(creatorRequest.name()), + new StudentEmail(creatorRequest.email()) + ); + + creator.create(creatorRequest); + + verify(repository, atLeastOnce()).save(student); + } + +} diff --git a/src/mooc/test/tv/codely/mooc/students/infrastructure/persistence/InMemoryStudentRepositoryTest.java b/src/mooc/test/tv/codely/mooc/students/infrastructure/persistence/InMemoryStudentRepositoryTest.java new file mode 100644 index 00000000..b9538900 --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/students/infrastructure/persistence/InMemoryStudentRepositoryTest.java @@ -0,0 +1,49 @@ +package tv.codely.mooc.students.infrastructure.persistence; + +import org.junit.jupiter.api.Test; +import tv.codely.mooc.students.domain.Student; +import tv.codely.mooc.students.domain.StudentEmail; +import tv.codely.mooc.students.domain.StudentId; +import tv.codely.mooc.students.domain.StudentName; + +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class InMemoryStudentRepositoryTest { + + @Test + void save_a_student() { + InMemoryStudentRepository repository = new InMemoryStudentRepository(); + Student student = new Student( + new StudentId(UUID.randomUUID().toString()), + new StudentName("name"), + new StudentEmail("email@sad.com") + ); + + repository.save(student); + } + + @Test + void return_an_existing_student() { + InMemoryStudentRepository repository = new InMemoryStudentRepository(); + Student student = new Student( + new StudentId(UUID.randomUUID().toString()), + new StudentName("name"), + new StudentEmail("as@d.com")); + + repository.save(student); + + assertEquals(Optional.of(student), repository.search(student.id())); + } + + @Test + void not_return_a_non_existing_student() { + InMemoryStudentRepository repository = new InMemoryStudentRepository(); + + assertFalse(repository.search(new StudentId( + UUID.randomUUID().toString() + )).isPresent()); + } +} diff --git a/src/shared/main/tv/codely/shared/domain/EmailValueObject.java b/src/shared/main/tv/codely/shared/domain/EmailValueObject.java new file mode 100644 index 00000000..a2686eff --- /dev/null +++ b/src/shared/main/tv/codely/shared/domain/EmailValueObject.java @@ -0,0 +1,20 @@ +package tv.codely.shared.domain; + +public abstract class EmailValueObject { + private final String value; + + public EmailValueObject(String value) { + ensureIsValidEmail(value); + this.value = value; + } + + private void ensureIsValidEmail(String value) { + if (!value.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$")) { + throw new IllegalArgumentException(String.format("The email <%s> is not valid", value)); + } + } + + public String value() { + return value; + } +}