From 33b5f6297c2c975bec8a74a8facc208261c03c9e Mon Sep 17 00:00:00 2001 From: transtrike Date: Tue, 19 Jan 2021 20:36:39 +0200 Subject: Replaced RepoMethods with BaseClass and inherited it where needed --- src/DevHive.Data/Repositories/TechnologyRepository.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/DevHive.Data/Repositories/TechnologyRepository.cs') diff --git a/src/DevHive.Data/Repositories/TechnologyRepository.cs b/src/DevHive.Data/Repositories/TechnologyRepository.cs index 73827a7..390ad3f 100644 --- a/src/DevHive.Data/Repositories/TechnologyRepository.cs +++ b/src/DevHive.Data/Repositories/TechnologyRepository.cs @@ -8,7 +8,7 @@ using Microsoft.EntityFrameworkCore; namespace DevHive.Data.Repositories { - public class TechnologyRepository : ITechnologyRepository + public class TechnologyRepository : BaseRepository, ITechnologyRepository { private readonly DevHiveContext _context; @@ -25,7 +25,7 @@ namespace DevHive.Data.Repositories .Set() .AddAsync(entity); - return await RepositoryMethods.SaveChangesAsync(this._context); + return await this.SaveChangesAsync(this._context); } #endregion @@ -52,7 +52,7 @@ namespace DevHive.Data.Repositories .Set() .Update(newEntity); - return await RepositoryMethods.SaveChangesAsync(this._context); + return await this.SaveChangesAsync(this._context); } #endregion @@ -64,7 +64,7 @@ namespace DevHive.Data.Repositories .Set() .Remove(entity); - return await RepositoryMethods.SaveChangesAsync(this._context); + return await this.SaveChangesAsync(this._context); } #endregion -- cgit v1.2.3 From 9e86699c9b3aff17e0c4d19850b41b792a9625ef Mon Sep 17 00:00:00 2001 From: transtrike Date: Thu, 21 Jan 2021 19:12:04 +0200 Subject: Removed HTTP Patch; Refactored HTTP Put; Fixed Update bug --- .../Repositories/LanguageRepository.cs | 7 +- .../Repositories/TechnologyRepository.cs | 1 + src/DevHive.Data/Repositories/UserRepository.cs | 15 ++- .../Configurations/Mapping/RoleMapings.cs | 2 +- .../Configurations/Mapping/TechnologyMappings.cs | 2 + .../Mapping/UserCollectionMappings.cs | 22 ---- src/DevHive.Services/Interfaces/IUserService.cs | 1 - .../Models/Identity/Role/CreateRoleServiceModel.cs | 14 +++ .../Models/Identity/User/FriendServiceModel.cs | 3 + .../Identity/User/UpdateFriendServiceModel.cs | 10 ++ .../User/UpdateUserCollectionServiceModel.cs | 7 -- .../Models/Identity/User/UpdateUserServiceModel.cs | 11 +- src/DevHive.Services/Services/UserService.cs | 135 +++++++++------------ .../Configurations/Mapping/LanguageMappings.cs | 7 +- .../Configurations/Mapping/RoleMappings.cs | 9 +- .../Configurations/Mapping/TechnologyMappings.cs | 3 +- .../Configurations/Mapping/UserMappings.cs | 13 +- src/DevHive.Web/Controllers/UserController.cs | 14 --- .../Models/Identity/User/UpdateUserWebModel.cs | 5 + 19 files changed, 132 insertions(+), 149 deletions(-) delete mode 100644 src/DevHive.Services/Configurations/Mapping/UserCollectionMappings.cs create mode 100644 src/DevHive.Services/Models/Identity/Role/CreateRoleServiceModel.cs create mode 100644 src/DevHive.Services/Models/Identity/User/UpdateFriendServiceModel.cs delete mode 100644 src/DevHive.Services/Models/Identity/User/UpdateUserCollectionServiceModel.cs (limited to 'src/DevHive.Data/Repositories/TechnologyRepository.cs') diff --git a/src/DevHive.Data/Repositories/LanguageRepository.cs b/src/DevHive.Data/Repositories/LanguageRepository.cs index 108b307..4c51cf3 100644 --- a/src/DevHive.Data/Repositories/LanguageRepository.cs +++ b/src/DevHive.Data/Repositories/LanguageRepository.cs @@ -20,8 +20,7 @@ namespace DevHive.Data.Repositories public async Task AddAsync(Language entity) { - await this._context - .Set() + await this._context.Languages .AddAsync(entity); return await this.SaveChangesAsync(this._context); @@ -32,14 +31,14 @@ namespace DevHive.Data.Repositories public async Task GetByIdAsync(Guid id) { - return await this._context - .Set() + return await this._context.Languages .FindAsync(id); } public async Task GetByNameAsync(string languageName) { return await this._context.Languages + .AsNoTracking() .FirstOrDefaultAsync(x => x.Name == languageName); } #endregion diff --git a/src/DevHive.Data/Repositories/TechnologyRepository.cs b/src/DevHive.Data/Repositories/TechnologyRepository.cs index 390ad3f..a41d4fb 100644 --- a/src/DevHive.Data/Repositories/TechnologyRepository.cs +++ b/src/DevHive.Data/Repositories/TechnologyRepository.cs @@ -40,6 +40,7 @@ namespace DevHive.Data.Repositories public async Task GetByNameAsync(string technologyName) { return await this._context.Technologies + .AsNoTracking() .FirstOrDefaultAsync(x => x.Name == technologyName); } #endregion diff --git a/src/DevHive.Data/Repositories/UserRepository.cs b/src/DevHive.Data/Repositories/UserRepository.cs index 3f9af70..c769f7e 100644 --- a/src/DevHive.Data/Repositories/UserRepository.cs +++ b/src/DevHive.Data/Repositories/UserRepository.cs @@ -6,6 +6,7 @@ using DevHive.Common.Models.Misc; using DevHive.Data.Interfaces.Repositories; using DevHive.Data.Models; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; namespace DevHive.Data.Repositories { @@ -78,7 +79,9 @@ namespace DevHive.Data.Repositories public async Task GetByUsernameAsync(string username) { return await this._context.Users - .Include(u => u.Roles) + .AsNoTracking() + .Include(x => x.Languages) + .Include(x => x.Technologies) .FirstOrDefaultAsync(x => x.UserName == username); } @@ -107,9 +110,13 @@ namespace DevHive.Data.Repositories #region Update - public async Task EditAsync(User newEntity) + public async Task EditAsync(User entity) { - this._context.Update(newEntity); + User user = await this._context.Users + .FirstOrDefaultAsync(x => x.Id == entity.Id); + + this._context.Update(user); + this._context.Entry(entity).CurrentValues.SetValues(entity); return await this.SaveChangesAsync(this._context); } @@ -177,6 +184,7 @@ namespace DevHive.Data.Repositories public async Task DoesUserExistAsync(Guid id) { return await this._context.Users + .AsNoTracking() .AnyAsync(x => x.Id == id); } @@ -208,6 +216,7 @@ namespace DevHive.Data.Repositories public bool DoesUserHaveThisUsername(Guid id, string username) { return this._context.Users + .AsNoTracking() .Any(x => x.Id == id && x.UserName == username); } diff --git a/src/DevHive.Services/Configurations/Mapping/RoleMapings.cs b/src/DevHive.Services/Configurations/Mapping/RoleMapings.cs index b5541f9..d6c8511 100644 --- a/src/DevHive.Services/Configurations/Mapping/RoleMapings.cs +++ b/src/DevHive.Services/Configurations/Mapping/RoleMapings.cs @@ -12,7 +12,7 @@ namespace DevHive.Services.Configurations.Mapping CreateMap(); CreateMap(); - CreateMap(); + CreateMap(); } } } diff --git a/src/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs b/src/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs index 079ec3e..0103ccf 100644 --- a/src/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs +++ b/src/DevHive.Services/Configurations/Mapping/TechnologyMappings.cs @@ -11,8 +11,10 @@ namespace DevHive.Services.Configurations.Mapping CreateMap(); CreateMap(); CreateMap(); + CreateMap(); CreateMap(); + CreateMap(); } } } diff --git a/src/DevHive.Services/Configurations/Mapping/UserCollectionMappings.cs b/src/DevHive.Services/Configurations/Mapping/UserCollectionMappings.cs deleted file mode 100644 index 7a773e8..0000000 --- a/src/DevHive.Services/Configurations/Mapping/UserCollectionMappings.cs +++ /dev/null @@ -1,22 +0,0 @@ -using AutoMapper; -using DevHive.Data.Models; -using DevHive.Services.Models.Identity.User; - -namespace DevHive.Services.Configurations.Mapping -{ - public class UserCollectionMappings : Profile - { - public UserCollectionMappings() - { - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - - CreateMap(); - CreateMap(); - CreateMap(); - CreateMap(); - } - } -} diff --git a/src/DevHive.Services/Interfaces/IUserService.cs b/src/DevHive.Services/Interfaces/IUserService.cs index 88be0c8..923e9bb 100644 --- a/src/DevHive.Services/Interfaces/IUserService.cs +++ b/src/DevHive.Services/Interfaces/IUserService.cs @@ -18,7 +18,6 @@ namespace DevHive.Services.Interfaces Task GetUserById(Guid id); Task UpdateUser(UpdateUserServiceModel updateModel); - Task PatchUser(Guid id, List patch); Task DeleteUser(Guid id); Task RemoveFriend(Guid userId, Guid friendId); diff --git a/src/DevHive.Services/Models/Identity/Role/CreateRoleServiceModel.cs b/src/DevHive.Services/Models/Identity/Role/CreateRoleServiceModel.cs new file mode 100644 index 0000000..53bea9e --- /dev/null +++ b/src/DevHive.Services/Models/Identity/Role/CreateRoleServiceModel.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; + +namespace DevHive.Services.Models.Identity.Role +{ + public class CreateRoleServiceModel + { + [NotNull] + [Required] + [MinLength(3)] + [MaxLength(50)] + public string Name { get; set; } + } +} diff --git a/src/DevHive.Services/Models/Identity/User/FriendServiceModel.cs b/src/DevHive.Services/Models/Identity/User/FriendServiceModel.cs index 63d57f7..a784f5c 100644 --- a/src/DevHive.Services/Models/Identity/User/FriendServiceModel.cs +++ b/src/DevHive.Services/Models/Identity/User/FriendServiceModel.cs @@ -1,7 +1,10 @@ +using System; + namespace DevHive.Services.Models.Identity.User { public class FriendServiceModel { + public Guid Id { get; set; } public string UserName { get; set; } } } diff --git a/src/DevHive.Services/Models/Identity/User/UpdateFriendServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateFriendServiceModel.cs new file mode 100644 index 0000000..83fcc34 --- /dev/null +++ b/src/DevHive.Services/Models/Identity/User/UpdateFriendServiceModel.cs @@ -0,0 +1,10 @@ +using System; + +namespace DevHive.Services.Models.Identity.User +{ + public class UpdateFriendServiceModel + { + public Guid Id { get; set; } + public string Name { get; set; } + } +} diff --git a/src/DevHive.Services/Models/Identity/User/UpdateUserCollectionServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateUserCollectionServiceModel.cs deleted file mode 100644 index c40a980..0000000 --- a/src/DevHive.Services/Models/Identity/User/UpdateUserCollectionServiceModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DevHive.Services.Models.Identity.User -{ - public class UpdateUserCollectionServiceModel - { - public string Name { get; set; } - } -} diff --git a/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs b/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs index 835bf54..9277e3e 100644 --- a/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs +++ b/src/DevHive.Services/Models/Identity/User/UpdateUserServiceModel.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using DevHive.Services.Models.Identity.Role; +using DevHive.Services.Models.Language; +using DevHive.Services.Models.Technology; namespace DevHive.Services.Models.Identity.User { @@ -9,13 +12,13 @@ namespace DevHive.Services.Models.Identity.User public string Password { get; set; } - public HashSet Roles { get; set; } = new HashSet(); + public HashSet Roles { get; set; } = new HashSet(); - public HashSet Friends { get; set; } = new HashSet(); + public HashSet Friends { get; set; } = new HashSet(); - public HashSet Languages { get; set; } = new HashSet(); + public HashSet Languages { get; set; } = new HashSet(); - public HashSet Technologies { get; set; } = new HashSet(); + public HashSet Technologies { get; set; } = new HashSet(); } } diff --git a/src/DevHive.Services/Services/UserService.cs b/src/DevHive.Services/Services/UserService.cs index dca00fa..a57fd23 100644 --- a/src/DevHive.Services/Services/UserService.cs +++ b/src/DevHive.Services/Services/UserService.cs @@ -14,8 +14,9 @@ using DevHive.Services.Interfaces; using DevHive.Data.Interfaces.Repositories; using System.Linq; using DevHive.Common.Models.Misc; -using System.Reflection; -using Microsoft.CodeAnalysis.CSharp.Syntax; +using DevHive.Services.Models.Language; +using DevHive.Services.Models.Technology; +using DevHive.Services.Models.Identity.Role; namespace DevHive.Services.Services { @@ -135,69 +136,57 @@ namespace DevHive.Services.Services public async Task UpdateUser(UpdateUserServiceModel updateUserServiceModel) { - //Method: ValidateUserOnUpdate - if (!await this._userRepository.DoesUserExistAsync(updateUserServiceModel.Id)) - throw new ArgumentException("User does not exist!"); - - if (!this._userRepository.DoesUserHaveThisUsername(updateUserServiceModel.Id, updateUserServiceModel.UserName) - && await this._userRepository.DoesUsernameExistAsync(updateUserServiceModel.UserName)) - throw new ArgumentException("Username already exists!"); + await this.ValidateUserOnUpdate(updateUserServiceModel); await this.ValidateUserCollections(updateUserServiceModel); - //Method: Insert collections to user - HashSet languages = new(); - foreach (UpdateUserCollectionServiceModel lang in updateUserServiceModel.Languages) - languages.Add(await this._languageRepository.GetByNameAsync(lang.Name) ?? - throw new ArgumentException("Invalid language name!")); + //Preserve roles + int roleCount = updateUserServiceModel.Roles.Count; + for (int i = 0; i < roleCount; i++) + { + Role role = await this._roleRepository.GetByNameAsync(updateUserServiceModel.Roles.ElementAt(i).Name) ?? + throw new ArgumentException("Invalid role name!"); - HashSet technologies = new(); - foreach (UpdateUserCollectionServiceModel tech in updateUserServiceModel.Technologies) - technologies.Add(await this._technologyRepository.GetByNameAsync(tech.Name) ?? - throw new ArgumentException("Invalid technology name!")); + UpdateRoleServiceModel updateRoleServiceModel = this._userMapper.Map(role); - User user = this._userMapper.Map(updateUserServiceModel); + updateUserServiceModel.Roles.Add(updateRoleServiceModel); + } - user.Languages = languages; - user.Technologies = technologies; + int langCount = updateUserServiceModel.Languages.Count; + for (int i = 0; i < langCount; i++) + { + Language language = await this._languageRepository.GetByNameAsync(updateUserServiceModel.Languages.ElementAt(i).Name) ?? + throw new ArgumentException("Invalid language name!"); - bool successful = await this._userRepository.EditAsync(user); + UpdateLanguageServiceModel updateLanguageServiceModel = this._userMapper.Map(language); - if (!successful) - throw new InvalidOperationException("Unable to edit user!"); + updateUserServiceModel.Languages.Add(updateLanguageServiceModel); + } - return this._userMapper.Map(user); ; - } + //Clean the already replaced languages + updateUserServiceModel.Languages.RemoveWhere(x => x.Id == Guid.Empty); - public async Task PatchUser(Guid id, List patchList) - { - User user = await this._userRepository.GetByIdAsync(id) ?? - throw new ArgumentException("User does not exist!"); + int techCount = updateUserServiceModel.Technologies.Count; + for (int i = 0; i < techCount; i++) + { + Technology technology = await this._technologyRepository.GetByNameAsync(updateUserServiceModel.Technologies.ElementAt(i).Name) ?? + throw new ArgumentException("Invalid technology name!"); - UpdateUserServiceModel updateUserServiceModel = this._userMapper.Map(user); + UpdateTechnologyServiceModel updateTechnologyServiceModel = this._userMapper.Map(technology); - foreach (Patch patch in patchList) - { - bool successful = patch.Action switch - { - "replace" => ReplacePatch(updateUserServiceModel, patch), - "add" => AddPatch(updateUserServiceModel, patch), - "remove" => RemovePatch(updateUserServiceModel, patch), - _ => throw new ArgumentException("Invalid patch operation!"), - }; - - if (!successful) - throw new ArgumentException("A problem occurred while applying patch"); + updateUserServiceModel.Technologies.Add(updateTechnologyServiceModel); } - bool success = await this._userRepository.EditAsync(user); - if (success) - { - user = await this._userRepository.GetByIdAsync(id); - return this._userMapper.Map(user); - } - else - return null; + //Clean the already replaced technologies + updateUserServiceModel.Technologies.RemoveWhere(x => x.Id == Guid.Empty); + + User user = this._userMapper.Map(updateUserServiceModel); + bool successful = await this._userRepository.EditAsync(user); + + if (!successful) + throw new InvalidOperationException("Unable to edit user!"); + + return this._userMapper.Map(user); } #endregion @@ -282,10 +271,20 @@ namespace DevHive.Services.Services return toReturn; } + private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel) + { + if (!await this._userRepository.DoesUserExistAsync(updateUserServiceModel.Id)) + throw new ArgumentException("User does not exist!"); + + if (!this._userRepository.DoesUserHaveThisUsername(updateUserServiceModel.Id, updateUserServiceModel.UserName) + && await this._userRepository.DoesUsernameExistAsync(updateUserServiceModel.UserName)) + throw new ArgumentException("Username already exists!"); + } + private async Task ValidateUserCollections(UpdateUserServiceModel updateUserServiceModel) { // Friends - foreach (UpdateUserCollectionServiceModel friend in updateUserServiceModel.Friends) + foreach (var friend in updateUserServiceModel.Friends) { User returnedFriend = await this._userRepository.GetByUsernameAsync(friend.Name); @@ -294,29 +293,24 @@ namespace DevHive.Services.Services } // Languages - foreach (UpdateUserCollectionServiceModel language in updateUserServiceModel.Languages) + foreach (var language in updateUserServiceModel.Languages) { Language returnedLanguage = await this._languageRepository.GetByNameAsync(language.Name); - if (default(Language) == returnedLanguage) + if (returnedLanguage == null) throw new ArgumentException($"Language {language.Name} does not exist!"); } // Technology - foreach (UpdateUserCollectionServiceModel technology in updateUserServiceModel.Technologies) + foreach (var technology in updateUserServiceModel.Technologies) { Technology returnedTechnology = await this._technologyRepository.GetByNameAsync(technology.Name); - if (default(Technology) == returnedTechnology) + if (returnedTechnology == null) throw new ArgumentException($"Technology {technology.Name} does not exist!"); } } - private async Task ValidateUserOnUpdate(UpdateUserServiceModel updateUserServiceModel) - { - throw new NotImplementedException(); - } - private string WriteJWTSecurityToken(Guid userId, HashSet roles) { byte[] signingKey = Encoding.ASCII.GetBytes(_jwtOptions.Secret); @@ -344,25 +338,6 @@ namespace DevHive.Services.Services SecurityToken token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } - - private bool AddPatch(UpdateUserServiceModel updateUserServiceModel, Patch patch) - { - // Type type = typeof(UpdateUserServiceModel); - // PropertyInfo property = type.GetProperty(patch.Name); - - // property.SetValue(updateUserServiceModel, patch.Value); - throw new NotImplementedException(); - } - - private bool RemovePatch(UpdateUserServiceModel updateUserServiceModel, Patch patch) - { - throw new NotImplementedException(); - } - - private bool ReplacePatch(UpdateUserServiceModel updateUserServiceModel, Patch patch) - { - throw new NotImplementedException(); - } #endregion } } diff --git a/src/DevHive.Web/Configurations/Mapping/LanguageMappings.cs b/src/DevHive.Web/Configurations/Mapping/LanguageMappings.cs index 8cac3ca..eca0d1a 100644 --- a/src/DevHive.Web/Configurations/Mapping/LanguageMappings.cs +++ b/src/DevHive.Web/Configurations/Mapping/LanguageMappings.cs @@ -8,10 +8,11 @@ namespace DevHive.Web.Configurations.Mapping { public LanguageMappings() { - CreateMap(); - CreateMap(); CreateMap(); - CreateMap(); + CreateMap(); + CreateMap() + .ForMember(src => src.Id, dest => dest.Ignore()); + CreateMap(); CreateMap(); CreateMap(); diff --git a/src/DevHive.Web/Configurations/Mapping/RoleMappings.cs b/src/DevHive.Web/Configurations/Mapping/RoleMappings.cs index 66ae8e3..2ea2742 100644 --- a/src/DevHive.Web/Configurations/Mapping/RoleMappings.cs +++ b/src/DevHive.Web/Configurations/Mapping/RoleMappings.cs @@ -8,11 +8,14 @@ namespace DevHive.Web.Configurations.Mapping { public RoleMappings() { - CreateMap(); - CreateMap(); + CreateMap(); + CreateMap() + .ForMember(src => src.Id, dest => dest.Ignore()); + CreateMap(); + CreateMap(); + CreateMap(); CreateMap(); - CreateMap(); } } } diff --git a/src/DevHive.Web/Configurations/Mapping/TechnologyMappings.cs b/src/DevHive.Web/Configurations/Mapping/TechnologyMappings.cs index 4ecd5f3..708b6ac 100644 --- a/src/DevHive.Web/Configurations/Mapping/TechnologyMappings.cs +++ b/src/DevHive.Web/Configurations/Mapping/TechnologyMappings.cs @@ -10,7 +10,8 @@ namespace DevHive.Web.Configurations.Mapping { CreateMap(); CreateMap(); - CreateMap(); + CreateMap() + .ForMember(src => src.Id, dest => dest.Ignore()); CreateMap(); CreateMap(); diff --git a/src/DevHive.Web/Configurations/Mapping/UserMappings.cs b/src/DevHive.Web/Configurations/Mapping/UserMappings.cs index 5faf4b5..9dbf613 100644 --- a/src/DevHive.Web/Configurations/Mapping/UserMappings.cs +++ b/src/DevHive.Web/Configurations/Mapping/UserMappings.cs @@ -20,13 +20,14 @@ namespace DevHive.Web.Configurations.Mapping CreateMap(); - CreateMap(); - CreateMap(); + //Update + CreateMap() + .ForMember(src => src.Id, dest => dest.Ignore()); + CreateMap() + .ForMember(src => src.Id, dest => dest.Ignore()); - CreateMap() - .ForMember(f => f.Name, u => u.MapFrom(src => src.UserName)); - CreateMap(); - CreateMap(); + CreateMap(); + CreateMap(); } } } diff --git a/src/DevHive.Web/Controllers/UserController.cs b/src/DevHive.Web/Controllers/UserController.cs index 7121ac8..fbbbbff 100644 --- a/src/DevHive.Web/Controllers/UserController.cs +++ b/src/DevHive.Web/Controllers/UserController.cs @@ -96,20 +96,6 @@ namespace DevHive.Web.Controllers return new AcceptedResult("UpdateUser", userWebModel); } - - [HttpPatch] - public async Task Patch(Guid id, [FromBody] List patch, [FromHeader] string authorization) - { - if (!await this._userService.ValidJWT(id, authorization)) - return new UnauthorizedResult(); - - UserServiceModel userServiceModel = await this._userService.PatchUser(id, patch); - - if (userServiceModel == null) - return new BadRequestObjectResult("Wrong patch properties"); - else - return new OkObjectResult(this._userMapper.Map(userServiceModel)); - } #endregion #region Delete diff --git a/src/DevHive.Web/Models/Identity/User/UpdateUserWebModel.cs b/src/DevHive.Web/Models/Identity/User/UpdateUserWebModel.cs index 3c38ab6..30c66fb 100644 --- a/src/DevHive.Web/Models/Identity/User/UpdateUserWebModel.cs +++ b/src/DevHive.Web/Models/Identity/User/UpdateUserWebModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using DevHive.Web.Attributes; +using DevHive.Web.Models.Identity.Role; using DevHive.Web.Models.Language; using DevHive.Web.Models.Technology; @@ -18,6 +19,10 @@ namespace DevHive.Web.Models.Identity.User [Required] public HashSet Friends { get; set; } + [NotNull] + [Required] + public HashSet Roles { get; set; } + [NotNull] [Required] public HashSet Languages { get; set; } -- cgit v1.2.3 From 833c4e183581bc69102d66872b4b5bb157d80821 Mon Sep 17 00:00:00 2001 From: Danail Dimitrov Date: Thu, 21 Jan 2021 19:36:49 +0200 Subject: Refactored Technology repo edit method --- src/DevHive.Data/Repositories/TechnologyRepository.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/DevHive.Data/Repositories/TechnologyRepository.cs') diff --git a/src/DevHive.Data/Repositories/TechnologyRepository.cs b/src/DevHive.Data/Repositories/TechnologyRepository.cs index a41d4fb..6853893 100644 --- a/src/DevHive.Data/Repositories/TechnologyRepository.cs +++ b/src/DevHive.Data/Repositories/TechnologyRepository.cs @@ -46,12 +46,13 @@ namespace DevHive.Data.Repositories #endregion #region Edit - - public async Task EditAsync(Technology newEntity) + public async Task EditAsync(Technology entity) { - this._context - .Set() - .Update(newEntity); + Technology technology = await this._context.Technologies + .FirstOrDefaultAsync(x => x.Id == entity.Id); + + this._context.Update(technology); + this._context.Entry(entity).CurrentValues.SetValues(entity); return await this.SaveChangesAsync(this._context); } -- cgit v1.2.3 From 58178d5036f65bb4896fea08bbec9388a8ab8c20 Mon Sep 17 00:00:00 2001 From: transtrike Date: Thu, 21 Jan 2021 19:41:28 +0200 Subject: Code cleanup & consistency --- .../Repositories/LanguageRepository.cs | 12 +---- src/DevHive.Data/Repositories/PostRepository.cs | 43 +++++++---------- src/DevHive.Data/Repositories/RoleRepository.cs | 33 +++++++------ .../Repositories/TechnologyRepository.cs | 20 ++------ .../DevHive.Data.Tests/UserRepositoryTests.cs | 56 ---------------------- 5 files changed, 41 insertions(+), 123 deletions(-) (limited to 'src/DevHive.Data/Repositories/TechnologyRepository.cs') diff --git a/src/DevHive.Data/Repositories/LanguageRepository.cs b/src/DevHive.Data/Repositories/LanguageRepository.cs index 4c51cf3..491019c 100644 --- a/src/DevHive.Data/Repositories/LanguageRepository.cs +++ b/src/DevHive.Data/Repositories/LanguageRepository.cs @@ -17,7 +17,6 @@ namespace DevHive.Data.Repositories } #region Create - public async Task AddAsync(Language entity) { await this._context.Languages @@ -28,7 +27,6 @@ namespace DevHive.Data.Repositories #endregion #region Read - public async Task GetByIdAsync(Guid id) { return await this._context.Languages @@ -47,28 +45,22 @@ namespace DevHive.Data.Repositories public async Task EditAsync(Language newEntity) { - this._context - .Set() - .Update(newEntity); + this._context.Languages.Update(newEntity); return await this.SaveChangesAsync(this._context); } #endregion #region Delete - public async Task DeleteAsync(Language entity) { - this._context - .Set() - .Remove(entity); + this._context.Languages.Remove(entity); return await this.SaveChangesAsync(this._context); } #endregion #region Validations - public async Task DoesLanguageNameExistAsync(string languageName) { return await this._context.Languages diff --git a/src/DevHive.Data/Repositories/PostRepository.cs b/src/DevHive.Data/Repositories/PostRepository.cs index db2c4af..71602e7 100644 --- a/src/DevHive.Data/Repositories/PostRepository.cs +++ b/src/DevHive.Data/Repositories/PostRepository.cs @@ -16,11 +16,10 @@ namespace DevHive.Data.Repositories this._context = context; } - //Create + #region Create public async Task AddAsync(Post post) { - await this._context - .Set() + await this._context.Posts .AddAsync(post); return await this.SaveChangesAsync(this._context); @@ -28,18 +27,17 @@ namespace DevHive.Data.Repositories public async Task AddCommentAsync(Comment entity) { - await this._context - .Set() + await this._context.Comments .AddAsync(entity); return await this.SaveChangesAsync(this._context); } + #endregion - //Read + #region Read public async Task GetByIdAsync(Guid id) { - return await this._context - .Set() + return await this._context.Posts .FindAsync(id); } @@ -52,8 +50,7 @@ namespace DevHive.Data.Repositories public async Task GetCommentByIdAsync(Guid id) { - return await this._context - .Set() + return await this._context.Comments .FindAsync(id); } @@ -63,12 +60,12 @@ namespace DevHive.Data.Repositories .FirstOrDefaultAsync(p => p.IssuerId == issuerId && p.TimeCreated == timeCreated); } + #endregion - //Update + #region Update public async Task EditAsync(Post newPost) { - this._context - .Set() + this._context.Posts .Update(newPost); return await this.SaveChangesAsync(this._context); @@ -76,18 +73,17 @@ namespace DevHive.Data.Repositories public async Task EditCommentAsync(Comment newEntity) { - this._context - .Set() + this._context.Comments .Update(newEntity); return await this.SaveChangesAsync(this._context); } + #endregion - //Delete + #region Delete public async Task DeleteAsync(Post post) { - this._context - .Set() + this._context.Posts .Remove(post); return await this.SaveChangesAsync(this._context); @@ -95,27 +91,24 @@ namespace DevHive.Data.Repositories public async Task DeleteCommentAsync(Comment entity) { - this._context - .Set() + this._context.Comments .Remove(entity); return await this.SaveChangesAsync(this._context); } + #endregion #region Validations - public async Task DoesPostExist(Guid postId) { - return await this._context - .Set() + return await this._context.Posts .AsNoTracking() .AnyAsync(r => r.Id == postId); } public async Task DoesCommentExist(Guid id) { - return await this._context - .Set() + return await this._context.Comments .AsNoTracking() .AnyAsync(r => r.Id == id); } diff --git a/src/DevHive.Data/Repositories/RoleRepository.cs b/src/DevHive.Data/Repositories/RoleRepository.cs index 684fbd7..25549bf 100644 --- a/src/DevHive.Data/Repositories/RoleRepository.cs +++ b/src/DevHive.Data/Repositories/RoleRepository.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using DevHive.Common.Models.Misc; using DevHive.Data.Interfaces.Repositories; using DevHive.Data.Models; using Microsoft.EntityFrameworkCore; @@ -16,32 +15,31 @@ namespace DevHive.Data.Repositories this._context = context; } - //Create + #region Create public async Task AddAsync(Role entity) { - await this._context - .Set() + await this._context.Roles .AddAsync(entity); return await this.SaveChangesAsync(this._context); } + #endregion - //Read + #region Read public async Task GetByIdAsync(Guid id) { - return await this._context - .Set() + return await this._context.Roles .FindAsync(id); } public async Task GetByNameAsync(string name) { - return await this._context - .Set() + return await this._context.Roles .FirstOrDefaultAsync(x => x.Name == name); } + #endregion - //Update + #region Update public async Task EditAsync(Role newEntity) { Role role = await this.GetByIdAsync(newEntity.Id); @@ -53,31 +51,32 @@ namespace DevHive.Data.Repositories return await this.SaveChangesAsync(this._context); } + #endregion - //Delete + #region Delete public async Task DeleteAsync(Role entity) { - this._context - .Set() + this._context.Roles .Remove(entity); return await this.SaveChangesAsync(this._context); } + #endregion + #region Validations public async Task DoesNameExist(string name) { - return await this._context - .Set() + return await this._context.Roles .AsNoTracking() .AnyAsync(r => r.Name == name); } public async Task DoesRoleExist(Guid id) { - return await this._context - .Set() + return await this._context.Roles .AsNoTracking() .AnyAsync(r => r.Id == id); } + #endregion } } diff --git a/src/DevHive.Data/Repositories/TechnologyRepository.cs b/src/DevHive.Data/Repositories/TechnologyRepository.cs index a41d4fb..597a532 100644 --- a/src/DevHive.Data/Repositories/TechnologyRepository.cs +++ b/src/DevHive.Data/Repositories/TechnologyRepository.cs @@ -18,11 +18,9 @@ namespace DevHive.Data.Repositories } #region Create - public async Task AddAsync(Technology entity) { - await this._context - .Set() + await this._context.Technologies .AddAsync(entity); return await this.SaveChangesAsync(this._context); @@ -30,11 +28,9 @@ namespace DevHive.Data.Repositories #endregion #region Read - public async Task GetByIdAsync(Guid id) { - return await this._context - .Set() + return await this._context.Technologies .FindAsync(id); } public async Task GetByNameAsync(string technologyName) @@ -46,11 +42,9 @@ namespace DevHive.Data.Repositories #endregion #region Edit - public async Task EditAsync(Technology newEntity) { - this._context - .Set() + this._context.Technologies .Update(newEntity); return await this.SaveChangesAsync(this._context); @@ -58,11 +52,9 @@ namespace DevHive.Data.Repositories #endregion #region Delete - public async Task DeleteAsync(Technology entity) { - this._context - .Set() + this._context.Technologies .Remove(entity); return await this.SaveChangesAsync(this._context); @@ -70,11 +62,9 @@ namespace DevHive.Data.Repositories #endregion #region Validations - public async Task DoesTechnologyNameExistAsync(string technologyName) { - return await this._context - .Set() + return await this._context.Technologies .AsNoTracking() .AnyAsync(r => r.Name == technologyName); } diff --git a/src/DevHive.Tests/DevHive.Data.Tests/UserRepositoryTests.cs b/src/DevHive.Tests/DevHive.Data.Tests/UserRepositoryTests.cs index be116b0..d4daae5 100644 --- a/src/DevHive.Tests/DevHive.Data.Tests/UserRepositoryTests.cs +++ b/src/DevHive.Tests/DevHive.Data.Tests/UserRepositoryTests.cs @@ -51,62 +51,6 @@ namespace DevHive.Data.Tests //Assert Assert.True(result, "User int' inserted properly into the database"); } - - [Test] - public async Task AddFriendToUserAsync_ShouldAddFriendToUsersList() - { - //Arrange - User dummyUserOne = CreateDummyUser(); - User dummyUserTwo = CreateAnotherDummyUser(); - - await this._userRepository.AddAsync(dummyUserOne); - await this._userRepository.AddAsync(dummyUserTwo); - - //Act - bool result = await this._userRepository.AddFriendToUserAsync(dummyUserOne, dummyUserTwo); - - //Assert - Assert.True(result, "Friend didn't save properly in the database"); - Assert.True(dummyUserOne.Friends.Contains(dummyUserTwo), "Friend doesn't get added to user properly"); - } - - [Test] - public async Task AddLanguageToUserAsync_ShouldAddLanguageToUser() - { - //Arrange - User dummyUser = CreateDummyUser(); - await this._userRepository.AddAsync(dummyUser); - Language language = new() - { - Name = "typescript" - }; - - //Act - bool result = await this._userRepository.AddLanguageToUserAsync(dummyUser, language); - - //Assert - Assert.True(result, "The language isn't inserted properly to the database"); - Assert.True(dummyUser.Languages.Contains(language), "The language doesn't get added properly to the user"); - } - - [Test] - public async Task AddTechnologyToUserAsync_ShouldAddTechnologyToUser() - { - //Arrange - User dummyUser = CreateDummyUser(); - await this._userRepository.AddAsync(dummyUser); - Technology technology = new() - { - Name = "Angular" - }; - - //Act - bool result = await this._userRepository.AddTechnologyToUserAsync(dummyUser, technology); - - //Assert - Assert.True(result, "The technology isn't inserted properly to the database"); - Assert.True(dummyUser.Technologies.Contains(technology), "The technology doesn't get added properly to the user"); - } #endregion #region Read -- cgit v1.2.3 From bda98b96433d7a9952524fab4ec65f96998b55de Mon Sep 17 00:00:00 2001 From: transtrike Date: Thu, 21 Jan 2021 22:08:50 +0200 Subject: Generic base repo class refactored; All repos inherit generic base repo --- .../Interfaces/Repositories/IRepository.cs | 2 +- src/DevHive.Data/Repositories/BaseRepository.cs | 54 +++++++++++++++++++++- .../Repositories/LanguageRepository.cs | 43 +---------------- src/DevHive.Data/Repositories/PostRepository.cs | 34 +------------- src/DevHive.Data/Repositories/RoleRepository.cs | 43 +---------------- .../Repositories/TechnologyRepository.cs | 39 +--------------- src/DevHive.Data/Repositories/UserRepository.cs | 41 ++-------------- 7 files changed, 64 insertions(+), 192 deletions(-) (limited to 'src/DevHive.Data/Repositories/TechnologyRepository.cs') diff --git a/src/DevHive.Data/Interfaces/Repositories/IRepository.cs b/src/DevHive.Data/Interfaces/Repositories/IRepository.cs index 40a78de..d9f7c7a 100644 --- a/src/DevHive.Data/Interfaces/Repositories/IRepository.cs +++ b/src/DevHive.Data/Interfaces/Repositories/IRepository.cs @@ -18,4 +18,4 @@ namespace DevHive.Data.Repositories.Interfaces //Delete Entity from database Task DeleteAsync(TEntity entity); } -} \ No newline at end of file +} diff --git a/src/DevHive.Data/Repositories/BaseRepository.cs b/src/DevHive.Data/Repositories/BaseRepository.cs index b0f0f3e..dabb35b 100644 --- a/src/DevHive.Data/Repositories/BaseRepository.cs +++ b/src/DevHive.Data/Repositories/BaseRepository.cs @@ -1,11 +1,61 @@ +using System; using System.Threading.Tasks; +using DevHive.Data.Repositories.Interfaces; using Microsoft.EntityFrameworkCore; namespace DevHive.Data.Repositories { - public class BaseRepository + public class BaseRepository : IRepository + where TEntity : class { - public async Task SaveChangesAsync(DbContext context) + private readonly DbContext _context; + + public BaseRepository(DbContext context) + { + this._context = context; + this._context.ChangeTracker.AutoDetectChangesEnabled = false; + } + + public virtual async Task AddAsync(TEntity entity) + { + await this._context + .Set() + .AddAsync(entity); + + return await this.SaveChangesAsync(_context); + } + + public virtual async Task GetByIdAsync(Guid id) + { + return await this._context + .Set() + .FindAsync(id); + } + + public virtual async Task EditAsync(TEntity newEntity) + { + // Old way(backup) + // User user = await this._context.Users + // .FirstOrDefaultAsync(x => x.Id == entity.Id); + + // this._context.Update(user); + // this._context.Entry(entity).CurrentValues.SetValues(entity); + + this._context + .Set() + .Update(newEntity); + + return await this.SaveChangesAsync(_context); + } + + public virtual async Task DeleteAsync(TEntity entity) + { + this._context.Remove(entity); + + return await this.SaveChangesAsync(_context); + } + + public virtual async Task SaveChangesAsync(DbContext context) { int result = await context.SaveChangesAsync(); diff --git a/src/DevHive.Data/Repositories/LanguageRepository.cs b/src/DevHive.Data/Repositories/LanguageRepository.cs index 59c88a6..d7ee609 100644 --- a/src/DevHive.Data/Repositories/LanguageRepository.cs +++ b/src/DevHive.Data/Repositories/LanguageRepository.cs @@ -1,38 +1,22 @@ using System; using System.Threading.Tasks; -using DevHive.Common.Models.Misc; using DevHive.Data.Interfaces.Repositories; using DevHive.Data.Models; using Microsoft.EntityFrameworkCore; namespace DevHive.Data.Repositories { - public class LanguageRepository : BaseRepository, ILanguageRepository + public class LanguageRepository : BaseRepository, ILanguageRepository { private readonly DevHiveContext _context; public LanguageRepository(DevHiveContext context) + :base(context) { this._context = context; } - #region Create - public async Task AddAsync(Language entity) - { - await this._context.Languages - .AddAsync(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Read - public async Task GetByIdAsync(Guid id) - { - return await this._context.Languages - .FindAsync(id); - } - public async Task GetByNameAsync(string languageName) { return await this._context.Languages @@ -41,29 +25,6 @@ namespace DevHive.Data.Repositories } #endregion - #region Update - - public async Task EditAsync(Language entity) - { - Language language = await this._context.Languages - .FirstOrDefaultAsync(x => x.Id == entity.Id); - - this._context.Update(language); - this._context.Entry(entity).CurrentValues.SetValues(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - - #region Delete - public async Task DeleteAsync(Language entity) - { - this._context.Languages.Remove(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Validations public async Task DoesLanguageNameExistAsync(string languageName) { diff --git a/src/DevHive.Data/Repositories/PostRepository.cs b/src/DevHive.Data/Repositories/PostRepository.cs index 71602e7..9230a2e 100644 --- a/src/DevHive.Data/Repositories/PostRepository.cs +++ b/src/DevHive.Data/Repositories/PostRepository.cs @@ -1,30 +1,22 @@ using System; using System.Threading.Tasks; -using DevHive.Common.Models.Misc; using DevHive.Data.Interfaces.Repositories; using DevHive.Data.Models; using Microsoft.EntityFrameworkCore; namespace DevHive.Data.Repositories { - public class PostRepository : BaseRepository, IPostRepository + public class PostRepository : BaseRepository, IPostRepository { private readonly DevHiveContext _context; public PostRepository(DevHiveContext context) + : base(context) { this._context = context; } #region Create - public async Task AddAsync(Post post) - { - await this._context.Posts - .AddAsync(post); - - return await this.SaveChangesAsync(this._context); - } - public async Task AddCommentAsync(Comment entity) { await this._context.Comments @@ -35,12 +27,6 @@ namespace DevHive.Data.Repositories #endregion #region Read - public async Task GetByIdAsync(Guid id) - { - return await this._context.Posts - .FindAsync(id); - } - public async Task GetPostByIssuerAndTimeCreatedAsync(Guid issuerId, DateTime timeCreated) { return await this._context.Posts @@ -63,14 +49,6 @@ namespace DevHive.Data.Repositories #endregion #region Update - public async Task EditAsync(Post newPost) - { - this._context.Posts - .Update(newPost); - - return await this.SaveChangesAsync(this._context); - } - public async Task EditCommentAsync(Comment newEntity) { this._context.Comments @@ -81,14 +59,6 @@ namespace DevHive.Data.Repositories #endregion #region Delete - public async Task DeleteAsync(Post post) - { - this._context.Posts - .Remove(post); - - return await this.SaveChangesAsync(this._context); - } - public async Task DeleteCommentAsync(Comment entity) { this._context.Comments diff --git a/src/DevHive.Data/Repositories/RoleRepository.cs b/src/DevHive.Data/Repositories/RoleRepository.cs index 25549bf..156792d 100644 --- a/src/DevHive.Data/Repositories/RoleRepository.cs +++ b/src/DevHive.Data/Repositories/RoleRepository.cs @@ -6,32 +6,17 @@ using Microsoft.EntityFrameworkCore; namespace DevHive.Data.Repositories { - public class RoleRepository : BaseRepository, IRoleRepository + public class RoleRepository : BaseRepository, IRoleRepository { private readonly DevHiveContext _context; public RoleRepository(DevHiveContext context) + :base(context) { this._context = context; } - #region Create - public async Task AddAsync(Role entity) - { - await this._context.Roles - .AddAsync(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Read - public async Task GetByIdAsync(Guid id) - { - return await this._context.Roles - .FindAsync(id); - } - public async Task GetByNameAsync(string name) { return await this._context.Roles @@ -39,30 +24,6 @@ namespace DevHive.Data.Repositories } #endregion - #region Update - public async Task EditAsync(Role newEntity) - { - Role role = await this.GetByIdAsync(newEntity.Id); - - this._context - .Entry(role) - .CurrentValues - .SetValues(newEntity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - - #region Delete - public async Task DeleteAsync(Role entity) - { - this._context.Roles - .Remove(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Validations public async Task DoesNameExist(string name) { diff --git a/src/DevHive.Data/Repositories/TechnologyRepository.cs b/src/DevHive.Data/Repositories/TechnologyRepository.cs index 35ee567..83cc7aa 100644 --- a/src/DevHive.Data/Repositories/TechnologyRepository.cs +++ b/src/DevHive.Data/Repositories/TechnologyRepository.cs @@ -1,38 +1,22 @@ using System; using System.Threading.Tasks; -using DevHive.Common.Models.Misc; using DevHive.Data.Interfaces.Repositories; using DevHive.Data.Models; using Microsoft.EntityFrameworkCore; - namespace DevHive.Data.Repositories { - public class TechnologyRepository : BaseRepository, ITechnologyRepository + public class TechnologyRepository : BaseRepository, ITechnologyRepository { private readonly DevHiveContext _context; public TechnologyRepository(DevHiveContext context) + :base(context) { this._context = context; } - #region Create - public async Task AddAsync(Technology entity) - { - await this._context.Technologies - .AddAsync(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Read - public async Task GetByIdAsync(Guid id) - { - return await this._context.Technologies - .FindAsync(id); - } public async Task GetByNameAsync(string technologyName) { return await this._context.Technologies @@ -41,25 +25,6 @@ namespace DevHive.Data.Repositories } #endregion - #region Edit - public async Task EditAsync(Technology newEntity) - { - this._context.Technologies.Update(newEntity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - - #region Delete - public async Task DeleteAsync(Technology entity) - { - this._context.Technologies - .Remove(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Validations public async Task DoesTechnologyNameExistAsync(string technologyName) { diff --git a/src/DevHive.Data/Repositories/UserRepository.cs b/src/DevHive.Data/Repositories/UserRepository.cs index f0c28f1..1511c63 100644 --- a/src/DevHive.Data/Repositories/UserRepository.cs +++ b/src/DevHive.Data/Repositories/UserRepository.cs @@ -8,26 +8,16 @@ using Microsoft.EntityFrameworkCore; namespace DevHive.Data.Repositories { - public class UserRepository : BaseRepository, IUserRepository + public class UserRepository : BaseRepository, IUserRepository { private readonly DevHiveContext _context; public UserRepository(DevHiveContext context) + :base(context) { this._context = context; } - #region Create - - public async Task AddAsync(User entity) - { - await this._context.Users - .AddAsync(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Read public IEnumerable QueryAll() @@ -38,7 +28,7 @@ namespace DevHive.Data.Repositories .AsEnumerable(); } - public async Task GetByIdAsync(Guid id) + public override async Task GetByIdAsync(Guid id) { return await this._context.Users .Include(x => x.Friends) @@ -80,31 +70,6 @@ namespace DevHive.Data.Repositories } #endregion - #region Update - - public async Task EditAsync(User entity) - { - User user = await this._context.Users - .FirstOrDefaultAsync(x => x.Id == entity.Id); - - this._context.Update(user); - this._context.Entry(entity).CurrentValues.SetValues(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - - #region Delete - - public async Task DeleteAsync(User entity) - { - this._context.Users - .Remove(entity); - - return await this.SaveChangesAsync(this._context); - } - #endregion - #region Validations public async Task DoesUserExistAsync(Guid id) -- cgit v1.2.3