From ce6a517be9df2366b5faecdb81d9f139b79fdbd7 Mon Sep 17 00:00:00 2001 From: nic <nic@ubuntu22.myguest.virtualbox.org> Date: Thu, 1 Feb 2024 05:39:53 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20=D0=9F=D0=BE=D1=84=D0=B8=D0=BA=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D0=BC=D0=BD=D0=BE=D0=B3=D0=BE=D0=B5=20?= =?UTF-8?q?=D0=B8=D0=B7=20=D0=B3=D0=B8=D1=82=D0=B0,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BE=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=20?= =?UTF-8?q?=D1=80=D0=BE=D0=BB=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- creating.sql | 98 ++++++++++++--------- demo.http | 34 +++++-- src/Authenticator/LoginAuthenticator.php | 15 ++-- src/Authenticator/RegisterAuthenticator.php | 92 +++++++++++++++++++ src/Controller/ArticleController.php | 2 +- src/Controller/CommentController.php | 2 +- src/Controller/ExampleController.php | 4 +- src/Controller/RegisterController.php | 24 ----- src/Controller/TagController.php | 2 +- src/Controller/TopicController.php | 2 +- src/Controller/UserController.php | 8 +- src/Entity/Admission.php | 53 +++++++++++ src/Entity/Article.php | 25 ++++-- src/Entity/ArticleTag.php | 11 +-- src/Entity/Comment.php | 7 +- src/Entity/Tag.php | 4 +- src/Entity/Topic.php | 41 +++++++-- src/Entity/User.php | 2 +- src/Model/ArticleModel.php | 2 +- src/Model/ArticleResponseModel.php | 2 +- src/Model/BaseModel.php | 7 ++ src/Model/CommentModel.php | 4 +- src/Model/RegisterModel.php | 4 +- src/Model/TagModel.php | 3 +- src/Model/TestModel.php | 20 ----- src/Model/TopicModel.php | 40 ++++++++- src/Model/TopicResponseModel.php | 80 +++++++++++++++++ src/Model/UserModel.php | 4 +- src/Service/ArticleService.php | 27 ++++-- src/Service/CommentService.php | 6 +- src/Service/TopicService.php | 41 ++++++++- src/Service/UserProvider.php | 15 +--- 32 files changed, 501 insertions(+), 180 deletions(-) create mode 100644 src/Authenticator/RegisterAuthenticator.php delete mode 100755 src/Controller/RegisterController.php create mode 100644 src/Entity/Admission.php create mode 100755 src/Model/BaseModel.php delete mode 100755 src/Model/TestModel.php create mode 100644 src/Model/TopicResponseModel.php diff --git a/creating.sql b/creating.sql index 3144d5f..ff1c08f 100644 --- a/creating.sql +++ b/creating.sql @@ -1,74 +1,88 @@ CREATE TABLE IF NOT EXISTS tag( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - title VARCHAR(60) NOT NULL UNIQUE -); + id INTEGER PRIMARY KEY AUTO_INCREMENT, + title VARCHAR(60) NOT NULL UNIQUE + ); CREATE TABLE IF NOT EXISTS user( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - username VARCHAR(120) NOT NULL UNIQUE , + id INTEGER PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(120) NOT NULL UNIQUE , email VARCHAR(120) NOT NULL UNIQUE , - password VARCHAR(60) NOT NULL , + password VARCHAR(120) NOT NULL , role VARCHAR(10), created DATETIME, changed DATETIME, CONSTRAINT role_enum CHECK ( role IN ('USER', 'MODERATOR', 'ADMIN') ) -); + ); CREATE TABLE IF NOT EXISTS topic( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - author_id INTEGER, - title VARCHAR(365) NOT NULL , + id INTEGER PRIMARY KEY AUTO_INCREMENT, + author_id INTEGER, + title VARCHAR(365) NOT NULL , + type VARCHAR(8) NOT NULL , created DATETIME, CONSTRAINT FOREIGN KEY (author_id) - REFERENCES user(id) - ON DELETE no action -); + REFERENCES user(id) + ON DELETE no action, + CONSTRAINT type_check CHECK ( type IN ('PUBLIC', 'PRIVATE') ) + ); CREATE TABLE IF NOT EXISTS article( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - author_id INTEGER , - topic_id INTEGER , - title VARCHAR(480) NOT NULL , + id INTEGER PRIMARY KEY AUTO_INCREMENT, + author_id INTEGER , + topic_id INTEGER , + title VARCHAR(480) NOT NULL , body VARCHAR(10000) , created DATETIME , changed DATETIME , CONSTRAINT FOREIGN KEY (author_id) - REFERENCES user(id) - ON DELETE no action , + REFERENCES user(id) + ON DELETE no action , CONSTRAINT FOREIGN KEY (topic_id) - REFERENCES topic(id) - ON DELETE set null -); + REFERENCES topic(id) + ON DELETE set null + ); CREATE TABLE IF NOT EXISTS comment( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - author_id INTEGER, - article_id INTEGER, - body VARCHAR(1000), + id INTEGER PRIMARY KEY AUTO_INCREMENT, + author_id INTEGER, + article_id INTEGER, + body VARCHAR(1000), created DATETIME, changed DATETIME, CONSTRAINT FOREIGN KEY (author_id) - REFERENCES user(id) - ON DELETE no action , + REFERENCES user(id) + ON DELETE no action , CONSTRAINT FOREIGN KEY (article_id) - REFERENCES article(id) - ON DELETE CASCADE -); + REFERENCES article(id) + ON DELETE CASCADE + ); CREATE TABLE IF NOT EXISTS article_tag( - id INTEGER PRIMARY KEY AUTO_INCREMENT, - article_id INTEGER, - tag_id INTEGER, - CONSTRAINT FOREIGN KEY (article_id) - REFERENCES article(id) - ON DELETE CASCADE , + id INTEGER PRIMARY KEY AUTO_INCREMENT, + article_id INTEGER, + tag_id INTEGER, + CONSTRAINT FOREIGN KEY (article_id) + REFERENCES article(id) + ON DELETE CASCADE , CONSTRAINT FOREIGN KEY (tag_id) - REFERENCES tag(id) - ON DELETE CASCADE -); + REFERENCES tag(id) + ON DELETE CASCADE + ); + +CREATE TABLE IF NOT EXISTS admission( + id INTEGER PRIMARY KEY AUTO_INCREMENT, + topic_id INTEGER, + user_id INTEGER, + CONSTRAINT FOREIGN KEY (topic_id) + REFERENCES topic(id) + ON DELETE CASCADE , + CONSTRAINT FOREIGN KEY (user_id) + REFERENCES user(id) + ON DELETE CASCADE + ); INSERT INTO user(username, email, password, role, created, changed) -VALUES ('test', 'test@gmail.com', '12345', 'USER', '2022-12-27 08:26:49.219717', '2022-12-27 08:26:49.219717'); +VALUES ('test', 'test@gmail.com', '5994471ABB01112AFCC18159F6CC74B4F511B99806DA59B3CAF5A9C173CACFC5', 'USER', '2022-12-27 08:26:49.219717', '2022-12-27 08:26:49.219717'); INSERT INTO user(username, email, password, role, created, changed) -VALUES ('Admin', 'admin@gmail.com', '12345', 'ADMIN', '2022-12-27 08:26:49.219717', '2022-12-27 08:26:49.219717'); +VALUES ('Admin', 'admin@gmail.com', '5994471ABB01112AFCC18159F6CC74B4F511B99806DA59B3CAF5A9C173CACFC5', 'ADMIN', '2022-12-27 08:26:49.219717', '2022-12-27 08:26:49.219717'); diff --git a/demo.http b/demo.http index ea1b918..5dfca27 100644 --- a/demo.http +++ b/demo.http @@ -28,12 +28,20 @@ Content-Type: application/json "password": "12345" } +### LOGIN +POST http://localhost:8800/login +Content-Type: application/json + +{ + "username": "test", + "password": "12345" +} + ### REGISTER POST http://localhost:8800/register Content-Type: application/json { - "id": 5, "username": "kphp", "email": "kphp@mail.com", "password": "12355" @@ -68,11 +76,21 @@ Content-Type: application/json ] } +### LOGIN MODER +POST http://localhost:8800/login +Content-Type: application/json + +{ + "username": "Moder", + "password": "qwerty" +} + + ### GET USER -GET http://localhost:8800/admin/user/3 +GET http://localhost:8800/admin/user/4 ### PUT USER -PUT http://localhost:8800/admin/user/3 +PUT http://localhost:8800/admin/user/4 Content-Type: application/json { @@ -111,6 +129,10 @@ Content-Type: application/json "id": 0, "authorId": 2, "title": "KPHP - not cool!", + "type": "PRIVATE", + "acceptedUsers": [ + 1 + ], "created": "2024-01-22 21:30:00" } @@ -118,7 +140,7 @@ Content-Type: application/json GET http://localhost:8800/topic/1 ### PUT TUPIC -PUT http://localhost:8800/moderator/topic/2 +PUT http://localhost:8800/moderator/topic/1 Content-Type: application/json { @@ -134,7 +156,7 @@ POST http://localhost:8800/article Content-Type: application/json { - "id": 2, + "id": 1, "authorId": 2, "topicId": 1, "title": "KPHP", @@ -151,7 +173,7 @@ Content-Type: application/json GET http://localhost:8800/article/1 ### CHANGE ARTICLE -PUT http://localhost:8800/article/3 +PUT http://localhost:8800/article/1 Content-Type: application/json { diff --git a/src/Authenticator/LoginAuthenticator.php b/src/Authenticator/LoginAuthenticator.php index 744364a..184dde6 100755 --- a/src/Authenticator/LoginAuthenticator.php +++ b/src/Authenticator/LoginAuthenticator.php @@ -15,7 +15,7 @@ use Kaa\Component\Security\AuthenticatorInterface; use Kaa\Component\Security\Exception\SessionException; use Kaa\Component\Security\Session\SessionService; use Random\RandomException; -use Symfony\Component\Filesystem\Exception\RuntimeException; +use RuntimeException; use Throwable; class LoginAuthenticator implements AuthenticatorInterface @@ -43,9 +43,9 @@ class LoginAuthenticator implements AuthenticatorInterface public function supports(Request $request): bool { $content = json_decode($request->getContent(), true); - return $request->getMethod() === 'POST' && - array_key_exists('username', $content) && - array_key_exists('password', $content); + return $request->getMethod() === 'POST' + && array_key_exists('username', $content) + && array_key_exists('password', $content); } /** @@ -55,7 +55,10 @@ class LoginAuthenticator implements AuthenticatorInterface { $data = json_decode($request->getContent(), true); $user = $this->entityManager->findOneBy(User::class, ['username' => $data['username']]); - if (($data['username'] === $user->getUsername()) && ($data['password'] === $user->getPassword())) { + if ( + ($data['username'] === $user->getUsername()) + && (strtoupper(hash('sha256', $data['password'])) === $user->getPassword()) + ) { return fn () => $this->userProvider->getUser($user->getIdentifier()); } throw new RuntimeException('Incorrect username or password'); @@ -77,6 +80,6 @@ class LoginAuthenticator implements AuthenticatorInterface public function onAuthenticationFailure(Request $request, Throwable $throwable): ?Response { - return new JsonResponse('Incorrect login or password', 401); + return new JsonResponse('Incorrect username or password', 401); } } diff --git a/src/Authenticator/RegisterAuthenticator.php b/src/Authenticator/RegisterAuthenticator.php new file mode 100644 index 0000000..6735bab --- /dev/null +++ b/src/Authenticator/RegisterAuthenticator.php @@ -0,0 +1,92 @@ +<?php + +namespace App\Authenticator; + +use App\Model\UserModel; +use App\Service\UserProvider; +use DateTimeImmutable; +use Exception; +use Kaa\Component\Database\EntityManager\EntityManagerInterface; +use Kaa\Component\HttpMessage\Exception\BadRequestException; +use Kaa\Component\HttpMessage\Exception\NoContentException; +use Kaa\Component\HttpMessage\Exception\SuspiciousOperationException; +use Kaa\Component\HttpMessage\Request; +use Kaa\Component\HttpMessage\Response\JsonResponse; +use Kaa\Component\HttpMessage\Response\Response; +use Kaa\Component\Security\AuthenticatorInterface; +use Kaa\Component\Security\Exception\SessionException; +use Kaa\Component\Security\Session\SessionService; +use Random\RandomException; +use Throwable; + +class RegisterAuthenticator implements AuthenticatorInterface +{ + private SessionService $sessionService; + private EntityManagerInterface $entityManager; + + private UserProvider $userProvider; + + public function __construct( + SessionService $sessionService, + EntityManagerInterface $entityManager, + UserProvider $userProvider + ) + { + $this->sessionService = $sessionService; + $this->entityManager = $entityManager; + $this->userProvider = $userProvider; + } + + /** + * @throws BadRequestException + * @throws SuspiciousOperationException + * @throws NoContentException + */ + public function supports(Request $request): bool + { + $content = json_decode($request->getContent(), true); + return $request->getMethod() === 'POST' + && array_key_exists('username', $content) + && array_key_exists('password', $content) + && array_key_exists('email', $content); + } + + /** + * @throws NoContentException + * @throws Exception + */ + public function authenticate(Request $request): callable + { + $data = json_decode($request->getContent(), true); + $id = $this->userProvider->createUser(new UserModel( + 0, + (string)$data['username'], + (string)$data['email'], + (string)$data['password'], + ['USER'], + new DateTimeImmutable(), + new DateTimeImmutable() + )); + return fn() => $this->userProvider->getUser((string)$id); + } + + /** + * @throws SessionException + * @throws RandomException + */ + public function onAuthenticationSuccess(Request $request, callable $getUser): ?Response + { + $cookie = $this->sessionService->writeSession($getUser()); + + $response = new Response('Success', 200); + $response->addCookie($cookie); + + return $response; + } + + public function onAuthenticationFailure(Request $request, Throwable $throwable): ?Response + { + return new JsonResponse('Something went wrong...', 400); + } +} + diff --git a/src/Controller/ArticleController.php b/src/Controller/ArticleController.php index 5d45bf5..76ba18a 100755 --- a/src/Controller/ArticleController.php +++ b/src/Controller/ArticleController.php @@ -58,7 +58,7 @@ class ArticleController User $user ): Response { $articleService->updateArticle($id, $articleModel, $user); - return new JsonResponse('Successful changed', status: 200); + return new JsonResponse('Successful changed', 200); } #[Get('/my')] diff --git a/src/Controller/CommentController.php b/src/Controller/CommentController.php index 93c12c7..6256c45 100755 --- a/src/Controller/CommentController.php +++ b/src/Controller/CommentController.php @@ -61,7 +61,7 @@ class CommentController User $user ): Response { $commentService->updateComment($id, $commentModel, $user); - return new JsonResponse('Successful changed', status: 200); + return new JsonResponse('Successful changed', 200); } #[Get('/my')] diff --git a/src/Controller/ExampleController.php b/src/Controller/ExampleController.php index 803ec31..b7d251e 100755 --- a/src/Controller/ExampleController.php +++ b/src/Controller/ExampleController.php @@ -11,7 +11,7 @@ class ExampleController #[Get('/test')] public function test(): JsonResponse { - return new JsonResponse('{"hame": "kolaya"}', 200, []); + return new JsonResponse('{"hame": "kolaya"}', 200); } # warning for incorrect json for parsing? #[Get('/test/{id}')] @@ -19,6 +19,6 @@ class ExampleController #[MapRouteParameter] int $id ): JsonResponse { - return new JsonResponse("{'id': {$id}}", 200, []); + return new JsonResponse("{'id': {$id}}", 200); } } diff --git a/src/Controller/RegisterController.php b/src/Controller/RegisterController.php deleted file mode 100755 index 0c3d7dc..0000000 --- a/src/Controller/RegisterController.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php - -namespace App\Controller; - -use App\Model\RegisterModel; -use App\Service\UserProvider; -use Kaa\Component\DependencyInjectionDecorator\Inject; -use Kaa\Component\RequestMapperDecorator\AsJsonResponse; -use Kaa\Component\RequestMapperDecorator\MapJsonPayload; -use Kaa\Component\Router\Attribute\Post; - -class RegisterController -{ - #[Post('/register')] - #[AsJsonResponse] - public function register( - #[MapJsonPayload] - RegisterModel $registerModel, - #[Inject] - UserProvider $userProvider - ): int { - return $userProvider->registerUser($registerModel); - } -} diff --git a/src/Controller/TagController.php b/src/Controller/TagController.php index fc90a9b..08c640c 100755 --- a/src/Controller/TagController.php +++ b/src/Controller/TagController.php @@ -49,6 +49,6 @@ class TagController TagModel $tagModel ): JsonResponse { $tagService->updateTag($id, $tagModel); - return new JsonResponse('Successful changed', status: 200); + return new JsonResponse('Successful changed', 200); } } diff --git a/src/Controller/TopicController.php b/src/Controller/TopicController.php index f9290db..af24c71 100755 --- a/src/Controller/TopicController.php +++ b/src/Controller/TopicController.php @@ -50,7 +50,7 @@ class TopicController TopicService $topicService ): JsonResponse { $topicService->updateTopic($id, $topicModel); - return new JsonResponse('Successful changed', status: 200); + return new JsonResponse('Successful changed', 200); } #[Get('/topic/my')] diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index d0c9321..279a976 100755 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -37,7 +37,7 @@ class UserController #[CurrentUser] User $user, #[Inject] - UserProvider $userProvider, + UserProvider $userProvider ): UserModel { return $userProvider->getCurrentUser($user); } @@ -66,9 +66,9 @@ class UserController try { $userProvider->updateUser($userModel, $id); } catch (Exception $exception) { - return new JsonResponse('Nothing changed', status: 200); + return new JsonResponse('Nothing changed', 200); } - return new JsonResponse('Successfully changed', status: 200); + return new JsonResponse('Successfully changed', 200); } #[Put('/user/me')] @@ -85,6 +85,6 @@ class UserController ->setCreationDate($user->getCreationTime()) ->setChangingDate(new DateTimeImmutable()); $userProvider->updateUser($userModel, $user->getId()); - return new JsonResponse('Successfully changed', status: 200); + return new JsonResponse('Successfully changed', 200); } } diff --git a/src/Entity/Admission.php b/src/Entity/Admission.php new file mode 100644 index 0000000..be4641d --- /dev/null +++ b/src/Entity/Admission.php @@ -0,0 +1,53 @@ +<?php + +namespace App\Entity; + +use Kaa\Component\Database\Attribute as Db; +use Kaa\Component\Database\EntityInterface; + +#[Db\Entity] +abstract class Admission implements EntityInterface +{ + #[Db\Id] + #[Db\Column] + protected ?int $id = null; + + #[Db\ManyToOne(Topic::class)] + protected Topic $topic; + + #[Db\ManyToOne(User::class)] + protected User $user; + + public function getId(): int + { + return $this->id ?? -1; + } + + public function setId(int $id): Admission + { + $this->id = $id; + return $this; + } + + public function getTopic(): Topic + { + return $this->topic; + } + + public function setTopic(Topic $topic): Admission + { + $this->topic = $topic; + return $this; + } + + public function getUser(): User + { + return $this->user; + } + + public function setUser(User $user): Admission + { + $this->user = $user; + return $this; + } +} diff --git a/src/Entity/Article.php b/src/Entity/Article.php index 74ae8fa..b9cbbfb 100755 --- a/src/Entity/Article.php +++ b/src/Entity/Article.php @@ -34,9 +34,13 @@ abstract class Article implements EntityInterface #[Db\OneToMany(ArticleTag::class, mappedBy: 'article')] protected array $tags = []; + /** @var Comment[] */ + #[Db\OneToMany(Comment::class, mappedBy: 'article')] + protected array$comments = []; + public function getId(): int { - return $this->id; + return $this->id ?? -1; } public function setId(int $id): Article @@ -45,11 +49,6 @@ abstract class Article implements EntityInterface return $this; } - public function getAuthorId(): int - { - return $this->author->getId(); - } - public function getTopicId(): int { return $this->topic->getId(); @@ -135,4 +134,18 @@ abstract class Article implements EntityInterface $this->tags[] = $tag; return $this; } + + /** + * @return Comment[] + */ + public function getComments(): array + { + return $this->comments; + } + + public function addComment(Comment $comment): Article + { + $this->comments[] = $comment; + return $this; + } } diff --git a/src/Entity/ArticleTag.php b/src/Entity/ArticleTag.php index f0fd05d..c9c1381 100755 --- a/src/Entity/ArticleTag.php +++ b/src/Entity/ArticleTag.php @@ -20,7 +20,7 @@ abstract class ArticleTag implements EntityInterface public function getId(): int { - return $this->id; + return $this->id ?? -1; } public function setId(int $id): ArticleTag @@ -29,15 +29,6 @@ abstract class ArticleTag implements EntityInterface return $this; } - public function getArticleId(): int - { - return $this->article->getId(); - } - - public function getTagId(): int - { - return $this->tag->getId(); - } public function getArticle(): Article { diff --git a/src/Entity/Comment.php b/src/Entity/Comment.php index 77d229e..bac27b9 100755 --- a/src/Entity/Comment.php +++ b/src/Entity/Comment.php @@ -30,7 +30,7 @@ abstract class Comment implements EntityInterface public function getId(): int { - return $this->id; + return $this->id ?? -1; } public function setId(int $id): Comment @@ -39,11 +39,6 @@ abstract class Comment implements EntityInterface return $this; } - public function getAuthorId(): int - { - return $this->author->getId(); - } - public function getArticleId(): int { return $this->article->getId(); diff --git a/src/Entity/Tag.php b/src/Entity/Tag.php index 3678c13..6c03e30 100755 --- a/src/Entity/Tag.php +++ b/src/Entity/Tag.php @@ -15,13 +15,13 @@ abstract class Tag implements EntityInterface #[Db\Column] protected string $title; - /** @var Article[] */ + /** @var ArticleTag[] */ #[Db\OneToMany(ArticleTag::class, mappedBy: 'tag')] protected array $articles = []; public function getId(): int { - return $this->id; + return $this->id ?? -1; } public function setId(int $id): Tag diff --git a/src/Entity/Topic.php b/src/Entity/Topic.php index c2aa5d4..0422222 100755 --- a/src/Entity/Topic.php +++ b/src/Entity/Topic.php @@ -5,6 +5,7 @@ namespace App\Entity; use DateTimeImmutable; use Kaa\Component\Database\Attribute as Db; use Kaa\Component\Database\EntityInterface; +use Twig\Node\Expression\Binary\AddBinary; #[Db\Entity] abstract class Topic implements EntityInterface @@ -19,12 +20,21 @@ abstract class Topic implements EntityInterface #[Db\Column] protected string $title; + #[Db\Column] + protected string $type; + + /** + * @var Admission[] + */ + #[Db\OneToMany(Admission::class, mappedBy: 'topic')] + protected array $acceptedUsers = []; + #[Db\Column(type: Db\Type::DateTimeImmutable)] protected DateTimeImmutable $created; public function getId(): int { - return $this->id; + return $this->id ?? -1; } public function setId(int $id): Topic @@ -33,11 +43,6 @@ abstract class Topic implements EntityInterface return $this; } - public function getAuthorId(): int - { - return $this->author->getId(); - } - public function getTitle(): string { return $this->title; @@ -49,6 +54,30 @@ abstract class Topic implements EntityInterface return $this; } + public function getType(): string + { + return $this->type; + } + + public function setType(string $type): Topic + { + $this->type = $type; + return $this; + } + + /** + * @return Admission[] + */ + public function getAcceptedUsers(): array + { + return $this->acceptedUsers; + } + + public function addAcceptedUser(Admission $user): Topic + { + $this->acceptedUsers[] = $user; + return $this; + } public function getCreationTime(): DateTimeImmutable { diff --git a/src/Entity/User.php b/src/Entity/User.php index bec9574..4021afe 100755 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -41,7 +41,7 @@ abstract class User implements EntityInterface, UserInterface public function getId(): int { - return $this->id; + return $this->id ?? -1; } public function setId(int $id): User diff --git a/src/Model/ArticleModel.php b/src/Model/ArticleModel.php index 095b90d..b88fb62 100755 --- a/src/Model/ArticleModel.php +++ b/src/Model/ArticleModel.php @@ -5,7 +5,7 @@ namespace App\Model; use DateTimeImmutable; use Kaa\Component\Validator\Assert; -class ArticleModel +class ArticleModel extends BaseModel { #[Assert\PositiveOrZero] private int $id; diff --git a/src/Model/ArticleResponseModel.php b/src/Model/ArticleResponseModel.php index df2a26f..de11880 100755 --- a/src/Model/ArticleResponseModel.php +++ b/src/Model/ArticleResponseModel.php @@ -6,7 +6,7 @@ namespace App\Model; use DateTimeImmutable; use Kaa\Component\Validator\Assert; -class ArticleResponseModel +class ArticleResponseModel extends BaseModel { #[Assert\PositiveOrZero] private int $id; diff --git a/src/Model/BaseModel.php b/src/Model/BaseModel.php new file mode 100755 index 0000000..b24359a --- /dev/null +++ b/src/Model/BaseModel.php @@ -0,0 +1,7 @@ +<?php + +namespace App\Model; + +class BaseModel +{ +} diff --git a/src/Model/CommentModel.php b/src/Model/CommentModel.php index 538fd77..5b7ad93 100755 --- a/src/Model/CommentModel.php +++ b/src/Model/CommentModel.php @@ -5,7 +5,7 @@ namespace App\Model; use DateTimeImmutable; use Kaa\Component\Validator\Assert; -class CommentModel +class CommentModel extends BaseModel { #[Assert\PositiveOrZero] private int $id; @@ -19,7 +19,7 @@ class CommentModel #[Assert\Length(max: 1000)] private string $body; - private string $created; # maybe something asserting? + private string $created; private string $changed; diff --git a/src/Model/RegisterModel.php b/src/Model/RegisterModel.php index f0092bc..812c007 100755 --- a/src/Model/RegisterModel.php +++ b/src/Model/RegisterModel.php @@ -4,7 +4,7 @@ namespace App\Model; use Kaa\Component\Validator\Assert; -class RegisterModel +class RegisterModel extends BaseModel { #[Assert\PositiveOrZero] private int $id; @@ -22,7 +22,7 @@ class RegisterModel int $id, string $username, string $email, - string $password, + string $password ) { $this->id = $id; $this->username = $username; diff --git a/src/Model/TagModel.php b/src/Model/TagModel.php index e64391a..703a64e 100755 --- a/src/Model/TagModel.php +++ b/src/Model/TagModel.php @@ -4,7 +4,7 @@ namespace App\Model; use Kaa\Component\Validator\Assert; -class TagModel +class TagModel extends BaseModel { #[Assert\PositiveOrZero] private int $id; @@ -12,6 +12,7 @@ class TagModel #[Assert\Length(max: 60)] private string $title; + public function __construct(int $id, string $title) { $this->id = $id; diff --git a/src/Model/TestModel.php b/src/Model/TestModel.php deleted file mode 100755 index bbd959b..0000000 --- a/src/Model/TestModel.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -namespace App\Model; - -use DateTimeImmutable; - -class TestModel -{ - private DateTimeImmutable $dt; - - public function __construct(DateTimeImmutable $dt) - { - $this->dt = $dt; - } - - public function getDt(): DateTimeImmutable - { - return $this->dt; - } -} diff --git a/src/Model/TopicModel.php b/src/Model/TopicModel.php index 25997b5..beb65e4 100755 --- a/src/Model/TopicModel.php +++ b/src/Model/TopicModel.php @@ -5,7 +5,7 @@ namespace App\Model; use DateTimeImmutable; use Kaa\Component\Validator\Assert; -class TopicModel +class TopicModel extends BaseModel { #[Assert\PositiveOrZero] private int $id; @@ -16,13 +16,32 @@ class TopicModel #[Assert\Length(max: 365)] private string $title; - private string $created; # maybe something asserting? + private string $type; - public function __construct(int $id, int $author_id, string $title, DateTimeImmutable $created) - { + /** + * @var int[] + */ + private array $acceptedUsers; + + private string $created; + + /** + * @param int[] $acceptedUsers + */ + + public function __construct( + int $id, + int $author_id, + string $title, + string $type, + array $acceptedUsers, + DateTimeImmutable $created + ) { $this->id = $id; $this->authorId = $author_id; $this->title = $title; + $this->type = $type; + $this->acceptedUsers = $acceptedUsers; $this->created = $created->format('Y-m-d H:i:s'); } @@ -41,6 +60,19 @@ class TopicModel return $this->title; } + public function getType(): string + { + return $this->type; + } + + /** + * @return int[] + */ + public function getAcceptedUsers(): array + { + return $this->acceptedUsers; + } + public function getCreationTime(): string { return $this->created; diff --git a/src/Model/TopicResponseModel.php b/src/Model/TopicResponseModel.php new file mode 100644 index 0000000..119a576 --- /dev/null +++ b/src/Model/TopicResponseModel.php @@ -0,0 +1,80 @@ +<?php + +namespace App\Model; + +use DateTimeImmutable; +use Kaa\Component\Validator\Assert; + +class TopicResponseModel extends BaseModel +{ + #[Assert\PositiveOrZero] + private int $id; + + #[Assert\PositiveOrZero] + private int $authorId; + + #[Assert\Length(max: 365)] + private string $title; + + private string $type; + + /** + * @var UserModel[] + */ + private array $accepted_users; + + private string $created; + + /** + * @param UserModel[] $accepted_users + */ + + public function __construct( + int $id, + int $author_id, + string $title, + string $type, + array $accepted_users, + DateTimeImmutable $created + ) { + $this->id = $id; + $this->authorId = $author_id; + $this->title = $title; + $this->type = $type; + $this->accepted_users = $accepted_users; + $this->created = $created->format('Y-m-d H:i:s'); + } + + public function getId(): int + { + return $this->id; + } + + public function getAuthorId(): int + { + return $this->authorId; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getType(): string + { + return $this->type; + } + + /** + * @return UserModel[] + */ + public function getAcceptedUsers(): array + { + return $this->accepted_users; + } + + public function getCreationTime(): string + { + return $this->created; + } +} \ No newline at end of file diff --git a/src/Model/UserModel.php b/src/Model/UserModel.php index 8fcf861..cafecb0 100755 --- a/src/Model/UserModel.php +++ b/src/Model/UserModel.php @@ -6,7 +6,7 @@ use DateTimeImmutable; use Kaa\Component\Security\UserInterface; use Kaa\Component\Validator\Assert; -class UserModel implements UserInterface +class UserModel extends BaseModel implements UserInterface { #[Assert\PositiveOrZero] private int $id; @@ -17,7 +17,7 @@ class UserModel implements UserInterface #[Assert\Email] private string $email; - #[Assert\Length(max: 60)] + #[Assert\Length(max: 120)] private string $password; private string $created; diff --git a/src/Service/ArticleService.php b/src/Service/ArticleService.php index bd57eb4..871ecdb 100755 --- a/src/Service/ArticleService.php +++ b/src/Service/ArticleService.php @@ -4,7 +4,6 @@ namespace App\Service; use App\Entity\Article; use App\Entity\ArticleTag; -use App\Entity\Comment; use App\Entity\Tag; use App\Entity\Topic; use App\Entity\User; @@ -35,6 +34,14 @@ class ArticleService throw new RuntimeException("Article contains wrong tag id {$tag}"); } } + $topic = $this->entityManager->find(Topic::class, $articleModel->getTopicId()); + if ( + ($topic->getType() === 'PRIVATE') + && !in_array('MODERATOR', $user->getRoles()) + && !in_array($user->getId(), array_map(fn ($a) => $a->getUser()->getId(), $topic->getAcceptedUsers())) + ) { + throw new ForbiddenOverwriteException("You are not allow to write in this topic!"); + } $article = $this->entityManager->new(Article::class) ->setAuthor($user) ->setTopic($this->entityManager->find(Topic::class, $articleModel->getTopicId())) @@ -59,22 +66,24 @@ class ArticleService } $tags = []; foreach ($article->getTags() as $tag) { - $tagBd = $this->entityManager->find(Tag::class, $tag->getTagId()); + $tagBd = $this->entityManager->find(Tag::class, $tag->getTag()->getId()); $tags[] = new TagModel($tagBd->getId(), $tagBd->getTitle()); } - $topicBd = $this->entityManager->find(Topic::class, $article->getTopicId()); + $topicBd = $article->getTopic(); $topic = new TopicModel( $topicBd->getId(), - $topicBd->getAuthorId(), + $topicBd->getAuthor()->getId(), $topicBd->getTitle(), + $topicBd->getType(), + $topicBd->getAcceptedUsers(), $topicBd->getCreationTime() ); $comments = []; - $commentsBd = $this->entityManager->findBy(Comment::class, ['article' => $article->getId()]); + $commentsBd = $article->getComments(); foreach ($commentsBd as $commentBd) { $comments[] = new CommentModel( $commentBd->getId(), - $commentBd->getArticleId(), + $commentBd->getAuthor()->getId(), $commentBd->getArticleId(), $commentBd->getBody(), $commentBd->getCreationTime(), @@ -83,7 +92,7 @@ class ArticleService } return new ArticleResponseModel( $article->getId(), - $article->getAuthorId(), + $article->getAuthor()->getId(), $topic, $article->geTitle(), $article->getBody(), @@ -100,11 +109,11 @@ class ArticleService if ($article === null) { throw new RuntimeException("Article with id=$id not found"); } - if ($user->getId() !== $article->getAuthorId()) { + if ($user->getId() !== $article->getAuthor()->getId()) { throw new ForbiddenOverwriteException('You are not the author'); } $tagIds = array_map(function (ArticleTag $t) { - return $t->getTagId(); + return $t->getTag()->getId(); }, $article->getTags()); $tags = []; foreach ($tagIds as $tag) { diff --git a/src/Service/CommentService.php b/src/Service/CommentService.php index 73506a7..88d61e7 100755 --- a/src/Service/CommentService.php +++ b/src/Service/CommentService.php @@ -45,7 +45,7 @@ class CommentService } return new CommentModel( $comment->getId(), - $comment->getAuthorId(), + $comment->getAuthor()->getId(), $comment->getArticleId(), $comment->getBody(), $comment->getCreationTime(), @@ -59,7 +59,7 @@ class CommentService if ($comment === null) { throw new RuntimeException("Comment with id=$id not found"); } - if ($user->getId() !== $comment->getAuthorId()) { + if ($user->getId() !== $comment->getAuthor()->getId()) { throw new ForbiddenOverwriteException('You are not the author'); } $comment @@ -75,7 +75,7 @@ class CommentService foreach ($comments as $comment) { $commentsModels[] = new CommentModel( $comment->getId(), - $comment->getAuthorId(), + $comment->getAuthor()->getId(), $comment->getArticleId(), $comment->getBody(), $comment->getCreationTime(), diff --git a/src/Service/TopicService.php b/src/Service/TopicService.php index 7ef3dba..66908f5 100755 --- a/src/Service/TopicService.php +++ b/src/Service/TopicService.php @@ -2,6 +2,7 @@ namespace App\Service; +use App\Entity\Admission; use App\Entity\Topic; use App\Entity\User; use App\Model\MultipleTopicsModel; @@ -25,10 +26,22 @@ class TopicService */ public function createTopic(TopicModel $topicModel): int { + if ($topicModel->getType() === 'PRIVATE'){ + foreach ($topicModel->getAcceptedUsers() as $user){ + if (!$this->entityManager->find(User::class, $user)) + throw new RuntimeException("Topic contains wrong user with id={$user}"); + } + } $topic = $this->entityManager->new(Topic::class) ->setAuthor($this->entityManager->find(User::class, $topicModel->getAuthorId())) ->setTitle($topicModel->getTitle()) + ->setType($topicModel->getType()) ->setCreationTime(new DateTimeImmutable($topicModel->getCreationTime())); + foreach ($topicModel->getAcceptedUsers() as $user){ + $this->entityManager->new(Admission::class) + ->setTopic($topic) + ->setUser($this->entityManager->find(User::class, $user)); + } $this->entityManager->flush(); return not_null($topic->getId()); } @@ -41,8 +54,10 @@ class TopicService } return new TopicModel( $topic->getId(), - $topic->getAuthorId(), + $topic->getAuthor()->getId(), $topic->getTitle(), + $topic->getType(), + $topic->getAcceptedUsers(), $topic->getCreationTime() ); } @@ -56,9 +71,29 @@ class TopicService if ($topic === null) { throw new RuntimeException("Topic with id=$id not found"); } + $userIds = array_map(function (Admission $t) { + return $t->getUser()->getId(); + }, $topic->getAcceptedUsers()); + $users = []; + foreach ($userIds as $userId) { + if (!in_array($userId, $topicModel->getAcceptedUsers())) { + $users[] = $userId; + } + } + foreach ($users as $userId) { + if (!$this->entityManager->find(User::class, $userId)) { + throw new RuntimeException("Topic contains wrong user id {$userId}"); + } + } $topic ->setTitle($topicModel->getTitle()) + ->setType($topicModel->getType()) ->setCreationTime(new DateTimeImmutable($topicModel->getCreationTime())); + foreach ($users as $user) { + $this->entityManager->new(Admission::class) + ->setUser($this->entityManager->find(User::class, $user)) + ->setTopic($topic); + } $this->entityManager->flush(); } @@ -69,8 +104,10 @@ class TopicService foreach ($topics as $topic) { $topicsModelArray[] = new TopicModel( $topic->getId(), - $topic->getAuthorId(), + $topic->getAuthor()->getId(), $topic->getTitle(), + $topic->getType(), + $topic->getAcceptedUsers(), $topic->getCreationTime() ); } diff --git a/src/Service/UserProvider.php b/src/Service/UserProvider.php index 263c6ea..aea3325 100755 --- a/src/Service/UserProvider.php +++ b/src/Service/UserProvider.php @@ -23,19 +23,6 @@ class UserProvider implements UserProviderInterface $this->entityManager = $entityManager; } - public function registerUser(RegisterModel $registerModel): int - { - $user = $this->entityManager->new(User::class) - ->setUsername($registerModel->getUsername()) - ->setEmail($registerModel->getEmail()) - ->setPassword($registerModel->getPassword()) - ->setCreationTime(new DateTimeImmutable()) - ->setChangingTime(new DateTimeImmutable()) - ->setRole(['USER']); - $this->entityManager->flush(); - return $user->getId(); - } - /** * @throws Exception */ @@ -44,7 +31,7 @@ class UserProvider implements UserProviderInterface $user = $this->entityManager->new(User::class) ->setUsername($userModel->getUsername()) ->setEmail($userModel->getEmail()) - ->setPassword($userModel->getPassword()) + ->setPassword(strtoupper(hash('sha256', $userModel->getPassword()))) ->setCreationTime(new DateTimeImmutable($userModel->getCreationDate())) ->setChangingTime(new DateTimeImmutable($userModel->getChangingDate())) ->setRole($userModel->getRoles()); -- GitLab