Promact/slack-erp-custom-integration-mvc

View on GitHub
Slack.Automation/Promact.Core.Repository/ExternalLoginRepository/OAuthLoginRepository.cs

Summary

Maintainability
B
6 hrs
Test Coverage
using Microsoft.AspNet.Identity;
using Newtonsoft.Json;
using NLog;
using Promact.Core.Repository.SlackChannelRepository;
using Promact.Core.Repository.SlackUserRepository;
using Promact.Erp.DomainModel.ApplicationClass;
using Promact.Erp.DomainModel.ApplicationClass.SlackRequestAndResponse;
using Promact.Erp.DomainModel.DataRepository;
using Promact.Erp.DomainModel.Models;
using Promact.Erp.Util.EnvironmentVariableRepository;
using Promact.Erp.Util.ExceptionHandler;
using Promact.Erp.Util.HttpClient;
using Promact.Erp.Util.StringConstants;
using System;
using System.Threading.Tasks;



namespace Promact.Core.Repository.ExternalLoginRepository
{
    public class OAuthLoginRepository : IOAuthLoginRepository
    {
        #region Private Variables
        private readonly ApplicationUserManager _userManager;
        private readonly IHttpClientService _httpClientService;
        private readonly IRepository<SlackUserDetails> _slackUserDetailsRepository;
        private readonly ISlackUserRepository _slackUserRepository;
        private readonly ISlackChannelRepository _slackChannelRepository;
        private readonly IRepository<SlackChannelDetails> _slackChannelDetails;
        private readonly IStringConstantRepository _stringConstant;
        private readonly IEnvironmentVariableRepository _envVariableRepository;
        private readonly IRepository<IncomingWebHook> _incomingWebHookRepository;
        private readonly ILogger _logger;

        #endregion

