public virtual async Task <IActionResult> Error()
        {
            var            exception = HttpContext.Features.Get <IExceptionHandlerFeature>();
            ErrorViewModel model     = new ErrorViewModel()
            {
                Exception      = exception?.Error,
                GeneralMessage = exception?.Error.Message,
                RequestId      = Activity.Current?.Id ?? HttpContext.TraceIdentifier,
                HelpMessage    = "Please contact support if it keeps happening.",
                HelpLinkHref   = "/",
            };

            //these following lines might throw error, and we do not want error while dealing with one alraedy.
            try
            {
                model.SupportEmail = Settings.GetAppSupportEmailAddress();
            }
            catch (System.Exception) { }

            try
            {
                model.ShowExceptionDetails = UserInContextHelper.IsCurrentUserIdAdmin(HttpContext);
            }
            catch (System.Exception) { }

            try
            {
                Logger.LogCritical(exception?.Error, "Critical Error Occured.");
            }
            catch (System.Exception)
            {
            }
            return(View(Views.ErrorPage, model));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the logged on user data from memory cache.
        /// </summary>
        /// <param name="refresh">If set to <c>true</c>, then even if the cache data is available it will still call the <see cref="SetLoggedOnUserInCache"/> method</param>
        /// <returns>
        /// <see cref="Exico.Shopify.Data.Domain.AppModels.AppUser"/>
        /// </returns>
        public async Task <AppUser> GetLoggedOnUser(bool refresh = false)
        {
            AppUser cacheData = null;

            if (_HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
            {
                var userId = UserInContextHelper.GetCurrentUserId(_HttpContextAccessor.HttpContext);
                var key    = GetUserCacheKey(userId);
                if (_Cache.TryGetValue <AppUser>(key, out cacheData))
                {
                    _Logger.LogInformation($"Data found in cache for key = {key}");

                    if (refresh)
                    {
                        _Logger.LogInformation($"Refreshing cache data for key = {key} becuase refresh is requested.");
                        cacheData = await SetLoggedOnUserInCache();
                    }
                }
                else
                {
                    _Logger.LogWarning($"Missing cache data for logged on user for key = {key}. Save logged on user data in cache now.");
                    cacheData = await SetLoggedOnUserInCache();
                }
            }
            else
            {
                _Logger.LogInformation("Returning null because user is not logged in.");
            }

            return(cacheData);
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Gets the logged on user's cache key.
 /// </summary>
 /// <returns>The cache key </returns>
 public string GetLoggedOnUserCacheKey()
 {
     if (_HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
     {
         return(GetUserCacheKey(UserInContextHelper.GetCurrentUserId(_HttpContextAccessor.HttpContext)));
     }
     else
     {
         _Logger.LogInformation("Returning null as current logged on users cache key becuase user is not logged on.");
         return(null);
     }
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Clears the logged on user data from cache.
 /// It can automatically determins the cach key for the current logged in user.
 /// </summary>
 public void ClearLoggedOnUser()
 {
     if (_HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
     {
         var userId = UserInContextHelper.GetCurrentUserId(_HttpContextAccessor.HttpContext);
         _Logger.LogInformation($"Clearning cache for user id =  {userId}");
         ClearUser(userId);
     }
     else
     {
         _Logger.LogInformation("Didn't clear anything in cache, because user is not logged in.");
     }
 }
        /// <summary>
        /// Gets a context as <see cref="LoggingContext"/> data class that has information about logged in user and store.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="scope"></param>
        /// <returns></returns>
        public async Task <LoggingContext> GetLoggingContext(HttpContext context, IServiceScope scope)
        {
            var loggedInStatus = UserInContextHelper.IsLoggedIn(context);

            if (!loggedInStatus)
            {
                return new LoggingContext()
                       {
                           LoggedIn = false,
                           IP       = context.Connection.RemoteIpAddress.ToString()
                       }
            }
            ;
            else
            {
                var caching = scope.ServiceProvider.GetService <IUserCaching>();

                var planReader = scope.ServiceProvider.GetService <IPlansReader>();
                var user       = await caching.GetLoggedOnUser();

                if (user != null)
                {
                    var plan = planReader[user.PlanId.HasValue ? user.PlanId.Value : 0];
                    return(new LoggingContext()
                    {
                        LoggedIn = true,
                        AccessToken = user.ShopifyAccessToken,
                        Email = user.Email,
                        IP = context.Connection.RemoteIpAddress.ToString(),
                        RequestPath = context.Request.Path,
                        Shop = user.MyShopifyDomain,
                        ChargeId = user.ShopifyChargeId,
                        PlanId = user.PlanId,
                        PlanName = plan?.Name,
                        UserId = user.Id,
                    });
                }
                else
                {
                    //somethings not right, but let us cope with the situation
                    return(new LoggingContext()
                    {
                        LoggedIn = true,
                        IP = context.Connection.RemoteIpAddress.ToString(),
                        UserId = UserInContextHelper.GetCurrentUserId(context),
                        Shop = context.User.Identity.Name,
                        Comment = "User is logged in but not present in the cache. Deleted from the db??"
                    });
                }
            }
        }
Ejemplo n.º 6
0
        public void Get_Current_User_Id_Return_Null_If_Not_Authenticated(bool userIsLoggedOn)
        {
            InitServiceProvider(userIsLoggedOn);
            var contextAccessor = serviceProvider.GetRequiredService <IHttpContextAccessor>();

            if (userIsLoggedOn)
            {
                Assert.Equal(UserId, UserInContextHelper.GetCurrentUserId(contextAccessor.HttpContext));
            }
            else
            {
                Assert.Null(UserInContextHelper.GetCurrentUserId(contextAccessor.HttpContext));
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Gets a copy of the user data the from DB by logged on user id and sets it into memory cache.
        /// </summary>
        /// <returns>
        /// <see cref="Exico.Shopify.Data.Domain.AppModels.AppUser"/>
        /// </returns>
        public async Task <AppUser> SetLoggedOnUserInCache()
        {
            AppUser cacheData = null;

            if (_HttpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
            {
                AspNetUser user = await _Store.GetClaimedUserData(_HttpContextAccessor.HttpContext.User);

                if (user != null)
                {
                    var cKey = GetUserCacheKey(user.Id);
                    _Logger.LogInformation($"Setting logged on user in to cache with key = '{cKey}'.");
                    cacheData = new AppUser(user, UserInContextHelper.IsCurrentUserIdAdmin(_HttpContextAccessor.HttpContext));
                    _Cache.Set <AppUser>(cKey, cacheData, new MemoryCacheEntryOptions()
                    {
                        SlidingExpiration = TimeSpan.FromMinutes(USER_CACHE_EXPIRE_MINUTES),
                        Priority          = CacheItemPriority.High,
                    });
                    _Logger.LogInformation("Returning cached logged in user {@user}.", cacheData);
                }
                else
                {
                    var errMsg = $"User {_HttpContextAccessor.HttpContext.User.Identity.Name} is logged in user but identity is not found in our database.";
                    _Logger.LogError(new Exception(errMsg), errMsg + "{@data}", _HttpContextAccessor.HttpContext.User.Identity.Name);
                    _Logger.LogWarning("Force signing out.");
                    await _SignInManager.SignOutAsync();

                    _Logger.LogInformation("Redirecting to / ");
                    _HttpContextAccessor.HttpContext.Response.Redirect("/");
                };
            }
            else
            {
                _Logger.LogInformation("Returning null because user is not logged in.");
            }

            return(cacheData);
        }
Ejemplo n.º 8
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;
                }
            }
        }
Ejemplo n.º 9
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;
            }
        }
Ejemplo n.º 10
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;
                }
            }
        }