diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e7d65cce..00000000 --- a/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM adoptopenjdk/openjdk11:alpine-jre -VOLUME /tmp -ARG JAR_FILE=target/*.jar -COPY ${JAR_FILE} app.jar -ENTRYPOINT ["java","-jar","/app.jar"] \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0ad25db4..cce8fa1f 100644 --- a/LICENSE +++ b/LICENSE @@ -85,16 +85,16 @@ distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through +parties to make or receive copies. Mere interaction with a userEntity through a computer network, with no transfer of a copy, is not conveying. - An interactive user interface displays "Appropriate Legal Notices" + An interactive userEntity interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the +tells the userEntity that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a +the interface presents a list of userEntity commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. @@ -215,7 +215,7 @@ terms of section 4, provided that you also meet all of these conditions: permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. - d) If the work has interactive user interfaces, each must display + d) If the work has interactive userEntity interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. @@ -287,9 +287,9 @@ tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a +product received by a particular userEntity, "normally used" refers to a typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user +of the particular userEntity or of the way in which the particular userEntity actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent diff --git a/README.md b/README.md index 2906f0fd..04978091 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,11 @@ git clone https://github.com/coma123/Spring-Boot-Blog-REST-API.git ``` **2. Create Mysql database** + ```bash create database blogapi ``` + - run `src/main/resources/blogapi.sql` **3. Change mysql username and password as per your installation** @@ -28,6 +30,7 @@ create database blogapi ```bash mvn spring-boot:run ``` + The app will start running at ## Explore Rest APIs @@ -36,86 +39,87 @@ The app defines following CRUD APIs. ### Auth -| Method | Url | Decription | Sample Valid Request Body | -| ------ | --- | ---------- | --------------------------- | -| POST | /api/auth/signup | Sign up | [JSON](#signup) | -| POST | /api/auth/signin | Log in | [JSON](#signin) | +| Method | Url | Decription | Sample Valid Request Body | +|--------|------------------|------------|---------------------------| +| POST | /api/auth/signup | Sign up | [JSON](#signup) | +| POST | /api/auth/signin | Log in | [JSON](#signin) | ### Users -| Method | Url | Description | Sample Valid Request Body | -| ------ | --- | ----------- | ------------------------- | -| GET | /api/users/me | Get logged in user profile | | -| GET | /api/users/{username}/profile | Get user profile by username | | -| GET | /api/users/{username}/posts | Get posts created by user | | -| GET | /api/users/{username}/albums | Get albums created by user | | -| GET | /api/users/checkUsernameAvailability | Check if username is available to register | | -| GET | /api/users/checkEmailAvailability | Check if email is available to register | | -| POST | /api/users | Add user (Only for admins) | [JSON](#usercreate) | -| PUT | /api/users/{username} | Update user (If profile belongs to logged in user or logged in user is admin) | [JSON](#userupdate) | -| DELETE | /api/users/{username} | Delete user (For logged in user or admin) | | -| PUT | /api/users/{username}/giveAdmin | Give admin role to user (only for admins) | | -| PUT | /api/users/{username}/TakeAdmin | Take admin role from user (only for admins) | | -| PUT | /api/users/setOrUpdateInfo | Update user profile (If profile belongs to logged in user or logged in user is admin) | [JSON](#userinfoupdate) | +| Method | Url | Description | Sample Valid Request Body | +|--------|--------------------------------------|---------------------------------------------------------------------------------------------------------|---------------------------| +| GET | /api/users/me | Get logged in userEntity profile | | +| GET | /api/users/{username}/profile | Get userEntity profile by username | | +| GET | /api/users/{username}/posts | Get posts created by userEntity | | +| GET | /api/users/{username}/albums | Get albums created by userEntity | | +| GET | /api/users/checkUsernameAvailability | Check if username is available to register | | +| GET | /api/users/checkEmailAvailability | Check if email is available to register | | +| POST | /api/users | Add userEntity (Only for admins) | [JSON](#usercreate) | +| PUT | /api/users/{username} | Update userEntity (If profile belongs to logged in userEntity or logged in userEntity is admin) | [JSON](#userupdate) | +| DELETE | /api/users/{username} | Delete userEntity (For logged in userEntity or admin) | | +| PUT | /api/users/{username}/giveAdmin | Give admin role to userEntity (only for admins) | | +| PUT | /api/users/{username}/TakeAdmin | Take admin role from userEntity (only for admins) | | +| PUT | /api/users/setOrUpdateInfo | Update userEntity profile (If profile belongs to logged in userEntity or logged in userEntity is admin) | [JSON](#userinfoupdate) | ### Posts -| Method | Url | Description | Sample Valid Request Body | -| ------ | --- | ----------- | ------------------------- | -| GET | /api/posts | Get all posts | | -| GET | /api/posts/{id} | Get post by id | | -| POST | /api/posts | Create new post (By logged in user) | [JSON](#postcreate) | -| PUT | /api/posts/{id} | Update post (If post belongs to logged in user or logged in user is admin) | [JSON](#postupdate) | -| DELETE | /api/posts/{id} | Delete post (If post belongs to logged in user or logged in user is admin) | | +| Method | Url | Description | Sample Valid Request Body | +|--------|-----------------|----------------------------------------------------------------------------------------|---------------------------| +| GET | /api/posts | Get all posts | | +| GET | /api/posts/{id} | Get post by id | | +| POST | /api/posts | Create new post (By logged in userEntity) | [JSON](#postcreate) | +| PUT | /api/posts/{id} | Update post (If post belongs to logged in userEntity or logged in userEntity is admin) | [JSON](#postupdate) | +| DELETE | /api/posts/{id} | Delete post (If post belongs to logged in userEntity or logged in userEntity is admin) | | ### Comments -| Method | Url | Description | Sample Valid Request Body | -| ------ | --- | ----------- | ------------------------- | -| GET | /api/posts/{postId}/comments | Get all comments which belongs to post with id = postId | | -| GET | /api/posts/{postId}/comments/{id} | Get comment by id if it belongs to post with id = postId | | -| POST | /api/posts/{postId}/comments | Create new comment for post with id = postId (By logged in user) | [JSON](#commentcreate) | -| PUT | /api/posts/{postId}/comments/{id} | Update comment by id if it belongs to post with id = postId (If comment belongs to logged in user or logged in user is admin) | [JSON](#commentupdate) | -| DELETE | /api/posts/{postId}/comments/{id} | Delete comment by id if it belongs to post with id = postId (If comment belongs to logged in user or logged in user is admin) | | +| Method | Url | Description | Sample Valid Request Body | +|--------|-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|---------------------------| +| GET | /api/posts/{postId}/comments | Get all comments which belongs to post with id = postId | | +| GET | /api/posts/{postId}/comments/{id} | Get comment by id if it belongs to post with id = postId | | +| POST | /api/posts/{postId}/comments | Create new comment for post with id = postId (By logged in userEntity) | [JSON](#commentcreate) | +| PUT | /api/posts/{postId}/comments/{id} | Update comment by id if it belongs to post with id = postId (If comment belongs to logged in userEntity or logged in userEntity is admin) | [JSON](#commentupdate) | +| DELETE | /api/posts/{postId}/comments/{id} | Delete comment by id if it belongs to post with id = postId (If comment belongs to logged in userEntity or logged in userEntity is admin) | | ### Albums -| Method | Url | Description | Sample Valid Request Body | -| ------ | --- | ----------- | ------------------------- | -| GET | /api/albums | Get all albums | | -| GET | /api/albums/{id} | Get album by id | | -| POST | /api/albums | Create new album (By logged in user) | [JSON](#albumcreate) | -| PUT | /api/albums/{id} | Update album (If album belongs to logged in user or logged in user is admin) | [JSON](#albumupdate) | -| DELETE | /api/albums/{id} | Delete album (If album belongs to logged in user or logged in user is admin) | | -| GET | /api/albums/{id}/photos | Get all photos which belongs to album with id = id | | +| Method | Url | Description | Sample Valid Request Body | +|--------|-------------------------|------------------------------------------------------------------------------------------|---------------------------| +| GET | /api/albums | Get all albums | | +| GET | /api/albums/{id} | Get album by id | | +| POST | /api/albums | Create new album (By logged in userEntity) | [JSON](#albumcreate) | +| PUT | /api/albums/{id} | Update album (If album belongs to logged in userEntity or logged in userEntity is admin) | [JSON](#albumupdate) | +| DELETE | /api/albums/{id} | Delete album (If album belongs to logged in userEntity or logged in userEntity is admin) | | +| GET | /api/albums/{id}/photos | Get all photos which belongs to album with id = id | | ### Photos -| Method | Url | Description | Sample Valid Request Body | -| ------ | --- | ----------- | ------------------------- | -| GET | /api/photos | Get all photos | | -| GET | /api/photos/{id} | Get photo by id | | -| POST | /api/photos | Create new photo (By logged in user) | [JSON](#photocreate) | -| PUT | /api/photos/{id} | Update photo (If photo belongs to logged in user or logged in user is admin) | [JSON](#photoupdate) | -| DELETE | /api/photos/{id} | Delete photo (If photo belongs to logged in user or logged in user is admin) | | +| Method | Url | Description | Sample Valid Request Body | +|--------|------------------|------------------------------------------------------------------------------------------|---------------------------| +| GET | /api/photos | Get all photos | | +| GET | /api/photos/{id} | Get photo by id | | +| POST | /api/photos | Create new photo (By logged in userEntity) | [JSON](#photocreate) | +| PUT | /api/photos/{id} | Update photo (If photo belongs to logged in userEntity or logged in userEntity is admin) | [JSON](#photoupdate) | +| DELETE | /api/photos/{id} | Delete photo (If photo belongs to logged in userEntity or logged in userEntity is admin) | | ### Todos -| Method | Url | Description | Sample Valid Request Body | -| ------ | --- | ----------- | ------------------------- | -| GET | /api/todos | Get all todos which belongs to logged in user | | -| GET | /api/todos/{id} | Get todo by id (If todo belongs to logged in user) | | -| POST | /api/todos | Create new todo (By logged in user) | [JSON](#todocreate) | -| PUT | /api/todos/{id} | Update todo (If todo belongs to logged in user) | [JSON](#todoupdate) | -| DELETE | /api/todos/{id} | Delete todo (If todo belongs to logged in user) | | -| PUT | /api/todos/{id}/complete | Mark todo as complete (If todo belongs to logged in user) | | -| PUT | /api/todos/{id}/unComplete | Mark todo as uncomplete (If todo belongs to logged in user) | | +| Method | Url | Description | Sample Valid Request Body | +|--------|-----------------------------------|-------------------------------------------------------------------------------|---------------------------| +| GET | /api/todoEntities | Get all todoEntities which belongs to logged in userEntity | | +| GET | /api/todoEntities/{id} | Get todoEntity by id (If todoEntity belongs to logged in userEntity) | | +| POST | /api/todoEntities | Create new todoEntity (By logged in userEntity) | [JSON](#todocreate) | +| PUT | /api/todoEntities/{id} | Update todoEntity (If todoEntity belongs to logged in userEntity) | [JSON](#todoupdate) | +| DELETE | /api/todoEntities/{id} | Delete todoEntity (If todoEntity belongs to logged in userEntity) | | +| PUT | /api/todoEntities/{id}/complete | Mark todoEntity as complete (If todoEntity belongs to logged in userEntity) | | +| PUT | /api/todoEntities/{id}/unComplete | Mark todoEntity as uncomplete (If todoEntity belongs to logged in userEntity) | | Test them using postman or any other rest client. ## Sample Valid JSON Request Bodys ##### Sign Up -> /api/auth/signup + ```json { "firstName": "Leanne", @@ -127,6 +131,7 @@ Test them using postman or any other rest client. ``` ##### Log In -> /api/auth/signin + ```json { "usernameOrEmail": "leanne", @@ -135,6 +140,7 @@ Test them using postman or any other rest client. ``` ##### Create User -> /api/users + ```json { "firstName": "Ervin", @@ -163,6 +169,7 @@ Test them using postman or any other rest client. ``` ##### Update User -> /api/users/{username} + ```json { "firstName": "Ervin", @@ -191,6 +198,7 @@ Test them using postman or any other rest client. ``` ##### Update User Profile -> /api/users/setOrUpdateInfo + ```json { "street": "Douglas Extension", @@ -208,6 +216,7 @@ Test them using postman or any other rest client. ``` ##### Create Post -> /api/posts + ```json { "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", @@ -216,6 +225,7 @@ Test them using postman or any other rest client. ``` ##### Update Post -> /api/posts/{id} + ```json { "title": "UPDATED UPDATED UPDATED UPDATED UPDATED UPDATED", @@ -224,6 +234,7 @@ Test them using postman or any other rest client. ``` ##### Create Comment -> /api/posts/{postId}/comments + ```json { "body": "laudantium enim quasi est quidem magnam voluptate ipsam eos tempora quo necessitatibus dolor quam autem quasi reiciendis et nam sapiente accusantium" @@ -231,6 +242,7 @@ Test them using postman or any other rest client. ``` ##### Update Comment -> /api/posts/{postId}/comments/{id} + ```json { "body": "UPDATED UPDATED UPDATED UPDATED UPDATED UPDATED UPDATED UPDATED UPDATED UPDATED " @@ -238,6 +250,7 @@ Test them using postman or any other rest client. ``` ##### Create Album -> /api/albums + ```json { "title": "quidem molestiae enim" @@ -245,6 +258,7 @@ Test them using postman or any other rest client. ``` ##### Update Album -> /api/albums/{id} + ```json { "title": "quidem molestiae enim UPDATED" @@ -252,6 +266,7 @@ Test them using postman or any other rest client. ``` ##### Create Photo -> /api/photos + ```json { "title": "accusamus beatae ad facilis cum similique qui sunt", @@ -262,6 +277,7 @@ Test them using postman or any other rest client. ``` ##### Update Photo -> /api/photos{id} + ```json { "title": "accusamus beatae ad facilis ", @@ -271,7 +287,8 @@ Test them using postman or any other rest client. } ``` -##### Create Todo -> /api/todos +##### Create Todo -> /api/todoEntities + ```json { "title": "delectus aut autem", @@ -279,11 +296,13 @@ Test them using postman or any other rest client. } ``` -##### Update Todo -> /api/todos{id} +##### Update Todo -> /api/todoEntities{id} + ```json { "title": "delectus aut autem Updated", "completed": true } ``` + ![segment](https://api.segment.io/v1/pixel/track?data=ewogICJ3cml0ZUtleSI6ICJwcDJuOTU4VU1NT21NR090MWJXS0JQd0tFNkcydW51OCIsCiAgInVzZXJJZCI6ICIxMjNibG9nYXBpMTIzIiwKICAiZXZlbnQiOiAiQmxvZ0FwaSB2aXNpdGVkIiwKICAicHJvcGVydGllcyI6IHsKICAgICJzdWJqZWN0IjogIkJsb2dBcGkgdmlzaXRlZCIsCiAgICAiZW1haWwiOiAiY29tcy5zcHVyc0BnbWFpbC5jb20iCiAgfQp9) diff --git a/data/blogapi.sql b/data/blogapi.sql deleted file mode 100644 index 5cc9ced8..00000000 --- a/data/blogapi.sql +++ /dev/null @@ -1,192 +0,0 @@ -USE blogapi; - -UNLOCK TABLES; - -DROP TABLE IF EXISTS `post_tag`; -DROP TABLE IF EXISTS `tags`; -DROP TABLE IF EXISTS `user_role`; -DROP TABLE IF EXISTS `roles`; -DROP TABLE IF EXISTS `comments`; -DROP TABLE IF EXISTS `posts`; -DROP TABLE IF EXISTS `photos`; -DROP TABLE IF EXISTS `albums`; -DROP TABLE IF EXISTS `todos`; -DROP TABLE IF EXISTS `users`; -DROP TABLE IF EXISTS `address`; -DROP TABLE IF EXISTS `company`; -DROP TABLE IF EXISTS `geo`; - -CREATE TABLE `tags` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned NOT NULL, - `updated_by` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `geo` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `lat` varchar(255), - `lng` varchar(255), - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `company` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255), - `catch_phrase` varchar(255), - `bs` varchar(255), - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `address` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `street` varchar(255), - `suite` varchar(255), - `city` varchar(255), - `zipcode` varchar(255), - `geo_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_geo` (`geo_id`), - CONSTRAINT `fk_geo` FOREIGN KEY (`geo_id`) REFERENCES `geo` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `users` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `first_name` varchar(255) NOT NULL, - `last_name` varchar(255) NOT NULL, - `username` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `email` varchar(255) NOT NULL, - `address_id` bigint(19) unsigned DEFAULT NULL, - `phone` varchar(255), - `website` varchar(255), - `company_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - KEY `fk_address` (`address_id`), - KEY `fk_company` (`company_id`), - CONSTRAINT `fk_address` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `fk_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `todos` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `completed` boolean default false, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_user_todos` (`user_id`), - CONSTRAINT `fk_user_todos` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `albums` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_user_album` (`user_id`), - CONSTRAINT `fk_user_album` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `photos` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `url` varchar(255) NOT NULL, - `thumbnail_url` varchar(255) NOT NULL, - `album_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_album` (`album_id`), - CONSTRAINT `fk_album` FOREIGN KEY (`album_id`) REFERENCES `albums` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `posts` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `body` text NOT NULL, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_user_post` (`user_id`), - CONSTRAINT `fk_user_post` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `post_tag` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `post_id` bigint(19) unsigned NOT NULL, - `tag_id` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `fk_posttag_post_id` (`post_id`), - KEY `fk_posttag_tag_id` (`tag_id`), - CONSTRAINT `fk_posttag_post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`), - CONSTRAINT `fk_posttag_tag_id` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `comments` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `email` varchar(255) NOT NULL, - `body` text NOT NULL, - `post_id` bigint(19) unsigned DEFAULT NULL, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned NOT NULL, - `updated_by` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `fk_comment_post` (`post_id`), - KEY `fk_comment_user` (`user_id`), - CONSTRAINT `fk_comment_post` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`), - CONSTRAINT `fk_comment_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `roles` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `user_role` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `user_id` bigint(19) unsigned NOT NULL, - `role_id` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `fk_security_user_id` (`user_id`), - KEY `fk_security_role_id` (`role_id`), - CONSTRAINT `fk_security_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), - CONSTRAINT `fk_security_role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -LOCK TABLES `roles` WRITE; -INSERT INTO `roles` VALUES (1,'ROLE_ADMIN'),(2,'ROLE_USER'); -UNLOCK TABLES; diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 9bd9053e..00000000 --- a/docker-compose.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: '3.8' -services: - db: - image: mysql - container_name: blogapi-db - restart: always - environment: - MYSQL_DATABASE: 'blogapi' - MYSQL_PASSWORD: 'root' - MYSQL_ROOT_PASSWORD: 'root' - ports: - - '3306:3306' - networks: - - blogapi-network - healthcheck: - test: "/usr/bin/mysql --user=root --password=root --execute \"SHOW DATABASES;\"" - interval: 2s - timeout: 20s - retries: 10 - volumes: - - ./data:/docker-entrypoint-initdb.d - application: - container_name: blogapi-application - build: - context: ./ - dockerfile: Dockerfile - ports: - - "8080:8080" - networks: - - blogapi-network - depends_on: - - "db" -networks: - blogapi-network: - name: blogapi-network - driver: bridge diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 00000000..bff7f5e0 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.8' +services: + db: + image: 'postgres:16.3' + container_name: postgres_db + restart: always + ports: + - "5432:5432" + environment: + POSTGRES_DB: blogapi + POSTGRES_USER: blogapi_user + POSTGRES_PASSWORD: blogapi_pass + POSTGRES_ROOT_PASSWORD: blogapi_root_pass + volumes: + - ./init.sql:/docker-entrypoint-initdb.d/init.sql diff --git a/docker/init.sql b/docker/init.sql new file mode 100644 index 00000000..cc7fc32b --- /dev/null +++ b/docker/init.sql @@ -0,0 +1,186 @@ +DROP TABLE IF EXISTS post_tag; +DROP TABLE IF EXISTS tags; +DROP TABLE IF EXISTS user_role; +DROP TABLE IF EXISTS roles; +DROP TABLE IF EXISTS comments; +DROP TABLE IF EXISTS posts; +DROP TABLE IF EXISTS photos; +DROP TABLE IF EXISTS albums; +DROP TABLE IF EXISTS todos; +DROP TABLE IF EXISTS users; +DROP TABLE IF EXISTS address; +DROP TABLE IF EXISTS company; +DROP TABLE IF EXISTS geo; + +CREATE TABLE IF NOT EXISTS tags +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + name varchar(255) NOT NULL, + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS geo +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + lat varchar(255), + lng varchar(255), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS company +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + name varchar(255), + catch_phrase varchar(255), + bs varchar(255), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS address +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + street varchar(255), + suite varchar(255), + city varchar(255), + zipcode varchar(255), + geo_id bigint check (geo_id > 0) NOT NULL REFERENCES geo (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS users +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + first_name varchar(255) NOT NULL, + last_name varchar(255) NOT NULL, + username varchar(255) NOT NULL, + password varchar(255) NOT NULL, + email varchar(255) NOT NULL, + phone varchar(255), + website varchar(255), + address_id bigint check (address_id > 0) DEFAULT NULL REFERENCES address (id), + company_id bigint check (company_id > 0) DEFAULT NULL REFERENCES company (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint, + updated_by bigint, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS todos +( + todo_id bigint check (todo_id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + title varchar(255) NOT NULL, + completed boolean default false, + user_id bigint check (user_id > 0) DEFAULT NULL REFERENCES users (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (todo_id) +); + +CREATE TABLE IF NOT EXISTS albums +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + title varchar(255) NOT NULL, + user_id bigint check (user_id > 0) DEFAULT NULL REFERENCES users (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE photos +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + title varchar(255) NOT NULL, + url varchar(255) NOT NULL, + thumbnail_url varchar(255) NOT NULL, + album_id bigint check (album_id > 0) DEFAULT NULL REFERENCES albums (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS categories +( + category_id bigint check (category_id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + name varchar(255) NOT NULL, + user_id bigint check (user_id > 0) DEFAULT NULL REFERENCES users (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (category_id) +); + +CREATE TABLE posts +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + title varchar(255) NOT NULL, + body text NOT NULL, + user_id bigint check (user_id > 0) DEFAULT NULL REFERENCES users (id), + category_id bigint check (category_id > 0) DEFAULT NULL REFERENCES categories (category_id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE post_tag +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + post_id bigint check (post_id > 0) NOT NULL REFERENCES posts (id), + tag_id bigint check ( tag_id > 0 ) NOT NULL REFERENCES tags (id), + PRIMARY KEY (id) +); + +CREATE TABLE comments +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + name varchar(255) NOT NULL, + email varchar(255) NOT NULL, + body text NOT NULL, + post_id bigint check ( post_id > 0 ) DEFAULT NULL REFERENCES posts (id), + user_id bigint check ( user_id > 0 ) DEFAULT NULL REFERENCES users (id), + created_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_by bigint check (created_by > 0) NOT NULL, + updated_by bigint check (updated_by > 0) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE roles +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + name varchar(255) NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE user_role +( + id bigint check (id > 0) NOT NULL GENERATED ALWAYS AS IDENTITY, + user_id bigint check ( user_id > 0 ) NOT NULL REFERENCES users (id), + role_id bigint check ( role_id > 0 ) NOT NULL REFERENCES roles (id), + PRIMARY KEY (id) +); diff --git a/mvnw.cmd b/mvnw.cmd index 019bd74d..2c9a787c 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -41,7 +41,7 @@ @REM set %HOME% to equivalent of $HOME if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") -@REM Execute a user defined script before this one +@REM Execute a userEntity defined script before this one if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre @REM check for pre script, once with legacy .bat ending and once with .cmd ending if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" diff --git a/pom.xml b/pom.xml index 4b6fd187..e74641e8 100644 --- a/pom.xml +++ b/pom.xml @@ -15,16 +15,17 @@ org.springframework.boot spring-boot-starter-parent - 2.1.8.RELEASE - + 3.2.5 + UTF-8 UTF-8 - 1.8 - coma123 - https://sonarcloud.io + 21 + 1.5.5.Final + coma123 + https://sonarcloud.io @@ -34,131 +35,167 @@ - mysql - mysql-connector-java + org.postgresql + postgresql runtime - - org.projectlombok - lombok - 1.18.12 - provided - - - - org.springframework.boot - spring-boot-starter-web - + + org.springframework.boot + spring-boot-starter-web + org.springframework.boot spring-boot-starter-aop - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - org.mockito - mockito-all - 2.0.2-beta - test - - - - - org.springframework.security - spring-security-test - test - - - - - - org.hamcrest - hamcrest-library - test - - - - - org.modelmapper - modelmapper - 2.3.5 - - - - org.springframework.boot - spring-boot-devtools - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - org.springframework.boot - spring-boot-starter-security - - - - org.springframework.security - spring-security-jwt - 1.0.9.RELEASE - - - - org.springframework.security.oauth - spring-security-oauth2 - [2.3.5,) - - - - io.jsonwebtoken - jjwt - 0.9.1 - - - - javax.xml.bind - jaxb-api - - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - - org.apache.commons - commons-lang3 - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - com.sopromadze.blogapi.BlogApiApplication - - - - - repackage - - - - - - + + + org.springframework.boot + spring-boot-starter-test + test + + + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + + org.projectlombok + lombok + provided + + + + + org.mockito + mockito-all + 2.0.2-beta + test + + + + org.springframework.security + spring-security-test + test + + + + + org.hamcrest + hamcrest-library + test + + + + org.modelmapper + modelmapper + 2.3.5 + + + + org.springframework.boot + spring-boot-devtools + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security + spring-security-jwt + 1.0.9.RELEASE + + + + org.springframework.security.oauth + spring-security-oauth2 + [2.3.5,) + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + + io.jsonwebtoken + jjwt-api + 0.12.5 + + + io.jsonwebtoken + jjwt-impl + 0.12.5 + + + io.jsonwebtoken + jjwt-jackson + 0.12.5 + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + org.apache.commons + commons-lang3 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + com.sopromadze.blogapi.BlogApiApplication + + + + + repackage + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + + + org.projectlombok + lombok + ${lombok.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + diff --git a/src/main/java/com/sopromadze/blogapi/BlogApiApplication.java b/src/main/java/com/sopromadze/blogapi/BlogApiApplication.java index 6e45ce6b..5fc2ac79 100644 --- a/src/main/java/com/sopromadze/blogapi/BlogApiApplication.java +++ b/src/main/java/com/sopromadze/blogapi/BlogApiApplication.java @@ -1,6 +1,6 @@ package com.sopromadze.blogapi; -import com.sopromadze.blogapi.security.JwtAuthenticationFilter; +import jakarta.annotation.PostConstruct; import org.modelmapper.ModelMapper; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -8,31 +8,24 @@ import org.springframework.context.annotation.Bean; import org.springframework.data.convert.Jsr310Converters; -import javax.annotation.PostConstruct; import java.util.TimeZone; @SpringBootApplication @EntityScan(basePackageClasses = { BlogApiApplication.class, Jsr310Converters.class }) - public class BlogApiApplication { - public static void main(String[] args) { - SpringApplication.run(BlogApiApplication.class, args); - } - - @PostConstruct - void init() { - TimeZone.setDefault(TimeZone.getTimeZone("UTC")); - } + public static void main(String[] args) { + SpringApplication.run(BlogApiApplication.class, args); + } - @Bean - public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter(); - } + @PostConstruct + void init() { + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); + } - @Bean - public ModelMapper modelMapper() { - return new ModelMapper(); - } + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } } diff --git a/src/main/java/com/sopromadze/blogapi/application/TodoUseCase.java b/src/main/java/com/sopromadze/blogapi/application/TodoUseCase.java new file mode 100644 index 00000000..9b11479b --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/application/TodoUseCase.java @@ -0,0 +1,23 @@ +package com.sopromadze.blogapi.application; + +import com.sopromadze.blogapi.domain.model.Todo; +import com.sopromadze.blogapi.domain.service.TodoPersistenceService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@RequiredArgsConstructor +@Component +public class TodoUseCase { + + private final TodoPersistenceService todoPersistenceService; + + public Todo createTodo(Todo todo, String creatorUsername) { + log.debug("[START insert] todo: {} creatorUsername: {}", todo, creatorUsername); + Todo response = todoPersistenceService.createTodo(todo, creatorUsername); + log.debug("[STOP insert] inserted: {}", response); + return response; + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/config/ApplicationConfiguration.java b/src/main/java/com/sopromadze/blogapi/config/ApplicationConfiguration.java new file mode 100644 index 00000000..f2a25ad9 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/config/ApplicationConfiguration.java @@ -0,0 +1,34 @@ +package com.sopromadze.blogapi.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +@Configuration +public class ApplicationConfiguration { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } + + @Bean + public AuthenticationProvider authenticationProvider(UserDetailsService userDetailsService, BCryptPasswordEncoder passwordEncoder) { + DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(passwordEncoder); + + authProvider.setUserDetailsService(userDetailsService); + + return authProvider; + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/config/AuditingConfig.java b/src/main/java/com/sopromadze/blogapi/config/AuditingConfig.java index 144a9444..a4b988be 100644 --- a/src/main/java/com/sopromadze/blogapi/config/AuditingConfig.java +++ b/src/main/java/com/sopromadze/blogapi/config/AuditingConfig.java @@ -15,24 +15,26 @@ @EnableJpaAuditing public class AuditingConfig { - @Bean - public AuditorAware auditorProvider() { - return new SpringSecurityAuditAwareImpl(); - } + @Bean + public AuditorAware auditorProvider() { + return new SpringSecurityAuditAwareImpl(); + } + } class SpringSecurityAuditAwareImpl implements AuditorAware { - @Override - public Optional getCurrentAuditor() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + @Override + public Optional getCurrentAuditor() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication == null || !authentication.isAuthenticated() || authentication instanceof AnonymousAuthenticationToken) { + return Optional.empty(); + } - if (authentication == null || !authentication.isAuthenticated() || authentication instanceof AnonymousAuthenticationToken) { - return Optional.empty(); - } + UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); - UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); + return Optional.ofNullable(userPrincipal.getId()); + } - return Optional.ofNullable(userPrincipal.getId()); - } } diff --git a/src/main/java/com/sopromadze/blogapi/config/JwtAuthenticationFilter.java b/src/main/java/com/sopromadze/blogapi/config/JwtAuthenticationFilter.java new file mode 100644 index 00000000..49f602cb --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/config/JwtAuthenticationFilter.java @@ -0,0 +1,62 @@ +package com.sopromadze.blogapi.config; + +import com.sopromadze.blogapi.service.JwtService; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +@RequiredArgsConstructor +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + private final JwtService jwtService; + + private final UserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + String authHeader = request.getHeader("Authorization"); + + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } + + String jwt = authHeader.substring(7); + String username = jwtService.extractUsername(jwt); + + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (username != null && authentication == null) { + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + + if (jwtService.isTokenValid(jwt, userDetails)) { + UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( + userDetails, + null, + userDetails.getAuthorities() + ); + + authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authToken); + } + } + + filterChain.doFilter(request, response); + + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/config/RoleSeeder.java b/src/main/java/com/sopromadze/blogapi/config/RoleSeeder.java new file mode 100644 index 00000000..b643b7aa --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/config/RoleSeeder.java @@ -0,0 +1,42 @@ +package com.sopromadze.blogapi.config; + +import com.sopromadze.blogapi.model.role.Role; +import com.sopromadze.blogapi.model.role.RoleName; +import com.sopromadze.blogapi.repository.RoleRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Optional; + +@Component +@Slf4j +@RequiredArgsConstructor +public class RoleSeeder implements ApplicationListener { + + private final RoleRepository roleRepository; + + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + loadRoles(); + } + + private void loadRoles() { + RoleName[] roleNames = new RoleName[] { RoleName.ROLE_ADMIN, RoleName.ROLE_USER }; + + Arrays.stream(roleNames).forEach(roleName -> { + Optional optionalRole = roleRepository.findByName(roleName); + + optionalRole.ifPresentOrElse(role -> log.info("Role {} already exists", role.getName()), + () -> { + Role roleToCreate = new Role(roleName); + roleRepository.save(roleToCreate); + log.info("Role {} created", roleToCreate.getName()); + }); + }); + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/config/SecurityConfiguration.java b/src/main/java/com/sopromadze/blogapi/config/SecurityConfiguration.java new file mode 100644 index 00000000..5c4e93cd --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/config/SecurityConfiguration.java @@ -0,0 +1,41 @@ +package com.sopromadze.blogapi.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity +@RequiredArgsConstructor +public class SecurityConfiguration { + + private final AuthenticationProvider authenticationProvider; + + private final JwtAuthenticationFilter jwtAuthenticationFilter; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) + .cors(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> { + auth.requestMatchers("/api/auth/**").permitAll(); + auth.anyRequest().authenticated(); + }) + .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authenticationProvider(authenticationProvider) + .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/config/SecutiryConfig.java b/src/main/java/com/sopromadze/blogapi/config/SecutiryConfig.java deleted file mode 100644 index 1a0c1175..00000000 --- a/src/main/java/com/sopromadze/blogapi/config/SecutiryConfig.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.sopromadze.blogapi.config; - -import com.sopromadze.blogapi.repository.UserRepository; -import com.sopromadze.blogapi.security.JwtAuthenticationEntryPoint; -import com.sopromadze.blogapi.security.JwtAuthenticationFilter; -import com.sopromadze.blogapi.service.impl.CustomUserDetailsServiceImpl; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.BeanIds; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity( - securedEnabled = true, - jsr250Enabled = true, - prePostEnabled = true) -public class SecutiryConfig extends WebSecurityConfigurerAdapter { - private final CustomUserDetailsServiceImpl customUserDetailsService; - private final JwtAuthenticationEntryPoint unauthorizedHandler; - private final JwtAuthenticationFilter jwtAuthenticationFilter; - - @Autowired - public SecutiryConfig(UserRepository userRepository, CustomUserDetailsServiceImpl customUserDetailsService, - JwtAuthenticationEntryPoint unauthorizedHandler, JwtAuthenticationFilter jwtAuthenticationFilter) { - this.customUserDetailsService = customUserDetailsService; - this.unauthorizedHandler = unauthorizedHandler; - this.jwtAuthenticationFilter = jwtAuthenticationFilter; - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - - http.cors().and().csrf().disable() - .exceptionHandling() - .authenticationEntryPoint(unauthorizedHandler) - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.STATELESS) - .and() - .authorizeRequests() - .antMatchers(HttpMethod.GET, "/api/**").permitAll() - .antMatchers(HttpMethod.POST, "/api/auth/**").permitAll() - .antMatchers(HttpMethod.GET, "/api/users/checkUsernameAvailability", "/api/users/checkEmailAvailability").permitAll() - .anyRequest().authenticated(); - - http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); - - } - - public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { - authenticationManagerBuilder.userDetailsService(customUserDetailsService) - .passwordEncoder(passwordEncoder()); - } - - @Bean(BeanIds.AUTHENTICATION_MANAGER) - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); - } - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } -} diff --git a/src/main/java/com/sopromadze/blogapi/config/WebMvcConfig.java b/src/main/java/com/sopromadze/blogapi/config/WebMvcConfig.java deleted file mode 100644 index 301ecb17..00000000 --- a/src/main/java/com/sopromadze/blogapi/config/WebMvcConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.sopromadze.blogapi.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class WebMvcConfig implements WebMvcConfigurer { - - @Value("cors.allowedOrings") - private String allowedOrigins; - - public void addCorsMappings(CorsRegistry registry) { - final long MAX_AGE_SECS = 3600; - - registry.addMapping("/**") - .allowedOrigins(allowedOrigins) - .allowedMethods("GET", "POST", "PUT", "DELETE") - .allowedHeaders("*") - .maxAge(MAX_AGE_SECS); - } -} diff --git a/src/main/java/com/sopromadze/blogapi/controller/AlbumController.java b/src/main/java/com/sopromadze/blogapi/controller/AlbumController.java index b5dc9ff4..cab58d6d 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/AlbumController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/AlbumController.java @@ -13,78 +13,69 @@ import com.sopromadze.blogapi.service.PhotoService; import com.sopromadze.blogapi.utils.AppConstants; import com.sopromadze.blogapi.utils.AppUtils; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/albums") public class AlbumController { - @Autowired - private AlbumService albumService; - @Autowired - private PhotoService photoService; + @Autowired + private AlbumService albumService; + + @Autowired + private PhotoService photoService; - @ExceptionHandler(ResponseEntityErrorException.class) - public ResponseEntity handleExceptions(ResponseEntityErrorException exception) { - return exception.getApiResponse(); - } + @ExceptionHandler(ResponseEntityErrorException.class) + public ResponseEntity handleExceptions(ResponseEntityErrorException exception) { + return exception.getApiResponse(); + } - @GetMapping - public PagedResponse getAllAlbums( - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - AppUtils.validatePageNumberAndSize(page, size); + @GetMapping + public PagedResponse getAllAlbums( + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + AppUtils.validatePageNumberAndSize(page, size); - return albumService.getAllAlbums(page, size); - } + return albumService.getAllAlbums(page, size); + } - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addAlbum(@Valid @RequestBody AlbumRequest albumRequest, @CurrentUser UserPrincipal currentUser) { - return albumService.addAlbum(albumRequest, currentUser); - } + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addAlbum(@Valid @RequestBody AlbumRequest albumRequest, @CurrentUser UserPrincipal currentUser) { + return albumService.addAlbum(albumRequest, currentUser); + } - @GetMapping("/{id}") - public ResponseEntity getAlbum(@PathVariable(name = "id") Long id) { - return albumService.getAlbum(id); - } + @GetMapping("/{id}") + public ResponseEntity getAlbum(@PathVariable(name = "id") Long id) { + return albumService.getAlbum(id); + } - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updateAlbum(@PathVariable(name = "id") Long id, @Valid @RequestBody AlbumRequest newAlbum, - @CurrentUser UserPrincipal currentUser) { - return albumService.updateAlbum(id, newAlbum, currentUser); - } + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updateAlbum(@PathVariable(name = "id") Long id, @Valid @RequestBody AlbumRequest newAlbum, + @CurrentUser UserPrincipal currentUser) { + return albumService.updateAlbum(id, newAlbum, currentUser); + } - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deleteAlbum(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { - return albumService.deleteAlbum(id, currentUser); - } + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deleteAlbum(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { + return albumService.deleteAlbum(id, currentUser); + } - @GetMapping("/{id}/photos") - public ResponseEntity> getAllPhotosByAlbum(@PathVariable(name = "id") Long id, - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + @GetMapping("/{id}/photos") + public ResponseEntity> getAllPhotosByAlbum(@PathVariable(name = "id") Long id, + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - PagedResponse response = photoService.getAllPhotosByAlbum(id, page, size); + PagedResponse response = photoService.getAllPhotosByAlbum(id, page, size); - return new ResponseEntity<>(response, HttpStatus.OK); - } + return new ResponseEntity<>(response, HttpStatus.OK); + } } diff --git a/src/main/java/com/sopromadze/blogapi/controller/AuthController.java b/src/main/java/com/sopromadze/blogapi/controller/AuthController.java deleted file mode 100644 index 5d49753d..00000000 --- a/src/main/java/com/sopromadze/blogapi/controller/AuthController.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.sopromadze.blogapi.controller; - -import com.sopromadze.blogapi.exception.AppException; -import com.sopromadze.blogapi.exception.BlogapiException; -import com.sopromadze.blogapi.model.role.Role; -import com.sopromadze.blogapi.model.role.RoleName; -import com.sopromadze.blogapi.model.user.User; -import com.sopromadze.blogapi.payload.ApiResponse; -import com.sopromadze.blogapi.payload.JwtAuthenticationResponse; -import com.sopromadze.blogapi.payload.LoginRequest; -import com.sopromadze.blogapi.payload.SignUpRequest; -import com.sopromadze.blogapi.repository.RoleRepository; -import com.sopromadze.blogapi.repository.UserRepository; -import com.sopromadze.blogapi.security.JwtTokenProvider; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.support.ServletUriComponentsBuilder; - -import javax.validation.Valid; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -@RestController -@RequestMapping("/api/auth") -public class AuthController { - private static final String USER_ROLE_NOT_SET = "User role not set"; - - @Autowired - private AuthenticationManager authenticationManager; - - @Autowired - private UserRepository userRepository; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Autowired - private JwtTokenProvider jwtTokenProvider; - - @PostMapping("/signin") - public ResponseEntity authenticateUser(@Valid @RequestBody LoginRequest loginRequest) { - Authentication authentication = authenticationManager.authenticate( - new UsernamePasswordAuthenticationToken(loginRequest.getUsernameOrEmail(), loginRequest.getPassword())); - - SecurityContextHolder.getContext().setAuthentication(authentication); - - String jwt = jwtTokenProvider.generateToken(authentication); - return ResponseEntity.ok(new JwtAuthenticationResponse(jwt)); - } - - @PostMapping("/signup") - public ResponseEntity registerUser(@Valid @RequestBody SignUpRequest signUpRequest) { - if (Boolean.TRUE.equals(userRepository.existsByUsername(signUpRequest.getUsername()))) { - throw new BlogapiException(HttpStatus.BAD_REQUEST, "Username is already taken"); - } - - if (Boolean.TRUE.equals(userRepository.existsByEmail(signUpRequest.getEmail()))) { - throw new BlogapiException(HttpStatus.BAD_REQUEST, "Email is already taken"); - } - - String firstName = signUpRequest.getFirstName().toLowerCase(); - - String lastName = signUpRequest.getLastName().toLowerCase(); - - String username = signUpRequest.getUsername().toLowerCase(); - - String email = signUpRequest.getEmail().toLowerCase(); - - String password = passwordEncoder.encode(signUpRequest.getPassword()); - - User user = new User(firstName, lastName, username, email, password); - - List roles = new ArrayList<>(); - - if (userRepository.count() == 0) { - roles.add(roleRepository.findByName(RoleName.ROLE_USER) - .orElseThrow(() -> new AppException(USER_ROLE_NOT_SET))); - roles.add(roleRepository.findByName(RoleName.ROLE_ADMIN) - .orElseThrow(() -> new AppException(USER_ROLE_NOT_SET))); - } else { - roles.add(roleRepository.findByName(RoleName.ROLE_USER) - .orElseThrow(() -> new AppException(USER_ROLE_NOT_SET))); - } - - user.setRoles(roles); - - User result = userRepository.save(user); - - URI location = ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/users/{userId}") - .buildAndExpand(result.getId()).toUri(); - - return ResponseEntity.created(location).body(new ApiResponse(Boolean.TRUE, "User registered successfully")); - } -} diff --git a/src/main/java/com/sopromadze/blogapi/controller/AuthenticationController.java b/src/main/java/com/sopromadze/blogapi/controller/AuthenticationController.java new file mode 100644 index 00000000..643c63bb --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/controller/AuthenticationController.java @@ -0,0 +1,49 @@ +package com.sopromadze.blogapi.controller; + +import com.sopromadze.blogapi.model.user.UserEntity; +import com.sopromadze.blogapi.payload.LoginResponse; +import com.sopromadze.blogapi.payload.LoginUserDto; +import com.sopromadze.blogapi.payload.RegisterUserDto; +import com.sopromadze.blogapi.service.AuthenticationService; +import com.sopromadze.blogapi.service.JwtService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping("/api/auth") +@RestController +@RequiredArgsConstructor +public class AuthenticationController { + + private final JwtService jwtService; + + private final AuthenticationService authenticationService; + + @PostMapping("/signup") + public ResponseEntity register(@RequestBody RegisterUserDto registerUserDto) { + UserEntity registeredUserEntity = authenticationService.signup(registerUserDto); + + return ResponseEntity.status(HttpStatus.CREATED) + .body(registeredUserEntity); + } + + @PostMapping("/login") + public ResponseEntity authenticate(@RequestBody LoginUserDto loginUserDto) { + UserEntity authenticatedUserEntity = authenticationService.authenticate(loginUserDto); + + String jwtToken = jwtService.generateToken(authenticatedUserEntity.getUsername()); + + LoginResponse loginResponse = LoginResponse.builder() + .token(jwtToken) + .expiresIn(jwtService.getJwtExpiration()) + .build(); + + return ResponseEntity.status(HttpStatus.OK) + .body(loginResponse); + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/controller/CategoryController.java b/src/main/java/com/sopromadze/blogapi/controller/CategoryController.java index 39b63842..1a74198d 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/CategoryController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/CategoryController.java @@ -8,59 +8,51 @@ import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.CategoryService; import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/categories") public class CategoryController { - @Autowired - private CategoryService categoryService; - - @GetMapping - public PagedResponse getAllCategories( - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - return categoryService.getAllCategories(page, size); - } - - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addCategory(@Valid @RequestBody Category category, - @CurrentUser UserPrincipal currentUser) { - - return categoryService.addCategory(category, currentUser); - } - - @GetMapping("/{id}") - public ResponseEntity getCategory(@PathVariable(name = "id") Long id) { - return categoryService.getCategory(id); - } - - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updateCategory(@PathVariable(name = "id") Long id, - @Valid @RequestBody Category category, @CurrentUser UserPrincipal currentUser) throws UnauthorizedException { - return categoryService.updateCategory(id, category, currentUser); - } - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deleteCategory(@PathVariable(name = "id") Long id, - @CurrentUser UserPrincipal currentUser) throws UnauthorizedException { - return categoryService.deleteCategory(id, currentUser); - } + @Autowired + private CategoryService categoryService; + + @GetMapping + public PagedResponse getAllCategories( + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + return categoryService.getAllCategories(page, size); + } + + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addCategory(@Valid @RequestBody Category category, + @CurrentUser UserPrincipal currentUser) { + + return categoryService.addCategory(category, currentUser); + } + + @GetMapping("/{id}") + public ResponseEntity getCategory(@PathVariable(name = "id") Long id) { + return categoryService.getCategory(id); + } + + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updateCategory(@PathVariable(name = "id") Long id, + @Valid @RequestBody Category category, @CurrentUser UserPrincipal currentUser) throws UnauthorizedException { + return categoryService.updateCategory(id, category, currentUser); + } + + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deleteCategory(@PathVariable(name = "id") Long id, + @CurrentUser UserPrincipal currentUser) throws UnauthorizedException { + return categoryService.deleteCategory(id, currentUser); + } } diff --git a/src/main/java/com/sopromadze/blogapi/controller/CommentController.java b/src/main/java/com/sopromadze/blogapi/controller/CommentController.java index 2a402910..1f07fe94 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/CommentController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/CommentController.java @@ -8,76 +8,68 @@ import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.CommentService; import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/posts/{postId}/comments") public class CommentController { - @Autowired - private CommentService commentService; - @GetMapping - public ResponseEntity> getAllComments(@PathVariable(name = "postId") Long postId, - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + @Autowired + private CommentService commentService; - PagedResponse allComments = commentService.getAllComments(postId, page, size); + @GetMapping + public ResponseEntity> getAllComments(@PathVariable(name = "postId") Long postId, + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - return new ResponseEntity< >(allComments, HttpStatus.OK); - } + PagedResponse allComments = commentService.getAllComments(postId, page, size); - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addComment(@Valid @RequestBody CommentRequest commentRequest, - @PathVariable(name = "postId") Long postId, @CurrentUser UserPrincipal currentUser) { - Comment newComment = commentService.addComment(commentRequest, postId, currentUser); + return new ResponseEntity<>(allComments, HttpStatus.OK); + } - return new ResponseEntity<>(newComment, HttpStatus.CREATED); - } + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addComment(@Valid @RequestBody CommentRequest commentRequest, + @PathVariable(name = "postId") Long postId, @CurrentUser UserPrincipal currentUser) { + Comment newComment = commentService.addComment(commentRequest, postId, currentUser); - @GetMapping("/{id}") - public ResponseEntity getComment(@PathVariable(name = "postId") Long postId, - @PathVariable(name = "id") Long id) { - Comment comment = commentService.getComment(postId, id); + return new ResponseEntity<>(newComment, HttpStatus.CREATED); + } - return new ResponseEntity<>(comment, HttpStatus.OK); - } + @GetMapping("/{id}") + public ResponseEntity getComment(@PathVariable(name = "postId") Long postId, + @PathVariable(name = "id") Long id) { + Comment comment = commentService.getComment(postId, id); - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updateComment(@PathVariable(name = "postId") Long postId, - @PathVariable(name = "id") Long id, @Valid @RequestBody CommentRequest commentRequest, - @CurrentUser UserPrincipal currentUser) { + return new ResponseEntity<>(comment, HttpStatus.OK); + } - Comment updatedComment = commentService.updateComment(postId, id, commentRequest, currentUser); + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updateComment(@PathVariable(name = "postId") Long postId, + @PathVariable(name = "id") Long id, @Valid @RequestBody CommentRequest commentRequest, + @CurrentUser UserPrincipal currentUser) { - return new ResponseEntity<>(updatedComment, HttpStatus.OK); - } + Comment updatedComment = commentService.updateComment(postId, id, commentRequest, currentUser); - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deleteComment(@PathVariable(name = "postId") Long postId, - @PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { + return new ResponseEntity<>(updatedComment, HttpStatus.OK); + } - ApiResponse response = commentService.deleteComment(postId, id, currentUser); + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deleteComment(@PathVariable(name = "postId") Long postId, + @PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { - HttpStatus status = response.getSuccess() ? HttpStatus.OK : HttpStatus.BAD_REQUEST; + ApiResponse response = commentService.deleteComment(postId, id, currentUser); - return new ResponseEntity<>(response, status); - } + HttpStatus status = response.getSuccess() ? HttpStatus.OK : HttpStatus.BAD_REQUEST; + + return new ResponseEntity<>(response, status); + } } diff --git a/src/main/java/com/sopromadze/blogapi/controller/PhotoController.java b/src/main/java/com/sopromadze/blogapi/controller/PhotoController.java index 2f0846d0..2b400621 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/PhotoController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/PhotoController.java @@ -8,66 +8,59 @@ import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.PhotoService; import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/photos") public class PhotoController { - @Autowired - private PhotoService photoService; - @GetMapping - public PagedResponse getAllPhotos( - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - return photoService.getAllPhotos(page, size); - } + @Autowired + private PhotoService photoService; + + @GetMapping + public PagedResponse getAllPhotos( + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + return photoService.getAllPhotos(page, size); + } + + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addPhoto(@Valid @RequestBody PhotoRequest photoRequest, + @CurrentUser UserPrincipal currentUser) { + PhotoResponse photoResponse = photoService.addPhoto(photoRequest, currentUser); - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addPhoto(@Valid @RequestBody PhotoRequest photoRequest, - @CurrentUser UserPrincipal currentUser) { - PhotoResponse photoResponse = photoService.addPhoto(photoRequest, currentUser); + return new ResponseEntity<>(photoResponse, HttpStatus.OK); + } - return new ResponseEntity< >(photoResponse, HttpStatus.OK); - } + @GetMapping("/{id}") + public ResponseEntity getPhoto(@PathVariable(name = "id") Long id) { + PhotoResponse photoResponse = photoService.getPhoto(id); - @GetMapping("/{id}") - public ResponseEntity getPhoto(@PathVariable(name = "id") Long id) { - PhotoResponse photoResponse = photoService.getPhoto(id); + return new ResponseEntity<>(photoResponse, HttpStatus.OK); + } - return new ResponseEntity< >(photoResponse, HttpStatus.OK); - } + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updatePhoto(@PathVariable(name = "id") Long id, + @Valid @RequestBody PhotoRequest photoRequest, @CurrentUser UserPrincipal currentUser) { - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updatePhoto(@PathVariable(name = "id") Long id, - @Valid @RequestBody PhotoRequest photoRequest, @CurrentUser UserPrincipal currentUser) { + PhotoResponse photoResponse = photoService.updatePhoto(id, photoRequest, currentUser); - PhotoResponse photoResponse = photoService.updatePhoto(id, photoRequest, currentUser); + return new ResponseEntity<>(photoResponse, HttpStatus.OK); + } - return new ResponseEntity< >(photoResponse, HttpStatus.OK); - } + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deletePhoto(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { + ApiResponse apiResponse = photoService.deletePhoto(id, currentUser); - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deletePhoto(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { - ApiResponse apiResponse = photoService.deletePhoto(id, currentUser); + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } - return new ResponseEntity< >(apiResponse, HttpStatus.OK); - } } diff --git a/src/main/java/com/sopromadze/blogapi/controller/PostController.java b/src/main/java/com/sopromadze/blogapi/controller/PostController.java index 5b8efcc7..71c6d4c7 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/PostController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/PostController.java @@ -9,87 +9,80 @@ import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.PostService; import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/posts") public class PostController { - @Autowired - private PostService postService; - - @GetMapping - public ResponseEntity> getAllPosts( - @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - PagedResponse response = postService.getAllPosts(page, size); - - return new ResponseEntity< >(response, HttpStatus.OK); - } - - @GetMapping("/category/{id}") - public ResponseEntity> getPostsByCategory( - @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size, - @PathVariable(name = "id") Long id) { - PagedResponse response = postService.getPostsByCategory(id, page, size); - - return new ResponseEntity< >(response, HttpStatus.OK); - } - - @GetMapping("/tag/{id}") - public ResponseEntity> getPostsByTag( - @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size, - @PathVariable(name = "id") Long id) { - PagedResponse response = postService.getPostsByTag(id, page, size); - - return new ResponseEntity< >(response, HttpStatus.OK); - } - - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addPost(@Valid @RequestBody PostRequest postRequest, - @CurrentUser UserPrincipal currentUser) { - PostResponse postResponse = postService.addPost(postRequest, currentUser); - - return new ResponseEntity< >(postResponse, HttpStatus.CREATED); - } - - @GetMapping("/{id}") - public ResponseEntity getPost(@PathVariable(name = "id") Long id) { - Post post = postService.getPost(id); - - return new ResponseEntity< >(post, HttpStatus.OK); - } - - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updatePost(@PathVariable(name = "id") Long id, - @Valid @RequestBody PostRequest newPostRequest, @CurrentUser UserPrincipal currentUser) { - Post post = postService.updatePost(id, newPostRequest, currentUser); - - return new ResponseEntity< >(post, HttpStatus.OK); - } - - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deletePost(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { - ApiResponse apiResponse = postService.deletePost(id, currentUser); - - return new ResponseEntity< >(apiResponse, HttpStatus.OK); - } + + @Autowired + private PostService postService; + + @GetMapping + public ResponseEntity> getAllPosts( + @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + PagedResponse response = postService.getAllPosts(page, size); + + return new ResponseEntity<>(response, HttpStatus.OK); + } + + @GetMapping("/category/{id}") + public ResponseEntity> getPostsByCategory( + @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size, + @PathVariable(name = "id") Long id) { + PagedResponse response = postService.getPostsByCategory(id, page, size); + + return new ResponseEntity<>(response, HttpStatus.OK); + } + + @GetMapping("/tag/{id}") + public ResponseEntity> getPostsByTag( + @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size, + @PathVariable(name = "id") Long id) { + PagedResponse response = postService.getPostsByTag(id, page, size); + + return new ResponseEntity<>(response, HttpStatus.OK); + } + + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addPost(@Valid @RequestBody PostRequest postRequest, + @CurrentUser UserPrincipal currentUser) { + PostResponse postResponse = postService.addPost(postRequest, currentUser); + + return new ResponseEntity<>(postResponse, HttpStatus.CREATED); + } + + @GetMapping("/{id}") + public ResponseEntity getPost(@PathVariable(name = "id") Long id) { + Post post = postService.getPost(id); + + return new ResponseEntity<>(post, HttpStatus.OK); + } + + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updatePost(@PathVariable(name = "id") Long id, + @Valid @RequestBody PostRequest newPostRequest, @CurrentUser UserPrincipal currentUser) { + Post post = postService.updatePost(id, newPostRequest, currentUser); + + return new ResponseEntity<>(post, HttpStatus.OK); + } + + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deletePost(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { + ApiResponse apiResponse = postService.deletePost(id, currentUser); + + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/controller/TagController.java b/src/main/java/com/sopromadze/blogapi/controller/TagController.java index 9a9b45c8..bfa0b58b 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/TagController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/TagController.java @@ -7,68 +7,61 @@ import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.TagService; import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/tags") public class TagController { - @Autowired - private TagService tagService; - @GetMapping - public ResponseEntity> getAllTags( - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + @Autowired + private TagService tagService; - PagedResponse response = tagService.getAllTags(page, size); + @GetMapping + public ResponseEntity> getAllTags( + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - return new ResponseEntity< >(response, HttpStatus.OK); - } + PagedResponse response = tagService.getAllTags(page, size); - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addTag(@Valid @RequestBody Tag tag, @CurrentUser UserPrincipal currentUser) { - Tag newTag = tagService.addTag(tag, currentUser); + return new ResponseEntity<>(response, HttpStatus.OK); + } - return new ResponseEntity< >(newTag, HttpStatus.CREATED); - } + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addTag(@Valid @RequestBody Tag tag, @CurrentUser UserPrincipal currentUser) { + Tag newTag = tagService.addTag(tag, currentUser); - @GetMapping("/{id}") - public ResponseEntity getTag(@PathVariable(name = "id") Long id) { - Tag tag = tagService.getTag(id); + return new ResponseEntity<>(newTag, HttpStatus.CREATED); + } - return new ResponseEntity< >(tag, HttpStatus.OK); - } + @GetMapping("/{id}") + public ResponseEntity getTag(@PathVariable(name = "id") Long id) { + Tag tag = tagService.getTag(id); - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updateTag(@PathVariable(name = "id") Long id, @Valid @RequestBody Tag tag, @CurrentUser UserPrincipal currentUser) { + return new ResponseEntity<>(tag, HttpStatus.OK); + } - Tag updatedTag = tagService.updateTag(id, tag, currentUser); + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updateTag(@PathVariable(name = "id") Long id, @Valid @RequestBody Tag tag, + @CurrentUser UserPrincipal currentUser) { - return new ResponseEntity< >(updatedTag, HttpStatus.OK); - } + Tag updatedTag = tagService.updateTag(id, tag, currentUser); - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deleteTag(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { - ApiResponse apiResponse = tagService.deleteTag(id, currentUser); + return new ResponseEntity<>(updatedTag, HttpStatus.OK); + } - return new ResponseEntity< >(apiResponse, HttpStatus.OK); - } + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deleteTag(@PathVariable(name = "id") Long id, @CurrentUser UserPrincipal currentUser) { + ApiResponse apiResponse = tagService.deleteTag(id, currentUser); + + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } } diff --git a/src/main/java/com/sopromadze/blogapi/controller/TodoController.java b/src/main/java/com/sopromadze/blogapi/controller/TodoController.java deleted file mode 100644 index aeb57789..00000000 --- a/src/main/java/com/sopromadze/blogapi/controller/TodoController.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.sopromadze.blogapi.controller; - -import com.sopromadze.blogapi.model.Todo; -import com.sopromadze.blogapi.payload.ApiResponse; -import com.sopromadze.blogapi.payload.PagedResponse; -import com.sopromadze.blogapi.security.CurrentUser; -import com.sopromadze.blogapi.security.UserPrincipal; -import com.sopromadze.blogapi.service.TodoService; -import com.sopromadze.blogapi.utils.AppConstants; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; - -@RestController -@RequestMapping("/api/todos") -public class TodoController { - - @Autowired - private TodoService todoService; - - @GetMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity> getAllTodos( - @CurrentUser UserPrincipal currentUser, - @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - - PagedResponse response = todoService.getAllTodos(currentUser, page, size); - - return new ResponseEntity< >(response, HttpStatus.OK); - } - - @PostMapping - @PreAuthorize("hasRole('USER')") - public ResponseEntity addTodo(@Valid @RequestBody Todo todo, @CurrentUser UserPrincipal currentUser) { - Todo newTodo = todoService.addTodo(todo, currentUser); - - return new ResponseEntity< >(newTodo, HttpStatus.CREATED); - } - - @GetMapping("/{id}") - @PreAuthorize("hasRole('USER')") - public ResponseEntity getTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { - Todo todo = todoService.getTodo(id, currentUser); - - return new ResponseEntity< >(todo, HttpStatus.OK); - } - - @PutMapping("/{id}") - @PreAuthorize("hasRole('USER')") - public ResponseEntity updateTodo(@PathVariable(value = "id") Long id, @Valid @RequestBody Todo newTodo, - @CurrentUser UserPrincipal currentUser) { - Todo updatedTodo = todoService.updateTodo(id, newTodo, currentUser); - - return new ResponseEntity< >(updatedTodo, HttpStatus.OK); - } - - @DeleteMapping("/{id}") - @PreAuthorize("hasRole('USER')") - public ResponseEntity deleteTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { - ApiResponse apiResponse = todoService.deleteTodo(id, currentUser); - - return new ResponseEntity<>(apiResponse, HttpStatus.OK); - } - - @PutMapping("/{id}/complete") - @PreAuthorize("hasRole('USER')") - public ResponseEntity completeTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { - - Todo todo = todoService.completeTodo(id, currentUser); - - return new ResponseEntity< >(todo, HttpStatus.OK); - } - - @PutMapping("/{id}/unComplete") - @PreAuthorize("hasRole('USER')") - public ResponseEntity unCompleteTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { - - Todo todo = todoService.unCompleteTodo(id, currentUser); - - return new ResponseEntity< >(todo, HttpStatus.OK); - } -} diff --git a/src/main/java/com/sopromadze/blogapi/controller/UserController.java b/src/main/java/com/sopromadze/blogapi/controller/UserController.java index f6b717e2..97e5526f 100644 --- a/src/main/java/com/sopromadze/blogapi/controller/UserController.java +++ b/src/main/java/com/sopromadze/blogapi/controller/UserController.java @@ -2,143 +2,130 @@ import com.sopromadze.blogapi.model.Album; import com.sopromadze.blogapi.model.Post; -import com.sopromadze.blogapi.model.user.User; -import com.sopromadze.blogapi.payload.ApiResponse; -import com.sopromadze.blogapi.payload.InfoRequest; -import com.sopromadze.blogapi.payload.PagedResponse; -import com.sopromadze.blogapi.payload.UserIdentityAvailability; -import com.sopromadze.blogapi.payload.UserProfile; -import com.sopromadze.blogapi.payload.UserSummary; +import com.sopromadze.blogapi.model.user.UserEntity; +import com.sopromadze.blogapi.payload.*; import com.sopromadze.blogapi.security.CurrentUser; import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.AlbumService; import com.sopromadze.blogapi.service.PostService; import com.sopromadze.blogapi.service.UserService; import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; +import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/api/users") public class UserController { - @Autowired - private UserService userService; - @Autowired - private PostService postService; + @Autowired + private UserService userService; - @Autowired - private AlbumService albumService; + @Autowired + private PostService postService; - @GetMapping("/me") - @PreAuthorize("hasRole('USER')") - public ResponseEntity getCurrentUser(@CurrentUser UserPrincipal currentUser) { - UserSummary userSummary = userService.getCurrentUser(currentUser); + @Autowired + private AlbumService albumService; - return new ResponseEntity< >(userSummary, HttpStatus.OK); - } + @GetMapping("/me") + @PreAuthorize("hasRole('USER')") + public ResponseEntity getCurrentUser(@CurrentUser UserPrincipal currentUser) { + UserSummary userSummary = userService.getCurrentUser(currentUser); - @GetMapping("/checkUsernameAvailability") - public ResponseEntity checkUsernameAvailability(@RequestParam(value = "username") String username) { - UserIdentityAvailability userIdentityAvailability = userService.checkUsernameAvailability(username); + return new ResponseEntity<>(userSummary, HttpStatus.OK); + } - return new ResponseEntity< >(userIdentityAvailability, HttpStatus.OK); - } + @GetMapping("/checkUsernameAvailability") + public ResponseEntity checkUsernameAvailability(@RequestParam(value = "username") String username) { + UserIdentityAvailability userIdentityAvailability = userService.checkUsernameAvailability(username); - @GetMapping("/checkEmailAvailability") - public ResponseEntity checkEmailAvailability(@RequestParam(value = "email") String email) { - UserIdentityAvailability userIdentityAvailability = userService.checkEmailAvailability(email); - return new ResponseEntity< >(userIdentityAvailability, HttpStatus.OK); - } + return new ResponseEntity<>(userIdentityAvailability, HttpStatus.OK); + } - @GetMapping("/{username}/profile") - public ResponseEntity getUSerProfile(@PathVariable(value = "username") String username) { - UserProfile userProfile = userService.getUserProfile(username); + @GetMapping("/checkEmailAvailability") + public ResponseEntity checkEmailAvailability(@RequestParam(value = "email") String email) { + UserIdentityAvailability userIdentityAvailability = userService.checkEmailAvailability(email); + return new ResponseEntity<>(userIdentityAvailability, HttpStatus.OK); + } - return new ResponseEntity< >(userProfile, HttpStatus.OK); - } + @GetMapping("/{username}/profile") + public ResponseEntity getUSerProfile(@PathVariable(value = "username") String username) { + UserProfile userProfile = userService.getUserProfile(username); - @GetMapping("/{username}/posts") - public ResponseEntity> getPostsCreatedBy(@PathVariable(value = "username") String username, - @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - PagedResponse response = postService.getPostsByCreatedBy(username, page, size); + return new ResponseEntity<>(userProfile, HttpStatus.OK); + } - return new ResponseEntity< >(response, HttpStatus.OK); - } + @GetMapping("/{username}/posts") + public ResponseEntity> getPostsCreatedBy(@PathVariable(value = "username") String username, + @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(value = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + PagedResponse response = postService.getPostsByCreatedBy(username, page, size); - @GetMapping("/{username}/albums") - public ResponseEntity> getUserAlbums(@PathVariable(name = "username") String username, - @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, - @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + return new ResponseEntity<>(response, HttpStatus.OK); + } - PagedResponse response = albumService.getUserAlbums(username, page, size); + @GetMapping("/{username}/albums") + public ResponseEntity> getUserAlbums(@PathVariable(name = "username") String username, + @RequestParam(name = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { - return new ResponseEntity< >(response, HttpStatus.OK); - } + PagedResponse response = albumService.getUserAlbums(username, page, size); - @PostMapping - @PreAuthorize("hasRole('ADMIN')") - public ResponseEntity addUser(@Valid @RequestBody User user) { - User newUser = userService.addUser(user); + return new ResponseEntity<>(response, HttpStatus.OK); + } - return new ResponseEntity< >(newUser, HttpStatus.CREATED); - } + @PostMapping + @PreAuthorize("hasRole('ADMIN')") + public ResponseEntity addUser(@Valid @RequestBody UserEntity userEntity) { + UserEntity newUserEntity = userService.addUser(userEntity); - @PutMapping("/{username}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity updateUser(@Valid @RequestBody User newUser, - @PathVariable(value = "username") String username, @CurrentUser UserPrincipal currentUser) { - User updatedUSer = userService.updateUser(newUser, username, currentUser); + return new ResponseEntity<>(newUserEntity, HttpStatus.CREATED); + } - return new ResponseEntity< >(updatedUSer, HttpStatus.CREATED); - } + @PutMapping("/{username}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity updateUser(@Valid @RequestBody UserEntity newUserEntity, + @PathVariable(value = "username") String username, @CurrentUser UserPrincipal currentUser) { + UserEntity updatedUSer = userService.updateUser(newUserEntity, username, currentUser); - @DeleteMapping("/{username}") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity deleteUser(@PathVariable(value = "username") String username, - @CurrentUser UserPrincipal currentUser) { - ApiResponse apiResponse = userService.deleteUser(username, currentUser); + return new ResponseEntity<>(updatedUSer, HttpStatus.CREATED); + } - return new ResponseEntity< >(apiResponse, HttpStatus.OK); - } + @DeleteMapping("/{username}") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity deleteUser(@PathVariable(value = "username") String username, + @CurrentUser UserPrincipal currentUser) { + ApiResponse apiResponse = userService.deleteUser(username, currentUser); - @PutMapping("/{username}/giveAdmin") - @PreAuthorize("hasRole('ADMIN')") - public ResponseEntity giveAdmin(@PathVariable(name = "username") String username) { - ApiResponse apiResponse = userService.giveAdmin(username); + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } - return new ResponseEntity< >(apiResponse, HttpStatus.OK); - } + @PutMapping("/{username}/giveAdmin") + @PreAuthorize("hasRole('ADMIN')") + public ResponseEntity giveAdmin(@PathVariable(name = "username") String username) { + ApiResponse apiResponse = userService.giveAdmin(username); - @PutMapping("/{username}/takeAdmin") - @PreAuthorize("hasRole('ADMIN')") - public ResponseEntity takeAdmin(@PathVariable(name = "username") String username) { - ApiResponse apiResponse = userService.removeAdmin(username); + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } - return new ResponseEntity< >(apiResponse, HttpStatus.OK); - } + @PutMapping("/{username}/takeAdmin") + @PreAuthorize("hasRole('ADMIN')") + public ResponseEntity takeAdmin(@PathVariable(name = "username") String username) { + ApiResponse apiResponse = userService.removeAdmin(username); - @PutMapping("/setOrUpdateInfo") - @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") - public ResponseEntity setAddress(@CurrentUser UserPrincipal currentUser, - @Valid @RequestBody InfoRequest infoRequest) { - UserProfile userProfile = userService.setOrUpdateInfo(currentUser, infoRequest); + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } - return new ResponseEntity< >(userProfile, HttpStatus.OK); - } + @PutMapping("/setOrUpdateInfo") + @PreAuthorize("hasRole('USER') or hasRole('ADMIN')") + public ResponseEntity setAddress(@CurrentUser UserPrincipal currentUser, + @Valid @RequestBody InfoRequest infoRequest) { + UserProfile userProfile = userService.setOrUpdateInfo(currentUser, infoRequest); + + return new ResponseEntity<>(userProfile, HttpStatus.OK); + } } diff --git a/src/main/java/com/sopromadze/blogapi/domain/model/Todo.java b/src/main/java/com/sopromadze/blogapi/domain/model/Todo.java new file mode 100644 index 00000000..2c12332e --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/domain/model/Todo.java @@ -0,0 +1,20 @@ +package com.sopromadze.blogapi.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class Todo { + + private Long todoId; + + private String title; + + private boolean completed; + +} diff --git a/src/main/java/com/sopromadze/blogapi/domain/port/TodoPersistencePort.java b/src/main/java/com/sopromadze/blogapi/domain/port/TodoPersistencePort.java new file mode 100644 index 00000000..7427c423 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/domain/port/TodoPersistencePort.java @@ -0,0 +1,9 @@ +package com.sopromadze.blogapi.domain.port; + +import com.sopromadze.blogapi.domain.model.Todo; + +public interface TodoPersistencePort { + + Todo insert(Todo todo, String creatorUsername); + +} diff --git a/src/main/java/com/sopromadze/blogapi/domain/service/TodoPersistenceService.java b/src/main/java/com/sopromadze/blogapi/domain/service/TodoPersistenceService.java new file mode 100644 index 00000000..e727a007 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/domain/service/TodoPersistenceService.java @@ -0,0 +1,23 @@ +package com.sopromadze.blogapi.domain.service; + +import com.sopromadze.blogapi.domain.model.Todo; +import com.sopromadze.blogapi.domain.port.TodoPersistencePort; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@RequiredArgsConstructor +@Service +public class TodoPersistenceService { + + private final TodoPersistencePort todoPersistencePort; + + public Todo createTodo(Todo todo, String creatorUsername) { + log.debug("[START insert] todo: {} creatorUsername: {}", todo, creatorUsername); + Todo response = todoPersistencePort.insert(todo, creatorUsername); + log.debug("[STOP insert] inserted: {}", response); + return response; + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/exception/AccessDeniedException.java b/src/main/java/com/sopromadze/blogapi/exception/AccessDeniedException.java index ba5391e1..725c09eb 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/AccessDeniedException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/AccessDeniedException.java @@ -6,40 +6,41 @@ @ResponseStatus(code = HttpStatus.UNAUTHORIZED) public class AccessDeniedException extends RuntimeException { - private static final long serialVersionUID = 1L; - private ApiResponse apiResponse; + private static final long serialVersionUID = 1L; - private String message; + private ApiResponse apiResponse; - public AccessDeniedException(ApiResponse apiResponse) { - super(); - this.apiResponse = apiResponse; - } + private String message; - public AccessDeniedException(String message) { - super(message); - this.message = message; - } + public AccessDeniedException(ApiResponse apiResponse) { + super(); + this.apiResponse = apiResponse; + } - public AccessDeniedException(String message, Throwable cause) { - super(message, cause); - } + public AccessDeniedException(String message) { + super(message); + this.message = message; + } - public ApiResponse getApiResponse() { - return apiResponse; - } + public AccessDeniedException(String message, Throwable cause) { + super(message, cause); + } - public void setApiResponse(ApiResponse apiResponse) { - this.apiResponse = apiResponse; - } + public ApiResponse getApiResponse() { + return apiResponse; + } - public String getMessage() { - return message; - } + public void setApiResponse(ApiResponse apiResponse) { + this.apiResponse = apiResponse; + } - public void setMessage(String message) { - this.message = message; - } + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } } diff --git a/src/main/java/com/sopromadze/blogapi/exception/AppException.java b/src/main/java/com/sopromadze/blogapi/exception/AppException.java index a213876d..d22046db 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/AppException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/AppException.java @@ -5,13 +5,15 @@ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public class AppException extends RuntimeException { - private static final long serialVersionUID = 1L; - public AppException(String message) { - super(message); - } + private static final long serialVersionUID = 1L; + + public AppException(String message) { + super(message); + } + + public AppException(String message, Throwable cause) { + super(message, cause); + } - public AppException(String message, Throwable cause) { - super(message, cause); - } } diff --git a/src/main/java/com/sopromadze/blogapi/exception/BadRequestException.java b/src/main/java/com/sopromadze/blogapi/exception/BadRequestException.java index a35149fe..9389dd02 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/BadRequestException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/BadRequestException.java @@ -6,24 +6,26 @@ @ResponseStatus(HttpStatus.BAD_REQUEST) public class BadRequestException extends RuntimeException { - private static final long serialVersionUID = 1L; - private ApiResponse apiResponse; + private static final long serialVersionUID = 1L; - public BadRequestException(ApiResponse apiResponse) { - super(); - this.apiResponse = apiResponse; - } + private ApiResponse apiResponse; - public BadRequestException(String message) { - super(message); - } + public BadRequestException(ApiResponse apiResponse) { + super(); + this.apiResponse = apiResponse; + } - public BadRequestException(String message, Throwable cause) { - super(message, cause); - } + public BadRequestException(String message) { + super(message); + } + + public BadRequestException(String message, Throwable cause) { + super(message, cause); + } + + public ApiResponse getApiResponse() { + return apiResponse; + } - public ApiResponse getApiResponse() { - return apiResponse; - } } diff --git a/src/main/java/com/sopromadze/blogapi/exception/BlogapiException.java b/src/main/java/com/sopromadze/blogapi/exception/BlogapiException.java index 4da4fd63..7d979b9e 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/BlogapiException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/BlogapiException.java @@ -4,29 +4,30 @@ public class BlogapiException extends RuntimeException { - private static final long serialVersionUID = -6593330219878485669L; - - private final HttpStatus status; - private final String message; - - public BlogapiException(HttpStatus status, String message) { - super(); - this.status = status; - this.message = message; - } - - public BlogapiException(HttpStatus status, String message, Throwable exception) { - super(exception); - this.status = status; - this.message = message; - } - - public HttpStatus getStatus() { - return status; - } - - public String getMessage() { - return message; - } + private static final long serialVersionUID = -6593330219878485669L; + + private final HttpStatus status; + + private final String message; + + public BlogapiException(HttpStatus status, String message) { + super(); + this.status = status; + this.message = message; + } + + public BlogapiException(HttpStatus status, String message, Throwable exception) { + super(exception); + this.status = status; + this.message = message; + } + + public HttpStatus getStatus() { + return status; + } + + public String getMessage() { + return message; + } } diff --git a/src/main/java/com/sopromadze/blogapi/exception/ResourceNotFoundException.java b/src/main/java/com/sopromadze/blogapi/exception/ResourceNotFoundException.java index 4dd90e07..5ac1b817 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/ResourceNotFoundException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/ResourceNotFoundException.java @@ -6,40 +6,44 @@ @ResponseStatus(value = HttpStatus.NOT_FOUND) public class ResourceNotFoundException extends RuntimeException { - private static final long serialVersionUID = 1L; - private transient ApiResponse apiResponse; + private static final long serialVersionUID = 1L; - private String resourceName; - private String fieldName; - private Object fieldValue; + private transient ApiResponse apiResponse; - public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) { - super(); - this.resourceName = resourceName; - this.fieldName = fieldName; - this.fieldValue = fieldValue; - } + private String resourceName; - public String getResourceName() { - return resourceName; - } + private String fieldName; - public String getFieldName() { - return fieldName; - } + private Object fieldValue; - public Object getFieldValue() { - return fieldValue; - } + public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) { + super(); + this.resourceName = resourceName; + this.fieldName = fieldName; + this.fieldValue = fieldValue; + } - public ApiResponse getApiResponse() { - return apiResponse; - } + public String getResourceName() { + return resourceName; + } - private void setApiResponse() { - String message = String.format("%s not found with %s: '%s'", resourceName, fieldName, fieldValue); + public String getFieldName() { + return fieldName; + } + + public Object getFieldValue() { + return fieldValue; + } + + public ApiResponse getApiResponse() { + return apiResponse; + } + + private void setApiResponse() { + String message = String.format("%s not found with %s: '%s'", resourceName, fieldName, fieldValue); + + apiResponse = new ApiResponse(Boolean.FALSE, message); + } - apiResponse = new ApiResponse(Boolean.FALSE, message); - } } diff --git a/src/main/java/com/sopromadze/blogapi/exception/ResponseEntityErrorException.java b/src/main/java/com/sopromadze/blogapi/exception/ResponseEntityErrorException.java index f5aeaaed..b6b76e43 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/ResponseEntityErrorException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/ResponseEntityErrorException.java @@ -4,15 +4,17 @@ import org.springframework.http.ResponseEntity; public class ResponseEntityErrorException extends RuntimeException { - private static final long serialVersionUID = -3156815846745801694L; - private transient ResponseEntity apiResponse; + private static final long serialVersionUID = -3156815846745801694L; - public ResponseEntityErrorException(ResponseEntity apiResponse) { - this.apiResponse = apiResponse; - } + private transient ResponseEntity apiResponse; + + public ResponseEntityErrorException(ResponseEntity apiResponse) { + this.apiResponse = apiResponse; + } + + public ResponseEntity getApiResponse() { + return apiResponse; + } - public ResponseEntity getApiResponse() { - return apiResponse; - } } diff --git a/src/main/java/com/sopromadze/blogapi/exception/RestControllerExceptionHandler.java b/src/main/java/com/sopromadze/blogapi/exception/RestControllerExceptionHandler.java index a9372e45..14460689 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/RestControllerExceptionHandler.java +++ b/src/main/java/com/sopromadze/blogapi/exception/RestControllerExceptionHandler.java @@ -21,98 +21,99 @@ @ControllerAdvice public class RestControllerExceptionHandler { - public ResponseEntity resolveException(BlogapiException exception) { - String message = exception.getMessage(); - HttpStatus status = exception.getStatus(); - - ApiResponse apiResponse = new ApiResponse(); - - apiResponse.setSuccess(Boolean.FALSE); - apiResponse.setMessage(message); - - return new ResponseEntity<>(apiResponse, status); - } - - @ExceptionHandler(UnauthorizedException.class) - @ResponseBody - @ResponseStatus(code = HttpStatus.UNAUTHORIZED) - public ResponseEntity resolveException(UnauthorizedException exception) { - - ApiResponse apiResponse = exception.getApiResponse(); - - return new ResponseEntity<>(apiResponse, HttpStatus.UNAUTHORIZED); - } - - @ExceptionHandler(BadRequestException.class) - @ResponseBody - public ResponseEntity resolveException(BadRequestException exception) { - ApiResponse apiResponse = exception.getApiResponse(); - - return new ResponseEntity<>(apiResponse, HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler(ResourceNotFoundException.class) - @ResponseBody - public ResponseEntity resolveException(ResourceNotFoundException exception) { - ApiResponse apiResponse = exception.getApiResponse(); - - return new ResponseEntity<>(apiResponse, HttpStatus.NOT_FOUND); - } - - @ExceptionHandler(AccessDeniedException.class) - @ResponseBody - public ResponseEntity resolveException(AccessDeniedException exception) { - ApiResponse apiResponse = exception.getApiResponse(); - - return new ResponseEntity< >(apiResponse, HttpStatus.FORBIDDEN); - } - - @ExceptionHandler({ MethodArgumentNotValidException.class }) - @ResponseBody - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ResponseEntity resolveException(MethodArgumentNotValidException ex) { - List fieldErrors = ex.getBindingResult().getFieldErrors(); - List messages = new ArrayList<>(fieldErrors.size()); - for (FieldError error : fieldErrors) { - messages.add(error.getField() + " - " + error.getDefaultMessage()); - } - return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.BAD_REQUEST.getReasonPhrase(), - HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler({ MethodArgumentTypeMismatchException.class }) - @ResponseBody - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ResponseEntity resolveException(MethodArgumentTypeMismatchException ex) { - String message = "Parameter '" + ex.getParameter().getParameterName() + "' must be '" - + Objects.requireNonNull(ex.getRequiredType()).getSimpleName() + "'"; - List messages = new ArrayList<>(1); - messages.add(message); - return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.BAD_REQUEST.getReasonPhrase(), - HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); - } - - @ExceptionHandler({ HttpRequestMethodNotSupportedException.class }) - @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) - @ResponseBody - public ResponseEntity resolveException(HttpRequestMethodNotSupportedException ex) { - String message = "Request method '" + ex.getMethod() + "' not supported. List of all supported methods - " - + ex.getSupportedHttpMethods(); - List messages = new ArrayList<>(1); - messages.add(message); - - return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase(), - HttpStatus.METHOD_NOT_ALLOWED.value()), HttpStatus.METHOD_NOT_ALLOWED); - } - - @ExceptionHandler({ HttpMessageNotReadableException.class }) - @ResponseBody - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ResponseEntity resolveException(HttpMessageNotReadableException ex) { - String message = "Please provide Request Body in valid JSON format"; - List messages = new ArrayList<>(1); - messages.add(message); - return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.BAD_REQUEST.getReasonPhrase(), - HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); - } + public ResponseEntity resolveException(BlogapiException exception) { + String message = exception.getMessage(); + HttpStatus status = exception.getStatus(); + + ApiResponse apiResponse = new ApiResponse(); + + apiResponse.setSuccess(Boolean.FALSE); + apiResponse.setMessage(message); + + return new ResponseEntity<>(apiResponse, status); + } + + @ExceptionHandler(UnauthorizedException.class) + @ResponseBody + @ResponseStatus(code = HttpStatus.UNAUTHORIZED) + public ResponseEntity resolveException(UnauthorizedException exception) { + + ApiResponse apiResponse = exception.getApiResponse(); + + return new ResponseEntity<>(apiResponse, HttpStatus.UNAUTHORIZED); + } + + @ExceptionHandler(BadRequestException.class) + @ResponseBody + public ResponseEntity resolveException(BadRequestException exception) { + ApiResponse apiResponse = exception.getApiResponse(); + + return new ResponseEntity<>(apiResponse, HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(ResourceNotFoundException.class) + @ResponseBody + public ResponseEntity resolveException(ResourceNotFoundException exception) { + ApiResponse apiResponse = exception.getApiResponse(); + + return new ResponseEntity<>(apiResponse, HttpStatus.NOT_FOUND); + } + + @ExceptionHandler(AccessDeniedException.class) + @ResponseBody + public ResponseEntity resolveException(AccessDeniedException exception) { + ApiResponse apiResponse = exception.getApiResponse(); + + return new ResponseEntity<>(apiResponse, HttpStatus.FORBIDDEN); + } + + @ExceptionHandler({ MethodArgumentNotValidException.class }) + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseEntity resolveException(MethodArgumentNotValidException ex) { + List fieldErrors = ex.getBindingResult().getFieldErrors(); + List messages = new ArrayList<>(fieldErrors.size()); + for (FieldError error : fieldErrors) { + messages.add(error.getField() + " - " + error.getDefaultMessage()); + } + return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.BAD_REQUEST.getReasonPhrase(), + HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler({ MethodArgumentTypeMismatchException.class }) + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseEntity resolveException(MethodArgumentTypeMismatchException ex) { + String message = "Parameter '" + ex.getParameter().getParameterName() + "' must be '" + + Objects.requireNonNull(ex.getRequiredType()).getSimpleName() + "'"; + List messages = new ArrayList<>(1); + messages.add(message); + return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.BAD_REQUEST.getReasonPhrase(), + HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler({ HttpRequestMethodNotSupportedException.class }) + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + @ResponseBody + public ResponseEntity resolveException(HttpRequestMethodNotSupportedException ex) { + String message = "Request method '" + ex.getMethod() + "' not supported. List of all supported methods - " + + ex.getSupportedHttpMethods(); + List messages = new ArrayList<>(1); + messages.add(message); + + return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.METHOD_NOT_ALLOWED.getReasonPhrase(), + HttpStatus.METHOD_NOT_ALLOWED.value()), HttpStatus.METHOD_NOT_ALLOWED); + } + + @ExceptionHandler({ HttpMessageNotReadableException.class }) + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ResponseEntity resolveException(HttpMessageNotReadableException ex) { + String message = "Please provide Request Body in valid JSON format"; + List messages = new ArrayList<>(1); + messages.add(message); + return new ResponseEntity<>(new ExceptionResponse(messages, HttpStatus.BAD_REQUEST.getReasonPhrase(), + HttpStatus.BAD_REQUEST.value()), HttpStatus.BAD_REQUEST); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/exception/UnauthorizedException.java b/src/main/java/com/sopromadze/blogapi/exception/UnauthorizedException.java index 1760c66b..acc59dbc 100644 --- a/src/main/java/com/sopromadze/blogapi/exception/UnauthorizedException.java +++ b/src/main/java/com/sopromadze/blogapi/exception/UnauthorizedException.java @@ -6,40 +6,41 @@ @ResponseStatus(code = HttpStatus.UNAUTHORIZED) public class UnauthorizedException extends RuntimeException { - private static final long serialVersionUID = 1L; - private ApiResponse apiResponse; + private static final long serialVersionUID = 1L; - private String message; + private ApiResponse apiResponse; - public UnauthorizedException(ApiResponse apiResponse) { - super(); - this.apiResponse = apiResponse; - } + private String message; - public UnauthorizedException(String message) { - super(message); - this.message = message; - } + public UnauthorizedException(ApiResponse apiResponse) { + super(); + this.apiResponse = apiResponse; + } - public UnauthorizedException(String message, Throwable cause) { - super(message, cause); - } + public UnauthorizedException(String message) { + super(message); + this.message = message; + } - public ApiResponse getApiResponse() { - return apiResponse; - } + public UnauthorizedException(String message, Throwable cause) { + super(message, cause); + } - public void setApiResponse(ApiResponse apiResponse) { - this.apiResponse = apiResponse; - } + public ApiResponse getApiResponse() { + return apiResponse; + } - public String getMessage() { - return message; - } + public void setApiResponse(ApiResponse apiResponse) { + this.apiResponse = apiResponse; + } - public void setMessage(String message) { - this.message = message; - } + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } } diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/adapter/TodoPostgresqlPersistenceAdapter.java b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/adapter/TodoPostgresqlPersistenceAdapter.java new file mode 100644 index 00000000..f1073c7b --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/adapter/TodoPostgresqlPersistenceAdapter.java @@ -0,0 +1,34 @@ +package com.sopromadze.blogapi.infrastructure.persistence.postgresql.adapter; + +import com.sopromadze.blogapi.domain.model.Todo; +import com.sopromadze.blogapi.domain.port.TodoPersistencePort; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.mapper.TodoEntityMapper; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.repository.TodoRepository; +import com.sopromadze.blogapi.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class TodoPostgresqlPersistenceAdapter implements TodoPersistencePort { + + private final TodoEntityMapper todoEntityMapper; + + private final TodoRepository todoRepository; + + private final UserRepository userRepository; + + @Override + public Todo insert(Todo todo, String creatorUsername) { + TodoEntity todoEntity = todoEntityMapper.toEntity(todo); + userRepository.findByUsername(creatorUsername) + .ifPresent(todoEntity::setUser); + TodoEntity savedTodo = todoRepository.save(todoEntity); + return todoEntityMapper.toDomain(savedTodo); + } + +} + diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/entity/TodoEntity.java b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/entity/TodoEntity.java new file mode 100644 index 00000000..66307612 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/entity/TodoEntity.java @@ -0,0 +1,36 @@ +package com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity; + +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import com.sopromadze.blogapi.model.user.UserEntity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Entity +@Table(name = "todos", uniqueConstraints = { @UniqueConstraint(columnNames = { "title" }) }) +public class TodoEntity extends MetadataEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "todo_id") + private Long todoId; + + @Column(name = "title") + private String title; + + @Column(name = "completed") + private boolean completed; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private UserEntity user; + +} diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/mapper/TodoEntityMapper.java b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/mapper/TodoEntityMapper.java new file mode 100644 index 00000000..9db5bdc2 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/mapper/TodoEntityMapper.java @@ -0,0 +1,14 @@ +package com.sopromadze.blogapi.infrastructure.persistence.postgresql.mapper; + +import com.sopromadze.blogapi.domain.model.Todo; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface TodoEntityMapper { + + TodoEntity toEntity(Todo todo); + + Todo toDomain(TodoEntity todoEntity); + +} diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/repository/TodoRepository.java b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/repository/TodoRepository.java new file mode 100644 index 00000000..ecb8d3b6 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/persistence/postgresql/repository/TodoRepository.java @@ -0,0 +1,14 @@ +package com.sopromadze.blogapi.infrastructure.persistence.postgresql.repository; + +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface TodoRepository extends JpaRepository { + + Page findByCreatedBy(Long userId, Pageable pageable); + +} diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/rest/controller/TodoController.java b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/controller/TodoController.java new file mode 100644 index 00000000..77933e25 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/controller/TodoController.java @@ -0,0 +1,101 @@ +package com.sopromadze.blogapi.infrastructure.rest.controller; + +import com.sopromadze.blogapi.application.TodoUseCase; +import com.sopromadze.blogapi.domain.model.Todo; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; +import com.sopromadze.blogapi.infrastructure.rest.mapper.TodoMapper; +import com.sopromadze.blogapi.infrastructure.rest.payload.request.TodoPostRequestDto; +import com.sopromadze.blogapi.infrastructure.rest.payload.response.TodoResponseDto; +import com.sopromadze.blogapi.payload.ApiResponse; +import com.sopromadze.blogapi.payload.PagedResponse; +import com.sopromadze.blogapi.security.CurrentUser; +import com.sopromadze.blogapi.security.UserPrincipal; +import com.sopromadze.blogapi.service.TodoService; +import com.sopromadze.blogapi.utils.AppConstants; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/todos") +public class TodoController { + + private final TodoService todoService; + + private final TodoMapper todoMapper; + + private final TodoUseCase todoUseCase; + + @GetMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity> getAllTodos( + @CurrentUser UserPrincipal currentUser, + @RequestParam(value = "page", required = false, defaultValue = AppConstants.DEFAULT_PAGE_NUMBER) Integer page, + @RequestParam(name = "size", required = false, defaultValue = AppConstants.DEFAULT_PAGE_SIZE) Integer size) { + + PagedResponse response = todoService.getAllTodos(currentUser, page, size); + + return new ResponseEntity<>(response, HttpStatus.OK); + } + + @PostMapping + @PreAuthorize("hasRole('USER')") + public ResponseEntity addTodo(@Valid @RequestBody TodoPostRequestDto requestDto, + @AuthenticationPrincipal(expression = "username") String username) { + Todo todo = todoMapper.toDomain(requestDto); + Todo createdTodo = todoUseCase.createTodo(todo, username); + TodoResponseDto responseDto = todoMapper.toResponseDto(createdTodo); + + return ResponseEntity.status(HttpStatus.CREATED) + .body(responseDto); + } + + @GetMapping("/{id}") + @PreAuthorize("hasRole('USER')") + public ResponseEntity getTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { + TodoEntity todoEntity = todoService.getTodo(id, currentUser); + + return new ResponseEntity<>(todoEntity, HttpStatus.OK); + } + + @PutMapping("/{id}") + @PreAuthorize("hasRole('USER')") + public ResponseEntity updateTodo(@PathVariable(value = "id") Long id, @Valid @RequestBody TodoEntity newTodoEntity, + @CurrentUser UserPrincipal currentUser) { + TodoEntity updatedTodoEntity = todoService.updateTodo(id, newTodoEntity, currentUser); + + return new ResponseEntity<>(updatedTodoEntity, HttpStatus.OK); + } + + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('USER')") + public ResponseEntity deleteTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { + ApiResponse apiResponse = todoService.deleteTodo(id, currentUser); + + return new ResponseEntity<>(apiResponse, HttpStatus.OK); + } + + @PutMapping("/{id}/complete") + @PreAuthorize("hasRole('USER')") + public ResponseEntity completeTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { + + TodoEntity todoEntity = todoService.completeTodo(id, currentUser); + + return new ResponseEntity<>(todoEntity, HttpStatus.OK); + } + + @PutMapping("/{id}/unComplete") + @PreAuthorize("hasRole('USER')") + public ResponseEntity unCompleteTodo(@PathVariable(value = "id") Long id, @CurrentUser UserPrincipal currentUser) { + + TodoEntity todoEntity = todoService.unCompleteTodo(id, currentUser); + + return new ResponseEntity<>(todoEntity, HttpStatus.OK); + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/rest/mapper/TodoMapper.java b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/mapper/TodoMapper.java new file mode 100644 index 00000000..0d7443b1 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/mapper/TodoMapper.java @@ -0,0 +1,15 @@ +package com.sopromadze.blogapi.infrastructure.rest.mapper; + +import com.sopromadze.blogapi.domain.model.Todo; +import com.sopromadze.blogapi.infrastructure.rest.payload.request.TodoPostRequestDto; +import com.sopromadze.blogapi.infrastructure.rest.payload.response.TodoResponseDto; +import org.mapstruct.Mapper; + +@Mapper(componentModel = "spring") +public interface TodoMapper { + + Todo toDomain(TodoPostRequestDto todoPostRequestDto); + + TodoResponseDto toResponseDto(Todo todo); + +} diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/rest/payload/request/TodoPostRequestDto.java b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/payload/request/TodoPostRequestDto.java new file mode 100644 index 00000000..6675d60b --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/payload/request/TodoPostRequestDto.java @@ -0,0 +1,20 @@ +package com.sopromadze.blogapi.infrastructure.rest.payload.request; + +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TodoPostRequestDto { + + @NotEmpty(message = "The title is required.") + @Size(min = 2, max = 100, message = "The length of title must be between 2 and 100 characters.") + private String title; + +} diff --git a/src/main/java/com/sopromadze/blogapi/infrastructure/rest/payload/response/TodoResponseDto.java b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/payload/response/TodoResponseDto.java new file mode 100644 index 00000000..7dee1fe9 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/infrastructure/rest/payload/response/TodoResponseDto.java @@ -0,0 +1,20 @@ +package com.sopromadze.blogapi.infrastructure.rest.payload.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TodoResponseDto { + + private Long todoId; + + private String title; + + private boolean completed; + +} diff --git a/src/main/java/com/sopromadze/blogapi/model/Album.java b/src/main/java/com/sopromadze/blogapi/model/Album.java index 311d5991..e35e80d7 100644 --- a/src/main/java/com/sopromadze/blogapi/model/Album.java +++ b/src/main/java/com/sopromadze/blogapi/model/Album.java @@ -1,64 +1,39 @@ package com.sopromadze.blogapi.model; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import com.sopromadze.blogapi.model.user.UserEntity; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotBlank; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; @EqualsAndHashCode(callSuper = true) -@Entity @Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Entity @Table(name = "albums", uniqueConstraints = { @UniqueConstraint(columnNames = { "title" }) }) -public class Album extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotBlank - @Column(name = "title") - private String title; +public class Album extends MetadataEntity { - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id") - private User user; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @OneToMany(mappedBy = "album", cascade = CascadeType.ALL, orphanRemoval = true) - private List photo; + @NotBlank + @Column(name = "title") + private String title; - @JsonIgnore - public User getUser() { - return user; - } + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private UserEntity user; - public List getPhoto() { - return this.photo == null ? null : new ArrayList<>(this.photo); - } + @OneToMany(mappedBy = "album", cascade = CascadeType.ALL, orphanRemoval = true) + private List photo; - public void setPhoto(List photo) { - if (photo == null) { - this.photo = null; - } else { - this.photo = Collections.unmodifiableList(photo); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/model/Category.java b/src/main/java/com/sopromadze/blogapi/model/Category.java index 102c6e39..920d2486 100644 --- a/src/main/java/com/sopromadze/blogapi/model/Category.java +++ b/src/main/java/com/sopromadze/blogapi/model/Category.java @@ -2,19 +2,12 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import com.sopromadze.blogapi.model.audit.UserDateAudit; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.Table; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -25,34 +18,34 @@ @NoArgsConstructor @Table(name = "categories") @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Category extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "name") - private String name; - - @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) - private List posts; - - public Category(String name) { - super(); - this.name = name; - } - - public List getPosts() { - return this.posts == null ? null : new ArrayList<>(this.posts); - } - - public void setPosts(List posts) { - if (posts == null) { - this.posts = null; - } else { - this.posts = Collections.unmodifiableList(posts); - } - } +public class Category extends MetadataEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "category_id") + private Long categoryId; + + @Column(name = "name") + private String name; + + @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, orphanRemoval = true) + private List posts; + + public Category(String name) { + super(); + this.name = name; + } + + public List getPosts() { + return this.posts == null ? null : new ArrayList<>(this.posts); + } + + public void setPosts(List posts) { + if (posts == null) { + this.posts = null; + } else { + this.posts = Collections.unmodifiableList(posts); + } + } } diff --git a/src/main/java/com/sopromadze/blogapi/model/Comment.java b/src/main/java/com/sopromadze/blogapi/model/Comment.java index d9d21972..a46d8dd3 100644 --- a/src/main/java/com/sopromadze/blogapi/model/Comment.java +++ b/src/main/java/com/sopromadze/blogapi/model/Comment.java @@ -1,31 +1,23 @@ package com.sopromadze.blogapi.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import com.sopromadze.blogapi.model.user.UserEntity; +import jakarta.persistence.*; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; - @EqualsAndHashCode(callSuper = true) @Entity @Data @NoArgsConstructor @Table(name = "comments") -public class Comment extends UserDateAudit { +public class Comment extends MetadataEntity { + private static final long serialVersionUID = 1L; @Id @@ -54,7 +46,7 @@ public class Comment extends UserDateAudit { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") - private User user; + private UserEntity user; public Comment(@NotBlank @Size(min = 10, message = "Comment body must be minimum 10 characters") String body) { this.body = body; @@ -66,7 +58,8 @@ public Post getPost() { } @JsonIgnore - public User getUser() { + public UserEntity getUser() { return user; } + } diff --git a/src/main/java/com/sopromadze/blogapi/model/Photo.java b/src/main/java/com/sopromadze/blogapi/model/Photo.java index 7aaa1d2a..b0eb324f 100644 --- a/src/main/java/com/sopromadze/blogapi/model/Photo.java +++ b/src/main/java/com/sopromadze/blogapi/model/Photo.java @@ -1,60 +1,52 @@ package com.sopromadze.blogapi.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotBlank; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotBlank; - @EqualsAndHashCode(callSuper = true) @Entity @Data @NoArgsConstructor @Table(name = "photos", uniqueConstraints = { @UniqueConstraint(columnNames = { "title" }) }) -public class Photo extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotBlank - @Column(name = "title") - private String title; - - @NotBlank - @Column(name = "url") - private String url; - - @NotBlank - @Column(name = "thumbnail_url") - private String thumbnailUrl; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "album_id") - private Album album; - - public Photo(@NotBlank String title, @NotBlank String url, @NotBlank String thumbnailUrl, Album album) { - this.title = title; - this.url = url; - this.thumbnailUrl = thumbnailUrl; - this.album = album; - } - - @JsonIgnore - public Album getAlbum() { - return album; - } +public class Photo extends MetadataEntity { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @Column(name = "title") + private String title; + + @NotBlank + @Column(name = "url") + private String url; + + @NotBlank + @Column(name = "thumbnail_url") + private String thumbnailUrl; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "album_id") + private Album album; + + public Photo(@NotBlank String title, @NotBlank String url, @NotBlank String thumbnailUrl, Album album) { + this.title = title; + this.url = url; + this.thumbnailUrl = thumbnailUrl; + this.album = album; + } + + @JsonIgnore + public Album getAlbum() { + return album; + } + } diff --git a/src/main/java/com/sopromadze/blogapi/model/Post.java b/src/main/java/com/sopromadze/blogapi/model/Post.java index 6b97dbcf..fda74a33 100644 --- a/src/main/java/com/sopromadze/blogapi/model/Post.java +++ b/src/main/java/com/sopromadze/blogapi/model/Post.java @@ -3,25 +3,12 @@ import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.ObjectIdGenerators; -import com.sopromadze.blogapi.model.audit.UserDateAudit; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import com.sopromadze.blogapi.model.user.UserEntity; +import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -31,65 +18,68 @@ @Data @Table(name = "posts", uniqueConstraints = { @UniqueConstraint(columnNames = { "title" }) }) @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Post extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "title") - private String title; - - @Column(name = "body") - private String body; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id") - private User user; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "category_id") - private Category category; - - @JsonIgnore - @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) - private List comments; - - @ManyToMany(fetch = FetchType.LAZY) - @JoinTable(name = "post_tag", joinColumns = @JoinColumn(name = "post_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id")) - private List tags; - - @JsonIgnore - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public List getComments() { - return comments == null ? null : new ArrayList<>(comments); - } - - public void setComments(List comments) { - if (comments == null) { - this.comments = null; - } else { - this.comments = Collections.unmodifiableList(comments); - } - } - - public List getTags() { - return tags == null ? null : new ArrayList<>(tags); - } - - public void setTags(List tags) { - if (tags == null) { - this.tags = null; - } else { - this.tags = Collections.unmodifiableList(tags); - } - } +public class Post extends MetadataEntity { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "title") + private String title; + + @Column(name = "body") + private String body; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private UserEntity user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private Category category; + + @JsonIgnore + @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) + private List comments; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = "post_tag", joinColumns = @JoinColumn(name = "post_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id")) + private List tags; + + @JsonIgnore + public UserEntity getUser() { + return user; + } + + public void setUser(UserEntity user) { + this.user = user; + } + + public List getComments() { + return comments == null ? null : new ArrayList<>(comments); + } + + public void setComments(List comments) { + if (comments == null) { + this.comments = null; + } else { + this.comments = Collections.unmodifiableList(comments); + } + } + + public List getTags() { + return tags == null ? null : new ArrayList<>(tags); + } + + public void setTags(List tags) { + if (tags == null) { + this.tags = null; + } else { + this.tags = Collections.unmodifiableList(tags); + } + } + } diff --git a/src/main/java/com/sopromadze/blogapi/model/Tag.java b/src/main/java/com/sopromadze/blogapi/model/Tag.java index a3cbd193..6048d918 100644 --- a/src/main/java/com/sopromadze/blogapi/model/Tag.java +++ b/src/main/java/com/sopromadze/blogapi/model/Tag.java @@ -1,22 +1,12 @@ package com.sopromadze.blogapi.model; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; -import com.sopromadze.blogapi.model.Post; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import jakarta.persistence.*; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.Table; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,37 +17,38 @@ @NoArgsConstructor @Table(name = "tags") //@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") -public class Tag extends UserDateAudit { - - private static final long serialVersionUID = -5298707266367331514L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "name") - private String name; - - @JsonIgnore - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "post_tag", joinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "post_id", referencedColumnName = "id")) - private List posts; - - public Tag(String name) { - super(); - this.name = name; - } - - public List getPosts() { - return posts == null ? null : new ArrayList<>(posts); - } - - public void setPosts(List posts) { - if (posts == null) { - this.posts = null; - } else { - this.posts = Collections.unmodifiableList(posts); - } - } +public class Tag extends MetadataEntity { + + private static final long serialVersionUID = -5298707266367331514L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "name") + private String name; + + @JsonIgnore + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "post_tag", joinColumns = @JoinColumn(name = "tag_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "post_id", referencedColumnName = "id")) + private List posts; + + public Tag(String name) { + super(); + this.name = name; + } + + public List getPosts() { + return posts == null ? null : new ArrayList<>(posts); + } + + public void setPosts(List posts) { + if (posts == null) { + this.posts = null; + } else { + this.posts = Collections.unmodifiableList(posts); + } + } } diff --git a/src/main/java/com/sopromadze/blogapi/model/Todo.java b/src/main/java/com/sopromadze/blogapi/model/Todo.java deleted file mode 100644 index 7fed93d1..00000000 --- a/src/main/java/com/sopromadze/blogapi/model/Todo.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.sopromadze.blogapi.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; -import com.sopromadze.blogapi.model.user.User; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.NotBlank; - -@EqualsAndHashCode(callSuper = true) -@Entity -@Data -@Table(name = "todos", uniqueConstraints = { @UniqueConstraint(columnNames = { "title" }) }) -public class Todo extends UserDateAudit { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NotBlank - @Column(name = "title") - private String title; - - @Column(name = "completed") - private Boolean completed; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "user_id") - private User user; - - @JsonIgnore - public User getUser() { - return user; - } -} diff --git a/src/main/java/com/sopromadze/blogapi/model/audit/DateAudit.java b/src/main/java/com/sopromadze/blogapi/model/audit/DateAudit.java deleted file mode 100644 index c9f8abe7..00000000 --- a/src/main/java/com/sopromadze/blogapi/model/audit/DateAudit.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.sopromadze.blogapi.model.audit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -import javax.persistence.Column; -import javax.persistence.EntityListeners; -import javax.persistence.MappedSuperclass; -import java.io.Serializable; -import java.time.Instant; - -@MappedSuperclass -@Data -@EntityListeners(AuditingEntityListener.class) -@JsonIgnoreProperties( - value = { "createdAt", "updatedAt" }, - allowGetters = true -) -public abstract class DateAudit implements Serializable { - - private static final long serialVersionUID = 1L; - - @CreatedDate - @Column(nullable = false, updatable = false) - private Instant createdAt; - - @LastModifiedDate - @Column(nullable = false) - private Instant updatedAt; - -} diff --git a/src/main/java/com/sopromadze/blogapi/model/audit/UserDateAudit.java b/src/main/java/com/sopromadze/blogapi/model/audit/UserDateAudit.java deleted file mode 100644 index 10644bd5..00000000 --- a/src/main/java/com/sopromadze/blogapi/model/audit/UserDateAudit.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sopromadze.blogapi.model.audit; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.springframework.data.annotation.CreatedBy; -import org.springframework.data.annotation.LastModifiedBy; - -import javax.persistence.Column; -import javax.persistence.MappedSuperclass; - -@EqualsAndHashCode(callSuper = true) -@MappedSuperclass -@Data -@JsonIgnoreProperties( - value = { "createdBY", "updatedBy" }, - allowGetters = true -) -public abstract class UserDateAudit extends DateAudit { - private static final long serialVersionUID = 1L; - - @CreatedBy - @Column(updatable = false) - private Long createdBy; - - @LastModifiedBy - private Long updatedBy; -} diff --git a/src/main/java/com/sopromadze/blogapi/model/metadata/MetadataEntity.java b/src/main/java/com/sopromadze/blogapi/model/metadata/MetadataEntity.java new file mode 100644 index 00000000..6f9b0b0f --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/model/metadata/MetadataEntity.java @@ -0,0 +1,43 @@ +package com.sopromadze.blogapi.model.metadata; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.io.Serializable; +import java.time.Instant; + +@MappedSuperclass +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EntityListeners(AuditingEntityListener.class) +public class MetadataEntity implements Serializable { + + @CreatedDate + @Column(name = "created_at", nullable = false, updatable = false) + private Instant createdAt; + + @LastModifiedDate + @Column(name = "updated_at", nullable = false) + private Instant updatedAt; + + @CreatedBy + @Column(name = "created_by", updatable = false) + private Long createdBy; + + @LastModifiedBy + @Column(name = "updated_by") + private Long updatedBy; + +} diff --git a/src/main/java/com/sopromadze/blogapi/model/role/Role.java b/src/main/java/com/sopromadze/blogapi/model/role/Role.java index 00231ca9..422001aa 100644 --- a/src/main/java/com/sopromadze/blogapi/model/role/Role.java +++ b/src/main/java/com/sopromadze/blogapi/model/role/Role.java @@ -1,33 +1,29 @@ package com.sopromadze.blogapi.model.role; +import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.NaturalId; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Table; +import java.io.Serializable; @Entity @Data @NoArgsConstructor @Table(name = "roles") -public class Role { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; +public class Role implements Serializable { - @Enumerated(EnumType.STRING) - @NaturalId - @Column(name = "name") - private RoleName name; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + @NaturalId + @Column(name = "name") + private RoleName name; + + public Role(RoleName name) { + this.name = name; + } - public Role(RoleName name) { - this.name = name; - } } diff --git a/src/main/java/com/sopromadze/blogapi/model/role/RoleName.java b/src/main/java/com/sopromadze/blogapi/model/role/RoleName.java index f2064b2f..5282fcc8 100644 --- a/src/main/java/com/sopromadze/blogapi/model/role/RoleName.java +++ b/src/main/java/com/sopromadze/blogapi/model/role/RoleName.java @@ -1,6 +1,6 @@ package com.sopromadze.blogapi.model.role; public enum RoleName { - ROLE_ADMIN, - ROLE_USER, + ROLE_ADMIN, + ROLE_USER } diff --git a/src/main/java/com/sopromadze/blogapi/model/user/Address.java b/src/main/java/com/sopromadze/blogapi/model/user/Address.java index f686bbbf..5ffe1a61 100644 --- a/src/main/java/com/sopromadze/blogapi/model/user/Address.java +++ b/src/main/java/com/sopromadze/blogapi/model/user/Address.java @@ -1,112 +1,43 @@ package com.sopromadze.blogapi.model.user; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import java.time.Instant; +import lombok.experimental.SuperBuilder; @EqualsAndHashCode(callSuper = true) -@Entity @Data @NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Entity @Table(name = "address") -public class Address extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "street") - private String street; - - @Column(name = "suite") - private String suite; - - @Column(name = "city") - private String city; - - @Column(name = "zipcode") - private String zipcode; - - @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name = "geo_id") - private Geo geo; - - @OneToOne(mappedBy = "address") - private User user; - - public Address(String street, String suite, String city, String zipcode, Geo geo) { - this.street = street; - this.suite = suite; - this.city = city; - this.zipcode = zipcode; - this.geo = geo; - } - - @JsonIgnore - public Long getId() { - return id; - } +public class Address extends MetadataEntity { - @JsonIgnore - @Override - public Long getCreatedBy() { - return super.getCreatedBy(); - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @JsonIgnore - @Override - public void setCreatedBy(Long createdBy) { - super.setCreatedBy(createdBy); - } + @Column(name = "street") + private String street; - @JsonIgnore - @Override - public Long getUpdatedBy() { - return super.getUpdatedBy(); - } + @Column(name = "suite") + private String suite; - @JsonIgnore - @Override - public void setUpdatedBy(Long updatedBy) { - super.setUpdatedBy(updatedBy); - } + @Column(name = "city") + private String city; - @JsonIgnore - @Override - public Instant getCreatedAt() { - return super.getCreatedAt(); - } + @Column(name = "zipcode") + private String zipcode; - @JsonIgnore - @Override - public void setCreatedAt(Instant createdAt) { - super.setCreatedAt(createdAt); - } + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "geo_id") + private Geo geo; - @JsonIgnore - @Override - public Instant getUpdatedAt() { - return super.getUpdatedAt(); - } + @OneToOne(mappedBy = "address") + private UserEntity user; - @JsonIgnore - @Override - public void setUpdatedAt(Instant updatedAt) { - super.setUpdatedAt(updatedAt); - } } diff --git a/src/main/java/com/sopromadze/blogapi/model/user/Company.java b/src/main/java/com/sopromadze/blogapi/model/user/Company.java index 7cc93a2f..b507a9d6 100644 --- a/src/main/java/com/sopromadze/blogapi/model/user/Company.java +++ b/src/main/java/com/sopromadze/blogapi/model/user/Company.java @@ -1,105 +1,38 @@ package com.sopromadze.blogapi.model.user; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import java.time.Instant; +import lombok.experimental.SuperBuilder; @EqualsAndHashCode(callSuper = true) -@Entity @Data @NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Entity @Table(name = "company") -public class Company extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "name") - private String name; - - @Column(name = "catch_phrase") - private String catchPhrase; - - @Column(name = "bs") - private String bs; - - @OneToOne(mappedBy = "company") - private User user; - - - public Company(String name, String catchPhrase, String bs) { - this.name = name; - this.catchPhrase = catchPhrase; - this.bs = bs; - } - - @JsonIgnore - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - @JsonIgnore - @Override - public Long getCreatedBy() { - return super.getCreatedBy(); - } +public class Company extends MetadataEntity { - @JsonIgnore - @Override - public void setCreatedBy(Long createdBy) { - super.setCreatedBy(createdBy); - } + private static final long serialVersionUID = 1L; - @JsonIgnore - @Override - public Long getUpdatedBy() { - return super.getUpdatedBy(); - } + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @JsonIgnore - @Override - public void setUpdatedBy(Long updatedBy) { - super.setUpdatedBy(updatedBy); - } + @Column(name = "name") + private String name; - @JsonIgnore - @Override - public Instant getCreatedAt() { - return super.getCreatedAt(); - } + @Column(name = "catch_phrase") + private String catchPhrase; - @JsonIgnore - @Override - public void setCreatedAt(Instant createdAt) { - super.setCreatedAt(createdAt); - } + @Column(name = "bs") + private String bs; - @JsonIgnore - @Override - public Instant getUpdatedAt() { - return super.getUpdatedAt(); - } + @OneToOne(mappedBy = "company") + private UserEntity user; - @JsonIgnore - @Override - public void setUpdatedAt(Instant updatedAt) { - super.setUpdatedAt(updatedAt); - } } diff --git a/src/main/java/com/sopromadze/blogapi/model/user/Geo.java b/src/main/java/com/sopromadze/blogapi/model/user/Geo.java index f2845e22..a80b1292 100644 --- a/src/main/java/com/sopromadze/blogapi/model/user/Geo.java +++ b/src/main/java/com/sopromadze/blogapi/model/user/Geo.java @@ -1,92 +1,35 @@ package com.sopromadze.blogapi.model.user; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.audit.UserDateAudit; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import java.time.Instant; +import lombok.experimental.SuperBuilder; @EqualsAndHashCode(callSuper = true) -@Entity @Data @NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Entity @Table(name = "geo") -public class Geo extends UserDateAudit { - private static final long serialVersionUID = 1L; - - @JsonIgnore - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(name = "lat") - private String lat; - - @Column(name = "lng") - private String lng; - - @OneToOne(mappedBy = "geo") - private Address address; - - public Geo(String lat, String lng) { - this.lat = lat; - this.lng = lng; - } - - @JsonIgnore - @Override - public Long getCreatedBy() { - return super.getCreatedBy(); - } - - @JsonIgnore - @Override - public void setCreatedBy(Long createdBy) { - super.setCreatedBy(createdBy); - } - - @JsonIgnore - @Override - public Long getUpdatedBy() { - return super.getUpdatedBy(); - } +public class Geo extends MetadataEntity { - @JsonIgnore - @Override - public void setUpdatedBy(Long updatedBy) { - super.setUpdatedBy(updatedBy); - } + @JsonIgnore + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - @JsonIgnore - @Override - public Instant getCreatedAt() { - return super.getCreatedAt(); - } + @Column(name = "lat") + private String lat; - @JsonIgnore - @Override - public void setCreatedAt(Instant createdAt) { - super.setCreatedAt(createdAt); - } + @Column(name = "lng") + private String lng; - @JsonIgnore - @Override - public Instant getUpdatedAt() { - return super.getUpdatedAt(); - } + @OneToOne(mappedBy = "geo") + private Address address; - @JsonIgnore - @Override - public void setUpdatedAt(Instant updatedAt) { - super.setUpdatedAt(updatedAt); - } } diff --git a/src/main/java/com/sopromadze/blogapi/model/user/User.java b/src/main/java/com/sopromadze/blogapi/model/user/User.java deleted file mode 100644 index 90f2e489..00000000 --- a/src/main/java/com/sopromadze/blogapi/model/user/User.java +++ /dev/null @@ -1,192 +0,0 @@ -package com.sopromadze.blogapi.model.user; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.sopromadze.blogapi.model.Album; -import com.sopromadze.blogapi.model.audit.DateAudit; -import com.sopromadze.blogapi.model.Comment; -import com.sopromadze.blogapi.model.Post; -import com.sopromadze.blogapi.model.role.Role; -import com.sopromadze.blogapi.model.Todo; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import org.hibernate.annotations.NaturalId; - -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -@EqualsAndHashCode(callSuper = true) -@Entity -@Data -@NoArgsConstructor -@Table(name = "users", uniqueConstraints = { @UniqueConstraint(columnNames = { "username" }), - @UniqueConstraint(columnNames = { "email" }) }) -public class User extends DateAudit { - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id") - private Long id; - - @NotBlank - @Column(name = "first_name") - @Size(max = 40) - private String firstName; - - @NotBlank - @Column(name = "last_name") - @Size(max = 40) - private String lastName; - - @NotBlank - @Column(name = "username") - @Size(max = 15) - private String username; - - @NotBlank - @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) - @Size(max = 100) - @Column(name = "password") - private String password; - - @NotBlank - @NaturalId - @Size(max = 40) - @Column(name = "email") - @Email - private String email; - - @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "address_id") - private Address address; - - @Column(name = "phone") - private String phone; - - @Column(name = "website") - private String website; - - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")) - private List roles; - - @JsonIgnore - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private List todos; - - @JsonIgnore - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private List albums; - - @JsonIgnore - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private List posts; - - @JsonIgnore - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) - private List comments; - - @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) - @JoinColumn(name = "company_id") - private Company company; - - public User(String firstName, String lastName, String username, String email, String password) { - this.firstName = firstName; - this.lastName = lastName; - this.username = username; - this.email = email; - this.password = password; - } - - - - public List getTodos() { - - return todos == null ? null : new ArrayList<>(todos); - } - - public void setTodos(List todos) { - - if (todos == null) { - this.todos = null; - } else { - this.todos = Collections.unmodifiableList(todos); - } - } - - public List getAlbums() { - - return albums == null ? null : new ArrayList<>(albums); - } - - public void setAlbums(List albums) { - - if (albums == null) { - this.albums = null; - } else { - this.albums = Collections.unmodifiableList(albums); - } - } - - - public List getPosts() { - - return posts == null ? null : new ArrayList<>(posts); - } - - public void setPosts(List posts) { - - if (posts == null) { - this.posts = null; - } else { - this.posts = Collections.unmodifiableList(posts); - } - } - - public List getRoles() { - - return roles == null ? null : new ArrayList<>(roles); - } - - public void setRoles(List roles) { - - if (roles == null) { - this.roles = null; - } else { - this.roles = Collections.unmodifiableList(roles); - } - } - - public List getComments() { - return comments == null ? null : new ArrayList<>(comments); - } - - public void setComments(List comments) { - - if (comments == null) { - this.comments = null; - } else { - this.comments = Collections.unmodifiableList(comments); - } - } -} diff --git a/src/main/java/com/sopromadze/blogapi/model/user/UserEntity.java b/src/main/java/com/sopromadze/blogapi/model/user/UserEntity.java new file mode 100644 index 00000000..13abc455 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/model/user/UserEntity.java @@ -0,0 +1,104 @@ +package com.sopromadze.blogapi.model.user; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; +import com.sopromadze.blogapi.model.Album; +import com.sopromadze.blogapi.model.Comment; +import com.sopromadze.blogapi.model.Post; +import com.sopromadze.blogapi.model.metadata.MetadataEntity; +import com.sopromadze.blogapi.model.role.Role; +import jakarta.persistence.*; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.NaturalId; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Entity +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@Table(name = "users", uniqueConstraints = { + @UniqueConstraint(columnNames = { "username" }), + @UniqueConstraint(columnNames = { "email" }) +}) +public class UserEntity extends MetadataEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @NotBlank + @Column(name = "first_name") + @Size(max = 40) + private String firstName; + + @NotBlank + @Column(name = "last_name") + @Size(max = 40) + private String lastName; + + @NotBlank + @Column(name = "username") + @Size(max = 15) + private String username; + + @NotBlank + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + @Size(max = 100) + @Column(name = "password") + private String password; + + @NotBlank + @NaturalId + @Size(max = 40) + @Column(name = "email") + @Email + private String email; + + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "address_id") + private Address address; + + @Column(name = "phone") + private String phone; + + @Column(name = "website") + private String website; + + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id")) + private List roles; + + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List todos; + + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List albums; + + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List posts; + + @JsonIgnore + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) + private List comments; + + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true) + @JoinColumn(name = "company_id") + private Company company; + +} diff --git a/src/main/java/com/sopromadze/blogapi/payload/AlbumResponse.java b/src/main/java/com/sopromadze/blogapi/payload/AlbumResponse.java index ea57f7df..70d2100c 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/AlbumResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/AlbumResponse.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.sopromadze.blogapi.model.Photo; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.user.UserEntity; import lombok.Data; import lombok.EqualsAndHashCode; @@ -15,25 +15,27 @@ @Data @JsonInclude(Include.NON_NULL) public class AlbumResponse extends UserDateAuditPayload { - private Long id; - private String title; + private Long id; - private User user; + private String title; - private List photo; + private UserEntity userEntity; - public List getPhoto() { + private List photo; - return photo == null ? null : new ArrayList<>(photo); - } + public List getPhoto() { - public void setPhoto(List photo) { + return photo == null ? null : new ArrayList<>(photo); + } + + public void setPhoto(List photo) { + + if (photo == null) { + this.photo = null; + } else { + this.photo = Collections.unmodifiableList(photo); + } + } - if (photo == null) { - this.photo = null; - } else { - this.photo = Collections.unmodifiableList(photo); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/ApiResponse.java b/src/main/java/com/sopromadze/blogapi/payload/ApiResponse.java index 4dfa14ab..9332bef8 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/ApiResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/ApiResponse.java @@ -10,35 +10,36 @@ @Data @JsonPropertyOrder({ - "success", - "message" + "success", + "message" }) public class ApiResponse implements Serializable { - @JsonIgnore - private static final long serialVersionUID = 7702134516418120340L; + @JsonIgnore + private static final long serialVersionUID = 7702134516418120340L; - @JsonProperty("success") - private Boolean success; + @JsonProperty("success") + private Boolean success; - @JsonProperty("message") - private String message; + @JsonProperty("message") + private String message; - @JsonIgnore - private HttpStatus status; + @JsonIgnore + private HttpStatus status; - public ApiResponse() { + public ApiResponse() { - } + } - public ApiResponse(Boolean success, String message) { - this.success = success; - this.message = message; - } + public ApiResponse(Boolean success, String message) { + this.success = success; + this.message = message; + } + + public ApiResponse(Boolean success, String message, HttpStatus httpStatus) { + this.success = success; + this.message = message; + this.status = httpStatus; + } - public ApiResponse(Boolean success, String message, HttpStatus httpStatus) { - this.success = success; - this.message = message; - this.status = httpStatus; - } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/CommentRequest.java b/src/main/java/com/sopromadze/blogapi/payload/CommentRequest.java index c88239ff..f62fcd30 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/CommentRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/CommentRequest.java @@ -1,13 +1,14 @@ package com.sopromadze.blogapi.payload; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.Data; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; - @Data public class CommentRequest { - @NotBlank - @Size(min = 10, message = "Comment body must be minimum 10 characters") - private String body; + + @NotBlank + @Size(min = 10, message = "Comment body must be minimum 10 characters") + private String body; + } diff --git a/src/main/java/com/sopromadze/blogapi/payload/DateAuditPayload.java b/src/main/java/com/sopromadze/blogapi/payload/DateAuditPayload.java index 7ec74a5a..d797fb49 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/DateAuditPayload.java +++ b/src/main/java/com/sopromadze/blogapi/payload/DateAuditPayload.java @@ -4,23 +4,24 @@ public abstract class DateAuditPayload { - private Instant createdAt; + private Instant createdAt; - private Instant updatedAt; + private Instant updatedAt; - public Instant getCreatedAt() { - return createdAt; - } + public Instant getCreatedAt() { + return createdAt; + } - public void setCreatedAt(Instant createdAt) { - this.createdAt = createdAt; - } + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } - public Instant getUpdatedAt() { - return updatedAt; - } + public Instant getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } - public void setUpdatedAt(Instant updatedAt) { - this.updatedAt = updatedAt; - } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/ExceptionResponse.java b/src/main/java/com/sopromadze/blogapi/payload/ExceptionResponse.java index a243981b..aa83c97d 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/ExceptionResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/ExceptionResponse.java @@ -9,30 +9,34 @@ @Data public class ExceptionResponse { - private String error; - private Integer status; - private List messages; - private Instant timestamp; - - public ExceptionResponse(List messages, String error, Integer status) { - setMessages(messages); - this.error = error; - this.status = status; - this.timestamp = Instant.now(); - } - - public List getMessages() { - - return messages == null ? null : new ArrayList<>(messages); - } - - public final void setMessages(List messages) { - - if (messages == null) { - this.messages = null; - } else { - this.messages = Collections.unmodifiableList(messages); - } - } + + private String error; + + private Integer status; + + private List messages; + + private Instant timestamp; + + public ExceptionResponse(List messages, String error, Integer status) { + setMessages(messages); + this.error = error; + this.status = status; + this.timestamp = Instant.now(); + } + + public List getMessages() { + + return messages == null ? null : new ArrayList<>(messages); + } + + public final void setMessages(List messages) { + + if (messages == null) { + this.messages = null; + } else { + this.messages = Collections.unmodifiableList(messages); + } + } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/InfoRequest.java b/src/main/java/com/sopromadze/blogapi/payload/InfoRequest.java index 7baf210f..43af683a 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/InfoRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/InfoRequest.java @@ -1,35 +1,35 @@ package com.sopromadze.blogapi.payload; +import jakarta.validation.constraints.NotBlank; import lombok.Data; -import javax.validation.constraints.NotBlank; - @Data public class InfoRequest { - @NotBlank - private String street; + @NotBlank + private String street; + + @NotBlank + private String suite; - @NotBlank - private String suite; + @NotBlank + private String city; - @NotBlank - private String city; + @NotBlank + private String zipcode; - @NotBlank - private String zipcode; + private String companyName; - private String companyName; + private String catchPhrase; - private String catchPhrase; + private String bs; - private String bs; + private String website; - private String website; + private String phone; - private String phone; + private String lat; - private String lat; + private String lng; - private String lng; } diff --git a/src/main/java/com/sopromadze/blogapi/payload/JwtAuthenticationResponse.java b/src/main/java/com/sopromadze/blogapi/payload/JwtAuthenticationResponse.java index 148aa475..136ab005 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/JwtAuthenticationResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/JwtAuthenticationResponse.java @@ -4,11 +4,13 @@ @Data public class JwtAuthenticationResponse { - private String accessToken; - private String tokenType = "Bearer"; - public JwtAuthenticationResponse(String accessToken) { - this.accessToken = accessToken; - } + private String accessToken; + + private String tokenType = "Bearer"; + + public JwtAuthenticationResponse(String accessToken) { + this.accessToken = accessToken; + } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/LoginRequest.java b/src/main/java/com/sopromadze/blogapi/payload/LoginRequest.java index ac1b0ee8..0d3ee7ac 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/LoginRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/LoginRequest.java @@ -1,14 +1,15 @@ package com.sopromadze.blogapi.payload; +import jakarta.validation.constraints.NotBlank; import lombok.Data; -import javax.validation.constraints.NotBlank; - @Data public class LoginRequest { - @NotBlank - private String usernameOrEmail; - @NotBlank - private String password; + @NotBlank + private String usernameOrEmail; + + @NotBlank + private String password; + } diff --git a/src/main/java/com/sopromadze/blogapi/payload/LoginResponse.java b/src/main/java/com/sopromadze/blogapi/payload/LoginResponse.java new file mode 100644 index 00000000..5b651c66 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/payload/LoginResponse.java @@ -0,0 +1,18 @@ +package com.sopromadze.blogapi.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class LoginResponse { + + private String token; + + private long expiresIn; + +} diff --git a/src/main/java/com/sopromadze/blogapi/payload/LoginUserDto.java b/src/main/java/com/sopromadze/blogapi/payload/LoginUserDto.java new file mode 100644 index 00000000..aecd836d --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/payload/LoginUserDto.java @@ -0,0 +1,18 @@ +package com.sopromadze.blogapi.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class LoginUserDto { + + private String email; + + private String password; + +} diff --git a/src/main/java/com/sopromadze/blogapi/payload/PagedResponse.java b/src/main/java/com/sopromadze/blogapi/payload/PagedResponse.java index 9e73e40e..cf600357 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/PagedResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/PagedResponse.java @@ -8,41 +8,46 @@ @Data public class PagedResponse { - private List content; - private int page; - private int size; - private long totalElements; - private int totalPages; - private boolean last; - - public PagedResponse() { - - } - - public PagedResponse(List content, int page, int size, long totalElements, int totalPages, boolean last) { - setContent(content); - this.page = page; - this.size = size; - this.totalElements = totalElements; - this.totalPages = totalPages; - this.last = last; - } - - public List getContent() { - return content == null ? null : new ArrayList<>(content); - } - - public final void setContent(List content) { - if (content == null) { - this.content = null; - } else { - this.content = Collections.unmodifiableList(content); - } - } - - - - public boolean isLast() { - return last; - } + + private List content; + + private int page; + + private int size; + + private long totalElements; + + private int totalPages; + + private boolean last; + + public PagedResponse() { + + } + + public PagedResponse(List content, int page, int size, long totalElements, int totalPages, boolean last) { + setContent(content); + this.page = page; + this.size = size; + this.totalElements = totalElements; + this.totalPages = totalPages; + this.last = last; + } + + public List getContent() { + return content == null ? null : new ArrayList<>(content); + } + + public final void setContent(List content) { + if (content == null) { + this.content = null; + } else { + this.content = Collections.unmodifiableList(content); + } + } + + public boolean isLast() { + return last; + } + } diff --git a/src/main/java/com/sopromadze/blogapi/payload/PhotoRequest.java b/src/main/java/com/sopromadze/blogapi/payload/PhotoRequest.java index 74950489..ed6a772d 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/PhotoRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/PhotoRequest.java @@ -1,26 +1,26 @@ package com.sopromadze.blogapi.payload; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.Data; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - @Data public class PhotoRequest { - @NotBlank - @Size(min = 3) - private String title; + @NotBlank + @Size(min = 3) + private String title; + + @NotBlank + @Size(min = 10) + private String url; - @NotBlank - @Size(min = 10) - private String url; + @NotBlank + @Size(min = 10) + private String thumbnailUrl; - @NotBlank - @Size(min = 10) - private String thumbnailUrl; + @NotNull + private Long albumId; - @NotNull - private Long albumId; } diff --git a/src/main/java/com/sopromadze/blogapi/payload/PhotoResponse.java b/src/main/java/com/sopromadze/blogapi/payload/PhotoResponse.java index e695b977..a0cfb056 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/PhotoResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/PhotoResponse.java @@ -4,18 +4,23 @@ @Data public class PhotoResponse { - private Long id; - private String title; - private String url; - private String thumbnailUrl; - private Long albumId; - - public PhotoResponse(Long id, String title, String url, String thumbnailUrl, Long albumId) { - this.id = id; - this.title = title; - this.url = url; - this.thumbnailUrl = thumbnailUrl; - this.albumId = albumId; - } + + private Long id; + + private String title; + + private String url; + + private String thumbnailUrl; + + private Long albumId; + + public PhotoResponse(Long id, String title, String url, String thumbnailUrl, Long albumId) { + this.id = id; + this.title = title; + this.url = url; + this.thumbnailUrl = thumbnailUrl; + this.albumId = albumId; + } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/PostRequest.java b/src/main/java/com/sopromadze/blogapi/payload/PostRequest.java index 28d7ed13..921f6535 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/PostRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/PostRequest.java @@ -1,10 +1,10 @@ package com.sopromadze.blogapi.payload; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.Data; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -12,30 +12,31 @@ @Data public class PostRequest { - @NotBlank - @Size(min = 10) - private String title; + @NotBlank + @Size(min = 10) + private String title; - @NotBlank - @Size(min = 50) - private String body; + @NotBlank + @Size(min = 50) + private String body; - @NotNull - private Long categoryId; + @NotNull + private Long categoryId; - private List tags; + private List tags; - public List getTags() { + public List getTags() { - return tags == null ? Collections.emptyList() : new ArrayList<>(tags); - } + return tags == null ? Collections.emptyList() : new ArrayList<>(tags); + } - public void setTags(List tags) { + public void setTags(List tags) { + + if (tags == null) { + this.tags = null; + } else { + this.tags = Collections.unmodifiableList(tags); + } + } - if (tags == null) { - this.tags = null; - } else { - this.tags = Collections.unmodifiableList(tags); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/PostResponse.java b/src/main/java/com/sopromadze/blogapi/payload/PostResponse.java index f054e518..585bb0f8 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/PostResponse.java +++ b/src/main/java/com/sopromadze/blogapi/payload/PostResponse.java @@ -8,24 +8,27 @@ @Data public class PostResponse { - private String title; - private String body; - private String category; - private List tags; + private String title; + private String body; - public List getTags() { + private String category; - return tags == null ? null : new ArrayList<>(tags); - } + private List tags; - public void setTags(List tags) { + public List getTags() { + + return tags == null ? null : new ArrayList<>(tags); + } + + public void setTags(List tags) { + + if (tags == null) { + this.tags = null; + } else { + this.tags = Collections.unmodifiableList(tags); + } + } - if (tags == null) { - this.tags = null; - } else { - this.tags = Collections.unmodifiableList(tags); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/payload/RegisterUserDto.java b/src/main/java/com/sopromadze/blogapi/payload/RegisterUserDto.java new file mode 100644 index 00000000..b52e43db --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/payload/RegisterUserDto.java @@ -0,0 +1,22 @@ +package com.sopromadze.blogapi.payload; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RegisterUserDto { + + private String email; + + private String password; + + private String firstName; + + private String lastName; + +} diff --git a/src/main/java/com/sopromadze/blogapi/payload/SignUpRequest.java b/src/main/java/com/sopromadze/blogapi/payload/SignUpRequest.java index 3f993f13..6fda7087 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/SignUpRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/SignUpRequest.java @@ -1,31 +1,32 @@ package com.sopromadze.blogapi.payload; +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.Data; -import javax.validation.constraints.Email; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Size; - @Data public class SignUpRequest { - @NotBlank - @Size(min = 4, max = 40) - private String firstName; - - @NotBlank - @Size(min = 4, max = 40) - private String lastName; - - @NotBlank - @Size(min = 3, max = 15) - private String username; - - @NotBlank - @Size(max = 40) - @Email - private String email; - - @NotBlank - @Size(min = 6, max = 20) - private String password; + + @NotBlank + @Size(min = 4, max = 40) + private String firstName; + + @NotBlank + @Size(min = 4, max = 40) + private String lastName; + + @NotBlank + @Size(min = 3, max = 15) + private String username; + + @NotBlank + @Size(max = 40) + @Email + private String email; + + @NotBlank + @Size(min = 6, max = 20) + private String password; + } diff --git a/src/main/java/com/sopromadze/blogapi/payload/UserDateAuditPayload.java b/src/main/java/com/sopromadze/blogapi/payload/UserDateAuditPayload.java index 834f095d..8d9fdc71 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/UserDateAuditPayload.java +++ b/src/main/java/com/sopromadze/blogapi/payload/UserDateAuditPayload.java @@ -6,8 +6,9 @@ @EqualsAndHashCode(callSuper = true) @Data public abstract class UserDateAuditPayload extends DateAuditPayload { - private Long createdBy; - private Long updatedBy; + private Long createdBy; + + private Long updatedBy; } diff --git a/src/main/java/com/sopromadze/blogapi/payload/UserIdentityAvailability.java b/src/main/java/com/sopromadze/blogapi/payload/UserIdentityAvailability.java index c5d09fc2..60267fd6 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/UserIdentityAvailability.java +++ b/src/main/java/com/sopromadze/blogapi/payload/UserIdentityAvailability.java @@ -6,6 +6,7 @@ @Data @AllArgsConstructor public class UserIdentityAvailability { - private Boolean available; + + private Boolean available; } diff --git a/src/main/java/com/sopromadze/blogapi/payload/UserProfile.java b/src/main/java/com/sopromadze/blogapi/payload/UserProfile.java index b428ea12..031421fe 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/UserProfile.java +++ b/src/main/java/com/sopromadze/blogapi/payload/UserProfile.java @@ -12,15 +12,27 @@ @AllArgsConstructor @NoArgsConstructor public class UserProfile { - private Long id; - private String username; - private String firstName; - private String lastName; - private Instant joinedAt; - private String email; - private Address address; - private String phone; - private String website; - private Company company; - private Long postCount; + + private Long id; + + private String username; + + private String firstName; + + private String lastName; + + private Instant joinedAt; + + private String email; + + private Address address; + + private String phone; + + private String website; + + private Company company; + + private Long postCount; + } diff --git a/src/main/java/com/sopromadze/blogapi/payload/UserSummary.java b/src/main/java/com/sopromadze/blogapi/payload/UserSummary.java index 7fe8fe92..77fd2e42 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/UserSummary.java +++ b/src/main/java/com/sopromadze/blogapi/payload/UserSummary.java @@ -6,8 +6,13 @@ @Data @AllArgsConstructor public class UserSummary { - private Long id; - private String username; - private String firstName; - private String lastName; + + private Long id; + + private String username; + + private String firstName; + + private String lastName; + } diff --git a/src/main/java/com/sopromadze/blogapi/payload/request/AlbumRequest.java b/src/main/java/com/sopromadze/blogapi/payload/request/AlbumRequest.java index 83e4f1eb..592d4dd6 100644 --- a/src/main/java/com/sopromadze/blogapi/payload/request/AlbumRequest.java +++ b/src/main/java/com/sopromadze/blogapi/payload/request/AlbumRequest.java @@ -1,7 +1,7 @@ package com.sopromadze.blogapi.payload.request; import com.sopromadze.blogapi.model.Photo; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.user.UserEntity; import com.sopromadze.blogapi.payload.UserDateAuditPayload; import lombok.Data; @@ -12,25 +12,26 @@ @Data public class AlbumRequest extends UserDateAuditPayload { - private Long id; + private Long id; - private String title; + private String title; - private User user; + private UserEntity userEntity; - private List photo; + private List photo; - public List getPhoto() { + public List getPhoto() { - return photo == null ? null : new ArrayList<>(photo); - } + return photo == null ? null : new ArrayList<>(photo); + } - public void setPhoto(List photo) { + public void setPhoto(List photo) { + + if (photo == null) { + this.photo = null; + } else { + this.photo = Collections.unmodifiableList(photo); + } + } - if (photo == null) { - this.photo = null; - } else { - this.photo = Collections.unmodifiableList(photo); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/repository/AlbumRepository.java b/src/main/java/com/sopromadze/blogapi/repository/AlbumRepository.java index 12d6837f..3cda3a4c 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/AlbumRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/AlbumRepository.java @@ -8,5 +8,7 @@ @Repository public interface AlbumRepository extends JpaRepository { - Page findByCreatedBy(Long userId, Pageable pageable); + + Page findByCreatedBy(Long userId, Pageable pageable); + } diff --git a/src/main/java/com/sopromadze/blogapi/repository/CommentRepository.java b/src/main/java/com/sopromadze/blogapi/repository/CommentRepository.java index b4fb3be3..cebde2e4 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/CommentRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/CommentRepository.java @@ -8,5 +8,7 @@ @Repository public interface CommentRepository extends JpaRepository { - Page findByPostId(Long postId, Pageable pageable); + + Page findByPostId(Long postId, Pageable pageable); + } diff --git a/src/main/java/com/sopromadze/blogapi/repository/PhotoRepository.java b/src/main/java/com/sopromadze/blogapi/repository/PhotoRepository.java index a6f52698..e76bab15 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/PhotoRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/PhotoRepository.java @@ -8,5 +8,7 @@ @Repository public interface PhotoRepository extends JpaRepository { - Page findByAlbumId(Long albumId, Pageable pageable); + + Page findByAlbumId(Long albumId, Pageable pageable); + } diff --git a/src/main/java/com/sopromadze/blogapi/repository/PostRepository.java b/src/main/java/com/sopromadze/blogapi/repository/PostRepository.java index a748afb8..3b269c23 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/PostRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/PostRepository.java @@ -11,11 +11,13 @@ @Repository public interface PostRepository extends JpaRepository { - Page findByCreatedBy(Long userId, Pageable pageable); - Page findByCategory(Long categoryId, Pageable pageable); + Page findByCreatedBy(Long userId, Pageable pageable); - Page findByTags(List tags, Pageable pageable); + Page findByCategory(Long categoryId, Pageable pageable); + + Page findByTags(List tags, Pageable pageable); + + Long countByCreatedBy(Long userId); - Long countByCreatedBy(Long userId); } diff --git a/src/main/java/com/sopromadze/blogapi/repository/RoleRepository.java b/src/main/java/com/sopromadze/blogapi/repository/RoleRepository.java index 067294c6..b9eac3c7 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/RoleRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/RoleRepository.java @@ -7,5 +7,7 @@ import java.util.Optional; public interface RoleRepository extends JpaRepository { - Optional findByName(RoleName name); + + Optional findByName(RoleName name); + } diff --git a/src/main/java/com/sopromadze/blogapi/repository/TagRepository.java b/src/main/java/com/sopromadze/blogapi/repository/TagRepository.java index e9620636..1ec4e3d2 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/TagRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/TagRepository.java @@ -6,5 +6,7 @@ @Repository public interface TagRepository extends JpaRepository { - Tag findByName(String name); + + Tag findByName(String name); + } diff --git a/src/main/java/com/sopromadze/blogapi/repository/TodoRepository.java b/src/main/java/com/sopromadze/blogapi/repository/TodoRepository.java deleted file mode 100644 index 3cb55e71..00000000 --- a/src/main/java/com/sopromadze/blogapi/repository/TodoRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.sopromadze.blogapi.repository; - -import com.sopromadze.blogapi.model.Todo; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface TodoRepository extends JpaRepository { - Page findByCreatedBy(Long userId, Pageable pageable); -} diff --git a/src/main/java/com/sopromadze/blogapi/repository/UserRepository.java b/src/main/java/com/sopromadze/blogapi/repository/UserRepository.java index 94290248..5b35bd10 100644 --- a/src/main/java/com/sopromadze/blogapi/repository/UserRepository.java +++ b/src/main/java/com/sopromadze/blogapi/repository/UserRepository.java @@ -1,32 +1,34 @@ package com.sopromadze.blogapi.repository; import com.sopromadze.blogapi.exception.ResourceNotFoundException; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.user.UserEntity; import com.sopromadze.blogapi.security.UserPrincipal; +import jakarta.validation.constraints.NotBlank; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import javax.validation.constraints.NotBlank; import java.util.Optional; @Repository -public interface UserRepository extends JpaRepository { - Optional findByUsername(@NotBlank String username); +public interface UserRepository extends JpaRepository { - Optional findByEmail(@NotBlank String email); + Optional findByUsername(@NotBlank String username); - Boolean existsByUsername(@NotBlank String username); + Optional findByEmail(@NotBlank String email); - Boolean existsByEmail(@NotBlank String email); + Boolean existsByUsername(@NotBlank String username); - Optional findByUsernameOrEmail(String username, String email); + Boolean existsByEmail(@NotBlank String email); - default User getUser(UserPrincipal currentUser) { - return getUserByName(currentUser.getUsername()); - } + Optional findByUsernameOrEmail(String username, String email); + + default UserEntity getUser(UserPrincipal currentUser) { + return getUserByName(currentUser.getUsername()); + } + + default UserEntity getUserByName(String username) { + return findByUsername(username) + .orElseThrow(() -> new ResourceNotFoundException("User", "username", username)); + } - default User getUserByName(String username) { - return findByUsername(username) - .orElseThrow(() -> new ResourceNotFoundException("User", "username", username)); - } } diff --git a/src/main/java/com/sopromadze/blogapi/security/CurrentUser.java b/src/main/java/com/sopromadze/blogapi/security/CurrentUser.java index 400b4a48..2e5b1b27 100644 --- a/src/main/java/com/sopromadze/blogapi/security/CurrentUser.java +++ b/src/main/java/com/sopromadze/blogapi/security/CurrentUser.java @@ -2,15 +2,12 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.*; -@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE }) +@Target({ ElementType.PARAMETER, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented @AuthenticationPrincipal public @interface CurrentUser { + } diff --git a/src/main/java/com/sopromadze/blogapi/security/JwtAuthenticationEntryPoint.java b/src/main/java/com/sopromadze/blogapi/security/JwtAuthenticationEntryPoint.java deleted file mode 100644 index b9f644ab..00000000 --- a/src/main/java/com/sopromadze/blogapi/security/JwtAuthenticationEntryPoint.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.sopromadze.blogapi.security; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { - private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class); - - @Override - public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) - throws IOException, ServletException { - LOGGER.error("Responding with unauthorized error. Message - {}", e.getMessage()); - httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Sorry, You're not authorized to access this resource."); - } -} diff --git a/src/main/java/com/sopromadze/blogapi/security/JwtAuthenticationFilter.java b/src/main/java/com/sopromadze/blogapi/security/JwtAuthenticationFilter.java deleted file mode 100644 index 3c162554..00000000 --- a/src/main/java/com/sopromadze/blogapi/security/JwtAuthenticationFilter.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.sopromadze.blogapi.security; - -import com.sopromadze.blogapi.service.CustomUserDetailsService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -import org.springframework.util.StringUtils; -import org.springframework.web.filter.OncePerRequestFilter; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; - -public class JwtAuthenticationFilter extends OncePerRequestFilter { - private static final Logger LOGGER = LoggerFactory.getLogger(JwtAuthenticationFilter.class); - @Autowired - private JwtTokenProvider tokenProvider; - @Autowired - private CustomUserDetailsService customUserDetailsService; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - try { - String jwt = getJwtFromRequest(request); - - if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) { - Long userId = tokenProvider.getUserIdFromJWT(jwt); - - UserDetails userDetails = customUserDetailsService.loadUserById(userId); - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, - userDetails.getAuthorities()); - authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); - - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - } - } catch (Exception ex) { - LOGGER.error("Could not set user authentication in security context", ex); - } - - filterChain.doFilter(request, response); - } - - private String getJwtFromRequest(HttpServletRequest request) { - String bearerToken = request.getHeader("Authorization"); - if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { - return bearerToken.substring(7, bearerToken.length()); - } - return null; - } -} diff --git a/src/main/java/com/sopromadze/blogapi/security/JwtTokenProvider.java b/src/main/java/com/sopromadze/blogapi/security/JwtTokenProvider.java deleted file mode 100644 index 77fad327..00000000 --- a/src/main/java/com/sopromadze/blogapi/security/JwtTokenProvider.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.sopromadze.blogapi.security; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.SignatureException; -import io.jsonwebtoken.UnsupportedJwtException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; - -import java.util.Date; - -@Component -public class JwtTokenProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(JwtTokenProvider.class); - - @Value(value = "${app.jwtSecret}") - private String jwtSecret; - - @Value(value = "${app.jwtExpirationInMs}") - private int jwtExpirationInMs; - - public String generateToken(Authentication authentication) { - UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal(); - - Date now = new Date(); - Date expiryDate = new Date(now.getTime() + jwtExpirationInMs); - - return Jwts.builder() - .setSubject(Long.toString(userPrincipal.getId())) - .setIssuedAt(new Date()) - .setExpiration(expiryDate) - .signWith(SignatureAlgorithm.HS512, jwtSecret) - .compact(); - } - - public Long getUserIdFromJWT(String token) { - Claims claims = Jwts.parser() - .setSigningKey(jwtSecret) - .parseClaimsJws(token) - .getBody(); - - return Long.valueOf(claims.getSubject()); - } - - public boolean validateToken(String authToken) { - try { - Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken); - return true; - } catch (SignatureException ex) { - LOGGER.error("Invalid JWT signature"); - } catch (MalformedJwtException ex) { - LOGGER.error("Invalid JWT token"); - } catch (ExpiredJwtException ex) { - LOGGER.error("Expired JWT token"); - } catch (UnsupportedJwtException ex) { - LOGGER.error("Unsupported JWT token"); - } catch (IllegalArgumentException ex) { - LOGGER.error("JWT claims string is empty"); - } - return false; - } -} diff --git a/src/main/java/com/sopromadze/blogapi/security/UserPrincipal.java b/src/main/java/com/sopromadze/blogapi/security/UserPrincipal.java index 3402459f..eb065eb5 100644 --- a/src/main/java/com/sopromadze/blogapi/security/UserPrincipal.java +++ b/src/main/java/com/sopromadze/blogapi/security/UserPrincipal.java @@ -1,121 +1,71 @@ package com.sopromadze.blogapi.security; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.sopromadze.blogapi.model.user.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.util.ArrayList; import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder public class UserPrincipal implements UserDetails { - private static final long serialVersionUID = 1L; - - private Long id; - - private String firstName; - - private String lastName; - - private String username; - - @JsonIgnore - private String email; - - @JsonIgnore - private String password; - - private Collection authorities; - - public UserPrincipal(Long id, String firstName, String lastName, String username, String email, String password, - Collection authorities) { - this.id = id; - this.firstName = firstName; - this.lastName = lastName; - this.username = username; - this.email = email; - this.password = password; - - if (authorities == null) { - this.authorities = null; - } else { - this.authorities = new ArrayList<>(authorities); - } - } - - public static UserPrincipal create(User user) { - List authorities = user.getRoles().stream() - .map(role -> new SimpleGrantedAuthority(role.getName().name())).collect(Collectors.toList()); - - return new UserPrincipal(user.getId(), user.getFirstName(), user.getLastName(), user.getUsername(), - user.getEmail(), user.getPassword(), authorities); - } - - public Long getId() { - return id; - } - - public String getEmail() { - return email; - } - - @Override - public Collection getAuthorities() { - return authorities == null ? null : new ArrayList<>(authorities); - } - - @Override - public String getPassword() { - return password; - } - - @Override - public String getUsername() { - return username; - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } - - public boolean equals(Object object) { - if (this == object) - return true; - if (object == null || getClass() != object.getClass()) - return false; - UserPrincipal that = (UserPrincipal) object; - return Objects.equals(id, that.id); - } - - public int hashCode() { - return Objects.hash(id); - } - - public String getFirstName() { - return firstName; - } - - public String getLastName() { - return lastName; - } + + private Long id; + + private String firstName; + + private String lastName; + + private String username; + + @JsonIgnore + private String email; + + @JsonIgnore + private String password; + + private Collection authorities; + + @Override + public Collection getAuthorities() { + return authorities == null ? null : new ArrayList<>(authorities); + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + } diff --git a/src/main/java/com/sopromadze/blogapi/service/AlbumService.java b/src/main/java/com/sopromadze/blogapi/service/AlbumService.java index ef4a3621..1ce6dc26 100644 --- a/src/main/java/com/sopromadze/blogapi/service/AlbumService.java +++ b/src/main/java/com/sopromadze/blogapi/service/AlbumService.java @@ -10,16 +10,16 @@ public interface AlbumService { - PagedResponse getAllAlbums(int page, int size); + PagedResponse getAllAlbums(int page, int size); - ResponseEntity addAlbum(AlbumRequest albumRequest, UserPrincipal currentUser); + ResponseEntity addAlbum(AlbumRequest albumRequest, UserPrincipal currentUser); - ResponseEntity getAlbum(Long id); + ResponseEntity getAlbum(Long id); - ResponseEntity updateAlbum(Long id, AlbumRequest newAlbum, UserPrincipal currentUser); + ResponseEntity updateAlbum(Long id, AlbumRequest newAlbum, UserPrincipal currentUser); - ResponseEntity deleteAlbum(Long id, UserPrincipal currentUser); + ResponseEntity deleteAlbum(Long id, UserPrincipal currentUser); - PagedResponse getUserAlbums(String username, int page, int size); + PagedResponse getUserAlbums(String username, int page, int size); } diff --git a/src/main/java/com/sopromadze/blogapi/service/AuthenticationService.java b/src/main/java/com/sopromadze/blogapi/service/AuthenticationService.java new file mode 100644 index 00000000..2f130475 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/service/AuthenticationService.java @@ -0,0 +1,70 @@ +package com.sopromadze.blogapi.service; + +import com.sopromadze.blogapi.model.role.Role; +import com.sopromadze.blogapi.model.role.RoleName; +import com.sopromadze.blogapi.model.user.UserEntity; +import com.sopromadze.blogapi.payload.LoginUserDto; +import com.sopromadze.blogapi.payload.RegisterUserDto; +import com.sopromadze.blogapi.repository.RoleRepository; +import com.sopromadze.blogapi.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class AuthenticationService { + + private final UserRepository userRepository; + + private final PasswordEncoder passwordEncoder; + + private final AuthenticationManager authenticationManager; + + private final RoleRepository roleRepository; + + public UserEntity signup(RegisterUserDto input) { + + List roleNames = new ArrayList<>(List.of(RoleName.ROLE_USER)); + + if (userRepository.count() == 0) { + roleNames.add(RoleName.ROLE_ADMIN); + } + + List roles = roleNames.stream() + .map(roleRepository::findByName) + .filter(Optional::isPresent) + .map(Optional::get) + .toList(); + + UserEntity userEntity = UserEntity.builder() + .firstName(input.getFirstName()) + .lastName(input.getLastName()) + .email(input.getEmail()) + .username(input.getEmail()) + .roles(roles) + .password(passwordEncoder.encode(input.getPassword())) + .build(); + return userRepository.save(userEntity); + + } + + public UserEntity authenticate(LoginUserDto input) { + authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken( + input.getEmail(), + input.getPassword() + ) + ); + + return userRepository.findByEmail(input.getEmail()) + .orElseThrow(); + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/service/CategoryService.java b/src/main/java/com/sopromadze/blogapi/service/CategoryService.java index 65734a3e..437ef45b 100644 --- a/src/main/java/com/sopromadze/blogapi/service/CategoryService.java +++ b/src/main/java/com/sopromadze/blogapi/service/CategoryService.java @@ -9,15 +9,15 @@ public interface CategoryService { - PagedResponse getAllCategories(int page, int size); + PagedResponse getAllCategories(int page, int size); - ResponseEntity getCategory(Long id); + ResponseEntity getCategory(Long id); - ResponseEntity addCategory(Category category, UserPrincipal currentUser); + ResponseEntity addCategory(Category category, UserPrincipal currentUser); - ResponseEntity updateCategory(Long id, Category newCategory, UserPrincipal currentUser) - throws UnauthorizedException; + ResponseEntity updateCategory(Long id, Category newCategory, UserPrincipal currentUser) + throws UnauthorizedException; - ResponseEntity deleteCategory(Long id, UserPrincipal currentUser) throws UnauthorizedException; + ResponseEntity deleteCategory(Long id, UserPrincipal currentUser) throws UnauthorizedException; } diff --git a/src/main/java/com/sopromadze/blogapi/service/CommentService.java b/src/main/java/com/sopromadze/blogapi/service/CommentService.java index cdbc34de..164ab957 100644 --- a/src/main/java/com/sopromadze/blogapi/service/CommentService.java +++ b/src/main/java/com/sopromadze/blogapi/service/CommentService.java @@ -8,14 +8,14 @@ public interface CommentService { - PagedResponse getAllComments(Long postId, int page, int size); + PagedResponse getAllComments(Long postId, int page, int size); - Comment addComment(CommentRequest commentRequest, Long postId, UserPrincipal currentUser); + Comment addComment(CommentRequest commentRequest, Long postId, UserPrincipal currentUser); - Comment getComment(Long postId, Long id); + Comment getComment(Long postId, Long id); - Comment updateComment(Long postId, Long id, CommentRequest commentRequest, UserPrincipal currentUser); + Comment updateComment(Long postId, Long id, CommentRequest commentRequest, UserPrincipal currentUser); - ApiResponse deleteComment(Long postId, Long id, UserPrincipal currentUser); + ApiResponse deleteComment(Long postId, Long id, UserPrincipal currentUser); } diff --git a/src/main/java/com/sopromadze/blogapi/service/CustomUserDetailsService.java b/src/main/java/com/sopromadze/blogapi/service/CustomUserDetailsService.java deleted file mode 100644 index 55084feb..00000000 --- a/src/main/java/com/sopromadze/blogapi/service/CustomUserDetailsService.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.sopromadze.blogapi.service; - -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -public interface CustomUserDetailsService { - - UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException; - - UserDetails loadUserById(Long id); - -} \ No newline at end of file diff --git a/src/main/java/com/sopromadze/blogapi/service/JwtService.java b/src/main/java/com/sopromadze/blogapi/service/JwtService.java new file mode 100644 index 00000000..acba5c26 --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/service/JwtService.java @@ -0,0 +1,83 @@ +package com.sopromadze.blogapi.service; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.io.Decoders; +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +@Service +@Data +public class JwtService { + + @Value("${security.jwt.secret-key}") + private String secretKey; + + @Value("${security.jwt.expiration-time}") + private long jwtExpiration; + + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } + + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + public String generateToken(String username) { + return generateToken(new HashMap<>(), username); + } + + public String generateToken(Map extraClaims, String username) { + return buildToken(extraClaims, username, jwtExpiration); + } + + private String buildToken(Map extraClaims, String username, long expiration) { + return Jwts + .builder() + .claims(extraClaims) + .subject(username) + .issuedAt(new Date(System.currentTimeMillis())) + .expiration(new Date(System.currentTimeMillis() + expiration)) + .signWith(getSignInKey()) + .compact(); + } + + public boolean isTokenValid(String token, UserDetails userDetails) { + final String username = extractUsername(token); + return (username.equals(userDetails.getUsername())) && !isTokenExpired(token); + } + + private boolean isTokenExpired(String token) { + return extractExpiration(token).before(new Date()); + } + + private Date extractExpiration(String token) { + return extractClaim(token, Claims::getExpiration); + } + + private Claims extractAllClaims(String token) { + return Jwts + .parser() + .verifyWith(getSignInKey()) + .build() + .parseSignedClaims(token) + .getPayload(); + } + + private SecretKey getSignInKey() { + byte[] keyBytes = Decoders.BASE64.decode(secretKey); + return new SecretKeySpec(keyBytes, "HmacSHA256"); + } + +} \ No newline at end of file diff --git a/src/main/java/com/sopromadze/blogapi/service/PhotoService.java b/src/main/java/com/sopromadze/blogapi/service/PhotoService.java index b59c767f..ba954f2d 100644 --- a/src/main/java/com/sopromadze/blogapi/service/PhotoService.java +++ b/src/main/java/com/sopromadze/blogapi/service/PhotoService.java @@ -8,16 +8,16 @@ public interface PhotoService { - PagedResponse getAllPhotos(int page, int size); + PagedResponse getAllPhotos(int page, int size); - PhotoResponse getPhoto(Long id); + PhotoResponse getPhoto(Long id); - PhotoResponse updatePhoto(Long id, PhotoRequest photoRequest, UserPrincipal currentUser); + PhotoResponse updatePhoto(Long id, PhotoRequest photoRequest, UserPrincipal currentUser); - PhotoResponse addPhoto(PhotoRequest photoRequest, UserPrincipal currentUser); + PhotoResponse addPhoto(PhotoRequest photoRequest, UserPrincipal currentUser); - ApiResponse deletePhoto(Long id, UserPrincipal currentUser); + ApiResponse deletePhoto(Long id, UserPrincipal currentUser); - PagedResponse getAllPhotosByAlbum(Long albumId, int page, int size); + PagedResponse getAllPhotosByAlbum(Long albumId, int page, int size); } \ No newline at end of file diff --git a/src/main/java/com/sopromadze/blogapi/service/PostService.java b/src/main/java/com/sopromadze/blogapi/service/PostService.java index d4754205..e2b4fccf 100644 --- a/src/main/java/com/sopromadze/blogapi/service/PostService.java +++ b/src/main/java/com/sopromadze/blogapi/service/PostService.java @@ -9,20 +9,20 @@ public interface PostService { - PagedResponse getAllPosts(int page, int size); + PagedResponse getAllPosts(int page, int size); - PagedResponse getPostsByCreatedBy(String username, int page, int size); + PagedResponse getPostsByCreatedBy(String username, int page, int size); - PagedResponse getPostsByCategory(Long id, int page, int size); + PagedResponse getPostsByCategory(Long id, int page, int size); - PagedResponse getPostsByTag(Long id, int page, int size); + PagedResponse getPostsByTag(Long id, int page, int size); - Post updatePost(Long id, PostRequest newPostRequest, UserPrincipal currentUser); + Post updatePost(Long id, PostRequest newPostRequest, UserPrincipal currentUser); - ApiResponse deletePost(Long id, UserPrincipal currentUser); + ApiResponse deletePost(Long id, UserPrincipal currentUser); - PostResponse addPost(PostRequest postRequest, UserPrincipal currentUser); + PostResponse addPost(PostRequest postRequest, UserPrincipal currentUser); - Post getPost(Long id); + Post getPost(Long id); } diff --git a/src/main/java/com/sopromadze/blogapi/service/TagService.java b/src/main/java/com/sopromadze/blogapi/service/TagService.java index db321cca..07c8c824 100644 --- a/src/main/java/com/sopromadze/blogapi/service/TagService.java +++ b/src/main/java/com/sopromadze/blogapi/service/TagService.java @@ -7,14 +7,14 @@ public interface TagService { - PagedResponse getAllTags(int page, int size); + PagedResponse getAllTags(int page, int size); - Tag getTag(Long id); + Tag getTag(Long id); - Tag addTag(Tag tag, UserPrincipal currentUser); + Tag addTag(Tag tag, UserPrincipal currentUser); - Tag updateTag(Long id, Tag newTag, UserPrincipal currentUser); + Tag updateTag(Long id, Tag newTag, UserPrincipal currentUser); - ApiResponse deleteTag(Long id, UserPrincipal currentUser); + ApiResponse deleteTag(Long id, UserPrincipal currentUser); } diff --git a/src/main/java/com/sopromadze/blogapi/service/TodoService.java b/src/main/java/com/sopromadze/blogapi/service/TodoService.java index 23e7903d..4c06cf05 100644 --- a/src/main/java/com/sopromadze/blogapi/service/TodoService.java +++ b/src/main/java/com/sopromadze/blogapi/service/TodoService.java @@ -1,24 +1,24 @@ package com.sopromadze.blogapi.service; -import com.sopromadze.blogapi.model.Todo; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; import com.sopromadze.blogapi.payload.ApiResponse; import com.sopromadze.blogapi.payload.PagedResponse; import com.sopromadze.blogapi.security.UserPrincipal; public interface TodoService { - Todo completeTodo(Long id, UserPrincipal currentUser); + TodoEntity completeTodo(Long id, UserPrincipal currentUser); - Todo unCompleteTodo(Long id, UserPrincipal currentUser); + TodoEntity unCompleteTodo(Long id, UserPrincipal currentUser); - PagedResponse getAllTodos(UserPrincipal currentUser, int page, int size); + PagedResponse getAllTodos(UserPrincipal currentUser, int page, int size); - Todo addTodo(Todo todo, UserPrincipal currentUser); + TodoEntity addTodo(TodoEntity todoEntity, String username); - Todo getTodo(Long id, UserPrincipal currentUser); + TodoEntity getTodo(Long id, UserPrincipal currentUser); - Todo updateTodo(Long id, Todo newTodo, UserPrincipal currentUser); + TodoEntity updateTodo(Long id, TodoEntity newTodoEntity, UserPrincipal currentUser); - ApiResponse deleteTodo(Long id, UserPrincipal currentUser); + ApiResponse deleteTodo(Long id, UserPrincipal currentUser); } diff --git a/src/main/java/com/sopromadze/blogapi/service/UserService.java b/src/main/java/com/sopromadze/blogapi/service/UserService.java index a134a637..b213d3a6 100644 --- a/src/main/java/com/sopromadze/blogapi/service/UserService.java +++ b/src/main/java/com/sopromadze/blogapi/service/UserService.java @@ -1,33 +1,29 @@ package com.sopromadze.blogapi.service; -import com.sopromadze.blogapi.model.user.User; -import com.sopromadze.blogapi.payload.ApiResponse; -import com.sopromadze.blogapi.payload.InfoRequest; -import com.sopromadze.blogapi.payload.UserIdentityAvailability; -import com.sopromadze.blogapi.payload.UserProfile; -import com.sopromadze.blogapi.payload.UserSummary; +import com.sopromadze.blogapi.model.user.UserEntity; +import com.sopromadze.blogapi.payload.*; import com.sopromadze.blogapi.security.UserPrincipal; public interface UserService { - UserSummary getCurrentUser(UserPrincipal currentUser); + UserSummary getCurrentUser(UserPrincipal currentUser); - UserIdentityAvailability checkUsernameAvailability(String username); + UserIdentityAvailability checkUsernameAvailability(String username); - UserIdentityAvailability checkEmailAvailability(String email); + UserIdentityAvailability checkEmailAvailability(String email); - UserProfile getUserProfile(String username); + UserProfile getUserProfile(String username); - User addUser(User user); + UserEntity addUser(UserEntity userEntity); - User updateUser(User newUser, String username, UserPrincipal currentUser); + UserEntity updateUser(UserEntity newUserEntity, String username, UserPrincipal currentUser); - ApiResponse deleteUser(String username, UserPrincipal currentUser); + ApiResponse deleteUser(String username, UserPrincipal currentUser); - ApiResponse giveAdmin(String username); + ApiResponse giveAdmin(String username); - ApiResponse removeAdmin(String username); + ApiResponse removeAdmin(String username); - UserProfile setOrUpdateInfo(UserPrincipal currentUser, InfoRequest infoRequest); + UserProfile setOrUpdateInfo(UserPrincipal currentUser, InfoRequest infoRequest); } \ No newline at end of file diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/AlbumServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/AlbumServiceImpl.java index 6964008e..16fabf2b 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/AlbumServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/AlbumServiceImpl.java @@ -4,7 +4,7 @@ import com.sopromadze.blogapi.exception.ResourceNotFoundException; import com.sopromadze.blogapi.model.Album; import com.sopromadze.blogapi.model.role.RoleName; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.user.UserEntity; import com.sopromadze.blogapi.payload.AlbumResponse; import com.sopromadze.blogapi.payload.ApiResponse; import com.sopromadze.blogapi.payload.PagedResponse; @@ -33,101 +33,104 @@ @Service public class AlbumServiceImpl implements AlbumService { - private static final String CREATED_AT = "createdAt"; - private static final String ALBUM_STR = "Album"; + private static final String CREATED_AT = "createdAt"; - private static final String YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION = "You don't have permission to make this operation"; + private static final String ALBUM_STR = "Album"; - @Autowired - private AlbumRepository albumRepository; + private static final String YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION = "You don't have permission to make this operation"; - @Autowired - private UserRepository userRepository; + @Autowired + private AlbumRepository albumRepository; - @Autowired - private ModelMapper modelMapper; + @Autowired + private UserRepository userRepository; - @Override - public PagedResponse getAllAlbums(int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); + @Autowired + private ModelMapper modelMapper; - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + @Override + public PagedResponse getAllAlbums(int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); - Page albums = albumRepository.findAll(pageable); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - if (albums.getNumberOfElements() == 0) { - return new PagedResponse<>(Collections.emptyList(), albums.getNumber(), albums.getSize(), albums.getTotalElements(), - albums.getTotalPages(), albums.isLast()); - } + Page albums = albumRepository.findAll(pageable); - List albumResponses = Arrays.asList(modelMapper.map(albums.getContent(), AlbumResponse[].class)); + if (albums.getNumberOfElements() == 0) { + return new PagedResponse<>(Collections.emptyList(), albums.getNumber(), albums.getSize(), albums.getTotalElements(), + albums.getTotalPages(), albums.isLast()); + } - return new PagedResponse<>(albumResponses, albums.getNumber(), albums.getSize(), albums.getTotalElements(), albums.getTotalPages(), - albums.isLast()); - } + List albumResponses = Arrays.asList(modelMapper.map(albums.getContent(), AlbumResponse[].class)); - @Override - public ResponseEntity addAlbum(AlbumRequest albumRequest, UserPrincipal currentUser) { - User user = userRepository.getUser(currentUser); + return new PagedResponse<>(albumResponses, albums.getNumber(), albums.getSize(), albums.getTotalElements(), albums.getTotalPages(), + albums.isLast()); + } - Album album = new Album(); + @Override + public ResponseEntity addAlbum(AlbumRequest albumRequest, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.getUser(currentUser); - modelMapper.map(albumRequest, album); + Album album = new Album(); - album.setUser(user); - Album newAlbum = albumRepository.save(album); - return new ResponseEntity<>(newAlbum, HttpStatus.CREATED); - } + modelMapper.map(albumRequest, album); - @Override - public ResponseEntity getAlbum(Long id) { - Album album = albumRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(ALBUM_STR, ID, id)); - return new ResponseEntity<>(album, HttpStatus.OK); - } + album.setUser(userEntity); + Album newAlbum = albumRepository.save(album); + return new ResponseEntity<>(newAlbum, HttpStatus.CREATED); + } - @Override - public ResponseEntity updateAlbum(Long id, AlbumRequest newAlbum, UserPrincipal currentUser) { - Album album = albumRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(ALBUM_STR, ID, id)); - User user = userRepository.getUser(currentUser); - if (album.getUser().getId().equals(user.getId()) || currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - album.setTitle(newAlbum.getTitle()); - Album updatedAlbum = albumRepository.save(album); + @Override + public ResponseEntity getAlbum(Long id) { + Album album = albumRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(ALBUM_STR, ID, id)); + return new ResponseEntity<>(album, HttpStatus.OK); + } - AlbumResponse albumResponse = new AlbumResponse(); + @Override + public ResponseEntity updateAlbum(Long id, AlbumRequest newAlbum, UserPrincipal currentUser) { + Album album = albumRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(ALBUM_STR, ID, id)); + UserEntity userEntity = userRepository.getUser(currentUser); + if (album.getUser().getId().equals(userEntity.getId()) || currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + album.setTitle(newAlbum.getTitle()); + Album updatedAlbum = albumRepository.save(album); - modelMapper.map(updatedAlbum, albumResponse); + AlbumResponse albumResponse = new AlbumResponse(); - return new ResponseEntity<>(albumResponse, HttpStatus.OK); - } + modelMapper.map(updatedAlbum, albumResponse); - throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - } + return new ResponseEntity<>(albumResponse, HttpStatus.OK); + } - @Override - public ResponseEntity deleteAlbum(Long id, UserPrincipal currentUser) { - Album album = albumRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(ALBUM_STR, ID, id)); - User user = userRepository.getUser(currentUser); - if (album.getUser().getId().equals(user.getId()) || currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - albumRepository.deleteById(id); - return new ResponseEntity<>(new ApiResponse(Boolean.TRUE, "You successfully deleted album"), HttpStatus.OK); - } + throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + } - throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - } + @Override + public ResponseEntity deleteAlbum(Long id, UserPrincipal currentUser) { + Album album = albumRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(ALBUM_STR, ID, id)); + UserEntity userEntity = userRepository.getUser(currentUser); + if (album.getUser().getId().equals(userEntity.getId()) || currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + albumRepository.deleteById(id); + return new ResponseEntity<>(new ApiResponse(Boolean.TRUE, "You successfully deleted album"), HttpStatus.OK); + } - @Override - public PagedResponse getUserAlbums(String username, int page, int size) { - User user = userRepository.getUserByName(username); + throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + } - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + @Override + public PagedResponse getUserAlbums(String username, int page, int size) { + UserEntity userEntity = userRepository.getUserByName(username); - Page albums = albumRepository.findByCreatedBy(user.getId(), pageable); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - List content = albums.getNumberOfElements() > 0 ? albums.getContent() : Collections.emptyList(); + Page albums = albumRepository.findByCreatedBy(userEntity.getId(), pageable); + + List content = albums.getNumberOfElements() > 0 ? albums.getContent() : Collections.emptyList(); + + return new PagedResponse<>(content, albums.getNumber(), albums.getSize(), albums.getTotalElements(), albums.getTotalPages(), + albums.isLast()); + } - return new PagedResponse<>(content, albums.getNumber(), albums.getSize(), albums.getTotalElements(), albums.getTotalPages(), albums.isLast()); - } } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/CategoryServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/CategoryServiceImpl.java index a98064b3..acdd51a9 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/CategoryServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/CategoryServiceImpl.java @@ -26,58 +26,59 @@ @Service public class CategoryServiceImpl implements CategoryService { - @Autowired - private CategoryRepository categoryRepository; - - @Override - public PagedResponse getAllCategories(int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); - - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt"); - - Page categories = categoryRepository.findAll(pageable); - - List content = categories.getNumberOfElements() == 0 ? Collections.emptyList() : categories.getContent(); - - return new PagedResponse<>(content, categories.getNumber(), categories.getSize(), categories.getTotalElements(), - categories.getTotalPages(), categories.isLast()); - } - - @Override - public ResponseEntity getCategory(Long id) { - Category category = categoryRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Category", "id", id)); - return new ResponseEntity<>(category, HttpStatus.OK); - } - - @Override - public ResponseEntity addCategory(Category category, UserPrincipal currentUser) { - Category newCategory = categoryRepository.save(category); - return new ResponseEntity<>(newCategory, HttpStatus.CREATED); - } - - @Override - public ResponseEntity updateCategory(Long id, Category newCategory, UserPrincipal currentUser) { - Category category = categoryRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Category", "id", id)); - if (category.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - category.setName(newCategory.getName()); - Category updatedCategory = categoryRepository.save(category); - return new ResponseEntity<>(updatedCategory, HttpStatus.OK); - } - - throw new UnauthorizedException("You don't have permission to edit this category"); - } - - @Override - public ResponseEntity deleteCategory(Long id, UserPrincipal currentUser) { - Category category = categoryRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("category", "id", id)); - if (category.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - categoryRepository.deleteById(id); - return new ResponseEntity<>(new ApiResponse(Boolean.TRUE, "You successfully deleted category"), HttpStatus.OK); - } - throw new UnauthorizedException("You don't have permission to delete this category"); - } + @Autowired + private CategoryRepository categoryRepository; + + @Override + public PagedResponse getAllCategories(int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); + + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt"); + + Page categories = categoryRepository.findAll(pageable); + + List content = categories.getNumberOfElements() == 0 ? Collections.emptyList() : categories.getContent(); + + return new PagedResponse<>(content, categories.getNumber(), categories.getSize(), categories.getTotalElements(), + categories.getTotalPages(), categories.isLast()); + } + + @Override + public ResponseEntity getCategory(Long id) { + Category category = categoryRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Category", "id", id)); + return new ResponseEntity<>(category, HttpStatus.OK); + } + + @Override + public ResponseEntity addCategory(Category category, UserPrincipal currentUser) { + Category newCategory = categoryRepository.save(category); + return new ResponseEntity<>(newCategory, HttpStatus.CREATED); + } + + @Override + public ResponseEntity updateCategory(Long id, Category newCategory, UserPrincipal currentUser) { + Category category = categoryRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Category", "id", id)); + if (category.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + category.setName(newCategory.getName()); + Category updatedCategory = categoryRepository.save(category); + return new ResponseEntity<>(updatedCategory, HttpStatus.OK); + } + + throw new UnauthorizedException("You don't have permission to edit this category"); + } + + @Override + public ResponseEntity deleteCategory(Long id, UserPrincipal currentUser) { + Category category = categoryRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("category", "id", id)); + if (category.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + categoryRepository.deleteById(id); + return new ResponseEntity<>(new ApiResponse(Boolean.TRUE, "You successfully deleted category"), HttpStatus.OK); + } + throw new UnauthorizedException("You don't have permission to delete this category"); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/CommentServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/CommentServiceImpl.java index 00258de7..18857d79 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/CommentServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/CommentServiceImpl.java @@ -5,7 +5,7 @@ import com.sopromadze.blogapi.model.Comment; import com.sopromadze.blogapi.model.Post; import com.sopromadze.blogapi.model.role.RoleName; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.user.UserEntity; import com.sopromadze.blogapi.payload.ApiResponse; import com.sopromadze.blogapi.payload.CommentRequest; import com.sopromadze.blogapi.payload.PagedResponse; @@ -26,102 +26,104 @@ @Service public class CommentServiceImpl implements CommentService { - private static final String THIS_COMMENT = " this comment"; - - private static final String YOU_DON_T_HAVE_PERMISSION_TO = "You don't have permission to "; - - private static final String ID_STR = "id"; - - private static final String COMMENT_STR = "Comment"; - - private static final String POST_STR = "Post"; - - private static final String COMMENT_DOES_NOT_BELONG_TO_POST = "Comment does not belong to post"; - - @Autowired - private CommentRepository commentRepository; - - @Autowired - private PostRepository postRepository; - - @Autowired - private UserRepository userRepository; - - @Override - public PagedResponse getAllComments(Long postId, int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt"); - - Page comments = commentRepository.findByPostId(postId, pageable); - - return new PagedResponse<>(comments.getContent(), comments.getNumber(), comments.getSize(), - comments.getTotalElements(), comments.getTotalPages(), comments.isLast()); - } - - @Override - public Comment addComment(CommentRequest commentRequest, Long postId, UserPrincipal currentUser) { - Post post = postRepository.findById(postId) - .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); - User user = userRepository.getUser(currentUser); - Comment comment = new Comment(commentRequest.getBody()); - comment.setUser(user); - comment.setPost(post); - comment.setName(currentUser.getUsername()); - comment.setEmail(currentUser.getEmail()); - return commentRepository.save(comment); - } - - @Override - public Comment getComment(Long postId, Long id) { - Post post = postRepository.findById(postId) - .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); - Comment comment = commentRepository.findById(id) - .orElseThrow(() -> new ResourceNotFoundException(COMMENT_STR, ID_STR, id)); - if (comment.getPost().getId().equals(post.getId())) { - return comment; - } - - throw new BlogapiException(HttpStatus.BAD_REQUEST, COMMENT_DOES_NOT_BELONG_TO_POST); - } - - @Override - public Comment updateComment(Long postId, Long id, CommentRequest commentRequest, - UserPrincipal currentUser) { - Post post = postRepository.findById(postId) - .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); - Comment comment = commentRepository.findById(id) - .orElseThrow(() -> new ResourceNotFoundException(COMMENT_STR, ID_STR, id)); - - if (!comment.getPost().getId().equals(post.getId())) { - throw new BlogapiException(HttpStatus.BAD_REQUEST, COMMENT_DOES_NOT_BELONG_TO_POST); - } - - if (comment.getUser().getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - comment.setBody(commentRequest.getBody()); - return commentRepository.save(comment); - } - - throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO + "update" + THIS_COMMENT); - } - - @Override - public ApiResponse deleteComment(Long postId, Long id, UserPrincipal currentUser) { - Post post = postRepository.findById(postId) - .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); - Comment comment = commentRepository.findById(id) - .orElseThrow(() -> new ResourceNotFoundException(COMMENT_STR, ID_STR, id)); - - if (!comment.getPost().getId().equals(post.getId())) { - return new ApiResponse(Boolean.FALSE, COMMENT_DOES_NOT_BELONG_TO_POST); - } - - if (comment.getUser().getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - commentRepository.deleteById(comment.getId()); - return new ApiResponse(Boolean.TRUE, "You successfully deleted comment"); - } - - throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO + "delete" + THIS_COMMENT); - } + + private static final String THIS_COMMENT = " this comment"; + + private static final String YOU_DON_T_HAVE_PERMISSION_TO = "You don't have permission to "; + + private static final String ID_STR = "id"; + + private static final String COMMENT_STR = "Comment"; + + private static final String POST_STR = "Post"; + + private static final String COMMENT_DOES_NOT_BELONG_TO_POST = "Comment does not belong to post"; + + @Autowired + private CommentRepository commentRepository; + + @Autowired + private PostRepository postRepository; + + @Autowired + private UserRepository userRepository; + + @Override + public PagedResponse getAllComments(Long postId, int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt"); + + Page comments = commentRepository.findByPostId(postId, pageable); + + return new PagedResponse<>(comments.getContent(), comments.getNumber(), comments.getSize(), + comments.getTotalElements(), comments.getTotalPages(), comments.isLast()); + } + + @Override + public Comment addComment(CommentRequest commentRequest, Long postId, UserPrincipal currentUser) { + Post post = postRepository.findById(postId) + .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); + UserEntity userEntity = userRepository.getUser(currentUser); + Comment comment = new Comment(commentRequest.getBody()); + comment.setUser(userEntity); + comment.setPost(post); + comment.setName(currentUser.getUsername()); + comment.setEmail(currentUser.getEmail()); + return commentRepository.save(comment); + } + + @Override + public Comment getComment(Long postId, Long id) { + Post post = postRepository.findById(postId) + .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); + Comment comment = commentRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException(COMMENT_STR, ID_STR, id)); + if (comment.getPost().getId().equals(post.getId())) { + return comment; + } + + throw new BlogapiException(HttpStatus.BAD_REQUEST, COMMENT_DOES_NOT_BELONG_TO_POST); + } + + @Override + public Comment updateComment(Long postId, Long id, CommentRequest commentRequest, + UserPrincipal currentUser) { + Post post = postRepository.findById(postId) + .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); + Comment comment = commentRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException(COMMENT_STR, ID_STR, id)); + + if (!comment.getPost().getId().equals(post.getId())) { + throw new BlogapiException(HttpStatus.BAD_REQUEST, COMMENT_DOES_NOT_BELONG_TO_POST); + } + + if (comment.getUser().getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + comment.setBody(commentRequest.getBody()); + return commentRepository.save(comment); + } + + throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO + "update" + THIS_COMMENT); + } + + @Override + public ApiResponse deleteComment(Long postId, Long id, UserPrincipal currentUser) { + Post post = postRepository.findById(postId) + .orElseThrow(() -> new ResourceNotFoundException(POST_STR, ID_STR, postId)); + Comment comment = commentRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException(COMMENT_STR, ID_STR, id)); + + if (!comment.getPost().getId().equals(post.getId())) { + return new ApiResponse(Boolean.FALSE, COMMENT_DOES_NOT_BELONG_TO_POST); + } + + if (comment.getUser().getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + commentRepository.deleteById(comment.getId()); + return new ApiResponse(Boolean.TRUE, "You successfully deleted comment"); + } + + throw new BlogapiException(HttpStatus.UNAUTHORIZED, YOU_DON_T_HAVE_PERMISSION_TO + "delete" + THIS_COMMENT); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/CustomUserDetailsService.java b/src/main/java/com/sopromadze/blogapi/service/impl/CustomUserDetailsService.java new file mode 100644 index 00000000..8abb637d --- /dev/null +++ b/src/main/java/com/sopromadze/blogapi/service/impl/CustomUserDetailsService.java @@ -0,0 +1,44 @@ +package com.sopromadze.blogapi.service.impl; + +import com.sopromadze.blogapi.model.user.UserEntity; +import com.sopromadze.blogapi.repository.UserRepository; +import com.sopromadze.blogapi.security.UserPrincipal; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +@Service +public class CustomUserDetailsService implements UserDetailsService { + + private final UserRepository userRepository; + + @Override + @Transactional + public UserDetails loadUserByUsername(String usernameOrEmail) { + UserEntity userEntity = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail) + .orElseThrow(() -> new UsernameNotFoundException(String.format("User not found with this username or email: %s", usernameOrEmail))); + + List authorities = userEntity.getRoles().stream() + .map(role -> new SimpleGrantedAuthority(role.getName().name())).collect(Collectors.toList()); + + return UserPrincipal.builder() + .id(userEntity.getId()) + .firstName(userEntity.getFirstName()) + .lastName(userEntity.getLastName()) + .username(userEntity.getUsername()) + .email(userEntity.getEmail()) + .password(userEntity.getPassword()) + .authorities(authorities) + .build(); + } + +} diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/CustomUserDetailsServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/CustomUserDetailsServiceImpl.java deleted file mode 100644 index 27451513..00000000 --- a/src/main/java/com/sopromadze/blogapi/service/impl/CustomUserDetailsServiceImpl.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.sopromadze.blogapi.service.impl; - -import com.sopromadze.blogapi.model.user.User; -import com.sopromadze.blogapi.repository.UserRepository; -import com.sopromadze.blogapi.security.UserPrincipal; -import com.sopromadze.blogapi.service.CustomUserDetailsService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -import javax.transaction.Transactional; - -@Service -public class CustomUserDetailsServiceImpl implements UserDetailsService, CustomUserDetailsService { - @Autowired - private UserRepository userRepository; - - @Override - @Transactional - public UserDetails loadUserByUsername(String usernameOrEmail) { - User user = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail) - .orElseThrow(() -> new UsernameNotFoundException(String.format("User not found with this username or email: %s", usernameOrEmail))); - return UserPrincipal.create(user); - } - - @Override - @Transactional - public UserDetails loadUserById(Long id) { - User user = userRepository.findById(id).orElseThrow(() -> new UsernameNotFoundException(String.format("User not found with id: %s", id))); - - return UserPrincipal.create(user); - } -} diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/PhotoServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/PhotoServiceImpl.java index dfa90b86..e4482521 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/PhotoServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/PhotoServiceImpl.java @@ -27,116 +27,114 @@ import java.util.Collections; import java.util.List; -import static com.sopromadze.blogapi.utils.AppConstants.ALBUM; -import static com.sopromadze.blogapi.utils.AppConstants.CREATED_AT; -import static com.sopromadze.blogapi.utils.AppConstants.ID; -import static com.sopromadze.blogapi.utils.AppConstants.PHOTO; +import static com.sopromadze.blogapi.utils.AppConstants.*; @Service public class PhotoServiceImpl implements PhotoService { - @Autowired - private PhotoRepository photoRepository; - - @Autowired - private AlbumRepository albumRepository; - - @Override - public PagedResponse getAllPhotos(int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); - - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - Page photos = photoRepository.findAll(pageable); - - List photoResponses = new ArrayList<>(photos.getContent().size()); - for (Photo photo : photos.getContent()) { - photoResponses.add(new PhotoResponse(photo.getId(), photo.getTitle(), photo.getUrl(), - photo.getThumbnailUrl(), photo.getAlbum().getId())); - } - - if (photos.getNumberOfElements() == 0) { - return new PagedResponse<>(Collections.emptyList(), photos.getNumber(), photos.getSize(), - photos.getTotalElements(), photos.getTotalPages(), photos.isLast()); - } - return new PagedResponse<>(photoResponses, photos.getNumber(), photos.getSize(), photos.getTotalElements(), - photos.getTotalPages(), photos.isLast()); - - } - - @Override - public PhotoResponse getPhoto(Long id) { - Photo photo = photoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(PHOTO, ID, id)); - - return new PhotoResponse(photo.getId(), photo.getTitle(), photo.getUrl(), - photo.getThumbnailUrl(), photo.getAlbum().getId()); - } - - @Override - public PhotoResponse updatePhoto(Long id, PhotoRequest photoRequest, UserPrincipal currentUser) { - Album album = albumRepository.findById(photoRequest.getAlbumId()) - .orElseThrow(() -> new ResourceNotFoundException(ALBUM, ID, photoRequest.getAlbumId())); - Photo photo = photoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(PHOTO, ID, id)); - if (photo.getAlbum().getUser().getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - photo.setTitle(photoRequest.getTitle()); - photo.setThumbnailUrl(photoRequest.getThumbnailUrl()); - photo.setAlbum(album); - Photo updatedPhoto = photoRepository.save(photo); - return new PhotoResponse(updatedPhoto.getId(), updatedPhoto.getTitle(), - updatedPhoto.getUrl(), updatedPhoto.getThumbnailUrl(), updatedPhoto.getAlbum().getId()); - } - - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to update this photo"); - - throw new UnauthorizedException(apiResponse); - } - - @Override - public PhotoResponse addPhoto(PhotoRequest photoRequest, UserPrincipal currentUser) { - Album album = albumRepository.findById(photoRequest.getAlbumId()) - .orElseThrow(() -> new ResourceNotFoundException(ALBUM, ID, photoRequest.getAlbumId())); - if (album.getUser().getId().equals(currentUser.getId())) { - Photo photo = new Photo(photoRequest.getTitle(), photoRequest.getUrl(), photoRequest.getThumbnailUrl(), - album); - Photo newPhoto = photoRepository.save(photo); - return new PhotoResponse(newPhoto.getId(), newPhoto.getTitle(), newPhoto.getUrl(), - newPhoto.getThumbnailUrl(), newPhoto.getAlbum().getId()); - } - - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to add photo in this album"); - - throw new UnauthorizedException(apiResponse); - } - - @Override - public ApiResponse deletePhoto(Long id, UserPrincipal currentUser) { - Photo photo = photoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(PHOTO, ID, id)); - if (photo.getAlbum().getUser().getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - photoRepository.deleteById(id); - return new ApiResponse(Boolean.TRUE, "Photo deleted successfully"); - } - - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete this photo"); - - throw new UnauthorizedException(apiResponse); - } - - @Override - public PagedResponse getAllPhotosByAlbum(Long albumId, int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); - - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, AppConstants.CREATED_AT); - - Page photos = photoRepository.findByAlbumId(albumId, pageable); - - List photoResponses = new ArrayList<>(photos.getContent().size()); - for (Photo photo : photos.getContent()) { - photoResponses.add(new PhotoResponse(photo.getId(), photo.getTitle(), photo.getUrl(), - photo.getThumbnailUrl(), photo.getAlbum().getId())); - } - - return new PagedResponse<>(photoResponses, photos.getNumber(), photos.getSize(), photos.getTotalElements(), - photos.getTotalPages(), photos.isLast()); - } + @Autowired + private PhotoRepository photoRepository; + + @Autowired + private AlbumRepository albumRepository; + + @Override + public PagedResponse getAllPhotos(int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); + + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + Page photos = photoRepository.findAll(pageable); + + List photoResponses = new ArrayList<>(photos.getContent().size()); + for (Photo photo : photos.getContent()) { + photoResponses.add(new PhotoResponse(photo.getId(), photo.getTitle(), photo.getUrl(), + photo.getThumbnailUrl(), photo.getAlbum().getId())); + } + + if (photos.getNumberOfElements() == 0) { + return new PagedResponse<>(Collections.emptyList(), photos.getNumber(), photos.getSize(), + photos.getTotalElements(), photos.getTotalPages(), photos.isLast()); + } + return new PagedResponse<>(photoResponses, photos.getNumber(), photos.getSize(), photos.getTotalElements(), + photos.getTotalPages(), photos.isLast()); + + } + + @Override + public PhotoResponse getPhoto(Long id) { + Photo photo = photoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(PHOTO, ID, id)); + + return new PhotoResponse(photo.getId(), photo.getTitle(), photo.getUrl(), + photo.getThumbnailUrl(), photo.getAlbum().getId()); + } + + @Override + public PhotoResponse updatePhoto(Long id, PhotoRequest photoRequest, UserPrincipal currentUser) { + Album album = albumRepository.findById(photoRequest.getAlbumId()) + .orElseThrow(() -> new ResourceNotFoundException(ALBUM, ID, photoRequest.getAlbumId())); + Photo photo = photoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(PHOTO, ID, id)); + if (photo.getAlbum().getUser().getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + photo.setTitle(photoRequest.getTitle()); + photo.setThumbnailUrl(photoRequest.getThumbnailUrl()); + photo.setAlbum(album); + Photo updatedPhoto = photoRepository.save(photo); + return new PhotoResponse(updatedPhoto.getId(), updatedPhoto.getTitle(), + updatedPhoto.getUrl(), updatedPhoto.getThumbnailUrl(), updatedPhoto.getAlbum().getId()); + } + + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to update this photo"); + + throw new UnauthorizedException(apiResponse); + } + + @Override + public PhotoResponse addPhoto(PhotoRequest photoRequest, UserPrincipal currentUser) { + Album album = albumRepository.findById(photoRequest.getAlbumId()) + .orElseThrow(() -> new ResourceNotFoundException(ALBUM, ID, photoRequest.getAlbumId())); + if (album.getUser().getId().equals(currentUser.getId())) { + Photo photo = new Photo(photoRequest.getTitle(), photoRequest.getUrl(), photoRequest.getThumbnailUrl(), + album); + Photo newPhoto = photoRepository.save(photo); + return new PhotoResponse(newPhoto.getId(), newPhoto.getTitle(), newPhoto.getUrl(), + newPhoto.getThumbnailUrl(), newPhoto.getAlbum().getId()); + } + + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to add photo in this album"); + + throw new UnauthorizedException(apiResponse); + } + + @Override + public ApiResponse deletePhoto(Long id, UserPrincipal currentUser) { + Photo photo = photoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(PHOTO, ID, id)); + if (photo.getAlbum().getUser().getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + photoRepository.deleteById(id); + return new ApiResponse(Boolean.TRUE, "Photo deleted successfully"); + } + + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete this photo"); + + throw new UnauthorizedException(apiResponse); + } + + @Override + public PagedResponse getAllPhotosByAlbum(Long albumId, int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); + + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, AppConstants.CREATED_AT); + + Page photos = photoRepository.findByAlbumId(albumId, pageable); + + List photoResponses = new ArrayList<>(photos.getContent().size()); + for (Photo photo : photos.getContent()) { + photoResponses.add(new PhotoResponse(photo.getId(), photo.getTitle(), photo.getUrl(), + photo.getThumbnailUrl(), photo.getAlbum().getId())); + } + + return new PagedResponse<>(photoResponses, photos.getNumber(), photos.getSize(), photos.getTotalElements(), + photos.getTotalPages(), photos.isLast()); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/PostServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/PostServiceImpl.java index 8666ec58..818bd8b3 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/PostServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/PostServiceImpl.java @@ -7,7 +7,7 @@ import com.sopromadze.blogapi.model.Post; import com.sopromadze.blogapi.model.Tag; import com.sopromadze.blogapi.model.role.RoleName; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.model.user.UserEntity; import com.sopromadze.blogapi.payload.ApiResponse; import com.sopromadze.blogapi.payload.PagedResponse; import com.sopromadze.blogapi.payload.PostRequest; @@ -32,174 +32,171 @@ import java.util.Collections; import java.util.List; -import static com.sopromadze.blogapi.utils.AppConstants.CATEGORY; -import static com.sopromadze.blogapi.utils.AppConstants.CREATED_AT; -import static com.sopromadze.blogapi.utils.AppConstants.ID; -import static com.sopromadze.blogapi.utils.AppConstants.POST; -import static com.sopromadze.blogapi.utils.AppConstants.TAG; -import static com.sopromadze.blogapi.utils.AppConstants.USER; +import static com.sopromadze.blogapi.utils.AppConstants.*; @Service public class PostServiceImpl implements PostService { - @Autowired - private PostRepository postRepository; - @Autowired - private UserRepository userRepository; + @Autowired + private PostRepository postRepository; - @Autowired - private CategoryRepository categoryRepository; + @Autowired + private UserRepository userRepository; - @Autowired - private TagRepository tagRepository; + @Autowired + private CategoryRepository categoryRepository; - @Override - public PagedResponse getAllPosts(int page, int size) { - validatePageNumberAndSize(page, size); + @Autowired + private TagRepository tagRepository; - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + @Override + public PagedResponse getAllPosts(int page, int size) { + validatePageNumberAndSize(page, size); - Page posts = postRepository.findAll(pageable); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); + Page posts = postRepository.findAll(pageable); - return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), - posts.getTotalPages(), posts.isLast()); - } + List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); - @Override - public PagedResponse getPostsByCreatedBy(String username, int page, int size) { - validatePageNumberAndSize(page, size); - User user = userRepository.getUserByName(username); - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - Page posts = postRepository.findByCreatedBy(user.getId(), pageable); + return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), + posts.getTotalPages(), posts.isLast()); + } - List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); + @Override + public PagedResponse getPostsByCreatedBy(String username, int page, int size) { + validatePageNumberAndSize(page, size); + UserEntity userEntity = userRepository.getUserByName(username); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + Page posts = postRepository.findByCreatedBy(userEntity.getId(), pageable); - return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), - posts.getTotalPages(), posts.isLast()); - } + List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); - @Override - public PagedResponse getPostsByCategory(Long id, int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); - Category category = categoryRepository.findById(id) - .orElseThrow(() -> new ResourceNotFoundException(CATEGORY, ID, id)); + return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), + posts.getTotalPages(), posts.isLast()); + } - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - Page posts = postRepository.findByCategory(category.getId(), pageable); + @Override + public PagedResponse getPostsByCategory(Long id, int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); + Category category = categoryRepository.findById(id) + .orElseThrow(() -> new ResourceNotFoundException(CATEGORY, ID, id)); - List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + Page posts = postRepository.findByCategory(category.getCategoryId(), pageable); - return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), - posts.getTotalPages(), posts.isLast()); - } + List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); - @Override - public PagedResponse getPostsByTag(Long id, int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); + return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), + posts.getTotalPages(), posts.isLast()); + } - Tag tag = tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TAG, ID, id)); + @Override + public PagedResponse getPostsByTag(Long id, int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + Tag tag = tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TAG, ID, id)); - Page posts = postRepository.findByTags(Collections.singletonList(tag), pageable); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); + Page posts = postRepository.findByTags(Collections.singletonList(tag), pageable); - return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), - posts.getTotalPages(), posts.isLast()); - } + List content = posts.getNumberOfElements() == 0 ? Collections.emptyList() : posts.getContent(); - @Override - public Post updatePost(Long id, PostRequest newPostRequest, UserPrincipal currentUser) { - Post post = postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(POST, ID, id)); - Category category = categoryRepository.findById(newPostRequest.getCategoryId()) - .orElseThrow(() -> new ResourceNotFoundException(CATEGORY, ID, newPostRequest.getCategoryId())); - if (post.getUser().getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - post.setTitle(newPostRequest.getTitle()); - post.setBody(newPostRequest.getBody()); - post.setCategory(category); - return postRepository.save(post); - } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to edit this post"); + return new PagedResponse<>(content, posts.getNumber(), posts.getSize(), posts.getTotalElements(), + posts.getTotalPages(), posts.isLast()); + } - throw new UnauthorizedException(apiResponse); - } + @Override + public Post updatePost(Long id, PostRequest newPostRequest, UserPrincipal currentUser) { + Post post = postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(POST, ID, id)); + Category category = categoryRepository.findById(newPostRequest.getCategoryId()) + .orElseThrow(() -> new ResourceNotFoundException(CATEGORY, ID, newPostRequest.getCategoryId())); + if (post.getUser().getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + post.setTitle(newPostRequest.getTitle()); + post.setBody(newPostRequest.getBody()); + post.setCategory(category); + return postRepository.save(post); + } + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to edit this post"); - @Override - public ApiResponse deletePost(Long id, UserPrincipal currentUser) { - Post post = postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(POST, ID, id)); - if (post.getUser().getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - postRepository.deleteById(id); - return new ApiResponse(Boolean.TRUE, "You successfully deleted post"); - } + throw new UnauthorizedException(apiResponse); + } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete this post"); + @Override + public ApiResponse deletePost(Long id, UserPrincipal currentUser) { + Post post = postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(POST, ID, id)); + if (post.getUser().getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + postRepository.deleteById(id); + return new ApiResponse(Boolean.TRUE, "You successfully deleted post"); + } - throw new UnauthorizedException(apiResponse); - } + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete this post"); - @Override - public PostResponse addPost(PostRequest postRequest, UserPrincipal currentUser) { - User user = userRepository.findById(currentUser.getId()) - .orElseThrow(() -> new ResourceNotFoundException(USER, ID, 1L)); - Category category = categoryRepository.findById(postRequest.getCategoryId()) - .orElseThrow(() -> new ResourceNotFoundException(CATEGORY, ID, postRequest.getCategoryId())); + throw new UnauthorizedException(apiResponse); + } - List tags = new ArrayList<>(postRequest.getTags().size()); + @Override + public PostResponse addPost(PostRequest postRequest, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.findById(currentUser.getId()) + .orElseThrow(() -> new ResourceNotFoundException(USER, ID, 1L)); + Category category = categoryRepository.findById(postRequest.getCategoryId()) + .orElseThrow(() -> new ResourceNotFoundException(CATEGORY, ID, postRequest.getCategoryId())); - for (String name : postRequest.getTags()) { - Tag tag = tagRepository.findByName(name); - tag = tag == null ? tagRepository.save(new Tag(name)) : tag; + List tags = new ArrayList<>(postRequest.getTags().size()); - tags.add(tag); - } + for (String name : postRequest.getTags()) { + Tag tag = tagRepository.findByName(name); + tag = tag == null ? tagRepository.save(new Tag(name)) : tag; - Post post = new Post(); - post.setBody(postRequest.getBody()); - post.setTitle(postRequest.getTitle()); - post.setCategory(category); - post.setUser(user); - post.setTags(tags); + tags.add(tag); + } - Post newPost = postRepository.save(post); + Post post = new Post(); + post.setBody(postRequest.getBody()); + post.setTitle(postRequest.getTitle()); + post.setCategory(category); + post.setUser(userEntity); + post.setTags(tags); - PostResponse postResponse = new PostResponse(); + Post newPost = postRepository.save(post); - postResponse.setTitle(newPost.getTitle()); - postResponse.setBody(newPost.getBody()); - postResponse.setCategory(newPost.getCategory().getName()); + PostResponse postResponse = new PostResponse(); - List tagNames = new ArrayList<>(newPost.getTags().size()); + postResponse.setTitle(newPost.getTitle()); + postResponse.setBody(newPost.getBody()); + postResponse.setCategory(newPost.getCategory().getName()); - for (Tag tag : newPost.getTags()) { - tagNames.add(tag.getName()); - } + List tagNames = new ArrayList<>(newPost.getTags().size()); - postResponse.setTags(tagNames); + for (Tag tag : newPost.getTags()) { + tagNames.add(tag.getName()); + } - return postResponse; - } + postResponse.setTags(tagNames); - @Override - public Post getPost(Long id) { - return postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(POST, ID, id)); - } + return postResponse; + } - private void validatePageNumberAndSize(int page, int size) { - if (page < 0) { - throw new BadRequestException("Page number cannot be less than zero."); - } + @Override + public Post getPost(Long id) { + return postRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(POST, ID, id)); + } - if (size < 0) { - throw new BadRequestException("Size number cannot be less than zero."); - } + private void validatePageNumberAndSize(int page, int size) { + if (page < 0) { + throw new BadRequestException("Page number cannot be less than zero."); + } + + if (size < 0) { + throw new BadRequestException("Size number cannot be less than zero."); + } + + if (size > AppConstants.MAX_PAGE_SIZE) { + throw new BadRequestException("Page size must not be greater than " + AppConstants.MAX_PAGE_SIZE); + } + } - if (size > AppConstants.MAX_PAGE_SIZE) { - throw new BadRequestException("Page size must not be greater than " + AppConstants.MAX_PAGE_SIZE); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/TagServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/TagServiceImpl.java index 18488a23..7ae1cc3e 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/TagServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/TagServiceImpl.java @@ -24,58 +24,59 @@ @Service public class TagServiceImpl implements TagService { - @Autowired - private TagRepository tagRepository; - - @Override - public PagedResponse getAllTags(int page, int size) { - AppUtils.validatePageNumberAndSize(page, size); - - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt"); - - Page tags = tagRepository.findAll(pageable); - - List content = tags.getNumberOfElements() == 0 ? Collections.emptyList() : tags.getContent(); - - return new PagedResponse<>(content, tags.getNumber(), tags.getSize(), tags.getTotalElements(), tags.getTotalPages(), tags.isLast()); - } - - @Override - public Tag getTag(Long id) { - return tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Tag", "id", id)); - } - - @Override - public Tag addTag(Tag tag, UserPrincipal currentUser) { - return tagRepository.save(tag); - } - - @Override - public Tag updateTag(Long id, Tag newTag, UserPrincipal currentUser) { - Tag tag = tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Tag", "id", id)); - if (tag.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - tag.setName(newTag.getName()); - return tagRepository.save(tag); - } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to edit this tag"); - - throw new UnauthorizedException(apiResponse); - } - - @Override - public ApiResponse deleteTag(Long id, UserPrincipal currentUser) { - Tag tag = tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Tag", "id", id)); - if (tag.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - tagRepository.deleteById(id); - return new ApiResponse(Boolean.TRUE, "You successfully deleted tag"); - } - - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete this tag"); - - throw new UnauthorizedException(apiResponse); - } + @Autowired + private TagRepository tagRepository; + + @Override + public PagedResponse getAllTags(int page, int size) { + AppUtils.validatePageNumberAndSize(page, size); + + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, "createdAt"); + + Page tags = tagRepository.findAll(pageable); + + List content = tags.getNumberOfElements() == 0 ? Collections.emptyList() : tags.getContent(); + + return new PagedResponse<>(content, tags.getNumber(), tags.getSize(), tags.getTotalElements(), tags.getTotalPages(), tags.isLast()); + } + + @Override + public Tag getTag(Long id) { + return tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Tag", "id", id)); + } + + @Override + public Tag addTag(Tag tag, UserPrincipal currentUser) { + return tagRepository.save(tag); + } + + @Override + public Tag updateTag(Long id, Tag newTag, UserPrincipal currentUser) { + Tag tag = tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Tag", "id", id)); + if (tag.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + tag.setName(newTag.getName()); + return tagRepository.save(tag); + } + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to edit this tag"); + + throw new UnauthorizedException(apiResponse); + } + + @Override + public ApiResponse deleteTag(Long id, UserPrincipal currentUser) { + Tag tag = tagRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("Tag", "id", id)); + if (tag.getCreatedBy().equals(currentUser.getId()) || currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + tagRepository.deleteById(id); + return new ApiResponse(Boolean.TRUE, "You successfully deleted tag"); + } + + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete this tag"); + + throw new UnauthorizedException(apiResponse); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/TodoServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/TodoServiceImpl.java index 9ef3b2e8..38918279 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/TodoServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/TodoServiceImpl.java @@ -3,11 +3,11 @@ import com.sopromadze.blogapi.exception.BadRequestException; import com.sopromadze.blogapi.exception.ResourceNotFoundException; import com.sopromadze.blogapi.exception.UnauthorizedException; -import com.sopromadze.blogapi.model.Todo; -import com.sopromadze.blogapi.model.user.User; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.entity.TodoEntity; +import com.sopromadze.blogapi.infrastructure.persistence.postgresql.repository.TodoRepository; +import com.sopromadze.blogapi.model.user.UserEntity; import com.sopromadze.blogapi.payload.ApiResponse; import com.sopromadze.blogapi.payload.PagedResponse; -import com.sopromadze.blogapi.repository.TodoRepository; import com.sopromadze.blogapi.repository.UserRepository; import com.sopromadze.blogapi.security.UserPrincipal; import com.sopromadze.blogapi.service.TodoService; @@ -22,125 +22,123 @@ import java.util.Collections; import java.util.List; -import static com.sopromadze.blogapi.utils.AppConstants.CREATED_AT; -import static com.sopromadze.blogapi.utils.AppConstants.ID; -import static com.sopromadze.blogapi.utils.AppConstants.TODO; -import static com.sopromadze.blogapi.utils.AppConstants.YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION; +import static com.sopromadze.blogapi.utils.AppConstants.*; @Service public class TodoServiceImpl implements TodoService { - @Autowired - private TodoRepository todoRepository; + @Autowired + private TodoRepository todoRepository; - @Autowired - private UserRepository userRepository; + @Autowired + private UserRepository userRepository; - @Override - public Todo completeTodo(Long id, UserPrincipal currentUser) { - Todo todo = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); + @Override + public TodoEntity completeTodo(Long id, UserPrincipal currentUser) { + TodoEntity todoEntity = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); - User user = userRepository.getUser(currentUser); + UserEntity userEntity = userRepository.getUser(currentUser); - if (todo.getUser().getId().equals(user.getId())) { - todo.setCompleted(Boolean.TRUE); - return todoRepository.save(todo); - } + if (todoEntity.getUser().getId().equals(userEntity.getId())) { + todoEntity.setCompleted(Boolean.TRUE); + return todoRepository.save(todoEntity); + } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - throw new UnauthorizedException(apiResponse); - } + throw new UnauthorizedException(apiResponse); + } - @Override - public Todo unCompleteTodo(Long id, UserPrincipal currentUser) { - Todo todo = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); - User user = userRepository.getUser(currentUser); - if (todo.getUser().getId().equals(user.getId())) { - todo.setCompleted(Boolean.FALSE); - return todoRepository.save(todo); - } + @Override + public TodoEntity unCompleteTodo(Long id, UserPrincipal currentUser) { + TodoEntity todoEntity = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); + UserEntity userEntity = userRepository.getUser(currentUser); + if (todoEntity.getUser().getId().equals(userEntity.getId())) { + todoEntity.setCompleted(Boolean.FALSE); + return todoRepository.save(todoEntity); + } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - throw new UnauthorizedException(apiResponse); - } + throw new UnauthorizedException(apiResponse); + } - @Override - public PagedResponse getAllTodos(UserPrincipal currentUser, int page, int size) { - validatePageNumberAndSize(page, size); - Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); + @Override + public PagedResponse getAllTodos(UserPrincipal currentUser, int page, int size) { + validatePageNumberAndSize(page, size); + Pageable pageable = PageRequest.of(page, size, Sort.Direction.DESC, CREATED_AT); - Page todos = todoRepository.findByCreatedBy(currentUser.getId(), pageable); + Page todos = todoRepository.findByCreatedBy(currentUser.getId(), pageable); - List content = todos.getNumberOfElements() == 0 ? Collections.emptyList() : todos.getContent(); + List content = todos.getNumberOfElements() == 0 ? Collections.emptyList() : todos.getContent(); - return new PagedResponse<>(content, todos.getNumber(), todos.getSize(), todos.getTotalElements(), - todos.getTotalPages(), todos.isLast()); - } + return new PagedResponse<>(content, todos.getNumber(), todos.getSize(), todos.getTotalElements(), + todos.getTotalPages(), todos.isLast()); + } - @Override - public Todo addTodo(Todo todo, UserPrincipal currentUser) { - User user = userRepository.getUser(currentUser); - todo.setUser(user); - return todoRepository.save(todo); - } + @Override + public TodoEntity addTodo(TodoEntity todoEntity, String username) { + userRepository.findByUsername(username) + .ifPresent(todoEntity::setUser); + return todoRepository.save(todoEntity); + } - @Override - public Todo getTodo(Long id, UserPrincipal currentUser) { - User user = userRepository.getUser(currentUser); - Todo todo = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); + @Override + public TodoEntity getTodo(Long id, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.getUser(currentUser); + TodoEntity todoEntity = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); - if (todo.getUser().getId().equals(user.getId())) { - return todo; - } + if (todoEntity.getUser().getId().equals(userEntity.getId())) { + return todoEntity; + } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - throw new UnauthorizedException(apiResponse); - } + throw new UnauthorizedException(apiResponse); + } - @Override - public Todo updateTodo(Long id, Todo newTodo, UserPrincipal currentUser) { - User user = userRepository.getUser(currentUser); - Todo todo = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); - if (todo.getUser().getId().equals(user.getId())) { - todo.setTitle(newTodo.getTitle()); - todo.setCompleted(newTodo.getCompleted()); - return todoRepository.save(todo); - } + @Override + public TodoEntity updateTodo(Long id, TodoEntity newTodoEntity, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.getUser(currentUser); + TodoEntity todoEntity = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); + if (todoEntity.getUser().getId().equals(userEntity.getId())) { + todoEntity.setTitle(newTodoEntity.getTitle()); + todoEntity.setCompleted(newTodoEntity.isCompleted()); + return todoRepository.save(todoEntity); + } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - throw new UnauthorizedException(apiResponse); - } + throw new UnauthorizedException(apiResponse); + } - @Override - public ApiResponse deleteTodo(Long id, UserPrincipal currentUser) { - User user = userRepository.getUser(currentUser); - Todo todo = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); + @Override + public ApiResponse deleteTodo(Long id, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.getUser(currentUser); + TodoEntity todoEntity = todoRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(TODO, ID, id)); - if (todo.getUser().getId().equals(user.getId())) { - todoRepository.deleteById(id); - return new ApiResponse(Boolean.TRUE, "You successfully deleted todo"); - } + if (todoEntity.getUser().getId().equals(userEntity.getId())) { + todoRepository.deleteById(id); + return new ApiResponse(Boolean.TRUE, "You successfully deleted todo"); + } - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION); - throw new UnauthorizedException(apiResponse); - } + throw new UnauthorizedException(apiResponse); + } - private void validatePageNumberAndSize(int page, int size) { - if (page < 0) { - throw new BadRequestException("Page number cannot be less than zero."); - } + private void validatePageNumberAndSize(int page, int size) { + if (page < 0) { + throw new BadRequestException("Page number cannot be less than zero."); + } - if (size < 0) { - throw new BadRequestException("Size number cannot be less than zero."); - } + if (size < 0) { + throw new BadRequestException("Size number cannot be less than zero."); + } + + if (size > AppConstants.MAX_PAGE_SIZE) { + throw new BadRequestException("Page size must not be greater than " + AppConstants.MAX_PAGE_SIZE); + } + } - if (size > AppConstants.MAX_PAGE_SIZE) { - throw new BadRequestException("Page size must not be greater than " + AppConstants.MAX_PAGE_SIZE); - } - } } diff --git a/src/main/java/com/sopromadze/blogapi/service/impl/UserServiceImpl.java b/src/main/java/com/sopromadze/blogapi/service/impl/UserServiceImpl.java index d740f27b..3823ed8a 100644 --- a/src/main/java/com/sopromadze/blogapi/service/impl/UserServiceImpl.java +++ b/src/main/java/com/sopromadze/blogapi/service/impl/UserServiceImpl.java @@ -1,21 +1,13 @@ package com.sopromadze.blogapi.service.impl; -import com.sopromadze.blogapi.exception.AccessDeniedException; -import com.sopromadze.blogapi.exception.AppException; -import com.sopromadze.blogapi.exception.BadRequestException; -import com.sopromadze.blogapi.exception.ResourceNotFoundException; -import com.sopromadze.blogapi.exception.UnauthorizedException; +import com.sopromadze.blogapi.exception.*; import com.sopromadze.blogapi.model.role.Role; import com.sopromadze.blogapi.model.role.RoleName; import com.sopromadze.blogapi.model.user.Address; import com.sopromadze.blogapi.model.user.Company; import com.sopromadze.blogapi.model.user.Geo; -import com.sopromadze.blogapi.model.user.User; -import com.sopromadze.blogapi.payload.ApiResponse; -import com.sopromadze.blogapi.payload.InfoRequest; -import com.sopromadze.blogapi.payload.UserIdentityAvailability; -import com.sopromadze.blogapi.payload.UserProfile; -import com.sopromadze.blogapi.payload.UserSummary; +import com.sopromadze.blogapi.model.user.UserEntity; +import com.sopromadze.blogapi.payload.*; import com.sopromadze.blogapi.repository.PostRepository; import com.sopromadze.blogapi.repository.RoleRepository; import com.sopromadze.blogapi.repository.UserRepository; @@ -32,154 +24,167 @@ @Service public class UserServiceImpl implements UserService { - @Autowired - private UserRepository userRepository; - - @Autowired - private PostRepository postRepository; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Override - public UserSummary getCurrentUser(UserPrincipal currentUser) { - return new UserSummary(currentUser.getId(), currentUser.getUsername(), currentUser.getFirstName(), - currentUser.getLastName()); - } - - @Override - public UserIdentityAvailability checkUsernameAvailability(String username) { - Boolean isAvailable = !userRepository.existsByUsername(username); - return new UserIdentityAvailability(isAvailable); - } - - @Override - public UserIdentityAvailability checkEmailAvailability(String email) { - Boolean isAvailable = !userRepository.existsByEmail(email); - return new UserIdentityAvailability(isAvailable); - } - - @Override - public UserProfile getUserProfile(String username) { - User user = userRepository.getUserByName(username); - - Long postCount = postRepository.countByCreatedBy(user.getId()); - - return new UserProfile(user.getId(), user.getUsername(), user.getFirstName(), user.getLastName(), - user.getCreatedAt(), user.getEmail(), user.getAddress(), user.getPhone(), user.getWebsite(), - user.getCompany(), postCount); - } - - @Override - public User addUser(User user) { - if (userRepository.existsByUsername(user.getUsername())) { - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "Username is already taken"); - throw new BadRequestException(apiResponse); - } - - if (userRepository.existsByEmail(user.getEmail())) { - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "Email is already taken"); - throw new BadRequestException(apiResponse); - } - - List roles = new ArrayList<>(); - roles.add( - roleRepository.findByName(RoleName.ROLE_USER).orElseThrow(() -> new AppException("User role not set"))); - user.setRoles(roles); - - user.setPassword(passwordEncoder.encode(user.getPassword())); - return userRepository.save(user); - } - - @Override - public User updateUser(User newUser, String username, UserPrincipal currentUser) { - User user = userRepository.getUserByName(username); - if (user.getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - user.setFirstName(newUser.getFirstName()); - user.setLastName(newUser.getLastName()); - user.setPassword(passwordEncoder.encode(newUser.getPassword())); - user.setAddress(newUser.getAddress()); - user.setPhone(newUser.getPhone()); - user.setWebsite(newUser.getWebsite()); - user.setCompany(newUser.getCompany()); - - return userRepository.save(user); - - } - - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to update profile of: " + username); - throw new UnauthorizedException(apiResponse); - - } - - @Override - public ApiResponse deleteUser(String username, UserPrincipal currentUser) { - User user = userRepository.findByUsername(username) - .orElseThrow(() -> new ResourceNotFoundException("User", "id", username)); - if (!user.getId().equals(currentUser.getId()) || !currentUser.getAuthorities() - .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete profile of: " + username); - throw new AccessDeniedException(apiResponse); - } - - userRepository.deleteById(user.getId()); - - return new ApiResponse(Boolean.TRUE, "You successfully deleted profile of: " + username); - } - - @Override - public ApiResponse giveAdmin(String username) { - User user = userRepository.getUserByName(username); - List roles = new ArrayList<>(); - roles.add(roleRepository.findByName(RoleName.ROLE_ADMIN) - .orElseThrow(() -> new AppException("User role not set"))); - roles.add( - roleRepository.findByName(RoleName.ROLE_USER).orElseThrow(() -> new AppException("User role not set"))); - user.setRoles(roles); - userRepository.save(user); - return new ApiResponse(Boolean.TRUE, "You gave ADMIN role to user: " + username); - } - - @Override - public ApiResponse removeAdmin(String username) { - User user = userRepository.getUserByName(username); - List roles = new ArrayList<>(); - roles.add( - roleRepository.findByName(RoleName.ROLE_USER).orElseThrow(() -> new AppException("User role not set"))); - user.setRoles(roles); - userRepository.save(user); - return new ApiResponse(Boolean.TRUE, "You took ADMIN role from user: " + username); - } - - @Override - public UserProfile setOrUpdateInfo(UserPrincipal currentUser, InfoRequest infoRequest) { - User user = userRepository.findByUsername(currentUser.getUsername()) - .orElseThrow(() -> new ResourceNotFoundException("User", "username", currentUser.getUsername())); - Geo geo = new Geo(infoRequest.getLat(), infoRequest.getLng()); - Address address = new Address(infoRequest.getStreet(), infoRequest.getSuite(), infoRequest.getCity(), - infoRequest.getZipcode(), geo); - Company company = new Company(infoRequest.getCompanyName(), infoRequest.getCatchPhrase(), infoRequest.getBs()); - if (user.getId().equals(currentUser.getId()) - || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { - user.setAddress(address); - user.setCompany(company); - user.setWebsite(infoRequest.getWebsite()); - user.setPhone(infoRequest.getPhone()); - User updatedUser = userRepository.save(user); - - Long postCount = postRepository.countByCreatedBy(updatedUser.getId()); - - return new UserProfile(updatedUser.getId(), updatedUser.getUsername(), - updatedUser.getFirstName(), updatedUser.getLastName(), updatedUser.getCreatedAt(), - updatedUser.getEmail(), updatedUser.getAddress(), updatedUser.getPhone(), updatedUser.getWebsite(), - updatedUser.getCompany(), postCount); - } - - ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to update users profile", HttpStatus.FORBIDDEN); - throw new AccessDeniedException(apiResponse); - } + + @Autowired + private UserRepository userRepository; + + @Autowired + private PostRepository postRepository; + + @Autowired + private RoleRepository roleRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Override + public UserSummary getCurrentUser(UserPrincipal currentUser) { + return new UserSummary(currentUser.getId(), currentUser.getUsername(), currentUser.getFirstName(), + currentUser.getLastName()); + } + + @Override + public UserIdentityAvailability checkUsernameAvailability(String username) { + Boolean isAvailable = !userRepository.existsByUsername(username); + return new UserIdentityAvailability(isAvailable); + } + + @Override + public UserIdentityAvailability checkEmailAvailability(String email) { + Boolean isAvailable = !userRepository.existsByEmail(email); + return new UserIdentityAvailability(isAvailable); + } + + @Override + public UserProfile getUserProfile(String username) { + UserEntity userEntity = userRepository.getUserByName(username); + + Long postCount = postRepository.countByCreatedBy(userEntity.getId()); + + return new UserProfile(userEntity.getId(), userEntity.getUsername(), userEntity.getFirstName(), userEntity.getLastName(), + userEntity.getCreatedAt(), userEntity.getEmail(), userEntity.getAddress(), userEntity.getPhone(), userEntity.getWebsite(), + userEntity.getCompany(), postCount); + } + + @Override + public UserEntity addUser(UserEntity userEntity) { + if (userRepository.existsByUsername(userEntity.getUsername())) { + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "Username is already taken"); + throw new BadRequestException(apiResponse); + } + + if (userRepository.existsByEmail(userEntity.getEmail())) { + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "Email is already taken"); + throw new BadRequestException(apiResponse); + } + + List roles = new ArrayList<>(); + roles.add(roleRepository.findByName(RoleName.ROLE_USER).orElseThrow(() -> new AppException("User role not set"))); + userEntity.setRoles(roles); + + userEntity.setPassword(passwordEncoder.encode(userEntity.getPassword())); + return userRepository.save(userEntity); + } + + @Override + public UserEntity updateUser(UserEntity newUserEntity, String username, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.getUserByName(username); + if (userEntity.getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + userEntity.setFirstName(newUserEntity.getFirstName()); + userEntity.setLastName(newUserEntity.getLastName()); + userEntity.setPassword(passwordEncoder.encode(newUserEntity.getPassword())); + userEntity.setAddress(newUserEntity.getAddress()); + userEntity.setPhone(newUserEntity.getPhone()); + userEntity.setWebsite(newUserEntity.getWebsite()); + userEntity.setCompany(newUserEntity.getCompany()); + + return userRepository.save(userEntity); + + } + + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to update profile of: " + username); + throw new UnauthorizedException(apiResponse); + + } + + @Override + public ApiResponse deleteUser(String username, UserPrincipal currentUser) { + UserEntity userEntity = userRepository.findByUsername(username) + .orElseThrow(() -> new ResourceNotFoundException("User", "id", username)); + if (!userEntity.getId().equals(currentUser.getId()) || !currentUser.getAuthorities() + .contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to delete profile of: " + username); + throw new AccessDeniedException(apiResponse); + } + + userRepository.deleteById(userEntity.getId()); + + return new ApiResponse(Boolean.TRUE, "You successfully deleted profile of: " + username); + } + + @Override + public ApiResponse giveAdmin(String username) { + UserEntity userEntity = userRepository.getUserByName(username); + List roles = new ArrayList<>(); + roles.add(roleRepository.findByName(RoleName.ROLE_ADMIN) + .orElseThrow(() -> new AppException("User role not set"))); + roles.add( + roleRepository.findByName(RoleName.ROLE_USER).orElseThrow(() -> new AppException("User role not set"))); + userEntity.setRoles(roles); + userRepository.save(userEntity); + return new ApiResponse(Boolean.TRUE, "You gave ADMIN role to user: " + username); + } + + @Override + public ApiResponse removeAdmin(String username) { + UserEntity userEntity = userRepository.getUserByName(username); + List roles = new ArrayList<>(); + roles.add( + roleRepository.findByName(RoleName.ROLE_USER).orElseThrow(() -> new AppException("User role not set"))); + userEntity.setRoles(roles); + userRepository.save(userEntity); + return new ApiResponse(Boolean.TRUE, "You took ADMIN role from user: " + username); + } + + @Override + public UserProfile setOrUpdateInfo(UserPrincipal currentUser, InfoRequest infoRequest) { + UserEntity userEntity = userRepository.findByUsername(currentUser.getUsername()) + .orElseThrow(() -> new ResourceNotFoundException("User", "username", currentUser.getUsername())); + Geo geo = Geo.builder() + .lat(infoRequest.getLat()) + .lng(infoRequest.getLng()) + .build(); + Address address = Address.builder() + .street(infoRequest.getStreet()) + .suite(infoRequest.getSuite()) + .city(infoRequest.getCity()) + .zipcode(infoRequest.getZipcode()) + .geo(geo) + .build(); + Company company = Company.builder() + .name(infoRequest.getCompanyName()) + .catchPhrase(infoRequest.getCatchPhrase()) + .bs(infoRequest.getBs()) + .build(); + if (userEntity.getId().equals(currentUser.getId()) + || currentUser.getAuthorities().contains(new SimpleGrantedAuthority(RoleName.ROLE_ADMIN.toString()))) { + userEntity.setAddress(address); + userEntity.setCompany(company); + userEntity.setWebsite(infoRequest.getWebsite()); + userEntity.setPhone(infoRequest.getPhone()); + UserEntity updatedUserEntity = userRepository.save(userEntity); + + Long postCount = postRepository.countByCreatedBy(updatedUserEntity.getId()); + + return new UserProfile(updatedUserEntity.getId(), updatedUserEntity.getUsername(), + updatedUserEntity.getFirstName(), updatedUserEntity.getLastName(), updatedUserEntity.getCreatedAt(), + updatedUserEntity.getEmail(), updatedUserEntity.getAddress(), updatedUserEntity.getPhone(), updatedUserEntity.getWebsite(), + updatedUserEntity.getCompany(), postCount); + } + + ApiResponse apiResponse = new ApiResponse(Boolean.FALSE, "You don't have permission to update users profile", HttpStatus.FORBIDDEN); + throw new AccessDeniedException(apiResponse); + } + } diff --git a/src/main/java/com/sopromadze/blogapi/utils/AppConstants.java b/src/main/java/com/sopromadze/blogapi/utils/AppConstants.java index 19df8f75..30544f36 100644 --- a/src/main/java/com/sopromadze/blogapi/utils/AppConstants.java +++ b/src/main/java/com/sopromadze/blogapi/utils/AppConstants.java @@ -1,31 +1,33 @@ package com.sopromadze.blogapi.utils; public class AppConstants { - public static final String DEFAULT_PAGE_NUMBER = "0"; - public static final String DEFAULT_PAGE_SIZE = "30"; + public static final String DEFAULT_PAGE_NUMBER = "0"; - public static final int MAX_PAGE_SIZE = 30; + public static final String DEFAULT_PAGE_SIZE = "30"; - public static final String CREATED_AT = "createdAt"; + public static final int MAX_PAGE_SIZE = 30; - public static final String ID = "id"; + public static final String CREATED_AT = "createdAt"; - public static final String PHOTO = "Photo"; + public static final String ID = "id"; - public static final String ALBUM = "Album"; + public static final String PHOTO = "Photo"; - public static final String USERNAME = "username"; + public static final String ALBUM = "Album"; - public static final String USER = "User"; + public static final String USERNAME = "username"; - public static final String CATEGORY = "Category"; + public static final String USER = "User"; - public static final String TAG = "Tag"; + public static final String CATEGORY = "Category"; - public static final String POST = "Post"; + public static final String TAG = "Tag"; - public static final String TODO = "ToDo"; + public static final String POST = "Post"; + + public static final String TODO = "ToDo"; + + public static final String YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION = "You don't have permission to make this operation"; - public static final String YOU_DON_T_HAVE_PERMISSION_TO_MAKE_THIS_OPERATION = "You don't have permission to make this operation"; } diff --git a/src/main/java/com/sopromadze/blogapi/utils/AppUtils.java b/src/main/java/com/sopromadze/blogapi/utils/AppUtils.java index fccdf832..90502bba 100644 --- a/src/main/java/com/sopromadze/blogapi/utils/AppUtils.java +++ b/src/main/java/com/sopromadze/blogapi/utils/AppUtils.java @@ -4,17 +4,19 @@ import org.springframework.http.HttpStatus; public class AppUtils { - public static void validatePageNumberAndSize(int page, int size) { - if (page < 0) { - throw new BlogapiException(HttpStatus.BAD_REQUEST, "Page number cannot be less than zero."); - } - if (size < 0) { - throw new BlogapiException(HttpStatus.BAD_REQUEST, "Size number cannot be less than zero."); - } + public static void validatePageNumberAndSize(int page, int size) { + if (page < 0) { + throw new BlogapiException(HttpStatus.BAD_REQUEST, "Page number cannot be less than zero."); + } + + if (size < 0) { + throw new BlogapiException(HttpStatus.BAD_REQUEST, "Size number cannot be less than zero."); + } + + if (size > AppConstants.MAX_PAGE_SIZE) { + throw new BlogapiException(HttpStatus.BAD_REQUEST, "Page size must not be greater than " + AppConstants.MAX_PAGE_SIZE); + } + } - if (size > AppConstants.MAX_PAGE_SIZE) { - throw new BlogapiException(HttpStatus.BAD_REQUEST, "Page size must not be greater than " + AppConstants.MAX_PAGE_SIZE); - } - } } diff --git a/src/main/resources/_application.properties b/src/main/resources/_application.properties deleted file mode 100644 index d7d7b14c..00000000 --- a/src/main/resources/_application.properties +++ /dev/null @@ -1,12 +0,0 @@ -spring.jpa.hibernate.ddl-auto=none -spring.datasource.url=jdbc:mysql://localhost:3306/blogapi?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true -spring.datasource.username=root -spring.datasource.password=root -spring.jpa.show-sql=true -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect -app.jwtSecret=secret -# Expiration in milliseconds - 1 Hour -app.jwtExpirationInMs=3600000 -spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false -spring.jackson.time-zone=UTC -cors.allowedOrings=* diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ef6d7e3d..582dd2ad 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,15 +1,19 @@ +logging: + level: + root: DEBUG + spring: datasource: - url: jdbc:mysql://blogapi-db:3306/blogapi?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true - username: root - password: root + url: jdbc:postgresql://localhost:5432/blogapi + username: blogapi_user + password: blogapi_pass jpa: hibernate: ddl-auto: none show-sql: true properties: hibernate: - dialect: org.hibernate.dialect.MySQL5Dialect + dialect: org.hibernate.dialect.PostgreSQLDialect jackson: serialization: WRITE_DATES_AS_TIMESTAMPS: false @@ -19,5 +23,10 @@ app: jwtSecret: secret jwtExpirationInMs: 3600000 +security: + jwt: + secret-key: 3cfa76ef14937c1c0ea519f8fc057a80fcd04a7420f8e8bcd0a7567c272e007b + expiration-time: 3600000 + cors: allowedOrings: '*' diff --git a/src/main/resources/blogapi.sql b/src/main/resources/blogapi.sql deleted file mode 100644 index 3a85baec..00000000 --- a/src/main/resources/blogapi.sql +++ /dev/null @@ -1,190 +0,0 @@ -UNLOCK TABLES; - -DROP TABLE IF EXISTS `post_tag`; -DROP TABLE IF EXISTS `tags`; -DROP TABLE IF EXISTS `user_role`; -DROP TABLE IF EXISTS `roles`; -DROP TABLE IF EXISTS `comments`; -DROP TABLE IF EXISTS `posts`; -DROP TABLE IF EXISTS `photos`; -DROP TABLE IF EXISTS `albums`; -DROP TABLE IF EXISTS `todos`; -DROP TABLE IF EXISTS `users`; -DROP TABLE IF EXISTS `address`; -DROP TABLE IF EXISTS `company`; -DROP TABLE IF EXISTS `geo`; - -CREATE TABLE `tags` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned NOT NULL, - `updated_by` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `geo` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `lat` varchar(255), - `lng` varchar(255), - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `company` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255), - `catch_phrase` varchar(255), - `bs` varchar(255), - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `address` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `street` varchar(255), - `suite` varchar(255), - `city` varchar(255), - `zipcode` varchar(255), - `geo_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_geo` (`geo_id`), - CONSTRAINT `fk_geo` FOREIGN KEY (`geo_id`) REFERENCES `geo` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `users` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `first_name` varchar(255) NOT NULL, - `last_name` varchar(255) NOT NULL, - `username` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `email` varchar(255) NOT NULL, - `address_id` bigint(19) unsigned DEFAULT NULL, - `phone` varchar(255), - `website` varchar(255), - `company_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - KEY `fk_address` (`address_id`), - KEY `fk_company` (`company_id`), - CONSTRAINT `fk_address` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `fk_company` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `todos` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `completed` boolean default false, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_user_todos` (`user_id`), - CONSTRAINT `fk_user_todos` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `albums` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_user_album` (`user_id`), - CONSTRAINT `fk_user_album` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `photos` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `url` varchar(255) NOT NULL, - `thumbnail_url` varchar(255) NOT NULL, - `album_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_album` (`album_id`), - CONSTRAINT `fk_album` FOREIGN KEY (`album_id`) REFERENCES `albums` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `posts` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `title` varchar(255) NOT NULL, - `body` text NOT NULL, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned DEFAULT NULL, - `updated_by` bigint(19) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `fk_user_post` (`user_id`), - CONSTRAINT `fk_user_post` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `post_tag` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `post_id` bigint(19) unsigned NOT NULL, - `tag_id` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `fk_posttag_post_id` (`post_id`), - KEY `fk_posttag_tag_id` (`tag_id`), - CONSTRAINT `fk_posttag_post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`), - CONSTRAINT `fk_posttag_tag_id` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `comments` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - `email` varchar(255) NOT NULL, - `body` text NOT NULL, - `post_id` bigint(19) unsigned DEFAULT NULL, - `user_id` bigint(19) unsigned DEFAULT NULL, - `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `created_by` bigint(19) unsigned NOT NULL, - `updated_by` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `fk_comment_post` (`post_id`), - KEY `fk_comment_user` (`user_id`), - CONSTRAINT `fk_comment_post` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`), - CONSTRAINT `fk_comment_user` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `roles` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -CREATE TABLE `user_role` ( - `id` bigint(19) unsigned NOT NULL AUTO_INCREMENT, - `user_id` bigint(19) unsigned NOT NULL, - `role_id` bigint(19) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `fk_security_user_id` (`user_id`), - KEY `fk_security_role_id` (`role_id`), - CONSTRAINT `fk_security_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), - CONSTRAINT `fk_security_role_id` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; - -LOCK TABLES `roles` WRITE; -INSERT INTO `roles` VALUES (1,'ROLE_ADMIN'),(2,'ROLE_USER'); -UNLOCK TABLES; diff --git a/src/test/java/com/sopromadze/blogapi/BlogApiApplicationTests.java b/src/test/java/com/sopromadze/blogapi/BlogApiApplicationTests.java deleted file mode 100644 index b1247c5c..00000000 --- a/src/test/java/com/sopromadze/blogapi/BlogApiApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.sopromadze.blogapi; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest(classes = BlogApiApplication.class) -public class BlogApiApplicationTests { - - @Test - public void contextLoads() { - } - -}