        #region Constructor
        public OAuthLoginRepository(ApplicationUserManager userManager,
            IHttpClientService httpClientService, IRepository<SlackUserDetails> slackUserDetailsRepository,
            IRepository<SlackChannelDetails> slackChannelDetailsRepository, IStringConstantRepository stringConstant,
            ISlackUserRepository slackUserRepository, IEnvironmentVariableRepository envVariableRepository,
            IRepository<IncomingWebHook> incomingWebHook, ISlackChannelRepository slackChannelRepository)
        {
            _userManager = userManager;
            _httpClientService = httpClientService;
            _slackUserDetailsRepository = slackUserDetailsRepository;
            _stringConstant = stringConstant;
            _slackUserRepository = slackUserRepository;
            _slackChannelDetails = slackChannelDetailsRepository;
            _envVariableRepository = envVariableRepository;
            _incomingWebHookRepository = incomingWebHook;
            _slackChannelRepository = slackChannelRepository;
            _logger = LogManager.GetLogger("AuthenticationModule");
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Method to add a new user in Application user table and store user's external login information in UserLogin table
        /// </summary>
        /// <param name="email"></param>
        /// <param name="refreshToken"></param>
        /// <param name="userId"></param>
        /// <returns>user information</returns>
        public async Task<ApplicationUser> AddNewUserFromExternalLoginAsync(string email, string refreshToken, string userId)
        {
            _logger.Debug("Start AddNewUserFromExternalLoginAsync:" + email + "RefreshToken: " + refreshToken + " UserID: " + userId);
            ApplicationUser userInfo = _userManager.FindById(userId);
            if (userInfo == null)// check user is already added or not
            {
                userInfo = new ApplicationUser() { Email = email, UserName = email, Id = userId };
                //Creating a user with email only. Password not required
                IdentityResult result = await _userManager.CreateAsync(userInfo);

                //Adding external Oauth details
                UserLoginInfo userLoginInfo = new UserLoginInfo(_stringConstant.PromactStringName, refreshToken);
                var success = await _userManager.AddLoginAsync(userInfo.Id, userLoginInfo);
            }
            return userInfo;
        }

        /// <summary>
        /// Method to get OAuth Server's app information
        /// </summary>
        /// <param name="refreshToken"></param>
        /// <returns>Oauth</returns>
        public OAuthApplication ExternalLoginInformation(string refreshToken)
        {
            string clientId = _envVariableRepository.PromactOAuthClientId;
            string clientSecret = _envVariableRepository.PromactOAuthClientSecret;
            OAuthApplication oAuth = new OAuthApplication();
            oAuth.ClientId = clientId;
            oAuth.ClientSecret = clientSecret;
            oAuth.RefreshToken = refreshToken;
            oAuth.ReturnUrl = _stringConstant.ClientReturnUrl;
            return oAuth;
        }

        /// <summary>
        /// Method to add/update Slack User,channels and groups information 
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public async Task AddSlackUserInformationAsync(string code)
        {
            string slackOAuthRequest = string.Format(_stringConstant.SlackOauthRequestUrl, _envVariableRepository.SlackOAuthClientId, _envVariableRepository.SlackOAuthClientSecret, code);
            string slackOAuthResponse = await _httpClientService.GetAsync(_stringConstant.OAuthAcessUrl, slackOAuthRequest, null, _stringConstant.Bearer);
            SlackOAuthResponse slackOAuth = JsonConvert.DeserializeObject<SlackOAuthResponse>(slackOAuthResponse);
            _logger.Info("slackOAuth UserID" + slackOAuth.UserId);
            bool checkUserIncomingWebHookExist = _incomingWebHookRepository.Any(x => x.UserId == slackOAuth.UserId);
            if (!checkUserIncomingWebHookExist)
            {
                IncomingWebHook slackItem = new IncomingWebHook()
                {
                    UserId = slackOAuth.UserId,
                    IncomingWebHookUrl = slackOAuth.IncomingWebhook.Url
                };
                _incomingWebHookRepository.Insert(slackItem);
                await _incomingWebHookRepository.SaveChangesAsync();
            }

            string detailsRequest = string.Format(_stringConstant.SlackUserDetailsUrl, slackOAuth.AccessToken);
            //get all the slack users of the team
            string userDetailsResponse = await _httpClientService.GetAsync(_stringConstant.SlackUserListUrl, detailsRequest, null, _stringConstant.Bearer);
            SlackUserResponse slackUsers = JsonConvert.DeserializeObject<SlackUserResponse>(userDetailsResponse);
            if (slackUsers.Ok)
            {
                SlackUserDetails slackUserDetails = slackUsers.Members?.Find(x => x.UserId == slackOAuth.UserId);
                _logger.Debug("slackUserDetails" + slackUserDetails.UserId);
                if (!string.IsNullOrEmpty(slackUserDetails?.Profile?.Email))
                {
                    //fetch the details of the user who is authenticated with Promact OAuth server with the given slack user's email
                    _logger.Debug("Profile Email" + slackUserDetails.Profile.Email);
                    ApplicationUser applicationUser = await _userManager.FindByEmailAsync(slackUserDetails.Profile.Email);
                    if (applicationUser != null)
                    {
                        _logger.Debug("slackUserDetails UserID" + slackUserDetails.UserId);
                        applicationUser.SlackUserId = slackUserDetails.UserId;
                        _logger.Debug("applicationUser SlackUserId" + applicationUser.SlackUserId);
                        var succeeded = await _userManager.UpdateAsync(applicationUser);
                        _logger.Debug("applicationUser Object:" + JsonConvert.SerializeObject(applicationUser));
                        _logger.Debug("Update Application User succeeded" + succeeded.Succeeded);
                        _logger.Debug("Update Application User Errors" + succeeded.Errors);
                        ApplicationUser testApllicationUser = await _userManager.FindByEmailAsync(applicationUser.Email);
                        _logger.Debug("Test Application Slcak UserId" + testApllicationUser.SlackUserId);
                        _logger.Debug("Test ApplicationUser Object:" + JsonConvert.SerializeObject(testApllicationUser));
                        await _slackUserRepository.AddSlackUserAsync(slackUserDetails);
                        _logger.Debug("Add Slack User Id Done");
                        //the public channels' details
                        string channelDetailsResponse = await _httpClientService.GetAsync(_stringConstant.SlackChannelListUrl, detailsRequest, null, _stringConstant.Bearer);
                        SlackChannelResponse channels = JsonConvert.DeserializeObject<SlackChannelResponse>(channelDetailsResponse);
                        if (channels.Ok)
                        {
                            _logger.Info("Channels error:" + channels.ErrorMessage);
                            foreach (var channel in channels.Channels)
                            {
                                _logger.Info("Channel:" + channel);
                                await AddChannelGroupAsync(channel);
                            }
                        }
                        else
                            throw new SlackAuthorizeException(_stringConstant.SlackAuthError + channels.ErrorMessage);
                        _logger.Info("Slack User Id  : " + (await _userManager.FindByEmailAsync(applicationUser.Email)).SlackUserId);
                        //the public groups' details
                        string groupDetailsResponse = await _httpClientService.GetAsync(_stringConstant.SlackGroupListUrl, detailsRequest, null, _stringConstant.Bearer);
                        SlackGroupDetails groups = JsonConvert.DeserializeObject<SlackGroupDetails>(groupDetailsResponse);
                        _logger.Info("Groups:" + groups.ErrorMessage);
                        _logger.Debug("Slack User Id  : " + (await _userManager.FindByEmailAsync(applicationUser.Email)).SlackUserId);
                        if (groups.Ok)
                        {
                            foreach (var channel in groups.Groups)
                            {
                                _logger.Info("Group:" + channel);
                                await AddChannelGroupAsync(channel);
                                _logger.Debug("Slack User Id  : " + (await _userManager.FindByEmailAsync(applicationUser.Email)).SlackUserId);
                            }
                        }
                        else
                            throw new SlackAuthorizeException(_stringConstant.SlackAuthError + groups.ErrorMessage);
                    }
                    else
                        throw new SlackAuthorizeException(string.Format(_stringConstant.NotInSlackOrNotExpectedUser, slackUserDetails.Profile.Email));
                }
                else
                    throw new SlackAuthorizeException(_stringConstant.UserNotInSlack);
            }
            else
                throw new SlackAuthorizeException(_stringConstant.SlackAuthError + slackUsers.ErrorMessage);

        }


        /// <summary>
        /// Add slack channel details to the database - JJ
        /// </summary>
        /// <param name="slackChannelDetails">Slack channel details obtained from slack</param>
        /// <returns></returns>
        private async Task AddChannelGroupAsync(SlackChannelDetails slackChannelDetails)
        {
            SlackChannelDetails slackChannel = await _slackChannelDetails.FirstOrDefaultAsync(x => x.ChannelId == slackChannelDetails.ChannelId);
            if (slackChannel == null)
            {
                if (!slackChannelDetails.Deleted)
                {
                    slackChannelDetails.CreatedOn = DateTime.UtcNow;
                    await _slackChannelRepository.AddSlackChannelAsync(slackChannelDetails);
                }
            }
            else
            {
                slackChannel.Name = slackChannelDetails.Name;
                await _slackChannelRepository.UpdateSlackChannelAsync(slackChannel);
            }

        }


        /// <summary>
        /// Method to update slack user table when there is any changes in slack
        /// </summary>
        /// <param name="slackEvent"></param>
        public async Task SlackEventUpdateAsync(SlackEventApiAC slackEvent)
        {
            SlackUserDetails user = await _slackUserDetailsRepository.FirstOrDefaultAsync(x => x.UserId == slackEvent.Event.User.UserId);
            if (user == null)
                await _slackUserRepository.AddSlackUserAsync(slackEvent.Event.User);
        }


        /// <summary>
        /// Method to update slack channel table when a channel is added or updated in team.
        /// </summary>
        /// <param name="slackEvent"></param>
        public async Task SlackChannelAddAsync(SlackEventApiAC slackEvent)
        {
            SlackChannelDetails channel = await _slackChannelDetails.FirstOrDefaultAsync(x => x.ChannelId == slackEvent.Event.Channel.ChannelId);
            if (channel == null)
            {
                slackEvent.Event.Channel.CreatedOn = DateTime.UtcNow;
                _slackChannelDetails.Insert(slackEvent.Event.Channel);
                await _slackChannelDetails.SaveChangesAsync();
            }
            else
            {
                channel.Name = slackEvent.Event.Channel.Name;
                _slackChannelDetails.Update(channel);
                await _slackChannelDetails.SaveChangesAsync();
            }
        }


        /// <summary>
        /// Method check user slackid is exists or ot 
        /// </summary>
        /// <param name="userId">login user id</param>
        /// <returns>empty string</returns>
        public async Task<string> CheckUserSlackInformation(string userId)
        {
            ApplicationUser user = await _userManager.FindByIdAsync(userId);
            _logger.Debug("Slack User Id  : " + (await _userManager.FindByEmailAsync(user.Email)).SlackUserId);
            if (!string.IsNullOrEmpty(user.SlackUserId))
            {
                _logger.Debug("Slack User Id  : " + (await _userManager.FindByEmailAsync(user.Email)).SlackUserId);
                if (_slackUserDetailsRepository.Any(x => x.UserId == user.SlackUserId))
                    return string.Empty;
            }
            return user.Email;
        }


        #endregion
    }
}