Promact/slack-erp-custom-integration-mvc

View on GitHub
Slack.Automation/Promact.Core.Repository/SlackRepository/SlackRepository.cs

Summary

Maintainability
F
1 wk
Test Coverage
using Promact.Core.Repository.LeaveRequestRepository;
using Promact.Core.Repository.OauthCallsRepository;
using Promact.Erp.DomainModel.ApplicationClass;
using Promact.Erp.DomainModel.ApplicationClass.SlackRequestAndResponse;
using Promact.Erp.DomainModel.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Promact.Core.Repository.Client;
using Promact.Core.Repository.AttachmentRepository;
using System.Linq;
using System.Globalization;
using Promact.Erp.DomainModel.DataRepository;
using System.Net.Mail;
using Promact.Erp.Util.StringConstants;
using Promact.Core.Repository.SlackUserRepository;
using System.Threading;
using Promact.Core.Repository.EmailServiceTemplateRepository;
using Promact.Erp.Util.Email;
using Promact.Erp.Util.ExceptionHandler;
using NLog;

namespace Promact.Core.Repository.SlackRepository
{
    public class SlackRepository : ISlackRepository
    {
        #region Private Variable
        private readonly IOauthCallsRepository _oauthCallsRepository;
        private readonly ISlackUserRepository _slackUserRepository;
        private readonly ILeaveRequestRepository _leaveRepository;
        private readonly IClient _clientRepository;
        private readonly IStringConstantRepository _stringConstant;
        private readonly IAttachmentRepository _attachmentRepository;
        private readonly IRepository<ApplicationUser> _userManagerRepository;
        string replyText = null;
        private readonly IRepository<IncomingWebHook> _incomingWebHookRepository;
        private readonly IEmailServiceTemplateRepository _emailTemplateRepository;
        private readonly IEmailService _emailService;
        private readonly ILogger _logger;
        #endregion

