improvements

This commit is contained in:
jozsef.b@aycode.com 2023-12-10 14:13:30 +01:00
parent e752965d6f
commit 9c2b6bfb44
14 changed files with 182 additions and 134 deletions

View File

@ -5,7 +5,7 @@ using TIAM.Database.DbContexts;
namespace TIAM.Database.Test
{
[TestClass]
public class DatabaseTest : DatabaseTestModelBase
public class DatabaseTest //: DatabaseTestModelBase<TiamDbContextBase>
{
[TestInitialize]

View File

@ -1,4 +1,5 @@
using AyCode.Database.Tests;
using AyCode.Database.DataLayers;
using AyCode.Database.Tests;
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -10,7 +11,7 @@ using TIAM.Entities.Users;
namespace TIAM.Database.Test
{
[TestClass]
public class UserDalTests : DatabaseTestModelBase
public class UserDalTests : DatabaseTestModelBase<UserDbContext>
{
private Mock<UserDbContext> _mockContext;
private UserDal _userDal;
@ -18,109 +19,143 @@ namespace TIAM.Database.Test
[TestInitialize]
public void TestInitialize()
{
var options = new DbContextOptionsBuilder<UserDbContext>()
.UseInMemoryDatabase(databaseName: "UserDatabase")
.Options;
//var options = new DbContextOptionsBuilder<UserDbContext>()
// .UseInMemoryDatabase(databaseName: "UserDatabase")
// .Options;
_mockContext = new Mock<UserDbContext>(options);
//_mockContext = new Mock<UserDbContext>(options);
var mockSet = new Mock<DbSet<User>>();
_mockContext.Setup(c => c.Users).Returns(mockSet.Object);
//var mockSet = new Mock<DbSet<User>>();
//_mockContext.Setup(c => c.Users).Returns(mockSet.Object);
_userDal = new UserDal(_mockContext.Object);
//_userDal = new UserDal(_mockContext.Object);
_userDal = PooledDal.CreateDal<UserDal>();
}
[TestMethod]
[DataRow("test@tiam.hu")]
public void GetUserByEmail_ReturnsUser_WhenUserExists(string email)
{
//var userDal = PooledDal.CreateDal<UserDal>();
var user = _userDal.GetUserByEmail(email);
Assert.IsNotNull(user);
Assert.AreEqual(email, user.EmailAddress);
}
[TestMethod]
[DataRow("test@tiam.hu")]
public async Task GetUserByEmailAsync_ReturnsUser_WhenUserExists(string email)
{
// Arrange
var user = new User { Email = email };
var users = new[] { user }.AsQueryable();
User? user = null;
//var userDal = PooledDal.CreateDal<UserDal>();
var mockSet = new Mock<DbSet<User>>();
mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
user = await _userDal.GetUserByEmailAsync(email).ConfigureAwait(false);
_mockContext.Setup(c => c.Users).Returns(mockSet.Object);
//user = await _userDal.SessionAsync(ctx => ctx.Users.FirstOrDefault(x => x.EmailAddress == email)).ConfigureAwait(false);
// Act
var result = await _userDal.GetUserByEmailAsync(email);
//await using (var ctx = _userDal.Context)
//{
// user = await ctx.Users.FirstOrDefaultAsync(x => x.EmailAddress == email).ConfigureAwait(false);
//}
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(email, result.Email);
Assert.IsNotNull(user);
Assert.AreEqual(email, user.EmailAddress);
}
[TestMethod]
[DataRow("test@test.hu")]
public async Task GetUserByEmailAsync_ReturnsNull_WhenUserDoesNotExist(string email)
{
// Arrange
var users = new User[0].AsQueryable();
//[TestMethod]
//[DataRow("test@tiam.hu")]
//public async Task GetUserByEmailAsync_ReturnsUser_WhenUserExists(string email)
//{
// // Arrange
// var user = new User { EmailAddress = email };
// var users = new[] { user }.AsQueryable();
var mockSet = new Mock<DbSet<User>>();
mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
// var mockSet = new Mock<DbSet<User>>();
// mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
// mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
// mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
// mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
_mockContext.Setup(c => c.Users).Returns(mockSet.Object);
// _mockContext.Setup(c => c.Users).Returns(mockSet.Object);
// Act
var result = await _userDal.GetUserByEmailAsync(email);
// // Act
// var result = await _userDal.GetUserByEmailAsync(email);
// Assert
Assert.IsNull(result);
}
// // Assert
// Assert.IsNotNull(result);
// Assert.AreEqual(email, result.EmailAddress);
//}
[TestMethod]
[DataRow("test@test.com", "+1234567890", "password")]
public async Task CreateUserAsync_ShouldReturnTrue_WhenUserIsCreated(string email, string phoneNumbr, string password)
{
// Arrange
var user = new User
{
Id = Guid.NewGuid(),
Email = email,
PhoneNumber = phoneNumbr,
Password = password
};
//[TestMethod]
//[DataRow("TEST@TEST.COM")]
//public async Task GetUserByEmailAsync_ReturnsNull_WhenUserDoesNotExist(string email)
//{
// // Arrange
// var users = new User[0].AsQueryable();
var mockSet = new Mock<DbSet<User>>();
_mockContext.Setup(x => x.Users).Returns(mockSet.Object);
_mockContext.Setup(x => x.Users.Add(user)).Returns(() => null);
// var mockSet = new Mock<DbSet<User>>();
// mockSet.As<IQueryable<User>>().Setup(m => m.Provider).Returns(users.Provider);
// mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(users.Expression);
// mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(users.ElementType);
// mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator());
_mockContext.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()))
.ReturnsAsync(1)
.Verifiable();
// _mockContext.Setup(c => c.Users).Returns(mockSet.Object);
// Act
var result = await _userDal.CreateUserAsync(user);
// // Act
// var result = await _userDal.GetUserByEmailAsync(email);
// Assert
Assert.IsTrue(result);
}
// // Assert
// Assert.IsNull(result);
//}
[TestMethod]
[DataRow("test@test.com", "+1234567890", "password")]
public async Task UpdateUserAsync_ShouldUpdateUser(string email, string phoneNumbr, string password)
{
// Arrange
var user = new User(Guid.NewGuid(), email, phoneNumbr, password);
_mockContext.Object.Users.Add(user);
await _mockContext.Object.SaveChangesAsync();
//[TestMethod]
//[DataRow("TEST@TEST.COM", "+1234567890", "password")]
//public async Task CreateUserAsync_ShouldReturnTrue_WhenUserIsCreated(string email, string phoneNumbr, string password)
//{
// // Arrange
// var user = new User
// {
// Id = Guid.NewGuid(),
// EmailAddress = email,
// PhoneNumber = phoneNumbr,
// Password = password
// };
// Act
user.Email = email;
var result = await _userDal.UpdateUserAsync(user);
// var mockSet = new Mock<DbSet<User>>();
// _mockContext.Setup(x => x.Users).Returns(mockSet.Object);
// _mockContext.Setup(x => x.Users.Add(user)).Returns(() => null);
// Assert
Assert.IsTrue(result);
var updatedUser = _mockContext.Object.Users.Single(u => u.Email == user.Email);
Assert.AreEqual(email, updatedUser.Email);
}
// _mockContext.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()))
// .ReturnsAsync(1)
// .Verifiable();
// // Act
// var result = await _userDal.CreateUserAsync(user);
// // Assert
// Assert.IsTrue(result);
//}
//[TestMethod]
//[DataRow("TEST@TEST.COM", "+1234567890", "password")]
//public async Task UpdateUserAsync_ShouldUpdateUser(string email, string phoneNumbr, string password)
//{
// // Arrange
// var user = new User(Guid.NewGuid(), email, phoneNumbr, password);
// _mockContext.Object.Users.Add(user);
// await _mockContext.Object.SaveChangesAsync();
// // Act
// user.EmailAddress = email;
// var result = await _userDal.UpdateUserAsync(user);
// // Assert
// Assert.IsTrue(result);
// var updatedUser = _mockContext.Object.Users.Single(u => u.EmailAddress == user.EmailAddress);
// Assert.AreEqual(email, updatedUser.EmailAddress);
//}
}
}

