diff options
Diffstat (limited to 'src/Services/DevHive.Services')
13 files changed, 273 insertions, 148 deletions
diff --git a/src/Services/DevHive.Services/DevHive.Services.csproj b/src/Services/DevHive.Services/DevHive.Services.csproj index f51c1b6..2468711 100644 --- a/src/Services/DevHive.Services/DevHive.Services.csproj +++ b/src/Services/DevHive.Services/DevHive.Services.csproj @@ -4,15 +4,15 @@ </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0"/> - <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3"> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> - <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.8.0"/> + <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0"/> <PackageReference Include="AutoMapper" Version="10.1.1"/> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.1"/> - <PackageReference Include="CloudinaryDotNet" Version="1.14.0"/> - <PackageReference Include="SonarAnalyzer.CSharp" Version="8.19.0.28253"/> + <PackageReference Include="CloudinaryDotNet" Version="1.15.1"/> + <PackageReference Include="SonarAnalyzer.CSharp" Version="8.20.0.28934"/> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\Data\DevHive.Data\DevHive.Data.csproj"/> diff --git a/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs new file mode 100644 index 0000000..edf2775 --- /dev/null +++ b/src/Services/DevHive.Services/Interfaces/IProfilePictureService.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading.Tasks; +using DevHive.Services.Models.ProfilePicture; + +namespace DevHive.Services.Interfaces +{ + public interface IProfilePictureService + { + /// <summary> + /// Get a profile picture by it's Guid + /// </summary> + /// <param name="id">Profile picture's Guid</param> + /// <returns>The profile picture's URL in the cloud</returns> + Task<string> GetProfilePictureById(Guid id); + + /// <summary> + /// Uploads the given picture and assigns it's link to the user in the database + /// </summary> + /// <param name="profilePictureServiceModel">Contains User's Guid and the new picture to be updated</param> + /// <returns>The new profile picture's URL in the cloud</returns> + Task<string> UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel); + + /// <summary> + /// Delete a profile picture from the cloud and the database + /// </summary> + /// <param name="id">The profile picture's Guid</param> + /// <returns>True if the picture is deleted, false otherwise</returns> + Task<bool> DeleteProfilePicture(Guid id); + } +} diff --git a/src/Services/DevHive.Services/Interfaces/IUserService.cs b/src/Services/DevHive.Services/Interfaces/IUserService.cs index a55f9dd..da07507 100644 --- a/src/Services/DevHive.Services/Interfaces/IUserService.cs +++ b/src/Services/DevHive.Services/Interfaces/IUserService.cs @@ -45,14 +45,6 @@ namespace DevHive.Services.Interfaces Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel); /// <summary> - /// Uploads the given picture and assigns it's link to the user in the database - /// Requires authenticated user - /// </summary> - /// <param name="updateProfilePictureServiceModel">Contains User's Guid and the new picture to be updated</param> - /// <returns>The new picture's URL</returns> - Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel); - - /// <summary> /// Deletes a user from the database and removes his data entirely /// Requires authenticated user /// </summary> diff --git a/src/Services/DevHive.Services/Services/CloudinaryService.cs b/src/Services/DevHive.Services/Services/CloudinaryService.cs index 57955a2..078bb5d 100644 --- a/src/Services/DevHive.Services/Services/CloudinaryService.cs +++ b/src/Services/DevHive.Services/Services/CloudinaryService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text.RegularExpressions; using System.Threading.Tasks; using CloudinaryDotNet; using CloudinaryDotNet.Actions; @@ -11,6 +12,10 @@ namespace DevHive.Services.Services { public class CloudinaryService : ICloudService { + // Regex for getting the filename without (final) filename extension + // So, from image.png, it will match image, and from doc.my.txt will match doc.my + private static readonly Regex s_imageRegex = new(".*(?=\\.)"); + private readonly Cloudinary _cloudinary; public CloudinaryService(string cloudName, string apiKey, string apiSecret) @@ -23,23 +28,21 @@ namespace DevHive.Services.Services List<string> fileUrls = new(); foreach (var formFile in formFiles) { - string formFileId = Guid.NewGuid().ToString(); + string fileName = s_imageRegex.Match(formFile.FileName).ToString(); + + using var ms = new MemoryStream(); + formFile.CopyTo(ms); + byte[] formBytes = ms.ToArray(); - using (var ms = new MemoryStream()) + RawUploadParams rawUploadParams = new() { - formFile.CopyTo(ms); - byte[] formBytes = ms.ToArray(); - - RawUploadParams rawUploadParams = new() - { - File = new FileDescription(formFileId, new MemoryStream(formBytes)), - PublicId = formFileId, - UseFilename = true - }; - - RawUploadResult rawUploadResult = await this._cloudinary.UploadAsync(rawUploadParams); - fileUrls.Add(rawUploadResult.Url.AbsoluteUri); - } + File = new FileDescription(fileName, new MemoryStream(formBytes)), + PublicId = fileName, + UseFilename = true + }; + + RawUploadResult rawUploadResult = await this._cloudinary.UploadAsync(rawUploadParams); + fileUrls.Add(rawUploadResult.Url.AbsoluteUri); } return fileUrls; @@ -47,6 +50,9 @@ namespace DevHive.Services.Services public async Task<bool> RemoveFilesFromCloud(List<string> fileUrls) { + // Workaround, this method isn't fully implemented yet + await Task.Run(null); + return true; } } diff --git a/src/Services/DevHive.Services/Services/CommentService.cs b/src/Services/DevHive.Services/Services/CommentService.cs index b48bac8..1c388f6 100644 --- a/src/Services/DevHive.Services/Services/CommentService.cs +++ b/src/Services/DevHive.Services/Services/CommentService.cs @@ -1,14 +1,15 @@ using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Security.Claims; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; +using DevHive.Data.Interfaces; using DevHive.Data.Models; -using DevHive.Services.Models.Comment; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; using DevHive.Services.Interfaces; -using DevHive.Data.Interfaces; -using System.Linq; +using DevHive.Services.Models.Comment; namespace DevHive.Services.Services { @@ -31,7 +32,7 @@ namespace DevHive.Services.Services public async Task<Guid> AddComment(CreateCommentServiceModel createCommentServiceModel) { if (!await this._postRepository.DoesPostExist(createCommentServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Comment comment = this._postMapper.Map<Comment>(createCommentServiceModel); comment.TimeCreated = DateTime.Now; @@ -56,10 +57,10 @@ namespace DevHive.Services.Services public async Task<ReadCommentServiceModel> GetCommentById(Guid id) { Comment comment = await this._commentRepository.GetByIdAsync(id) ?? - throw new ArgumentException("The comment does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); User user = await this._userRepository.GetByIdAsync(comment.Creator.Id) ?? - throw new ArgumentException("The user does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); ReadCommentServiceModel readCommentServiceModel = this._postMapper.Map<ReadCommentServiceModel>(comment); readCommentServiceModel.IssuerFirstName = user.FirstName; @@ -74,7 +75,7 @@ namespace DevHive.Services.Services public async Task<Guid> UpdateComment(UpdateCommentServiceModel updateCommentServiceModel) { if (!await this._commentRepository.DoesCommentExist(updateCommentServiceModel.CommentId)) - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); Comment comment = this._postMapper.Map<Comment>(updateCommentServiceModel); comment.TimeCreated = DateTime.Now; @@ -95,7 +96,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteComment(Guid id) { if (!await this._commentRepository.DoesCommentExist(id)) - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); Comment comment = await this._commentRepository.GetByIdAsync(id); return await this._commentRepository.DeleteAsync(comment); @@ -121,7 +122,7 @@ namespace DevHive.Services.Services public async Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData) { Comment comment = await this._commentRepository.GetByIdAsync(commentId) ?? - throw new ArgumentException("Comment does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); User user = await this.GetUserForValidation(rawTokenData); //If user made the comment @@ -141,10 +142,10 @@ namespace DevHive.Services.Services { JwtSecurityToken jwt = new JwtSecurityTokenHandler().ReadJwtToken(rawTokenData.Remove(0, 7)); - Guid jwtUserId = Guid.Parse(this.GetClaimTypeValues("ID", jwt.Claims).First()); + Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First()); User user = await this._userRepository.GetByIdAsync(jwtUserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return user; } @@ -152,7 +153,7 @@ namespace DevHive.Services.Services /// <summary> /// Returns all values from a given claim type /// </summary> - private List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims) + private static List<string> GetClaimTypeValues(string type, IEnumerable<Claim> claims) { List<string> toReturn = new(); diff --git a/src/Services/DevHive.Services/Services/FeedService.cs b/src/Services/DevHive.Services/Services/FeedService.cs index 0af8093..9c622b3 100644 --- a/src/Services/DevHive.Services/Services/FeedService.cs +++ b/src/Services/DevHive.Services/Services/FeedService.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -26,10 +28,11 @@ namespace DevHive.Services.Services /// <summary> /// This method is used in the feed page. - /// See the FeedRepository "GetFriendsPosts" menthod for more information on how it works. + /// See the FeedRepository "GetFriendsPosts" method for more information on how it works. /// </summary> public async Task<ReadPageServiceModel> GetPage(GetPageServiceModel getPageServiceModel) { + //TODO: Rework the initialization of User User user = null; if (getPageServiceModel.UserId != Guid.Empty) @@ -37,10 +40,10 @@ namespace DevHive.Services.Services else if (!string.IsNullOrEmpty(getPageServiceModel.Username)) user = await this._userRepository.GetByUsernameAsync(getPageServiceModel.Username); else - throw new ArgumentException("Invalid given data!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); if (user == null) - throw new ArgumentException("User doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); List<Post> posts = await this._feedRepository .GetFriendsPosts(user.Friends.ToList(), getPageServiceModel.FirstRequestIssued, getPageServiceModel.PageNumber, getPageServiceModel.PageSize); @@ -58,15 +61,16 @@ namespace DevHive.Services.Services /// </summary> public async Task<ReadPageServiceModel> GetUserPage(GetPageServiceModel model) { + //TODO: Rework the initialization of User User user = null; if (!string.IsNullOrEmpty(model.Username)) user = await this._userRepository.GetByUsernameAsync(model.Username); else - throw new ArgumentException("Invalid given data!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); if (user == null) - throw new ArgumentException("User doesn't exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); List<Post> posts = await this._feedRepository .GetUsersPosts(user, model.FirstRequestIssued, model.PageNumber, model.PageSize); diff --git a/src/Services/DevHive.Services/Services/LanguageService.cs b/src/Services/DevHive.Services/Services/LanguageService.cs index 9d2041e..7ee7d9f 100644 --- a/src/Services/DevHive.Services/Services/LanguageService.cs +++ b/src/Services/DevHive.Services/Services/LanguageService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -24,7 +26,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreateLanguage(CreateLanguageServiceModel createLanguageServiceModel) { if (await this._languageRepository.DoesLanguageNameExistAsync(createLanguageServiceModel.Name)) - throw new ArgumentException("Language already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); Language language = this._languageMapper.Map<Language>(createLanguageServiceModel); bool success = await this._languageRepository.AddAsync(language); @@ -45,7 +47,7 @@ namespace DevHive.Services.Services Language language = await this._languageRepository.GetByIdAsync(id); if (language == null) - throw new ArgumentException("The language does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language)); return this._languageMapper.Map<ReadLanguageServiceModel>(language); } @@ -65,10 +67,10 @@ namespace DevHive.Services.Services bool newLangNameExists = await this._languageRepository.DoesLanguageNameExistAsync(languageServiceModel.Name); if (!langExists) - throw new ArgumentException("Language does not exist!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); if (newLangNameExists) - throw new ArgumentException("Language name already exists in our data base!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Language)); Language lang = this._languageMapper.Map<Language>(languageServiceModel); return await this._languageRepository.EditAsync(languageServiceModel.Id, lang); @@ -79,7 +81,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteLanguage(Guid id) { if (!await this._languageRepository.DoesLanguageExistAsync(id)) - throw new ArgumentException("Language does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Language)); Language language = await this._languageRepository.GetByIdAsync(id); return await this._languageRepository.DeleteAsync(language); diff --git a/src/Services/DevHive.Services/Services/PostService.cs b/src/Services/DevHive.Services/Services/PostService.cs index a565473..8580e82 100644 --- a/src/Services/DevHive.Services/Services/PostService.cs +++ b/src/Services/DevHive.Services/Services/PostService.cs @@ -1,15 +1,16 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; -using AutoMapper; -using DevHive.Data.Models; -using DevHive.Services.Models.Post; using System.IdentityModel.Tokens.Jwt; +using System.Linq; using System.Security.Claims; -using DevHive.Services.Interfaces; +using System.Threading.Tasks; +using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; -using System.Linq; +using DevHive.Data.Models; using DevHive.Data.Models.Relational; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.Post; namespace DevHive.Services.Services { @@ -34,7 +35,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreatePost(CreatePostServiceModel createPostServiceModel) { if (!await this._userRepository.DoesUserExistAsync(createPostServiceModel.CreatorId)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); Post post = this._postMapper.Map<Post>(createPostServiceModel); @@ -66,7 +67,7 @@ namespace DevHive.Services.Services public async Task<ReadPostServiceModel> GetPostById(Guid id) { Post post = await this._postRepository.GetByIdAsync(id) ?? - throw new ArgumentException("The post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); // This can't happen in repo, because of how time is usually compared post.Comments = post.Comments @@ -74,7 +75,7 @@ namespace DevHive.Services.Services .ToList(); User user = await this._userRepository.GetByIdAsync(post.Creator.Id) ?? - throw new ArgumentException("The user does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); int currentRating = 0; foreach (Rating rating in post.Ratings) @@ -100,7 +101,7 @@ namespace DevHive.Services.Services public async Task<Guid> UpdatePost(UpdatePostServiceModel updatePostServiceModel) { if (!await this._postRepository.DoesPostExist(updatePostServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Post post = this._postMapper.Map<Post>(updatePostServiceModel); @@ -111,11 +112,11 @@ namespace DevHive.Services.Services List<string> fileUrlsToRemove = await this._postRepository.GetFileUrls(updatePostServiceModel.PostId); bool success = await _cloudService.RemoveFilesFromCloud(fileUrlsToRemove); if (!success) - throw new InvalidCastException("Could not delete files from the post!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower())); } List<string> fileUrls = await _cloudService.UploadFilesToCloud(updatePostServiceModel.Files) ?? - throw new ArgumentException("Unable to upload images to cloud!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower())); post.Attachments = GetPostAttachmentsFromUrls(post, fileUrls); } @@ -136,7 +137,7 @@ namespace DevHive.Services.Services public async Task<bool> DeletePost(Guid id) { if (!await this._postRepository.DoesPostExist(id)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); Post post = await this._postRepository.GetByIdAsync(id); @@ -145,7 +146,7 @@ namespace DevHive.Services.Services List<string> fileUrls = await this._postRepository.GetFileUrls(id); bool success = await _cloudService.RemoveFilesFromCloud(fileUrls); if (!success) - throw new InvalidCastException("Could not delete files from the post. Please try again"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Files.ToLower())); } return await this._postRepository.DeleteAsync(post); @@ -158,7 +159,7 @@ namespace DevHive.Services.Services /// </summary> public async Task<bool> ValidateJwtForCreating(Guid userId, string rawTokenData) { - User user = await this.GetUserForValidation(rawTokenData); + User user = await GetUserForValidation(rawTokenData); return user.Id == userId; } @@ -171,8 +172,8 @@ namespace DevHive.Services.Services public async Task<bool> ValidateJwtForPost(Guid postId, string rawTokenData) { Post post = await this._postRepository.GetByIdAsync(postId) ?? - throw new ArgumentException("Post does not exist!"); - User user = await this.GetUserForValidation(rawTokenData); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); + User user = await GetUserForValidation(rawTokenData); //If user made the post if (post.Creator.Id == user.Id) @@ -192,8 +193,8 @@ namespace DevHive.Services.Services public async Task<bool> ValidateJwtForComment(Guid commentId, string rawTokenData) { Comment comment = await this._commentRepository.GetByIdAsync(commentId) ?? - throw new ArgumentException("Comment does not exist!"); - User user = await this.GetUserForValidation(rawTokenData); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Comment)); + User user = await GetUserForValidation(rawTokenData); //If user made the comment if (comment.Creator.Id == user.Id) @@ -215,7 +216,7 @@ namespace DevHive.Services.Services Guid jwtUserId = Guid.Parse(GetClaimTypeValues("ID", jwt.Claims).First()); User user = await this._userRepository.GetByIdAsync(jwtUserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return user; } diff --git a/src/Services/DevHive.Services/Services/ProfilePictureService.cs b/src/Services/DevHive.Services/Services/ProfilePictureService.cs new file mode 100644 index 0000000..cafa7cb --- /dev/null +++ b/src/Services/DevHive.Services/Services/ProfilePictureService.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using DevHive.Common.Constants; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.ProfilePicture; +using Microsoft.AspNetCore.Http; + +namespace DevHive.Services.Services +{ + public class ProfilePictureService : IProfilePictureService + { + private readonly IUserRepository _userRepository; + private readonly IProfilePictureRepository _profilePictureRepository; + private readonly ICloudService _cloudinaryService; + + public ProfilePictureService(IUserRepository userRepository, IProfilePictureRepository profilePictureRepository, ICloudService cloudinaryService) + { + this._userRepository = userRepository; + this._profilePictureRepository = profilePictureRepository; + this._cloudinaryService = cloudinaryService; + } + + public async Task<string> GetProfilePictureById(Guid id) + { + return (await this._profilePictureRepository.GetByIdAsync(id)).PictureURL; + } + + public async Task<string> UpdateProfilePicture(ProfilePictureServiceModel profilePictureServiceModel) + { + ValidateProfPic(profilePictureServiceModel.ProfilePictureFormFile); + await ValidateUserExistsAsync(profilePictureServiceModel.UserId); + + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + if (user.ProfilePicture.Id != Guid.Empty) + { + List<string> file = new() { user.ProfilePicture.PictureURL }; + bool removed = await this._cloudinaryService.RemoveFilesFromCloud(file); + + if (!removed) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); + } + + return await SaveProfilePictureInDatabase(profilePictureServiceModel); + } + + public async Task<bool> DeleteProfilePicture(Guid id) + { + ProfilePicture profilePic = await this._profilePictureRepository.GetByIdAsync(id) ?? + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Picture)); + + bool removedFromDb = await this._profilePictureRepository.DeleteAsync(profilePic); + if (!removedFromDb) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); + + List<string> file = new() { profilePic.PictureURL }; + bool removedFromCloud = await this._cloudinaryService.RemoveFilesFromCloud(file); + if (!removedFromCloud) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotDelete, ClassesConstants.Picture.ToLower())); + + return true; + } + + private async Task<string> SaveProfilePictureInDatabase(ProfilePictureServiceModel profilePictureServiceModel) + { + List<IFormFile> file = new() { profilePictureServiceModel.ProfilePictureFormFile }; + string picUrl = (await this._cloudinaryService.UploadFilesToCloud(file))[0]; + ProfilePicture profilePic = new() { PictureURL = picUrl }; + + User user = await this._userRepository.GetByIdAsync(profilePictureServiceModel.UserId); + profilePic.UserId = user.Id; + profilePic.User = user; + + bool success = await this._profilePictureRepository.AddAsync(profilePic); + if (!success) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotUpload, ClassesConstants.Files.ToLower())); + + user.ProfilePicture = profilePic; + bool userProfilePicAlter = await this._userRepository.EditAsync(user.Id, user); + + if (!userProfilePicAlter) + throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, "user's profile picture")); + + return picUrl; + } + + private static void ValidateProfPic(IFormFile profilePictureFormFile) + { + if (profilePictureFormFile.Length == 0) + throw new ArgumentNullException(nameof(profilePictureFormFile), string.Format(ErrorMessages.InvalidData, ClassesConstants.Data.ToLower())); + } + + private async Task ValidateUserExistsAsync(Guid userId) + { + if (!await this._userRepository.DoesUserExistAsync(userId)) + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); + } + } +} diff --git a/src/Services/DevHive.Services/Services/RatingService.cs b/src/Services/DevHive.Services/Services/RatingService.cs index 1f77a6e..d6b4299 100644 --- a/src/Services/DevHive.Services/Services/RatingService.cs +++ b/src/Services/DevHive.Services/Services/RatingService.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -19,6 +16,8 @@ namespace DevHive.Services.Services private readonly IRatingRepository _ratingRepository; private readonly IMapper _mapper; + private const string NotRated = "{0} has not rated" + ClassesConstants.Post; + public RatingService(IPostRepository postRepository, IRatingRepository ratingRepository, IUserRepository userRepository, IMapper mapper) { this._postRepository = postRepository; @@ -31,7 +30,7 @@ namespace DevHive.Services.Services public async Task<Guid> RatePost(CreateRatingServiceModel createRatingServiceModel) { if (!await this._postRepository.DoesPostExist(createRatingServiceModel.PostId)) - throw new ArgumentException("Post does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Post)); if (await this._ratingRepository.UserRatedPost(createRatingServiceModel.UserId, createRatingServiceModel.PostId)) throw new ArgumentException("User already rated the post!"); @@ -57,8 +56,9 @@ namespace DevHive.Services.Services #region Read public async Task<ReadRatingServiceModel> GetRatingById(Guid ratingId) { - Rating rating = await this._ratingRepository.GetByIdAsync(ratingId) ?? - throw new ArgumentException("The rating does not exist"); + Rating rating = await this._ratingRepository.GetByIdAsync(ratingId); + if (rating is null) + return null; ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating); readRatingServiceModel.UserId = rating.User.Id; @@ -68,8 +68,9 @@ namespace DevHive.Services.Services public async Task<ReadRatingServiceModel> GetRatingByPostAndUser(Guid userId, Guid postId) { - Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId) ?? - throw new ArgumentException("The rating does not exist"); + Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(userId, postId); + if (rating is null) + return null; ReadRatingServiceModel readRatingServiceModel = this._mapper.Map<ReadRatingServiceModel>(rating); readRatingServiceModel.UserId = rating.User.Id; @@ -82,13 +83,13 @@ namespace DevHive.Services.Services public async Task<ReadRatingServiceModel> UpdateRating(UpdateRatingServiceModel updateRatingServiceModel) { Rating rating = await this._ratingRepository.GetRatingByUserAndPostId(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId) ?? - throw new ArgumentException("Rating does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating)); User user = await this._userRepository.GetByIdAsync(updateRatingServiceModel.UserId) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); if (!await this._ratingRepository.UserRatedPost(updateRatingServiceModel.UserId, updateRatingServiceModel.PostId)) - throw new ArgumentException("User has not rated the post!"); + throw new ArgumentException(string.Format(NotRated, ClassesConstants.User)); rating.User = user; rating.IsLike = updateRatingServiceModel.IsLike; @@ -109,7 +110,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteRating(Guid ratingId) { if (!await this._ratingRepository.DoesRatingExist(ratingId)) - throw new ArgumentException("Rating does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Rating)); Rating rating = await this._ratingRepository.GetByIdAsync(ratingId); return await this._ratingRepository.DeleteAsync(rating); diff --git a/src/Services/DevHive.Services/Services/RoleService.cs b/src/Services/DevHive.Services/Services/RoleService.cs index a5da759..f61181a 100644 --- a/src/Services/DevHive.Services/Services/RoleService.cs +++ b/src/Services/DevHive.Services/Services/RoleService.cs @@ -1,6 +1,8 @@ using System; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -22,7 +24,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreateRole(CreateRoleServiceModel createRoleServiceModel) { if (await this._roleRepository.DoesNameExist(createRoleServiceModel.Name)) - throw new ArgumentException("Role already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role)); Role role = this._roleMapper.Map<Role>(createRoleServiceModel); bool success = await this._roleRepository.AddAsync(role); @@ -40,7 +42,7 @@ namespace DevHive.Services.Services public async Task<RoleServiceModel> GetRoleById(Guid id) { Role role = await this._roleRepository.GetByIdAsync(id) ?? - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); return this._roleMapper.Map<RoleServiceModel>(role); } @@ -48,10 +50,10 @@ namespace DevHive.Services.Services public async Task<bool> UpdateRole(UpdateRoleServiceModel updateRoleServiceModel) { if (!await this._roleRepository.DoesRoleExist(updateRoleServiceModel.Id)) - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); if (await this._roleRepository.DoesNameExist(updateRoleServiceModel.Name)) - throw new ArgumentException("Role name already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Role)); Role role = this._roleMapper.Map<Role>(updateRoleServiceModel); return await this._roleRepository.EditAsync(updateRoleServiceModel.Id, role); @@ -60,7 +62,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteRole(Guid id) { if (!await this._roleRepository.DoesRoleExist(id)) - throw new ArgumentException("Role does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); Role role = await this._roleRepository.GetByIdAsync(id); return await this._roleRepository.DeleteAsync(role); diff --git a/src/Services/DevHive.Services/Services/TechnologyService.cs b/src/Services/DevHive.Services/Services/TechnologyService.cs index 09c4d20..4cf84c5 100644 --- a/src/Services/DevHive.Services/Services/TechnologyService.cs +++ b/src/Services/DevHive.Services/Services/TechnologyService.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Data; using System.Threading.Tasks; using AutoMapper; +using DevHive.Common.Constants; using DevHive.Data.Interfaces; using DevHive.Data.Models; using DevHive.Services.Interfaces; @@ -24,7 +26,7 @@ namespace DevHive.Services.Services public async Task<Guid> CreateTechnology(CreateTechnologyServiceModel technologyServiceModel) { if (await this._technologyRepository.DoesTechnologyNameExistAsync(technologyServiceModel.Name)) - throw new ArgumentException("Technology already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology)); Technology technology = this._technologyMapper.Map<Technology>(technologyServiceModel); bool success = await this._technologyRepository.AddAsync(technology); @@ -45,7 +47,7 @@ namespace DevHive.Services.Services Technology technology = await this._technologyRepository.GetByIdAsync(id); if (technology == null) - throw new ArgumentException("The technology does not exist"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); return this._technologyMapper.Map<ReadTechnologyServiceModel>(technology); } @@ -62,10 +64,10 @@ namespace DevHive.Services.Services public async Task<bool> UpdateTechnology(UpdateTechnologyServiceModel updateTechnologyServiceModel) { if (!await this._technologyRepository.DoesTechnologyExistAsync(updateTechnologyServiceModel.Id)) - throw new ArgumentException("Technology does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); if (await this._technologyRepository.DoesTechnologyNameExistAsync(updateTechnologyServiceModel.Name)) - throw new ArgumentException("Technology name already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Technology)); Technology technology = this._technologyMapper.Map<Technology>(updateTechnologyServiceModel); bool result = await this._technologyRepository.EditAsync(updateTechnologyServiceModel.Id, technology); @@ -78,7 +80,7 @@ namespace DevHive.Services.Services public async Task<bool> DeleteTechnology(Guid id) { if (!await this._technologyRepository.DoesTechnologyExistAsync(id)) - throw new ArgumentException("Technology does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Technology)); Technology technology = await this._technologyRepository.GetByIdAsync(id); bool result = await this._technologyRepository.DeleteAsync(technology); diff --git a/src/Services/DevHive.Services/Services/UserService.cs b/src/Services/DevHive.Services/Services/UserService.cs index 4f74b06..62576d4 100644 --- a/src/Services/DevHive.Services/Services/UserService.cs +++ b/src/Services/DevHive.Services/Services/UserService.cs @@ -1,15 +1,17 @@ -using AutoMapper; -using DevHive.Services.Models.User; -using System.Threading.Tasks; -using DevHive.Data.Models; using System; using System.Collections.Generic; -using DevHive.Common.Models.Identity; -using DevHive.Services.Interfaces; -using DevHive.Data.Interfaces; +using System.Data; +using System.IO; using System.Linq; -using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; +using AutoMapper; +using DevHive.Common.Constants; using DevHive.Common.Jwt.Interfaces; +using DevHive.Common.Models.Identity; +using DevHive.Data.Interfaces; +using DevHive.Data.Models; +using DevHive.Services.Interfaces; +using DevHive.Services.Models.User; namespace DevHive.Services.Services { @@ -20,15 +22,17 @@ namespace DevHive.Services.Services private readonly ILanguageRepository _languageRepository; private readonly ITechnologyRepository _technologyRepository; private readonly IMapper _userMapper; - private readonly ICloudService _cloudService; private readonly IJwtService _jwtService; + private const string NoYourselfAsFriend = "You cant add yourself as a friend(sry, bro)!"; + private const string Rant = "Can't promote shit in this country..."; + + public UserService(IUserRepository userRepository, ILanguageRepository languageRepository, IRoleRepository roleRepository, ITechnologyRepository technologyRepository, IMapper mapper, - ICloudService cloudService, IJwtService jwtService) { this._userRepository = userRepository; @@ -36,7 +40,6 @@ namespace DevHive.Services.Services this._userMapper = mapper; this._languageRepository = languageRepository; this._technologyRepository = technologyRepository; - this._cloudService = cloudService; this._jwtService = jwtService; } @@ -44,12 +47,12 @@ namespace DevHive.Services.Services public async Task<TokenModel> LoginUser(LoginServiceModel loginModel) { if (!await this._userRepository.DoesUsernameExistAsync(loginModel.UserName)) - throw new ArgumentException("Invalid username!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, ClassesConstants.Username)); User user = await this._userRepository.GetByUsernameAsync(loginModel.UserName); if (!await this._userRepository.VerifyPassword(user, loginModel.Password)) - throw new ArgumentException("Incorrect password!"); + throw new InvalidDataException(string.Format(ErrorMessages.IncorrectData, ClassesConstants.Password.ToLower())); List<string> roleNames = user.Roles.Select(x => x.Name).ToList(); return new TokenModel(this._jwtService.GenerateJwtToken(user.Id, user.UserName, roleNames)); @@ -58,10 +61,11 @@ namespace DevHive.Services.Services public async Task<TokenModel> RegisterUser(RegisterServiceModel registerModel) { if (await this._userRepository.DoesUsernameExistAsync(registerModel.UserName)) - throw new ArgumentException("Username already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username)); if (await this._userRepository.DoesEmailExistAsync(registerModel.Email)) - throw new ArgumentException("Email already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Email)); + User user = this._userMapper.Map<User>(registerModel); @@ -69,9 +73,9 @@ namespace DevHive.Services.Services bool roleResult = await this._userRepository.AddRoleToUser(user, Role.DefaultRole); if (!userResult) - throw new ArgumentException("Unable to create a user"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotCreate, ClassesConstants.User.ToLower())); if (!roleResult) - throw new ArgumentException("Unable to add role to user"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotAdd, ClassesConstants.Role.ToLower())); User createdUser = await this._userRepository.GetByUsernameAsync(registerModel.UserName); @@ -84,7 +88,7 @@ namespace DevHive.Services.Services public async Task<UserServiceModel> GetUserById(Guid id) { User user = await this._userRepository.GetByIdAsync(id) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return this._userMapper.Map<UserServiceModel>(user); } @@ -92,7 +96,7 @@ namespace DevHive.Services.Services public async Task<UserServiceModel> GetUserByUsername(string username) { User user = await this._userRepository.GetByUsernameAsync(username) ?? - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); return this._userMapper.Map<UserServiceModel>(user); } @@ -101,53 +105,31 @@ namespace DevHive.Services.Services #region Update public async Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateUserServiceModel) { - await this.ValidateUserOnUpdate(updateUserServiceModel); + await ValidateUserOnUpdate(updateUserServiceModel); User user = await this._userRepository.GetByIdAsync(updateUserServiceModel.Id); - await this.PopulateUserModel(user, updateUserServiceModel); + await PopulateUserModel(user, updateUserServiceModel); if (updateUserServiceModel.Friends.Count > 0) - await this.CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList()); + await CreateRelationToFriends(user, updateUserServiceModel.Friends.ToList()); else user.Friends.Clear(); bool result = await this._userRepository.EditAsync(user.Id, user); if (!result) - throw new InvalidOperationException("Unable to edit user!"); + throw new InvalidOperationException(string.Format(ErrorMessages.CannotEdit, ClassesConstants.User.ToLower())); User newUser = await this._userRepository.GetByIdAsync(user.Id); return this._userMapper.Map<UserServiceModel>(newUser); } - - public async Task<ProfilePictureServiceModel> UpdateProfilePicture(UpdateProfilePictureServiceModel updateProfilePictureServiceModel) - { - User user = await this._userRepository.GetByIdAsync(updateProfilePictureServiceModel.UserId); - - if (!string.IsNullOrEmpty(user.ProfilePicture.PictureURL)) - { - bool success = await _cloudService.RemoveFilesFromCloud(new List<string> { user.ProfilePicture.PictureURL }); - if (!success) - throw new InvalidCastException("Could not delete old profile picture!"); - } - - string fileUrl = (await this._cloudService.UploadFilesToCloud(new List<IFormFile> { updateProfilePictureServiceModel.Picture }))[0] ?? - throw new ArgumentException("Unable to upload profile picture to cloud"); - - bool successful = await this._userRepository.UpdateProfilePicture(updateProfilePictureServiceModel.UserId, fileUrl); - - if (!successful) - throw new InvalidOperationException("Unable to change profile picture!"); - - return new ProfilePictureServiceModel() { ProfilePictureURL = fileUrl }; - } #endregion #region Delete public async Task<bool> DeleteUser(Guid id) { if (!await this._userRepository.DoesUserExistAsync(id)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); User user = await this._userRepository.GetByIdAsync(id); return await this._userRepository.DeleteAsync(user); @@ -162,21 +144,21 @@ namespace DevHive.Services.Services private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel) { if (!await this._userRepository.DoesUserExistAsync(updateUserServiceModel.Id)) - throw new ArgumentException("User does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User)); if (updateUserServiceModel.Friends.Any(x => x.UserName == updateUserServiceModel.UserName)) - throw new ArgumentException("You cant add yourself as a friend(sry, bro)!"); + throw new InvalidOperationException(NoYourselfAsFriend); if (!await this._userRepository.DoesUserHaveThisUsernameAsync(updateUserServiceModel.Id, updateUserServiceModel.UserName) && await this._userRepository.DoesUsernameExistAsync(updateUserServiceModel.UserName)) - throw new ArgumentException("Username already exists!"); + throw new DuplicateNameException(string.Format(ErrorMessages.AlreadyExists, ClassesConstants.Username.ToLower())); List<string> usernames = new(); foreach (var friend in updateUserServiceModel.Friends) usernames.Add(friend.UserName); if (!await this._userRepository.ValidateFriendsCollectionAsync(usernames)) - throw new ArgumentException("One or more friends do not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.OneOrMoreFriends)); } #endregion @@ -184,7 +166,7 @@ namespace DevHive.Services.Services public async Task<TokenModel> SuperSecretPromotionToAdmin(Guid userId) { User user = await this._userRepository.GetByIdAsync(userId) ?? - throw new ArgumentException("User does not exist! Can't promote shit in this country..."); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.User) + " " + Rant); if (!await this._roleRepository.DoesNameExist(Role.AdminRole)) { @@ -224,7 +206,7 @@ namespace DevHive.Services.Services foreach (var role in updateUserServiceModel.Roles) { Role returnedRole = await this._roleRepository.GetByNameAsync(role.Name) ?? - throw new ArgumentException($"Role {role.Name} does not exist!"); + throw new ArgumentNullException(string.Format(ErrorMessages.DoesNotExist, ClassesConstants.Role)); roles.Add(returnedRole); } @@ -236,7 +218,7 @@ namespace DevHive.Services.Services for (int i = 0; i < languagesCount; i++) { Language language = await this._languageRepository.GetByNameAsync(updateUserServiceModel.Languages.ElementAt(i).Name) ?? - throw new ArgumentException("Invalid language name!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Language))); languages.Add(language); } @@ -248,7 +230,8 @@ namespace DevHive.Services.Services for (int i = 0; i < technologiesCount; i++) { Technology technology = await this._technologyRepository.GetByNameAsync(updateUserServiceModel.Technologies.ElementAt(i).Name) ?? - throw new ArgumentException("Invalid technology name!"); + throw new InvalidDataException(string.Format(ErrorMessages.InvalidData, nameof(Technology))); + technologies.Add(technology); } |
