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 apps/mooc/backend/config/routes/users.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
users_put:
path: /users/{id}
controller: CodelyTv\Apps\Mooc\Backend\Controller\Users\UsersPutController
methods: [PUT]
36 changes: 36 additions & 0 deletions apps/mooc/backend/src/Controller/Users/UsersPutController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace CodelyTv\Apps\Mooc\Backend\Controller\Users;

use CodelyTv\Mooc\Users\Application\CreateUserRequest;
use CodelyTv\Mooc\Users\Application\UserCreator;
use InvalidArgumentException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class UsersPutController
{
private $creator;

public function __construct(UserCreator $userCreator)
{
$this->creator = $userCreator;
}

public function __invoke(string $id, Request $request)
{
$request = new CreateUserRequest(
$id,
$request->request->get('name'),
$request->request->get('email'),
$request->request->get('password')
);

try {
$this->creator->__invoke($request);
} catch (InvalidArgumentException $exception) {
return new Response('', Response::HTTP_BAD_REQUEST);
}
return new Response('', Response::HTTP_CREATED);
}
}
39 changes: 39 additions & 0 deletions src/Mooc/Users/Application/CreateUserRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace CodelyTv\Mooc\Users\Application;

class CreateUserRequest
{
private $id;
private $name;
private $password;
private $email;

public function __construct(string $id, string $name, string $email, string $password)
{
$this->id = $id;
$this->name = $name;
$this->email = $email;
$this->password = $password;
}

public function id(): string
{
return $this->id;
}

public function name(): string
{
return $this->name;
}

public function email(): string
{
return $this->email;
}

public function password(): string
{
return $this->password;
}
}
31 changes: 31 additions & 0 deletions src/Mooc/Users/Application/UserCreator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace CodelyTv\Mooc\Users\Application;

use CodelyTv\Mooc\Users\Domain\User;
use CodelyTv\Mooc\Users\Domain\UserEmail;
use CodelyTv\Mooc\Users\Domain\UserId;
use CodelyTv\Mooc\Users\Domain\UserName;
use CodelyTv\Mooc\Users\Domain\UserPassword;
use CodelyTv\Mooc\Users\Domain\UserRepository;

class UserCreator
{
private $repository;

public function __construct(UserRepository $repository)
{
$this->repository = $repository;
}

public function __invoke(CreateUserRequest $request)
{
$user = new User(
new UserId($request->id()),
new UserName($request->name()),
new UserEmail($request->email()),
new UserPassword($request->password())
);
$this->repository->saveUser($user);
}
}
49 changes: 49 additions & 0 deletions src/Mooc/Users/Domain/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace CodelyTv\Mooc\Users\Domain;

class User
{
private $id;
private $name;
private $email;
private $password;

public function __construct(UserId $id, UserName $name, UserEmail $email, UserPassword $password)
{
$this->id = $id;
$this->name = $name;
$this->email = $email;
$this->password = $password;
}

public function id(): UserId
{
return $this->id;
}

public function email(): UserEmail
{
return $this->email;
}

public function name(): UserName
{
return $this->name;
}

public function password(): UserPassword
{
return $this->password;
}

public function toString(): string
{
return json_encode([
'id' => $this->id()->value(),
'name' => $this->name()->value(),
'email' => $this->email()->value(),
'password' => $this->password()->hashValue()
]);
}
}
25 changes: 25 additions & 0 deletions src/Mooc/Users/Domain/UserEmail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace CodelyTv\Mooc\Users\Domain;

use CodelyTv\Shared\Domain\ValueObject\StringValueObject;
use InvalidArgumentException;

class UserEmail extends StringValueObject
{
/** @throws InvalidArgumentException */
public function __construct(string $value)
{
$this->ensureIsValidEmail($value);
parent::__construct($value);
}

/** @throws InvalidArgumentException */
private function ensureIsValidEmail(string $email): void
{
$validate = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($validate === false) {
throw new InvalidArgumentException(sprintf('<%s> does not allow the value <%s>.', static::class, $email));
}
}
}
10 changes: 10 additions & 0 deletions src/Mooc/Users/Domain/UserId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace CodelyTv\Mooc\Users\Domain;

use CodelyTv\Shared\Domain\ValueObject\Uuid;

class UserId extends Uuid
{

}
27 changes: 27 additions & 0 deletions src/Mooc/Users/Domain/UserName.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace CodelyTv\Mooc\Users\Domain;

use CodelyTv\Shared\Domain\ValueObject\StringValueObject;
use InvalidArgumentException;