View File

@ -18,30 +18,30 @@ namespace TIAM.Database.DataLayers.Users
public Task<List<User>> GetUsersAsync()
{
return Ctx.Users.ToListAsync();
return Context.Users.ToListAsync();
}
public Task<User?> GetUserByEmailAsync(string email)
{
Console.WriteLine($"Getting user from db {email}");
var emailLower = email.ToLower();
return Ctx.Users.SingleOrDefaultAsync(x=>x.Email.ToLower() == emailLower);
return Context.Users.SingleOrDefaultAsync(x=>x.EmailAddress.ToLower() == emailLower);
}
public Task<bool> CreateUserAsync(User user)
{
user.Created = DateTime.UtcNow;
user.Modified = DateTime.UtcNow;
Ctx.Users.Add(user);
Console.WriteLine($"Saving user to db {user.Id}, {user.Email}, {user.PhoneNumber}, {user.Password}");
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
Context.Users.Add(user);
Console.WriteLine($"Saving user to db {user.Id}, {user.EmailAddress}, {user.PhoneNumber}, {user.Password}");
return Context.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
public Task<bool> UpdateUserAsync(User user)
{
user.Modified = DateTime.UtcNow;
Ctx.Users.Update(user);
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
Context.Users.Update(user);
return Context.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
}
}

