diff --git a/creating.sql b/creating.sql index 3144d5f6aba10e96b4a054cd1ee065a8bb893d26..ff1c08f9fe9c9763e1c4b7d8eabb290132861673 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 ea1b91864043303e855f062e95126f59cf45ba99..5dfca271c495338c977966dae034d9aa8f04b8c7 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 744364ac6a7b9c19bb7ec3424b1b6cf8254e95c0..184dde61823f03a139b6d8743221bd8a93fad5fc 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 0000000000000000000000000000000000000000..6735bab0b2bff2d0ef9cf891d281ef2c8679ffba --- /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 5d45bf5a0ad809b47b4a07b728050d55087c8e6e..76ba18a7f167fee03e599f327bb5b38c0d8ad4e3 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 93c12c70766a4472c43621618b1645c93026f56c..6256c45c6929c32c89c4b8704e84bde39931a4c0 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 803ec31f382439fc4727665698dccf17fcb785da..b7d251e9f5426c5e2ee58535f0dd7acccce543af 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 0c3d7dc890d1a79b17adac20e686cc721dbc51f9..0000000000000000000000000000000000000000 --- 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 fc90a9be0fc5dac0d2b63401a0f3dc67dc0b8eca..08c640cae2c38b67e9bf9575192ffdeb4d836964 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 f9290db877d146da5b2fdd9348de9367387d7b1d..af24c71b066a9153376d391ec358559307fd1ccf 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 d0c93215766e0df23816b1552b91fe9c48f99517..279a976c8f130c91a80b39a34666f325e736f44c 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 0000000000000000000000000000000000000000..be4641dc19b238b9561d23b0f306df3b34f82e79 --- /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 74ae8fa04c80fb7df1f3ea8e7c2b91427c69b4e7..b9cbbfbc84123c64137db1354b3ab73a175b9960 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 f0fd05da1561806d13f40cf76f7c617eab1882d1..c9c1381637b30cec7935ccd5998f1d41db146e24 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 77d229efda47371762d8f85147a8533f22d428e8..bac27b9326a1f11260ab5b6422c59f6cf2d93658 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 3678c134391a86c845410357baa9537c6738d7a4..6c03e30db12289d71a710c4dd8fc43bbc920acf5 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 c2aa5d4ce5fa19ccd7af8a064b2f2df168282164..04222228108b4e872cdbbd865052ab9fbbd74523 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 bec95740d23ddc8cec4b5ab5191202195f481b68..4021afec2b5a270fd8722580db3f54876025f68a 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 095b90dc97b6168942d6103013dc4925b8c68c4f..b88fb624755cc4d6876a076b02b45e9a446ef734 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 df2a26f79175a502da554c9e95aba24e4f2f519b..de118800d25f61f2a264ccf7e49bb15f40527c4e 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 0000000000000000000000000000000000000000..b24359a87a2af6e53e7c4adc2ac1d99bc1cf53b0 --- /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 538fd777c3d7f7e5d32598d0cdebee83d061a38d..5b7ad936343256540820f79e2f578e6952c1aa39 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 f0092bccbc6290d6c4075b818edc9fa1b4ef4669..812c0071eaf5b9472fec565a278625559266cbb4 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 e64391af0d5520b5ef532d630366eec84d179cd5..703a64e03b5d91f25a82335bff66cef79bf0bab2 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 bbd959bd8a7caf21ff257c6903769eec47b518d5..0000000000000000000000000000000000000000 --- 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 25997b5322ec1a49c359d0ba9429d739de5d9d08..beb65e4f7dd26b18f359420a6ec73cc3380186a3 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 0000000000000000000000000000000000000000..119a5761ad6cf7541babe6e00458a5c49d6d79a5 --- /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 8fcf8610c195084921a2978034e3d0dd0238b721..cafecb0af0db37237d72552a4738d26b39002bf5 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 bd57eb4caaaa53c873e0d761282e93fb2d9eea4a..871ecdb881929161cccc4ff2280e7c4b9721fe14 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 73506a7c44672fdada4c2ffef76735956df8d65e..88d61e724109be87c0f01baff6b1fa0e0adad82c 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 7ef3dba2d3422f80557b7e3144820d383eed49c6..66908f5759ab8d4369f54a627d6ce6da9529d94b 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 263c6eaa356f6f05df1c9fea4c50c598b6c66909..aea3325978c101050b7c17ebca0fd31d0aab3729 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());