        #region Constructor
        public SlackRepository(ILeaveRequestRepository leaveRepository, IOauthCallsRepository oauthCallsRepository,
            ISlackUserRepository slackUserRepository, IClient clientRepository, IStringConstantRepository stringConstant,
            IAttachmentRepository attachmentRepository, IRepository<ApplicationUser> userManagerRepository,
            IRepository<IncomingWebHook> incomingWebHookRepository, IEmailServiceTemplateRepository emailTemplateRepository,
            IEmailService emailService)
        {
            _oauthCallsRepository = oauthCallsRepository;
            _leaveRepository = leaveRepository;
            _clientRepository = clientRepository;
            _stringConstant = stringConstant;
            _attachmentRepository = attachmentRepository;
            _userManagerRepository = userManagerRepository;
            _slackUserRepository = slackUserRepository;
            _incomingWebHookRepository = incomingWebHookRepository;
            _emailTemplateRepository = emailTemplateRepository;
            _emailService = emailService;
            _logger = LogManager.GetLogger("SlackRepository");
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Method to get leave Updated from slack button response
        /// </summary>
        /// <param name="leaveResponse">leave update response from slack</param>
        public async Task UpdateLeaveAsync(SlashChatUpdateResponse leaveResponse)
        {
            try
            {
                _logger.Debug("UpdateLeaveAsync Leave update method");
                // method to get leave by its id
                LeaveRequest leave = await _leaveRepository.LeaveByIdAsync(Convert.ToInt32(leaveResponse.CallbackId));
                _logger.Debug("UpdateLeaveAsync leave applied by : " + leave.EmployeeId);
                ApplicationUser user = await _userManagerRepository.FirstOrDefaultAsync(x => x.Id == leave.EmployeeId);
                _logger.Debug("UpdateLeaveAsync User name : " + user.UserName);
                SlackUserDetailAc slackUser = await _slackUserRepository.GetByIdAsync(user.SlackUserId);
                _logger.Debug("UpdateLeaveAsync User slack name : " + slackUser.Name);
                ApplicationUser updaterUser = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == leaveResponse.User.Id);
                if (updaterUser != null)
                {
                    _logger.Debug("UpdateLeaveAsync User want to update the leave : " + updaterUser.UserName);
                    // only pending status can be modified
                    if (leave.Status == Condition.Pending)
                    {
                        if (leaveResponse.Actions[0].Value == _stringConstant.Approved)
                        {
                            leave.Status = Condition.Approved;
                        }
                        else
                        {
                            leave.Status = Condition.Rejected;
                        }
                        await _leaveRepository.UpdateLeaveAsync(leave);
                        _logger.Debug("UpdateLeaveAsync leave updated successfully");
                        _logger.Debug("Leave details : " + leave.ToString());
                        replyText = string.Format(_stringConstant.CasualLeaveUpdateMessageForUser,
                                    leave.Id, leave.FromDate.ToShortDateString(), leave.EndDate.Value.ToShortDateString(),
                                    leave.Reason, leave.Status, leaveResponse.User.Name);
                        _logger.Debug("Reply text to user : " + replyText);
                        IncomingWebHook incomingWebHook = await _incomingWebHookRepository.FirstOrDefaultAsync(x => x.UserId == slackUser.UserId);
                        _logger.Debug("UpdateLeaveAsync user incoming webhook is null : " + string.IsNullOrEmpty(incomingWebHook.IncomingWebHookUrl));
                        // Used to send slack message to the user about leave updation
                        _logger.Debug("UpdateLeaveAsync Client repository - UpdateMessageAsync");
                        await _clientRepository.UpdateMessageAsync(incomingWebHook.IncomingWebHookUrl, replyText);
                        _logger.Debug("Creating Email object");
                        // Used to send email to the user about leave updation
                        EmailApplication email = new EmailApplication();
                        email.To = new List<string>();
                        email.Body = _emailTemplateRepository.EmailServiceTemplateLeaveUpdate(leave);
                        _logger.Debug("Email body is null : " + email.Body);
                        email.From = updaterUser.Email;
                        _logger.Debug("Email from : " + email.From);
                        email.To.Add(user.Email);
                        _logger.Debug("Email from : " + email.To);
                        email.Subject = string.Format(_stringConstant.LeaveUpdateEmailStringFormat, _stringConstant.Leave, leave.Status);
                        replyText = string.Format(_stringConstant.ReplyTextForUpdateLeave, leave.Status, slackUser.Name,
                        leave.FromDate.ToShortDateString(), leave.EndDate.Value.ToShortDateString(), leave.Reason,
                        leave.RejoinDate.Value.ToShortDateString());
                        _logger.Debug("Reply text to updator : " + replyText);
                        _logger.Debug("UpdateLeaveAsync Email sending");
                        _emailService.Send(email);
                        _logger.Debug("UpdateLeaveAsync Email successfully send");
                    }
                    else
                    {
                        _logger.Debug("UpdateLeaveAsync leave already updated");
                        replyText = string.Format(_stringConstant.AlreadyUpdatedMessage, leave.Status);
                    }
                }
                else
                    replyText = _stringConstant.YouAreNotInExistInOAuthServer;
            }
            catch (SmtpException ex)
            {
                replyText += string.Format(_stringConstant.ReplyTextForSMTPExceptionErrorMessage,
                    _stringConstant.ErrorWhileSendingEmail, ex.Message.ToString());
            }
            _logger.Debug("UpdateLeaveAsync Client Repository - SendMessageAsync");
            // updating leave applied text of slack
            await _clientRepository.SendMessageAsync(leaveResponse.ResponseUrl, replyText);
        }

        /// <summary>
        /// Method to operate leave slack command
        /// </summary>
        /// <param name="leave">slash command object</param>
        public async Task LeaveRequestAsync(SlashCommand leave)
        {
            SlackAction actionType;
            // method to convert slash command to list of string
            List<string> slackText = _attachmentRepository.SlackText(leave.Text);
            // to get user details by slack user name
            ApplicationUser user = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == leave.UserId);
            if (user != null)
            {
                _logger.Debug("LeaveRequestAsync leave request user name : " + user.UserName);
                IncomingWebHook incomingWebHook = await _incomingWebHookRepository.FirstOrDefaultAsync(x => x.UserId == user.SlackUserId);
                if (incomingWebHook != null)
                {
                    _logger.Debug("LeaveRequestAsync leave request user incoming webhook is null : " + incomingWebHook.IncomingWebHookUrl);
                    leave.Text.ToLower();
                    // getting access token of user of promact oauth server
                    string accessToken = await _attachmentRepository.UserAccessTokenAsync(user.UserName);
                    // checking whether string ca convert to Slack Action or not, if true then further process will be conduct
                    bool actionConvertorResult = Enum.TryParse(slackText[0], out actionType);
                    if (actionConvertorResult)
                    {
                        switch (actionType)
                        {
                            case SlackAction.apply:
                                replyText = await LeaveApplyAsync(slackText, leave, accessToken, user.Id);
                                break;
                            case SlackAction.list:
                                replyText = await SlackLeaveListAsync(slackText, leave, accessToken);
                                break;
                            case SlackAction.cancel:
                                replyText = await SlackLeaveCancelAsync(slackText, leave, accessToken);
                                break;
                            case SlackAction.status:
                                replyText = await SlackLeaveStatusAsync(slackText, leave, accessToken);
                                break;
                            case SlackAction.balance:
                                replyText = await SlackLeaveBalanceAsync(leave, accessToken);
                                break;
                            case SlackAction.update:
                                replyText = await UpdateSickLeaveAsync(slackText, user, accessToken);
                                break;
                            default:
                                replyText = SlackLeaveHelp(leave);
                                break;
                        }
                    }
                    else
                        // if error in converting then user will get message to enter proper action command
                        replyText = _stringConstant.RequestToEnterProperAction;
                }
                else
                    replyText = _stringConstant.RequestToAddSlackApp;
            }
            else
                // if user doesn't exist then will get message of user doesn't exist and ask to externally logic from Oauth server
                replyText = _stringConstant.SorryYouCannotApplyLeave;
            _logger.Debug("LeaveRequestAsync Client Repository - SendMessageAsync");
            await _clientRepository.SendMessageAsync(leave.ResponseUrl, replyText);
        }