View File

@ -18,37 +18,37 @@ namespace TIAM.Database.DataLayers.Users
public Task<List<AuctionBid>> GetBids()
{
return Ctx.AuctionBids.ToListAsync();
return Context.AuctionBids.ToListAsync();
}
public Task<List<AuctionBid>> GetBidsByEmail(string email)
{
Console.WriteLine($"Getting bid from db {email}");
var emailLower = email.ToLower();
return Ctx.AuctionBids.Where(x => x.Email.ToLower() == emailLower).ToListAsync();
return Context.AuctionBids.Where(x => x.Email.ToLower() == emailLower).ToListAsync();
}
public async Task<AuctionBid?> GetBidById(Guid id)
{
Console.WriteLine($"Getting bid from db {id}");
return Ctx.AuctionBids.FirstOrDefault(x => x.Id == id);
return Context.AuctionBids.FirstOrDefault(x => x.Id == id);
}
public Task<bool> CreateBidAsync(AuctionBid auctionBid)
{
auctionBid.Created = DateTime.UtcNow;
auctionBid.Modified = DateTime.UtcNow;
Ctx.AuctionBids.Add(auctionBid);
Context.AuctionBids.Add(auctionBid);
Console.WriteLine($"Saving user to db {auctionBid.Id}, {auctionBid.Email}, {auctionBid.PhoneNumber}");
return Ctx.SaveChangesAsync().ContinueWith(x => x.Result > 0);
return Context.SaveChangesAsync().ContinueWith(x => x.Result > 0);
}
public Task<bool> UpdateBidAsync(AuctionBid auctionBid)
{
auctionBid.Modified = DateTime.UtcNow;
Ctx.AuctionBids.Update(auctionBid);
return Ctx.SaveChangesAsync().ContinueWith(x => x.Result > 0);
Context.AuctionBids.Update(auctionBid);
return Context.SaveChangesAsync().ContinueWith(x => x.Result > 0);
}
}
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AyCode.Database.DataLayers;
using TIAM.Database.DbContexts;
namespace TIAM.Database.DataLayers;

View File

@ -21,7 +21,7 @@ public class TransferDestinationDal : TiamDalBase<TransferDestinationDbContext>
{
transferDestination.Created = DateTime.UtcNow;
transferDestination.Modified = DateTime.UtcNow;
Ctx.TransferDestinations.Add(transferDestination);
return Ctx.SaveChangesAsync().ContinueWith(x => x.Result > 0);
Context.TransferDestinations.Add(transferDestination);
return Context.SaveChangesAsync().ContinueWith(x => x.Result > 0);
}
}

View File