class UserName extends StringValueObject
{
private const LIMIT_MIN = 2;

/** @throws InvalidArgumentException */
public function __construct(string $value)
{
$this->ensureIsValidName($value);
parent::__construct($value);
}

/** @throws InvalidArgumentException */
private function ensureIsValidName(string $name): void
{
$validate = strlen($name) > self::LIMIT_MIN;
if ($validate === false) {
throw new InvalidArgumentException(sprintf('<%s> does not allow the value <%s>.', static::class, $name));
}
}
}
43 changes: 43 additions & 0 deletions src/Mooc/Users/Domain/UserPassword.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace CodelyTv\Mooc\Users\Domain;

use CodelyTv\Shared\Domain\ValueObject\StringValueObject;
use InvalidArgumentException;

class UserPassword extends StringValueObject
{
private const MIN_LENGTH = 8;

/** @throws InvalidArgumentException */
public function __construct(string $value)
{
$this->ensureIsValidPassword($value);
parent::__construct($value);
}

/** @throws InvalidArgumentException */
private function ensureIsValidPassword(string $password): void
{
if (strlen($password) < self::MIN_LENGTH) {
throw new InvalidArgumentException('The password has an invalid length. It must be greater than 8 characters');
}
if (false === (bool)preg_match('/[a-z]/', $password)) {
throw new InvalidArgumentException('The password is invalid. It must contain a lower case character');
}
if (false === (bool)preg_match('/[A-Z]/', $password)) {
throw new InvalidArgumentException('The password is invalid. It must contain an upper case character');
}
if (false === (bool)preg_match('/[0-9]/', $password)) {
throw new InvalidArgumentException('The password is invalid. It must contain a number');
}
if (false === (bool)preg_match('/[^a-zA-Z0-9]/', $password)) {
throw new InvalidArgumentException('The password is invalid. It must contain a symbol (not a letter nor a number)');
}
}

public function hashValue(): string
{
return password_hash($this->value(), PASSWORD_DEFAULT);
}
}
8 changes: 8 additions & 0 deletions src/Mooc/Users/Domain/UserRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace CodelyTv\Mooc\Users\Domain;

interface UserRepository
{
public function saveUser(User $user): void;
}
26 changes: 26 additions & 0 deletions src/Mooc/Users/Infraestructure/FileUserRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace CodelyTv\Mooc\Users\Infraestructure;

use CodelyTv\Mooc\Users\Domain\User;
use CodelyTv\Mooc\Users\Domain\UserRepository;

class FileUserRepository implements UserRepository
{
private $directory;

public function __construct()
{
$this->directory = __DIR__ . '/users';
}

public function saveUser(User $user): void
{
file_put_contents($this->fileName($user->id()->value()), $user->toString());
}

private function fileName(string $id): string
{
return "{$this->directory}.{$id}";
}
}
16 changes: 16 additions & 0 deletions tests/apps/mooc/backend/features/users/users_put.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Feature: Create a new user
In order to have users on the platform
As a user with admin permissions
I want to create a new user

Scenario: A valid non existing user
Given I send a PUT request to "/users/1aab45ba-3c7a-4344-8936-78466eca77fa" with body:
"""
{
"name": "John Smith",
"email": "john-smith@gamil.com",
"password": "**-Pa55w0rD-**"
}
"""
Then the response status code should be 201
And the response should be empty
6 changes: 6 additions & 0 deletions tests/apps/mooc/backend/mooc_backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ mooc_backend:
contexts:
- CodelyTv\Tests\Shared\Infrastructure\Behat\ApiRequestContext
- CodelyTv\Tests\Shared\Infrastructure\Behat\ApiResponseContext

users:
paths: [ tests/apps/mooc/backend/features/users ]
contexts:
- CodelyTv\Tests\Shared\Infrastructure\Behat\ApiRequestContext
- CodelyTv\Tests\Shared\Infrastructure\Behat\ApiResponseContext
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public static function create(string $value): CourseName

public static function random(): CourseName
{
return self::create(WordMother::random());
return self::create(WordMother::randomWord());
}
}
23 changes: 23 additions & 0 deletions tests/src/Mooc/Users/Application/CreateUserRequestMother.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace CodelyTv\Tests\Mooc\Users\Application;

use CodelyTv\Mooc\Users\Application\CreateUserRequest;

class CreateUserRequestMother
{
public static function create(string $id, string $name, string $email, string $password): CreateUserRequest
{
return new CreateUserRequest($id, $name, $email, $password);
}

public static function random(): CreateUserRequest
{
return self::create(
UserIdMother::random()->value(),
UserNameMother::random()->value(),
UserEmailMother::random()->value(),
UserPasswordMother::random()->value()
);
}
}
Loading