diff options
64 files changed, 2606 insertions, 2458 deletions
@@ -354,4 +354,5 @@ MigrationBackup/ *.blob appsettings.Development.json **/.vscode/ -**/*.swp
\ No newline at end of file +**/*.swp +**/Logs diff --git a/docs/API-Endpoints.md b/docs/API-Endpoints.md new file mode 100644 index 0000000..503bfc4 --- /dev/null +++ b/docs/API-Endpoints.md @@ -0,0 +1,864 @@ +### Contents: +- [/api/User](#apiuser) + - [/Login](#login) + - [/Register](#register) + - [/GetUser](#getuser) + - [/ProfilePicture](#profilepicture) + - [Get User By Id](#get-user-by-id) + - [Update User By Id](#update-user-by-id) + - [Delete User By Id](#delete-user-by-id) +- [/api/Role](#apirole) + - [Create Role](#create-role) + - [Get Role By Id](#get-role-by-id) + - [Update Role By Id](#update-role-by-id) + - [Delete Role By Id](#delete-role-by-id) +- [/api/Feed](#apifeed) + - [/GetPosts](#getposts) + - [/GetUserPosts](#getuserposts) +- [/api/Post](#apipost) + - [Create Post](#create-post) + - [Get Post By Id](#get-post-by-id) + - [Update Post By Id](#update-post-by-id) + - [Delete Post By Id](#delete-post-by-id) +- [/api/Comment](#apicomment) + - [Create Comment](#create-comment) + - [Get Comment By Id](#get-comment-by-id) + - [Update Comment By Id](#update-comment-by-id) + - [Delete Comment By Id](#delete-comment-by-id) +- [/api/Language](#apilanguage) + - [/GetLanguages](#getlanguages) + - [Create Language](#create-language) + - [Get Language By Id](#get-language-by-id) + - [Update Language By Id](#update-language-by-id) + - [Delete Language By Id](#delete-language-by-id) +- [/api/Technology](#apitechnology) + - [/GetTechnologies](#gettechnologies) + - [Create Technology](#create-technology) + - [Get Technology By Id](#get-technology-by-id) + - [Update Technology By Id](#update-technology-by-id) + - [Delete Technology By Id](#delete-technology-by-id) + +*** + +# /api/User + +## /Login + +||| +|---|---| +|Description|Get a JWT for an existing user| +|Type|POST| +|URL structure|`http://localhost:5000/api/User/login`| +|Authentication|None| +|Body|JSON| +|Returns|JSON; The JWT| +||| + +Sample body: +```json +{ + "userName": "string", + "password": "string" +} +``` +Sample response: +```json +{ + "token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjFiMTU2ZTY3LTVhZmItNGZmMi1hYzRmLTY4NjVmZWI5NzFiYiIsIlVzZXJuYW1lIjoieW9yZ3VzIiwicm9sZSI6IlVzZXIiLCJuYmYiOjE2MTIzMzg5NzIsImV4cCI6MTYxMjkwODAwMCwiaWF0IjoxNjEyMzM4OTcyfQ.dneQidggMu9FD7UXBzn5td3phX3OIgp7y4BygHTqq5Un5D67xH1jZTRQpi9Zqcq76mODvUToAo7j4PFdJtIdtg" +} +``` + +## /Register + +||| +|---|---| +|Description|Add an account to the database and get a JWT| +|Type|POST| +|URL structure|`http://localhost:5000/api/User/register`| +|Authentication|None| +|Body|JSON| +|Returns|JSON; The JWT| + +Sample body: +```json +{ + "userName": "string", + "email": "user@example.com", + "firstName": "string", + "lastName": "string", + "password": "string" +} +``` +Sample response: +```json +{ + "token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjFiMTU2ZTY3LTVhZmItNGZmMi1hYzRmLTY4NjVmZWI5NzFiYiIsIlVzZXJuYW1lIjoieW9yZ3VzIiwicm9sZSI6IlVzZXIiLCJuYmYiOjE2MTIzMzg5NzIsImV4cCI6MTYxMjkwODAwMCwiaWF0IjoxNjEyMzM4OTcyfQ.dneQidggMu9FD7UXBzn5td3phX3OIgp7y4BygHTqq5Un5D67xH1jZTRQpi9Zqcq76mODvUToAo7j4PFdJtIdtg" +} +``` + +## /GetUser + +||| +|---|---| +|Description|Get a user via his UserName| +|Type|GET| +|URL structure|`http://localhost:5000/api/User/GetUser?UserName=test`| +|Authentication|None| +|Body|None| +|Returns|JSON; The object of the user| +||| + +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4", + "roles": [ + { + "name": "User" + } + ], + "friends": [ + ], + "languages": [ + { + "id": "cf40034d-75d7-4792-821d-c16220a5b928" + } + ], + "technologies": [ + { + "id": "907421d9-1b60-411b-b780-85e65a004b56" + } + ], + "posts": [ + { + "id": "850d0655-72cb-4477-b69b-35e8645db266" + } + ], + "userName": "test", + "email": "test@bg.com", + "firstName": "Test", + "lastName": "Test" +} +``` + +## /ProfilePicture + +||| +|---|---| +|Description|Update the profile picture of the given User| +|Type|PUT| +|URL structure|`http://localhost:5000/api/User/ProfilePicture?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|Multipart Form| +|Returns|JSON; The link to the uploaded profile picture| +||| + +Sample body: +|Name|Value| +|---|---| +|Picture|`new-profile-picture.png` (this is the actual file)| + +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4" +} +``` + +## Get User By Id + +||| +|---|---| +|Description|Get a user via his Id| +|Type|GET| +|URL structure|`http://localhost:5000/api/User?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The object of the user| +||| + +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4", + "roles": [ + { + "name": "User" + } + ], + "friends": [ + ], + "languages": [ + { + "id": "cf40034d-75d7-4792-821d-c16220a5b928" + } + ], + "technologies": [ + { + "id": "907421d9-1b60-411b-b780-85e65a004b56" + } + ], + "posts": [ + { + "id": "850d0655-72cb-4477-b69b-35e8645db266" + } + ], + "userName": "test", + "email": "test@bg.com", + "firstName": "Test", + "lastName": "Test" +} +``` + +## Update User By Id + +||| +|---|---| +|Description|Modify the values in an existing user (account)| +|Type|PUT| +|URL structure|`http://localhost:5000/api/User?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The updated user object| +||| + +Sample body: +```json +{ + "userName": "string", + "email": "user@example.com", + "firstName": "string", + "lastName": "string", + "password": "string", + "friends": [ + { + "userName": "string" + } + ], + "roles": [ + { + "name": "string" + } + ], + "languages": [ + { + "name": "string" + } + ], + "technologies": [ + { + "name": "string" + } + ] +} +``` +Sample response: +```json +{ + "profilePictureURL": "https://avatars.githubusercontent.com/u/75525529?s=60&v=4", + "roles": [ + { + "name": "User" + } + ], + "friends": [], + "languages": [ + { + "id": "33397a3b-46eb-424f-8e19-d88dbf3e953b" + }, + { + "id": "cea85a74-4820-42ff-b64f-61d7e9bfc696" + } + ], + "technologies": [ + { + "id": "907421d9-1b60-411b-b780-85e65a004b56" + } + ], + "posts": [], + "userName": "test", + "email": "test1@bg.com", + "firstName": "Tester", + "lastName": "Tester" +} +``` + +## Delete User By Id + +||| +|---|---| +|Description|Delete an existing user from the database `WARNING: THIS IS IRREVERSIBLE`| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/User?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|Nothing| +||| + +*** + +# /api/Role + +## Create Role + +||| +|---|---| +|Description|Add a new Role to the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Role`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result role object, only with the role Id| +||| + +Sample body: +```json +{ + "name": "string" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Role By Id + +||| +|---|---| +|Description|Get an existing Role via it's Id| +|Type|GET| +|URL structure|`http://localhost:5000/api/Role?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The role object, only with it's name| +||| + +Sample response: +```json +{ + "name": "Test" +} +``` + +## Update Role By Id + +||| +|---|---| +|Description|Modify the values (name) of an existing role| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Role?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|Nothing| +||| + +Sample body: +```json +{ + "name": "string" +} +``` + +## Delete Role By Id + +||| +|---|---| +|Description|Remove an existing Role from the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Role?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|Nothing| +||| + +*** + +# /api/Feed + +## /GetPosts + +||| +|---|---| +|Description|Get a certain amount of the latest posts of a User's friends| +|Type|POST| +|URL structure|`http://localhost:5000/api/Feed/GetPosts?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; An array with the selected posts| +||| + +Sample body: +```json +{ + "pageNumber": 1, + "firstPageTimeIssued": "2022-01-30T18:43:01.082Z", + "pageSize": 5 +} +``` +Sample response: +```json +{ + "posts": [ + { + "postId": "850d0655-72cb-4477-b69b-35e8645db266", + "creatorFirstName": "test", + "creatorLastName": "Test", + "creatorUsername": "Test", + "message": "A sample post", + "timeCreated": "2021-02-03T10:52:38.271647", + "comments": [], + "fileUrls": [] + } + ] +} +``` + +## /GetUserPosts + +||| +|---|---| +|Description|Get a certain amount of the latest posts from a User| +|Type|POST| +|URL structure|`http://localhost:5000/api/GetUserPosts?UserName=test`| +|Authentication|None| +|Body|JSON| +|Returns|JSON; An array with the selected posts| +||| + +Sample body: +```json +{ + "pageNumber": 1, + "firstPageTimeIssued": "2022-01-30T18:43:01.082Z", + "pageSize": 5 +} +``` +Sample response: +```json +{ + "posts": [ + { + "postId": "850d0655-72cb-4477-b69b-35e8645db266", + "creatorFirstName": "test", + "creatorLastName": "Test", + "creatorUsername": "Test", + "message": "A sample post", + "timeCreated": "2021-02-03T10:52:38.271647", + "comments": [], + "fileUrls": [] + } + ] +} +``` + +*** + +# /api/Post + +## Create Post + +||| +|---|---| +|Description|Add a new Post to the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Post?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|Multipart Form| +|Returns|JSON; The result Post object, only with the Post Id| +||| + +Sample body: +|Name|Value| +|---|---| +|Message|The message of my post| +|Files|`attachment.txt` (that is the actual file)| +|Files|`attachment2.txt` (that is the actual file)| +|...|| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Post By Id + +||| +|---|---| +|Description|Get an existing Post from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Post?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Post object| +||| + +Sample response: +```json +{ + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "creatorFirstName": "Test", + "creatorLastName": "Test", + "creatorUsername": "test", + "message": "A sample post", + "timeCreated": "2021-02-02T18:29:31.942772", + "comments": [], + "fileUrls": [] +} +``` + +## Update Post By Id + +||| +|---|---| +|Description|Update the values of an existing post| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Post?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|Multipart Form| +|Returns|JSON; The result Post object, only with the Post Id| +||| + +**Note:** When editing a post's files, they all get replaced, you cannot just add new files. After post is edited, it's "timeCreated" get's updated. + +Sample body: +|Name|Value| +|---|---| +|PostId|1cc9773f-8d9a-4bfd-83ca-2099dc787a39| +|NewMessage|The new message of the post| +|Files|`attachment3.txt` (that is the actual file)| +|Files|`attachment4.txt` (that is the actual file)| +|...| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Delete Post By Id + +||| +|---|---| +|Description|Remove an existing Post from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Post?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| + +*** + +# /api/Comment + +## Add comment + +||| +|---|---| +|Description|Add a new Comment to an existing Post| +|Type|POST| +|URL structure|`http://localhost:5000/api/Comment?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Comment object, only with the Comment Id| +||| + +Sample body: +```json +{ + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "message": "First comment" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Comment By Id + +||| +|---|---| +|Description|Get an existing Comment from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Comment?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Comment object| +||| + +Sample response: +```json +{ + "commentId": "086d1a23-c977-4cdc-9bdf-dc81992b3a12", + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "issuerFirstName": "Test", + "issuerLastName": "Test", + "issuerUsername": "test", + "message": "First coment", + "timeCreated": "2021-02-01T13:18:57.434512" +} +``` + +## Update Comment By Id + +||| +|---|---| +|Description|Update the values of an existing comment| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Comment?UserId=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Comment object, only with the Comment Id| +||| + +Sample body: +```json +{ + "commentId": "086d1a23-c977-4cdc-9bdf-dc81992b3a12", + "postId": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "newMessage": "string" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Delete Comment By Id + +||| +|---|---| +|Description|Remove an existing Comment from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Comment?Id=086d1a23-c977-4cdc-9bdf-dc81992b3a12`| +|Authentication|Bearer Token (JWT), [Authorization Type 2](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| + +*** + +# /api/Language + +## /GetLanguages + +||| +|---|---| +|Description|Get all available Languages from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Language/GetLanguages`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The result Language array object| +||| + +Sample response: +```json +[ + { + "id": "5286821a-1407-4daf-ac3e-49153c2d3f66", + "name": "CSharp" + }, + { + "id": "cea85a74-4820-42ff-b64f-61d7e9bfc696", + "name": "Perl" + }, + { + "id": "6dc1cb1a-1c4f-41af-8b44-86441cb60136", + "name": "Java" + } +] +``` + +## Create Language + +||| +|---|---| +|Description|Add a new Language in the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Comment`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Comment object, only with the Comment Id| +||| + +Sample body: +```json +{ + "name": "Perl" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Language By Id + +||| +|---|---| +|Description|Get an existing Language from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Language?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Language object| +||| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "name": "Perl" +} +``` + +## Update Language By Id + +||| +|---|---| +|Description|Update the values of an existing Language| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Language?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|None| +||| + +Sample body: +```json +{ + "name": "string" +} +``` + +## Delete Language By Id + +||| +|---|---| +|Description|Remove an existing Language from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Language?Id=086d1a23-c977-4cdc-9bdf-dc81992b3a12`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +||| + +*** + +# /api/Technology + +## /GetTechnologies + +||| +|---|---| +|Description|Get all available Technologies from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Language/GetTechnologies`| +|Authentication|Bearer Token (JWT), [Authorization Type 1](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|JSON; The result Technology array object| +||| + +Sample response: +```json +[ + { + "id": "5286821a-1407-4daf-ac3e-49153c2d3f66", + "name": "ASP.NET" + }, + { + "id": "cea85a74-4820-42ff-b64f-61d7e9bfc696", + "name": "Angular" + } +] +``` + +## Create Technology + +||| +|---|---| +|Description|Add a new Technology in the DataBase| +|Type|POST| +|URL structure|`http://localhost:5000/api/Technology`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|JSON; The result Technology object, only with the Technology Id| +||| + +Sample body: +```json +{ + "name": "Angular" +} +``` +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39" +} +``` + +## Get Technology By Id + +||| +|---|---| +|Description|Get an existing Technology from the DataBase| +|Type|GET| +|URL structure|`http://localhost:5000/api/Technology?Id=1cc9773f-8d9a-4bfd-83ca-2099dc787a39`| +|Authentication|None| +|Body|None| +|Returns|JSON; The result Technology object| +||| + +Sample response: +```json +{ + "id": "1cc9773f-8d9a-4bfd-83ca-2099dc787a39", + "name": "Angular" +} +``` + +## Update Technology By Id + +||| +|---|---| +|Description|Update the values of an existing Technology| +|Type|PUT| +|URL structure|`http://localhost:5000/api/Technology?Id=27e203bd-5312-4831-9334-cd3c20e5d672`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|JSON| +|Returns|None| +||| + +Sample body: +```json +{ + "name": "string" +} +``` + +## Delete Technology By Id + +||| +|---|---| +|Description|Remove an existing Technology from the DataBase| +|Type|DELETE| +|URL structure|`http://localhost:5000/api/Technology?Id=086d1a23-c977-4cdc-9bdf-dc81992b3a12`| +|Authentication|Bearer Token (JWT), [Authorization Type 3](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication#token-validation)| +|Body|None| +|Returns|None| +|||
\ No newline at end of file diff --git a/docs/Authentication.md b/docs/Authentication.md new file mode 100644 index 0000000..f9e6525 --- /dev/null +++ b/docs/Authentication.md @@ -0,0 +1,52 @@ +Certain actions with the API require User authentication. In DevHive, all authentication is done with [JSON Web Tokens](https://en.wikipedia.org/wiki/JSON_Web_Token). + +The JWTs must be sent as a [Bearer Token](https://www.oauth.com/oauth2-servers/differences-between-oauth-1-2/bearer-tokens/). + +## Structure of tokens + +The main contents of a User's token are the `UserName`, `ID` and `Roles`. + +Sample token: +``` +eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjI3ZTIwM2JkLTUzMTItNDgzMS05MzM0LWNkM2MyMGU1ZDY3MiIsIlVzZXJuYW1lIjoidGVzdCIsInJvbGUiOiJVc2VyIiwibmJmIjoxNjEyMzYxOTc1LCJleHAiOjE2MTI5MDgwMDAsImlhdCI6MTYxMjM2MTk3NX0.ZxhDSUsDf9cGig03QpzNgj3dkqbcfAoFXVIfixYGurzhd0l1_IO79UpE_Sb6ZU9hz3IT1XPrlrQ_Kd46L7xcQg +``` +[Decoded](https://jwt.io/): + +- Header +```json +{ + "alg": "HS512", + "typ": "JWT" +} +``` + +- Data +```json +{ + "ID": "27e203bd-5312-4831-9334-cd3c20e5d672", + "Username": "test", + "role": "User", + "nbf": 1612361975, + "exp": 1612908000, + "iat": 1612361975 +} +``` + +- Signature +``` +HMACSHA512( + base64UrlEncode(header) + "." + + base64UrlEncode(payload) +) +``` + +## Token validation + +All token validations are done in the User Service. Depending on the situation, we can differentiate a couple types of authentication: + +||| +|---|---| +|1|Has the role "User" or "Admin"| +|2|Has the role "User" and is the owner/author of the object or has the role "Admin"| +|3|Has the role "Admin"| +|||
\ No newline at end of file diff --git a/docs/File-Structure.md b/docs/File-Structure.md new file mode 100644 index 0000000..4d0341e --- /dev/null +++ b/docs/File-Structure.md @@ -0,0 +1,495 @@ +DevHive has a lot of files and it can be hard to really see the whole structure of everything from a first glance. In this document, all of the important/notable files and folders are represented in a tree structure. + +### Contents: +- [Common](#common) +- [Data](#data) +- [Service](#service) +- [Tests](#tests) +- [Web](#web) +- [Full Overview](#full-overview) + +# Common + +``` +└── DevHive.Common + └── Models +   ├── Identity +   │  └── TokenModel.cs +   └── Misc +   ├── IdModel.cs +   ├── PasswordModifications.cs +   └── Patch.cs +``` + +# Data + +``` +└── DevHive.Data +   ├── ConnectionString.json +   ├── DevHiveContext.cs +   ├── DevHiveContextFactory.cs + ├── Interfaces + | ├── Models + | │  ├── IComment.cs + │ |  ├── ILanguage.cs + │ |  ├── IModel.cs + │ |  ├── IPost.cs + │ |  ├── IProfilePicture.cs + │ |  ├── IRating.cs + │ |  ├── IRole.cs + │ |  ├── ITechnology.cs + │ |  └── IUser.cs + | └── Repositories + | ├── ICommentRepository.cs + | ├── IFeedRepository.cs + | ├── ILanguageRepository.cs + | ├── IPostRepository.cs + | ├── IRatingRepository.cs + | ├── IRepository.cs + | ├── IRoleRepository.cs + | ├── ITechnologyRepository.cs + | └── IUserRepository.cs +   ├── Migrations +   ├── Models +   │  ├── Comment.cs +   │  ├── Language.cs +   │  ├── Post.cs +   │  ├── ProfilePicture.cs +  │  ├── Rating.cs +   │  ├── Role.cs +   │  ├── Technology.cs +   │  └── User.cs +   ├── RelationModels +   │  ├── RatedPost.cs +   │  ├── UserFriend.cs +   │  └── UserRate.cs +   └── Repositories +   ├── BaseRepository.cs +   ├── CommentRepository.cs +   ├── FeedRepository.cs +   ├── LanguageRepository.cs +   ├── PostRepository.cs +   ├── RatingRepository.cs +   ├── RoleRepository.cs +   ├── TechnologyRepository.cs +   └── UserRepository.cs +``` + +# Service + +``` +└── DevHive.Services +   ├── Configurations +   │  └── Mapping + | ├── CommentMappings.cs + | ├── FeedMappings.cs + | ├── LanguageMappings.cs + | ├── PostMappings.cs + | ├── RatingMappings.cs + | ├── RoleMapings.cs + | ├── TechnologyMappings.cs + | └── UserMappings.cs +   ├── Interfaces +   │  ├── ICloudService.cs +   │  ├── ICommentService.cs +   │  ├── IFeedService.cs +   │  ├── ILanguageService.cs +   │  ├── IPostService.cs +   │  ├── IRateService.cs +   │  ├── IRoleService.cs +   │  ├── ITechnologyService.cs +   │  └── IUserService.cs +   ├── Models + | ├── Cloud + | │  └── CloudinaryService.cs + | ├── Comment + | │  ├── CreateCommentServiceModel.cs + | │  ├── ReadCommentServiceModel.cs + | │  └── UpdateCommentServiceModel.cs + | ├── Feed + | │  ├── GetPageServiceModel.cs + | │  └── ReadPageServiceModel.cs + | ├── Identity + | │  ├── Role + | │  │  ├── CreateRoleServiceModel.cs + | │  │  ├── RoleServiceModel.cs + | │  │  └── UpdateRoleServiceModel.cs + | │  └── User + | │  ├── BaseUserServiceModel.cs + | │  ├── FriendServiceModel.cs + | │  ├── LoginServiceModel.cs + | │  ├── ProfilePictureServiceModel.cs + | │  ├── RegisterServiceModel.cs + | │  ├── UpdateFriendServiceModel.cs + | │  ├── UpdateProfilePictureServiceModel.cs + | │  ├── UpdateUserServiceModel.cs + | │  └── UserServiceModel.cs + | ├── Language + | │  ├── CreateLanguageServiceModel.cs + | │  ├── LanguageServiceModel.cs + | │  ├── ReadLanguageServiceModel.cs + | │  └── UpdateLanguageServiceModel.cs + | ├── Post + | | ├── Rating + | | │  ├── RatePostServiceModel.cs + | | │  └── ReadPostRatingServiceModel.cs + | │  ├── CreatePostServiceModel.cs + | │  ├── ReadPostServiceModel.cs + | │  └── UpdatePostServiceModel.cs + | └── Technology + | ├── CreateTechnologyServiceModel.cs + | ├── ReadTechnologyServiceModel.cs + | ├── TechnologyServiceModel.cs + | └── UpdateTechnologyServiceModel.cs +   ├── Options +  │  └── JWTOptions.cs +   └── Services +   ├── CommentService.cs +   ├── FeedService.cs +  ├── LanguageService.cs +   ├── PostService.cs +   ├── RateService.cs +   ├── RoleService.cs +   ├── TechnologyService.cs +   └── UserService.cs +``` + +# Tests + +``` +└── DevHive.Tests +   ├── DevHive.Data.Tests +   │  ├── CommentRepository.Tests.cs +   │  ├── FeedRepository.Tests.cs +   │  ├── LenguageRepository.Tests.cs +   │  ├── PostRepository.Tests.cs +   │  ├── RoleRepository.Tests.cs +   │  ├── TechnologyRepository.Tests.cs +   │  └── UserRepositoryTests.cs +   ├── DevHive.Services.Tests +   │  ├── FeedService.Tests.cs +   │  ├── LanguageService.Tests.cs +   │  ├── PostService.Tests.cs +   │  ├── RoleService.Tests.cs +   │  ├── TechnologyServices.Tests.cs +   │  └── UserService.Tests.cs +   └── DevHive.Web.Tests +   ├── LanguageController.Tests.cs +   └── TechnologyController.Tests.cs +``` + +# Web + +``` +└── DevHive.Web + ├── appsettings.json + ├── Attributes + │  ├── GoodPasswordModelValidation.cs + │  └── OnlyLettersModelValidation.cs + ├── Configurations + | ├── Extensions + | │  ├── ConfigureAutoMapper.cs + | │  ├── ConfigureDatabase.cs + | │  ├── ConfigureDependencyInjection.cs + | │  ├── ConfigureExceptionHandlerMiddleware.cs + | │  ├── ConfigureJWT.cs + | │  └── ConfigureSwagger.cs + | └── Mapping + | ├── CommentMappings.cs + | ├── FeedMappings.cs + | ├── LanguageMappings.cs + | ├── PostMappings.cs + | ├── RatingMappings.cs + | ├── RoleMappings.cs + | ├── TechnologyMappings.cs + | └── UserMappings.cs + ├── Controllers + │  ├── CommentController.cs + │  ├── FeedController.cs + │  ├── LanguageController.cs + │  ├── PostController.cs + │  ├── RateController.cs + │  ├── RoleController.cs + │  ├── TechnologyController.cs + │  └── UserController.cs + ├── Middleware + │  └── ExceptionMiddleware.cs + ├── Models + | ├── Comment + | │  ├── CreateCommentWebModel.cs + | │  ├── ReadCommentWebModel.cs + | │  └── UpdateCommentWebModel.cs + | ├── Feed + | │  ├── GetPageWebModel.cs + | │  └── ReadPageWebModel.cs + | ├── Identity + | │  ├── Role + | │  │  ├── CreateRoleWebModel.cs + | │  │  ├── RoleWebModel.cs + | │  │  └── UpdateRoleWebModel.cs + | │  └── User + | │  ├── BaseUserWebModel.cs + | │  ├── LoginWebModel.cs + | │  ├── ProfilePictureWebModel.cs + | │  ├── RegisterWebModel.cs + | │  ├── TokenWebModel.cs + | │  ├── UpdateProfilePictureWebModel.cs + | │  ├── UpdateUserWebModel.cs + | │  ├── UsernameWebModel.cs + | │  └── UserWebModel.cs + | ├── Language + | │  ├── CreateLanguageWebModel.cs + | │  ├── LanguageWebModel.cs + | │  ├── ReadLanguageWebModel.cs + | │  └── UpdateLanguageWebModel.cs + | ├── Post + | │  ├── Rating + | │  │  ├── RatePostWebModel.cs + | │  │  └── ReadPostRatingWebModel.cs + | │  ├── CreatePostWebModel.cs + | │  ├── ReadPostWebModel.cs + | │  └── UpdatePostWebModel.cs + | └── Technology + | ├── CreateTechnologyWebModel.cs + | ├── ReadTechnologyWebModel.cs + | ├── TechnologyWebModel.cs + | └── UpdateTechnologyWebModel.cs + ├── Program.cs + ├── Properties + │  └── launchSettings.json + └── Startup.cs +``` + +# Full overview + +``` +. +├── DevHive.code-workspace +├── DevHive.Common +| └── Models +|   ├── Identity +|   │  └── TokenModel.cs +|   └── Misc +|   ├── IdModel.cs +|   ├── PasswordModifications.cs +|   └── Patch.cs +├── DevHive.Data +│  ├── ConnectionString.json +│  ├── DevHiveContext.cs +│  ├── DevHiveContextFactory.cs +| ├── Interfaces +| | ├── Models +| | │  ├── IComment.cs +| │ |  ├── ILanguage.cs +| │ |  ├── IModel.cs +| │ |  ├── IPost.cs +| │ |  ├── IProfilePicture.cs +| │ |  ├── IRating.cs +| │ |  ├── IRole.cs +| │ |  ├── ITechnology.cs +| │ |  └── IUser.cs +| | └── Repositories +| | ├── ICommentRepository.cs +| | ├── IFeedRepository.cs +| | ├── ILanguageRepository.cs +| | ├── IPostRepository.cs +| | ├── IRatingRepository.cs +| | ├── IRepository.cs +| | ├── IRoleRepository.cs +| | ├── ITechnologyRepository.cs +| | └── IUserRepository.cs +│  ├── Migrations +│  ├── Models +│  │  ├── Comment.cs +│  │  ├── Language.cs +│  │  ├── Post.cs +│  │  ├── ProfilePicture.cs +│  │  ├── Rating.cs +│  │  ├── Role.cs +│  │  ├── Technology.cs +│  │  └── User.cs +│  ├── RelationModels +│  │  ├── RatedPost.cs +│  │  ├── UserFriend.cs +│  │  └── UserRate.cs +│  └── Repositories +│  ├── BaseRepository.cs +│  ├── CommentRepository.cs +│  ├── FeedRepository.cs +│  ├── LanguageRepository.cs +│  ├── PostRepository.cs +│  ├── RatingRepository.cs +│  ├── RoleRepository.cs +│  ├── TechnologyRepository.cs +│  └── UserRepository.cs +├── DevHive.Services +│  ├── Configurations +│  │  └── Mapping +| | ├── CommentMappings.cs +| | ├── FeedMappings.cs +| | ├── LanguageMappings.cs +| | ├── PostMappings.cs +| | ├── RatingMappings.cs +| | ├── RoleMapings.cs +| | ├── TechnologyMappings.cs +| | └── UserMappings.cs +│  ├── Interfaces +│  │  ├── ICloudService.cs +│  │  ├── ICommentService.cs +│  │  ├── IFeedService.cs +│  │  ├── ILanguageService.cs +│  │  ├── IPostService.cs +│  │  ├── IRateService.cs +│  │  ├── IRoleService.cs +│  │  ├── ITechnologyService.cs +│  │  └── IUserService.cs +│  ├── Models +| | ├── Cloud +| | │  └── CloudinaryService.cs +| | ├── Comment +| | │  ├── CreateCommentServiceModel.cs +| | │  ├── ReadCommentServiceModel.cs +| | │  └── UpdateCommentServiceModel.cs +| | ├── Feed +| | │  ├── GetPageServiceModel.cs +| | │  └── ReadPageServiceModel.cs +| | ├── Identity +| | │  ├── Role +| | │  │  ├── CreateRoleServiceModel.cs +| | │  │  ├── RoleServiceModel.cs +| | │  │  └── UpdateRoleServiceModel.cs +| | │  └── User +| | │  ├── BaseUserServiceModel.cs +| | │  ├── FriendServiceModel.cs +| | │  ├── LoginServiceModel.cs +| | │  ├── ProfilePictureServiceModel.cs +| | │  ├── RegisterServiceModel.cs +| | │  ├── UpdateFriendServiceModel.cs +| | │  ├── UpdateProfilePictureServiceModel.cs +| | │  ├── UpdateUserServiceModel.cs +| | │  └── UserServiceModel.cs +| | ├── Language +| | │  ├── CreateLanguageServiceModel.cs +| | │  ├── LanguageServiceModel.cs +| | │  ├── ReadLanguageServiceModel.cs +| | │  └── UpdateLanguageServiceModel.cs +| | ├── Post +| | | ├── Rating +| | | │  ├── RatePostServiceModel.cs +| | | │  └── ReadPostRatingServiceModel.cs +| | │  ├── CreatePostServiceModel.cs +| | │  ├── ReadPostServiceModel.cs +| | │  └── UpdatePostServiceModel.cs +| | └── Technology +| | ├── CreateTechnologyServiceModel.cs +| | ├── ReadTechnologyServiceModel.cs +| | ├── TechnologyServiceModel.cs +| | └── UpdateTechnologyServiceModel.cs +│  ├── Options +│  │  └── JWTOptions.cs +│  └── Services +│  ├── CommentService.cs +│  ├── FeedService.cs +│  ├── LanguageService.cs +│  ├── PostService.cs +│  ├── RateService.cs +│  ├── RoleService.cs +│  ├── TechnologyService.cs +│  └── UserService.cs +├── DevHive.Tests +│  ├── DevHive.Data.Tests +│  │  ├── CommentRepository.Tests.cs +│  │  ├── FeedRepository.Tests.cs +│  │  ├── LenguageRepository.Tests.cs +│  │  ├── PostRepository.Tests.cs +│  │  ├── RoleRepository.Tests.cs +│  │  ├── TechnologyRepository.Tests.cs +│  │  └── UserRepositoryTests.cs +│  ├── DevHive.Services.Tests +│  │  ├── FeedService.Tests.cs +│  │  ├── LanguageService.Tests.cs +│  │  ├── PostService.Tests.cs +│  │  ├── RoleService.Tests.cs +│  │  ├── TechnologyServices.Tests.cs +│  │  └── UserService.Tests.cs +│  └── DevHive.Web.Tests +│  ├── LanguageController.Tests.cs +│  └── TechnologyController.Tests.cs +└── DevHive.Web + ├── appsettings.json + ├── Attributes + │  ├── GoodPasswordModelValidation.cs + │  └── OnlyLettersModelValidation.cs + ├── Configurations + | ├── Extensions + | │  ├── ConfigureAutoMapper.cs + | │  ├── ConfigureDatabase.cs + | │  ├── ConfigureDependencyInjection.cs + | │  ├── ConfigureExceptionHandlerMiddleware.cs + | │  ├── ConfigureJWT.cs + | │  └── ConfigureSwagger.cs + | └── Mapping + | ├── CommentMappings.cs + | ├── FeedMappings.cs + | ├── LanguageMappings.cs + | ├── PostMappings.cs + | ├── RatingMappings.cs + | ├── RoleMappings.cs + | ├── TechnologyMappings.cs + | └── UserMappings.cs + ├── Controllers + │  ├── CommentController.cs + │  ├── FeedController.cs + │  ├── LanguageController.cs + │  ├── PostController.cs + │  ├── RateController.cs + │  ├── RoleController.cs + │  ├── TechnologyController.cs + │  └── UserController.cs + ├── Middleware + │  └── ExceptionMiddleware.cs + ├── Models + | ├── Comment + | │  ├── CreateCommentWebModel.cs + | │  ├── ReadCommentWebModel.cs + | │  └── UpdateCommentWebModel.cs + | ├── Feed + | │  ├── GetPageWebModel.cs + | │  └── ReadPageWebModel.cs + | ├── Identity + | │  ├── Role + | │  │  ├── CreateRoleWebModel.cs + | │  │  ├── RoleWebModel.cs + | │  │  └── UpdateRoleWebModel.cs + | │  └── User + | │  ├── BaseUserWebModel.cs + | │  ├── LoginWebModel.cs + | │  ├── ProfilePictureWebModel.cs + | │  ├── RegisterWebModel.cs + | │  ├── TokenWebModel.cs + | │  ├── UpdateProfilePictureWebModel.cs + | │  ├── UpdateUserWebModel.cs + | │  ├── UsernameWebModel.cs + | │  └── UserWebModel.cs + | ├── Language + | │  ├── CreateLanguageWebModel.cs + | │  ├── LanguageWebModel.cs + | │  ├── ReadLanguageWebModel.cs + | │  └── UpdateLanguageWebModel.cs + | ├── Post + | │  ├── Rating + | │  │  ├── RatePostWebModel.cs + | │  │  └── ReadPostRatingWebModel.cs + | │  ├── CreatePostWebModel.cs + | │  ├── ReadPostWebModel.cs + | │  └── UpdatePostWebModel.cs + | └── Technology + | ├── CreateTechnologyWebModel.cs + | ├── ReadTechnologyWebModel.cs + | ├── TechnologyWebModel.cs + | └── UpdateTechnologyWebModel.cs + ├── Program.cs + ├── Properties + │  └── launchSettings.json + └── Startup.cs +``` diff --git a/docs/Privacy-Policy.md b/docs/Privacy-Policy.md new file mode 100644 index 0000000..c338763 --- /dev/null +++ b/docs/Privacy-Policy.md @@ -0,0 +1,23 @@ +DevHive **doesn't collect any user data, that you haven't personally submitted** (there is no telemetry), and that won't ever change! + +The only potentially sensitive that that could be stored is your profile (first and last name, email, ..) and your posts (if you've shared anything sensitive), but in both cases you've personally given this information. + +## Data on the server + +All data is stored in the database and isn't shared with anyone. The entity that is hosting an instance of the application could expose data to unknown third parties, but DevHive doesn't do anything of the sorts by itself! + +## Data on your machine + +On your computer, the only thing that is saved is your [authentication token](https://github.com/Team-Kaleidoscope/DevHive/wiki/Authentication) in session storage. This is done so you could stay logged in the website in the current tab, and after closing it, the data gets deleted. + +In the future we could add a cookie to your computer storage, but that will still only hold the token for authentication purposes, so you can reopen your browser and still be logged in. **Tracking and third-party cookies are *never* going to be implemented!** + +## Telemetry by tools + +DevHive itself doesn't collect any type of telemetry, but that isn't the same for the tools it uses. + +The `dotnet` CLI tool is used to run the API, and `dotnet` does [`collect telemetry`](https://docs.microsoft.com/en-us/dotnet/core/tools/telemetry). [The same](https://angular.io/cli/usage-analytics-gathering) can be said for the Angular CLI (`ng`). + +Thankfully in both cases, you can opt out. Ask the administrator(s) of the instance you're using whether they have disabled telemetry. + +**Although**, it's important to mention that **this telemetry might not be collecting your data**, but the data of the server that uses it. Do your own research!
\ No newline at end of file diff --git a/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj b/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj index a952c59..db8d1c9 100644 --- a/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj +++ b/src/Common/DevHive.Common.Models/DevHive.Common.Models.csproj @@ -4,7 +4,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <PropertyGroup> <EnableNETAnalyzers>true</EnableNETAnalyzers> diff --git a/src/Common/DevHive.Common/Constants/ClassesConstants.cs b/src/Common/DevHive.Common/Constants/ClassesConstants.cs new file mode 100644 index 0000000..825f737 --- /dev/null +++ b/src/Common/DevHive.Common/Constants/ClassesConstants.cs @@ -0,0 +1,22 @@ +namespace DevHive.Common.Constants +{ + public static class ClassesConstants + { + public const string Data = "Data"; + + public const string Post = "The Post"; + public const string Comment = "The Comment"; + public const string User = "The User"; + public const string Language = "The Language"; + public const string Picture = "The Picture"; + public const string Files = "The Files"; + public const string Rating = "The Rating"; + public const string Role = "The Role"; + public const string Technology = "The Technology"; + + public const string Username = "The Username"; + public const string Email = "The Email"; + public const string Password = "Password"; + public const string OneOrMoreFriends = "One or more Friends"; + } +} diff --git a/src/Common/DevHive.Common/Constants/ErrorMessages.cs b/src/Common/DevHive.Common/Constants/ErrorMessages.cs new file mode 100644 index 0000000..30ca544 --- /dev/null +++ b/src/Common/DevHive.Common/Constants/ErrorMessages.cs @@ -0,0 +1,16 @@ +namespace DevHive.Common.Constants +{ + public static class ErrorMessages + { + public const string InvalidData = "Invalid {0}!"; + public const string IncorrectData = "Incorrect {0}!"; + public const string DoesNotExist = "{0} does not exist!"; + public const string AlreadyExists = "{0} already exists!"; + + public const string CannotAdd = "Could not add {0}!"; + public const string CannotCreate = "Could not create {0}!"; + public const string CannotDelete = "Could not delete {0}!"; + public const string CannotUpload = "Could not upload {0}!"; + public const string CannotEdit = "Could not edit {0}!"; + } +} diff --git a/src/Common/DevHive.Common/DevHive.Common.csproj b/src/Common/DevHive.Common/DevHive.Common.csproj index cd60d85..a5758f4 100644 --- a/src/Common/DevHive.Common/DevHive.Common.csproj +++ b/src/Common/DevHive.Common/DevHive.Common.csproj @@ -6,6 +6,6 @@ <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> - <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0"/> + <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0"/> </ItemGroup> -</Project> +</Project>
\ No newline at end of file diff --git a/src/Data/DevHive.Data.Models/Comment.cs b/src/Data/DevHive.Data.Models/Comment.cs index 0af40bf..8a58edd 100644 --- a/src/Data/DevHive.Data.Models/Comment.cs +++ b/src/Data/DevHive.Data.Models/Comment.cs @@ -6,12 +6,8 @@ namespace DevHive.Data.Models { public Guid Id { get; set; } - // public Guid PostId { get; set; } - public Post Post { get; set; } - // public Guid CreatorId { get; set; } - public User Creator { get; set; } public string Message { get; set; } diff --git a/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj b/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj index d249c77..2958f86 100644 --- a/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj +++ b/src/Data/DevHive.Data.Models/DevHive.Data.Models.csproj @@ -4,7 +4,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0"/> - <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.3"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.4"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> </Project>
\ No newline at end of file diff --git a/src/Data/DevHive.Data.Models/ProfilePicture.cs b/src/Data/DevHive.Data.Models/ProfilePicture.cs index e2ef04b..e8166d7 100644 --- a/src/Data/DevHive.Data.Models/ProfilePicture.cs +++ b/src/Data/DevHive.Data.Models/ProfilePicture.cs @@ -1,9 +1,13 @@ using System; +using System.ComponentModel.DataAnnotations.Schema; namespace DevHive.Data.Models { + [Table("ProfilePictures")] public class ProfilePicture { + public const string DefaultURL = "/assets/icons/tabler-icon-user.svg"; + public Guid Id { get; set; } public Guid UserId { get; set; } diff --git a/src/Data/DevHive.Data.Models/User.cs b/src/Data/DevHive.Data.Models/User.cs index ea0b4f2..d3789ec 100644 --- a/src/Data/DevHive.Data.Models/User.cs +++ b/src/Data/DevHive.Data.Models/User.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using DevHive.Data.Models.Relational; using Microsoft.AspNetCore.Identity; namespace DevHive.Data.Models @@ -13,7 +12,7 @@ namespace DevHive.Data.Models public string LastName { get; set; } - public ProfilePicture ProfilePicture { get; set; } = new() { PictureURL = "/assets/images/feed/profile-pic.png" }; + public ProfilePicture ProfilePicture { get; set; } = new() { PictureURL = ProfilePicture.DefaultURL }; public HashSet<Language> Languages { get; set; } = new(); diff --git a/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj b/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj index 25b2b39..e9b33e5 100644 --- a/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj +++ b/src/Data/DevHive.Data.Tests/DevHive.Data.Tests.csproj @@ -4,12 +4,12 @@ <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.3"/> + <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.4"/> <PackageReference Include="Moq" Version="4.16.1"/> <PackageReference Include="NUnit" Version="3.13.1"/> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\DevHive.Data\DevHive.Data.csproj"/> diff --git a/src/Data/DevHive.Data/ConnectionString.json b/src/Data/DevHive.Data/ConnectionString.json index c8300b2..1281a1c 100644 --- a/src/Data/DevHive.Data/ConnectionString.json +++ b/src/Data/DevHive.Data/ConnectionString.json @@ -1,5 +1,5 @@ { "ConnectionStrings": { - "DEV": "Server=localhost;Port=5432;Database=API;User Id=postgres;Password=password;" + "DEV": "Server=localhost;Port=5432;Database=DevHive_API;User Id=postgres;Password=password;" } -}
\ No newline at end of file +} diff --git a/src/Data/DevHive.Data/DevHive.Data.csproj b/src/Data/DevHive.Data/DevHive.Data.csproj index fcdb7ae..62320f7 100644 --- a/src/Data/DevHive.Data/DevHive.Data.csproj +++ b/src/Data/DevHive.Data/DevHive.Data.csproj @@ -5,14 +5,14 @@ <ItemGroup> <PackageReference Include="AutoMapper" Version="10.1.1"/> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/> - <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.3"/> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3"> + <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.4"/> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="5.0.0"/> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\DevHive.Data.Models\DevHive.Data.Models.csproj"/> diff --git a/src/Data/DevHive.Data/DevHiveContext.cs b/src/Data/DevHive.Data/DevHiveContext.cs index 621336f..0606864 100644 --- a/src/Data/DevHive.Data/DevHiveContext.cs +++ b/src/Data/DevHive.Data/DevHiveContext.cs @@ -17,6 +17,7 @@ namespace DevHive.Data public DbSet<PostAttachments> PostAttachments { get; set; } public DbSet<Comment> Comments { get; set; } public DbSet<Rating> Rating { get; set; } + public DbSet<ProfilePicture> ProfilePicture { get; set; } protected override void OnModelCreating(ModelBuilder builder) { @@ -25,11 +26,6 @@ namespace DevHive.Data .HasIndex(x => x.UserName) .IsUnique(); - builder.Entity<User>() - .HasOne(x => x.ProfilePicture) - .WithOne(x => x.User) - .HasForeignKey<ProfilePicture>(x => x.UserId); - /* Roles */ builder.Entity<User>() .HasMany(x => x.Roles) @@ -92,6 +88,15 @@ namespace DevHive.Data .HasMany(x => x.Ratings) .WithOne(x => x.Post); + /* Profile Picture */ + builder.Entity<ProfilePicture>() + .HasKey(x => x.Id); + + builder.Entity<User>() + .HasOne(x => x.ProfilePicture) + .WithOne(x => x.User) + .HasForeignKey<ProfilePicture>(x => x.UserId); + base.OnModelCreating(builder); } } diff --git a/src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs b/src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs new file mode 100644 index 0000000..45beaa0 --- /dev/null +++ b/src/Data/DevHive.Data/Interfaces/IProfilePictureRepository.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; +using DevHive.Data.Models; + +namespace DevHive.Data.Interfaces +{ + public interface IProfilePictureRepository : IRepository<ProfilePicture> + { + Task<ProfilePicture> GetByURLAsync(string picUrl); + } +} diff --git a/src/Data/DevHive.Data/Migrations/20210216152915_Inital.cs b/src/Data/DevHive.Data/Migrations/20210216152915_Inital.cs deleted file mode 100644 index 4c5b982..0000000 --- a/src/Data/DevHive.Data/Migrations/20210216152915_Inital.cs +++ /dev/null @@ -1,587 +0,0 @@ -// <auto-generated /> -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace DevHive.Data.Migrations -{ - public partial class Inital : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "AspNetRoles", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), - NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), - ConcurrencyStamp = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetRoles", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AspNetUsers", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - FirstName = table.Column<string>(type: "text", nullable: true), - LastName = table.Column<string>(type: "text", nullable: true), - UserId = table.Column<Guid>(type: "uuid", nullable: true), - UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), - NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), - Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), - NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), - EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false), - PasswordHash = table.Column<string>(type: "text", nullable: true), - SecurityStamp = table.Column<string>(type: "text", nullable: true), - ConcurrencyStamp = table.Column<string>(type: "text", nullable: true), - PhoneNumber = table.Column<string>(type: "text", nullable: true), - PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false), - TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false), - LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true), - LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false), - AccessFailedCount = table.Column<int>(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetUsers", x => x.Id); - table.ForeignKey( - name: "FK_AspNetUsers_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Languages", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - Name = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Languages", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "Technologies", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - Name = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Technologies", x => x.Id); - }); - - migrationBuilder.CreateTable( - name: "AspNetRoleClaims", - columns: table => new - { - Id = table.Column<int>(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - RoleId = table.Column<Guid>(type: "uuid", nullable: false), - ClaimType = table.Column<string>(type: "text", nullable: true), - ClaimValue = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); - table.ForeignKey( - name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", - column: x => x.RoleId, - principalTable: "AspNetRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AspNetUserClaims", - columns: table => new - { - Id = table.Column<int>(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - UserId = table.Column<Guid>(type: "uuid", nullable: false), - ClaimType = table.Column<string>(type: "text", nullable: true), - ClaimValue = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); - table.ForeignKey( - name: "FK_AspNetUserClaims_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AspNetUserLogins", - columns: table => new - { - LoginProvider = table.Column<string>(type: "text", nullable: false), - ProviderKey = table.Column<string>(type: "text", nullable: false), - ProviderDisplayName = table.Column<string>(type: "text", nullable: true), - UserId = table.Column<Guid>(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); - table.ForeignKey( - name: "FK_AspNetUserLogins_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AspNetUserRoles", - columns: table => new - { - UserId = table.Column<Guid>(type: "uuid", nullable: false), - RoleId = table.Column<Guid>(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); - table.ForeignKey( - name: "FK_AspNetUserRoles_AspNetRoles_RoleId", - column: x => x.RoleId, - principalTable: "AspNetRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_AspNetUserRoles_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "AspNetUserTokens", - columns: table => new - { - UserId = table.Column<Guid>(type: "uuid", nullable: false), - LoginProvider = table.Column<string>(type: "text", nullable: false), - Name = table.Column<string>(type: "text", nullable: false), - Value = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); - table.ForeignKey( - name: "FK_AspNetUserTokens_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Posts", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - CreatorId = table.Column<Guid>(type: "uuid", nullable: true), - Message = table.Column<string>(type: "text", nullable: true), - TimeCreated = table.Column<DateTime>(type: "timestamp without time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Posts", x => x.Id); - table.ForeignKey( - name: "FK_Posts_AspNetUsers_CreatorId", - column: x => x.CreatorId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "ProfilePicture", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - UserId = table.Column<Guid>(type: "uuid", nullable: false), - PictureURL = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_ProfilePicture", x => x.Id); - table.ForeignKey( - name: "FK_ProfilePicture_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "RoleUser", - columns: table => new - { - RolesId = table.Column<Guid>(type: "uuid", nullable: false), - UsersId = table.Column<Guid>(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_RoleUser", x => new { x.RolesId, x.UsersId }); - table.ForeignKey( - name: "FK_RoleUser_AspNetRoles_RolesId", - column: x => x.RolesId, - principalTable: "AspNetRoles", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_RoleUser_AspNetUsers_UsersId", - column: x => x.UsersId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "LanguageUser", - columns: table => new - { - LanguagesId = table.Column<Guid>(type: "uuid", nullable: false), - UsersId = table.Column<Guid>(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_LanguageUser", x => new { x.LanguagesId, x.UsersId }); - table.ForeignKey( - name: "FK_LanguageUser_AspNetUsers_UsersId", - column: x => x.UsersId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_LanguageUser_Languages_LanguagesId", - column: x => x.LanguagesId, - principalTable: "Languages", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "TechnologyUser", - columns: table => new - { - TechnologiesId = table.Column<Guid>(type: "uuid", nullable: false), - UsersId = table.Column<Guid>(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_TechnologyUser", x => new { x.TechnologiesId, x.UsersId }); - table.ForeignKey( - name: "FK_TechnologyUser_AspNetUsers_UsersId", - column: x => x.UsersId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_TechnologyUser_Technologies_TechnologiesId", - column: x => x.TechnologiesId, - principalTable: "Technologies", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Comments", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - PostId = table.Column<Guid>(type: "uuid", nullable: true), - CreatorId = table.Column<Guid>(type: "uuid", nullable: true), - Message = table.Column<string>(type: "text", nullable: true), - TimeCreated = table.Column<DateTime>(type: "timestamp without time zone", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Comments", x => x.Id); - table.ForeignKey( - name: "FK_Comments_AspNetUsers_CreatorId", - column: x => x.CreatorId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_Comments_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "PostAttachments", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - PostId = table.Column<Guid>(type: "uuid", nullable: true), - FileUrl = table.Column<string>(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_PostAttachments", x => x.Id); - table.ForeignKey( - name: "FK_PostAttachments_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "RatedPosts", - columns: table => new - { - UserId = table.Column<Guid>(type: "uuid", nullable: false), - PostId = table.Column<Guid>(type: "uuid", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_RatedPosts", x => new { x.UserId, x.PostId }); - table.ForeignKey( - name: "FK_RatedPosts_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_RatedPosts_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Rating", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - PostId = table.Column<Guid>(type: "uuid", nullable: false), - Rate = table.Column<int>(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Rating", x => x.Id); - table.ForeignKey( - name: "FK_Rating_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "UserRates", - columns: table => new - { - Id = table.Column<Guid>(type: "uuid", nullable: false), - UserId = table.Column<Guid>(type: "uuid", nullable: true), - Liked = table.Column<bool>(type: "boolean", nullable: false), - PostId = table.Column<Guid>(type: "uuid", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_UserRates", x => x.Id); - table.ForeignKey( - name: "FK_UserRates_AspNetUsers_UserId", - column: x => x.UserId, - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_UserRates_Posts_PostId", - column: x => x.PostId, - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_AspNetRoleClaims_RoleId", - table: "AspNetRoleClaims", - column: "RoleId"); - - migrationBuilder.CreateIndex( - name: "RoleNameIndex", - table: "AspNetRoles", - column: "NormalizedName", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_AspNetUserClaims_UserId", - table: "AspNetUserClaims", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_AspNetUserLogins_UserId", - table: "AspNetUserLogins", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_AspNetUserRoles_RoleId", - table: "AspNetUserRoles", - column: "RoleId"); - - migrationBuilder.CreateIndex( - name: "EmailIndex", - table: "AspNetUsers", - column: "NormalizedEmail"); - - migrationBuilder.CreateIndex( - name: "IX_AspNetUsers_UserId", - table: "AspNetUsers", - column: "UserId"); - - migrationBuilder.CreateIndex( - name: "IX_AspNetUsers_UserName", - table: "AspNetUsers", - column: "UserName", - unique: true); - - migrationBuilder.CreateIndex( - name: "UserNameIndex", - table: "AspNetUsers", - column: "NormalizedUserName", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Comments_CreatorId", - table: "Comments", - column: "CreatorId"); - - migrationBuilder.CreateIndex( - name: "IX_Comments_PostId", - table: "Comments", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_LanguageUser_UsersId", - table: "LanguageUser", - column: "UsersId"); - - migrationBuilder.CreateIndex( - name: "IX_PostAttachments_PostId", - table: "PostAttachments", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_Posts_CreatorId", - table: "Posts", - column: "CreatorId"); - - migrationBuilder.CreateIndex( - name: "IX_ProfilePicture_UserId", - table: "ProfilePicture", - column: "UserId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_RatedPosts_PostId", - table: "RatedPosts", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_Rating_PostId", - table: "Rating", - column: "PostId", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_RoleUser_UsersId", - table: "RoleUser", - column: "UsersId"); - - migrationBuilder.CreateIndex( - name: "IX_TechnologyUser_UsersId", - table: "TechnologyUser", - column: "UsersId"); - - migrationBuilder.CreateIndex( - name: "IX_UserRates_PostId", - table: "UserRates", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_UserRates_UserId", - table: "UserRates", - column: "UserId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "AspNetRoleClaims"); - - migrationBuilder.DropTable( - name: "AspNetUserClaims"); - - migrationBuilder.DropTable( - name: "AspNetUserLogins"); - - migrationBuilder.DropTable( - name: "AspNetUserRoles"); - - migrationBuilder.DropTable( - name: "AspNetUserTokens"); - - migrationBuilder.DropTable( - name: "Comments"); - - migrationBuilder.DropTable( - name: "LanguageUser"); - - migrationBuilder.DropTable( - name: "PostAttachments"); - - migrationBuilder.DropTable( - name: "ProfilePicture"); - - migrationBuilder.DropTable( - name: "RatedPosts"); - - migrationBuilder.DropTable( - name: "Rating"); - - migrationBuilder.DropTable( - name: "RoleUser"); - - migrationBuilder.DropTable( - name: "TechnologyUser"); - - migrationBuilder.DropTable( - name: "UserRates"); - - migrationBuilder.DropTable( - name: "Languages"); - - migrationBuilder.DropTable( - name: "AspNetRoles"); - - migrationBuilder.DropTable( - name: "Technologies"); - - migrationBuilder.DropTable( - name: "Posts"); - - migrationBuilder.DropTable( - name: "AspNetUsers"); - } - } -} diff --git a/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs b/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs deleted file mode 100644 index c0b67a6..0000000 --- a/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.Designer.cs +++ /dev/null @@ -1,678 +0,0 @@ -// <auto-generated /> -using System; -using DevHive.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace DevHive.Data.Migrations -{ - [DbContext(typeof(DevHiveContext))] - [Migration("20210225193352_rating_migration")] - partial class rating_migration - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("Relational:MaxIdentifierLength", 63) - .HasAnnotation("ProductVersion", "5.0.3") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - modelBuilder.Entity("DevHive.Data.Models.Comment", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<Guid?>("CreatorId") - .HasColumnType("uuid"); - - b.Property<string>("Message") - .HasColumnType("text"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<DateTime>("TimeCreated") - .HasColumnType("timestamp without time zone"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("PostId"); - - b.ToTable("Comments"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Language", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Languages"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Post", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<Guid?>("CreatorId") - .HasColumnType("uuid"); - - b.Property<int>("CurrentRating") - .HasColumnType("integer"); - - b.Property<string>("Message") - .HasColumnType("text"); - - b.Property<DateTime>("TimeCreated") - .HasColumnType("timestamp without time zone"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.ToTable("Posts"); - }); - - modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("PictureURL") - .HasColumnType("text"); - - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ProfilePicture"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Rating", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<bool>("IsLike") - .HasColumnType("boolean"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.HasIndex("UserId"); - - b.ToTable("Rating"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("FileUrl") - .HasColumnType("text"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.ToTable("PostAttachments"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<Guid>("PostId") - .HasColumnType("uuid"); - - b.HasKey("UserId", "PostId"); - - b.HasIndex("PostId"); - - b.ToTable("RatedPosts"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<bool>("Liked") - .HasColumnType("boolean"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.HasIndex("UserId"); - - b.ToTable("UserRates"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Role", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property<string>("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<string>("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Technology", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Technologies"); - }); - - modelBuilder.Entity("DevHive.Data.Models.User", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<int>("AccessFailedCount") - .HasColumnType("integer"); - - b.Property<string>("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property<string>("Email") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<bool>("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property<string>("FirstName") - .HasColumnType("text"); - - b.Property<string>("LastName") - .HasColumnType("text"); - - b.Property<bool>("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property<DateTimeOffset?>("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property<string>("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<string>("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<string>("PasswordHash") - .HasColumnType("text"); - - b.Property<string>("PhoneNumber") - .HasColumnType("text"); - - b.Property<bool>("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property<string>("SecurityStamp") - .HasColumnType("text"); - - b.Property<bool>("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.Property<string>("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.HasIndex("UserId"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("AspNetUsers"); - }); - - modelBuilder.Entity("LanguageUser", b => - { - b.Property<Guid>("LanguagesId") - .HasColumnType("uuid"); - - b.Property<Guid>("UsersId") - .HasColumnType("uuid"); - - b.HasKey("LanguagesId", "UsersId"); - - b.HasIndex("UsersId"); - - b.ToTable("LanguageUser"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b => - { - b.Property<int>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property<string>("ClaimType") - .HasColumnType("text"); - - b.Property<string>("ClaimValue") - .HasColumnType("text"); - - b.Property<Guid>("RoleId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b => - { - b.Property<int>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property<string>("ClaimType") - .HasColumnType("text"); - - b.Property<string>("ClaimValue") - .HasColumnType("text"); - - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b => - { - b.Property<string>("LoginProvider") - .HasColumnType("text"); - - b.Property<string>("ProviderKey") - .HasColumnType("text"); - - b.Property<string>("ProviderDisplayName") - .HasColumnType("text"); - - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<Guid>("RoleId") - .HasColumnType("uuid"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<string>("LoginProvider") - .HasColumnType("text"); - - b.Property<string>("Name") - .HasColumnType("text"); - - b.Property<string>("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens"); - }); - - modelBuilder.Entity("RoleUser", b => - { - b.Property<Guid>("RolesId") - .HasColumnType("uuid"); - - b.Property<Guid>("UsersId") - .HasColumnType("uuid"); - - b.HasKey("RolesId", "UsersId"); - - b.HasIndex("UsersId"); - - b.ToTable("RoleUser"); - }); - - modelBuilder.Entity("TechnologyUser", b => - { - b.Property<Guid>("TechnologiesId") - .HasColumnType("uuid"); - - b.Property<Guid>("UsersId") - .HasColumnType("uuid"); - - b.HasKey("TechnologiesId", "UsersId"); - - b.HasIndex("UsersId"); - - b.ToTable("TechnologyUser"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Comment", b => - { - b.HasOne("DevHive.Data.Models.User", "Creator") - .WithMany("Comments") - .HasForeignKey("CreatorId"); - - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Comments") - .HasForeignKey("PostId"); - - b.Navigation("Creator"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Post", b => - { - b.HasOne("DevHive.Data.Models.User", "Creator") - .WithMany("Posts") - .HasForeignKey("CreatorId"); - - b.Navigation("Creator"); - }); - - modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => - { - b.HasOne("DevHive.Data.Models.User", "User") - .WithOne("ProfilePicture") - .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Rating", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Ratings") - .HasForeignKey("PostId"); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany() - .HasForeignKey("UserId"); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Attachments") - .HasForeignKey("PostId"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany("RatedPosts") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId"); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany() - .HasForeignKey("UserId"); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.User", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany("Friends") - .HasForeignKey("UserId"); - }); - - modelBuilder.Entity("LanguageUser", b => - { - b.HasOne("DevHive.Data.Models.Language", null) - .WithMany() - .HasForeignKey("LanguagesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UsersId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("RoleUser", b => - { - b.HasOne("DevHive.Data.Models.Role", null) - .WithMany() - .HasForeignKey("RolesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UsersId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("TechnologyUser", b => - { - b.HasOne("DevHive.Data.Models.Technology", null) - .WithMany() - .HasForeignKey("TechnologiesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UsersId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("DevHive.Data.Models.Post", b => - { - b.Navigation("Attachments"); - - b.Navigation("Comments"); - - b.Navigation("Ratings"); - }); - - modelBuilder.Entity("DevHive.Data.Models.User", b => - { - b.Navigation("Comments"); - - b.Navigation("Friends"); - - b.Navigation("Posts"); - - b.Navigation("ProfilePicture"); - - b.Navigation("RatedPosts"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs b/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs deleted file mode 100644 index da81cdc..0000000 --- a/src/Data/DevHive.Data/Migrations/20210225193352_rating_migration.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace DevHive.Data.Migrations -{ - public partial class rating_migration : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Rating_Posts_PostId", - table: "Rating"); - - migrationBuilder.DropIndex( - name: "IX_Rating_PostId", - table: "Rating"); - - migrationBuilder.DropColumn( - name: "Rate", - table: "Rating"); - - migrationBuilder.AlterColumn<Guid>( - name: "PostId", - table: "Rating", - type: "uuid", - nullable: true, - oldClrType: typeof(Guid), - oldType: "uuid"); - - migrationBuilder.AddColumn<bool>( - name: "IsLike", - table: "Rating", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn<Guid>( - name: "UserId", - table: "Rating", - type: "uuid", - nullable: true); - - migrationBuilder.AddColumn<int>( - name: "CurrentRating", - table: "Posts", - type: "integer", - nullable: false, - defaultValue: 0); - - migrationBuilder.CreateIndex( - name: "IX_Rating_PostId", - table: "Rating", - column: "PostId"); - - migrationBuilder.CreateIndex( - name: "IX_Rating_UserId", - table: "Rating", - column: "UserId"); - - migrationBuilder.AddForeignKey( - name: "FK_Rating_AspNetUsers_UserId", - table: "Rating", - column: "UserId", - principalTable: "AspNetUsers", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - - migrationBuilder.AddForeignKey( - name: "FK_Rating_Posts_PostId", - table: "Rating", - column: "PostId", - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Restrict); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropForeignKey( - name: "FK_Rating_AspNetUsers_UserId", - table: "Rating"); - - migrationBuilder.DropForeignKey( - name: "FK_Rating_Posts_PostId", - table: "Rating"); - - migrationBuilder.DropIndex( - name: "IX_Rating_PostId", - table: "Rating"); - - migrationBuilder.DropIndex( - name: "IX_Rating_UserId", - table: "Rating"); - - migrationBuilder.DropColumn( - name: "IsLike", - table: "Rating"); - - migrationBuilder.DropColumn( - name: "UserId", - table: "Rating"); - - migrationBuilder.DropColumn( - name: "CurrentRating", - table: "Posts"); - - migrationBuilder.AlterColumn<Guid>( - name: "PostId", - table: "Rating", - type: "uuid", - nullable: false, - defaultValue: new Guid("00000000-0000-0000-0000-000000000000"), - oldClrType: typeof(Guid), - oldType: "uuid", - oldNullable: true); - - migrationBuilder.AddColumn<int>( - name: "Rate", - table: "Rating", - type: "integer", - nullable: false, - defaultValue: 0); - - migrationBuilder.CreateIndex( - name: "IX_Rating_PostId", - table: "Rating", - column: "PostId", - unique: true); - - migrationBuilder.AddForeignKey( - name: "FK_Rating_Posts_PostId", - table: "Rating", - column: "PostId", - principalTable: "Posts", - principalColumn: "Id", - onDelete: ReferentialAction.Cascade); - } - } -} diff --git a/src/Data/DevHive.Data/Migrations/20210303083146_rating_migrations_update.Designer.cs b/src/Data/DevHive.Data/Migrations/20210303083146_rating_migrations_update.Designer.cs deleted file mode 100644 index ff5dd1c..0000000 --- a/src/Data/DevHive.Data/Migrations/20210303083146_rating_migrations_update.Designer.cs +++ /dev/null @@ -1,675 +0,0 @@ -// <auto-generated /> -using System; -using DevHive.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace DevHive.Data.Migrations -{ - [DbContext(typeof(DevHiveContext))] - [Migration("20210303083146_rating_migrations_update")] - partial class rating_migrations_update - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("Relational:MaxIdentifierLength", 63) - .HasAnnotation("ProductVersion", "5.0.3") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - modelBuilder.Entity("DevHive.Data.Models.Comment", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<Guid?>("CreatorId") - .HasColumnType("uuid"); - - b.Property<string>("Message") - .HasColumnType("text"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<DateTime>("TimeCreated") - .HasColumnType("timestamp without time zone"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.HasIndex("PostId"); - - b.ToTable("Comments"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Language", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Languages"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Post", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<Guid?>("CreatorId") - .HasColumnType("uuid"); - - b.Property<string>("Message") - .HasColumnType("text"); - - b.Property<DateTime>("TimeCreated") - .HasColumnType("timestamp without time zone"); - - b.HasKey("Id"); - - b.HasIndex("CreatorId"); - - b.ToTable("Posts"); - }); - - modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("PictureURL") - .HasColumnType("text"); - - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId") - .IsUnique(); - - b.ToTable("ProfilePicture"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Rating", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<bool>("IsLike") - .HasColumnType("boolean"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.HasIndex("UserId"); - - b.ToTable("Rating"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("FileUrl") - .HasColumnType("text"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.ToTable("PostAttachments"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<Guid>("PostId") - .HasColumnType("uuid"); - - b.HasKey("UserId", "PostId"); - - b.HasIndex("PostId"); - - b.ToTable("RatedPosts"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<bool>("Liked") - .HasColumnType("boolean"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.HasIndex("UserId"); - - b.ToTable("UserRates"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Role", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property<string>("Name") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<string>("NormalizedName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasDatabaseName("RoleNameIndex"); - - b.ToTable("AspNetRoles"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Technology", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<string>("Name") - .HasColumnType("text"); - - b.HasKey("Id"); - - b.ToTable("Technologies"); - }); - - modelBuilder.Entity("DevHive.Data.Models.User", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<int>("AccessFailedCount") - .HasColumnType("integer"); - - b.Property<string>("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("text"); - - b.Property<string>("Email") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<bool>("EmailConfirmed") - .HasColumnType("boolean"); - - b.Property<string>("FirstName") - .HasColumnType("text"); - - b.Property<string>("LastName") - .HasColumnType("text"); - - b.Property<bool>("LockoutEnabled") - .HasColumnType("boolean"); - - b.Property<DateTimeOffset?>("LockoutEnd") - .HasColumnType("timestamp with time zone"); - - b.Property<string>("NormalizedEmail") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<string>("NormalizedUserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.Property<string>("PasswordHash") - .HasColumnType("text"); - - b.Property<string>("PhoneNumber") - .HasColumnType("text"); - - b.Property<bool>("PhoneNumberConfirmed") - .HasColumnType("boolean"); - - b.Property<string>("SecurityStamp") - .HasColumnType("text"); - - b.Property<bool>("TwoFactorEnabled") - .HasColumnType("boolean"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.Property<string>("UserName") - .HasMaxLength(256) - .HasColumnType("character varying(256)"); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasDatabaseName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasDatabaseName("UserNameIndex"); - - b.HasIndex("UserId"); - - b.HasIndex("UserName") - .IsUnique(); - - b.ToTable("AspNetUsers"); - }); - - modelBuilder.Entity("LanguageUser", b => - { - b.Property<Guid>("LanguagesId") - .HasColumnType("uuid"); - - b.Property<Guid>("UsersId") - .HasColumnType("uuid"); - - b.HasKey("LanguagesId", "UsersId"); - - b.HasIndex("UsersId"); - - b.ToTable("LanguageUser"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b => - { - b.Property<int>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property<string>("ClaimType") - .HasColumnType("text"); - - b.Property<string>("ClaimValue") - .HasColumnType("text"); - - b.Property<Guid>("RoleId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b => - { - b.Property<int>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property<string>("ClaimType") - .HasColumnType("text"); - - b.Property<string>("ClaimValue") - .HasColumnType("text"); - - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b => - { - b.Property<string>("LoginProvider") - .HasColumnType("text"); - - b.Property<string>("ProviderKey") - .HasColumnType("text"); - - b.Property<string>("ProviderDisplayName") - .HasColumnType("text"); - - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<Guid>("RoleId") - .HasColumnType("uuid"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<string>("LoginProvider") - .HasColumnType("text"); - - b.Property<string>("Name") - .HasColumnType("text"); - - b.Property<string>("Value") - .HasColumnType("text"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens"); - }); - - modelBuilder.Entity("RoleUser", b => - { - b.Property<Guid>("RolesId") - .HasColumnType("uuid"); - - b.Property<Guid>("UsersId") - .HasColumnType("uuid"); - - b.HasKey("RolesId", "UsersId"); - - b.HasIndex("UsersId"); - - b.ToTable("RoleUser"); - }); - - modelBuilder.Entity("TechnologyUser", b => - { - b.Property<Guid>("TechnologiesId") - .HasColumnType("uuid"); - - b.Property<Guid>("UsersId") - .HasColumnType("uuid"); - - b.HasKey("TechnologiesId", "UsersId"); - - b.HasIndex("UsersId"); - - b.ToTable("TechnologyUser"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Comment", b => - { - b.HasOne("DevHive.Data.Models.User", "Creator") - .WithMany("Comments") - .HasForeignKey("CreatorId"); - - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Comments") - .HasForeignKey("PostId"); - - b.Navigation("Creator"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Post", b => - { - b.HasOne("DevHive.Data.Models.User", "Creator") - .WithMany("Posts") - .HasForeignKey("CreatorId"); - - b.Navigation("Creator"); - }); - - modelBuilder.Entity("DevHive.Data.Models.ProfilePicture", b => - { - b.HasOne("DevHive.Data.Models.User", "User") - .WithOne("ProfilePicture") - .HasForeignKey("DevHive.Data.Models.ProfilePicture", "UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Rating", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Ratings") - .HasForeignKey("PostId"); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany() - .HasForeignKey("UserId"); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Attachments") - .HasForeignKey("PostId"); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany("RatedPosts") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId"); - - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany() - .HasForeignKey("UserId"); - - b.Navigation("Post"); - - b.Navigation("User"); - }); - - modelBuilder.Entity("DevHive.Data.Models.User", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany("Friends") - .HasForeignKey("UserId"); - }); - - modelBuilder.Entity("LanguageUser", b => - { - b.HasOne("DevHive.Data.Models.Language", null) - .WithMany() - .HasForeignKey("LanguagesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UsersId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.Role", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<System.Guid>", b => - { - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("RoleUser", b => - { - b.HasOne("DevHive.Data.Models.Role", null) - .WithMany() - .HasForeignKey("RolesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UsersId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("TechnologyUser", b => - { - b.HasOne("DevHive.Data.Models.Technology", null) - .WithMany() - .HasForeignKey("TechnologiesId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("DevHive.Data.Models.User", null) - .WithMany() - .HasForeignKey("UsersId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("DevHive.Data.Models.Post", b => - { - b.Navigation("Attachments"); - - b.Navigation("Comments"); - - b.Navigation("Ratings"); - }); - - modelBuilder.Entity("DevHive.Data.Models.User", b => - { - b.Navigation("Comments"); - - b.Navigation("Friends"); - - b.Navigation("Posts"); - - b.Navigation("ProfilePicture"); - - b.Navigation("RatedPosts"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/Data/DevHive.Data/Migrations/20210303083146_rating_migrations_update.cs b/src/Data/DevHive.Data/Migrations/20210303083146_rating_migrations_update.cs deleted file mode 100644 index 073ba50..0000000 --- a/src/Data/DevHive.Data/Migrations/20210303083146_rating_migrations_update.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace DevHive.Data.Migrations -{ - public partial class rating_migrations_update : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "CurrentRating", - table: "Posts"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn<int>( - name: "CurrentRating", - table: "Posts", - type: "integer", - nullable: false, - defaultValue: 0); - } - } -} diff --git a/src/Data/DevHive.Data/Migrations/20210216152915_Inital.Designer.cs b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.Designer.cs index a85f657..a3fcb2d 100644 --- a/src/Data/DevHive.Data/Migrations/20210216152915_Inital.Designer.cs +++ b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.Designer.cs @@ -10,8 +10,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DevHive.Data.Migrations { [DbContext(typeof(DevHiveContext))] - [Migration("20210216152915_Inital")] - partial class Inital + [Migration("20210328161726_Profile_Pic_Property_Alter")] + partial class Profile_Pic_Property_Alter { protected override void BuildTargetModel(ModelBuilder modelBuilder) { @@ -101,7 +101,7 @@ namespace DevHive.Data.Migrations b.HasIndex("UserId") .IsUnique(); - b.ToTable("ProfilePicture"); + b.ToTable("ProfilePictures"); }); modelBuilder.Entity("DevHive.Data.Models.Rating", b => @@ -110,16 +110,20 @@ namespace DevHive.Data.Migrations .ValueGeneratedOnAdd() .HasColumnType("uuid"); - b.Property<Guid>("PostId") + b.Property<bool>("IsLike") + .HasColumnType("boolean"); + + b.Property<Guid?>("PostId") .HasColumnType("uuid"); - b.Property<int>("Rate") - .HasColumnType("integer"); + b.Property<Guid?>("UserId") + .HasColumnType("uuid"); b.HasKey("Id"); - b.HasIndex("PostId") - .IsUnique(); + b.HasIndex("PostId"); + + b.HasIndex("UserId"); b.ToTable("Rating"); }); @@ -143,45 +147,6 @@ namespace DevHive.Data.Migrations b.ToTable("PostAttachments"); }); - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.Property<Guid>("UserId") - .HasColumnType("uuid"); - - b.Property<Guid>("PostId") - .HasColumnType("uuid"); - - b.HasKey("UserId", "PostId"); - - b.HasIndex("PostId"); - - b.ToTable("RatedPosts"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => - { - b.Property<Guid>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid"); - - b.Property<bool>("Liked") - .HasColumnType("boolean"); - - b.Property<Guid?>("PostId") - .HasColumnType("uuid"); - - b.Property<Guid?>("UserId") - .HasColumnType("uuid"); - - b.HasKey("Id"); - - b.HasIndex("PostId"); - - b.HasIndex("UserId"); - - b.ToTable("UserRates"); - }); - modelBuilder.Entity("DevHive.Data.Models.Role", b => { b.Property<Guid>("Id") @@ -486,55 +451,25 @@ namespace DevHive.Data.Migrations modelBuilder.Entity("DevHive.Data.Models.Rating", b => { b.HasOne("DevHive.Data.Models.Post", "Post") - .WithOne("Rating") - .HasForeignKey("DevHive.Data.Models.Rating", "PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Post"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany("Attachments") + .WithMany("Ratings") .HasForeignKey("PostId"); - b.Navigation("Post"); - }); - - modelBuilder.Entity("DevHive.Data.Models.Relational.RatedPost", b => - { - b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() - .HasForeignKey("PostId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany("RatedPosts") - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .WithMany() + .HasForeignKey("UserId"); b.Navigation("Post"); b.Navigation("User"); }); - modelBuilder.Entity("DevHive.Data.Models.Relational.UserRate", b => + modelBuilder.Entity("DevHive.Data.Models.Relational.PostAttachments", b => { b.HasOne("DevHive.Data.Models.Post", "Post") - .WithMany() + .WithMany("Attachments") .HasForeignKey("PostId"); - b.HasOne("DevHive.Data.Models.User", "User") - .WithMany() - .HasForeignKey("UserId"); - b.Navigation("Post"); - - b.Navigation("User"); }); modelBuilder.Entity("DevHive.Data.Models.User", b => @@ -646,7 +581,7 @@ namespace DevHive.Data.Migrations b.Navigation("Comments"); - b.Navigation("Rating"); + b.Navigation("Ratings"); }); modelBuilder.Entity("DevHive.Data.Models.User", b => @@ -658,8 +593,6 @@ namespace DevHive.Data.Migrations b.Navigation("Posts"); b.Navigation("ProfilePicture"); - - b.Navigation("RatedPosts"); }); #pragma warning restore 612, 618 } diff --git a/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs new file mode 100644 index 0000000..5aca664 --- /dev/null +++ b/src/Data/DevHive.Data/Migrations/20210328161726_Profile_Pic_Property_Alter.cs @@ -0,0 +1,526 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +namespace DevHive.Data.Migrations +{ + public partial class Profile_Pic_Property_Alter : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + FirstName = table.Column<string>(type: "text", nullable: true), + LastName = table.Column<string>(type: "text", nullable: true), + UserId = table.Column<Guid>(type: "uuid", nullable: true), + UserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedUserName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + Email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + NormalizedEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true), + EmailConfirmed = table.Column<bool>(type: "boolean", nullable: false), + PasswordHash = table.Column<string>(type: "text", nullable: true), + SecurityStamp = table.Column<string>(type: "text", nullable: true), + ConcurrencyStamp = table.Column<string>(type: "text", nullable: true), + PhoneNumber = table.Column<string>(type: "text", nullable: true), + PhoneNumberConfirmed = table.Column<bool>(type: "boolean", nullable: false), + TwoFactorEnabled = table.Column<bool>(type: "boolean", nullable: false), + LockoutEnd = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true), + LockoutEnabled = table.Column<bool>(type: "boolean", nullable: false), + AccessFailedCount = table.Column<int>(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUsers_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Languages", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Name = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Languages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Technologies", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + Name = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Technologies", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + RoleId = table.Column<Guid>(type: "uuid", nullable: false), + ClaimType = table.Column<string>(type: "text", nullable: true), + ClaimValue = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column<int>(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + ClaimType = table.Column<string>(type: "text", nullable: true), + ClaimValue = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column<string>(type: "text", nullable: false), + ProviderKey = table.Column<string>(type: "text", nullable: false), + ProviderDisplayName = table.Column<string>(type: "text", nullable: true), + UserId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column<Guid>(type: "uuid", nullable: false), + RoleId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column<Guid>(type: "uuid", nullable: false), + LoginProvider = table.Column<string>(type: "text", nullable: false), + Name = table.Column<string>(type: "text", nullable: false), + Value = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Posts", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + CreatorId = table.Column<Guid>(type: "uuid", nullable: true), + Message = table.Column<string>(type: "text", nullable: true), + TimeCreated = table.Column<DateTime>(type: "timestamp without time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Posts", x => x.Id); + table.ForeignKey( + name: "FK_Posts_AspNetUsers_CreatorId", + column: x => x.CreatorId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "ProfilePictures", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + UserId = table.Column<Guid>(type: "uuid", nullable: false), + PictureURL = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ProfilePictures", x => x.Id); + table.ForeignKey( + name: "FK_ProfilePictures_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "RoleUser", + columns: table => new + { + RolesId = table.Column<Guid>(type: "uuid", nullable: false), + UsersId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RoleUser", x => new { x.RolesId, x.UsersId }); + table.ForeignKey( + name: "FK_RoleUser_AspNetRoles_RolesId", + column: x => x.RolesId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_RoleUser_AspNetUsers_UsersId", + column: x => x.UsersId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "LanguageUser", + columns: table => new + { + LanguagesId = table.Column<Guid>(type: "uuid", nullable: false), + UsersId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_LanguageUser", x => new { x.LanguagesId, x.UsersId }); + table.ForeignKey( + name: "FK_LanguageUser_AspNetUsers_UsersId", + column: x => x.UsersId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_LanguageUser_Languages_LanguagesId", + column: x => x.LanguagesId, + principalTable: "Languages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "TechnologyUser", + columns: table => new + { + TechnologiesId = table.Column<Guid>(type: "uuid", nullable: false), + UsersId = table.Column<Guid>(type: "uuid", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_TechnologyUser", x => new { x.TechnologiesId, x.UsersId }); + table.ForeignKey( + name: "FK_TechnologyUser_AspNetUsers_UsersId", + column: x => x.UsersId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_TechnologyUser_Technologies_TechnologiesId", + column: x => x.TechnologiesId, + principalTable: "Technologies", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "Comments", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + PostId = table.Column<Guid>(type: "uuid", nullable: true), + CreatorId = table.Column<Guid>(type: "uuid", nullable: true), + Message = table.Column<string>(type: "text", nullable: true), + TimeCreated = table.Column<DateTime>(type: "timestamp without time zone", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Comments", x => x.Id); + table.ForeignKey( + name: "FK_Comments_AspNetUsers_CreatorId", + column: x => x.CreatorId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Comments_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "PostAttachments", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + PostId = table.Column<Guid>(type: "uuid", nullable: true), + FileUrl = table.Column<string>(type: "text", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PostAttachments", x => x.Id); + table.ForeignKey( + name: "FK_PostAttachments_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "Rating", + columns: table => new + { + Id = table.Column<Guid>(type: "uuid", nullable: false), + UserId = table.Column<Guid>(type: "uuid", nullable: true), + PostId = table.Column<Guid>(type: "uuid", nullable: true), + IsLike = table.Column<bool>(type: "boolean", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Rating", x => x.Id); + table.ForeignKey( + name: "FK_Rating_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_Rating_Posts_PostId", + column: x => x.PostId, + principalTable: "Posts", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_UserId", + table: "AspNetUsers", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUsers_UserName", + table: "AspNetUsers", + column: "UserName", + unique: true); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Comments_CreatorId", + table: "Comments", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_Comments_PostId", + table: "Comments", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_LanguageUser_UsersId", + table: "LanguageUser", + column: "UsersId"); + + migrationBuilder.CreateIndex( + name: "IX_PostAttachments_PostId", + table: "PostAttachments", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_Posts_CreatorId", + table: "Posts", + column: "CreatorId"); + + migrationBuilder.CreateIndex( + name: "IX_ProfilePictures_UserId", + table: "ProfilePictures", + column: "UserId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_Rating_PostId", + table: "Rating", + column: "PostId"); + + migrationBuilder.CreateIndex( + name: "IX_Rating_UserId", + table: "Rating", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_RoleUser_UsersId", + table: "RoleUser", + column: "UsersId"); + + migrationBuilder.CreateIndex( + name: "IX_TechnologyUser_UsersId", + table: "TechnologyUser", + column: "UsersId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "Comments"); + + migrationBuilder.DropTable( + name: "LanguageUser"); + + migrationBuilder.DropTable( + name: "PostAttachments"); + + migrationBuilder.DropTable( + name: "ProfilePictures"); + + migrationBuilder.DropTable( + name: "Rating"); + + migrationBuilder.DropTable( + name: "RoleUser"); + + migrationBuilder.DropTable( + name: "TechnologyUser"); + + migrationBuilder.DropTable( + name: "Languages"); + + migrationBuilder.DropTable( + name: "Posts"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "Technologies"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs index 3b328c6..242473b 100644 --- a/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs +++ b/src/Data/DevHive.Data/Migrations/DevHiveContextModelSnapshot.cs @@ -99,7 +99,7 @@ namespace DevHive.Data.Migrations b.HasIndex("UserId") .IsUnique(); - b.ToTable("ProfilePicture"); + b.ToTable("ProfilePictures"); }); modelBuilder.Entity("DevHive.Data.Models.Rating", b => diff --git a/src/Data/DevHive.Data/Repositories/PostRepository.cs b/src/Data/DevHive.Data/Repositories/PostRepository.cs index 0a88cf2..b5228c2 100644 --- a/src/Data/DevHive.Data/Repositories/PostRepository.cs +++ b/src/Data/DevHive.Data/Repositories/PostRepository.cs @@ -60,7 +60,6 @@ namespace DevHive.Data.Repositories public override async Task<bool> EditAsync(Guid id, Post newEntity) { Post post = await this.GetByIdAsync(id); - // var ratingId = post.Rating.Id; this._context .Entry(post) @@ -76,8 +75,6 @@ namespace DevHive.Data.Repositories foreach (var comment in newEntity.Comments) post.Comments.Add(comment); - // post.Rating.Id = ratingId; - this._context.Entry(post).State = EntityState.Modified; return await this.SaveChangesAsync(); diff --git a/src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs b/src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs new file mode 100644 index 0000000..7284464 --- /dev/null +++ b/src/Data/DevHive.Data/Repositories/ProfilePictureRepository.cs @@ -0,0 +1,25 @@ +using System.Threading.Tasks; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using Microsoft.EntityFrameworkCore; + +namespace DevHive.Data.Repositories +{ + public class ProfilePictureRepository : BaseRepository<ProfilePicture>, IProfilePictureRepository + { + private readonly DevHiveContext _context; + + public ProfilePictureRepository(DevHiveContext context) + : base(context) + { + this._context = context; + } + + public async Task<ProfilePicture> GetByURLAsync(string picUrl) + { + return await this._context + .ProfilePicture + .FirstOrDefaultAsync(x => x.PictureURL == picUrl); + } + } +} diff --git a/src/Data/DevHive.Data/Repositories/RatingRepository.cs b/src/Data/DevHive.Data/Repositories/RatingRepository.cs index c35f6d5..2048c3f 100644 --- a/src/Data/DevHive.Data/Repositories/RatingRepository.cs +++ b/src/Data/DevHive.Data/Repositories/RatingRepository.cs @@ -11,13 +11,11 @@ namespace DevHive.Data.Repositories public class RatingRepository : BaseRepository<Rating>, IRatingRepository { private readonly DevHiveContext _context; - private readonly IPostRepository _postRepository; - public RatingRepository(DevHiveContext context, IPostRepository postRepository) + public RatingRepository(DevHiveContext context) : base(context) { this._context = context; - this._postRepository = postRepository; } public override async Task<Rating> GetByIdAsync(Guid id) @@ -28,7 +26,7 @@ namespace DevHive.Data.Repositories .FirstOrDefaultAsync(x => x.Id == id); } /// <summary> - /// Gets all the ratings for a psot. + /// Gets all the ratings for a post. /// </summary> /// <param name="postId">Id of the post.</param> /// <returns></returns> @@ -40,10 +38,10 @@ namespace DevHive.Data.Repositories .Where(x => x.Post.Id == postId).ToListAsync(); } /// <summary> - /// Checks if a user rated a given post. In DevHive every user has one or no rating for every post. + /// Checks if a user rated a given post. In DevHive every user has one or no rating for every post. /// </summary> /// <param name="userId">Id of the user.</param> - /// <param name="postId">Id of the psot.</param> + /// <param name="postId">Id of the post.</param> /// <returns>True if the user has already rated the post and false if he hasn't.</returns> public async Task<bool> UserRatedPost(Guid userId, Guid postId) { diff --git a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj index a55972a..2345a8e 100644 --- a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj +++ b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj @@ -4,7 +4,7 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/> diff --git a/src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs b/src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs new file mode 100644 index 0000000..5e69d13 --- /dev/null +++ b/src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs @@ -0,0 +1,11 @@ +using System; +using Microsoft.AspNetCore.Http; + +namespace DevHive.Services.Models.ProfilePicture +{ + public class ProfilePictureServiceModel + { + public Guid UserId { get; set; } + public IFormFile ProfilePictureFormFile { get; set; } + } +} diff --git a/src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs b/src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs deleted file mode 100644 index cbe64b2..0000000 --- a/src/Services/DevHive.Services.Models/User/ProfilePictureServiceModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DevHive.Services.Models.User -{ - public class ProfilePictureServiceModel - { - public string ProfilePictureURL { get; set; } - } -} diff --git a/src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs b/src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs deleted file mode 100644 index 19ba08f..0000000 --- a/src/Services/DevHive.Services.Models/User/UpdateProfilePictureServiceModel.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; - -namespace DevHive.Services.Models.User -{ - public class UpdateProfilePictureServiceModel - { - public Guid UserId { get; set; } - - public IFormFile Picture { get; set; } - } -} diff --git a/src/Services/DevHive.Services.Models/User/UserServiceModel.cs b/src/Services/DevHive.Services.Models/User/UserServiceModel.cs index 04b618b..f48c703 100644 --- a/src/Services/DevHive.Services.Models/User/UserServiceModel.cs +++ b/src/Services/DevHive.Services.Models/User/UserServiceModel.cs @@ -8,7 +8,7 @@ namespace DevHive.Services.Models.User { public class UserServiceModel : BaseUserServiceModel { - public string ProfilePictureURL { get; set; } + public string ProfilePictureURL { get; set; } = new(string.Empty); public HashSet<RoleServiceModel> Roles { get; set; } = new(); diff --git a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj index d85eea2..4a7237b 100644 --- a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj +++ b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj @@ -4,12 +4,12 @@ <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.3"/> + <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.4"/> <PackageReference Include="Moq" Version="4.16.1"/> <PackageReference Include="NUnit" Version="3.13.1"/> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\DevHive.Services\DevHive.Services.csproj"/> diff --git a/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs b/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs new file mode 100644 index 0000000..a7a2963 --- /dev/null +++ b/src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs @@ -0,0 +1,84 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using DevHive.Data; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Data.Repositories; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using DevHive.Services.Services; +using Microsoft.AspNetCore.Http; +using Microsoft.EntityFrameworkCore; +using Moq; +using NUnit.Framework; + +namespace DevHive.Services.Tests +{ + [TestFixture] + public class ProfilePictureServiceTests + { + private DevHiveContext _context; + private Mock<IUserRepository> _userRepositoryMock; + private Mock<ProfilePictureRepository> _profilePictureRepository; + private Mock<ICloudService> _cloudService; + private ProfilePictureService _profilePictureService; + + [SetUp] + public void Setup() + { + DbContextOptionsBuilder<DevHiveContext> options = new DbContextOptionsBuilder<DevHiveContext>() + .UseInMemoryDatabase("DevHive_UserRepository_Database"); + this._context = new DevHiveContext(options.Options); + this._userRepositoryMock = new Mock<IUserRepository>(); + this._profilePictureRepository = new Mock<ProfilePictureRepository>(this._context); + this._cloudService = new Mock<ICloudService>(); + + this._profilePictureService = new ProfilePictureService( + this._userRepositoryMock.Object, + this._profilePictureRepository.Object, + this._cloudService.Object + ); + } + + [Test] + public async Task InsertProfilePicture_ShouldInsertProfilePicToDatabaseAndUploadToCloud() + { + //Arrange + Guid userId = Guid.NewGuid(); + Mock<IFormFile> fileMock = new(); + + //File mocking setup + var content = "Hello World from a Fake File"; + var fileName = "test.jpg"; + var ms = new MemoryStream(); + var writer = new StreamWriter(ms); + writer.Write(content); + writer.Flush(); + ms.Position = 0; + fileMock.Setup(p => p.FileName).Returns(fileName); + fileMock.Setup(p => p.Length).Returns(ms.Length); + fileMock.Setup(p => p.OpenReadStream()).Returns(ms); + + //User Setup + this._userRepositoryMock + .Setup(p => p.GetByIdAsync(userId)) + .ReturnsAsync(new User() + { + Id = userId + }); + + ProfilePictureServiceModel profilePictureServiceModel = new() + { + UserId = userId, + ProfilePictureFormFile = fileMock.Object + }; + + //Act + string profilePicURL = await this._profilePictureService.InsertProfilePicture(profilePictureServiceModel); + + //Assert + Assert.IsNotEmpty(profilePicURL); + } + } +} diff --git a/src/Services/DevHive.Services.Tests/UserService.Tests.cs b/src/Services/DevHive.Services.Tests/UserService.Tests.cs index 7990b32..9d1bca5 100644 --- a/src/Services/DevHive.Services.Tests/UserService.Tests.cs +++ b/src/Services/DevHive.Services.Tests/UserService.Tests.cs @@ -344,7 +344,7 @@ namespace DevHive.Services.Tests // } // else // { - // const string EXCEPTION_MESSAGE = "Unable to edit user!"; + // const string EXCEPTION_MESSAGE = string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower()); // // Exception ex = Assert.ThrowsAsync<InvalidOperationException>(() => this._userService.UpdateUser(updateUserServiceModel); // diff --git a/src/Services/DevHive.Services/DevHive.Services.csproj b/src/Services/DevHive.Services/DevHive.Services.csproj index f51c1b6..2468711 100644 --- a/src/Services/DevHive.Services/DevHive.Services.csproj +++ b/src/Services/DevHive.Services/DevHive.Services.csproj @@ -4,15 +4,15 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> - <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0"/> + <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0"/> <PackageReference Include="AutoMapper" Version="10.1.1"/> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/> - <PackageReference Include="CloudinaryDotNet" Version="1.14.0"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="CloudinaryDotNet" Version="1.15.1"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\Data\DevHive.Data\DevHive.Data.csproj"/> diff --git a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs new file mode 100644 index 0000000..edf2775 --- /dev/null +++ b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading.Tasks; +using DevHive.Services.Models.ProfilePicture; + +namespace DevHive.Services.Interfaces +{ + public interface IProfilePictureService + { + /// <summary> + /// Get a profile picture by it's Guid + /// </summary> + /// <param name="id">Profile picture's Guid</param> + /// <returns>The profile picture's URL in the cloud</returns> + Task<string> GetProfilePictureById(Guid id); + + /// <summary> + /// Uploads the given picture and assigns it's link to the user in the database + /// </summary> + /// <param name="profilePictureServiceModel">Contains User's Guid and the new picture to be updated</param> + /// <returns>The new profile picture's URL in the cloud</returns> + Task<string> UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); + + /// <summary> + /// Delete a profile picture from the cloud and the database + /// </summary> + /// <param name="id">The profile picture's Guid</param> + /// <returns>True if the picture is deleted, false otherwise</returns> + Task<bool> DeleteProfilePicture(Guid id); + } +} diff --git a/src/Services/DevHive.Services/Interfaces/IUserService.cs b/src/Services/DevHive.Services/Interfaces/IUserService.cs index a55f9dd..da07507 100644 --- a/src/Services/DevHive.Services/Interfaces/IUserService.cs +++ b/src/Services/DevHive.Services/Interfaces/IUserService.cs @@ -45,14 +45,6 @@ namespace DevHive.Services.Interfaces Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel); /// <summary> - /// Uploads the given picture and assigns it's link to the user in the database - /// Requires authenticated user - /// </summary> - /// <param name="updateProfilePictureServiceModel">Contains User's Guid and the new picture to be updated</param> - /// <returns>The new picture's URL</returns> - Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel); - - /// <summary> /// Deletes a user from the database and removes his data entirely /// Requires authenticated user /// </summary> diff --git a/src/Services/DevHive.Services/Services/CloudinaryService.cs b/src/Services/DevHive.Services/Services/CloudinaryService.cs index 57955a2..078bb5d 100644 --- a/src/Services/DevHive.Services/Services/CloudinaryService.cs +++ b/src/Services/DevHive.Services/Services/CloudinaryService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudinaryDotNet; using CloudinaryDotNet.Actions; @@ -11,6 +12,10 @@ namespace DevHive.Services.Services { public class CloudinaryService : ICloudService { + // Regex for getting the filename without (final) filename extension + // So, from image.png, it will match image, and from doc.my.txt will match doc.my + private static readonly Regex s_imageRegex = new(".*(?=\\.)"); + private readonly Cloudinary _cloudinary; public CloudinaryService(string cloudName, string apiKey, string apiSecret) @@ -23,23 +28,21 @@ namespace DevHive.Services.Services List<string> fileUrls = new(); foreach (var formFile in formFiles) { - string formFileId = Guid.NewGuid().ToString(); + string fileName = s_imageRegex.Match(formFile.FileName).ToString(); + + using var ms = new MemoryStream(); + formFile.CopyTo(ms); + byte[] formBytes = ms.ToArray(); - using (var ms = new MemoryStream()) + RawUploadParams rawUploadParams = new() { - formFile.CopyTo(ms); - byte[] formBytes = ms.ToArray(); - - RawUploadParams rawUploadParams = new() - { - File = new FileDescription(formFileId, new MemoryStream(formBytes)), - PublicId = formFileId, - UseFilename = true - }; - - RawUploadResult rawUploadResult = await this._cloudinary.UploadAsync(rawUploadParams); - fileUrls.Add(rawUploadResult.Url.AbsoluteUri); - } + File = new FileDescription(fileName, new MemoryStream(formBytes)), + PublicId = fileName, + UseFilename = true + }; + + RawUploadResult rawUploadResult = await this._cloudinary.UploadAsync(rawUploadParams); + fileUrls.Add(rawUploadResult.Url.AbsoluteUri); } return fileUrls; @@ -47,6 +50,9 @@ namespace DevHive.Services.Services public async Task<bool> RemoveFilesFromCloud(List<string> fileUrls) { + // Workaround, this method isn't fully implemented yet + await Task.Run(null); + return true; } } diff --git a/src/Services/DevHive.Services/Services/CommentService.cs b/src/Services/DevHive.Services/Services/CommentService.cs index b48bac8..1c388f6 100644 --- a/src/Services/DevHive.Services/Services/CommentService.cs +++ b/src/Services/DevHive.Services/Services/CommentService.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; +using DevHive.Data.Interfaces; using DevHive.Data.Models; -using DevHive.Services.Models.Comment; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; using DevHive.Services.Interfaces; -using DevHive.Data.Interfaces; -using System.Linq; +using DevHive.Services.Models.Comment; namespace DevHive.Services.Services { @@ -31,7 +32,7 @@ namespace DevHive.Services.Services public async Task<Guid> AddComment(CreateCommentServiceModel createCommentServiceModel) { if (!await this._postRepository.DoesPostExist(createCommentServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Comment comment = this._postMapper.Map<Comment>(createCommentServiceModel); comment.TimeCreated = DateTime.Now; @@ -56,10 +57,10 @@ namespace DevHive.Services.Services public async Task<ReadCommentServiceModel> GetCommentById(Guid id) { Comment comment = await this._commentRepository.GetByIdAsync(id) ?? - throw new ArgumentException("The comment does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); User user = await this._userRepository.GetByIdAsync(comment.Creator.Id) ?? - throw new ArgumentException("The user does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); ReadCommentServiceModel readCommentServiceModel = this._postMapper.Map<ReadCommentServiceModel>(comment); readCommentServiceModel.IssuerFirstName = user.FirstName; @@ -74,7 +75,7 @@ namespace DevHive.Services.Services public async Task<Guid> UpdateComment(UpdateCommentServiceModel updateCommentServiceModel) { if (!await this._commentRepository.DoesCommentExist(updateCommentServiceModel.CommentId)) - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); Comment comment = this._postMapper.Map<Comment>(updateCommentServiceModel); comment.TimeCreated = DateTime.Now; @@ -95,7 +96,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteComment(Guid id) { if (!await this._commentRepository.DoesCommentExist(id)) - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); Comment comment = await this._commentRepository.GetByIdAsync(id); return await this._commentRepository.DeleteAsync(comment); @@ -121,7 +122,7 @@ namespace DevHive.Services.Services public async Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData) { Comment comment = await this._commentRepository.GetByIdAsync(commentId) ?? - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); User user = await this.GetUserForValidation(rawTokenData); //If user made the comment @@ -141,10 +142,10 @@ namespace DevHive.Services.Services { JwtSecurityToken jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7)); - Guid jwtUserId = Guid.Parse(this.GetClaimTypeValues("ID", jwt.Claims).First()); + Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First()); User user = await this._userRepository.GetByIdAsync(jwtUserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return user; } @@ -152,7 +153,7 @@ namespace DevHive.Services.Services /// <summary> /// Returns all values from a given claim type /// </summary> - private List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims) + private static List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims) { List<string> toReturn = new(); diff --git a/src/Services/DevHive.Services/Services/FeedService.cs b/src/Services/DevHive.Services/Services/FeedService.cs index 0af8093..9c622b3 100644 --- a/src/Services/DevHive.Services/Services/FeedService.cs +++ b/src/Services/DevHive.Services/Services/FeedService.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -26,10 +28,11 @@ namespace DevHive.Services.Services /// <summary> /// This method is used in the feed page. - /// See the FeedRepository "GetFriendsPosts" menthod for more information on how it works. + /// See the FeedRepository "GetFriendsPosts" method for more information on how it works. /// </summary> public async Task<ReadPageServiceModel> GetPage(GetPageServiceModel getPageServiceModel) { + //TODO: Rework the initialization of User User user = null; if (getPageServiceModel.UserId != Guid.Empty) @@ -37,10 +40,10 @@ namespace DevHive.Services.Services else if (!string.IsNullOrEmpty(getPageServiceModel.Username)) user = await this._userRepository.GetByUsernameAsync(getPageServiceModel.Username); else - throw new ArgumentException("Invalid given data!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); if (user == null) - throw new ArgumentException("User doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); List<Post> posts = await this._feedRepository .GetFriendsPosts(user.Friends.ToList(), getPageServiceModel.FirstRequestIssued, getPageServiceModel.PageNumber, getPageServiceModel.PageSize); @@ -58,15 +61,16 @@ namespace DevHive.Services.Services /// </summary> public async Task<ReadPageServiceModel> GetUserPage(GetPageServiceModel model) { + //TODO: Rework the initialization of User User user = null; if (!string.IsNullOrEmpty(model.Username)) user = await this._userRepository.GetByUsernameAsync(model.Username); else - throw new ArgumentException("Invalid given data!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); if (user == null) - throw new ArgumentException("User doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); List<Post> posts = await this._feedRepository .GetUsersPosts(user, model.FirstRequestIssued, model.PageNumber, model.PageSize); diff --git a/src/Services/DevHive.Services/Services/LanguageService.cs b/src/Services/DevHive.Services/Services/LanguageService.cs index 9d2041e..7ee7d9f 100644 --- a/src/Services/DevHive.Services/Services/LanguageService.cs +++ b/src/Services/DevHive.Services/Services/LanguageService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -24,7 +26,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreateLanguage(CreateLanguageServiceModel createLanguageServiceModel) { if (await this._languageRepository.DoesLanguageNameExistAsync(createLanguageServiceModel.Name)) - throw new ArgumentException("Language already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); Language language = this._languageMapper.Map<Language>(createLanguageServiceModel); bool success = await this._languageRepository.AddAsync(language); @@ -45,7 +47,7 @@ namespace DevHive.Services.Services Language language = await this._languageRepository.GetByIdAsync(id); if (language == null) - throw new ArgumentException("The language does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language)); return this._languageMapper.Map<ReadLanguageServiceModel>(language); } @@ -65,10 +67,10 @@ namespace DevHive.Services.Services bool newLangNameExists = await this._languageRepository.DoesLanguageNameExistAsync(languageServiceModel.Name); if (!langExists) - throw new ArgumentException("Language does not exist!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); if (newLangNameExists) - throw new ArgumentException("Language name already exists in our data base!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); Language lang = this._languageMapper.Map<Language>(languageServiceModel); return await this._languageRepository.EditAsync(languageServiceModel.Id, lang); @@ -79,7 +81,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteLanguage(Guid id) { if (!await this._languageRepository.DoesLanguageExistAsync(id)) - throw new ArgumentException("Language does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language)); Language language = await this._languageRepository.GetByIdAsync(id); return await this._languageRepository.DeleteAsync(language); diff --git a/src/Services/DevHive.Services/Services/PostService.cs b/src/Services/DevHive.Services/Services/PostService.cs index a565473..8580e82 100644 --- a/src/Services/DevHive.Services/Services/PostService.cs +++ b/src/Services/DevHive.Services/Services/PostService.cs @@ -1,15 +1,16 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; -using AutoMapper; -using DevHive.Data.Models; -using DevHive.Services.Models.Post; using System.IdentityModel.Tokens.Jwt; +using System.Linq; using System.Security.Claims; -using DevHive.Services.Interfaces; +using System.Threading.Tasks; +using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; -using System.Linq; +using DevHive.Data.Models; using DevHive.Data.Models.Relational; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.Post; namespace DevHive.Services.Services { @@ -34,7 +35,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreatePost(CreatePostServiceModel createPostServiceModel) { if (!await this._userRepository.DoesUserExistAsync(createPostServiceModel.CreatorId)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); Post post = this._postMapper.Map<Post>(createPostServiceModel); @@ -66,7 +67,7 @@ namespace DevHive.Services.Services public async Task<ReadPostServiceModel> GetPostById(Guid id) { Post post = await this._postRepository.GetByIdAsync(id) ?? - throw new ArgumentException("The post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); // This can't happen in repo, because of how time is usually compared post.Comments = post.Comments @@ -74,7 +75,7 @@ namespace DevHive.Services.Services .ToList(); User user = await this._userRepository.GetByIdAsync(post.Creator.Id) ?? - throw new ArgumentException("The user does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); int currentRating = 0; foreach (Rating rating in post.Ratings) @@ -100,7 +101,7 @@ namespace DevHive.Services.Services public async Task<Guid> UpdatePost(UpdatePostServiceModel updatePostServiceModel) { if (!await this._postRepository.DoesPostExist(updatePostServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Post post = this._postMapper.Map<Post>(updatePostServiceModel); @@ -111,11 +112,11 @@ namespace DevHive.Services.Services List<string> fileUrlsToRemove = await this._postRepository.GetFileUrls(updatePostServiceModel.PostId); bool success = await _cloudService.RemoveFilesFromCloud(fileUrlsToRemove); if (!success) - throw new InvalidCastException("Could not delete files from the post!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower())); } List<string> fileUrls = await _cloudService.UploadFilesToCloud(updatePostServiceModel.Files) ?? - throw new ArgumentException("Unable to upload images to cloud!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower())); post.Attachments = GetPostAttachmentsFromUrls(post, fileUrls); } @@ -136,7 +137,7 @@ namespace DevHive.Services.Services public async Task<bool> DeletePost(Guid id) { if (!await this._postRepository.DoesPostExist(id)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Post post = await this._postRepository.GetByIdAsync(id); @@ -145,7 +146,7 @@ namespace DevHive.Services.Services List<string> fileUrls = await this._postRepository.GetFileUrls(id); bool success = await _cloudService.RemoveFilesFromCloud(fileUrls); if (!success) - throw new InvalidCastException("Could not delete files from the post. Please try again"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower())); } return await this._postRepository.DeleteAsync(post); @@ -158,7 +159,7 @@ namespace DevHive.Services.Services /// </summary> public async Task<bool> ValidateJwtForCreating(Guid userId, string rawTokenData) { - User user = await this.GetUserForValidation(rawTokenData); + User user = await GetUserForValidation(rawTokenData); return user.Id == userId; } @@ -171,8 +172,8 @@ namespace DevHive.Services.Services public async Task<bool> ValidateJwtForPost(Guid postId, string rawTokenData) { Post post = await this._postRepository.GetByIdAsync(postId) ?? - throw new ArgumentException("Post does not exist!"); - User user = await this.GetUserForValidation(rawTokenData); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); + User user = await GetUserForValidation(rawTokenData); //If user made the post if (post.Creator.Id == user.Id) @@ -192,8 +193,8 @@ namespace DevHive.Services.Services public async Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData) { Comment comment = await this._commentRepository.GetByIdAsync(commentId) ?? - throw new ArgumentException("Comment does not exist!"); - User user = await this.GetUserForValidation(rawTokenData); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); + User user = await GetUserForValidation(rawTokenData); //If user made the comment if (comment.Creator.Id == user.Id) @@ -215,7 +216,7 @@ namespace DevHive.Services.Services Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First()); User user = await this._userRepository.GetByIdAsync(jwtUserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return user; } diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs new file mode 100644 index 0000000..cafa7cb --- /dev/null +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using DevHive.Common.Constants; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using Microsoft.AspNetCore.Http; + +namespace DevHive.Services.Services +{ + public class ProfilePictureService : IProfilePictureService + { + private readonly IUserRepository _userRepository; + private readonly IProfilePictureRepository _profilePictureRepository; + private readonly ICloudService _cloudinaryService; + + public ProfilePictureService(IUserRepository userRepository, IProfilePictureRepository profilePictureRepository, ICloudService cloudinaryService) + { + this._userRepository = userRepository; + this._profilePictureRepository = profilePictureRepository; + this._cloudinaryService = cloudinaryService; + } + + public async Task<string> GetProfilePictureById(Guid id) + { + return (await this._profilePictureRepository.GetByIdAsync(id)).PictureURL; + } + + public async Task<string> UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) + { + ValidateProfPic(profilePictureServiceModel.ProfilePictureFormFile); + await ValidateUserExistsAsync(profilePictureServiceModel.UserId); + + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + if (user.ProfilePicture.Id != Guid.Empty) + { + List<string> file = new() { user.ProfilePicture.PictureURL }; + bool removed = await this._cloudinaryService.RemoveFilesFromCloud(file); + + if (!removed) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); + } + + return await SaveProfilePictureInDatabase(profilePictureServiceModel); + } + + public async Task<bool> DeleteProfilePicture(Guid id) + { + ProfilePicture profilePic = await this._profilePictureRepository.GetByIdAsync(id) ?? + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Picture)); + + bool removedFromDb = await this._profilePictureRepository.DeleteAsync(profilePic); + if (!removedFromDb) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); + + List<string> file = new() { profilePic.PictureURL }; + bool removedFromCloud = await this._cloudinaryService.RemoveFilesFromCloud(file); + if (!removedFromCloud) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); + + return true; + } + + private async Task<string> SaveProfilePictureInDatabase(ProfilePictureServiceModel profilePictureServiceModel) + { + List<IFormFile> file = new() { profilePictureServiceModel.ProfilePictureFormFile }; + string picUrl = (await this._cloudinaryService.UploadFilesToCloud(file))[0]; + ProfilePicture profilePic = new() { PictureURL = picUrl }; + + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + profilePic.UserId = user.Id; + profilePic.User = user; + + bool success = await this._profilePictureRepository.AddAsync(profilePic); + if (!success) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower())); + + user.ProfilePicture = profilePic; + bool userProfilePicAlter = await this._userRepository.EditAsync(user.Id, user); + + if (!userProfilePicAlter) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, "user's profile picture")); + + return picUrl; + } + + private static void ValidateProfPic(IFormFile profilePictureFormFile) + { + if (profilePictureFormFile.Length == 0) + throw new ArgumentNullException(nameof(profilePictureFormFile), string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); + } + + private async Task ValidateUserExistsAsync(Guid userId) + { + if (!await this._userRepository.DoesUserExistAsync(userId)) + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); + } + } +} diff --git a/src/Services/DevHive.Services/Services/RatingService.cs b/src/Services/DevHive.Services/Services/RatingService.cs index 1f77a6e..d6b4299 100644 --- a/src/Services/DevHive.Services/Services/RatingService.cs +++ b/src/Services/DevHive.Services/Services/RatingService.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -19,6 +16,8 @@ namespace DevHive.Services.Services private readonly IRatingRepository _ratingRepository; private readonly IMapper _mapper; + private const string NotRated = "{0} has not rated" + ClassesConstants.Post; + public RatingService(IPostRepository postRepository, IRatingRepository ratingRepository, IUserRepository userRepository, IMapper mapper) { this._postRepository = postRepository; @@ -31,7 +30,7 @@ namespace DevHive.Services.Services public async Task<Guid> RatePost(CreateRatingServiceModel createRatingServiceModel) { if (!await this._postRepository.DoesPostExist(createRatingServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); if (await this._ratingRepository.UserRatedPost(createRatingServiceModel.UserId, createRatingServiceModel.PostId)) throw new ArgumentException("User already rated the post!"); @@ -57,8 +56,9 @@ namespace DevHive.Services.Services #region Read public async Task<ReadRatingServiceModel> GetRatingById(Guid ratingId) { - Rating rating = await this._ratingRepository.GetByIdAsync(ratingId) ?? - throw new ArgumentException("The rating does not exist"); + Rating rating = await this._ratingRepository.GetByIdAsync(ratingId); + if (rating is null) + return null; ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating); readRatingServiceModel.UserId = rating.User.Id; @@ -68,8 +68,9 @@ namespace DevHive.Services.Services public async Task<ReadRatingServiceModel> GetRatingByPostAndUser(Guid userId, Guid postId) { - Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId) ?? - throw new ArgumentException("The rating does not exist"); + Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId); + if (rating is null) + return null; ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating); readRatingServiceModel.UserId = rating.User.Id; @@ -82,13 +83,13 @@ namespace DevHive.Services.Services public async Task<ReadRatingServiceModel> UpdateRating(UpdateRatingServiceModel updateRatingServiceModel) { Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId) ?? - throw new ArgumentException("Rating does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating)); User user = await this._userRepository.GetByIdAsync(updateRatingServiceModel.UserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); if (!await this._ratingRepository.UserRatedPost(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId)) - throw new ArgumentException("User has not rated the post!"); + throw new ArgumentException(string.Format(NotRated, ClassesConstants.User)); rating.User = user; rating.IsLike = updateRatingServiceModel.IsLike; @@ -109,7 +110,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteRating(Guid ratingId) { if (!await this._ratingRepository.DoesRatingExist(ratingId)) - throw new ArgumentException("Rating does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating)); Rating rating = await this._ratingRepository.GetByIdAsync(ratingId); return await this._ratingRepository.DeleteAsync(rating); diff --git a/src/Services/DevHive.Services/Services/RoleService.cs b/src/Services/DevHive.Services/Services/RoleService.cs index a5da759..f61181a 100644 --- a/src/Services/DevHive.Services/Services/RoleService.cs +++ b/src/Services/DevHive.Services/Services/RoleService.cs @@ -1,6 +1,8 @@ using System; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -22,7 +24,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreateRole(CreateRoleServiceModel createRoleServiceModel) { if (await this._roleRepository.DoesNameExist(createRoleServiceModel.Name)) - throw new ArgumentException("Role already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role)); Role role = this._roleMapper.Map<Role>(createRoleServiceModel); bool success = await this._roleRepository.AddAsync(role); @@ -40,7 +42,7 @@ namespace DevHive.Services.Services public async Task<RoleServiceModel> GetRoleById(Guid id) { Role role = await this._roleRepository.GetByIdAsync(id) ?? - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); return this._roleMapper.Map<RoleServiceModel>(role); } @@ -48,10 +50,10 @@ namespace DevHive.Services.Services public async Task<bool> UpdateRole(UpdateRoleServiceModel updateRoleServiceModel) { if (!await this._roleRepository.DoesRoleExist(updateRoleServiceModel.Id)) - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); if (await this._roleRepository.DoesNameExist(updateRoleServiceModel.Name)) - throw new ArgumentException("Role name already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role)); Role role = this._roleMapper.Map<Role>(updateRoleServiceModel); return await this._roleRepository.EditAsync(updateRoleServiceModel.Id, role); @@ -60,7 +62,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteRole(Guid id) { if (!await this._roleRepository.DoesRoleExist(id)) - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); Role role = await this._roleRepository.GetByIdAsync(id); return await this._roleRepository.DeleteAsync(role); diff --git a/src/Services/DevHive.Services/Services/TechnologyService.cs b/src/Services/DevHive.Services/Services/TechnologyService.cs index 09c4d20..4cf84c5 100644 --- a/src/Services/DevHive.Services/Services/TechnologyService.cs +++ b/src/Services/DevHive.Services/Services/TechnologyService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -24,7 +26,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreateTechnology(CreateTechnologyServiceModel technologyServiceModel) { if (await this._technologyRepository.DoesTechnologyNameExistAsync(technologyServiceModel.Name)) - throw new ArgumentException("Technology already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology)); Technology technology = this._technologyMapper.Map<Technology>(technologyServiceModel); bool success = await this._technologyRepository.AddAsync(technology); @@ -45,7 +47,7 @@ namespace DevHive.Services.Services Technology technology = await this._technologyRepository.GetByIdAsync(id); if (technology == null) - throw new ArgumentException("The technology does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); return this._technologyMapper.Map<ReadTechnologyServiceModel>(technology); } @@ -62,10 +64,10 @@ namespace DevHive.Services.Services public async Task<bool> UpdateTechnology(UpdateTechnologyServiceModel updateTechnologyServiceModel) { if (!await this._technologyRepository.DoesTechnologyExistAsync(updateTechnologyServiceModel.Id)) - throw new ArgumentException("Technology does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); if (await this._technologyRepository.DoesTechnologyNameExistAsync(updateTechnologyServiceModel.Name)) - throw new ArgumentException("Technology name already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology)); Technology technology = this._technologyMapper.Map<Technology>(updateTechnologyServiceModel); bool result = await this._technologyRepository.EditAsync(updateTechnologyServiceModel.Id, technology); @@ -78,7 +80,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteTechnology(Guid id) { if (!await this._technologyRepository.DoesTechnologyExistAsync(id)) - throw new ArgumentException("Technology does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); Technology technology = await this._technologyRepository.GetByIdAsync(id); bool result = await this._technologyRepository.DeleteAsync(technology); diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs index 4f74b06..62576d4 100644 --- a/src/Services/DevHive.Services/Services/UserService.cs +++ b/src/Services/DevHive.Services/Services/UserService.cs @@ -1,15 +1,17 @@ -using AutoMapper; -using DevHive.Services.Models.User; -using System.Threading.Tasks; -using DevHive.Data.Models; using System; using System.Collections.Generic; -using DevHive.Common.Models.Identity; -using DevHive.Services.Interfaces; -using DevHive.Data.Interfaces; +using System.Data; +using System.IO; using System.Linq; -using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using AutoMapper; +using DevHive.Common.Constants; using DevHive.Common.Jwt.Interfaces; +using DevHive.Common.Models.Identity; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.User; namespace DevHive.Services.Services { @@ -20,15 +22,17 @@ namespace DevHive.Services.Services private readonly ILanguageRepository _languageRepository; private readonly ITechnologyRepository _technologyRepository; private readonly IMapper _userMapper; - private readonly ICloudService _cloudService; private readonly IJwtService _jwtService; + private const string NoYourselfAsFriend = "You cant add yourself as a friend(sry, bro)!"; + private const string Rant = "Can't promote shit in this country..."; + + public UserService(IUserRepository userRepository, ILanguageRepository languageRepository, IRoleRepository roleRepository, ITechnologyRepository technologyRepository, IMapper mapper, - ICloudService cloudService, IJwtService jwtService) { this._userRepository = userRepository; @@ -36,7 +40,6 @@ namespace DevHive.Services.Services this._userMapper = mapper; this._languageRepository = languageRepository; this._technologyRepository = technologyRepository; - this._cloudService = cloudService; this._jwtService = jwtService; } @@ -44,12 +47,12 @@ namespace DevHive.Services.Services public async Task<TokenModel> LoginUser(LoginServiceModel loginModel) { if (!await this._userRepository.DoesUsernameExistAsync(loginModel.UserName)) - throw new ArgumentException("Invalid username!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Username)); User user = await this._userRepository.GetByUsernameAsync(loginModel.UserName); if (!await this._userRepository.VerifyPassword(user, loginModel.Password)) - throw new ArgumentException("Incorrect password!"); + throw new InvalidDataException(string.Format(ErrorMessages.IncorrectData, ClassesConstants.Password.ToLower())); List<string> roleNames = user.Roles.Select(x => x.Name).ToList(); return new TokenModel(this._jwtService.GenerateJwtToken(user.Id, user.UserName, roleNames)); @@ -58,10 +61,11 @@ namespace DevHive.Services.Services public async Task<TokenModel> RegisterUser(RegisterServiceModel registerModel) { if (await this._userRepository.DoesUsernameExistAsync(registerModel.UserName)) - throw new ArgumentException("Username already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username)); if (await this._userRepository.DoesEmailExistAsync(registerModel.Email)) - throw new ArgumentException("Email already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Email)); + User user = this._userMapper.Map<User>(registerModel); @@ -69,9 +73,9 @@ namespace DevHive.Services.Services bool roleResult = await this._userRepository.AddRoleToUser(user, Role.DefaultRole); if (!userResult) - throw new ArgumentException("Unable to create a user"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotCreate, ClassesConstants.User.ToLower())); if (!roleResult) - throw new ArgumentException("Unable to add role to user"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotAdd, ClassesConstants.Role.ToLower())); User createdUser = await this._userRepository.GetByUsernameAsync(registerModel.UserName); @@ -84,7 +88,7 @@ namespace DevHive.Services.Services public async Task<UserServiceModel> GetUserById(Guid id) { User user = await this._userRepository.GetByIdAsync(id) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return this._userMapper.Map<UserServiceModel>(user); } @@ -92,7 +96,7 @@ namespace DevHive.Services.Services public async Task<UserServiceModel> GetUserByUsername(string username) { User user = await this._userRepository.GetByUsernameAsync(username) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return this._userMapper.Map<UserServiceModel>(user); } @@ -101,53 +105,31 @@ namespace DevHive.Services.Services #region Update public async Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel) { - await this.ValidateUserOnUpdate(updateUserServiceModel); + await ValidateUserOnUpdate(updateUserServiceModel); User user = await this._userRepository.GetByIdAsync(updateUserServiceModel.Id); - await this.PopulateUserModel(user, updateUserServiceModel); + await PopulateUserModel(user, updateUserServiceModel); if (updateUserServiceModel.Friends.Count > 0) - await this.CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList()); + await CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList()); else user.Friends.Clear(); bool result = await this._userRepository.EditAsync(user.Id, user); if (!result) - throw new InvalidOperationException("Unable to edit user!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower())); User newUser = await this._userRepository.GetByIdAsync(user.Id); return this._userMapper.Map<UserServiceModel>(newUser); } - - public async Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel) - { - User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId); - - if (!string.IsNullOrEmpty(user.ProfilePicture.PictureURL)) - { - bool success = await _cloudService.RemoveFilesFromCloud(new List<string> { user.ProfilePicture.PictureURL }); - if (!success) - throw new InvalidCastException("Could not delete old profile picture!"); - } - - string fileUrl = (await this._cloudService.UploadFilesToCloud(new List<IFormFile> { updateProfilePictureServiceModel.Picture }))[0] ?? - throw new ArgumentException("Unable to upload profile picture to cloud"); - - bool successful = await this._userRepository.UpdateProfilePicture(updateProfilePictureServiceModel.UserId, fileUrl); - - if (!successful) - throw new InvalidOperationException("Unable to change profile picture!"); - - return new ProfilePictureServiceModel() { ProfilePictureURL = fileUrl }; - } #endregion #region Delete public async Task<bool> DeleteUser(Guid id) { if (!await this._userRepository.DoesUserExistAsync(id)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); User user = await this._userRepository.GetByIdAsync(id); return await this._userRepository.DeleteAsync(user); @@ -162,21 +144,21 @@ namespace DevHive.Services.Services private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel) { if (!await this._userRepository.DoesUserExistAsync(updateUserServiceModel.Id)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); if (updateUserServiceModel.Friends.Any(x => x.UserName == updateUserServiceModel.UserName)) - throw new ArgumentException("You cant add yourself as a friend(sry, bro)!"); + throw new InvalidOperationException(NoYourselfAsFriend); if (!await this._userRepository.DoesUserHaveThisUsernameAsync(updateUserServiceModel.Id, updateUserServiceModel.UserName) && await this._userRepository.DoesUsernameExistAsync(updateUserServiceModel.UserName)) - throw new ArgumentException("Username already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username.ToLower())); List<string> usernames = new(); foreach (var friend in updateUserServiceModel.Friends) usernames.Add(friend.UserName); if (!await this._userRepository.ValidateFriendsCollectionAsync(usernames)) - throw new ArgumentException("One or more friends do not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.OneOrMoreFriends)); } #endregion @@ -184,7 +166,7 @@ namespace DevHive.Services.Services public async Task<TokenModel> SuperSecretPromotionToAdmin(Guid userId) { User user = await this._userRepository.GetByIdAsync(userId) ?? - throw new ArgumentException("User does not exist! Can't promote shit in this country..."); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User) + " " + Rant); if (!await this._roleRepository.DoesNameExist(Role.AdminRole)) { @@ -224,7 +206,7 @@ namespace DevHive.Services.Services foreach (var role in updateUserServiceModel.Roles) { Role returnedRole = await this._roleRepository.GetByNameAsync(role.Name) ?? - throw new ArgumentException($"Role {role.Name} does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); roles.Add(returnedRole); } @@ -236,7 +218,7 @@ namespace DevHive.Services.Services for (int i = 0; i < languagesCount; i++) { Language language = await this._languageRepository.GetByNameAsync(updateUserServiceModel.Languages.ElementAt(i).Name) ?? - throw new ArgumentException("Invalid language name!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Language))); languages.Add(language); } @@ -248,7 +230,8 @@ namespace DevHive.Services.Services for (int i = 0; i < technologiesCount; i++) { Technology technology = await this._technologyRepository.GetByNameAsync(updateUserServiceModel.Technologies.ElementAt(i).Name) ?? - throw new ArgumentException("Invalid technology name!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Technology))); + technologies.Add(technology); } diff --git a/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj b/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj index 9d62eee..79c856f 100644 --- a/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj +++ b/src/Web/DevHive.Web.Models/DevHive.Web.Models.csproj @@ -8,6 +8,6 @@ </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> </Project>
\ No newline at end of file diff --git a/src/Web/DevHive.Web.Models/User/UpdateProfilePictureWebModel.cs b/src/Web/DevHive.Web.Models/ProfilePicture/ProfilePictureWebModel.cs index 196d1e7..3fe201c 100644 --- a/src/Web/DevHive.Web.Models/User/UpdateProfilePictureWebModel.cs +++ b/src/Web/DevHive.Web.Models/ProfilePicture/ProfilePictureWebModel.cs @@ -1,8 +1,8 @@ using Microsoft.AspNetCore.Http; -namespace DevHive.Web.Models.User +namespace DevHive.Web.Models.ProfilePicture { - public class UpdateProfilePictureWebModel + public class ProfilePictureWebModel { public IFormFile Picture { get; set; } } diff --git a/src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs b/src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs deleted file mode 100644 index e09ee08..0000000 --- a/src/Web/DevHive.Web.Models/User/ProfilePictureWebModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DevHive.Web.Models.User -{ - public class ProfilePictureWebModel - { - public string ProfilePictureURL { get; set; } - } -} diff --git a/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj b/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj index 5099119..49a9173 100644 --- a/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj +++ b/src/Web/DevHive.Web.Tests/DevHive.Web.Tests.csproj @@ -8,7 +8,7 @@ <PackageReference Include="NUnit" Version="3.13.1"/> <PackageReference Include="NUnit3TestAdapter" Version="3.17.0"/> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\DevHive.Web\DevHive.Web.csproj"/> diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs index 1bd8df0..b4c49b4 100644 --- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs +++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDatabase.cs @@ -18,7 +18,7 @@ namespace DevHive.Web.Configurations.Extensions { services.AddDbContext<DevHiveContext>(options => { - options.EnableSensitiveDataLogging(true); + // options.EnableSensitiveDataLogging(true); options.UseNpgsql(configuration.GetConnectionString("DEV"), options => { options.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); diff --git a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs index ae14520..f49a335 100644 --- a/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs +++ b/src/Web/DevHive.Web/Configurations/Extensions/ConfigureDependencyInjection.cs @@ -17,16 +17,16 @@ namespace DevHive.Web.Configurations.Extensions services.AddTransient<ILanguageRepository, LanguageRepository>(); services.AddTransient<IRoleRepository, RoleRepository>(); services.AddTransient<ITechnologyRepository, TechnologyRepository>(); - services.AddTransient<IUserRepository, UserRepository>(); services.AddTransient<IPostRepository, PostRepository>(); services.AddTransient<ICommentRepository, CommentRepository>(); services.AddTransient<IFeedRepository, FeedRepository>(); services.AddTransient<IRatingRepository, RatingRepository>(); + services.AddTransient<IProfilePictureRepository, ProfilePictureRepository>(); + services.AddTransient<IUserRepository, UserRepository>(); services.AddTransient<ILanguageService, LanguageService>(); services.AddTransient<IRoleService, RoleService>(); services.AddTransient<ITechnologyService, TechnologyService>(); - services.AddTransient<IUserService, UserService>(); services.AddTransient<IPostService, PostService>(); services.AddTransient<ICommentService, CommentService>(); services.AddTransient<IFeedService, FeedService>(); @@ -46,7 +46,6 @@ namespace DevHive.Web.Configurations.Extensions signingKey: Encoding.ASCII.GetBytes(configuration.GetSection("Jwt").GetSection("signingKey").Value), validationIssuer: configuration.GetSection("Jwt").GetSection("validationIssuer").Value, audience: configuration.GetSection("Jwt").GetSection("audience").Value)); - services.AddTransient<IRatingService, RatingService>(); } } } diff --git a/src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs b/src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs new file mode 100644 index 0000000..8c12a20 --- /dev/null +++ b/src/Web/DevHive.Web/Configurations/Mapping/ProfilePictureMappings.cs @@ -0,0 +1,16 @@ +using System; +using AutoMapper; +using DevHive.Web.Models.ProfilePicture; +using DevHive.Services.Models.ProfilePicture; + +namespace DevHive.Web.Configurations.Mapping +{ + public class ProfilePictureMappings : Profile + { + public ProfilePictureMappings() + { + CreateMap<ProfilePictureWebModel, ProfilePictureServiceModel>() + .ForMember(dest => dest.ProfilePictureFormFile, src => src.MapFrom(p => p.Picture)); + } + } +} diff --git a/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs b/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs index 14aaa3a..dabec93 100644 --- a/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs +++ b/src/Web/DevHive.Web/Configurations/Mapping/UserMappings.cs @@ -23,9 +23,6 @@ namespace DevHive.Web.Configurations.Mapping CreateMap<UsernameWebModel, FriendServiceModel>(); CreateMap<UsernameWebModel, UpdateFriendServiceModel>(); - CreateMap<UpdateProfilePictureWebModel, UpdateProfilePictureServiceModel>(); - CreateMap<ProfilePictureServiceModel, ProfilePictureWebModel>(); - CreateMap<UpdateUserServiceModel, UpdateUserWebModel>(); CreateMap<FriendServiceModel, UsernameWebModel>(); } diff --git a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs index 2eec99e..9a76e2c 100644 --- a/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs +++ b/src/Web/DevHive.Web/Controllers/ProfilePictureController.cs @@ -1,8 +1,12 @@ using System; using System.Threading.Tasks; -using DevHive.Web.Models.User; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using DevHive.Common.Jwt.Interfaces; +using AutoMapper; +using DevHive.Web.Models.ProfilePicture; namespace DevHive.Web.Controllers { @@ -13,36 +17,50 @@ namespace DevHive.Web.Controllers [Route("api/[controller]")] public class ProfilePictureController { - // private readonly ProfilePictureService _profilePictureService; + private readonly IProfilePictureService _profilePictureService; + private readonly IJwtService _jwtService; + private readonly IMapper _profilePictureMapper; - // public ProfilePictureController(ProfilePictureService profilePictureService) - // { - // this._profilePictureService = profilePictureService; - // } + public ProfilePictureController(IProfilePictureService profilePictureService, IJwtService jwtService, IMapper profilePictureMapper) + { + this._profilePictureService = profilePictureService; + this._jwtService = jwtService; + this._profilePictureMapper = profilePictureMapper; + } + + /// <summary> + /// Get the URL of user's profile picture + /// </summary> + /// <param name="profilePictureId">The profile picture's Id</param> + /// <param name="authorization">JWT Bearer Token</param> + /// <returns>The URL of the profile picture</returns> + [HttpGet] + [AllowAnonymous] + public async Task<IActionResult> ReadProfilePicture(Guid profilePictureId, [FromHeader] string authorization) + { + string profilePicURL = await this._profilePictureService.GetProfilePictureById(profilePictureId); + return new OkObjectResult(new { ProfilePictureURL = profilePicURL} ); + } /// <summary> /// Alter the profile picture of a user /// </summary> /// <param name="userId">The user's Id</param> - /// <param name="updateProfilePictureWebModel">The new profile picture</param> + /// <param name="profilePictureWebModel">The new profile picture</param> /// <param name="authorization">JWT Bearer Token</param> - /// <returns>???</returns> + /// <returns>The URL of the new profile picture</returns> [HttpPut] - [Route("ProfilePicture")] [Authorize(Roles = "User,Admin")] - public async Task<IActionResult> UpdateProfilePicture(Guid userId, [FromForm] UpdateProfilePictureWebModel updateProfilePictureWebModel, [FromHeader] string authorization) + public async Task<IActionResult> UpdateProfilePicture(Guid userId, [FromForm] ProfilePictureWebModel profilePictureWebModel, [FromHeader] string authorization) { - throw new NotImplementedException(); - // if (!await this._userService.ValidJWT(userId, authorization)) - // return new UnauthorizedResult(); - - // UpdateProfilePictureServiceModel updateProfilePictureServiceModel = this._userMapper.Map<UpdateProfilePictureServiceModel>(updateProfilePictureWebModel); - // updateProfilePictureServiceModel.UserId = userId; + if (!this._jwtService.ValidateToken(userId, authorization)) + return new UnauthorizedResult(); - // ProfilePictureServiceModel profilePictureServiceModel = await this._userService.UpdateProfilePicture(updateProfilePictureServiceModel); - // ProfilePictureWebModel profilePictureWebModel = this._userMapper.Map<ProfilePictureWebModel>(profilePictureServiceModel); + ProfilePictureServiceModel profilePictureServiceModel = this._profilePictureMapper.Map<ProfilePictureServiceModel>(profilePictureWebModel); + profilePictureServiceModel.UserId = userId; - // return new AcceptedResult("UpdateProfilePicture", profilePictureWebModel); + string url = await this._profilePictureService.UpdateProfilePicture(profilePictureServiceModel); + return new OkObjectResult(new { URL = url }); } } } diff --git a/src/Web/DevHive.Web/DevHive.Web.csproj b/src/Web/DevHive.Web/DevHive.Web.csproj index 39322ae..5b3a920 100644 --- a/src/Web/DevHive.Web/DevHive.Web.csproj +++ b/src/Web/DevHive.Web/DevHive.Web.csproj @@ -9,25 +9,30 @@ <AllowUntrustedCertificate>true</AllowUntrustedCertificate> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.3" NoWarn="NU1605"/> - <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.3" NoWarn="NU1605"/> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3"> + <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.4" NoWarn="NU1605"/> + <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.4" NoWarn="NU1605"/> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2"/> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/> <PackageReference Include="AutoMapper" Version="10.1.1"/> - <PackageReference Include="Newtonsoft.Json" Version="12.0.3"/> - <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> - <PackageReference Include="NSwag.AspNetCore" Version="13.10.7"/> - <PackageReference Include="NSwag.Generation.AspNetCore" Version="13.10.7"/> - <PackageReference Include="NSwag.Annotations" Version="13.10.7"/> - <PackageReference Include="NSwag.Core" Version="13.10.7"/> - <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.1.0"/> - <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.1.0"/> - <PackageReference Include="NSwag.SwaggerGeneration.WebApi" Version="12.3.0"/> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/> + <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.4"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> + <PackageReference Include="NSwag.AspNetCore" Version="13.10.8"/> + <PackageReference Include="NSwag.Generation.AspNetCore" Version="13.10.8"/> + <PackageReference Include="NSwag.Annotations" Version="13.10.8"/> + <PackageReference Include="NSwag.Core" Version="13.10.8"/> + <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.1.1"/> + <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.1.1"/> + <PackageReference Include="NSwag.SwaggerGeneration.WebApi" Version="12.3.1"/> + <PackageReference Include="Serilog.AspNetCore" Version="4.1.0"/> + <PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0"/> + <PackageReference Include="Serilog.Enrichers.Environment" Version="2.1.3"/> + <PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0"/> + <PackageReference Include="Serilog.Enrichers.Process" Version="2.0.1"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\DevHive.Web.Models\DevHive.Web.Models.csproj"/> diff --git a/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs b/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs index f159b69..ebec5e8 100644 --- a/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs +++ b/src/Web/DevHive.Web/Middleware/ExceptionMiddleware.cs @@ -2,7 +2,7 @@ using System; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; +using Newtonsoft.Json; namespace DevHive.Web.Middleware { @@ -32,11 +32,10 @@ namespace DevHive.Web.Middleware context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)HttpStatusCode.BadRequest; - return context.Response.WriteAsync(new - { - context.Response.StatusCode, - exception.Message - }.ToString()); + // Made to resemble the formatting of property validation errors (like [MinLength(3)]) + string message = JsonConvert.SerializeObject(new { Error = exception.Message }); + + return context.Response.WriteAsync(message); } } } diff --git a/src/Web/DevHive.Web/Program.cs b/src/Web/DevHive.Web/Program.cs index fdb6889..e7c47a9 100644 --- a/src/Web/DevHive.Web/Program.cs +++ b/src/Web/DevHive.Web/Program.cs @@ -1,5 +1,8 @@ +using System; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Configuration; +using Serilog; namespace DevHive.Web { @@ -11,11 +14,32 @@ namespace DevHive.Web public static void Main(string[] args) { - CreateHostBuilder(args).Build().Run(); + var config = new ConfigurationBuilder() + .AddJsonFile("appsettings.json") + .Build(); + + Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(config) + .CreateLogger(); + + try + { + Log.Information("Application Starting Up"); + CreateHostBuilder(args).Build().Run(); + } + catch (Exception ex) + { + Log.Fatal(ex, "The application failed to start correctly."); + } + finally + { + Log.CloseAndFlush(); + } } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) + .UseSerilog() .ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureKestrel(opt => opt.ListenLocalhost(HTTP_PORT)); diff --git a/src/Web/DevHive.Web/Startup.cs b/src/Web/DevHive.Web/Startup.cs index 002c718..05a75d9 100644 --- a/src/Web/DevHive.Web/Startup.cs +++ b/src/Web/DevHive.Web/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using DevHive.Web.Configurations.Extensions; using Newtonsoft.Json; +using Serilog; namespace DevHive.Web { @@ -46,7 +47,8 @@ namespace DevHive.Web if (env.IsDevelopment()) { - app.UseDeveloperExceptionPage(); + app.UseExceptionHandlerMiddlewareConfiguration(); + // app.UseDeveloperExceptionPage(); } else { @@ -58,6 +60,8 @@ namespace DevHive.Web app.UseDatabaseConfiguration(); app.UseAutoMapperConfiguration(); + app.UseSerilogRequestLogging(); + app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( diff --git a/src/Web/DevHive.Web/appsettings.json b/src/Web/DevHive.Web/appsettings.json index fcf9805..84d534d 100644 --- a/src/Web/DevHive.Web/appsettings.json +++ b/src/Web/DevHive.Web/appsettings.json @@ -5,18 +5,46 @@ "audience": "" }, "ConnectionStrings": { - "DEV": "Server=localhost;Port=5432;Database=API;User Id=postgres;Password=;" + "DEV": "Server=localhost;Port=5432;Database=DevHive_API;User Id=postgres;Password=;" }, "Cloud": { "cloudName": "devhive", "apiKey": "488664116365813", "apiSecret": "" }, - "Logging": { - "LogLevel": { + "Serilog": { + "Using": [], + "LevelSwitches": { + "$consoleSwitch": "Verbose", + "$fileSwitch": "Error" + }, + "MinimumLevel": { "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } + "Override": { + "Microsoft": "Warning", + "System": "Warning" + } + }, + "Enrich": [ + "FromLogContext", + "WithMachineName", + "WithProcessId", + "WithThreadId" + ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + "levelSwitch": "$consoleSwitch" + } + }, + { + "Name": "File", + "Args": { + "path": "./Logs/errors.log", + "levelSwitch": "$fileSwitch" + } + } + ] } } |