@ -3,13 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AyCode.Database.DataLayers;
using AyCode.Database.DataLayers.Users;
using AyCode.Entities.Users;
using Microsoft.EntityFrameworkCore;
using TIAM.Database.DbContexts;
using TIAM.Entities.Users;
namespace TIAM.Database.DataLayers.Users
{
public class UserDal : TiamDalBase<UserDbContext>
public class UserDal : UserDalBase<UserDbContext, User, UserTokenBase>
{
public UserDal() : base()
@ -22,62 +25,64 @@ namespace TIAM.Database.DataLayers.Users
public Task<List<User>> GetUsersAsync()
{
return Ctx.Users.ToListAsync();
return Context.Users.ToListAsync();
}
public virtual Task<User?> GetUserByEmailAsync(string email)
{
Console.WriteLine($"Getting user from db {email}");
var emailLower = email.ToLower();
return Ctx.Users.SingleOrDefaultAsync(x=>x.Email.ToLower() == emailLower);
}
//public Task<User?> GetUserByEmailAsync(string email)
//{
// Console.WriteLine($"Getting user from db {email}");
// //var emailLower = email.ToLower();
public virtual Task<User?> GetUserByPhoneNumberAsync(string phoneNumber)
// return Context.GetUserByEmail(email);
// //return Context.Users.SingleOrDefaultAsync(x=>x.Email.ToLower() == emailLower);
//}
public Task<User?> GetUserByPhoneNumberAsync(string phoneNumber)
{
Console.WriteLine($"Getting user from db {phoneNumber}");
var phoneNumberLower = phoneNumber.ToLower();
return Ctx.Users.SingleOrDefaultAsync(x=>x.PhoneNumber.ToLower() == phoneNumberLower);
return Context.Users.SingleOrDefaultAsync(x=>x.PhoneNumber.ToLower() == phoneNumberLower);
}
public virtual Task<User?> GetUserByEmailOrPhoneNumberAsync(string emailOrPhoneNumber)
public Task<User?> GetUserByEmailOrPhoneNumberAsync(string emailOrPhoneNumber)
{
Console.WriteLine($"Getting user from db {emailOrPhoneNumber}");
var emailOrPhoneNumberLower = emailOrPhoneNumber.ToLower();
return Ctx.Users.SingleOrDefaultAsync(x=>x.Email.ToLower() == emailOrPhoneNumberLower || x.PhoneNumber.ToLower() == emailOrPhoneNumberLower);
return Context.Users.SingleOrDefaultAsync(x=>x.EmailAddress.ToLower() == emailOrPhoneNumberLower || x.PhoneNumber.ToLower() == emailOrPhoneNumberLower);
}
//get user by Id
public virtual Task<User?> GetUserByIdAsync(Guid id)
{
Console.WriteLine($"Getting user from db {id}");
return Ctx.Users.SingleOrDefaultAsync(x=>x.Id == id);
return Context.Users.SingleOrDefaultAsync(x=>x.Id == id);
}
public Task<bool> CreateUserAsync(User user)
{
user.Created = DateTime.UtcNow;
user.Modified = DateTime.UtcNow;
Ctx.Users.Add(user);
Console.WriteLine($"Saving user to db {user.Id}, {user.Email}, {user.PhoneNumber}, {user.Password}");
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
Context.Users.Add(user);
Console.WriteLine($"Saving user to db {user.Id}, {user.EmailAddress}, {user.PhoneNumber}, {user.Password}");
return Context.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
public Task<bool> UpdateUserAsyncOld(User user)
{
user.Modified = DateTime.UtcNow;
Ctx.Users.Update(user);
return Ctx.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
Context.Users.Update(user);
return Context.SaveChangesAsync().ContinueWith(x=>x.Result > 0);
}
public Task<bool> UpdateUserAsync(User user)
{
var existingUser = Ctx.Users.FirstOrDefault(u => u.Email == user.Email);
var existingUser = Context.Users.FirstOrDefault(u => u.EmailAddress == user.EmailAddress);
if (existingUser != null)
{
//user.Modified = DateTime.UtcNow; //ezt nem kell megadni, a háttérben ezt magától megcsinálja a DbContextBase - J.
existingUser = user;
Ctx.Users.Update(existingUser);
return Ctx.SaveChangesAsync().ContinueWith(x => x.Result > 0);
Context.Users.Update(existingUser);
return Context.SaveChangesAsync().ContinueWith(x => x.Result > 0);
}
else
{

View File

@ -4,15 +4,19 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AyCode.Database.DbContexts;
using AyCode.Database.DbContexts.Users;
using AyCode.Entities.Users;
using AyCode.Interfaces.Users;
using Microsoft.EntityFrameworkCore;
using TIAM.Entities.TransferDestinations;
using TIAM.Entities.Users;
namespace TIAM.Database.DbContexts
{
public class UserDbContext : TiamDbContextBase
public class UserDbContext : TiamDbContextBase, IUserDbContextBase<User, UserTokenBase>
{
public virtual DbSet<User> Users { get; set; }
public DbSet<UserTokenBase> UserTokens { get; set; }
public UserDbContext() //: this(string.Empty)
{
@ -37,7 +41,5 @@ namespace TIAM.Database.DbContexts
optionsBuilder.EnableDetailedErrors(true);
base.OnConfiguring(optionsBuilder);
}
}
}

View File

@ -51,7 +51,7 @@ namespace TIAMMobilApp.Services
if (dbUser != null)
{
User = new UserSessionModel(dbUser.Id, UserType.User, dbUser.Email, 1);
User = new UserSessionModel(dbUser.Id, UserType.User, dbUser.EmailAddress, 1);
return User;
}
else

View File

@ -11,7 +11,7 @@ else
@foreach (var dest in Users)
{
<p>@dest.Email</p>
<p>@dest.EmailAddress</p>
}
</div>

View File

@ -56,7 +56,7 @@ namespace TIAMWebApp.Client.Services
if (dbUser != null)
{
User = new UserSessionModel(dbUser.Id, UserType.User, dbUser.Email, 1);
User = new UserSessionModel(dbUser.Id, UserType.User, dbUser.EmailAddress, 1);
return User;
}
else

View File

@ -48,7 +48,7 @@ namespace TIAMWebApp.Server.Controllers
[Route("GetTransferDestinations")]
public async Task<IEnumerable<TransferDestination>> GetTransferDestinations()
{
return await _transferDestinationDal.Ctx.TransferDestinations.ToListAsync();
return await _transferDestinationDal.Context.TransferDestinations.ToListAsync();
}
[AllowAnonymous]
@ -56,7 +56,7 @@ namespace TIAMWebApp.Server.Controllers
[Route("GetTransferDestinationByCoordinates")]
public async Task<TransferDestination?> GetTransferDestinationByCoordinates(double latitude, double longitude)
{
return await _transferDestinationDal.Ctx.TransferDestinations.FirstOrDefaultAsync(x => x.Latitude == latitude && x.Longitude == longitude);
return await _transferDestinationDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.Latitude == latitude && x.Longitude == longitude);
}
[AllowAnonymous]
@ -64,7 +64,7 @@ namespace TIAMWebApp.Server.Controllers
[Route("GetTransferDestinationByAddress")]
public async Task<TransferDestination?> GetTransferDestinationByAddress(string address)
{
return await _transferDestinationDal.Ctx.TransferDestinations.FirstOrDefaultAsync(x => x.Address == address);
return await _transferDestinationDal.Context.TransferDestinations.FirstOrDefaultAsync(x => x.Address == address);
}
[AllowAnonymous]
@ -102,7 +102,7 @@ namespace TIAMWebApp.Server.Controllers
Console.WriteLine($"TransferDestination to be created: {Longitude}");
Console.WriteLine($"TransferDestination to be created: {Address}");
//await _transferDestinationDal.Ctx.TransferDestinations.AddAsync(transferDestination);
//await _transferDestinationDal.Context.TransferDestinations.AddAsync(transferDestination);
await _transferDestinationDal.CreateTransferDestinationAsync(transferDestination);
return Ok("yes");
}

View File

@ -131,7 +131,7 @@ namespace TIAMWebApp.Server.Controllers
var claims = new List<Claim>
{
new(ClaimTypes.NameIdentifier, user.Id.ToString()),
new(ClaimTypes.Email, user.Email)
new(ClaimTypes.Email, user.EmailAddress)
};
var tokenDescriptor = new SecurityTokenDescriptor
@ -180,7 +180,7 @@ namespace TIAMWebApp.Server.Controllers
{
//get user from db
dbUser = await _userDal.GetUserByEmailAsync(email.Value);
Console.WriteLine("DbUser email: " + dbUser?.Email);
Console.WriteLine("DbUser email: " + dbUser?.EmailAddress);
}
//mocking - update userModel with new refreshToken so it returns true after the check below

View File

@ -1,4 +1,5 @@
using AyCode.Interfaces.Messages;
using AyCode.Database.DataLayers.Users;
using AyCode.Interfaces.Messages;
using SendGrid;
using SendGrid.Helpers.Mail;
using AyCode.Models.Enums;
@ -51,9 +52,13 @@ namespace TIAMWebApp.Server.Controllers
public async Task<string> SendMailWithSendgrid(EMailMessage message)
{
//példa, így is lehet... - J.
//var senderUser2 = await _userDal.SessionAsync(ctx => ctx.Users.FirstOrDefault(x => x.Id == message.SenderId);
//resolve user!!!
var senderUser = _userDal.Ctx.Users.FirstOrDefault(x => x.Id == message.SenderId);
var receiverUser = _userDal.Ctx.Users.FirstOrDefault(x => x.Id == message.ReceiverId);
var senderUser = _userDal.GetUserById(message.SenderId);
var receiverUser = _userDal.GetUserById(message.ReceiverId);
string apiKey = _configuration["SendGrid:Key"];
var _client = new SendGridClient(apiKey);
var _from = new EmailAddress("", "");
@ -64,10 +69,10 @@ namespace TIAMWebApp.Server.Controllers
}
else
{
_from = new EmailAddress(senderUser.Email, senderUser.Email);
_from = new EmailAddress(senderUser.EmailAddress, senderUser.EmailAddress);
}
var _subject = message.Subject;
var _to = new EmailAddress(receiverUser.Email, receiverUser.Email);
var _to = new EmailAddress(receiverUser.EmailAddress, receiverUser.EmailAddress);
var _plainTextContent = message.Message;
var _htmlContent = message.HtmlContent;
var _msg = MailHelper.CreateSingleEmail(_from, _to, message.Subject, _plainTextContent, _htmlContent);