aboutsummaryrefslogtreecommitdiff
path: root/src/Services
diff options
context:
space:
mode:
Diffstat (limited to 'src/Services')
-rw-r--r--src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj5
-rw-r--r--src/Services/DevHive.Services.Models/Post/Rating/CreateRatingServiceModel.cs (renamed from src/Services/DevHive.Services.Models/Post/Rating/RatePostServiceModel.cs)4
-rw-r--r--src/Services/DevHive.Services.Models/Post/Rating/ReadRatingServiceModel.cs (renamed from src/Services/DevHive.Services.Models/Post/Rating/ReadPostRatingServiceModel.cs)6
-rw-r--r--src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs15
-rw-r--r--src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs3
-rw-r--r--src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj8
-rw-r--r--src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs8
-rw-r--r--src/Services/DevHive.Services/DevHive.Services.csproj4
-rw-r--r--src/Services/DevHive.Services/Interfaces/IRateService.cs14
-rw-r--r--src/Services/DevHive.Services/Interfaces/IRatingService.cs22
-rw-r--r--src/Services/DevHive.Services/Interfaces/IUserService.cs49
-rw-r--r--src/Services/DevHive.Services/Options/JwtOptions.cs14
-rw-r--r--src/Services/DevHive.Services/Services/RateService.cs80
-rw-r--r--src/Services/DevHive.Services/Services/RatingService.cs125
-rw-r--r--src/Services/DevHive.Services/Services/UserService.cs125
15 files changed, 252 insertions, 230 deletions
diff --git a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
index 914efe0..a55972a 100644
--- a/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
+++ b/src/Services/DevHive.Services.Models/DevHive.Services.Models.csproj
@@ -4,9 +4,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="..\..\Common\DevHive.Common.Models\DevHive.Common.csproj"/>
+ <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/Post/Rating/RatePostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/Rating/CreateRatingServiceModel.cs
index d4eb7bd..aaeab73 100644
--- a/src/Services/DevHive.Services.Models/Post/Rating/RatePostServiceModel.cs
+++ b/src/Services/DevHive.Services.Models/Post/Rating/CreateRatingServiceModel.cs
@@ -2,12 +2,12 @@ using System;
namespace DevHive.Services.Models.Post.Rating
{
- public class RatePostServiceModel
+ public class CreateRatingServiceModel
{
public Guid UserId { get; set; }
public Guid PostId { get; set; }
- public bool Liked { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Services/DevHive.Services.Models/Post/Rating/ReadPostRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Post/Rating/ReadRatingServiceModel.cs
index 8c73aaf..86b4957 100644
--- a/src/Services/DevHive.Services.Models/Post/Rating/ReadPostRatingServiceModel.cs
+++ b/src/Services/DevHive.Services.Models/Post/Rating/ReadRatingServiceModel.cs
@@ -2,14 +2,14 @@ using System;
namespace DevHive.Services.Models.Post.Rating
{
- public class ReadPostRatingServiceModel
+ public class ReadRatingServiceModel
{
public Guid Id { get; set; }
public Guid PostId { get; set; }
- public int Likes { get; set; }
+ public Guid UserId { get; set; }
- public int Dislikes { get; set; }
+ public bool IsLike { get; set; }
}
}
diff --git a/src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs b/src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs
new file mode 100644
index 0000000..1ea8d8f
--- /dev/null
+++ b/src/Services/DevHive.Services.Models/Post/Rating/UpdateRatingServiceModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace DevHive.Services.Models.Post.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/Post/ReadPostServiceModel.cs b/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
index a7aa882..33d6520 100644
--- a/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
+++ b/src/Services/DevHive.Services.Models/Post/ReadPostServiceModel.cs
@@ -21,6 +21,7 @@ namespace DevHive.Services.Models.Post
public List<IdModel> Comments { get; set; } = new();
public List<string> FileUrls { get; set; }
- // public List<FileContentResult> Files { get; set; } = new();
+
+ public int CurrentRating { get; set; }
}
}
diff --git a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
index bdfb2bb..d85eea2 100644
--- a/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
+++ b/src/Services/DevHive.Services.Tests/DevHive.Services.Tests.csproj
@@ -5,14 +5,16 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.3"/>
- <PackageReference Include="Moq" Version="4.16.0"/>
+ <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.8.3"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</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>
diff --git a/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs b/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
index fefa6d8..4534511 100644
--- a/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
+++ b/src/Services/DevHive.Services/Configurations/Mapping/RatingMappings.cs
@@ -8,6 +8,14 @@ namespace DevHive.Services.Configurations.Mapping
{
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/DevHive.Services.csproj b/src/Services/DevHive.Services/DevHive.Services.csproj
index 650a304..f51c1b6 100644
--- a/src/Services/DevHive.Services/DevHive.Services.csproj
+++ b/src/Services/DevHive.Services/DevHive.Services.csproj
@@ -12,11 +12,13 @@
<PackageReference Include="AutoMapper" Version="10.1.1"/>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/>
<PackageReference Include="CloudinaryDotNet" Version="1.14.0"/>
- <PackageReference Include="SonarAnalyzer.CSharp" Version="8.18.0.27296"/>
+ <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/>
</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>
diff --git a/src/Services/DevHive.Services/Interfaces/IRateService.cs b/src/Services/DevHive.Services/Interfaces/IRateService.cs
deleted file mode 100644
index 359ef55..0000000
--- a/src/Services/DevHive.Services/Interfaces/IRateService.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using DevHive.Data.Models;
-using DevHive.Services.Models.Post.Rating;
-
-namespace DevHive.Services.Interfaces
-{
- public interface IRateService
- {
- Task<ReadPostRatingServiceModel> RatePost(RatePostServiceModel ratePostServiceModel);
-
- bool HasUserRatedThisPost(User user, Post post);
- }
-}
diff --git a/src/Services/DevHive.Services/Interfaces/IRatingService.cs b/src/Services/DevHive.Services/Interfaces/IRatingService.cs
new file mode 100644
index 0000000..beea821
--- /dev/null
+++ b/src/Services/DevHive.Services/Interfaces/IRatingService.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Threading.Tasks;
+using DevHive.Data.Models;
+using DevHive.Services.Models.Post.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);
+
+ Task<bool> HasUserRatedThisPost(Guid userId, Guid postId);
+ }
+}
diff --git a/src/Services/DevHive.Services/Interfaces/IUserService.cs b/src/Services/DevHive.Services/Interfaces/IUserService.cs
index 4a9ffc8..a55f9dd 100644
--- a/src/Services/DevHive.Services/Interfaces/IUserService.cs
+++ b/src/Services/DevHive.Services/Interfaces/IUserService.cs
@@ -7,19 +7,64 @@ 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>
+ /// Uploads the given picture and assigns it's link to the user in the database
+ /// Requires authenticated user
+ /// </summary>
+ /// <param name="updateProfilePictureServiceModel">Contains User's Guid and the new picture to be updated</param>
+ /// <returns>The new picture's URL</returns>
Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel);
+ /// <summary>
+ /// Deletes a user from the database and removes his data entirely
+ /// Requires authenticated user
+ /// </summary>
+ /// <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);
- Task<bool> ValidJWT(Guid id, string rawTokenData);
-
+ /// <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/Options/JwtOptions.cs b/src/Services/DevHive.Services/Options/JwtOptions.cs
deleted file mode 100644
index d973f45..0000000
--- a/src/Services/DevHive.Services/Options/JwtOptions.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.Extensions.Options;
-
-namespace DevHive.Services.Options
-{
- public class JwtOptions
- {
- public JwtOptions(string secret)
- {
- this.Secret = secret;
- }
-
- public string Secret { get; init; }
- }
-}
diff --git a/src/Services/DevHive.Services/Services/RateService.cs b/src/Services/DevHive.Services/Services/RateService.cs
deleted file mode 100644
index caf4b80..0000000
--- a/src/Services/DevHive.Services/Services/RateService.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using AutoMapper;
-using DevHive.Data.Interfaces;
-using DevHive.Data.Models;
-using DevHive.Services.Interfaces;
-using DevHive.Services.Models.Post.Rating;
-
-namespace DevHive.Services.Services
-{
- public class RateService : IRateService
- {
- private readonly IPostRepository _postRepository;
- private readonly IUserRepository _userRepository;
- private readonly IRatingRepository _ratingRepository;
- private readonly IMapper _mapper;
-
- public RateService(IPostRepository postRepository, IRatingRepository ratingRepository, IUserRepository userRepository, IMapper mapper)
- {
- this._postRepository = postRepository;
- this._ratingRepository = ratingRepository;
- this._userRepository = userRepository;
- this._mapper = mapper;
- }
-
- public async Task<ReadPostRatingServiceModel> RatePost(RatePostServiceModel ratePostServiceModel)
- {
- throw new NotImplementedException();
- // if (!await this._postRepository.DoesPostExist(ratePostServiceModel.PostId))
- // throw new ArgumentException("Post does not exist!");
-
- // if (!await this._userRepository.DoesUserExistAsync(ratePostServiceModel.UserId))
- // throw new ArgumentException("User does not exist!");
-
- // Post post = await this._postRepository.GetByIdAsync(ratePostServiceModel.PostId);
- // User user = await this._userRepository.GetByIdAsync(ratePostServiceModel.UserId);
-
- // if (this.HasUserRatedThisPost(user, post))
- // throw new ArgumentException("You can't rate the same post more then one(duh, amigo)");
-
- // this.Rate(user, post, ratePostServiceModel.Liked);
-
- // bool success = await this._ratingRepository.EditAsync(post.Rating.Id, post.Rating);
- // if (!success)
- // throw new InvalidOperationException("Unable to rate the post!");
-
- // Rating newRating = await this._ratingRepository.GetByIdAsync(post.Rating.Id);
- // return this._mapper.Map<ReadPostRatingServiceModel>(newRating);
- }
-
- public async Task<ReadPostRatingServiceModel> RemoveUserRateFromPost(Guid userId, Guid postId)
- {
- throw new NotImplementedException();
- // Post post = await this._postRepository.GetByIdAsync(postId);
- // User user = await this._userRepository.GetByIdAsync(userId);
-
- // if (!this.HasUserRatedThisPost(user, post))
- // throw new ArgumentException("You haven't rated this post, lmao!");
- }
-
- public bool HasUserRatedThisPost(User user, Post post)
- {
- throw new NotImplementedException();
- // return post.Rating.UsersThatRated
- // .Any(x => x.Id == user.Id);
- }
-
- private void Rate(User user, Post post, bool liked)
- {
- throw new NotImplementedException();
- // if (liked)
- // post.Rating.Rate++;
- // else
- // post.Rating.Rate--;
-
- // post.Rating.UsersThatRated.Add(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..6ddba1c
--- /dev/null
+++ b/src/Services/DevHive.Services/Services/RatingService.cs
@@ -0,0 +1,125 @@
+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.Data.Interfaces;
+using DevHive.Data.Models;
+using DevHive.Services.Interfaces;
+using DevHive.Services.Models.Post.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;
+
+ 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 ArgumentException("Post does not exist!");
+
+ 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) ??
+ throw new ArgumentException("The rating does not exist");
+
+ 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) ??
+ throw new ArgumentException("The rating does not exist");
+
+ 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.GetByIdAsync(updateRatingServiceModel.Id) ??
+ throw new ArgumentException("Rating does not exist!");
+
+ User user = await this._userRepository.GetByIdAsync(updateRatingServiceModel.UserId) ??
+ throw new ArgumentException("User does not exist!");
+
+ if (!await this._ratingRepository.UserRatedPost(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId))
+ throw new ArgumentException("User has not rated the post!");
+
+ 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 ArgumentException("Rating does not exist!");
+
+ Rating rating = await this._ratingRepository.GetByIdAsync(ratingId);
+ return await this._ratingRepository.DeleteAsync(rating);
+ }
+ #endregion
+
+ public async Task<bool> HasUserRatedThisPost(Guid userId, Guid postId)
+ {
+ return await this._ratingRepository
+ .UserRatedPost(userId, postId);
+ }
+ }
+}
diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs
index dfd45cc..4f74b06 100644
--- a/src/Services/DevHive.Services/Services/UserService.cs
+++ b/src/Services/DevHive.Services/Services/UserService.cs
@@ -1,21 +1,15 @@
using AutoMapper;
-using DevHive.Services.Options;
using DevHive.Services.Models.User;
using System.Threading.Tasks;
using DevHive.Data.Models;
using System;
-using System.IdentityModel.Tokens.Jwt;
-using System.Security.Claims;
-using Microsoft.IdentityModel.Tokens;
-using System.Text;
using System.Collections.Generic;
using DevHive.Common.Models.Identity;
using DevHive.Services.Interfaces;
using DevHive.Data.Interfaces;
using System.Linq;
-using DevHive.Common.Models.Misc;
using Microsoft.AspNetCore.Http;
-using Newtonsoft.Json;
+using DevHive.Common.Jwt.Interfaces;
namespace DevHive.Services.Services
{
@@ -26,31 +20,27 @@ namespace DevHive.Services.Services
private readonly ILanguageRepository _languageRepository;
private readonly ITechnologyRepository _technologyRepository;
private readonly IMapper _userMapper;
- private readonly JwtOptions _jwtOptions;
private readonly ICloudService _cloudService;
+ private readonly IJwtService _jwtService;
public UserService(IUserRepository userRepository,
ILanguageRepository languageRepository,
IRoleRepository roleRepository,
ITechnologyRepository technologyRepository,
IMapper mapper,
- JwtOptions jwtOptions,
- ICloudService cloudService)
+ ICloudService cloudService,
+ IJwtService jwtService)
{
this._userRepository = userRepository;
this._roleRepository = roleRepository;
this._userMapper = mapper;
- this._jwtOptions = jwtOptions;
this._languageRepository = languageRepository;
this._technologyRepository = technologyRepository;
this._cloudService = cloudService;
+ this._jwtService = jwtService;
}
#region Authentication
- /// <summary>
- /// Adds a new user to the database with the values from the given model.
- /// Returns a JSON Web Token (that can be used for authorization)
- /// </summary>
public async Task<TokenModel> LoginUser(LoginServiceModel loginModel)
{
if (!await this._userRepository.DoesUsernameExistAsync(loginModel.UserName))
@@ -61,12 +51,10 @@ namespace DevHive.Services.Services
if (!await this._userRepository.VerifyPassword(user, loginModel.Password))
throw new ArgumentException("Incorrect password!");
- return new TokenModel(WriteJWTSecurityToken(user.Id, user.UserName, user.Roles));
+ List<string> roleNames = user.Roles.Select(x => x.Name).ToList();
+ return new TokenModel(this._jwtService.GenerateJwtToken(user.Id, user.UserName, roleNames));
}
- /// <summary>
- /// Returns a new JSON Web Token (that can be used for authorization) for the given user
- /// </summary>
public async Task<TokenModel> RegisterUser(RegisterServiceModel registerModel)
{
if (await this._userRepository.DoesUsernameExistAsync(registerModel.UserName))
@@ -86,7 +74,9 @@ namespace DevHive.Services.Services
throw new ArgumentException("Unable to add role to user");
User createdUser = await this._userRepository.GetByUsernameAsync(registerModel.UserName);
- return new TokenModel(WriteJWTSecurityToken(createdUser.Id, createdUser.UserName, createdUser.Roles));
+
+ List<string> roleNames = createdUser.Roles.Select(x => x.Name).ToList();
+ return new TokenModel(this._jwtService.GenerateJwtToken(createdUser.Id, createdUser.UserName, roleNames));
}
#endregion
@@ -130,9 +120,6 @@ namespace DevHive.Services.Services
return this._userMapper.Map<UserServiceModel>(newUser);
}
- /// <summary>
- /// Uploads the given picture and assigns it's link to the user in the database
- /// </summary>
public async Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel)
{
User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId);
@@ -169,57 +156,7 @@ namespace DevHive.Services.Services
#region Validations
/// <summary>
- /// Checks whether the given user, gotten by the "id" property,
- /// is the same user as the one in the token (unless the user in the token has the admin role)
- /// and the roles in the token are the same as those in the user, gotten by the id in the token
- /// </summary>
- public async Task<bool> ValidJWT(Guid id, string rawTokenData)
- {
- // There is authorization name in the beginning, i.e. "Bearer eyJh..."
- var jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7));
-
- Guid jwtUserID = new(UserService.GetClaimTypeValues("ID", jwt.Claims).First());
- List<string> jwtRoleNames = UserService.GetClaimTypeValues("role", jwt.Claims);
-
- User user = await this._userRepository.GetByIdAsync(jwtUserID)
- ?? throw new ArgumentException("User does not exist!");
-
- /* Check if he is an admin */
- if (user.Roles.Any(x => x.Name == Role.AdminRole))
- return true;
-
- if (!jwtRoleNames.Contains(Role.AdminRole) && user.Id != id)
- return false;
-
- // Check if jwt contains all user roles (if it doesn't, jwt is either old or tampered with)
- foreach (var role in user.Roles)
- if (!jwtRoleNames.Contains(role.Name))
- return false;
-
- // Check if jwt contains only roles of user
- if (jwtRoleNames.Count != user.Roles.Count)
- return false;
-
- return true;
- }
-
- /// <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;
- }
-
- /// <summary>
- /// Checks whether the user in the model exists
- /// and whether the username in the model is already taken.
+ /// 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)
@@ -241,38 +178,6 @@ namespace DevHive.Services.Services
if (!await this._userRepository.ValidateFriendsCollectionAsync(usernames))
throw new ArgumentException("One or more friends do not exist!");
}
-
- /// <summary>
- /// Return a new JSON Web Token, containing the user id, username and roles.
- /// Tokens have an expiration time of 7 days.
- /// </summary>
- private string WriteJWTSecurityToken(Guid userId, string username, HashSet<Role> roles)
- {
- byte[] signingKey = Encoding.ASCII.GetBytes(_jwtOptions.Secret);
- HashSet<Claim> claims = new()
- {
- new Claim("ID", $"{userId}"),
- new Claim("Username", username)
- };
-
- foreach (var role in roles)
- {
- claims.Add(new Claim(ClaimTypes.Role, role.Name));
- }
-
- SecurityTokenDescriptor tokenDescriptor = new()
- {
- Subject = new ClaimsIdentity(claims),
- Expires = DateTime.Today.AddDays(7),
- SigningCredentials = new SigningCredentials(
- new SymmetricSecurityKey(signingKey),
- SecurityAlgorithms.HmacSha512Signature)
- };
-
- JwtSecurityTokenHandler tokenHandler = new();
- SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
- return tokenHandler.WriteToken(token);
- }
#endregion
#region Misc
@@ -294,9 +199,13 @@ namespace DevHive.Services.Services
user.Roles.Add(admin);
await this._userRepository.EditAsync(user.Id, user);
- User newUser = await this._userRepository.GetByIdAsync(userId);
+ User createdUser = await this._userRepository.GetByIdAsync(userId);
+ List<string> roleNames = createdUser
+ .Roles
+ .Select(x => x.Name)
+ .ToList();
- return new TokenModel(WriteJWTSecurityToken(newUser.Id, newUser.UserName, newUser.Roles));
+ return new TokenModel(this._jwtService.GenerateJwtToken(createdUser.Id, createdUser.UserName, roleNames));
}
private async Task PopulateUserModel(User user, UpdateUserServiceModel updateUserServiceModel)