aboutsummaryrefslogtreecommitdiff
path: root/src/Services
diff options
context:
space:
mode:
authorKamen Mladenov <kamen.d.mladenov@protonmail.com>2021-04-09 19:51:35 +0300
committerGitHub <noreply@github.com>2021-04-09 19:51:35 +0300
commit233f38915ba0079079233eff55434ef349c05c45 (patch)
tree6c5f69017865bcab87355e910c87339453da1406 /src/Services
parentf4a70c6430db923af9fa9958a11c2d6612cb52cc (diff)
parenta992357efcf1bc1ece81b95ecee5e05a0b73bfdc (diff)
downloadDevHive-0.2.tar
DevHive-0.2.tar.gz
DevHive-0.2.zip
Merge pull request #28 from Team-Kaleidoscope/devHEADv0.2mainheroku/main
Second stage: Complete
Diffstat (limited to 'src/Services')
-rw-r--r--src/Services/DevHive.Services.Models/Comment/CreateCommentServiceModel.cs13
-rw-r--r--src/Services/DevHive.Services.Models/Comment/ReadCommentServiceModel.cs21
-rw-r--r--src/Services/DevHive.Services.Models/Comment/UpdateCommentServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj13
-rw-r--r--src/Services/DevHive.Services.Models/Feed/GetPageServiceModel.cs17
-rw-r--r--src/Services/DevHive.Services.Models/Feed/ReadPageServiceModel.cs10
-rw-r--r--src/Services/DevHive.Services.Models/Language/CreateLanguageServiceModel.cs9
-rw-r--r--src/Services/DevHive.Services.Models/Language/LanguageServiceModel.cs9
-rw-r--r--src/Services/DevHive.Services.Models/Language/ReadLanguageServiceModel.cs11
-rw-r--r--src/Services/DevHive.Services.Models/Language/UpdateLanguageServiceModel.cs11
-rw-r--r--src/Services/DevHive.Services.Models/Post/CreatePostServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs27
-rw-r--r--src/Services/DevHive.Services.Models/Post/UpdatePostServiceModel.cs17
-rw-r--r--src/Services/DevHive.Services.Models/ProfilePicture/ProfilePictureServiceModel.cs11
-rw-r--r--src/Services/DevHive.Services.Models/Rating/CreateRatingServiceModel.cs13
-rw-r--r--src/Services/DevHive.Services.Models/Rating/ReadRatingServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/Rating/UpdateRatingServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/Role/CreateRoleServiceModel.cs10
-rw-r--r--src/Services/DevHive.Services.Models/Role/RoleServiceModel.cs7
-rw-r--r--src/Services/DevHive.Services.Models/Role/UpdateRoleServiceModel.cs10
-rw-r--r--src/Services/DevHive.Services.Models/Technology/CreateTechnologyServiceModel.cs9
-rw-r--r--src/Services/DevHive.Services.Models/Technology/ReadTechnologyServiceModel.cs11
-rw-r--r--src/Services/DevHive.Services.Models/Technology/TechnologyServiceModel.cs9
-rw-r--r--src/Services/DevHive.Services.Models/Technology/UpdateTechnologyServiceModel.cs11
-rw-r--r--src/Services/DevHive.Services.Models/User/BaseUserServiceModel.cs10
-rw-r--r--src/Services/DevHive.Services.Models/User/FriendServiceModel.cs10
-rw-r--r--src/Services/DevHive.Services.Models/User/LoginServiceModel.cs8
-rw-r--r--src/Services/DevHive.Services.Models/User/RegisterServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/User/UpdateFriendServiceModel.cs10
-rw-r--r--src/Services/DevHive.Services.Models/User/UpdateUserServiceModel.cs26
-rw-r--r--src/Services/DevHive.Services.Models/User/UserServiceModel.cs23
-rw-r--r--src/Services/DevHive.Services.Tests/CommentService.Tests.cs314
-rw-r--r--src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj23
-rw-r--r--src/Services/DevHive.Services.Tests/FeedService.Tests.cs155
-rw-r--r--src/Services/DevHive.Services.Tests/LanguageService.Tests.cs315
-rw-r--r--src/Services/DevHive.Services.Tests/PostService.Tests.cs320
-rw-r--r--src/Services/DevHive.Services.Tests/ProfilePictureService.Tests.cs84
-rw-r--r--src/Services/DevHive.Services.Tests/RatingService.Tests.cs448
-rw-r--r--src/Services/DevHive.Services.Tests/RoleService.Tests.cs271
-rw-r--r--src/Services/DevHive.Services.Tests/TechnologyServices.Tests.cs311
-rw-r--r--src/Services/DevHive.Services.Tests/UserService.Tests.cs429
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/CommentMappings.cs27
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/FeedMappings.cs11
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/LanguageMappings.cs22
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/PostMappings.cs32
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs21
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/RoleMapings.cs21
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs21
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/UserMappings.cs31
-rw-r--r--src/Services/DevHive.Services/DevHive.Services.csproj27
-rw-r--r--src/Services/DevHive.Services/Interfaces/ICloudService.cs14
-rw-r--r--src/Services/DevHive.Services/Interfaces/ICommentService.cs20
-rw-r--r--src/Services/DevHive.Services/Interfaces/IFeedService.cs11
-rw-r--r--src/Services/DevHive.Services/Interfaces/IFriendsService.cs11
-rw-r--r--src/Services/DevHive.Services/Interfaces/ILanguageService.cs19
-rw-r--r--src/Services/DevHive.Services/Interfaces/IPostService.cs20
-rw-r--r--src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs30
-rw-r--r--src/Services/DevHive.Services/Interfaces/IRatingService.cs20
-rw-r--r--src/Services/DevHive.Services/Interfaces/IRoleService.cs17
-rw-r--r--src/Services/DevHive.Services/Interfaces/ITechnologyService.cs19
-rw-r--r--src/Services/DevHive.Services/Interfaces/IUserService.cs62
-rw-r--r--src/Services/DevHive.Services/Services/CloudinaryService.cs59
-rw-r--r--src/Services/DevHive.Services/Services/CommentService.cs169
-rw-r--r--src/Services/DevHive.Services/Services/FeedService.cs85
-rw-r--r--src/Services/DevHive.Services/Services/FriendsService.cs45
-rw-r--r--src/Services/DevHive.Services/Services/LanguageService.cs91
-rw-r--r--src/Services/DevHive.Services/Services/PostService.cs249
-rw-r--r--src/Services/DevHive.Services/Services/ProfilePictureService.cs101
-rw-r--r--src/Services/DevHive.Services/Services/RatingService.cs120
-rw-r--r--src/Services/DevHive.Services/Services/RoleService.cs71
-rw-r--r--src/Services/DevHive.Services/Services/TechnologyService.cs92
-rw-r--r--src/Services/DevHive.Services/Services/UserService.cs255
72 files changed, 4874 insertions, 0 deletions
diff --git a/src/Services/DevHive.Services.Models/Comment/CreateCommentServiceModel.cs b/src/Services/DevHive.Services.Models/Comment/CreateCommentServiceModel.cs
new file mode 100644
index 0000000..30e919b
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Comment/CreateCommentServiceModel.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace DevHive.Services.Models.Comment
+{
+ public class CreateCommentServiceModel
+ {
+ public Guid PostId { get; set; }
+
+ public Guid CreatorId { get; set; }
+
+ public string Message { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Comment/ReadCommentServiceModel.cs b/src/Services/DevHive.Services.Models/Comment/ReadCommentServiceModel.cs
new file mode 100644
index 0000000..3196233
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Comment/ReadCommentServiceModel.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace DevHive.Services.Models.Comment
+{
+ public class ReadCommentServiceModel
+ {
+ public Guid CommentId { get; set; }
+
+ public string IssuerFirstName { get; set; }
+
+ public string IssuerLastName { get; set; }
+
+ public string IssuerUsername { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public string Message { get; set; }
+
+ public DateTime TimeCreated { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Comment/UpdateCommentServiceModel.cs b/src/Services/DevHive.Services.Models/Comment/UpdateCommentServiceModel.cs
new file mode 100644
index 0000000..3b78200
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Comment/UpdateCommentServiceModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace DevHive.Services.Models.Comment
+{
+ public class UpdateCommentServiceModel
+ {
+ public Guid CreatorId { get; set; }
+
+ public Guid CommentId { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public string NewMessage { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
new file mode 100644
index 0000000..2345a8e
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/Services/DevHive.Services.Models/Feed/GetPageServiceModel.cs b/src/Services/DevHive.Services.Models/Feed/GetPageServiceModel.cs
new file mode 100644
index 0000000..1f02486
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Feed/GetPageServiceModel.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace DevHive.Services.Models
+{
+ public class GetPageServiceModel
+ {
+ public Guid UserId { get; set; }
+
+ public string Username { get; set; }
+
+ public int PageNumber { get; set; }
+
+ public DateTime FirstRequestIssued { get; set; }
+
+ public int PageSize { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Feed/ReadPageServiceModel.cs b/src/Services/DevHive.Services.Models/Feed/ReadPageServiceModel.cs
new file mode 100644
index 0000000..95f6845
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Feed/ReadPageServiceModel.cs
@@ -0,0 +1,10 @@
+using System.Collections.Generic;
+using DevHive.Services.Models.Post;
+
+namespace DevHive.Services.Models
+{
+ public class ReadPageServiceModel
+ {
+ public List<ReadPostServiceModel> Posts { get; set; } = new();
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Language/CreateLanguageServiceModel.cs b/src/Services/DevHive.Services.Models/Language/CreateLanguageServiceModel.cs
new file mode 100644
index 0000000..9d66d3e
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Language/CreateLanguageServiceModel.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace DevHive.Services.Models.Language
+{
+ public class CreateLanguageServiceModel
+ {
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Language/LanguageServiceModel.cs b/src/Services/DevHive.Services.Models/Language/LanguageServiceModel.cs
new file mode 100644
index 0000000..a07aa16
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Language/LanguageServiceModel.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace DevHive.Services.Models.Language
+{
+ public class LanguageServiceModel
+ {
+ public Guid Id { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Language/ReadLanguageServiceModel.cs b/src/Services/DevHive.Services.Models/Language/ReadLanguageServiceModel.cs
new file mode 100644
index 0000000..651dc6d
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Language/ReadLanguageServiceModel.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace DevHive.Services.Models.Language
+{
+ public class ReadLanguageServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Language/UpdateLanguageServiceModel.cs b/src/Services/DevHive.Services.Models/Language/UpdateLanguageServiceModel.cs
new file mode 100644
index 0000000..84b7f27
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Language/UpdateLanguageServiceModel.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace DevHive.Services.Models.Language
+{
+ public class UpdateLanguageServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Post/CreatePostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/CreatePostServiceModel.cs
new file mode 100644
index 0000000..304eb90
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Post/CreatePostServiceModel.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Http;
+
+namespace DevHive.Services.Models.Post
+{
+ public class CreatePostServiceModel
+ {
+ public Guid CreatorId { get; set; }
+
+ public string Message { get; set; }
+
+ public List<IFormFile> Files { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
new file mode 100644
index 0000000..33d6520
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using DevHive.Common.Models.Misc;
+
+namespace DevHive.Services.Models.Post
+{
+ public class ReadPostServiceModel
+ {
+ public Guid PostId { get; set; }
+
+ public string CreatorFirstName { get; set; }
+
+ public string CreatorLastName { get; set; }
+
+ public string CreatorUsername { get; set; }
+
+ public string Message { get; set; }
+
+ public DateTime TimeCreated { get; set; }
+
+ public List<IdModel> Comments { get; set; } = new();
+
+ public List<string> FileUrls { get; set; }
+
+ public int CurrentRating { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Post/UpdatePostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/UpdatePostServiceModel.cs
new file mode 100644
index 0000000..51b16bc
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Post/UpdatePostServiceModel.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Http;
+
+namespace DevHive.Services.Models.Post
+{
+ public class UpdatePostServiceModel
+ {
+ public Guid PostId { get; set; }
+
+ public Guid CreatorId { get; set; }
+
+ public string NewMessage { get; set; }
+
+ public List<IFormFile> Files { get; set; }
+ }
+}
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/Rating/CreateRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Rating/CreateRatingServiceModel.cs
new file mode 100644
index 0000000..486e3d2
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Rating/CreateRatingServiceModel.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace DevHive.Services.Models.Rating
+{
+ public class CreateRatingServiceModel
+ {
+ public Guid UserId { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public bool IsLike { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Rating/ReadRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Rating/ReadRatingServiceModel.cs
new file mode 100644
index 0000000..56a5ab0
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Rating/ReadRatingServiceModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace DevHive.Services.Models.Rating
+{
+ public class ReadRatingServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public Guid UserId { get; set; }
+
+ public bool IsLike { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Rating/UpdateRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Rating/UpdateRatingServiceModel.cs
new file mode 100644
index 0000000..923e789
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Rating/UpdateRatingServiceModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace DevHive.Services.Models.Rating
+{
+ public class UpdateRatingServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public Guid UserId { get; set; }
+
+ public Guid PostId { get; set; }
+
+ public bool IsLike { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Role/CreateRoleServiceModel.cs b/src/Services/DevHive.Services.Models/Role/CreateRoleServiceModel.cs
new file mode 100644
index 0000000..8b03c65
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Role/CreateRoleServiceModel.cs
@@ -0,0 +1,10 @@
+using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
+
+namespace DevHive.Services.Models.Role
+{
+ public class CreateRoleServiceModel
+ {
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Role/RoleServiceModel.cs b/src/Services/DevHive.Services.Models/Role/RoleServiceModel.cs
new file mode 100644
index 0000000..77ca954
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Role/RoleServiceModel.cs
@@ -0,0 +1,7 @@
+namespace DevHive.Services.Models.Role
+{
+ public class RoleServiceModel
+ {
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Role/UpdateRoleServiceModel.cs b/src/Services/DevHive.Services.Models/Role/UpdateRoleServiceModel.cs
new file mode 100644
index 0000000..9b8fbfe
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Role/UpdateRoleServiceModel.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace DevHive.Services.Models.Role
+{
+ public class UpdateRoleServiceModel
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Technology/CreateTechnologyServiceModel.cs b/src/Services/DevHive.Services.Models/Technology/CreateTechnologyServiceModel.cs
new file mode 100644
index 0000000..a31d160
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Technology/CreateTechnologyServiceModel.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace DevHive.Services.Models.Technology
+{
+ public class CreateTechnologyServiceModel
+ {
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Technology/ReadTechnologyServiceModel.cs b/src/Services/DevHive.Services.Models/Technology/ReadTechnologyServiceModel.cs
new file mode 100644
index 0000000..99f4750
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Technology/ReadTechnologyServiceModel.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace DevHive.Services.Models.Technology
+{
+ public class ReadTechnologyServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Technology/TechnologyServiceModel.cs b/src/Services/DevHive.Services.Models/Technology/TechnologyServiceModel.cs
new file mode 100644
index 0000000..cb5c881
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Technology/TechnologyServiceModel.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace DevHive.Services.Models.Technology
+{
+ public class TechnologyServiceModel
+ {
+ public Guid Id { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/Technology/UpdateTechnologyServiceModel.cs b/src/Services/DevHive.Services.Models/Technology/UpdateTechnologyServiceModel.cs
new file mode 100644
index 0000000..f4c7921
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Technology/UpdateTechnologyServiceModel.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace DevHive.Services.Models.Technology
+{
+ public class UpdateTechnologyServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public string Name { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/BaseUserServiceModel.cs b/src/Services/DevHive.Services.Models/User/BaseUserServiceModel.cs
new file mode 100644
index 0000000..5c3dc6b
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/BaseUserServiceModel.cs
@@ -0,0 +1,10 @@
+namespace DevHive.Services.Models.User
+{
+ public class BaseUserServiceModel
+ {
+ public string UserName { get; set; }
+ public string Email { get; set; }
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/FriendServiceModel.cs b/src/Services/DevHive.Services.Models/User/FriendServiceModel.cs
new file mode 100644
index 0000000..2241886
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/FriendServiceModel.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace DevHive.Services.Models.User
+{
+ public class FriendServiceModel
+ {
+ public Guid Id { get; set; }
+ public string UserName { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/LoginServiceModel.cs b/src/Services/DevHive.Services.Models/User/LoginServiceModel.cs
new file mode 100644
index 0000000..6a0d128
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/LoginServiceModel.cs
@@ -0,0 +1,8 @@
+namespace DevHive.Services.Models.User
+{
+ public class LoginServiceModel
+ {
+ public string UserName { get; set; }
+ public string Password { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/RegisterServiceModel.cs b/src/Services/DevHive.Services.Models/User/RegisterServiceModel.cs
new file mode 100644
index 0000000..5852d46
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/RegisterServiceModel.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using DevHive.Services.Models.Language;
+using DevHive.Services.Models.Technology;
+
+namespace DevHive.Services.Models.User
+{
+ public class RegisterServiceModel : BaseUserServiceModel
+ {
+ public string Password { get; set; }
+
+ public HashSet<LanguageServiceModel> Languages { get; set; }
+
+ public HashSet<TechnologyServiceModel> Technologies { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/UpdateFriendServiceModel.cs b/src/Services/DevHive.Services.Models/User/UpdateFriendServiceModel.cs
new file mode 100644
index 0000000..0d7a8c1
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/UpdateFriendServiceModel.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace DevHive.Services.Models.User
+{
+ public class UpdateFriendServiceModel
+ {
+ public Guid Id { get; set; }
+ public string UserName { get; set; }
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/UpdateUserServiceModel.cs b/src/Services/DevHive.Services.Models/User/UpdateUserServiceModel.cs
new file mode 100644
index 0000000..ff20e6b
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/UpdateUserServiceModel.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using DevHive.Services.Models.Role;
+using DevHive.Services.Models.Language;
+using DevHive.Services.Models.Technology;
+
+namespace DevHive.Services.Models.User
+{
+ public class UpdateUserServiceModel : BaseUserServiceModel
+ {
+ public Guid Id { get; set; }
+
+ public string Password { get; set; }
+
+ public string ProfilePictureURL { get; set; }
+
+ public HashSet<UpdateRoleServiceModel> Roles { get; set; } = new HashSet<UpdateRoleServiceModel>();
+
+ public HashSet<UpdateFriendServiceModel> Friends { get; set; } = new HashSet<UpdateFriendServiceModel>();
+
+ public HashSet<UpdateLanguageServiceModel> Languages { get; set; } = new HashSet<UpdateLanguageServiceModel>();
+
+ public HashSet<UpdateTechnologyServiceModel> Technologies { get; set; } = new HashSet<UpdateTechnologyServiceModel>();
+
+ }
+}
diff --git a/src/Services/DevHive.Services.Models/User/UserServiceModel.cs b/src/Services/DevHive.Services.Models/User/UserServiceModel.cs
new file mode 100644
index 0000000..f48c703
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/User/UserServiceModel.cs
@@ -0,0 +1,23 @@
+using System.Collections.Generic;
+using DevHive.Common.Models.Misc;
+using DevHive.Services.Models.Role;
+using DevHive.Services.Models.Language;
+using DevHive.Services.Models.Technology;
+
+namespace DevHive.Services.Models.User
+{
+ public class UserServiceModel : BaseUserServiceModel
+ {
+ public string ProfilePictureURL { get; set; } = new(string.Empty);
+
+ public HashSet<RoleServiceModel> Roles { get; set; } = new();
+
+ public HashSet<FriendServiceModel> Friends { get; set; } = new();
+
+ public HashSet<LanguageServiceModel> Languages { get; set; } = new();
+
+ public HashSet<TechnologyServiceModel> Technologies { get; set; } = new();
+
+ public List<IdModel> Posts { get; set; } = new();
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/CommentService.Tests.cs b/src/Services/DevHive.Services.Tests/CommentService.Tests.cs
new file mode 100644
index 0000000..12229e8
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/CommentService.Tests.cs
@@ -0,0 +1,314 @@
+using System;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Comment;
+using DevHive.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class CommentServiceTests
+ {
+ private const string MESSAGE = "Gosho Trapov";
+ private Mock<IUserRepository> _userRepositoryMock;
+ private Mock<IPostRepository> _postRepositoryMock;
+ private Mock<ICommentRepository> _commentRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private CommentService _commentService;
+
+ #region Setup
+ [SetUp]
+ public void Setup()
+ {
+ this._userRepositoryMock = new Mock<IUserRepository>();
+ this._postRepositoryMock = new Mock<IPostRepository>();
+ this._commentRepositoryMock = new Mock<ICommentRepository>();
+ this._mapperMock = new Mock<IMapper>();
+ this._commentService = new CommentService(this._userRepositoryMock.Object, this._postRepositoryMock.Object, this._commentRepositoryMock.Object, this._mapperMock.Object);
+ }
+ #endregion
+
+ #region AddComment
+ [Test]
+ public async Task AddComment_ReturnsNonEmptyGuid_WhenEntityIsAddedSuccessfully()
+ {
+ Guid id = Guid.NewGuid();
+ User creator = new() { Id = Guid.NewGuid() };
+ CreateCommentServiceModel createCommentServiceModel = new()
+ {
+ Message = MESSAGE
+ };
+ Comment comment = new()
+ {
+ Message = MESSAGE,
+ Id = id,
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Comment>()))
+ .ReturnsAsync(true);
+ this._commentRepositoryMock
+ .Setup(p => p.GetCommentByIssuerAndTimeCreatedAsync(It.IsAny<Guid>(), It.IsAny<DateTime>()))
+ .ReturnsAsync(comment);
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(creator);
+ this._mapperMock
+ .Setup(p => p.Map<Comment>(It.IsAny<CreateCommentServiceModel>()))
+ .Returns(comment);
+
+ Guid result = await this._commentService.AddComment(createCommentServiceModel);
+
+ Assert.AreEqual(id, result);
+ }
+
+ [Test]
+ public async Task AddComment_ReturnsEmptyGuid_WhenEntityIsNotAddedSuccessfully()
+ {
+ CreateCommentServiceModel createCommentServiceModel = new()
+ {
+ Message = MESSAGE
+ };
+ Comment comment = new()
+ {
+ Message = MESSAGE,
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Comment>()))
+ .ReturnsAsync(false);
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._mapperMock
+ .Setup(p => p.Map<Comment>(It.IsAny<CreateCommentServiceModel>()))
+ .Returns(comment);
+
+ Guid result = await this._commentService.AddComment(createCommentServiceModel);
+
+ Assert.IsTrue(result == Guid.Empty);
+ }
+
+ [Test]
+ public void AddComment_ThrowsException_WhenPostDoesNotExist()
+ {
+ const string EXCEPTION_MESSAGE = "Post does not exist!";
+
+ CreateCommentServiceModel createCommentServiceModel = new()
+ {
+ Message = MESSAGE
+ };
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._commentService.AddComment(createCommentServiceModel), "AddComment does not throw excpeion when the post does not exist");
+
+ // Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region GetCommentById
+ [Test]
+ public async Task GetCommentById_ReturnsTheComment_WhenItExists()
+ {
+ Guid creatorId = new();
+ User creator = new() { Id = creatorId };
+ Comment comment = new()
+ {
+ Message = MESSAGE,
+ Creator = creator
+ };
+ ReadCommentServiceModel commentServiceModel = new()
+ {
+ Message = MESSAGE
+ };
+ User user = new()
+ {
+ Id = creatorId,
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(comment);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._mapperMock
+ .Setup(p => p.Map<ReadCommentServiceModel>(It.IsAny<Comment>()))
+ .Returns(commentServiceModel);
+
+ ReadCommentServiceModel result = await this._commentService.GetCommentById(Guid.NewGuid());
+
+ Assert.AreEqual(MESSAGE, result.Message);
+ }
+
+ [Test]
+ public void GetCommentById_ThorwsException_WhenTheUserDoesNotExist()
+ {
+ const string EXCEPTION_MESSAGE = "The user does not exist";
+ Guid creatorId = new();
+ User creator = new() { Id = creatorId };
+ Comment comment = new()
+ {
+ Message = MESSAGE,
+ Creator = creator
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(comment);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._commentService.GetCommentById(Guid.NewGuid()), "GetCommentById does not throw exception when the user does not exist");
+
+ // Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message);
+ }
+
+ [Test]
+ public void GetCommentById_ThrowsException_WhenCommentDoesNotExist()
+ {
+ string exceptionMessage = "The comment does not exist";
+ Guid creatorId = new();
+ User user = new()
+ {
+ Id = creatorId,
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Comment>(null));
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._commentService.GetCommentById(Guid.NewGuid()));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region UpdateComment
+ [Test]
+ public async Task UpdateComment_ReturnsTheIdOfTheComment_WhenUpdatedSuccessfully()
+ {
+ Guid id = Guid.NewGuid();
+ Comment comment = new()
+ {
+ Id = id,
+ Message = MESSAGE
+ };
+ UpdateCommentServiceModel updateCommentServiceModel = new()
+ {
+ CommentId = id,
+ NewMessage = MESSAGE
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.DoesCommentExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._commentRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Comment>()))
+ .ReturnsAsync(true);
+ this._commentRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(comment);
+ this._mapperMock
+ .Setup(p => p.Map<Comment>(It.IsAny<UpdateCommentServiceModel>()))
+ .Returns(comment);
+
+ Guid result = await this._commentService.UpdateComment(updateCommentServiceModel);
+
+ Assert.AreEqual(updateCommentServiceModel.CommentId, result);
+ }
+
+ [Test]
+ public async Task UpdateComment_ReturnsEmptyId_WhenTheCommentIsNotUpdatedSuccessfully()
+ {
+ Comment comment = new()
+ {
+ Message = MESSAGE
+ };
+ UpdateCommentServiceModel updateCommentServiceModel = new()
+ {
+ CommentId = Guid.NewGuid(),
+ NewMessage = MESSAGE
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.DoesCommentExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._commentRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Comment>()))
+ .ReturnsAsync(false);
+ this._mapperMock
+ .Setup(p => p.Map<Comment>(It.IsAny<UpdateCommentServiceModel>()))
+ .Returns(comment);
+
+ Guid result = await this._commentService.UpdateComment(updateCommentServiceModel);
+
+ Assert.AreEqual(Guid.Empty, result);
+ }
+
+ [Test]
+ public void UpdateComment_ThrowsArgumentException_WhenCommentDoesNotExist()
+ {
+ string exceptionMessage = "Comment does not exist!";
+ UpdateCommentServiceModel updateCommentServiceModel = new()
+ {
+ };
+
+ this._commentRepositoryMock
+ .Setup(p => p.DoesCommentExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._commentService.UpdateComment(updateCommentServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region DeleteComment
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task DeleteComment_ShouldReturnIfDeletionIsSuccessfull_WhenCommentExists(bool shouldPass)
+ {
+ Guid id = new();
+ Comment comment = new();
+
+ this._commentRepositoryMock
+ .Setup(p => p.DoesCommentExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._commentRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(comment);
+ this._commentRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Comment>()))
+ .ReturnsAsync(shouldPass);
+
+ bool result = await this._commentService.DeleteComment(id);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void DeleteComment_ThrowsException_WhenCommentDoesNotExist()
+ {
+ string exceptionMessage = "Comment does not exist!";
+ Guid id = new();
+
+ this._commentRepositoryMock
+ .Setup(p => p.DoesCommentExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._commentService.DeleteComment(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorrect exception message");
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
new file mode 100644
index 0000000..4a7237b
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ <IsPackable>false</IsPackable>
+ </PropertyGroup>
+ <ItemGroup>
+ <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.20.0.28934"/>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\DevHive.Services\DevHive.Services.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
+ </ItemGroup>
+ <PropertyGroup>
+ <EnableNETAnalyzers>true</EnableNETAnalyzers>
+ <AnalysisLevel>latest</AnalysisLevel>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/Services/DevHive.Services.Tests/FeedService.Tests.cs b/src/Services/DevHive.Services.Tests/FeedService.Tests.cs
new file mode 100644
index 0000000..1f21394
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/FeedService.Tests.cs
@@ -0,0 +1,155 @@
+//using System;
+//using System.Collections.Generic;
+//using System.Threading.Tasks;
+//using AutoMapper;
+//using DevHive.Data.Interfaces;
+//using DevHive.Data.Models;
+//using DevHive.Services.Models;
+//using DevHive.Services.Models.Post;
+//using DevHive.Services.Services;
+//using Moq;
+//using NUnit.Framework;
+
+//namespace DevHive.Services.Tests
+//{
+// [TestFixture]
+// public class FeedServiceTests
+// {
+// private Mock<IFeedRepository> FeedRepositoryMock { get; set; }
+// private Mock<IUserRepository> UserRepositoryMock { get; set; }
+// private Mock<IMapper> MapperMock { get; set; }
+// private FeedService FeedService { get; set; }
+
+// #region SetUps
+// [SetUp]
+// public void Setup()
+// {
+// this.FeedRepositoryMock = new Mock<IFeedRepository>();
+// this.UserRepositoryMock = new Mock<IUserRepository>();
+// this.MapperMock = new Mock<IMapper>();
+// this.FeedService = new FeedService(this.FeedRepositoryMock.Object, this.UserRepositoryMock.Object, this.MapperMock.Object);
+// }
+// #endregion
+
+// #region GetPage
+// [Test]
+// public async Task GetPage_ReturnsReadPageServiceModel_WhenSuitablePostsExist()
+// {
+// GetPageServiceModel getPageServiceModel = new GetPageServiceModel
+// {
+// UserId = Guid.NewGuid()
+// };
+
+// User dummyUser = CreateDummyUser();
+// User anotherDummyUser = CreateAnotherDummyUser();
+// HashSet<User> friends = new HashSet<User>();
+// friends.Add(anotherDummyUser);
+// dummyUser.Friends = friends;
+
+// List<Post> posts = new List<Post>
+// {
+// new Post{ Message = "Message"}
+// };
+
+// ReadPostServiceModel readPostServiceModel = new ReadPostServiceModel
+// {
+// PostId = Guid.NewGuid(),
+// Message = "Message"
+// };
+// List<ReadPostServiceModel> readPostServiceModels = new List<ReadPostServiceModel>();
+// readPostServiceModels.Add(readPostServiceModel);
+// ReadPageServiceModel readPageServiceModel = new ReadPageServiceModel
+// {
+// Posts = readPostServiceModels
+// };
+
+// this.UserRepositoryMock.Setup(p => p.GetByIdAsync(It.IsAny<Guid>())).Returns(Task.FromResult(dummyUser));
+// this.FeedRepositoryMock.Setup(p => p.GetFriendsPosts(It.IsAny<List<User>>(), It.IsAny<DateTime>(), It.IsAny<int>(), It.IsAny<int>())).Returns(Task.FromResult(posts));
+// this.MapperMock.Setup(p => p.Map<ReadPostServiceModel>(It.IsAny<Post>())).Returns(readPostServiceModel);
+
+// ReadPageServiceModel result = await this.FeedService.GetPage(getPageServiceModel);
+
+// Assert.GreaterOrEqual(1, result.Posts.Count, "GetPage does not correctly return the posts");
+// }
+
+// [Test]
+// public void GetPage_ThrowsException_WhenNoSuitablePostsExist()
+// {
+// const string EXCEPTION_MESSAGE = "No friends of user have posted anything yet!";
+// GetPageServiceModel getPageServiceModel = new GetPageServiceModel
+// {
+// UserId = Guid.NewGuid()
+// };
+
+// User dummyUser = CreateDummyUser();
+// User anotherDummyUser = CreateAnotherDummyUser();
+// HashSet<User> friends = new HashSet<User>();
+// friends.Add(anotherDummyUser);
+// dummyUser.Friends = friends;
+
+// ReadPostServiceModel readPostServiceModel = new ReadPostServiceModel
+// {
+// PostId = Guid.NewGuid(),
+// Message = "Message"
+// };
+// List<ReadPostServiceModel> readPostServiceModels = new List<ReadPostServiceModel>();
+// readPostServiceModels.Add(readPostServiceModel);
+// ReadPageServiceModel readPageServiceModel = new ReadPageServiceModel
+// {
+// Posts = readPostServiceModels
+// };
+
+// this.UserRepositoryMock.Setup(p => p.GetByIdAsync(It.IsAny<Guid>())).Returns(Task.FromResult(dummyUser));
+// this.FeedRepositoryMock.Setup(p => p.GetFriendsPosts(It.IsAny<List<User>>(), It.IsAny<DateTime>(), It.IsAny<int>(), It.IsAny<int>())).Returns(Task.FromResult(new List<Post>()));
+
+// Exception ex = Assert.ThrowsAsync<ArgumentException>(() => this.FeedService.GetPage(getPageServiceModel));
+
+// Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message, "Wrong exception message");
+// }
+
+// [Test]
+// public void GetPage_ThrowsException_WhenUserHasNoFriendsToGetPostsFrom()
+// {
+// const string EXCEPTION_MESSAGE = "User has no friends to get feed from!";
+// GetPageServiceModel getPageServiceModel = new GetPageServiceModel
+// {
+// UserId = Guid.NewGuid()
+// };
+
+// User dummyUser = CreateDummyUser();
+
+// this.UserRepositoryMock.Setup(p => p.GetByIdAsync(It.IsAny<Guid>())).Returns(Task.FromResult(dummyUser));
+
+// Exception ex = Assert.ThrowsAsync<ArgumentException>(() => this.FeedService.GetPage(getPageServiceModel));
+
+// Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message, "Wrong exception message");
+// }
+// #endregion
+
+// #region HelperMethods
+// private User CreateDummyUser()
+// {
+// return new()
+// {
+// Id = Guid.NewGuid(),
+// UserName = "dummyUser",
+// FirstName = "Spas",
+// LastName = "Spasov",
+// Email = "abv@abv.bg",
+// };
+// }
+
+// private User CreateAnotherDummyUser()
+// {
+// return new()
+// {
+// Id = Guid.NewGuid(),
+// UserName = "anotherDummyUser",
+// FirstName = "Alex",
+// LastName = "Spiridonov",
+// Email = "a_spiridonov@abv.bg",
+// };
+// }
+// #endregion
+// }
+//}
diff --git a/src/Services/DevHive.Services.Tests/LanguageService.Tests.cs b/src/Services/DevHive.Services.Tests/LanguageService.Tests.cs
new file mode 100644
index 0000000..eefeaea
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/LanguageService.Tests.cs
@@ -0,0 +1,315 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Language;
+using DevHive.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class LanguageServiceTests
+ {
+ private Mock<ILanguageRepository> _languageRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private LanguageService _languageService;
+
+ #region SetUps
+ [SetUp]
+ public void SetUp()
+ {
+ this._languageRepositoryMock = new Mock<ILanguageRepository>();
+ this._mapperMock = new Mock<IMapper>();
+ this._languageService = new LanguageService(this._languageRepositoryMock.Object, this._mapperMock.Object);
+ }
+ #endregion
+
+ #region CreateLanguage
+ [Test]
+ public async Task CreateLanguage_ReturnsNonEmptyGuid_WhenEntityIsAddedSuccessfully()
+ {
+ string technologyName = "Gosho Trapov";
+ Guid id = Guid.NewGuid();
+ CreateLanguageServiceModel createLanguageServiceModel = new CreateLanguageServiceModel
+ {
+ Name = technologyName
+ };
+ Language language = new Language
+ {
+ Name = technologyName,
+ Id = id
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._languageRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Language>()))
+ .ReturnsAsync(true);
+ this._languageRepositoryMock
+ .Setup(p => p.GetByNameAsync(It.IsAny<string>()))
+ .ReturnsAsync(language);
+ this._mapperMock
+ .Setup(p => p.Map<Language>(It.IsAny<CreateLanguageServiceModel>()))
+ .Returns(language);
+
+ Guid result = await this._languageService.CreateLanguage(createLanguageServiceModel);
+
+ Assert.AreEqual(id, result);
+ }
+
+ [Test]
+ public async Task CreateLanguage_ReturnsEmptyGuid_WhenEntityIsNotAddedSuccessfully()
+ {
+ string languageName = "Gosho Trapov";
+
+ CreateLanguageServiceModel createLanguageServiceModel = new CreateLanguageServiceModel
+ {
+ Name = languageName
+ };
+ Language language = new Language
+ {
+ Name = languageName
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._languageRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Language>()))
+ .ReturnsAsync(false);
+ this._mapperMock
+ .Setup(p => p.Map<Language>(It.IsAny<CreateLanguageServiceModel>()))
+ .Returns(language);
+
+ Guid result = await this._languageService.CreateLanguage(createLanguageServiceModel);
+
+ Assert.IsTrue(result == Guid.Empty);
+
+ }
+
+ [Test]
+ public void CreateLanguage_ThrowsArgumentException_WhenEntityAlreadyExists()
+ {
+ string exceptionMessage = "Language already exists!";
+ string languageName = "Gosho Trapov";
+
+ CreateLanguageServiceModel createLanguageServiceModel = new CreateLanguageServiceModel
+ {
+ Name = languageName
+ };
+ Language language = new Language
+ {
+ Name = languageName
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._languageService.CreateLanguage(createLanguageServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region GetLanguageById
+ [Test]
+ public async Task GetLanguageById_ReturnsTheLanguage_WhenItExists()
+ {
+ Guid id = Guid.NewGuid();
+ string name = "Gosho Trapov";
+ Language language = new Language
+ {
+ Name = name
+ };
+ ReadLanguageServiceModel readLanguageServiceModel = new ReadLanguageServiceModel
+ {
+ Name = name
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(language);
+ this._mapperMock
+ .Setup(p => p.Map<ReadLanguageServiceModel>(It.IsAny<Language>()))
+ .Returns(readLanguageServiceModel);
+
+ ReadLanguageServiceModel result = await this._languageService.GetLanguageById(id);
+
+ Assert.AreEqual(name, result.Name);
+ }
+
+ [Test]
+ public void GetLanguageById_ThrowsException_WhenLanguageDoesNotExist()
+ {
+ string exceptionMessage = "The language does not exist";
+ Guid id = Guid.NewGuid();
+ this._languageRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Language>(null));
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._languageService.GetLanguageById(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region GetLanguages
+ [Test]
+ public void GetLanguages_ReturnsAllLanguages_IfAnyExist()
+ {
+ ReadLanguageServiceModel firstLanguage = new ReadLanguageServiceModel();
+ ReadLanguageServiceModel secondLanguage = new ReadLanguageServiceModel();
+ HashSet<ReadLanguageServiceModel> languges = new HashSet<ReadLanguageServiceModel>();
+ languges.Add(firstLanguage);
+ languges.Add(secondLanguage);
+
+ this._languageRepositoryMock
+ .Setup(p => p.GetLanguages())
+ .Returns(new HashSet<Language>());
+ this._mapperMock
+ .Setup(p => p.Map<HashSet<ReadLanguageServiceModel>>(It.IsAny<HashSet<Language>>()))
+ .Returns(languges);
+
+ HashSet<ReadLanguageServiceModel> result = this._languageService.GetLanguages();
+
+ Assert.GreaterOrEqual(2, result.Count, "GetLanguages does not return all languages");
+ }
+
+ [Test]
+ public void GetLanguages_ReturnsEmptyHashSet_IfNoLanguagesExist()
+ {
+ this._languageRepositoryMock
+ .Setup(p => p.GetLanguages())
+ .Returns(new HashSet<Language>());
+ this._mapperMock
+ .Setup(p => p.Map<HashSet<ReadLanguageServiceModel>>(It.IsAny<HashSet<Language>>()))
+ .Returns(new HashSet<ReadLanguageServiceModel>());
+
+ HashSet<ReadLanguageServiceModel> result = this._languageService.GetLanguages();
+
+ Assert.IsEmpty(result, "GetLanguages does not return empty string when no languages exist");
+ }
+ #endregion
+
+ #region UpdateLanguage
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task UpdateLanguage_ReturnsIfUpdateIsSuccessfull_WhenLanguageExistsy(bool shouldPass)
+ {
+ string name = "Gosho Trapov";
+ Guid id = Guid.NewGuid();
+ Language language = new Language
+ {
+ Name = name,
+ Id = id
+ };
+ UpdateLanguageServiceModel updateLanguageServiceModel = new UpdateLanguageServiceModel
+ {
+ Name = name,
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._languageRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Language>()))
+ .ReturnsAsync(shouldPass);
+ this._mapperMock
+ .Setup(p => p.Map<Language>(It.IsAny<UpdateLanguageServiceModel>()))
+ .Returns(language);
+
+ bool result = await this._languageService.UpdateLanguage(updateLanguageServiceModel);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void UpdateLanguage_ThrowsArgumentException_WhenLanguageDoesNotExist()
+ {
+ string exceptionMessage = "Language does not exist!";
+ UpdateLanguageServiceModel updateTechnologyServiceModel = new UpdateLanguageServiceModel
+ {
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._languageService.UpdateLanguage(updateTechnologyServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+
+ [Test]
+ public void UpdateLanguage_ThrowsException_WhenLanguageNameAlreadyExists()
+ {
+ string exceptionMessage = "Language name already exists in our data base!";
+ UpdateLanguageServiceModel updateTechnologyServiceModel = new UpdateLanguageServiceModel
+ {
+ };
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._languageService.UpdateLanguage(updateTechnologyServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region DeleteLanguage
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task DeleteLanguage_ShouldReturnIfDeletionIsSuccessfull_WhenLanguageExists(bool shouldPass)
+ {
+ Guid id = Guid.NewGuid();
+ Language language = new Language();
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._languageRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(language);
+ this._languageRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Language>()))
+ .ReturnsAsync(shouldPass);
+
+ bool result = await this._languageService.DeleteLanguage(id);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void DeleteLanguage_ThrowsException_WhenLanguageDoesNotExist()
+ {
+ string exceptionMessage = "Language does not exist!";
+ Guid id = Guid.NewGuid();
+
+ this._languageRepositoryMock
+ .Setup(p => p.DoesLanguageExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._languageService.DeleteLanguage(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/PostService.Tests.cs b/src/Services/DevHive.Services.Tests/PostService.Tests.cs
new file mode 100644
index 0000000..d534511
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/PostService.Tests.cs
@@ -0,0 +1,320 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Interfaces;
+using DevHive.Services.Models.Post;
+using DevHive.Services.Services;
+using Microsoft.AspNetCore.Http;
+using Moq;
+using NUnit.Framework;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class PostServiceTests
+ {
+ private const string MESSAGE = "Gosho Trapov";
+ private Mock<ICloudService> _cloudServiceMock;
+ private Mock<IPostRepository> _postRepositoryMock;
+ private Mock<ICommentRepository> _commentRepositoryMock;
+ private Mock<IUserRepository> _userRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private PostService _postService;
+
+ #region SetUps
+ [SetUp]
+ public void Setup()
+ {
+ this._postRepositoryMock = new Mock<IPostRepository>();
+ this._cloudServiceMock = new Mock<ICloudService>();
+ this._userRepositoryMock = new Mock<IUserRepository>();
+ this._commentRepositoryMock = new Mock<ICommentRepository>();
+ this._mapperMock = new Mock<IMapper>();
+ this._postService = new PostService(this._cloudServiceMock.Object, this._userRepositoryMock.Object, this._postRepositoryMock.Object, this._commentRepositoryMock.Object, this._mapperMock.Object);
+ }
+ #endregion
+
+ #region CreatePost
+ [Test]
+ public async Task CreatePost_ReturnsIdOfThePost_WhenItIsSuccessfullyCreated()
+ {
+ Guid postId = Guid.NewGuid();
+ User creator = new User { Id = Guid.NewGuid() };
+ CreatePostServiceModel createPostServiceModel = new CreatePostServiceModel
+ {
+ Files = new List<IFormFile>()
+ };
+ Post post = new Post
+ {
+ Message = MESSAGE,
+ Id = postId,
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Post>()))
+ .ReturnsAsync(true);
+ this._postRepositoryMock
+ .Setup(p => p.GetPostByCreatorAndTimeCreatedAsync(It.IsAny<Guid>(), It.IsAny<DateTime>()))
+ .ReturnsAsync(post);
+ this._userRepositoryMock
+ .Setup(p => p.DoesUserExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(creator);
+ this._mapperMock
+ .Setup(p => p.Map<Post>(It.IsAny<CreatePostServiceModel>()))
+ .Returns(post);
+
+ Guid result = await this._postService.CreatePost(createPostServiceModel);
+
+ Assert.AreEqual(postId, result, "CreatePost does not return the correct id");
+ }
+
+ [Test]
+ public async Task CreatePost_ReturnsEmptyGuid_WhenItIsNotSuccessfullyCreated()
+ {
+ CreatePostServiceModel createPostServiceModel = new CreatePostServiceModel
+ {
+ Files = new List<IFormFile>()
+ };
+ Post post = new Post
+ {
+ Message = MESSAGE,
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Post>()))
+ .ReturnsAsync(false);
+ this._userRepositoryMock
+ .Setup(p => p.DoesUserExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._mapperMock
+ .Setup(p => p.Map<Post>(It.IsAny<CreatePostServiceModel>()))
+ .Returns(post);
+
+ Guid result = await this._postService.CreatePost(createPostServiceModel);
+
+ Assert.AreEqual(Guid.Empty, result, "CreatePost does not return empty id");
+ }
+
+ [Test]
+ public void CreatePost_ThrowsException_WhenUserDoesNotExist()
+ {
+ const string EXCEPTION_MESSAGE = "User does not exist!";
+ CreatePostServiceModel createPostServiceModel = new CreatePostServiceModel
+ {
+ };
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._postService.CreatePost(createPostServiceModel), "CreatePost does not throw excpeion when the user does not exist");
+
+ // Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message, "Excapetion message is not correct");
+ }
+ #endregion
+
+ #region GetPostById
+ [Test]
+ public async Task GetPostById_ReturnsThePost_WhenItExists()
+ {
+ Guid creatorId = Guid.NewGuid();
+ User creator = new User { Id = creatorId };
+ Post post = new Post
+ {
+ Message = MESSAGE,
+ Creator = creator,
+ Ratings = new List<Rating>()
+ };
+ ReadPostServiceModel readPostServiceModel = new ReadPostServiceModel
+ {
+ Message = MESSAGE
+ };
+ User user = new User
+ {
+ Id = creatorId,
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(post);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._mapperMock
+ .Setup(p => p.Map<ReadPostServiceModel>(It.IsAny<Post>()))
+ .Returns(readPostServiceModel);
+
+ ReadPostServiceModel result = await this._postService.GetPostById(Guid.NewGuid());
+
+ Assert.AreEqual(MESSAGE, result.Message);
+ }
+
+ [Test]
+ public void GetPostById_ThorwsException_WhenTheUserDoesNotExist()
+ {
+ const string EXCEPTION_MESSAGE = "The user does not exist!";
+ Guid creatorId = Guid.NewGuid();
+ User creator = new User { Id = creatorId };
+ Post post = new Post
+ {
+ Message = MESSAGE,
+ Creator = creator
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(post);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._postService.GetPostById(Guid.NewGuid()), "GetPostById does not throw exception when the user does not exist");
+
+ // Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message);
+ }
+
+ [Test]
+ public void GetPostById_ThrowsException_WhenCommentDoesNotExist()
+ {
+ string exceptionMessage = "The post does not exist!";
+ Guid creatorId = Guid.NewGuid();
+ User user = new User
+ {
+ Id = creatorId,
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Post>(null));
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._postService.GetPostById(Guid.NewGuid()));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region UpdatePost
+ [Test]
+ public async Task UpdatePost_ReturnsTheIdOfThePost_WhenUpdatedSuccessfully()
+ {
+ Guid id = Guid.NewGuid();
+ Post post = new Post
+ {
+ Id = id,
+ Message = MESSAGE
+ };
+ UpdatePostServiceModel updatePostServiceModel = new UpdatePostServiceModel
+ {
+ PostId = id,
+ NewMessage = MESSAGE,
+ Files = new List<IFormFile>()
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._postRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Post>()))
+ .ReturnsAsync(true);
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(post);
+ this._mapperMock
+ .Setup(p => p.Map<Post>(It.IsAny<UpdatePostServiceModel>()))
+ .Returns(post);
+
+ Guid result = await this._postService.UpdatePost(updatePostServiceModel);
+
+ Assert.AreEqual(updatePostServiceModel.PostId, result);
+ }
+
+ [Test]
+ public async Task UpdatePost_ReturnsEmptyId_WhenThePostIsNotUpdatedSuccessfully()
+ {
+ Post post = new Post
+ {
+ Message = MESSAGE
+ };
+ UpdatePostServiceModel updatePostServiceModel = new UpdatePostServiceModel
+ {
+ PostId = Guid.NewGuid(),
+ NewMessage = MESSAGE,
+ Files = new List<IFormFile>()
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._postRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Post>()))
+ .ReturnsAsync(false);
+ this._mapperMock
+ .Setup(p => p.Map<Post>(It.IsAny<UpdatePostServiceModel>()))
+ .Returns(post);
+
+ Guid result = await this._postService.UpdatePost(updatePostServiceModel);
+
+ Assert.AreEqual(Guid.Empty, result);
+ }
+
+ [Test]
+ public void UpdatePost_ThrowsArgumentException_WhenCommentDoesNotExist()
+ {
+ string exceptionMessage = "Post does not exist!";
+ UpdatePostServiceModel updatePostServiceModel = new UpdatePostServiceModel
+ {
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._postService.UpdatePost(updatePostServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region DeletePost
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task Deletepost_ShouldReturnIfDeletionIsSuccessfull_WhenPostExists(bool shouldPass)
+ {
+ Guid id = Guid.NewGuid();
+ Post post = new Post();
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(post);
+ this._postRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Post>()))
+ .ReturnsAsync(shouldPass);
+
+ bool result = await this._postService.DeletePost(id);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void DeletePost_ThrowsException_WhenPostDoesNotExist()
+ {
+ string exceptionMessage = "Post does not exist!";
+ Guid id = Guid.NewGuid();
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._postService.DeletePost(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+ }
+}
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..786de7b
--- /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.UpdateProfilePicture(profilePictureServiceModel);
+ //
+ // //Assert
+ // Assert.IsNotEmpty(profilePicURL);
+ // }
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/RatingService.Tests.cs b/src/Services/DevHive.Services.Tests/RatingService.Tests.cs
new file mode 100644
index 0000000..9f4300b
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/RatingService.Tests.cs
@@ -0,0 +1,448 @@
+using System;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Rating;
+using DevHive.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class RatingServiceTests
+ {
+ private Mock<IPostRepository> _postRepositoryMock;
+ private Mock<IRatingRepository> _ratingRepositoryMock;
+ private Mock<IUserRepository> _userRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private RatingService _ratingService;
+
+ #region SetUps
+ [SetUp]
+ public void SetUp()
+ {
+ this._postRepositoryMock = new Mock<IPostRepository>();
+ this._ratingRepositoryMock = new Mock<IRatingRepository>();
+ this._userRepositoryMock = new Mock<IUserRepository>();
+ this._mapperMock = new Mock<IMapper>();
+ this._ratingService = new RatingService(this._postRepositoryMock.Object, this._ratingRepositoryMock.Object, this._userRepositoryMock.Object, this._mapperMock.Object);
+ }
+ #endregion
+
+ #region Create
+ [Test]
+ public async Task RatePost_ReturnsNonEmptyGuid_WhenEntityIsAddedSuccessfully()
+ {
+ bool isLike = true;
+ Guid id = Guid.NewGuid();
+ Guid postId = Guid.NewGuid();
+ Guid userId = Guid.NewGuid();
+ CreateRatingServiceModel createRatingServiceModel = new CreateRatingServiceModel
+ {
+ PostId = postId,
+ UserId = userId,
+ IsLike = isLike
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike
+ };
+ User user = new User
+ {
+ Id = userId
+ };
+ Post post = new Post
+ {
+ Id = postId
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.UserRatedPost(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(post);
+ this._ratingRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Rating>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(rating);
+ this._mapperMock
+ .Setup(p => p.Map<Rating>(It.IsAny<CreateRatingServiceModel>()))
+ .Returns(rating);
+
+ Guid result = await this._ratingService.RatePost(createRatingServiceModel);
+
+ Assert.AreEqual(id, result);
+ }
+
+ [Test]
+ public async Task RatePost_ReturnsEmptyGuid_WhenEntityIsNotAddedSuccessfully()
+ {
+ bool isLike = true;
+ Guid id = Guid.NewGuid();
+ Guid postId = Guid.NewGuid();
+ Guid userId = Guid.NewGuid();
+ CreateRatingServiceModel createRatingServiceModel = new CreateRatingServiceModel
+ {
+ PostId = postId,
+ UserId = userId,
+ IsLike = isLike
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike
+ };
+ User user = new User
+ {
+ Id = userId
+ };
+ Post post = new Post
+ {
+ Id = postId
+ };
+
+ this._postRepositoryMock
+ .Setup(p => p.DoesPostExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.UserRatedPost(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._postRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(post);
+ this._ratingRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Rating>()))
+ .ReturnsAsync(false);
+ this._mapperMock
+ .Setup(p => p.Map<Rating>(It.IsAny<CreateRatingServiceModel>()))
+ .Returns(rating);
+
+ Guid result = await this._ratingService.RatePost(createRatingServiceModel);
+
+ Assert.AreEqual(result, Guid.Empty);
+ }
+ #endregion
+
+ #region Read
+ [Test]
+ public async Task GetRatingById_ReturnsTheRating_WhenItExists()
+ {
+ Guid id = Guid.NewGuid();
+ bool isLike = true;
+ User user = new User
+ {
+ Id = Guid.NewGuid()
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike,
+ User = user
+ };
+ ReadRatingServiceModel readRatingServiceModel = new ReadRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(rating);
+ this._mapperMock
+ .Setup(p => p.Map<ReadRatingServiceModel>(It.IsAny<Rating>()))
+ .Returns(readRatingServiceModel);
+
+ ReadRatingServiceModel result = await this._ratingService.GetRatingById(id);
+
+ Assert.AreEqual(isLike, result.IsLike);
+ }
+
+ // [Test]
+ // public void GetRatingById_ThrowsException_WhenRatingDoesNotExist()
+ // {
+ // string exceptionMessage = "The rating does not exist";
+ // this._ratingRepositoryMock
+ // .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ // .Returns(Task.FromResult<Rating>(null));
+ //
+ // Exception ex = Assert.ThrowsAsync<ArgumentException>(() => this._ratingService.GetRatingById(Guid.Empty));
+ //
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ // }
+
+ [Test]
+ public async Task GetRatingByPostAndUser_ReturnsTheRating_WhenItExists()
+ {
+ Guid id = Guid.NewGuid();
+ bool isLike = true;
+ User user = new User
+ {
+ Id = Guid.NewGuid()
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike,
+ User = user
+ };
+ ReadRatingServiceModel readRatingServiceModel = new ReadRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(rating);
+ this._mapperMock
+ .Setup(p => p.Map<ReadRatingServiceModel>(It.IsAny<Rating>()))
+ .Returns(readRatingServiceModel);
+
+ ReadRatingServiceModel result = await this._ratingService.GetRatingByPostAndUser(user.Id, Guid.Empty);
+
+ Assert.AreEqual(isLike, result.IsLike);
+ }
+
+ // [Test]
+ // public void GetRatingByPostAndUser_ThrowsException_WhenRatingDoesNotExist()
+ // {
+ // string exceptionMessage = "The rating does not exist";
+ // this._ratingRepositoryMock
+ // .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ // .Returns(Task.FromResult<Rating>(null));
+ //
+ // Exception ex = Assert.ThrowsAsync<ArgumentException>(() => this._ratingService.GetRatingById(Guid.Empty));
+ //
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ // }
+ #endregion
+
+ #region Update
+ [Test]
+ public async Task UpdateRating_ReturnsObject_WhenRatingIsUpdatedSuccessfully()
+ {
+ Guid id = Guid.NewGuid();
+ bool isLike = true;
+ UpdateRatingServiceModel updateRatingServiceModel = new UpdateRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+ User user = new User
+ {
+ Id = Guid.NewGuid()
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike,
+ User = user
+ };
+ ReadRatingServiceModel readRatingServiceModel = new ReadRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(rating);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._ratingRepositoryMock
+ .Setup(p => p.UserRatedPost(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Rating>()))
+ .ReturnsAsync(true);
+ this._mapperMock
+ .Setup(p => p.Map<ReadRatingServiceModel>(It.IsAny<Rating>()))
+ .Returns(readRatingServiceModel);
+
+ ReadRatingServiceModel result = await this._ratingService.UpdateRating(updateRatingServiceModel);
+
+ Assert.AreEqual(result, readRatingServiceModel);
+ }
+
+ [Test]
+ public async Task UpdateRating_ReturnsNull_WhenRatingIsNotUpdatedSuccessfully()
+ {
+ Guid id = Guid.NewGuid();
+ bool isLike = true;
+ UpdateRatingServiceModel updateRatingServiceModel = new UpdateRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+ User user = new User
+ {
+ Id = Guid.NewGuid()
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike,
+ User = user
+ };
+ ReadRatingServiceModel readRatingServiceModel = new ReadRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(rating);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._ratingRepositoryMock
+ .Setup(p => p.UserRatedPost(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Rating>()))
+ .ReturnsAsync(false);
+
+ ReadRatingServiceModel result = await this._ratingService.UpdateRating(updateRatingServiceModel);
+
+ Assert.IsNull(result);
+ }
+
+ [Test]
+ public void UpdateRating_ThrowsException_WhenRatingDoesNotExists()
+ {
+ string exceptionMessage = "Rating does not exist!";
+ UpdateRatingServiceModel updateRatingServiceModel = new UpdateRatingServiceModel
+ {
+ Id = Guid.Empty,
+ IsLike = true
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Rating>(null));
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._ratingService.UpdateRating(updateRatingServiceModel));
+
+ // Assert.AreEqual(ex.Message, exceptionMessage);
+ }
+
+ [Test]
+ public void UpdateRating_ThrowsException_WhenUserHasNotRatedPost()
+ {
+ string exceptionMessage = "User has not rated the post!";
+ Guid id = Guid.NewGuid();
+ bool isLike = true;
+ UpdateRatingServiceModel updateRatingServiceModel = new UpdateRatingServiceModel
+ {
+ Id = id,
+ IsLike = isLike
+ };
+ User user = new User
+ {
+ Id = Guid.NewGuid()
+ };
+ Rating rating = new Rating
+ {
+ Id = id,
+ IsLike = isLike,
+ User = user
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.GetRatingByUserAndPostId(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(rating);
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._ratingRepositoryMock
+ .Setup(p => p.UserRatedPost(It.IsAny<Guid>(), It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentException>(() => this._ratingService.UpdateRating(updateRatingServiceModel));
+
+ // Assert.AreEqual(ex.Message, exceptionMessage);
+ }
+ #endregion
+
+ #region Delete
+ [Test]
+ public async Task DeleteRating_ReturnsTrue_WhenRatingIsDeletedSuccessfully()
+ {
+ Guid ratingId = Guid.NewGuid();
+ Rating rating = new Rating
+ {
+ Id = ratingId
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.DoesRatingExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Rating>(null));
+ this._ratingRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Rating>()))
+ .ReturnsAsync(true);
+
+ bool result = await this._ratingService.DeleteRating(ratingId);
+
+ Assert.IsTrue(result);
+ }
+
+ [Test]
+ public async Task DeleteRating_ReturnsFalse_WhenRatingIsNotDeletedSuccessfully()
+ {
+ Guid ratingId = Guid.NewGuid();
+ Rating rating = new Rating
+ {
+ Id = ratingId
+ };
+
+ this._ratingRepositoryMock
+ .Setup(p => p.DoesRatingExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._ratingRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Rating>(null));
+ this._ratingRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Rating>()))
+ .ReturnsAsync(false);
+
+ bool result = await this._ratingService.DeleteRating(ratingId);
+
+ Assert.IsFalse(result);
+ }
+
+ [Test]
+ public void DeleteRating_ThrowsException_WhenRatingDoesNotExist()
+ {
+ string exceptionMessage = "Rating does not exist!";
+
+ this._ratingRepositoryMock
+ .Setup(p => p.DoesRatingExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._ratingService.DeleteRating(Guid.Empty));
+
+ // Assert.AreEqual(ex.Message, exceptionMessage);
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/RoleService.Tests.cs b/src/Services/DevHive.Services.Tests/RoleService.Tests.cs
new file mode 100644
index 0000000..c286c80
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/RoleService.Tests.cs
@@ -0,0 +1,271 @@
+using System;
+using System.Data;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Role;
+using DevHive.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class RoleServiceTests
+ {
+ private Mock<IRoleRepository> _roleRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private RoleService _roleService;
+
+ #region SetUps
+ [SetUp]
+ public void Setup()
+ {
+ this._roleRepositoryMock = new Mock<IRoleRepository>();
+ this._mapperMock = new Mock<IMapper>();
+ this._roleService = new RoleService(this._roleRepositoryMock.Object, this._mapperMock.Object);
+ }
+ #endregion
+
+ #region CreateRole
+ [Test]
+ public async Task CreateRole_ReturnsNonEmptyGuid_WhenEntityIsAddedSuccessfully()
+ {
+ string roleName = "Gosho Trapov";
+ Guid id = Guid.NewGuid();
+ CreateRoleServiceModel createRoleServiceModel = new CreateRoleServiceModel
+ {
+ Name = roleName
+ };
+ Role role = new()
+ {
+ Name = roleName,
+ Id = id
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesNameExist(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._roleRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Role>()))
+ .ReturnsAsync(true);
+ this._roleRepositoryMock
+ .Setup(p => p.GetByNameAsync(It.IsAny<string>()))
+ .ReturnsAsync(role);
+ this._mapperMock
+ .Setup(p => p.Map<Role>(It.IsAny<CreateRoleServiceModel>()))
+ .Returns(role);
+
+ Guid result = await this._roleService.CreateRole(createRoleServiceModel);
+
+ Assert.AreEqual(id, result);
+ }
+
+ [Test]
+ public async Task CreateRoley_ReturnsEmptyGuid_WhenEntityIsNotAddedSuccessfully()
+ {
+ string roleName = "Gosho Trapov";
+
+ CreateRoleServiceModel createRoleServiceModel = new CreateRoleServiceModel
+ {
+ Name = roleName
+ };
+ Role role = new Role
+ {
+ Name = roleName
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesNameExist(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._roleRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Role>()))
+ .ReturnsAsync(false);
+ this._mapperMock
+ .Setup(p => p.Map<Role>(It.IsAny<CreateRoleServiceModel>()))
+ .Returns(role);
+
+ Guid result = await this._roleService.CreateRole(createRoleServiceModel);
+
+ Assert.IsTrue(result == Guid.Empty);
+ }
+
+ [Test]
+ public void CreateTechnology_ThrowsArgumentException_WhenEntityAlreadyExists()
+ {
+ string exceptionMessage = "Role already exists!";
+ string roleName = "Gosho Trapov";
+
+ CreateRoleServiceModel createRoleServiceModel = new CreateRoleServiceModel
+ {
+ Name = roleName
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesNameExist(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._roleService.CreateRole(createRoleServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region GetRoleById
+ [Test]
+ public async Task GetRoleById_ReturnsTheRole_WhenItExists()
+ {
+ Guid id = Guid.NewGuid();
+ string name = "Gosho Trapov";
+ Role role = new Role
+ {
+ Name = name
+ };
+ RoleServiceModel roleServiceModel = new RoleServiceModel
+ {
+ Name = name
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(role);
+ this._mapperMock
+ .Setup(p => p.Map<RoleServiceModel>(It.IsAny<Role>()))
+ .Returns(roleServiceModel);
+
+ RoleServiceModel result = await this._roleService.GetRoleById(id);
+
+ Assert.AreEqual(name, result.Name);
+ }
+
+ [Test]
+ public void GetRoleById_ThrowsException_WhenRoleDoesNotExist()
+ {
+ string exceptionMessage = "Role does not exist!";
+ Guid id = Guid.NewGuid();
+ this._roleRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Role>(null));
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._roleService.GetRoleById(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region UpdateRole
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task UpdateRole_ReturnsIfUpdateIsSuccessfull_WhenRoleExistsy(bool shouldPass)
+ {
+ string name = "Gosho Trapov";
+ Guid id = Guid.NewGuid();
+ Role role = new Role
+ {
+ Name = name,
+ Id = id
+ };
+ UpdateRoleServiceModel updateRoleServiceModel = new UpdateRoleServiceModel
+ {
+ Name = name,
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesRoleExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._roleRepositoryMock
+ .Setup(p => p.DoesNameExist(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._roleRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Role>()))
+ .ReturnsAsync(shouldPass);
+ this._mapperMock
+ .Setup(p => p.Map<Role>(It.IsAny<UpdateRoleServiceModel>()))
+ .Returns(role);
+
+ bool result = await this._roleService.UpdateRole(updateRoleServiceModel);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void UpdateRole_ThrowsException_WhenRoleDoesNotExist()
+ {
+ string exceptionMessage = "Role does not exist!";
+ UpdateRoleServiceModel updateRoleServiceModel = new UpdateRoleServiceModel
+ {
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesRoleExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._roleService.UpdateRole(updateRoleServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+
+ [Test]
+ public void UpdateRole_ThrowsException_WhenRoleNameAlreadyExists()
+ {
+ string exceptionMessage = "Role name already exists!";
+ UpdateRoleServiceModel updateRoleServiceModel = new UpdateRoleServiceModel
+ {
+ };
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesRoleExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._roleRepositoryMock
+ .Setup(p => p.DoesNameExist(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._roleService.UpdateRole(updateRoleServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region DeleteRole
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task DeleteRole_ShouldReturnIfDeletionIsSuccessfull_WhenRoleExists(bool shouldPass)
+ {
+ Guid id = Guid.NewGuid();
+ Role role = new Role();
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesRoleExist(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._roleRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(role);
+ this._roleRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Role>()))
+ .ReturnsAsync(shouldPass);
+
+ bool result = await this._roleService.DeleteRole(id);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void DeleteRole_ThrowsException_WhenRoleDoesNotExist()
+ {
+ string exceptionMessage = "Role does not exist!";
+ Guid id = Guid.NewGuid();
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesRoleExist(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._roleService.DeleteRole(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/TechnologyServices.Tests.cs b/src/Services/DevHive.Services.Tests/TechnologyServices.Tests.cs
new file mode 100644
index 0000000..e11650f
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/TechnologyServices.Tests.cs
@@ -0,0 +1,311 @@
+using AutoMapper;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Technology;
+using DevHive.Services.Services;
+using Moq;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Threading.Tasks;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class TechnologyServicesTests
+ {
+ private Mock<ITechnologyRepository> _technologyRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private TechnologyService _technologyService;
+
+ #region SetUps
+ [SetUp]
+ public void Setup()
+ {
+ this._technologyRepositoryMock = new Mock<ITechnologyRepository>();
+ this._mapperMock = new Mock<IMapper>();
+ this._technologyService = new TechnologyService(this._technologyRepositoryMock.Object, this._mapperMock.Object);
+ }
+ #endregion
+
+ #region CreateTechnology
+ [Test]
+ public async Task CreateTechnology_ReturnsNonEmptyGuid_WhenEntityIsAddedSuccessfully()
+ {
+ string technologyName = "Gosho Trapov";
+ Guid id = Guid.NewGuid();
+ CreateTechnologyServiceModel createTechnologyServiceModel = new()
+ {
+ Name = technologyName
+ };
+ Technology technology = new()
+ {
+ Name = technologyName,
+ Id = id
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._technologyRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Technology>()))
+ .ReturnsAsync(true);
+ this._technologyRepositoryMock
+ .Setup(p => p.GetByNameAsync(It.IsAny<string>()))
+ .ReturnsAsync(technology);
+ this._mapperMock
+ .Setup(p => p.Map<Technology>(It.IsAny<CreateTechnologyServiceModel>()))
+ .Returns(technology);
+
+ Guid result = await this._technologyService.CreateTechnology(createTechnologyServiceModel);
+
+ Assert.AreEqual(id, result);
+ }
+
+ [Test]
+ public async Task CreateTechnology_ReturnsEmptyGuid_WhenEntityIsNotAddedSuccessfully()
+ {
+ string technologyName = "Gosho Trapov";
+
+ CreateTechnologyServiceModel createTechnologyServiceModel = new()
+ {
+ Name = technologyName
+ };
+ Technology technology = new()
+ {
+ Name = technologyName
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._technologyRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<Technology>()))
+ .ReturnsAsync(false);
+ this._mapperMock
+ .Setup(p => p.Map<Technology>(It.IsAny<CreateTechnologyServiceModel>()))
+ .Returns(technology);
+
+ Guid result = await this._technologyService.CreateTechnology(createTechnologyServiceModel);
+
+ Assert.IsTrue(result == Guid.Empty);
+ }
+
+ [Test]
+ public void CreateTechnology_ThrowsArgumentException_WhenEntityAlreadyExists()
+ {
+ string exceptionMessage = "Technology already exists!";
+ string technologyName = "Gosho Trapov";
+
+ CreateTechnologyServiceModel createTechnologyServiceModel = new()
+ {
+ Name = technologyName
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._technologyService.CreateTechnology(createTechnologyServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region GetTechnologyById
+ [Test]
+ public async Task GetTechnologyById_ReturnsTheTechnology_WhenItExists()
+ {
+ Guid id = Guid.NewGuid();
+ string name = "Gosho Trapov";
+ Technology technology = new()
+ {
+ Name = name
+ };
+ ReadTechnologyServiceModel readTechnologyServiceModel = new()
+ {
+ Name = name
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(technology);
+ this._mapperMock
+ .Setup(p => p.Map<ReadTechnologyServiceModel>(It.IsAny<Technology>()))
+ .Returns(readTechnologyServiceModel);
+
+ ReadTechnologyServiceModel result = await this._technologyService.GetTechnologyById(id);
+
+ Assert.AreEqual(name, result.Name);
+ }
+
+ [Test]
+ public void GetTechnologyById_ThrowsException_WhenTechnologyDoesNotExist()
+ {
+ string exceptionMessage = "The technology does not exist";
+ Guid id = Guid.NewGuid();
+ this._technologyRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<Technology>(null));
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._technologyService.GetTechnologyById(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region GetTechnologies
+ [Test]
+ public void GetTechnologies_ReturnsAllLanguages_IfAnyExist()
+ {
+ ReadTechnologyServiceModel firstTechnology = new ReadTechnologyServiceModel();
+ ReadTechnologyServiceModel secondTechnology = new ReadTechnologyServiceModel();
+ HashSet<ReadTechnologyServiceModel> technologies = new HashSet<ReadTechnologyServiceModel>();
+ technologies.Add(firstTechnology);
+ technologies.Add(secondTechnology);
+
+ this._technologyRepositoryMock
+ .Setup(p => p.GetTechnologies())
+ .Returns(new HashSet<Technology>());
+ this._mapperMock
+ .Setup(p => p.Map<HashSet<ReadTechnologyServiceModel>>(It.IsAny<HashSet<Technology>>()))
+ .Returns(technologies);
+
+ HashSet<ReadTechnologyServiceModel> result = this._technologyService.GetTechnologies();
+
+ Assert.GreaterOrEqual(2, result.Count, "GetTechnologies does not return all technologies");
+ }
+
+ [Test]
+ public void GetLanguages_ReturnsEmptyHashSet_IfNoLanguagesExist()
+ {
+ this._technologyRepositoryMock
+ .Setup(p => p.GetTechnologies())
+ .Returns(new HashSet<Technology>());
+ this._mapperMock
+ .Setup(p => p.Map<HashSet<ReadTechnologyServiceModel>>(It.IsAny<HashSet<Technology>>()))
+ .Returns(new HashSet<ReadTechnologyServiceModel>());
+
+ HashSet<ReadTechnologyServiceModel> result = this._technologyService.GetTechnologies();
+
+ Assert.IsEmpty(result, "GetTechnologies does not return empty string when no technologies exist");
+ }
+ #endregion
+
+ #region UpdateTechnology
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task UpdateTechnology_ReturnsIfUpdateIsSuccessfull_WhenTechnologyExistsy(bool shouldPass)
+ {
+ string name = "Gosho Trapov";
+ Guid id = Guid.NewGuid();
+ Technology technology = new Technology
+ {
+ Name = name,
+ Id = id
+ };
+ UpdateTechnologyServiceModel updatetechnologyServiceModel = new UpdateTechnologyServiceModel
+ {
+ Name = name,
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._technologyRepositoryMock
+ .Setup(p => p.EditAsync(It.IsAny<Guid>(), It.IsAny<Technology>()))
+ .ReturnsAsync(shouldPass);
+ this._mapperMock
+ .Setup(p => p.Map<Technology>(It.IsAny<UpdateTechnologyServiceModel>()))
+ .Returns(technology);
+
+ bool result = await this._technologyService.UpdateTechnology(updatetechnologyServiceModel);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void UpdateTechnology_ThrowsException_WhenTechnologyDoesNotExist()
+ {
+ string exceptionMessage = "Technology does not exist!";
+ UpdateTechnologyServiceModel updateTechnologyServiceModel = new UpdateTechnologyServiceModel
+ {
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._technologyService.UpdateTechnology(updateTechnologyServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+
+ [Test]
+ public void UpdateTechnology_ThrowsException_WhenTechnologyNameAlreadyExists()
+ {
+ string exceptionMessage = "Technology name already exists!";
+ UpdateTechnologyServiceModel updateTechnologyServiceModel = new UpdateTechnologyServiceModel
+ {
+ };
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyNameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._technologyService.UpdateTechnology(updateTechnologyServiceModel));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+
+ #region DeleteTechnology
+
+ [Test]
+ [TestCase(true)]
+ [TestCase(false)]
+ public async Task DeleteTechnology_ShouldReturnIfDeletionIsSuccessfull_WhenTechnologyExists(bool shouldPass)
+ {
+ Guid id = Guid.NewGuid();
+ Technology technology = new Technology();
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._technologyRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(technology);
+ this._technologyRepositoryMock
+ .Setup(p => p.DeleteAsync(It.IsAny<Technology>()))
+ .ReturnsAsync(shouldPass);
+
+ bool result = await this._technologyService.DeleteTechnology(id);
+
+ Assert.AreEqual(shouldPass, result);
+ }
+
+ [Test]
+ public void DeleteTechnology_ThrowsException_WhenTechnologyDoesNotExist()
+ {
+ string exceptionMessage = "Technology does not exist!";
+ Guid id = Guid.NewGuid();
+
+ this._technologyRepositoryMock
+ .Setup(p => p.DoesTechnologyExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._technologyService.DeleteTechnology(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorecct exception message");
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services.Tests/UserService.Tests.cs b/src/Services/DevHive.Services.Tests/UserService.Tests.cs
new file mode 100644
index 0000000..44ca7b4
--- /dev/null
+++ b/src/Services/DevHive.Services.Tests/UserService.Tests.cs
@@ -0,0 +1,429 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Threading.Tasks;
+using AutoMapper;
+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;
+using DevHive.Services.Services;
+using Moq;
+using NUnit.Framework;
+
+namespace DevHive.Services.Tests
+{
+ [TestFixture]
+ public class UserServiceTests
+ {
+ private Mock<ICloudService> _cloudServiceMock;
+ private Mock<IUserRepository> _userRepositoryMock;
+ private Mock<IRoleRepository> _roleRepositoryMock;
+ private Mock<ILanguageRepository> _languageRepositoryMock;
+ private Mock<ITechnologyRepository> _technologyRepositoryMock;
+ private Mock<IMapper> _mapperMock;
+ private Mock<IJwtService> _jwtServiceMock;
+ private UserService _userService;
+
+ #region SetUps
+ [SetUp]
+ public void Setup()
+ {
+ this._userRepositoryMock = new Mock<IUserRepository>();
+ this._roleRepositoryMock = new Mock<IRoleRepository>();
+ this._cloudServiceMock = new Mock<ICloudService>();
+ this._languageRepositoryMock = new Mock<ILanguageRepository>();
+ this._technologyRepositoryMock = new Mock<ITechnologyRepository>();
+ this._jwtServiceMock = new Mock<IJwtService>();
+ this._mapperMock = new Mock<IMapper>();
+ this._userService = new UserService(
+ this._userRepositoryMock.Object,
+ this._languageRepositoryMock.Object,
+ this._roleRepositoryMock.Object,
+ this._technologyRepositoryMock.Object,
+ this._mapperMock.Object,
+ this._jwtServiceMock.Object);
+ }
+ #endregion
+
+ #region LoginUser
+ [Test]
+ public async Task LoginUser_ReturnsTokenModel_WhenLoggingUserIn()
+ {
+ string somePassword = "I'm_Nigga";
+
+ LoginServiceModel loginServiceModel = new()
+ {
+ Password = somePassword
+ };
+ User user = new()
+ {
+ Id = Guid.NewGuid(),
+ PasswordHash = somePassword,
+ UserName = "g_trapov"
+ };
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.VerifyPassword(It.IsAny<User>(), It.IsAny<string>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.GetByUsernameAsync(It.IsAny<string>()))
+ .ReturnsAsync(user);
+
+ string jwtSecurityToken = "akjdhfakndvlahdfkljahdlfkjhasldf";
+ this._jwtServiceMock
+ .Setup(p => p.GenerateJwtToken(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<List<string>>()))
+ .Returns(jwtSecurityToken);
+ TokenModel tokenModel = await this._userService.LoginUser(loginServiceModel);
+
+ Assert.AreEqual(jwtSecurityToken, tokenModel.Token, "LoginUser does not return the correct token");
+ }
+
+ [Test]
+ public void LoginUser_ThrowsException_WhenUserNameDoesNotExist()
+ {
+ LoginServiceModel loginServiceModel = new();
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<InvalidDataException>(
+ () => this._userService.LoginUser(loginServiceModel));
+
+ Assert.AreEqual("Invalid The Username!", ex.Message, "Incorrect Exception message");
+ }
+
+ [Test]
+ public void LoginUser_ThrowsException_WhenPasswordIsIncorrect()
+ {
+ string somePassword = "I'm_Nigga";
+
+ LoginServiceModel loginServiceModel = new()
+ {
+ Password = somePassword
+ };
+ User user = new()
+ {
+ Id = Guid.NewGuid(),
+ };
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.GetByUsernameAsync(It.IsAny<string>()))
+ .ReturnsAsync(user);
+
+ Exception ex = Assert.ThrowsAsync<InvalidDataException>(() => this._userService.LoginUser(loginServiceModel));
+
+ Assert.AreEqual("Incorrect password!", ex.Message, "Incorrect Exception message");
+ }
+ #endregion
+
+ #region RegisterUser
+ [Test]
+ public async Task RegisterUser_ReturnsTokenModel_WhenUserIsSuccessfull()
+ {
+ Guid userId = Guid.NewGuid();
+ RegisterServiceModel registerServiceModel = new()
+ {
+ Password = "ImNigga"
+ };
+ User user = new()
+ {
+ Id = userId,
+ UserName = "g_trapov"
+ };
+ Role role = new() { Name = Role.DefaultRole };
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._userRepositoryMock
+ .Setup(p => p.VerifyPassword(It.IsAny<User>(), It.IsAny<string>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.DoesEmailExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._userRepositoryMock
+ .Setup(p => p.AddAsync(It.IsAny<User>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.AddRoleToUser(It.IsAny<User>(), It.IsAny<string>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.GetByUsernameAsync(It.IsAny<string>()))
+ .ReturnsAsync(user);
+
+ this._roleRepositoryMock
+ .Setup(p => p.DoesNameExist(It.IsAny<string>()))
+ .ReturnsAsync(true);
+ this._roleRepositoryMock
+ .Setup(p => p.GetByNameAsync(It.IsAny<string>()))
+ .ReturnsAsync(role);
+
+ this._mapperMock
+ .Setup(p => p.Map<User>(It.IsAny<RegisterServiceModel>()))
+ .Returns(user);
+
+ string jwtSecurityToken = "akjdhfakndvlahdfkljahdlfkjhasldf";
+ this._jwtServiceMock
+ .Setup(p => p.GenerateJwtToken(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<List<string>>()))
+ .Returns(jwtSecurityToken);
+ TokenModel tokenModel = await this._userService.RegisterUser(registerServiceModel);
+
+ Assert.AreEqual(jwtSecurityToken, tokenModel.Token, "RegisterUser does not return the correct token");
+ }
+
+ [Test]
+ public void RegisterUser_ThrowsException_WhenUsernameAlreadyExists()
+ {
+ const string EXCEPTION_MESSAGE = "The Username already exists!";
+ RegisterServiceModel registerServiceModel = new();
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(
+ () => this._userService.RegisterUser(registerServiceModel));
+
+ Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message, "Incorrect Exception message");
+ }
+
+ [Test]
+ public void RegisterUser_ThrowsException_WhenEmailAlreadyExists()
+ {
+ RegisterServiceModel registerServiceModel = new();
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(false);
+ this._userRepositoryMock
+ .Setup(p => p.DoesEmailExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._userService.RegisterUser(registerServiceModel));
+
+ Assert.AreEqual("The Email already exists!", ex.Message, "Incorrect Exception message");
+ }
+ #endregion
+
+ #region GetUserById
+ [Test]
+ public async Task GetUserById_ReturnsTheUser_WhenItExists()
+ {
+ Guid id = new();
+ string username = "g_trapov";
+ User user = new();
+ UserServiceModel userServiceModel = new()
+ {
+ UserName = username
+ };
+
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(user);
+ this._mapperMock
+ .Setup(p => p.Map<UserServiceModel>(It.IsAny<User>()))
+ .Returns(userServiceModel);
+
+ UserServiceModel result = await this._userService.GetUserById(id);
+
+ Assert.AreEqual(username, result.UserName);
+ }
+
+ [Test]
+ public void GetTechnologyById_ThrowsException_WhenTechnologyDoesNotExist()
+ {
+ Guid id = new();
+ this._userRepositoryMock
+ .Setup(p => p.GetByIdAsync(It.IsAny<Guid>()))
+ .Returns(Task.FromResult<User>(null));
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._userService.GetUserById(id));
+
+ // Assert.AreEqual("User does not exist!", ex.Message, "Incorrect exception message");
+ }
+ #endregion
+
+ #region GetUserByUsername
+ [Test]
+ public async Task GetUserByUsername_ReturnsTheCorrectUser_IfItExists()
+ {
+ string username = "g_trapov";
+ User user = new();
+ UserServiceModel userServiceModel = new()
+ {
+ UserName = username
+ };
+
+ this._userRepositoryMock
+ .Setup(p => p.GetByUsernameAsync(It.IsAny<string>()))
+ .ReturnsAsync(user);
+ this._mapperMock
+ .Setup(p => p.Map<UserServiceModel>(It.IsAny<User>()))
+ .Returns(userServiceModel);
+
+ UserServiceModel result = await this._userService.GetUserByUsername(username);
+
+ Assert.AreEqual(username, result.UserName, "GetUserByUsername does not return the correct user");
+ }
+
+ [Test]
+ public void GetUserByUsername_ThrowsException_IfUserDoesNotExist()
+ {
+ string username = "g_trapov";
+
+ this._userRepositoryMock
+ .Setup(p => p.GetByUsernameAsync(It.IsAny<string>()))
+ .Returns(Task.FromResult<User>(null));
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._userService.GetUserByUsername(username));
+
+ // Assert.AreEqual("User does not exist!", ex.Message, "Incorrect exception message");
+ }
+ #endregion
+
+ #region UpdateUser
+ // [Test]
+ // [TestCase(true)]
+ // [TestCase(false)]
+ // public async Task UpdateUser_ReturnsIfUpdateIsSuccessfull_WhenUserExistsy(bool shouldPass)
+ // {
+ // string username = "g_trapov";
+ // Guid id = Guid.NewGuid();
+ // User user = new User
+ // {
+ // UserName = username,
+ // Id = id,
+ // };
+ // UpdateUserServiceModel updateUserServiceModel = new UpdateUserServiceModel
+ // {
+ // UserName = username,
+ // };
+ // UserServiceModel userServiceModel = new UserServiceModel
+ // {
+ // UserName = username,
+ // };
+ // Role role = new Role { };
+ //
+ // this._userRepositoryMock.Setup(p =>
+ // p.DoesUserExistAsync(It.IsAny<Guid>()))
+ // .ReturnsAsync(true);
+ // this._userRepositoryMock.Setup(p =>
+ // p.DoesUsernameExistAsync(It.IsAny<string>()))
+ // .ReturnsAsync(false);
+ // this._userRepositoryMock.Setup(p =>
+ // p.DoesUserHaveThisUsernameAsync(It.IsAny<Guid>(), It.IsAny<string>()))
+ // .Returns(true);
+ // this._userRepositoryMock.Setup(p =>
+ // p.EditAsync(It.IsAny<Guid>(), It.IsAny<User>()))
+ // .ReturnsAsync(shouldPass);
+ // this._userRepositoryMock.Setup(p =>
+ // p.GetByIdAsync(It.IsAny<Guid>()))
+ // .ReturnsAsync(user);
+ // this._mapperMock.Setup(p =>
+ // p.Map<User>(It.IsAny<UpdateUserServiceModel>()))
+ // .Returns(user);
+ // this._mapperMock.Setup(p =>
+ // p.Map<UserServiceModel>(It.IsAny<User>()))
+ // .Returns(userServiceModel);
+ //
+ // if (shouldPass)
+ // {
+ // UserServiceModel result = await this._userService.UpdateUser(updateUserServiceModel);
+ //
+ // Assert.AreEqual(updateUserServiceModel.UserName, result.UserName);
+ // }
+ // else
+ // {
+ // const string EXCEPTION_MESSAGE = string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower());
+ //
+ // Exception ex = Assert.ThrowsAsync<InvalidOperationException>(() => this._userService.UpdateUser(updateUserServiceModel);
+ //
+ // Assert.AreEqual(EXCEPTION_MESSAGE, ex.Message, "Incorrect exception message");
+ // }
+ // }
+
+ [Test]
+ public void UpdateUser_ThrowsException_WhenUserDoesNotExist()
+ {
+ UpdateUserServiceModel updateUserServiceModel = new();
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUserExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._userService.UpdateUser(updateUserServiceModel));
+
+ // Assert.AreEqual("User does not exist!", ex.Message, "Incorrect exception message");
+ }
+
+ [Test]
+ public void UpdateUser_ThrowsException_WhenUserNameAlreadyExists()
+ {
+ UpdateUserServiceModel updateUserServiceModel = new();
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUserExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(true);
+ this._userRepositoryMock
+ .Setup(p => p.DoesUsernameExistAsync(It.IsAny<string>()))
+ .ReturnsAsync(true);
+
+ Exception ex = Assert.ThrowsAsync<DuplicateNameException>(() => this._userService.UpdateUser(updateUserServiceModel));
+
+ Assert.AreEqual("the username already exists!", ex.Message, "Incorrect exception message");
+ }
+ #endregion
+
+ #region DeleteUser
+ //TO DO: compleate once Viko has looked into the return type of UserService.DeleteUser
+ // [Test]
+ // [TestCase(true)]
+ // [TestCase(false)]
+ // public async Task DeleteUser_ShouldReturnIfDeletionIsSuccessfull_WhenUserExists(bool shouldPass)
+ // {
+ // Guid id = Guid.NewGuid();
+ // User user = new User();
+ //
+ // this._userRepositoryMock.Setup(p =>
+ // p.DoesUserExistAsync(It.IsAny<Guid>()))
+ // .ReturnsAsync(true);
+ // this._userRepositoryMock.Setup(p =>
+ // p.GetByIdAsync(It.IsAny<Guid>()))
+ // .ReturnsAsync(user);
+ // this._userRepositoryMock.Setup(p =>
+ // p.DeleteAsync(It.IsAny<User>()))
+ // .ReturnsAsync(shouldPass);
+ //
+ // bool result = await this._userService.DeleteUser(id);
+ //
+ // Assert.AreEqual(shouldPass, result);
+ // }
+ //
+ [Test]
+ public void DeleteUser_ThrowsException_WhenUserDoesNotExist()
+ {
+ string exceptionMessage = "User does not exist!";
+ Guid id = new();
+
+ this._userRepositoryMock
+ .Setup(p => p.DoesUserExistAsync(It.IsAny<Guid>()))
+ .ReturnsAsync(false);
+
+ Exception ex = Assert.ThrowsAsync<ArgumentNullException>(() => this._userService.DeleteUser(id));
+
+ // Assert.AreEqual(exceptionMessage, ex.Message, "Incorrect exception message");
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/CommentMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/CommentMappings.cs
new file mode 100644
index 0000000..5ca2a9e
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/CommentMappings.cs
@@ -0,0 +1,27 @@
+using DevHive.Data.Models;
+using AutoMapper;
+using DevHive.Services.Models.Comment;
+using DevHive.Common.Models.Misc;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class CommentMappings : Profile
+ {
+ public CommentMappings()
+ {
+ CreateMap<CreateCommentServiceModel, Comment>();
+ CreateMap<UpdateCommentServiceModel, Comment>()
+ .ForMember(dest => dest.Id, src => src.MapFrom(p => p.CommentId))
+ .ForMember(dest => dest.Message, src => src.MapFrom(p => p.NewMessage));
+
+ CreateMap<Comment, ReadCommentServiceModel>()
+ .ForMember(dest => dest.CommentId, src => src.MapFrom(p => p.Id))
+ .ForMember(dest => dest.IssuerFirstName, src => src.MapFrom(p => p.Creator.FirstName))
+ .ForMember(dest => dest.IssuerLastName, src => src.MapFrom(p => p.Creator.LastName))
+ .ForMember(dest => dest.IssuerUsername, src => src.MapFrom(p => p.Creator.UserName));
+
+ CreateMap<Comment, IdModel>()
+ .ForMember(dest => dest.Id, src => src.MapFrom(p => p.Id));
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/FeedMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/FeedMappings.cs
new file mode 100644
index 0000000..952e480
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/FeedMappings.cs
@@ -0,0 +1,11 @@
+using AutoMapper;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class FeedMappings : Profile
+ {
+ public FeedMappings()
+ {
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/LanguageMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/LanguageMappings.cs
new file mode 100644
index 0000000..9c572df
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/LanguageMappings.cs
@@ -0,0 +1,22 @@
+using DevHive.Data.Models;
+using AutoMapper;
+using DevHive.Services.Models.Language;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class LanguageMappings : Profile
+ {
+ public LanguageMappings()
+ {
+ CreateMap<LanguageServiceModel, Language>();
+ CreateMap<ReadLanguageServiceModel, Language>();
+ CreateMap<CreateLanguageServiceModel, Language>();
+ CreateMap<UpdateLanguageServiceModel, Language>();
+
+ CreateMap<Language, LanguageServiceModel>();
+ CreateMap<Language, ReadLanguageServiceModel>();
+ CreateMap<Language, CreateLanguageServiceModel>();
+ CreateMap<Language, UpdateLanguageServiceModel>();
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/PostMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/PostMappings.cs
new file mode 100644
index 0000000..1d7d88b
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/PostMappings.cs
@@ -0,0 +1,32 @@
+using DevHive.Data.Models;
+using AutoMapper;
+using DevHive.Services.Models.Post;
+using DevHive.Common.Models.Misc;
+using System.Collections.Generic;
+using DevHive.Services.Models;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class PostMappings : Profile
+ {
+ public PostMappings()
+ {
+ CreateMap<CreatePostServiceModel, Post>();
+ CreateMap<UpdatePostServiceModel, Post>()
+ .ForMember(dest => dest.Id, src => src.MapFrom(p => p.PostId))
+ // .ForMember(dest => dest.Files, src => src.Ignore())
+ .ForMember(dest => dest.Message, src => src.MapFrom(p => p.NewMessage));
+
+ CreateMap<Post, ReadPostServiceModel>()
+ .ForMember(dest => dest.PostId, src => src.MapFrom(p => p.Id))
+ .ForMember(dest => dest.CreatorFirstName, src => src.MapFrom(p => p.Creator.FirstName))
+ .ForMember(dest => dest.CreatorLastName, src => src.MapFrom(p => p.Creator.LastName))
+ .ForMember(dest => dest.CreatorUsername, src => src.MapFrom(p => p.Creator.UserName));
+
+ CreateMap<Post, IdModel>()
+ .ForMember(dest => dest.Id, src => src.MapFrom(x => x.Id));
+
+ CreateMap<List<Post>, ReadPageServiceModel>();
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
new file mode 100644
index 0000000..9ad5f25
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
@@ -0,0 +1,21 @@
+using AutoMapper;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Rating;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class RatingMappings : Profile
+ {
+ public RatingMappings()
+ {
+ CreateMap<CreateRatingServiceModel, Rating>()
+ .ForMember(dest => dest.User, src => src.Ignore())
+ .ForMember(dest => dest.Post, src => src.Ignore())
+ .ForMember(dest => dest.Id, src => src.Ignore());
+
+ CreateMap<Rating, ReadRatingServiceModel>();
+
+ CreateMap<UpdateRatingServiceModel, Rating>();
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/RoleMapings.cs b/src/Services/DevHive.Services/Configurations/Mapping/RoleMapings.cs
new file mode 100644
index 0000000..e870ab1
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/RoleMapings.cs
@@ -0,0 +1,21 @@
+using AutoMapper;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Role;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class RoleMappings : Profile
+ {
+ public RoleMappings()
+ {
+ CreateMap<CreateRoleServiceModel, Role>();
+ CreateMap<RoleServiceModel, Role>();
+ CreateMap<UpdateRoleServiceModel, Role>();
+
+ CreateMap<Role, RoleServiceModel>();
+ CreateMap<Role, UpdateRoleServiceModel>();
+
+ CreateMap<RoleServiceModel, UpdateRoleServiceModel>();
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs
new file mode 100644
index 0000000..85b57f1
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs
@@ -0,0 +1,21 @@
+using DevHive.Data.Models;
+using AutoMapper;
+using DevHive.Services.Models.Technology;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class TechnologyMappings : Profile
+ {
+ public TechnologyMappings()
+ {
+ CreateMap<CreateTechnologyServiceModel, Technology>();
+ CreateMap<UpdateTechnologyServiceModel, Technology>();
+ CreateMap<TechnologyServiceModel, Technology>();
+
+ CreateMap<Technology, CreateTechnologyServiceModel>();
+ CreateMap<Technology, TechnologyServiceModel>();
+ CreateMap<Technology, ReadTechnologyServiceModel>();
+ CreateMap<Technology, UpdateTechnologyServiceModel>();
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/UserMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/UserMappings.cs
new file mode 100644
index 0000000..5a39f73
--- /dev/null
+++ b/src/Services/DevHive.Services/Configurations/Mapping/UserMappings.cs
@@ -0,0 +1,31 @@
+using DevHive.Data.Models;
+using AutoMapper;
+using DevHive.Services.Models.User;
+
+namespace DevHive.Services.Configurations.Mapping
+{
+ public class UserMappings : Profile
+ {
+ public UserMappings()
+ {
+ CreateMap<UserServiceModel, User>();
+ CreateMap<RegisterServiceModel, User>()
+ .ForMember(dest => dest.PasswordHash, src => src.MapFrom(p => p.Password));
+ CreateMap<FriendServiceModel, User>()
+ .ForMember(dest => dest.Friends, src => src.Ignore());
+ CreateMap<UpdateUserServiceModel, User>()
+ .ForMember(dest => dest.Friends, src => src.Ignore());
+ CreateMap<UpdateFriendServiceModel, User>();
+
+ CreateMap<User, UserServiceModel>()
+ .ForMember(dest => dest.ProfilePictureURL, src => src.MapFrom(p => p.ProfilePicture.PictureURL))
+ .ForMember(dest => dest.Friends, src => src.MapFrom(p => p.Friends));
+ CreateMap<User, UpdateUserServiceModel>()
+ .ForMember(dest => dest.ProfilePictureURL, src => src.MapFrom(p => p.ProfilePicture.PictureURL));
+ CreateMap<User, FriendServiceModel>();
+
+ CreateMap<UserServiceModel, UpdateUserServiceModel>();
+ CreateMap<UserServiceModel, UpdateFriendServiceModel>();
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/DevHive.Services.csproj b/src/Services/DevHive.Services/DevHive.Services.csproj
new file mode 100644
index 0000000..2468711
--- /dev/null
+++ b/src/Services/DevHive.Services/DevHive.Services.csproj
@@ -0,0 +1,27 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/>
+ <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.10.0"/>
+ <PackageReference Include="AutoMapper" Version="10.1.1"/>
+ <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/>
+ <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"/>
+ <ProjectReference Include="..\DevHive.Services.Models\DevHive.Services.Models.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common\DevHive.Common.csproj"/>
+ <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.Models.csproj"/>
+ </ItemGroup>
+ <PropertyGroup>
+ <EnableNETAnalyzers>true</EnableNETAnalyzers>
+ <AnalysisLevel>latest</AnalysisLevel>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/Services/DevHive.Services/Interfaces/ICloudService.cs b/src/Services/DevHive.Services/Interfaces/ICloudService.cs
new file mode 100644
index 0000000..040729f
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/ICloudService.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface ICloudService
+ {
+ Task<List<string>> UploadFilesToCloud(List<IFormFile> formFiles);
+
+ Task<bool> RemoveFilesFromCloud(List<string> fileUrls);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/ICommentService.cs b/src/Services/DevHive.Services/Interfaces/ICommentService.cs
new file mode 100644
index 0000000..6d92a5d
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/ICommentService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Services.Models.Comment;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface ICommentService
+ {
+ Task<Guid> AddComment(CreateCommentServiceModel createCommentServiceModel);
+
+ Task<ReadCommentServiceModel> GetCommentById(Guid id);
+
+ Task<Guid> UpdateComment(UpdateCommentServiceModel updateCommentServiceModel);
+
+ Task<bool> DeleteComment(Guid id);
+
+ Task<bool> ValidateJwtForCreating(Guid userId, string rawTokenData);
+ Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IFeedService.cs b/src/Services/DevHive.Services/Interfaces/IFeedService.cs
new file mode 100644
index 0000000..b507b3b
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IFeedService.cs
@@ -0,0 +1,11 @@
+using System.Threading.Tasks;
+using DevHive.Services.Models;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IFeedService
+ {
+ Task<ReadPageServiceModel> GetPage(GetPageServiceModel getPageServiceModel);
+ Task<ReadPageServiceModel> GetUserPage(GetPageServiceModel model);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IFriendsService.cs b/src/Services/DevHive.Services/Interfaces/IFriendsService.cs
new file mode 100644
index 0000000..52f23f3
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IFriendsService.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Threading.Tasks;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IFriendsService
+ {
+ Task<bool> AddFriend(Guid userId, string friendUsername);
+ Task<bool> RemoveFriend(Guid userId, string friendUsername);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/ILanguageService.cs b/src/Services/DevHive.Services/Interfaces/ILanguageService.cs
new file mode 100644
index 0000000..fabbec2
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/ILanguageService.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using DevHive.Services.Models.Language;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface ILanguageService
+ {
+ Task<Guid> CreateLanguage(CreateLanguageServiceModel createLanguageServiceModel);
+
+ Task<ReadLanguageServiceModel> GetLanguageById(Guid id);
+ HashSet<ReadLanguageServiceModel> GetLanguages();
+
+ Task<bool> UpdateLanguage(UpdateLanguageServiceModel languageServiceModel);
+
+ Task<bool> DeleteLanguage(Guid id);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IPostService.cs b/src/Services/DevHive.Services/Interfaces/IPostService.cs
new file mode 100644
index 0000000..5ccecff
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IPostService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Services.Models.Post;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IPostService
+ {
+ Task<Guid> CreatePost(CreatePostServiceModel createPostServiceModel);
+
+ Task<ReadPostServiceModel> GetPostById(Guid id);
+
+ Task<Guid> UpdatePost(UpdatePostServiceModel updatePostServiceModel);
+
+ Task<bool> DeletePost(Guid id);
+
+ Task<bool> ValidateJwtForCreating(Guid userId, string rawTokenData);
+ Task<bool> ValidateJwtForPost(Guid postId, string rawTokenData);
+ }
+}
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/IRatingService.cs b/src/Services/DevHive.Services/Interfaces/IRatingService.cs
new file mode 100644
index 0000000..be33300
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IRatingService.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Rating;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IRatingService
+ {
+ Task<Guid> RatePost(CreateRatingServiceModel createRatingServiceModel);
+
+ Task<ReadRatingServiceModel> GetRatingById(Guid ratingId);
+ Task<ReadRatingServiceModel> GetRatingByPostAndUser(Guid userId, Guid postId);
+
+
+ Task<ReadRatingServiceModel> UpdateRating(UpdateRatingServiceModel updateRatingServiceModel);
+
+ Task<bool> DeleteRating(Guid ratingId);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IRoleService.cs b/src/Services/DevHive.Services/Interfaces/IRoleService.cs
new file mode 100644
index 0000000..36e5a01
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IRoleService.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Services.Models.Role;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IRoleService
+ {
+ Task<Guid> CreateRole(CreateRoleServiceModel createRoleServiceModel);
+
+ Task<RoleServiceModel> GetRoleById(Guid id);
+
+ Task<bool> UpdateRole(UpdateRoleServiceModel updateRoleServiceModel);
+
+ Task<bool> DeleteRole(Guid id);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/ITechnologyService.cs b/src/Services/DevHive.Services/Interfaces/ITechnologyService.cs
new file mode 100644
index 0000000..8f9510c
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/ITechnologyService.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using DevHive.Services.Models.Technology;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface ITechnologyService
+ {
+ Task<Guid> CreateTechnology(CreateTechnologyServiceModel technologyServiceModel);
+
+ Task<ReadTechnologyServiceModel> GetTechnologyById(Guid id);
+ HashSet<ReadTechnologyServiceModel> GetTechnologies();
+
+ Task<bool> UpdateTechnology(UpdateTechnologyServiceModel updateTechnologyServiceModel);
+
+ Task<bool> DeleteTechnology(Guid id);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IUserService.cs b/src/Services/DevHive.Services/Interfaces/IUserService.cs
new file mode 100644
index 0000000..da07507
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IUserService.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Common.Models.Identity;
+using DevHive.Services.Models.User;
+
+namespace DevHive.Services.Interfaces
+{
+ public interface IUserService
+ {
+ /// <summary>
+ /// Log ins an existing user and gives him/her a JWT Token for further authorization
+ /// </summary>
+ /// <param name="loginModel">Login service model, conaining user's username and password</param>
+ /// <returns>A JWT Token for authorization</returns>
+ Task<TokenModel> LoginUser(LoginServiceModel loginModel);
+
+ /// <summary>
+ /// Registers a new user and gives him/her a JWT Token for further authorization
+ /// </summary>
+ /// <param name="registerModel">Register service model, containing the new user's data</param>
+ /// <returns>A JWT Token for authorization</returns>
+ Task<TokenModel> RegisterUser(RegisterServiceModel registerModel);
+
+ /// <summary>
+ /// Get a user by his username. Used for querying profiles without provided authentication
+ /// </summary>
+ /// <param name="username">User's username, who's to be queried</param>
+ /// <returns>The queried user or null, if non existant</returns>
+ Task<UserServiceModel> GetUserByUsername(string username);
+
+ /// <summary>
+ /// Get a user by his Guid. Used for querying full user's profile
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="id">User's username, who's to be queried</param>
+ /// <returns>The queried user or null, if non existant</returns>
+ Task<UserServiceModel> GetUserById(Guid id);
+
+ /// <summary>
+ /// Updates a user's data, provided a full model with new details
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="updateUserServiceModel">Full update user model for updating</param>
+ /// <returns>Read model of the new user</returns>
+ Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel);
+
+ /// <summary>
+ /// Deletes a user from the database and removes his data entirely
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="id">The user's Guid, who's to be deleted</param>
+ /// <returns>True if successfull, false otherwise</returns>
+ Task<bool> DeleteUser(Guid id);
+
+ /// <summary>
+ /// We don't talk about that!
+ /// </summary>
+ /// <param name="userId"></param>
+ /// <returns></returns>
+ Task<TokenModel> SuperSecretPromotionToAdmin(Guid userId);
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/CloudinaryService.cs b/src/Services/DevHive.Services/Services/CloudinaryService.cs
new file mode 100644
index 0000000..61d06fc
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/CloudinaryService.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using CloudinaryDotNet;
+using CloudinaryDotNet.Actions;
+using DevHive.Services.Interfaces;
+using Microsoft.AspNetCore.Http;
+
+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)
+ {
+ this._cloudinary = new Cloudinary(new Account(cloudName, apiKey, apiSecret));
+ }
+
+ public async Task<List<string>> UploadFilesToCloud(List<IFormFile> formFiles)
+ {
+ List<string> fileUrls = new();
+ foreach (var formFile in formFiles)
+ {
+ string fileName = s_imageRegex.Match(formFile.FileName).ToString();
+
+ using var ms = new MemoryStream();
+ formFile.CopyTo(ms);
+ byte[] formBytes = ms.ToArray();
+
+ RawUploadParams rawUploadParams = new()
+ {
+ 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;
+ }
+
+ public async Task<bool> RemoveFilesFromCloud(List<string> fileUrls)
+ {
+ // Workaround, this method isn't fully implemented yet
+ await Task.Run(() => {});
+
+ return true;
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/CommentService.cs b/src/Services/DevHive.Services/Services/CommentService.cs
new file mode 100644
index 0000000..1c388f6
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/CommentService.cs
@@ -0,0 +1,169 @@
+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;
+using DevHive.Services.Models.Comment;
+
+namespace DevHive.Services.Services
+{
+ public class CommentService : ICommentService
+ {
+ private readonly IUserRepository _userRepository;
+ private readonly IPostRepository _postRepository;
+ private readonly ICommentRepository _commentRepository;
+ private readonly IMapper _postMapper;
+
+ public CommentService(IUserRepository userRepository, IPostRepository postRepository, ICommentRepository commentRepository, IMapper postMapper)
+ {
+ this._userRepository = userRepository;
+ this._postRepository = postRepository;
+ this._commentRepository = commentRepository;
+ this._postMapper = postMapper;
+ }
+
+ #region Create
+ public async Task<Guid> AddComment(CreateCommentServiceModel createCommentServiceModel)
+ {
+ if (!await this._postRepository.DoesPostExist(createCommentServiceModel.PostId))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post));
+
+ Comment comment = this._postMapper.Map<Comment>(createCommentServiceModel);
+ comment.TimeCreated = DateTime.Now;
+
+ comment.Creator = await this._userRepository.GetByIdAsync(createCommentServiceModel.CreatorId);
+ comment.Post = await this._postRepository.GetByIdAsync(createCommentServiceModel.PostId);
+
+ bool success = await this._commentRepository.AddAsync(comment);
+ if (success)
+ {
+ Comment newComment = await this._commentRepository
+ .GetCommentByIssuerAndTimeCreatedAsync(comment.Creator.Id, comment.TimeCreated);
+
+ return newComment.Id;
+ }
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Read
+ public async Task<ReadCommentServiceModel> GetCommentById(Guid id)
+ {
+ Comment comment = await this._commentRepository.GetByIdAsync(id) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment));
+
+ User user = await this._userRepository.GetByIdAsync(comment.Creator.Id) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ ReadCommentServiceModel readCommentServiceModel = this._postMapper.Map<ReadCommentServiceModel>(comment);
+ readCommentServiceModel.IssuerFirstName = user.FirstName;
+ readCommentServiceModel.IssuerLastName = user.LastName;
+ readCommentServiceModel.IssuerUsername = user.UserName;
+
+ return readCommentServiceModel;
+ }
+ #endregion
+
+ #region Update
+ public async Task<Guid> UpdateComment(UpdateCommentServiceModel updateCommentServiceModel)
+ {
+ if (!await this._commentRepository.DoesCommentExist(updateCommentServiceModel.CommentId))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment));
+
+ Comment comment = this._postMapper.Map<Comment>(updateCommentServiceModel);
+ comment.TimeCreated = DateTime.Now;
+
+ comment.Creator = await this._userRepository.GetByIdAsync(updateCommentServiceModel.CreatorId);
+ comment.Post = await this._postRepository.GetByIdAsync(updateCommentServiceModel.PostId);
+
+ bool result = await this._commentRepository.EditAsync(updateCommentServiceModel.CommentId, comment);
+
+ if (result)
+ return (await this._commentRepository.GetByIdAsync(updateCommentServiceModel.CommentId)).Id;
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeleteComment(Guid id)
+ {
+ if (!await this._commentRepository.DoesCommentExist(id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment));
+
+ Comment comment = await this._commentRepository.GetByIdAsync(id);
+ return await this._commentRepository.DeleteAsync(comment);
+ }
+ #endregion
+
+ #region Validations
+ /// <summary>
+ /// Checks whether the user Id in the token and the given user Id match
+ /// </summary>
+ public async Task<bool> ValidateJwtForCreating(Guid userId, string rawTokenData)
+ {
+ User user = await this.GetUserForValidation(rawTokenData);
+
+ return user.Id == userId;
+ }
+
+ /// <summary>
+ /// Checks whether the comment, gotten with the commentId,
+ /// is made by the user in the token
+ /// or if the user in the token is an admin
+ /// </summary>
+ public async Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData)
+ {
+ Comment comment = await this._commentRepository.GetByIdAsync(commentId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment));
+ User user = await this.GetUserForValidation(rawTokenData);
+
+ //If user made the comment
+ if (comment.Creator.Id == user.Id)
+ return true;
+ //If user is admin
+ else if (user.Roles.Any(x => x.Name == Role.AdminRole))
+ return true;
+ else
+ return false;
+ }
+
+ /// <summary>
+ /// Returns the user, via their Id in the token
+ /// </summary>
+ private async Task<User> GetUserForValidation(string rawTokenData)
+ {
+ JwtSecurityToken jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7));
+
+ Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First());
+
+ User user = await this._userRepository.GetByIdAsync(jwtUserId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ return user;
+ }
+
+ /// <summary>
+ /// Returns all values from a given claim type
+ /// </summary>
+ private static List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims)
+ {
+ List<string> toReturn = new();
+
+ foreach (var claim in claims)
+ if (claim.Type == type)
+ toReturn.Add(claim.Value);
+
+ return toReturn;
+ }
+ #endregion
+ }
+}
+
diff --git a/src/Services/DevHive.Services/Services/FeedService.cs b/src/Services/DevHive.Services/Services/FeedService.cs
new file mode 100644
index 0000000..9c622b3
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/FeedService.cs
@@ -0,0 +1,85 @@
+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;
+using DevHive.Services.Models;
+using DevHive.Services.Models.Post;
+
+namespace DevHive.Services.Services
+{
+ public class FeedService : IFeedService
+ {
+ private readonly IMapper _mapper;
+ private readonly IFeedRepository _feedRepository;
+ private readonly IUserRepository _userRepository;
+
+ public FeedService(IFeedRepository feedRepository, IUserRepository userRepository, IMapper mapper)
+ {
+ this._feedRepository = feedRepository;
+ this._userRepository = userRepository;
+ this._mapper = mapper;
+ }
+
+ /// <summary>
+ /// This method is used in the feed page.
+ /// 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)
+ user = await this._userRepository.GetByIdAsync(getPageServiceModel.UserId);
+ else if (!string.IsNullOrEmpty(getPageServiceModel.Username))
+ user = await this._userRepository.GetByUsernameAsync(getPageServiceModel.Username);
+ else
+ throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower()));
+
+ if (user == null)
+ 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);
+
+ ReadPageServiceModel readPageServiceModel = new();
+ foreach (Post post in posts)
+ readPageServiceModel.Posts.Add(this._mapper.Map<ReadPostServiceModel>(post));
+
+ return readPageServiceModel;
+ }
+
+ /// <summary>
+ /// This method is used in the profile pages.
+ /// See the FeedRepository "GetUsersPosts" method for more information on how it works.
+ /// </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 InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower()));
+
+ if (user == null)
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ List<Post> posts = await this._feedRepository
+ .GetUsersPosts(user, model.FirstRequestIssued, model.PageNumber, model.PageSize);
+
+ ReadPageServiceModel readPageServiceModel = new();
+ foreach (Post post in posts)
+ readPageServiceModel.Posts.Add(this._mapper.Map<ReadPostServiceModel>(post));
+
+ return readPageServiceModel;
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/FriendsService.cs b/src/Services/DevHive.Services/Services/FriendsService.cs
new file mode 100644
index 0000000..98f654b
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/FriendsService.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Common.Constants;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Interfaces;
+
+namespace DevHive.Services.Services
+{
+ public class FriendsService : IFriendsService
+ {
+ private readonly IUserRepository _friendRepository;
+
+ public FriendsService(IUserRepository friendRepository)
+ {
+ this._friendRepository = friendRepository;
+ }
+
+ public async Task<bool> AddFriend(Guid userId, string friendUsername)
+ {
+ User user = await this._friendRepository.GetByIdAsync(userId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, nameof(user)));
+
+ User friend = await this._friendRepository.GetByUsernameAsync(friendUsername) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, nameof(friend)));
+
+ bool addedToUser = user.Friends.Add(friend) && await this._friendRepository.EditAsync(userId, user);
+ bool addedToFriend = friend.Friends.Add(user) && await this._friendRepository.EditAsync(friend.Id, friend);
+ return addedToUser && addedToFriend;
+ }
+
+ public async Task<bool> RemoveFriend(Guid userId, string friendUsername)
+ {
+ User user = await this._friendRepository.GetByIdAsync(userId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, nameof(user)));
+
+ User friend = await this._friendRepository.GetByUsernameAsync(friendUsername) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, nameof(friend)));
+
+ bool addedToUser = user.Friends.Remove(friend) && await this._friendRepository.EditAsync(userId, user);
+ bool addedToFriend = friend.Friends.Remove(user) && await this._friendRepository.EditAsync(friend.Id, friend);
+ return addedToUser && addedToFriend;
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/LanguageService.cs b/src/Services/DevHive.Services/Services/LanguageService.cs
new file mode 100644
index 0000000..7ee7d9f
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/LanguageService.cs
@@ -0,0 +1,91 @@
+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;
+using DevHive.Services.Models.Language;
+
+namespace DevHive.Services.Services
+{
+ public class LanguageService : ILanguageService
+ {
+ private readonly ILanguageRepository _languageRepository;
+ private readonly IMapper _languageMapper;
+
+ public LanguageService(ILanguageRepository languageRepository, IMapper mapper)
+ {
+ this._languageRepository = languageRepository;
+ this._languageMapper = mapper;
+ }
+
+ #region Create
+ public async Task<Guid> CreateLanguage(CreateLanguageServiceModel createLanguageServiceModel)
+ {
+ if (await this._languageRepository.DoesLanguageNameExistAsync(createLanguageServiceModel.Name))
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language));
+
+ Language language = this._languageMapper.Map<Language>(createLanguageServiceModel);
+ bool success = await this._languageRepository.AddAsync(language);
+
+ if (success)
+ {
+ Language newLanguage = await this._languageRepository.GetByNameAsync(createLanguageServiceModel.Name);
+ return newLanguage.Id;
+ }
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Read
+ public async Task<ReadLanguageServiceModel> GetLanguageById(Guid id)
+ {
+ Language language = await this._languageRepository.GetByIdAsync(id);
+
+ if (language == null)
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language));
+
+ return this._languageMapper.Map<ReadLanguageServiceModel>(language);
+ }
+
+ public HashSet<ReadLanguageServiceModel> GetLanguages()
+ {
+ HashSet<Language> languages = this._languageRepository.GetLanguages();
+
+ return this._languageMapper.Map<HashSet<ReadLanguageServiceModel>>(languages);
+ }
+ #endregion
+
+ #region Update
+ public async Task<bool> UpdateLanguage(UpdateLanguageServiceModel languageServiceModel)
+ {
+ bool langExists = await this._languageRepository.DoesLanguageExistAsync(languageServiceModel.Id);
+ bool newLangNameExists = await this._languageRepository.DoesLanguageNameExistAsync(languageServiceModel.Name);
+
+ if (!langExists)
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language));
+
+ if (newLangNameExists)
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language));
+
+ Language lang = this._languageMapper.Map<Language>(languageServiceModel);
+ return await this._languageRepository.EditAsync(languageServiceModel.Id, lang);
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeleteLanguage(Guid id)
+ {
+ if (!await this._languageRepository.DoesLanguageExistAsync(id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language));
+
+ Language language = await this._languageRepository.GetByIdAsync(id);
+ return await this._languageRepository.DeleteAsync(language);
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/PostService.cs b/src/Services/DevHive.Services/Services/PostService.cs
new file mode 100644
index 0000000..8580e82
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/PostService.cs
@@ -0,0 +1,249 @@
+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.Data.Models.Relational;
+using DevHive.Services.Interfaces;
+using DevHive.Services.Models.Post;
+
+namespace DevHive.Services.Services
+{
+ public class PostService : IPostService
+ {
+ private readonly ICloudService _cloudService;
+ private readonly IUserRepository _userRepository;
+ private readonly IPostRepository _postRepository;
+ private readonly ICommentRepository _commentRepository;
+ private readonly IMapper _postMapper;
+
+ public PostService(ICloudService cloudService, IUserRepository userRepository, IPostRepository postRepository, ICommentRepository commentRepository, IMapper postMapper)
+ {
+ this._cloudService = cloudService;
+ this._userRepository = userRepository;
+ this._postRepository = postRepository;
+ this._commentRepository = commentRepository;
+ this._postMapper = postMapper;
+ }
+
+ #region Create
+ public async Task<Guid> CreatePost(CreatePostServiceModel createPostServiceModel)
+ {
+ if (!await this._userRepository.DoesUserExistAsync(createPostServiceModel.CreatorId))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ Post post = this._postMapper.Map<Post>(createPostServiceModel);
+
+ if (createPostServiceModel.Files.Count != 0)
+ {
+ List<string> fileUrls = await _cloudService.UploadFilesToCloud(createPostServiceModel.Files);
+ post.Attachments = GetPostAttachmentsFromUrls(post, fileUrls);
+ }
+
+ post.Creator = await this._userRepository.GetByIdAsync(createPostServiceModel.CreatorId);
+ post.TimeCreated = DateTime.Now;
+
+ bool success = await this._postRepository.AddAsync(post);
+ if (success)
+ {
+ Post newPost = await this._postRepository
+ .GetPostByCreatorAndTimeCreatedAsync(post.Creator.Id, post.TimeCreated);
+
+ await this._postRepository.AddNewPostToCreator(createPostServiceModel.CreatorId, newPost);
+
+ return newPost.Id;
+ }
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Read
+ public async Task<ReadPostServiceModel> GetPostById(Guid id)
+ {
+ Post post = await this._postRepository.GetByIdAsync(id) ??
+ 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
+ .OrderByDescending(x => x.TimeCreated.ToFileTimeUtc())
+ .ToList();
+
+ User user = await this._userRepository.GetByIdAsync(post.Creator.Id) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ int currentRating = 0;
+ foreach (Rating rating in post.Ratings)
+ {
+ if (rating.IsLike)
+ currentRating++;
+ else
+ currentRating--;
+ }
+
+ ReadPostServiceModel readPostServiceModel = this._postMapper.Map<ReadPostServiceModel>(post);
+ readPostServiceModel.CreatorFirstName = user.FirstName;
+ readPostServiceModel.CreatorLastName = user.LastName;
+ readPostServiceModel.CreatorUsername = user.UserName;
+ readPostServiceModel.FileUrls = post.Attachments.Select(x => x.FileUrl).ToList();
+ readPostServiceModel.CurrentRating = currentRating;
+
+ return readPostServiceModel;
+ }
+ #endregion
+
+ #region Update
+ public async Task<Guid> UpdatePost(UpdatePostServiceModel updatePostServiceModel)
+ {
+ if (!await this._postRepository.DoesPostExist(updatePostServiceModel.PostId))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post));
+
+ Post post = this._postMapper.Map<Post>(updatePostServiceModel);
+
+ if (updatePostServiceModel.Files.Count != 0)
+ {
+ if (await this._postRepository.DoesPostHaveFiles(updatePostServiceModel.PostId))
+ {
+ List<string> fileUrlsToRemove = await this._postRepository.GetFileUrls(updatePostServiceModel.PostId);
+ bool success = await _cloudService.RemoveFilesFromCloud(fileUrlsToRemove);
+ if (!success)
+ throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower()));
+ }
+
+ List<string> fileUrls = await _cloudService.UploadFilesToCloud(updatePostServiceModel.Files) ??
+ throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower()));
+ post.Attachments = GetPostAttachmentsFromUrls(post, fileUrls);
+ }
+
+ post.Creator = await this._userRepository.GetByIdAsync(updatePostServiceModel.CreatorId);
+ post.Comments = await this._commentRepository.GetPostComments(updatePostServiceModel.PostId);
+ post.TimeCreated = DateTime.Now;
+
+ bool result = await this._postRepository.EditAsync(updatePostServiceModel.PostId, post);
+
+ if (result)
+ return (await this._postRepository.GetByIdAsync(updatePostServiceModel.PostId)).Id;
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeletePost(Guid id)
+ {
+ if (!await this._postRepository.DoesPostExist(id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post));
+
+ Post post = await this._postRepository.GetByIdAsync(id);
+
+ if (await this._postRepository.DoesPostHaveFiles(id))
+ {
+ List<string> fileUrls = await this._postRepository.GetFileUrls(id);
+ bool success = await _cloudService.RemoveFilesFromCloud(fileUrls);
+ if (!success)
+ throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower()));
+ }
+
+ return await this._postRepository.DeleteAsync(post);
+ }
+ #endregion
+
+ #region Validations
+ /// <summary>
+ /// Checks whether the user Id in the token and the given user Id match
+ /// </summary>
+ public async Task<bool> ValidateJwtForCreating(Guid userId, string rawTokenData)
+ {
+ User user = await GetUserForValidation(rawTokenData);
+
+ return user.Id == userId;
+ }
+
+ /// <summary>
+ /// Checks whether the post, gotten with the postId,
+ /// is made by the user in the token
+ /// or if the user in the token is an admin
+ /// </summary>
+ public async Task<bool> ValidateJwtForPost(Guid postId, string rawTokenData)
+ {
+ Post post = await this._postRepository.GetByIdAsync(postId) ??
+ 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)
+ return true;
+ //If user is admin
+ else if (user.Roles.Any(x => x.Name == Role.AdminRole))
+ return true;
+ else
+ return false;
+ }
+
+ /// <summary>
+ /// Checks whether the comment, gotten with the commentId,
+ /// is made by the user in the token
+ /// or if the user in the token is an admin
+ /// </summary>
+ public async Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData)
+ {
+ Comment comment = await this._commentRepository.GetByIdAsync(commentId) ??
+ 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)
+ return true;
+ //If user is admin
+ else if (user.Roles.Any(x => x.Name == Role.AdminRole))
+ return true;
+ else
+ return false;
+ }
+
+ /// <summary>
+ /// Returns the user, via their Id in the token
+ /// </summary>
+ private async Task<User> GetUserForValidation(string rawTokenData)
+ {
+ JwtSecurityToken jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7));
+
+ Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First());
+
+ User user = await this._userRepository.GetByIdAsync(jwtUserId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ return user;
+ }
+
+ /// <summary>
+ /// Returns all values from a given claim type
+ /// </summary>
+ private static List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims)
+ {
+ List<string> toReturn = new();
+
+ foreach (var claim in claims)
+ if (claim.Type == type)
+ toReturn.Add(claim.Value);
+
+ return toReturn;
+ }
+ #endregion
+
+ #region Misc
+ private static List<PostAttachments> GetPostAttachmentsFromUrls(Post post, List<string> fileUrls)
+ {
+ List<PostAttachments> postAttachments = new();
+ foreach (string url in fileUrls)
+ postAttachments.Add(new PostAttachments { Post = post, FileUrl = url });
+ return postAttachments;
+ }
+ #endregion
+ }
+}
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
new file mode 100644
index 0000000..d6b4299
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/RatingService.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Threading.Tasks;
+using AutoMapper;
+using DevHive.Common.Constants;
+using DevHive.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Interfaces;
+using DevHive.Services.Models.Rating;
+
+namespace DevHive.Services.Services
+{
+ public class RatingService : IRatingService
+ {
+ private readonly IPostRepository _postRepository;
+ private readonly IUserRepository _userRepository;
+ 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;
+ this._ratingRepository = ratingRepository;
+ this._userRepository = userRepository;
+ this._mapper = mapper;
+ }
+
+ #region Create
+ public async Task<Guid> RatePost(CreateRatingServiceModel createRatingServiceModel)
+ {
+ if (!await this._postRepository.DoesPostExist(createRatingServiceModel.PostId))
+ 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!");
+
+ Rating rating = this._mapper.Map<Rating>(createRatingServiceModel);
+
+ rating.User = await this._userRepository.GetByIdAsync(createRatingServiceModel.UserId);
+ rating.Post = await this._postRepository.GetByIdAsync(createRatingServiceModel.PostId);
+
+ bool success = await this._ratingRepository.AddAsync(rating);
+
+ if (success)
+ {
+ Rating newRating = await this._ratingRepository.GetRatingByUserAndPostId(rating.User.Id, rating.Post.Id);
+
+ return newRating.Id;
+ }
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Read
+ public async Task<ReadRatingServiceModel> GetRatingById(Guid ratingId)
+ {
+ 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;
+
+ return readRatingServiceModel;
+ }
+
+ public async Task<ReadRatingServiceModel> GetRatingByPostAndUser(Guid userId, Guid postId)
+ {
+ 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;
+
+ return readRatingServiceModel;
+ }
+ #endregion
+
+ #region Update
+ public async Task<ReadRatingServiceModel> UpdateRating(UpdateRatingServiceModel updateRatingServiceModel)
+ {
+ Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating));
+
+ User user = await this._userRepository.GetByIdAsync(updateRatingServiceModel.UserId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ if (!await this._ratingRepository.UserRatedPost(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId))
+ throw new ArgumentException(string.Format(NotRated, ClassesConstants.User));
+
+ rating.User = user;
+ rating.IsLike = updateRatingServiceModel.IsLike;
+
+ bool result = await this._ratingRepository.EditAsync(updateRatingServiceModel.Id, rating);
+
+ if (result)
+ {
+ ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating);
+ return readRatingServiceModel;
+ }
+ else
+ return null;
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeleteRating(Guid ratingId)
+ {
+ if (!await this._ratingRepository.DoesRatingExist(ratingId))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating));
+
+ Rating rating = await this._ratingRepository.GetByIdAsync(ratingId);
+ return await this._ratingRepository.DeleteAsync(rating);
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/RoleService.cs b/src/Services/DevHive.Services/Services/RoleService.cs
new file mode 100644
index 0000000..f61181a
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/RoleService.cs
@@ -0,0 +1,71 @@
+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;
+using DevHive.Services.Models.Role;
+
+namespace DevHive.Services.Services
+{
+ public class RoleService : IRoleService
+ {
+ private readonly IRoleRepository _roleRepository;
+ private readonly IMapper _roleMapper;
+
+ public RoleService(IRoleRepository roleRepository, IMapper mapper)
+ {
+ this._roleRepository = roleRepository;
+ this._roleMapper = mapper;
+ }
+
+ public async Task<Guid> CreateRole(CreateRoleServiceModel createRoleServiceModel)
+ {
+ if (await this._roleRepository.DoesNameExist(createRoleServiceModel.Name))
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role));
+
+ Role role = this._roleMapper.Map<Role>(createRoleServiceModel);
+ bool success = await this._roleRepository.AddAsync(role);
+
+ if (success)
+ {
+ Role newRole = await this._roleRepository.GetByNameAsync(createRoleServiceModel.Name);
+ return newRole.Id;
+ }
+ else
+ return Guid.Empty;
+
+ }
+
+ public async Task<RoleServiceModel> GetRoleById(Guid id)
+ {
+ Role role = await this._roleRepository.GetByIdAsync(id) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role));
+
+ return this._roleMapper.Map<RoleServiceModel>(role);
+ }
+
+ public async Task<bool> UpdateRole(UpdateRoleServiceModel updateRoleServiceModel)
+ {
+ if (!await this._roleRepository.DoesRoleExist(updateRoleServiceModel.Id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role));
+
+ if (await this._roleRepository.DoesNameExist(updateRoleServiceModel.Name))
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role));
+
+ Role role = this._roleMapper.Map<Role>(updateRoleServiceModel);
+ return await this._roleRepository.EditAsync(updateRoleServiceModel.Id, role);
+ }
+
+ public async Task<bool> DeleteRole(Guid id)
+ {
+ if (!await this._roleRepository.DoesRoleExist(id))
+ 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
new file mode 100644
index 0000000..4cf84c5
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/TechnologyService.cs
@@ -0,0 +1,92 @@
+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;
+using DevHive.Services.Models.Technology;
+
+namespace DevHive.Services.Services
+{
+ public class TechnologyService : ITechnologyService
+ {
+ private readonly ITechnologyRepository _technologyRepository;
+ private readonly IMapper _technologyMapper;
+
+ public TechnologyService(ITechnologyRepository technologyRepository, IMapper technologyMapper)
+ {
+ this._technologyRepository = technologyRepository;
+ this._technologyMapper = technologyMapper;
+ }
+
+ #region Create
+ public async Task<Guid> CreateTechnology(CreateTechnologyServiceModel technologyServiceModel)
+ {
+ if (await this._technologyRepository.DoesTechnologyNameExistAsync(technologyServiceModel.Name))
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology));
+
+ Technology technology = this._technologyMapper.Map<Technology>(technologyServiceModel);
+ bool success = await this._technologyRepository.AddAsync(technology);
+
+ if (success)
+ {
+ Technology newTechnology = await this._technologyRepository.GetByNameAsync(technologyServiceModel.Name);
+ return newTechnology.Id;
+ }
+ else
+ return Guid.Empty;
+ }
+ #endregion
+
+ #region Read
+ public async Task<ReadTechnologyServiceModel> GetTechnologyById(Guid id)
+ {
+ Technology technology = await this._technologyRepository.GetByIdAsync(id);
+
+ if (technology == null)
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology));
+
+ return this._technologyMapper.Map<ReadTechnologyServiceModel>(technology);
+ }
+
+ public HashSet<ReadTechnologyServiceModel> GetTechnologies()
+ {
+ HashSet<Technology> technologies = this._technologyRepository.GetTechnologies();
+
+ return this._technologyMapper.Map<HashSet<ReadTechnologyServiceModel>>(technologies);
+ }
+ #endregion
+
+ #region Update
+ public async Task<bool> UpdateTechnology(UpdateTechnologyServiceModel updateTechnologyServiceModel)
+ {
+ if (!await this._technologyRepository.DoesTechnologyExistAsync(updateTechnologyServiceModel.Id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology));
+
+ if (await this._technologyRepository.DoesTechnologyNameExistAsync(updateTechnologyServiceModel.Name))
+ 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);
+
+ return result;
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeleteTechnology(Guid id)
+ {
+ if (!await this._technologyRepository.DoesTechnologyExistAsync(id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology));
+
+ Technology technology = await this._technologyRepository.GetByIdAsync(id);
+ bool result = await this._technologyRepository.DeleteAsync(technology);
+
+ return result;
+ }
+ #endregion
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs
new file mode 100644
index 0000000..62576d4
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/UserService.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.Linq;
+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
+{
+ public class UserService : IUserService
+ {
+ private readonly IUserRepository _userRepository;
+ private readonly IRoleRepository _roleRepository;
+ private readonly ILanguageRepository _languageRepository;
+ private readonly ITechnologyRepository _technologyRepository;
+ private readonly IMapper _userMapper;
+ 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,
+ IJwtService jwtService)
+ {
+ this._userRepository = userRepository;
+ this._roleRepository = roleRepository;
+ this._userMapper = mapper;
+ this._languageRepository = languageRepository;
+ this._technologyRepository = technologyRepository;
+ this._jwtService = jwtService;
+ }
+
+ #region Authentication
+ public async Task<TokenModel> LoginUser(LoginServiceModel loginModel)
+ {
+ if (!await this._userRepository.DoesUsernameExistAsync(loginModel.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 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));
+ }
+
+ public async Task<TokenModel> RegisterUser(RegisterServiceModel registerModel)
+ {
+ if (await this._userRepository.DoesUsernameExistAsync(registerModel.UserName))
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username));
+
+ if (await this._userRepository.DoesEmailExistAsync(registerModel.Email))
+ throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Email));
+
+
+ User user = this._userMapper.Map<User>(registerModel);
+
+ bool userResult = await this._userRepository.AddAsync(user);
+ bool roleResult = await this._userRepository.AddRoleToUser(user, Role.DefaultRole);
+
+ if (!userResult)
+ throw new InvalidOperationException(string.Format(ErrorMessages.CannotCreate, ClassesConstants.User.ToLower()));
+ if (!roleResult)
+ throw new InvalidOperationException(string.Format(ErrorMessages.CannotAdd, ClassesConstants.Role.ToLower()));
+
+ User createdUser = await this._userRepository.GetByUsernameAsync(registerModel.UserName);
+
+ List<string> roleNames = createdUser.Roles.Select(x => x.Name).ToList();
+ return new TokenModel(this._jwtService.GenerateJwtToken(createdUser.Id, createdUser.UserName, roleNames));
+ }
+ #endregion
+
+ #region Read
+ public async Task<UserServiceModel> GetUserById(Guid id)
+ {
+ User user = await this._userRepository.GetByIdAsync(id) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ return this._userMapper.Map<UserServiceModel>(user);
+ }
+
+ public async Task<UserServiceModel> GetUserByUsername(string username)
+ {
+ User user = await this._userRepository.GetByUsernameAsync(username) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ return this._userMapper.Map<UserServiceModel>(user);
+ }
+ #endregion
+
+ #region Update
+ public async Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel)
+ {
+ await ValidateUserOnUpdate(updateUserServiceModel);
+
+ User user = await this._userRepository.GetByIdAsync(updateUserServiceModel.Id);
+ await PopulateUserModel(user, updateUserServiceModel);
+
+ if (updateUserServiceModel.Friends.Count > 0)
+ await CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList());
+ else
+ user.Friends.Clear();
+
+ bool result = await this._userRepository.EditAsync(user.Id, user);
+
+ if (!result)
+ throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower()));
+
+ User newUser = await this._userRepository.GetByIdAsync(user.Id);
+ return this._userMapper.Map<UserServiceModel>(newUser);
+ }
+ #endregion
+
+ #region Delete
+ public async Task<bool> DeleteUser(Guid id)
+ {
+ if (!await this._userRepository.DoesUserExistAsync(id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ User user = await this._userRepository.GetByIdAsync(id);
+ return await this._userRepository.DeleteAsync(user);
+ }
+ #endregion
+
+ #region Validations
+ /// <summary>
+ /// Checks whether the user in the model exists and whether the username in the model is already taken.
+ /// If the check fails (is false), it throws an exception, otherwise nothing happens
+ /// </summary>
+ private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel)
+ {
+ if (!await this._userRepository.DoesUserExistAsync(updateUserServiceModel.Id))
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User));
+
+ if (updateUserServiceModel.Friends.Any(x => x.UserName == updateUserServiceModel.UserName))
+ throw new InvalidOperationException(NoYourselfAsFriend);
+
+ if (!await this._userRepository.DoesUserHaveThisUsernameAsync(updateUserServiceModel.Id, updateUserServiceModel.UserName)
+ && await this._userRepository.DoesUsernameExistAsync(updateUserServiceModel.UserName))
+ 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 ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.OneOrMoreFriends));
+ }
+ #endregion
+
+ #region Misc
+ public async Task<TokenModel> SuperSecretPromotionToAdmin(Guid userId)
+ {
+ User user = await this._userRepository.GetByIdAsync(userId) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User) + " " + Rant);
+
+ if (!await this._roleRepository.DoesNameExist(Role.AdminRole))
+ {
+ Role adminRole = new() { Name = Role.AdminRole };
+ adminRole.Users.Add(user);
+
+ await this._roleRepository.AddAsync(adminRole);
+ }
+
+ Role admin = await this._roleRepository.GetByNameAsync(Role.AdminRole);
+
+ user.Roles.Add(admin);
+ await this._userRepository.EditAsync(user.Id, user);
+
+ User createdUser = await this._userRepository.GetByIdAsync(userId);
+ List<string> roleNames = createdUser
+ .Roles
+ .Select(x => x.Name)
+ .ToList();
+
+ return new TokenModel(this._jwtService.GenerateJwtToken(createdUser.Id, createdUser.UserName, roleNames));
+ }
+
+ private async Task PopulateUserModel(User user, UpdateUserServiceModel updateUserServiceModel)
+ {
+ user.UserName = updateUserServiceModel.UserName;
+ user.FirstName = updateUserServiceModel.FirstName;
+ user.LastName = updateUserServiceModel.LastName;
+ user.Email = updateUserServiceModel.Email;
+
+ //Do NOT allow a user to change his roles, unless he is an Admin
+ bool isAdmin = await this._userRepository.IsInRoleAsync(user, Role.AdminRole);
+
+ if (isAdmin)
+ {
+ HashSet<Role> roles = new();
+ foreach (var role in updateUserServiceModel.Roles)
+ {
+ Role returnedRole = await this._roleRepository.GetByNameAsync(role.Name) ??
+ throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role));
+
+ roles.Add(returnedRole);
+ }
+ user.Roles = roles;
+ }
+
+ HashSet<Language> languages = new();
+ int languagesCount = updateUserServiceModel.Languages.Count;
+ for (int i = 0; i < languagesCount; i++)
+ {
+ Language language = await this._languageRepository.GetByNameAsync(updateUserServiceModel.Languages.ElementAt(i).Name) ??
+ throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Language)));
+
+ languages.Add(language);
+ }
+ user.Languages = languages;
+
+ /* Fetch Technologies and replace model's*/
+ HashSet<Technology> technologies = new();
+ int technologiesCount = updateUserServiceModel.Technologies.Count;
+ for (int i = 0; i < technologiesCount; i++)
+ {
+ Technology technology = await this._technologyRepository.GetByNameAsync(updateUserServiceModel.Technologies.ElementAt(i).Name) ??
+ throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Technology)));
+
+
+ technologies.Add(technology);
+ }
+ user.Technologies = technologies;
+ }
+
+ private async Task CreateRelationToFriends(User user, List<UpdateFriendServiceModel> friends)
+ {
+ foreach (var friend in friends)
+ {
+ User amigo = await this._userRepository.GetByUsernameAsync(friend.UserName);
+
+ user.Friends.Add(amigo);
+ amigo.Friends.Add(user);
+
+ await this._userRepository.EditAsync(amigo.Id, amigo);
+ }
+ }
+ #endregion
+ }
+}