        /// <summary>
        /// Method to send error message to user od slack
        /// </summary>
        /// <param name="errorMessage">Message to send</param>
        /// <param name="responseUrl">Incoming webhook url</param>
        public async Task ErrorAsync(string responseUrl, string errorMessage)
        {
            // if something error will happen user will get this message
            var replyText = string.Format(_stringConstant.FirstSecondAndThirdIndexStringFormat, _stringConstant.Star, errorMessage, _stringConstant.Star);
            await _clientRepository.SendMessageAsync(responseUrl, replyText);
        }
        #endregion

        #region Private Methods


        /// <summary>
        /// Method to apply leave
        /// </summary>
        /// <param name="slackRequest">list of string contain leave slash command parameters</param>
        /// <param name="leave">leave slash command</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> LeaveApplyAsync(List<string> slackRequest, SlashCommand leave, string accessToken, string userId)
        {
            try
            {
                LeaveType leaveType;
                DateTime startDate, endDate, reJoinDate;
                User user = new User();
                string dateFormat = Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
                _logger.Debug("LeaveApplyAsync Date format of leave command : " + dateFormat);
                _logger.Debug("LeaveApplyAsync Current Culture info : " + Thread.CurrentThread.CurrentCulture.DisplayName);
                // checking whether string can convert to date of independent culture or not, if return true then further process will be conduct
                bool startDateConvertorResult = DateTime.TryParseExact(slackRequest[3], dateFormat, CultureInfo.InvariantCulture,
                    DateTimeStyles.None, out startDate);
                if (startDateConvertorResult)
                {
                    user = await _oauthCallsRepository.GetUserByUserIdAsync(userId, accessToken);
                    LeaveRequest leaveRequest = new LeaveRequest();
                    // Method to check leave's start date is not beyond today. Back date checking
                    bool validStartDate = LeaveStartDateValid(startDate);
                    if (validStartDate)
                    {
                        // checking whether string can convert to leave type or not, if return true then further process will be conduct
                        bool leaveTypeConvertorResult = Enum.TryParse(slackRequest[1], out leaveType);
                        if (leaveTypeConvertorResult)
                        {
                            // converting string to leave type of indian culture
                            switch (leaveType)
                            {
                                case LeaveType.cl:
                                    {
                                        _logger.Debug("LeaveApplyAsync Casual leave");
                                        // checking whether string can convert to date of indian culture or not, if return true then further process will be conduct
                                        bool endDateConvertorResult = DateTime.TryParseExact(slackRequest[4], dateFormat,
                                            CultureInfo.InvariantCulture, DateTimeStyles.None, out endDate);
                                        bool reJoinDateConvertorResult = DateTime.TryParseExact(slackRequest[5], dateFormat,
                                            CultureInfo.InvariantCulture, DateTimeStyles.None, out reJoinDate);
                                        if (endDateConvertorResult && reJoinDateConvertorResult)
                                        {
                                            // Method to check leave's end date is not beyond start date and re-join date is not beyond end date
                                            bool validDate = ValidDateTimeForLeave(startDate, endDate, reJoinDate);
                                            if (validDate)
                                            {
                                                // get user details from oAuth server
                                                leaveRequest.EndDate = endDate;
                                                leaveRequest.RejoinDate = reJoinDate;
                                                leaveRequest.Status = Condition.Pending;
                                                leaveRequest.Type = leaveType;
                                                leaveRequest.Reason = slackRequest[2];
                                                leaveRequest.FromDate = startDate;
                                                leaveRequest.CreatedOn = DateTime.UtcNow;
                                                // if user doesn't exist in OAuth server then user can't apply leave
                                                if (user.Id != null)
                                                {
                                                    _logger.Debug("LeaveApplyAsync leave apply user name : " + user.UserName);
                                                    // Method to check more than one leave cannot be applied on that date
                                                    validDate = await LeaveDateDuplicate(user.Id, startDate, endDate);
                                                    if (!validDate)
                                                    {
                                                        leaveRequest.EmployeeId = user.Id;
                                                        await _leaveRepository.ApplyLeaveAsync(leaveRequest);
                                                        _logger.Debug("LeaveApplyAsync Leave applied sucessfully");
                                                        replyText = _attachmentRepository.ReplyText(leave.Username, leaveRequest);
                                                        _logger.Debug("LeaveApplyAsync Client Repository - SendMessageWithAttachmentIncomingWebhookAsync");
                                                        // method to send slack notification and email to team leaders and management
                                                        await _clientRepository.SendMessageWithAttachmentIncomingWebhookAsync(leaveRequest,
                                                            accessToken, replyText, user.Id);
                                                    }
                                                    else
                                                        replyText = _stringConstant.LeaveAlreadyExistOnSameDate;
                                                }
                                                else
                                                    // if user doesn't exist in OAuth server then user can't apply leave, will get this message
                                                    replyText = _stringConstant.SorryYouCannotApplyLeave;
                                            }
                                            else
                                                replyText = _stringConstant.InValidDateErrorMessage;
                                        }
                                        else
                                            // if date is not proper than date format error message will be send to user
                                            replyText = string.Format(_stringConstant.DateFormatErrorMessage, dateFormat);
                                    }
                                    break;
                                case LeaveType.sl:
                                    {
                                        _logger.Debug("LeaveApplyAsync Sick leave");
                                        bool isAdmin = false;
                                        User newUser = new User();
                                        if (slackRequest.Count > 4)
                                        {
                                            isAdmin = await _oauthCallsRepository.UserIsAdminAsync(userId, accessToken);
                                            _logger.Debug("LeaveApplyAsync User is admin : " + isAdmin);
                                            if (isAdmin)
                                            {
                                                _logger.Debug("LeaveApplyAsync Sick Leave applying for other");
                                                SlackUserDetailAc slackUser = await _slackUserRepository.GetBySlackNameAsync(slackRequest[4]);
                                                // get user details from oAuth server for other user
                                                var newUserDetails = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == slackUser.UserId);
                                                newUser = await _oauthCallsRepository.GetUserByUserIdAsync(newUserDetails.Id, accessToken);
                                            }
                                            else
                                                replyText = _stringConstant.AdminErrorMessageApplySickLeave;
                                        }
                                        else
                                        {
                                            _logger.Debug("LeaveApplyAsync Sick Leave applying for own");
                                            // get user details from oAuth server for own
                                            newUser = await _oauthCallsRepository.GetUserByUserIdAsync(userId, accessToken);
                                            leaveRequest.EndDate = startDate;
                                            leaveRequest.RejoinDate = startDate.AddDays(1);
                                        }
                                        leaveRequest.Status = Condition.Approved;
                                        leaveRequest.Type = leaveType;
                                        leaveRequest.Reason = slackRequest[2];
                                        leaveRequest.FromDate = startDate;
                                        leaveRequest.CreatedOn = DateTime.UtcNow;
                                        // if user doesn't exist in OAuth server then user can't apply leave
                                        if (newUser.Id != null)
                                        {
                                            // Method to check more than one leave cannot be applied on that date
                                            bool validDate = await LeaveDateDuplicate(newUser.Id, startDate, null);
                                            if (!validDate)
                                            {
                                                leaveRequest.EmployeeId = newUser.Id;
                                                await _leaveRepository.ApplyLeaveAsync(leaveRequest);
                                                _logger.Debug("LeaveApplyAsync Leave applied successfully");
                                                replyText = _attachmentRepository.ReplyTextSick(newUser.FirstName, leaveRequest);
                                                _logger.Debug("LeaveApplyAsync Client Repository - SendMessageWithoutButtonAttachmentIncomingWebhookAsync");
                                                await _clientRepository.SendMessageWithoutButtonAttachmentIncomingWebhookAsync(leaveRequest,
                                                    accessToken, replyText, newUser.Id);
                                                if (isAdmin)
                                                {
                                                    _logger.Debug("LeaveApplyAsync Client Repository - SendSickLeaveMessageToUserIncomingWebhookAsync");
                                                    await _clientRepository.SendSickLeaveMessageToUserIncomingWebhookAsync(leaveRequest,
                                                        user.Email, replyText, newUser);
                                                }
                                            }
                                            else
                                                replyText = _stringConstant.LeaveAlreadyExistOnSameDate;
                                        }
                                        else
                                            // if user doesn't exist in OAuth server then user can't apply leave, will get this message
                                            replyText += _stringConstant.SorryYouCannotApplyLeave;
                                    }
                                    break;
                            }
                        }
                        else
                            // if leave type is not proper than not of leave type format error message will be send to user
                            replyText = _stringConstant.NotTypeOfLeave;
                    }
                    else
                        replyText = _stringConstant.BackDateErrorMessage;
                }
                else
                    // if date is not proper than date format error message will be send to user
                    replyText = string.Format(_stringConstant.DateFormatErrorMessage, dateFormat);
            }
            catch (SmtpException ex)
            {
                // error message will be send to email. But leave will be applied
                replyText = string.Format(_stringConstant.ReplyTextForSMTPExceptionErrorMessage,
                    _stringConstant.ErrorWhileSendingEmail, ex.Message.ToString());
            }
            return replyText;
        }

        /// <summary>
        /// Method to get Employee Id from its slackUserId and from its employeeId, to get list of leave
        /// </summary>
        /// <param name="userId">User's used Id</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> LeavesListBySlackUserIdAsync(string userId, string accessToken)
        {
            // get user details from oAuth server
            User user = await _oauthCallsRepository.GetUserByUserIdAsync(userId, accessToken);
            _logger.Debug("LeavesListBySlackUserIdAsync user name : " + user.UserName);
            // get list of leave from user Id
            IEnumerable<LeaveRequest> leaveList = _leaveRepository.LeaveListByUserId(user.Id);
            _logger.Debug("LeavesListBySlackUserIdAsync leave list count : " + leaveList.Count());
            // if leave exit then further will get list in string else 
            if (leaveList.Count() != 0)
            {
                foreach (var leave in leaveList)
                {
                    if (leave.Type == LeaveType.cl)
                    {
                        replyText += string.Format(_stringConstant.ReplyTextForCasualLeaveList, leave.Id,
                            leave.Reason, leave.FromDate.ToShortDateString(),
                            leave.EndDate.Value.ToShortDateString(), leave.Status,
                            Environment.NewLine);
                    }
                    else
                    {
                        replyText += string.Format(_stringConstant.ReplyTextForSickLeaveList, leave.Id,
                            leave.Reason, leave.FromDate.ToShortDateString(), leave.Status,
                            Environment.NewLine);
                    }
                }
            }
            else
            {
                // if leave doesnot exit for that user
                replyText = _stringConstant.SlashCommandLeaveStatusErrorMessage;
            }
            return replyText;
        }

        /// <summary>
        /// Method to Cancel leave, only allowed to the applier of the leave to cancel the leave
        /// </summary>
        /// <param name="leaveId">leave request Id</param>
        /// <param name="userId">User's user Id</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> LeaveCancelByIdAsync(int leaveId, string userId, string accessToken)
        {
            // get user details from oAuth server
            User user = await _oauthCallsRepository.GetUserByUserIdAsync(userId, accessToken);
            _logger.Debug("LeaveCancelByIdAsync user name : " + user.UserName);
            LeaveRequest leave = await _leaveRepository.LeaveByIdAsync(leaveId);
            _logger.Debug("LeaveCancelByIdAsync leave employee id : " + leave.EmployeeId);
            // only authorize user of leave is allowed to cancel there leave
            if (user.Id == leave.EmployeeId)
            {
                // method to cancel leave
                LeaveRequest updateLeave = await _leaveRepository.CancelLeaveAsync(leaveId);
                _logger.Debug("LeaveCancelByIdAsync leave cancel sucessfully");
                replyText = string.Format(_stringConstant.ReplyTextForCancelLeave, updateLeave.Id,
                    updateLeave.FromDate.ToShortDateString(), updateLeave.EndDate.Value.ToShortDateString(),
                    updateLeave.Status);
            }
            else
            {
                // if leave doesn't exist or unauthorize trespass try to do
                replyText = _stringConstant.ReplyTextForErrorInCancelLeave;
            }
            return replyText;
        }

        /// <summary>
        /// Method to get Employee Id from its userName and from its employeeId, to get last leave status
        /// </summary>
        /// <param name="userId">User's user Id</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> LeaveStatusBySlackUserIdAsync(string userId, string accessToken)
        {
            // get user details from oAuth server
            User user = await _oauthCallsRepository.GetUserByUserIdAsync(userId, accessToken);
            _logger.Debug("LeaveStatusBySlackUserIdAsync user name : " + user.UserName);
            try
            {
                // get only last leave of the user
                LeaveRequest leave = _leaveRepository.LeaveListStatusByUserId(user.Id);
                if (leave.Type == LeaveType.cl)
                {
                    replyText = string.Format(_stringConstant.ReplyTextForCasualLeaveStatus, leave.Id,
                        leave.FromDate.ToShortDateString(), leave.EndDate.Value.ToShortDateString(),
                        leave.Reason, leave.Status);
                }
                else
                {
                    replyText = string.Format(_stringConstant.ReplyTextForSickLeaveStatus, leave.Id,
                        leave.FromDate.ToShortDateString(), leave.Reason, leave.Status);
                }
            }
            catch (LeaveNotFoundForUser)
            {
                // if leave doesn't exist 
                replyText = _stringConstant.SlashCommandLeaveStatusErrorMessage;
            }
            return replyText;
        }

        /// <summary>
        /// Method to Get Leave List on slack
        /// </summary>
        /// <param name="slackText">list of string contain leave slash command parameter</param>
        /// <param name="leave">leave slash command</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> SlackLeaveListAsync(List<string> slackText, SlashCommand leave, string accessToken)
        {
            // if slackText count is more then 1 then its means that user want to get leave list of someone else
            if (slackText.Count > 1)
            {
                // other user slack user name
                SlackUserDetailAc slackUser = await _slackUserRepository.GetBySlackNameAsync(slackText[1]);
                if (slackUser != null)
                {
                    var user = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == slackUser.UserId);
                    _logger.Debug("SlackLeaveListAsync user name other : " + user.UserName);
                    // leave list of other user 
                    replyText = await LeavesListBySlackUserIdAsync(user.Id, accessToken);
                }
                else
                    replyText = string.Format(_stringConstant.UserDetailsNotFound, slackText[1]);
            }
            else
            {
                var user = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == leave.UserId);
                _logger.Debug("SlackLeaveListAsync user name own : " + user.UserName);
                // leave list of own
                replyText = await LeavesListBySlackUserIdAsync(user.Id, accessToken);
            }
            return replyText;
        }

        /// <summary>
        /// Method to cancel leave by its Id from slack
        /// </summary>
        /// <param name="slackText">list of string contain leave slash command parameter</param>
        /// <param name="leave">leave slash command</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> SlackLeaveCancelAsync(List<string> slackText, SlashCommand leave, string accessToken)
        {
            int leaveId;
            // checking whether string can be convert to integer or not, true then only further process will be conduct
            bool leaveIdConvertorResult = int.TryParse(slackText[1], out leaveId);
            if (leaveIdConvertorResult)
            {
                var user = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == leave.UserId);
                _logger.Debug("SlackLeaveCancelAsync user name : " + user.UserName);
                // method to cancel leave by its id
                replyText = await LeaveCancelByIdAsync(leaveId, user.Id, accessToken);
            }
            else
                // if string converting to integer return false then user will get cancel command error message
                replyText = _stringConstant.SlashCommandLeaveCancelErrorMessage;
            return replyText;
        }

        /// <summary>
        /// Method to get last leave status and details on slack
        /// </summary>
        /// <param name="slackText">list of string contain leave slash command parameter</param>
        /// <param name="leave">leave slash command</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> SlackLeaveStatusAsync(List<string> slackText, SlashCommand leave, string accessToken)
        {
            // if slackText count is more then 1 then its means that user want to get leave list of someone else
            if (slackText.Count > 1)
            {
                // other user slack user name
                SlackUserDetailAc slackUser = await _slackUserRepository.GetBySlackNameAsync(slackText[1]);
                if (slackUser != null)
                {
                    var user = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == slackUser.UserId);
                    _logger.Debug("SlackLeaveStatusAsync user name other : " + user.UserName);
                    // last leave details of other user 
                    replyText = await LeaveStatusBySlackUserIdAsync(user.Id, accessToken);
                }
                else
                    replyText = string.Format(_stringConstant.UserDetailsNotFound, slackText[1]);
            }
            else
            {
                var user = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == leave.UserId);
                _logger.Debug("SlackLeaveStatusAsync user name own : " + user.UserName);
                // last leave details of own
                replyText = await LeaveStatusBySlackUserIdAsync(user.Id, accessToken);
            }
            return replyText;
        }


        /// <summary>
        /// Method to check leave Balance from slack
        /// </summary>
        /// <param name="leave">leave slash command</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> SlackLeaveBalanceAsync(SlashCommand leave, string accessToken)
        {
            var userDetails = await _userManagerRepository.FirstOrDefaultAsync(x => x.SlackUserId == leave.UserId);
            // get user details from oAuth server
            User user = await _oauthCallsRepository.GetUserByUserIdAsync(userDetails.Id, accessToken);
            if (user.Id != null)
            {
                _logger.Debug("SlackLeaveBalanceAsync user name : " + user.UserName);
                // get user leave allowed details from oAuth server
                LeaveAllowed allowedLeave = await _oauthCallsRepository.AllowedLeave(user.Id, accessToken);
                // method to get user's number of leave taken
                LeaveAllowed leaveTaken = _leaveRepository.NumberOfLeaveTaken(user.Id);
                double casualLeaveTaken = leaveTaken.CasualLeave;
                double sickLeaveTaken = leaveTaken.SickLeave;
                double casualLeaveLeft = allowedLeave.CasualLeave - casualLeaveTaken;
                double sickLeaveLeft = allowedLeave.SickLeave - sickLeaveTaken;
                replyText = string.Format(_stringConstant.ReplyTextForCasualLeaveBalance, casualLeaveTaken,
                    allowedLeave.CasualLeave, Environment.NewLine, casualLeaveLeft);
                replyText += string.Format(_stringConstant.ReplyTextForSickLeaveBalance, sickLeaveTaken,
                    allowedLeave.SickLeave, Environment.NewLine, sickLeaveLeft);
            }
            else
            {
                // if user doesn't exist in Oauth server
                replyText = _stringConstant.LeaveNoUserErrorMessage;
            }
            return replyText;
        }

        /// <summary>
        /// Method for gettin help on slack regards Leave slash command
        /// </summary>
        /// <param name="leave">list of string contain leave slash command parameter</param>
        /// <returns>Reply text to be send</returns>
        private string SlackLeaveHelp(SlashCommand leave)
        {
            string replyText = _stringConstant.SlackHelpMessage;
            return replyText;
        }

        /// <summary>
        /// Method to update sick leave, only admin allowed
        /// </summary>
        /// <param name="slackText">list of string contain leave slash command parameter</param>
        /// <param name="user">User details</param>
        /// <param name="accessToken">User's access token</param>
        /// <returns>Reply text to be send</returns>
        private async Task<string> UpdateSickLeaveAsync(List<string> slackText, ApplicationUser user, string accessToken)
        {
            // checking from oAuth whether user is Admin or not
            bool isAdmin = await _oauthCallsRepository.UserIsAdminAsync(user.Id, accessToken);
            _logger.Debug("UpdateSickLeaveAsync user is admin : " + isAdmin);
            if (isAdmin)
            {
                int leaveId;
                DateTime endDate, reJoinDate;
                // checking whether string can be convert to integer or not, true then only further process will be conduct
                bool leaveIdConvertorResult = int.TryParse(slackText[1], out leaveId);
                if (leaveIdConvertorResult)
                {
                    LeaveRequest leave = await _leaveRepository.LeaveByIdAsync(leaveId);
                    if (leave != null && leave.Type == LeaveType.sl)
                    {
                        _logger.Debug("UpdateSickLeaveAsync Leave employee id : " + leave.EmployeeId);
                        string dateFormat = Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
                        // checking whether string can convert to date of indian culture or not, if return true then further process will be conduct
                        bool endDateConvertorResult = DateTime.TryParseExact(slackText[2], dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out endDate);
                        bool reJoinDateConvertorResult = DateTime.TryParseExact(slackText[3], dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out reJoinDate);
                        if (endDateConvertorResult && reJoinDateConvertorResult)
                        {
                            User newUser = await _oauthCallsRepository.GetUserByUserIdAsync(leave.EmployeeId, accessToken);
                            leave.EndDate = endDate;
                            leave.RejoinDate = reJoinDate;
                            // Method to check leave's end date is not beyond start date and re-join date is not beyond end date
                            bool validDate = ValidDateTimeForLeave(leave.FromDate, leave.EndDate.Value, leave.RejoinDate.Value);
                            if (validDate)
                            {
                                await _leaveRepository.UpdateLeaveAsync(leave);
                                _logger.Debug("UpdateSickLeaveAsync leave updated successfully");
                                replyText = string.Format(_stringConstant.ReplyTextForSickLeaveUpdate
                                    , newUser.FirstName, leave.FromDate.ToShortDateString(), leave.EndDate.Value.ToShortDateString(),
                                    leave.Reason, leave.RejoinDate.Value.ToShortDateString());
                                _logger.Debug("Client Repository - SendMessageWithoutButtonAttachmentIncomingWebhookAsync");
                                await _clientRepository.SendMessageWithoutButtonAttachmentIncomingWebhookAsync(leave, accessToken, replyText, newUser.Id);
                                _logger.Debug("Client Repository - SendSickLeaveMessageToUserIncomingWebhookAsync");
                                await _clientRepository.SendSickLeaveMessageToUserIncomingWebhookAsync(leave, user.Email, replyText, newUser);
                            }
                            else
                                replyText = _stringConstant.InValidDateErrorMessage;
                        }
                        else
                            // if date is not proper than date format error message will be send to user
                            replyText = string.Format(_stringConstant.DateFormatErrorMessage, dateFormat);
                    }
                    else
                        // if sick leave will doesn't exist for leaveId
                        replyText = _stringConstant.SickLeaveDoesnotExist;
                }
                else
                    // if string converting to integer return false then user will get cancel command error message
                    replyText = _stringConstant.UpdateEnterAValidLeaveId;
            }
            else
                // if user is not admin then this message will be show to user
                replyText = _stringConstant.AdminErrorMessageUpdateSickLeave;
            return replyText;
        }

        /// <summary>
        /// Method to check leave's end date is not beyond start date and re-join date is not beyond end date
        /// </summary>
        /// <param name="startDate">leave start date</param>
        /// <param name="endDate">leave end date</param>
        /// <param name="rejoinDate">leave rejoin date</param>
        /// <returns>true or false</returns>
        private bool ValidDateTimeForLeave(DateTime startDate, DateTime endDate, DateTime rejoinDate)
        {
            var valid = startDate.CompareTo(endDate);
            if (valid < 1)
            {
                valid = endDate.CompareTo(rejoinDate);
                if (valid < 0)
                    return true;
                else
                    return false;
            }
            else
                return false;
        }

        /// <summary>
        /// Method to check leave's start date is not beyond today. Back date checking
        /// </summary>
        /// <param name="startDate">leave start date</param>
        /// <returns>true or false</returns>
        private bool LeaveStartDateValid(DateTime startDate)
        {
            var valid = DateTime.UtcNow.Date.CompareTo(startDate.Date);
            if (valid <= 0)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Method to check more than one leave cannot be applied on that date
        /// </summary>
        /// <param name="userId">User's Id</param>
        /// <param name="startDate">leave start date</param>
        /// <param name="endDate">leave end date</param>
        /// <returns>true or false</returns>
        private async Task<bool> LeaveDateDuplicate(string userId, DateTime startDate, DateTime? endDate)
        {
            int valid = -1;
            bool validIndicator = false;
            LeaveRequest lastLeave = new LeaveRequest();
            IEnumerable<LeaveRequest> allLeave = await _leaveRepository.LeaveListByUserIdOnlyApprovedAndPending(userId);
            if (allLeave != null)
            {
                foreach (var leave in allLeave)
                {
                    _logger.Debug("LeaveDateDuplicate Leave of user in count : " + allLeave.Count());
                    if (leave.EndDate.HasValue)
                        valid = leave.EndDate.Value.CompareTo(startDate);
                    else
                        valid = leave.FromDate.CompareTo(startDate);
                    switch (valid)
                    {
                        case -1:
                            {
                                if (endDate != null)
                                    valid = leave.FromDate.CompareTo(endDate);
                                else
                                    valid = leave.FromDate.CompareTo(startDate);
                                if (valid == -1)
                                    validIndicator = false;
                                else
                                    validIndicator = true;
                            }
                            break;
                        case 0:
                            {
                                validIndicator = true;
                            }
                            break;
                        case 1:
                            {
                                if (endDate != null)
                                    valid = leave.FromDate.CompareTo(endDate);
                                else
                                    valid = leave.FromDate.CompareTo(startDate);
                                if (valid == 1)
                                    validIndicator = false;
                                else
                                    validIndicator = true;
                            }
                            break;
                    }
                    if (validIndicator)
                        break;
                }
            }
            return validIndicator;
        }

        /// <summary>
        /// try to convert string date to DateTime
        /// </summary>
        /// <param name="inputDate">string date</param>
        /// <param name="date">expected date as out</param>
        /// <returns>true or false</returns>
        private bool DateFormatChecker(string inputDate, out DateTime date)
        {
            var dateFormat = Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern;
            return DateTime.TryParseExact(inputDate, dateFormat, CultureInfo.InvariantCulture,
                DateTimeStyles.None, out date);
        }
        #endregion
    }
}