/// <summary> /// This method mainly tries to generate access token, creates user record, creates uninstall web hook and finally /// sends to the page where user can choose plan. /// </summary> /// <param name="shop">The store (URL) that is trying to access app.</param> /// <param name="code">Authrization code generated and send from shopify that will be used to gnerate access code</param> /// <returns></returns> public virtual async Task <IActionResult> AuthResult(string shop, string code) { using (Logger.BeginScope(new { Shop = shop, Code = code })) { try { Logger.LogInformation("Checking request authenticity."); if (ShopifyAPI.IsAuthenticRequest(Request)) { Logger.LogInformation("Request is authentic."); Logger.LogInformation("Checking if shop is authorized."); if (UserDbServiceHelper.ShopIsAuthorized(UserDbService, shop)) { Logger.LogInformation("Shop is authrorized.Calling _ProceedWithShopExists."); return(await _ProceedWithShopExists(shop)); } else { string accessToken = ""; try { Logger.LogWarning("Shop is NOT authrorized.Requesting authentication (access) token via api."); accessToken = await ShopifyAPI.Authorize(shop, code); } catch (Exception ex) { Logger.LogCritical("Shopify did not authorize.No access code received.Throwing exception."); throw new Exception("Shopify did not authorize.No access code received.", ex); } Logger.LogInformation($"Rceived access token '{accessToken}'"); Thread.Sleep(500); /*Get shop object cause we need the shop email address*/ ShopifyShopObject shopObj = null; try { Logger.LogInformation("Request shopify shop obj using access token."); shopObj = await ShopifyAPI.GetShopAsync(shop, accessToken); } catch (Exception ex) { Logger.LogCritical("Could not retrive shop info obj."); throw new Exception("Could not retrive shop info obj.", ex); } Logger.LogInformation($"Received shop info obj. Shop '{shopObj.Domain}' and email '{shopObj.Email}'"); #region User Creation //Generate password Logger.LogInformation("Generating password using shop info obj."); string password = PassGenerator.GetPassword(new PasswordGeneratorInfo(shopObj.MyShopifyDomain, shopObj.Email)); Logger.LogInformation($"Successfully generated a password '{password}'."); /*Now create an account */ Logger.LogInformation("Creating user account using shop info and password."); var userCreation = await UserManager.CreateAppUser(shopObj.MyShopifyDomain, shopObj.Email, accessToken, password); #endregion if (userCreation.Succeeded) { AppUser user = await UserDbServiceHelper.GetUserByShopDomain(UserDbService, shopObj.MyShopifyDomain); Logger.LogInformation($"Successfully created user for the shop.User id '{user.Id}'"); #region Uninstall hook creation //As soon as user is created , create the uninstall hook string uninstallCallback = ""; try { Logger.LogInformation("Trying to find app/uninstalled topic in the web hook definition list in the appsettings.json file."); List <WebHookDefinition> whDefList = AppSettings.BindObject <List <WebHookDefinition> >("WebHooks", Config); if (whDefList.Count > 0) { var def = whDefList.Where(x => x.Topic.ToLower() == "app/uninstalled").FirstOrDefault(); if (def.Topic == string.Empty) { Logger.LogWarning("List of webhooks found in the appsettings file but no app/uninstalled topic found."); uninstallCallback = ShopifyUrlHelper.GetAppUninstallWebHookUrl(Settings, user.Id); Logger.LogInformation($"Using system default uninstall callback url {uninstallCallback}."); } else { Logger.LogInformation($"Found app/uninstalled topic call in the appsettings file.The callback url is {def.Callback}."); uninstallCallback = ShopifyUrlHelper.GetAppUninstallWebHookUrl(def.Callback, user.Id); } } else { Logger.LogInformation("No weebhooks are defined in the appsettings file."); uninstallCallback = ShopifyUrlHelper.GetAppUninstallWebHookUrl(Settings, user.Id); Logger.LogInformation($"Using system default uninstall callback url {uninstallCallback}."); } Logger.LogInformation($"Trying to create uninstall web hook with call back url {uninstallCallback}."); var hook = await ShopifyAPI.CreateWebhookAsync(user.MyShopifyDomain, accessToken, new ShopifyWebhookObject() { Address = uninstallCallback, Topic = "app/uninstalled" }); Logger.LogInformation($"Successfully created uninstall web hook. Hook id '{hook.Id.Value}'."); } catch (Exception ex) { LogGenericError(ex); Logger.LogCritical($"Failed creating uninstall webhook for user id '{user.Id}.The call back url is {uninstallCallback}'."); Logger.LogInformation("Sending UninstallHookCreationFailedAsync email."); var response = await Emailer.UninstallHookCreationFailedAsync(user, shopObj.MyShopifyDomain); if (response) { Logger.LogInformation("Successfully sent UninstallHookCreationFailedAsync email."); } else { Logger.LogInformation("Could not send UninstallHookCreationFailedAsync email."); } //we dont thorw error here...just gracefully ignore it } #endregion #region Sign in //Now sign in Logger.LogInformation($"Trying to sign in using username '{user.UserName}' and password '{password}'. User id '{user.Id}'"); var signInStatus = await SignInManager.PasswordSignInAsync(user.UserName, password, false, lockoutOnFailure : false); if (signInStatus.Succeeded) { Logger.LogInformation($"Successfully signed in. User id '{user.Id}'"); UserCache.ClearLoggedOnUser(); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } else { Logger.LogCritical($"Signing in for User id '{user.Id}' failed."); throw new Exception("Could not sign you in using app account.Sign in failed!"); } #endregion } else { var reasons = $"Reasons: { string.Join(", ", userCreation.Errors) }"; Logger.LogCritical($"User creation failed.{reasons}"); throw new Exception($"Could not create app user.{reasons}."); } } } else { Logger.LogCritical("Request is not authentic. Throwing error."); throw new Exception("Request is not authentic."); } } catch (Exception ex) { Logger.LogWarning("Error occurred while executing AuthResult()."); LogGenericError(ex); throw ex; } } }
public void OnAuthorization(AuthorizationFilterContext filterContext) { //already logged in by Identity now check subscription if (filterContext.Result == null) { _Logger.LogInformation("Starting subscription check."); var context = filterContext.HttpContext; _Logger.LogInformation("Getting current user."); AppUser currentUser = _UserCache.GetLoggedOnUser().Result; if (currentUser == null) { _Logger.LogError("User must be logged on before checking subscription.Redirecting to login page."); //throw new Exception("Subscription check must be done on logged on user. But current user is found null."); filterContext.Result = new RedirectToActionResult(ACCOUNT_ACTIONS.Login.ToString(), _Settings.GetAccountControllerName(), new { }); } else { _Logger.LogInformation($"Current user is '{currentUser.MyShopifyDomain}'"); //admin must have access token atleast if (currentUser.ShopIsConnected == false /*&& !currentUser.IsAdmin*/) { _Logger.LogWarning($"User '{currentUser.MyShopifyDomain}' has no shopify access token. Charge status check cannot be done on diconnected shop.Redirecting to '{_Settings.GetShopifyControllerName()}/{SHOPIFY_ACTIONS.HandShake.ToString()}'."); filterContext.Result = _CreateRedirectResult(_Settings.GetShopifyControllerName(), SHOPIFY_ACTIONS.HandShake.ToString()); } //billing connected or disconnected, for admin it is never checked else if (currentUser.BillingIsConnected == false && !currentUser.IsAdmin) { _Logger.LogWarning($"User '{currentUser.MyShopifyDomain}' billing charge id is null.Charge status check cannot be done on null charge id.Redirecting to '{_Settings.GetShopifyControllerName()}/{SHOPIFY_ACTIONS.ChoosePlan.ToString()}'."); filterContext.Result = _CreateRedirectResult(_Settings.GetShopifyControllerName(), SHOPIFY_ACTIONS.ChoosePlan.ToString()); } else { ShopifyRecurringChargeObject chargeStatus = null; //for admin user if no billing charge id all good, but if theres one then we will look into it if (currentUser.IsAdmin) { _Logger.LogInformation($"Skipping charge status check because user '{currentUser.MyShopifyDomain}' is admin."); chargeStatus = new ShopifyRecurringChargeObject() { Status = SHOPIFY_CHARGE_STATUS.active.ToString() }; } else { _Logger.LogInformation($"Checking charge status for user '{currentUser.MyShopifyDomain}'."); try { chargeStatus = Task.Run(() => _ShopifyApi.GetRecurringChargeAsync(currentUser.MyShopifyDomain, currentUser.ShopifyAccessToken, currentUser.ShopifyChargeId.Value)).Result; } catch (Exception ex) { _Logger.LogError($"Error occurred duing GetRecurringChargeAsync() call.{ex.Message}.{ex.StackTrace}"); throw ex; } } if (chargeStatus.Status == SHOPIFY_CHARGE_STATUS.accepted.ToString() || chargeStatus.Status == SHOPIFY_CHARGE_STATUS.active.ToString()) { _Logger.LogInformation($"Require subscription passed for user '{currentUser.MyShopifyDomain}'"); } else { _Emailer.InActiveChargeIdDetectedAsync(currentUser, chargeStatus.Status); if (chargeStatus.Status == SHOPIFY_CHARGE_STATUS.declined.ToString() || chargeStatus.Status == SHOPIFY_CHARGE_STATUS.expired.ToString() || chargeStatus.Status == SHOPIFY_CHARGE_STATUS.pending.ToString()) { _Logger.LogWarning($"Require subscription did not pass for user '{currentUser.MyShopifyDomain}'"); _Logger.LogWarning($"User '{currentUser.MyShopifyDomain}' has declined/expired/pending charge status."); _Logger.LogWarning($"Unsetting charge info for user '{currentUser.MyShopifyDomain}'."); UserDbServiceHelper.UnSetUserChargeInfo(_UserDbService, currentUser.Id); _Logger.LogWarning($"Removing user '{currentUser.MyShopifyDomain}' from cache."); _UserCache.ClearLoggedOnUser();//resset cache so that next try makes BillingIsConnected = false var handShakeAction = SHOPIFY_ACTIONS.HandShake.ToString(); _Logger.LogWarning($"Redirecting user '{currentUser.MyShopifyDomain}' to '{_Settings.GetShopifyControllerName()}/{handShakeAction}'."); filterContext.Result = _CreateRedirectResult(_Settings.GetShopifyControllerName(), handShakeAction); } else if (chargeStatus.Status == SHOPIFY_CHARGE_STATUS.frozen.ToString()) { _Logger.LogError($"User '{currentUser.MyShopifyDomain}' has frozen shopify store account. Throwing error."); throw new UnauthorizedAccessException("Your shopify account is frozen.Once shopify unfreezes your store account you will be able to use this app again."); } } } } } }