public void Set_Users_Charge_Info_Should_Set_Billing_Related_Info_in_Db() { //This is Assert valid user with NO billing info var user = new AspNetUser() { Email = "*****@*****.**", MyShopifyDomain = "test3.myshopify.com", UserName = "******", Id = Guid.NewGuid().ToString(), ShopifyAccessToken = "validtoken", BillingOn = null, PlanId = null, ShopifyChargeId = null }; service.Add(user); var ret = UserDbServiceHelper.SetUsersChargeInfo(service, user.Id, 2, 2, DateTime.Now); Assert.True(ret); var data = service.FindSingleWhere(x => x.Id == user.Id); Assert.NotNull(data.BillingOn); Assert.Equal(2, data.ShopifyChargeId); Assert.Equal(2, data.PlanId); }
public virtual async Task <IActionResult> ChoosePlan() { try { Logger.LogInformation("Getting user."); var user = await UserDbServiceHelper.GetAppUserByIdAsync(UserDbService, UserInContextHelper.GetCurrentUserId(HttpContext)); var planStartId = user.GetPlanId(); ViewBag.PrePlan = planStartId > 0 ? true : false; Logger.LogInformation($"Got user. User ID '{user.Id}', existing plan/plan start ID '{planStartId}'."); //Dev plans are only included if ip is privileged and user is admin var ipIsPriviledged = IPAddressHelper.IsCurrentUserIpPrivileged(HttpContext, Settings); var isAdmin = user.IsAdmin;; Logger.LogInformation($"User IP is priviledged : '{ipIsPriviledged}'."); Logger.LogInformation($"User is admin : '{isAdmin}'."); bool includeDev = ipIsPriviledged && isAdmin; Logger.LogInformation($"Dev plans are being included : '{includeDev}'"); Logger.LogInformation("Listing plans now."); var plans = PlanReader.GetAvailableUpgrades(planStartId, includeDev); Logger.LogInformation($"Total '{plans.Count}' have been listed."); Logger.LogInformation($"Choose plan view name is {Views.Shopify.ChoosePlan}."); return(View(Views.Shopify.ChoosePlan, plans)); } catch (Exception ex) { Logger.LogWarning("Error occurred while executing ChoosePlan())"); LogGenericError(ex); throw ex; } }
public void Un_Set_User_Charge_Info_Should_null_Charge_values_in_db_record() { //This is Assert valid user with valid billing info var user = new AspNetUser() { Email = "*****@*****.**", MyShopifyDomain = "test4.myshopify.com", UserName = "******", Id = Guid.NewGuid().ToString(), ShopifyAccessToken = "validtoken", BillingOn = DateTime.Now, PlanId = 1, ShopifyChargeId = 1 }; service.Add(user); var ret = UserDbServiceHelper.UnSetUserChargeInfo(service, user.Id); Assert.True(ret); var data = service.FindSingleWhere(x => x.Id == user.Id); Assert.Null(data.BillingOn); Assert.Null(data.ShopifyChargeId); Assert.Null(data.PlanId); }
public void remove_user_should_return_false_for_invalid_user_id() { //making sure it doesnt exist in the db var retNull = UserDbServiceHelper.GetAppUserByIdAsync(service, "invalid_id").Result; Assert.Null(retNull); var retFalse = UserDbServiceHelper.RemoveUser(service, "invalid_id"); Assert.False(retFalse); }
protected virtual async Task <IActionResult> _ProceedWithShopExists(string myShopifyDomain) { AppUser user = await UserDbServiceHelper.GetUserByShopDomain(UserDbService, myShopifyDomain);//this must exists..otherwise this method wont be called var password = PassGenerator.GetPassword(new PasswordGeneratorInfo(user.UserName, user.Email)); var status = await SignInManager.PasswordSignInAsync(user.UserName, password, false, lockoutOnFailure : false); if (status.Succeeded) { await UserCache.SetLoggedOnUserInCache(); return(RedirectAfterSuccessfullLogin()); } else { //throw LogCoreException(new CoreException(CoreErrorType.APP_COULD_NOT_SIGN_IN, baseMessage + ".Reason: " + status.ToString(), user, shop)); throw new Exception($"Could not sign into your account.Please try again or contact {AppName} support."); } }
/// <summary> /// This is the method that is called first when user tries to access or install your app. /// This method starts the installation process (by sending to authrization url) if user is not subscribed already otherwise /// tries to auto login the user and sends to the landing page(dashboard). /// </summary> /// <param name="shop">The store (URL) that is trying to access app.</param> /// <returns></returns> public virtual async Task <IActionResult> Handshake(string shop) { using (Logger.BeginScope(new { Shop = shop })) { 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 already authrorized.Calling _ProceedWithShopExists."); return(await _ProceedWithShopExists(shop)); } else { Logger.LogWarning("Shop is NOT authrorized.Either new shop or imcomplete installation from previous attempt.So let's install it."); var handlerUrl = ShopifyUrlHelper.GetAuthResultHandlerUrl(Settings); Logger.LogInformation("Getting permission list."); var permissions = ListPermissions(); Logger.LogInformation("Permission list acquiring is done. {@list}.", permissions); Logger.LogInformation("Getting authorization url."); var authUrl = ShopifyAPI.GetAuthorizationUrl(shop, permissions, handlerUrl); Logger.LogInformation($"Redirecting to authrization url '{authUrl}'."); return(Redirect(authUrl.ToString())); } } else { Logger.LogWarning("Request is NOT authentic.Throwing Exception."); throw new Exception("Request is not authentic."); } } catch (Exception ex) { Logger.LogWarning("Error occurred while handshaking."); throw ex; } } }
public void Get_App_User_By_Id_Async_Should_Return_Null() { //setup connection MyDbConnection con = new MyDbConnection(); //setup command MyDbCommand command = new MyDbCommand(0 /*not admin*/); command.Connection = con; //setup repository Mock <IDbRepository <AspNetUser> > repo = new Mock <IDbRepository <AspNetUser> >(); repo.Setup(x => x.CreateDbCommand(It.IsAny <CommandType>(), It.IsAny <string>(), It.IsAny <Dictionary <string, object> >())).Returns(command); //setup service Mock <IDbService <AspNetUser> > service = new Mock <IDbService <AspNetUser> >(); service.Setup(x => x.FindSingleWhere(It.IsAny <Expression <Func <AspNetUser, bool> > >())); service.Setup(x => x.GetRepo()).Returns(repo.Object); var data = UserDbServiceHelper.GetAppUserByIdAsync(service.Object, UserOne.Id).Result; Assert.Null(data); }
public void Get_User_By_Shop_Domain_Sould_Return_Valid_User_For_Valid_Shop() { //setup connection MyDbConnection con = new MyDbConnection(); //setup command MyDbCommand command = new MyDbCommand(1 /*admin*/); command.Connection = con; //setup repository Mock <IDbRepository <AspNetUser> > repo = new Mock <IDbRepository <AspNetUser> >(); repo.Setup(x => x.CreateDbCommand(It.IsAny <CommandType>(), It.IsAny <string>(), It.IsAny <Dictionary <string, object> >())).Returns(command); //setup service Mock <IDbService <AspNetUser> > service = new Mock <IDbService <AspNetUser> >(); service.Setup(x => x.FindSingleWhere(It.IsAny <Expression <Func <AspNetUser, bool> > >())).Returns(UserOne); service.Setup(x => x.GetRepo()).Returns(repo.Object); var data = UserDbServiceHelper.GetUserByShopDomain(service.Object, UserOne.MyShopifyDomain).Result; Assert.NotNull(data); Assert.Equal(UserOne.Id, data.Id); }
public void remove_user_should_return_true_for_valid_user_id() { var user = new AspNetUser() { Email = "*****@*****.**", MyShopifyDomain = "test5.myshopify.com", UserName = "******", Id = Guid.NewGuid().ToString(), ShopifyAccessToken = "validtoken", BillingOn = null, PlanId = null, ShopifyChargeId = null }; service.Add(user); var retTrue = UserDbServiceHelper.RemoveUser(service, user.Id); Assert.True(retTrue); var retNull = UserDbServiceHelper.GetAppUserByIdAsync(service, user.Id).Result; Assert.Null(retNull); }
public virtual async Task <IActionResult> SelectedPlan(int planId) { using (Logger.BeginScope(new { PlanId = planId })) { try { Logger.LogInformation("Getting user"); var user = await UserDbServiceHelper.GetAppUserByIdAsync(UserDbService, UserInContextHelper.GetCurrentUserId(HttpContext)); string domain = user.MyShopifyDomain; string token = user.ShopifyAccessToken; /*user plan id = 0 means that customer is new*/ int userPlanId = user.GetPlanId(); Logger.LogInformation($"Got user.User ID '{user.Id}', domain '{user.MyShopifyDomain}', token '{user.ShopifyAccessToken}' and Plan Id '{user.PlanId}'."); //privileged ip holders can downgrade or upgrade plan, others are upgrade only var validUpgrade = planId >= userPlanId; var priviledgedUser = IPAddressHelper.IsCurrentUserIpPrivileged(HttpContext, Settings); Logger.LogInformation($"Selected is a valid upgrade : {validUpgrade}"); Logger.LogInformation($"Selector's IP is priviledged: {priviledgedUser}"); if (validUpgrade || priviledgedUser) { Logger.LogInformation("Plan selection is approved."); var plan = PlanReader[planId]; if (plan != null && plan.Id > 0) { Logger.LogInformation($"Found plan for the selected ID. Plan Name '{plan.Name}'."); var charge = new ShopifyRecurringChargeObject() { Name = plan.Name, Price = plan.Price, TrialDays = plan.TrialDays, Test = plan.IsTest, ReturnUrl = ShopifyUrlHelper.GetChargeResultHandlerUrl(Settings), }; try { Logger.LogInformation("Creating recurring charge via api for selected plan."); charge = await ShopifyAPI.CreateRecurringChargeAsync(domain, token, charge); Logger.LogInformation($"Successfully created recurring charge. Redirecting to confirmation URL '{charge.ConfirmationUrl}'."); return(Redirect(charge.ConfirmationUrl)); } catch (Exception ex) { Logger.LogError(ex, $"Failed creating recurring charge for the selected plan.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action."); WebMsg.AddTempDanger(this, "Could not create a recurring charge record/confirmation url via shopify api. Please try again.", false, false); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } } } //if we are here then it is an invalid plan Logger.LogWarning($"Selection is not approved.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' adction"); WebMsg.AddTempDanger(this, "Invalid Plan Selected", false, false); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } catch (Exception ex) { Logger.LogWarning("Error occurred while executing SelectedPlan())"); LogGenericError(ex); throw ex; } } }
public virtual async Task <IActionResult> ChargeResult(string shop, long charge_id) { using (Logger.BeginScope(new { Shop = shop, ChargeId = charge_id })) { try { Logger.LogInformation("Getting current user."); var user = await UserDbServiceHelper.GetAppUserByIdAsync(UserDbService, UserInContextHelper.GetCurrentUserId(HttpContext)); Logger.LogInformation($"Found user. Id is '{user.Id}'"); //to detect if its an upgrade we need users previous plan id, 0 means no previous plan. Logger.LogInformation($"Getting previous plan info, if any."); var previousPlan = user.GetPlanId(); Logger.LogInformation($"Previous plan ID is set to '{previousPlan}'."); PlanAppModel newPlan = null; ShopifyRecurringChargeObject charge = null; try { Logger.LogInformation($"Retriving recurring charge info (before activation). Access token '{user.ShopifyAccessToken}' and charge id '{charge_id}'."); charge = await ShopifyAPI.GetRecurringChargeAsync(user.MyShopifyDomain, user.ShopifyAccessToken, charge_id); Logger.LogInformation($"Successfully retrived recurring charge info (before activation).Id is '{charge.Id}'.Associated plan name '{charge.Name}' and price '{charge.Price}'."); } catch (Exception ex) { Logger.LogError(ex, "Error retriving recurring charge info (before activation)."); WebMsg.AddTempDanger(this, "Could not retrive charge status by charge id via shopify api (before activation)."); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } newPlan = PlanReader[charge.Name]; if (newPlan != null) { Logger.LogInformation($"New plan ID is set to '{newPlan.Id}'."); Logger.LogInformation($"Recurring charge status (before activation) is '{charge.Status}'."); if (charge.Status == "accepted") { //Lets activate the charge try { Logger.LogInformation("Trying to activate the recurring charge."); await ShopifyAPI.ActivateRecurringChargeAsync(user.MyShopifyDomain, user.ShopifyAccessToken, charge_id); Logger.LogInformation("Recurring charge activationon is done."); } catch (Exception ex) { Logger.LogError(ex, $"Recurring charge activation failed.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action."); WebMsg.AddTempDanger(this, "Could not activate the recurring charge via shopify api.Please try again."); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } //Lets check if we were sucessful activating the charge try { Logger.LogInformation("Checking recurring charge status after activation."); charge = await ShopifyAPI.GetRecurringChargeAsync(user.MyShopifyDomain, user.ShopifyAccessToken, charge_id); } catch (Exception ex) { Logger.LogError(ex, "Error getting recurring charge status after activation."); WebMsg.AddTempDanger(this, "Could not retrieve charge status by id via shopify api (after activation). Please try again or contact support"); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } Logger.LogInformation($"Recurring Charge Status after activation is '{charge.Status}'."); //if we were succesful if (charge.Status == "active") { Logger.LogInformation($"Saving user payment information. User id '{user.Id}', charge id '{charge_id}' , plan id '{newPlan.Id}' and billing on '{charge.BillingOn}'."); var updateResult = UserDbServiceHelper.SetUsersChargeInfo(UserDbService, user.Id, charge_id, newPlan.Id, charge.BillingOn); if (!updateResult) { Logger.LogCritical($"Could not save user payment information.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action."); await Emailer.UserPaymentInfoCouldNotBeSavedAsync(user, charge_id, charge.Name); //this.LogCoreException(new CoreException(CoreErrorType.APP_COULD_NOT_SAVE_CHARGE_INFO, errMessage + $".Activated Charge Id {charge.Id}", user, shop)); WebMsg.AddTempDanger(this, "Could not save your payment confirmation in our db.Please try again."); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } else { Logger.LogInformation("Succesfully saved user payment information."); Logger.LogInformation("Refreshing user cache data now."); user = await UserCache.GetLoggedOnUser(true); Logger.LogInformation("Now detecting installation type."); if (previousPlan > 0 && previousPlan != newPlan.Id)//its an upgrade { Logger.LogInformation("Installation was an upgrade type for existing store. Redirecting to RedirectAfterSuccessfulUpgrade()."); await UserChangedPlan(user, newPlan.Id); //handle upgrade event return(RedirectAfterSuccessfulUpgrade(charge.Name)); //now redirect } else//new installation { Logger.LogInformation("Installation was for a new store."); Logger.LogInformation("Now handling post installation tasks by calling DoPostInstallationTasks()."); await DoPostInstallationTasks(user);//handle new installation event Logger.LogInformation("Done handling post installation tasks. "); await SendEmailsOnSuccessfullInstallation(user);//send emails Logger.LogInformation($"Now processing all webhooks defined in the appsettings.json by calling ProcessWebHooksCreation()."); await ProcessWebhooks(user); Logger.LogInformation("Done processing webhooks defined in appsettings.json."); Logger.LogInformation("Now redirecting after successfull sign in."); return(RedirectAfterSuccessfullLogin());//now redirect } } } else /*if status is not active*/ { Logger.LogCritical($"SHopify could not activate the recurring charge. Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action."); WebMsg.AddTempDanger(this, "Shopify did not activate the recurring payment this app requested. Please try again by choosing a plan."); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } } else if (charge.Status == "declined") { Logger.LogCritical("Recurring charge was declined (before activation).Probably user declined payment."); Logger.LogInformation("Calling UserCancelledPayment() event."); await UserCancelledPayment(user, newPlan.Id); Logger.LogInformation("Done handling UserCancelledPayment() event."); if (user.GetPlanId() <= 0) { Logger.LogWarning("Redirecting to RedirectAfterNewUserCancelledPayment() as payment cancelled."); return(RedirectAfterNewUserCancelledPayment(user)); } else { Logger.LogWarning("Redirecting to RedirectAfterPlanChangePaymentDeclined() as payment declined"); return(RedirectAfterPlanChangePaymentDeclined()); } } else { Logger.LogCritical($"Recurring charge was not accepted by shopify (before activation). Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action."); WebMsg.AddTempDanger(this, "Payment was not accepted by shopify. Please try again."); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName())); } } else { Logger.LogCritical($"Recurring charge's plan is not found in the loaded db plan list.Redirecting to '{SHOPIFY_ACTIONS.ChoosePlan.ToString()}' action."); WebMsg.AddTempDanger(this, "Could not retrieve plan information.Please try again."); return(RedirectToAction(SHOPIFY_ACTIONS.ChoosePlan.ToString(), Settings.GetShopifyControllerName()));//let the user try again } } catch (Exception ex) { Logger.LogWarning("Error occurred while executing ChargeResult()."); LogGenericError(ex); throw ex; } } }
/// <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."); } } } } } }
/// <summary> /// Called by the uninstall web hook from shopify end /// </summary> /// <param name="userId">User who uninstalled</param> /// <returns></returns> /// public virtual async Task <IActionResult> AppUninstalled(string userId) { Logger.LogInformation("Start handling app/uninstalled webhook."); bool isValidRequest = false; Logger.LogInformation("Checking webhook authenticity."); try { isValidRequest = await ShopifyAPI.IsAuthenticWebhook(Request); } catch (Exception ex) { LogGenericError(ex); Logger.LogWarning("Exception occurred during checking of the webhook authenticity. Gracefully ignoring and continueing."); } if (!isValidRequest) { Logger.LogWarning("Webhook is not authentic.Still returning 200 OK."); return(Content("Webhook is not authentic."));//yet its a 200 OK msg } else { Logger.LogInformation("Request is authentic."); AppUser user = null; Logger.LogInformation("Trying to retrieve user data."); try { user = await UserDbServiceHelper.GetAppUserByIdAsync(UsrDbService, userId); } catch (Exception ex) { LogGenericError(ex); Logger.LogWarning("Exception occurred while retrieving user data. Gracefully ingnoring and continuing."); } if (user != null) { Logger.LogInformation("Found user data. {@user}", user); bool removeSuccess = false; Exception removalException = null; try { Logger.LogInformation("Trying to remove user account."); removeSuccess = UserDbServiceHelper.RemoveUser(UsrDbService, userId); } catch (Exception ex) { LogGenericError(ex); Logger.LogInformation("Error occurred during user account removal. Gracefully ignoring and continuing."); removalException = ex; } if (!removeSuccess) { Logger.LogInformation("Calling CouldNotDeleteUser() event."); await CouldNotDeleteUser(user, removalException ?? new Exception("Reason not known")); Logger.LogInformation("Done handling CouldNotDeleteUser() event."); } else { Logger.LogInformation("user account removal was successfull."); Logger.LogInformation("Calling UserIsDeleted() event."); await UserIsDeleted(user); Logger.LogInformation("Done handling UserIsDeleted() event."); } try { Logger.LogInformation("Trying to clear user cache calling ClearUser()."); UserCache.ClearUser(userId); Logger.LogInformation("Done clearning user cache."); } catch (Exception ex) { LogGenericError(ex); Logger.LogWarning("Error occurred during clearning user cache.Ignoring and continuing."); } } try { Logger.LogInformation("Sending out uninstall event email."); var emailRet = await SendUninstallEmail(user); if (emailRet) { Logger.LogInformation("Successfully sent out uninstall even email."); } else { Logger.LogWarning("Error sending uninstall event email."); } Logger.LogInformation("Calling UnInstallCompleted() event."); await UnInstallCompleted(user); Logger.LogInformation("Done handling UnInstallCompleted() event."); } catch (Exception ex) { Logger.LogError(ex, "Unhandled exection occurred during app uninstall web hook processing."); } Logger.LogInformation("Returning 200 OK to satisfy shopify."); return(Ok()); //shopify wants 200 OK msg } }
public void Shop_Is_Authorized_Should_Return_True() { var ret = UserDbServiceHelper.ShopIsAuthorized(service, UserTwo.MyShopifyDomain); Assert.True(ret); }
public void Get_User_By_Shop_Domain_Should_Return_NUll_For_Invalid_Shop() { var data = UserDbServiceHelper.GetUserByShopDomain(service, "invalid shop name").Result; Assert.Null(data); }