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);
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 5
0
        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.");
            }
        }
Exemplo n.º 6
0
 /// <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);
        }
Exemplo n.º 10
0
        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;
                }
            }
        }
Exemplo n.º 11
0
        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;
                }
            }
        }
Exemplo n.º 12
0
        /// <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;
                }
            }
        }
Exemplo n.º 13
0
        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.");
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 14
0
        /// <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);
        }