Clear        


                
                    using CORE.Domain;
using CORE.Models;
using CORE.Services;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using Users.APP.Domain;

namespace Users.APP.Features.Users
{
    // Request properties are created according to the data that
    // will be retrieved from APIs.
    public class UserAddRequest : Record, IRequest<CommandResponse>
    {
        // Copy all the non navigation properties from User entity.
        /*
        ErrorMessage parameter can be set in all data annotations 
        to show custom validation error messages:  
        Example 1: [Required(ErrorMessage = "{0} is required!")] 
        where {0} is the property name which is "UserName".
        Example 2: [StringLength(30, 3, 
        ErrorMessage = "{0} must be minimum {2} maximum {1} characters!")] 
        where {0} is the property name which is "UserName", {1} is the 
        first parameter which is 30 and {2} is the second parameter 
        which is 3.
        */
        // UserName is required and can be minimum 3 maximum 30 characters.
        [Required(ErrorMessage = "{0} is required!")]
        [StringLength(30, MinimumLength = 3,
            ErrorMessage = "{0} must be minimum {2} maximum {1} characters!")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "{0} is required!")]
        [StringLength(15, MinimumLength = 3,
            ErrorMessage = "{0} must be minimum {2} maximum {1} characters!")]
        public string Password { get; set; }

        [StringLength(50, ErrorMessage = "{0} must be maximum {1} characters!")]
        public string FirstName { get; set; }

        [StringLength(50, ErrorMessage = "{0} must be maximum {1} characters!")]
        public string LastName { get; set; }

        public Genders Gender { get; set; }

        public DateTime? BirthDate { get; set; }

        // We don't need to get the RegistrationDate value from the client
        // since it will be assigned automatically in the handler.

        // Minimum value can be 0, maximum value can be 5.
        /*
        The type changed from double to double? to be able to use [Required] 
        attribute. If the type is double, the default value will be 0 and 
        the validation will always be successful even if no value is assigned.
        */
        [Required(ErrorMessage = "{0} is required!")]
        [Range(0, 5, ErrorMessage = "{0} must be between {1} and {2}!")]
        public double? Score { get; set; }

        // We don't need to get the IsOnline value from the client
        // since it will be assigned automatically during token
        // authentication.



        // Modify (1 to many) or add (many to many) the relationship properties.
        /* 
        The type changed from int to int? to be able to use [Required] attribute. 
        If the type is int, the default value will be 0 and the validation will 
        always be successful even if no value is assigned.
        */
        // For users-status one to many relationship.
        [Required(ErrorMessage = "{0} is required!")]
        public int? StatusId { get; set; }

        // Required may not be defined if a user may not have a role.
        // For users-roles many to many relationship.
        [Required(ErrorMessage = "At least one role is required!")]
        public List<int> RoleIds { get; set; }
    }

    // UserAddHandler inherits the DbService class for User entity type,
    // therefore User entity database operations of the DbService
    // class can be used in this class.
    // UserAddHandler also implements the Mediator IRequestHandler
    // interface for UserAddRequest and CommandResponse types,
    // therefore IRequestHandler interface's Handle method
    // definition can be implemented for types UserAddRequest and
    // CommandResponse in this class, which will be used by
    // the related controller's action.
    public class UserAddHandler : DbService<User>, 
        IRequestHandler<UserAddRequest, CommandResponse>
    {
        // Constructor that passes the injected DbContext instance
        // to the DbService base class constructor.
        public UserAddHandler(DbContext db) : base(db)
        {
        }

        // Checks whether the user with the same trimmed and
        // case sensitive user name exists in the Users database table
        // first. If it doesn't exist, inserts the User entity
        // mapped from the UserAddRequest instance to the Users
        // database table.
        public async Task<CommandResponse> Handle(
            UserAddRequest request, CancellationToken cancellationToken)
        {
            if (await DbQuery().AnyAsync(u =>
                u.UserName == request.UserName.Trim(), cancellationToken
            //&& u.BirthDate == request.BirthDate
            // One or many conditions can be used by && (and), || (or)
            // and ! (not) operators.
            ))
                return Error("User with the same user name exists!");
            // u: User entity delegate.
            // Trim method removes white space characters in the
            // beginning and at the end.

            // Create a new User entity instance from the
            // UserAddRequest instance then insert the entity in the
            // Users database table (third save default parameter
            // of the DbAddAsync method is true therefore changes of the
            // DbSets are commited to the related database tables).
            var userEntity = new User
            {
                UserName = request.UserName.Trim(),
                Password = request.Password.Trim(),
                FirstName = request.FirstName?.Trim(),
                // Since request.FirstName may be null, ? is used after
                // meaning that if request.FirstName is null, assign
                // null to the User entity's FirstName property else
                // assign the trimmed value of request.FirstName.
                LastName = request.LastName?.Trim(),
                // Since request.LastName may be null, ? is used after
                // meaning that if request.LastName is null, assign
                // null to the User entity's LastName property else
                // assign the trimmed value of request.LastName.
                RegistrationDate = DateTime.Now,
                BirthDate = request.BirthDate,
                Gender = request.Gender,
                Score = request.Score ?? 0,
                StatusId = request.StatusId ?? 0,
                // ??: Null coalescing operator: If request.StatusId is
                // null assign 0 else assign request.StatusId value to the
                // User entity StatusId property. request.StatusId.Value
                // may also be used since request.StatusId is required. 
                // Same for request.Score.
                RoleIds = request.RoleIds
            };
            await DbAddAsync(userEntity, cancellationToken);

            // Entity's Id value will be updated by the database after insert.
            return Success(userEntity.Id, "User created successfully.");
        }
    }
}