예제 #1
0
        public HttpResponseMessage ProcessMobileCheckin(string param)
        {
            try
            {
                var session = HttpContext.Current.Session;

                var currentCheckInState = session["CheckInState"] as CheckInState;
                if (currentCheckInState.CheckIn.SearchType.Guid != Constants.CHECKIN_SEARCH_TYPE_USERLOGIN.AsGuid())
                {
                    throw new Exception(); //We'll catch this later and return a forbidden
                }

                var localDeviceConfigCookie = HttpContext.Current.Request.Cookies[CheckInCookieKey.LocalDeviceConfig].Value;
                var localDevice             = localDeviceConfigCookie.FromJsonOrNull <LocalDeviceConfiguration>();

                var rockContext = new Rock.Data.RockContext();

                UserLoginService userLoginService = new UserLoginService(rockContext);
                var family = userLoginService.Queryable().AsNoTracking()
                             .Where(u => u.UserName == currentCheckInState.CheckIn.SearchValue)
                             .Select(u => u.Person.PrimaryFamily)
                             .FirstOrDefault();
                var checkinFamily = new CheckInFamily
                {
                    Group    = family.Clone(false),
                    Caption  = family.ToString(),
                    Selected = true
                };
                currentCheckInState.CheckIn.Families.Add(checkinFamily);
                SaveState(session, currentCheckInState);

                Guid   blockGuid        = ( Guid )session["BlockGuid"];
                var    block            = BlockCache.Get(blockGuid);
                Guid?  workflowGuid     = block.GetAttributeValue("WorkflowType").AsGuidOrNull();
                string workflowActivity = block.GetAttributeValue("WorkflowActivity");

                List <string> errors;
                var           workflowService = new WorkflowService(rockContext);
                var           workflowType    = WorkflowTypeCache.Get(workflowGuid.Value);

                var CurrentWorkflow = Rock.Model.Workflow.Activate(workflowType, currentCheckInState.Kiosk.Device.Name, rockContext);

                var activityType = workflowType.ActivityTypes.Where(a => a.Name == workflowActivity).FirstOrDefault();
                if (activityType != null)
                {
                    WorkflowActivity.Activate(activityType, CurrentWorkflow, rockContext);
                    if (workflowService.Process(CurrentWorkflow, currentCheckInState, out errors))
                    {
                        if (errors.Any())
                        {
                            var innerException = new Exception(string.Join(" -- ", errors));
                            ExceptionLogService.LogException(new Exception("Process Mobile Checkin failed initial workflow. See inner exception for details.", innerException));
                        }

                        // Keep workflow active for continued processing
                        CurrentWorkflow.CompletedDateTime = null;
                        SaveState(session, currentCheckInState);
                        List <CheckInFamily> families = currentCheckInState.CheckIn.Families;
                        families = families.OrderBy(f => f.Caption).ToList();
                        return(ControllerContext.Request.CreateResponse(HttpStatusCode.OK, param));
                    }
                    else
                    {
                        if (errors.Any())
                        {
                            var innerException = new Exception(string.Join(" -- ", errors));
                            ExceptionLogService.LogException(new Exception("Process Mobile Checkin failed initial workflow. See inner exception for details.", innerException));
                        }
                        else
                        {
                            ExceptionLogService.LogException(new Exception("Process Mobile Checkin failed initial workflow. See inner exception for details."));
                        }
                    }
                }
                else
                {
                    return(ControllerContext.Request.CreateResponse(HttpStatusCode.InternalServerError, string.Format("Workflow type does not have a '{0}' activity type", workflowActivity)));
                }
                return(ControllerContext.Request.CreateResponse(HttpStatusCode.InternalServerError, String.Join("\n", errors)));
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(ex, HttpContext.Current);
                return(ControllerContext.Request.CreateResponse(HttpStatusCode.Forbidden, "Forbidden"));
            }
        }
예제 #2
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap             = context.JobDetail.JobDataMap;
            Guid?      groupGuid           = dataMap.GetString("EligibleFollowers").AsGuidOrNull();
            Guid?      systemEmailGuid     = dataMap.GetString("EmailTemplate").AsGuidOrNull();
            int        followingEventsSent = 0;

            if (groupGuid.HasValue && systemEmailGuid.HasValue)
            {
                var exceptionMsgs = new List <string>();

                using (var rockContext = new RockContext())
                {
                    var followingService                  = new FollowingService(rockContext);
                    var followingEventTypeService         = new FollowingEventTypeService(rockContext);
                    var followingEventNotificationService = new FollowingEventNotificationService(rockContext);

                    // Get all the active event types
                    var eventTypes = followingEventTypeService
                                     .Queryable().AsNoTracking()
                                     .Where(e =>
                                            e.EntityTypeId.HasValue &&
                                            e.IsActive)
                                     .OrderBy(e => e.Order)
                                     .ToList();

                    // Get the required event types
                    var requiredEventTypes = eventTypes
                                             .Where(e => e.IsNoticeRequired)
                                             .ToList();

                    // The people who are eligible to get following event notices based on the group type setting for this job
                    var eligiblePersonIds = new GroupMemberService(rockContext)
                                            .Queryable().AsNoTracking()
                                            .Where(m =>
                                                   m.Group != null &&
                                                   m.Group.Guid.Equals(groupGuid.Value) &&
                                                   m.GroupMemberStatus == GroupMemberStatus.Active &&
                                                   m.Person != null &&
                                                   m.Person.Email != null &&
                                                   m.Person.Email != "")
                                            .Select(m => m.PersonId)
                                            .Distinct()
                                            .ToList();

                    // Get all the subscriptions for the eligible people
                    var eventSubscriptions = new FollowingEventSubscriptionService(rockContext)
                                             .Queryable("PersonAlias").AsNoTracking()
                                             .Where(f => eligiblePersonIds.Contains(f.PersonAlias.PersonId))
                                             .ToList();

                    // Dictionaries used to store information that will be used to create notification
                    var personSubscriptions = new Dictionary <int, List <int> >();                  // Key: personId, Value: list of event type ids that person subscribes to
                    var personFollowings    = new Dictionary <int, List <int> >();                  // Key: personId, Value: list of following ids that person follows
                    var eventsThatHappened  = new Dictionary <int, Dictionary <int, string> >();    // Key: event type id Value: Dictionary of entity id and formatted event notice for the entity

                    //Get the subscriptions for each person
                    foreach (int personId in eligiblePersonIds)
                    {
                        var personEventTypes = eventSubscriptions
                                               .Where(s => s.PersonAlias.PersonId == personId)
                                               .Select(s => s.EventType)
                                               .ToList();
                        personEventTypes.AddRange(requiredEventTypes);
                        if (personEventTypes.Any())
                        {
                            personSubscriptions.AddOrIgnore(personId, personEventTypes
                                                            .OrderBy(e => e.Order)
                                                            .ThenBy(e => e.Name)
                                                            .Select(e => e.Id)
                                                            .Distinct()
                                                            .ToList());
                        }
                    }

                    // Get a distinct list of each entitytype/entity that is being followed by anyone that subscribes to events
                    var followings = followingService
                                     .Queryable("PersonAlias").AsNoTracking()
                                     .Where(f => personSubscriptions.Keys.Contains(f.PersonAlias.PersonId))
                                     .ToList();

                    // group the followings by their type
                    var followedEntityIds = new Dictionary <int, List <int> >();
                    foreach (var followedEntity in followings
                             .Select(f => new
                    {
                        f.EntityTypeId,
                        f.EntityId
                    })
                             .Distinct())
                    {
                        followedEntityIds.AddOrIgnore(followedEntity.EntityTypeId, new List <int>());
                        followedEntityIds[followedEntity.EntityTypeId].Add(followedEntity.EntityId);
                    }

                    // group the followings by the follower
                    foreach (int personId in personSubscriptions.Select(s => s.Key))
                    {
                        var personFollowing = followings
                                              .Where(f => f.PersonAlias.PersonId == personId)
                                              .Select(f => f.Id)
                                              .ToList();

                        personFollowings.Add(personId, personFollowing);
                    }

                    var timestamp = RockDateTime.Now;

                    // foreach followed entitytype
                    foreach (var keyVal in followedEntityIds)
                    {
                        // Get the entitytype
                        EntityTypeCache itemEntityType = EntityTypeCache.Read(keyVal.Key);
                        if (itemEntityType.AssemblyName != null)
                        {
                            // get the actual type of what is being followed
                            Type entityType = itemEntityType.GetEntityType();
                            if (entityType != null)
                            {
                                var dbContext = Reflection.GetDbContextForEntityType(entityType);
                                if (dbContext != null)
                                {
                                    var serviceInstance = Reflection.GetServiceForEntityType(entityType, dbContext);
                                    if (serviceInstance != null)
                                    {
                                        MethodInfo qryMethod = serviceInstance.GetType().GetMethod("Queryable", new Type[] { });
                                        var        entityQry = qryMethod.Invoke(serviceInstance, new object[] { }) as IQueryable <IEntity>;

                                        // If looking at person alias following, make sure to exclude deceased people
                                        if (entityType == typeof(Rock.Model.PersonAlias))
                                        {
                                            var personAliasQry = entityQry as IQueryable <PersonAlias>;
                                            if (personAliasQry != null)
                                            {
                                                entityQry = personAliasQry.Where(p => !p.Person.IsDeceased);
                                            }
                                        }

                                        var entityList = entityQry.Where(q => keyVal.Value.Contains(q.Id)).ToList();

                                        // If there are any followed entities of this type
                                        if (entityList.Any())
                                        {
                                            // Get the active event types for this entity type
                                            foreach (var eventType in eventTypes.Where(e => e.FollowedEntityTypeId == keyVal.Key))
                                            {
                                                try
                                                {
                                                    // Get the component
                                                    var eventComponent = eventType.GetEventComponent();
                                                    if (eventComponent != null)
                                                    {
                                                        // Get the previous notificatoins for this event type
                                                        var previousNotifications = followingEventNotificationService
                                                                                    .Queryable()
                                                                                    .Where(n => n.FollowingEventTypeId == eventType.Id)
                                                                                    .ToList();

                                                        // check each entity that is followed (by anyone)
                                                        foreach (IEntity entity in entityList)
                                                        {
                                                            var previousNotification = previousNotifications
                                                                                       .Where(n => n.EntityId == entity.Id)
                                                                                       .FirstOrDefault();
                                                            DateTime?lastNotification = previousNotification != null ? previousNotification.LastNotified : (DateTime?)null;

                                                            // if the event happened
                                                            if (eventComponent.HasEventHappened(eventType, entity, lastNotification))
                                                            {
                                                                // Store the event type id and the entity for later processing of notifications
                                                                eventsThatHappened.AddOrIgnore(eventType.Id, new Dictionary <int, string>());
                                                                eventsThatHappened[eventType.Id].Add(entity.Id, eventComponent.FormatEntityNotification(eventType, entity));

                                                                if (previousNotification == null)
                                                                {
                                                                    previousNotification = new FollowingEventNotification();
                                                                    previousNotification.FollowingEventTypeId = eventType.Id;
                                                                    previousNotification.EntityId             = entity.Id;
                                                                    followingEventNotificationService.Add(previousNotification);
                                                                }
                                                                previousNotification.LastNotified = timestamp;
                                                            }
                                                        }

                                                        rockContext.SaveChanges();
                                                    }

                                                    eventType.LastCheckDateTime = RockDateTime.Now;
                                                }

                                                catch (Exception ex)
                                                {
                                                    exceptionMsgs.Add(string.Format("An exception occurred calculating events for the '{0}' suggestion type:{1}    {2}", eventType.Name, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                                                    ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // send notificatons
                    var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read(rockContext).GetValue("ExternalApplicationRoot");

                    var possibleRecipients = new PersonService(rockContext)
                                             .Queryable().AsNoTracking()
                                             .Where(p => personSubscriptions.Keys.Contains(p.Id))
                                             .ToList();

                    // Loop through the possible recipients that actually subscribe to events
                    foreach (var personSubscription in personSubscriptions)
                    {
                        // Get the recipient person
                        int personId = personSubscription.Key;
                        var person   = possibleRecipients.Where(p => p.Id == personId).FirstOrDefault();
                        if (person != null)
                        {
                            try
                            {
                                // Make sure person is actually following anything
                                if (personFollowings.ContainsKey(personId))
                                {
                                    // Dictionary to store the entities that had an event for each event type
                                    var personEventTypeNotices = new List <FollowingEventTypeNotices>();

                                    // Get the event types that person subscribes to
                                    foreach (var eventType in eventsThatHappened.Where(e => personSubscription.Value.Contains(e.Key)))
                                    {
                                        // Get the EntityTypeId for this event type
                                        int entityTypeId = eventTypes
                                                           .Where(e => e.Id == eventType.Key)
                                                           .Select(e => e.FollowedEntityTypeId.Value)
                                                           .FirstOrDefault();

                                        // Find all the entities with this event type that the person follows
                                        var personFollowedEntityIds = followings
                                                                      .Where(f =>
                                                                             personFollowings[personId].Contains(f.Id) &&
                                                                             f.EntityTypeId == entityTypeId)
                                                                      .Select(f => f.EntityId)
                                                                      .ToList();

                                        // Get any of those entities that had an event happen
                                        var personFollowedEntities = eventType.Value
                                                                     .Where(e => personFollowedEntityIds.Contains(e.Key))
                                                                     .ToList();

                                        // If any were found
                                        if (personFollowedEntities.Any())
                                        {
                                            // Add the entry
                                            var eventTypeObj = eventTypes.Where(e => e.Id == eventType.Key).FirstOrDefault();
                                            if (eventTypeObj != null)
                                            {
                                                personEventTypeNotices.Add(new FollowingEventTypeNotices(eventTypeObj, personFollowedEntities.Select(e => e.Value).ToList()));
                                            }
                                        }
                                    }

                                    // If there are any events for any of the entities that this person follows, send a notification
                                    if (personEventTypeNotices.Any())
                                    {
                                        // Send the notice
                                        var recipients  = new List <RecipientData>();
                                        var mergeFields = new Dictionary <string, object>();
                                        mergeFields.Add("Person", person);
                                        mergeFields.Add("EventTypes", personEventTypeNotices.OrderBy(e => e.EventType.Order).ToList());
                                        recipients.Add(new RecipientData(person.Email, mergeFields));
                                        Email.Send(systemEmailGuid.Value, recipients, appRoot);
                                        followingEventsSent++;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                exceptionMsgs.Add(string.Format("An exception occurred sending event notice to '{0}':{1}    {2}", person.FullName, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                                ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                            }
                        }
                    }
                }

                context.Result = string.Format("{0} following events emails sent", followingEventsSent);

                if (exceptionMsgs.Any())
                {
                    throw new Exception("One or more exceptions occurred calculating following events..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
                }
            }
        }
예제 #3
0
파일: AddStep.cs 프로젝트: waldo2590/Rock
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            errorMessages = new List <string>();
            var mergeFields = GetMergeFields(action);

            // Validate the person exists
            var personGuid = GetAttributeValue(action, AttributeKey.Person, true).AsGuidOrNull();

            if (!personGuid.HasValue)
            {
                errorMessages.Add("The person guid is required but was missing");
                return(LogMessagesForExit(action, errorMessages));
            }

            var personService = new PersonService(rockContext);
            var person        = personService.Queryable("Aliases").AsNoTracking()
                                .FirstOrDefault(p => p.Guid == personGuid.Value || p.Aliases.Any(pa => pa.Guid == personGuid.Value));

            if (person == null)
            {
                errorMessages.Add($"The person with the guid '{personGuid.Value}' was not found");
                return(LogMessagesForExit(action, errorMessages));
            }

            if (!person.PrimaryAliasId.HasValue)
            {
                errorMessages.Add($"{person.FullName} does not have a primary alias identifier");
                return(LogMessagesForExit(action, errorMessages));
            }

            // Validate the step type exists. Could be a step type id or a guid
            var stepType = GetStepType(rockContext, action, out var errorMessage);

            if (!errorMessage.IsNullOrWhiteSpace())
            {
                errorMessages.Add(errorMessage);
                return(LogMessagesForExit(action, errorMessages));
            }

            if (stepType == null)
            {
                errorMessages.Add("The step type could not be found");
                return(LogMessagesForExit(action, errorMessages));
            }

            // Validate the step status exists and is in the same program as the step type
            var stepStatus = GetStepStatus(stepType, action, out errorMessage);

            if (!errorMessage.IsNullOrWhiteSpace())
            {
                errorMessages.Add(errorMessage);
                return(LogMessagesForExit(action, errorMessages));
            }

            if (stepStatus == null)
            {
                errorMessages.Add("The step status could not be found");
                return(LogMessagesForExit(action, errorMessages));
            }

            // Get the start and end dates
            var startDate = GetLavaAttributeValue(action, AttributeKey.StartDate).AsDateTime() ?? RockDateTime.Now;
            var endDate   = GetLavaAttributeValue(action, AttributeKey.EndDate).AsDateTime();

            var campusAttributeValue = GetLavaAttributeValue(action, AttributeKey.Campus);
            var campusId             = campusAttributeValue.AsIntegerOrNull();
            var campusGuid           = campusAttributeValue.AsGuidOrNull();

            if (campusGuid != null)
            {
                var campus = CampusCache.Get(campusGuid.Value);
                if (campus != null)
                {
                    campusId = campus.Id;
                }
            }

            // The completed date is today or the end date if the status is a completed status
            var completedDate = stepStatus.IsCompleteStatus ? (endDate ?? RockDateTime.Now) : ( DateTime? )null;

            // Create the step object
            var step = new Step
            {
                StepTypeId        = stepType.Id,
                PersonAliasId     = person.PrimaryAliasId.Value,
                StartDateTime     = startDate,
                EndDateTime       = endDate,
                CompletedDateTime = completedDate,
                StepStatusId      = stepStatus.Id,
                CampusId          = campusId
            };

            // Validate the step
            if (!step.IsValid)
            {
                errorMessages.AddRange(step.ValidationResults.Select(a => a.ErrorMessage));
                return(LogMessagesForExit(action, errorMessages));
            }

            // Check if the step can be created because of Allow Multiple rules on the step type and also prerequisite requirements
            var stepService = new StepService(rockContext);
            var canAdd      = stepService.CanAdd(step, out errorMessage);

            if (!errorMessage.IsNullOrWhiteSpace())
            {
                errorMessages.Add(errorMessage);
            }
            else if (!canAdd)
            {
                errorMessages.Add("Cannot add the step for an unspecified reason");
            }
            else
            {
                try
                {
                    stepService.Add(step);
                    rockContext.SaveChanges();

                    SetCreatedItemAttribute(action, AttributeKey.StepAttribute, step, rockContext);
                }
                catch (Exception exception)
                {
                    errorMessages.Add($"Exception thrown: {exception.Message}");
                    ExceptionLogService.LogException(exception);
                }
            }

            return(LogMessagesForExit(action, errorMessages));
        }
예제 #4
0
파일: Gateway.cs 프로젝트: sjison/Rock
        /// <summary>
        /// Performs the final step of a three-step charge.
        /// </summary>
        /// <param name="financialGateway">The financial gateway.</param>
        /// <param name="resultQueryString">The result query string from step 2.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        public override FinancialTransaction ChargeStep3(FinancialGateway financialGateway, string resultQueryString, out string errorMessage)
        {
            errorMessage = string.Empty;

            try
            {
                var rootElement = GetRoot(financialGateway, "complete-action");
                rootElement.Add(new XElement("token-id", resultQueryString.Substring(10)));
                XDocument xdoc   = new XDocument(new XDeclaration("1.0", "UTF-8", "yes"), rootElement);
                var       result = PostToGateway(financialGateway, xdoc);

                if (result == null)
                {
                    errorMessage = "Invalid Response from NMI!";
                    return(null);
                }

                if (result.GetValueOrNull("result") != "1")
                {
                    errorMessage = result.GetValueOrNull("result-text");

                    string resultCodeMessage = GetResultCodeMessage(result);
                    if (resultCodeMessage.IsNotNullOrWhitespace())
                    {
                        errorMessage += string.Format(" ({0})", resultCodeMessage);
                    }

                    // write result error as an exception
                    ExceptionLogService.LogException(new Exception($"Error processing NMI transaction. Result Code:  {result.GetValueOrNull( "result-code" )} ({resultCodeMessage}). Result text: {result.GetValueOrNull( "result-text" )}. Card Holder Name: {result.GetValueOrNull( "first-name" )} {result.GetValueOrNull( "last-name" )}. Amount: {result.GetValueOrNull( "total-amount" )}. Transaction id: {result.GetValueOrNull( "transaction-id" )}. Descriptor: {result.GetValueOrNull( "descriptor" )}. Order description: {result.GetValueOrNull( "order-description" )}."));

                    return(null);
                }

                var transaction = new FinancialTransaction();
                transaction.TransactionCode        = result.GetValueOrNull("transaction-id");
                transaction.ForeignKey             = result.GetValueOrNull("customer-vault-id");
                transaction.FinancialPaymentDetail = new FinancialPaymentDetail();

                string ccNumber = result.GetValueOrNull("billing_cc-number");
                if (!string.IsNullOrWhiteSpace(ccNumber))
                {
                    // cc payment
                    var curType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD);
                    transaction.FinancialPaymentDetail.NameOnCardEncrypted   = Encryption.EncryptString($"{result.GetValueOrNull( "billing_first-name" )} {result.GetValueOrNull( "billing_last-name" )}");
                    transaction.FinancialPaymentDetail.CurrencyTypeValueId   = curType != null ? curType.Id : (int?)null;
                    transaction.FinancialPaymentDetail.CreditCardTypeValueId = CreditCardPaymentInfo.GetCreditCardType(ccNumber.Replace('*', '1').AsNumeric())?.Id;
                    transaction.FinancialPaymentDetail.AccountNumberMasked   = ccNumber.Masked(true);

                    string mmyy = result.GetValueOrNull("billing_cc-exp");
                    if (!string.IsNullOrWhiteSpace(mmyy) && mmyy.Length == 4)
                    {
                        transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = Encryption.EncryptString(mmyy.Substring(0, 2));
                        transaction.FinancialPaymentDetail.ExpirationYearEncrypted  = Encryption.EncryptString(mmyy.Substring(2, 2));
                    }
                }
                else
                {
                    // ach payment
                    var curType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH);
                    transaction.FinancialPaymentDetail.CurrencyTypeValueId = curType != null ? curType.Id : (int?)null;
                    transaction.FinancialPaymentDetail.AccountNumberMasked = result.GetValueOrNull("billing_account-number").Masked(true);
                }

                transaction.AdditionalLavaFields = new Dictionary <string, object>();
                foreach (var keyVal in result)
                {
                    transaction.AdditionalLavaFields.Add(keyVal.Key, keyVal.Value);
                }

                return(transaction);
            }

            catch (WebException webException)
            {
                string message = GetResponseMessage(webException.Response.GetResponseStream());
                errorMessage = webException.Message + " - " + message;
                return(null);
            }

            catch (Exception ex)
            {
                errorMessage = ex.Message;
                return(null);
            }
        }
        public MobilePage GetPage(int id, string parameter = "")
        {
            var person = GetPerson();

            if (!HttpContext.Current.Items.Contains("CurrentPerson"))
            {
                HttpContext.Current.Items.Add("CurrentPerson", person);
            }

            var pageCache = PageCache.Get(id);

            if (pageCache == null || !pageCache.IsAuthorized(Authorization.VIEW, person))
            {
                return(new MobilePage());
            }

            SavePageViewInteraction(pageCache, person);

            string theme      = pageCache.Layout.Site.Theme;
            string layout     = pageCache.Layout.FileName;
            string layoutPath = PageCache.FormatPath(theme, layout);

            Rock.Web.UI.RockPage cmsPage = (Rock.Web.UI.RockPage)BuildManager.CreateInstanceFromVirtualPath(layoutPath, typeof(Rock.Web.UI.RockPage));

            MobilePage mobilePage = new MobilePage();

            mobilePage.Layout    = AvalancheUtilities.GetLayout(pageCache.Layout.Name);
            mobilePage.Title     = pageCache.PageTitle;
            mobilePage.ShowTitle = pageCache.PageDisplayTitle;

            foreach (var attribute in pageCache.Attributes)
            {
                mobilePage.Attributes.Add(attribute.Key, pageCache.GetAttributeValue(attribute.Key));
            }
            foreach (var block in pageCache.Blocks)
            {
                if (block.IsAuthorized(Authorization.VIEW, person))
                {
                    var blockCache = BlockCache.Get(block.Id);
                    try
                    {
                        var control = ( RockBlock )cmsPage.TemplateControl.LoadControl(blockCache.BlockType.Path);
                        if (control is RockBlock && control is IMobileResource)
                        {
                            control.SetBlock(pageCache, blockCache);
                            var mobileResource = control as IMobileResource;
                            var mobileBlock    = mobileResource.GetMobile(parameter);
                            mobileBlock.BlockId = blockCache.Id;
                            mobileBlock.Zone    = blockCache.Zone;
                            mobilePage.Blocks.Add(mobileBlock);
                        }
                    }
                    catch (Exception e)
                    {
                        ExceptionLogService.LogException(e, HttpContext.Current);
                    }
                }
            }
            HttpContext.Current.Response.Headers.Set("TTL", pageCache.OutputCacheDuration.ToString());
            return(mobilePage);
        }
예제 #6
0
        /// <summary>
        /// Create new attempt records and return them in a list. All new attempts should be after the most recent successful attempt.
        /// </summary>
        /// <param name="streakTypeAchievementTypeCache">The streak type achievement type cache.</param>
        /// <param name="streak">The streak.</param>
        /// <param name="mostRecentSuccess">The most recent successful attempt.</param>
        /// <returns></returns>
        protected override List <StreakAchievementAttempt> CreateNewAttempts(StreakTypeAchievementTypeCache streakTypeAchievementTypeCache, Streak streak, StreakAchievementAttempt mostRecentSuccess)
        {
            var rockContext       = new RockContext();
            var streakTypeService = new StreakTypeService(rockContext);
            var streakTypeCache   = streakTypeAchievementTypeCache.StreakTypeCache;

            // Validate the attribute values
            var numberToAccumulate = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.NumberToAccumulate).AsInteger();

            if (numberToAccumulate <= 0)
            {
                ExceptionLogService.LogException($"AccumulativeAchievement.CreateNewAttempts cannot process because the NumberToAccumulate attribute is less than 1");
                return(null);
            }

            var attributeTimespanDays = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.TimespanInDays).AsIntegerOrNull();

            if (attributeTimespanDays.HasValue && attributeTimespanDays.Value <= 0)
            {
                ExceptionLogService.LogException($"AccumulativeAchievement.CreateNewAttempts cannot process because the TimespanInDays attribute is less than 1");
                return(null);
            }

            // Calculate the date range where new achievements can be validly found
            var attributeMinDate = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.StartDateTime).AsDateTime();
            var attributeMaxDate = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.EndDateTime).AsDateTime();
            var minDate          = CalculateMinDateForAchievementAttempt(streak.EnrollmentDate, mostRecentSuccess, attributeMinDate, numberToAccumulate);
            var maxDate          = CalculateMaxDateForAchievementAttempt(minDate, attributeMaxDate);

            // Track the attempts in a list that will be returned. The int is the streak count for that attempt
            var attempts      = new List <StreakAchievementAttempt>();
            var accumulations = new List <ComputedStreak>();

            // Define what happens for each bit in the date range
            bool iterationAction(int currentUnit, DateTime currentDate, bool hasOccurrence, bool hasEngagement, bool hasExclusion)
            {
                // If there is an engagement and a timespan, then this is a possible attempt. If there is no timespan then only one
                // attempt needs to be tracked at a time
                if (hasOccurrence && hasEngagement && (attributeTimespanDays.HasValue || !accumulations.Any()))
                {
                    accumulations.Add(new ComputedStreak(currentDate));
                }

                for (var i = accumulations.Count - 1; i >= 0; i--)
                {
                    var accumulation = accumulations[i];

                    if (hasOccurrence && hasEngagement)
                    {
                        // Increment the accumulation
                        accumulation.Count++;
                        accumulation.EndDate = currentDate;

                        // Check for a fulfilled attempt
                        if (accumulation.Count >= numberToAccumulate)
                        {
                            accumulations.Clear();

                            if (streakTypeAchievementTypeCache.AllowOverAchievement)
                            {
                                accumulations.Add(accumulation);
                                i = 0;
                            }
                            else
                            {
                                attempts.Add(GetAttempt(accumulation, numberToAccumulate, true));
                                break;
                            }
                        }
                    }

                    // If there is a timespan and this accumulation is too old, then the attempt is closed
                    if (attributeTimespanDays.HasValue)
                    {
                        var inclusiveAge = (currentDate - accumulation.StartDate).Days + 1;

                        if (inclusiveAge >= attributeTimespanDays.Value)
                        {
                            var timedOutAttempt = GetAttempt(accumulation, numberToAccumulate, true);
                            attempts.Add(timedOutAttempt);
                            accumulations.RemoveAt(i);

                            // Remove more recently started accumulations that started before the next valid start date (based
                            // on the deficiency of this timed out attempt)
                            var nextValidStartDate = CalculateMinDateForAchievementAttempt(streak.EnrollmentDate, timedOutAttempt, attributeMinDate, numberToAccumulate);

                            for (var j = accumulations.Count - 1; j >= i; j--)
                            {
                                var moreRecentAccumulation = accumulations[j];

                                if (moreRecentAccumulation.StartDate < nextValidStartDate)
                                {
                                    accumulations.RemoveAt(j);
                                }
                            }
                        }
                    }
                }

                return(false);
            }

            // Iterate through the streak date for the date range specified
            streakTypeService.IterateStreakMap(streakTypeCache, streak.PersonAliasId, minDate, maxDate, iterationAction, out var errorMessage);

            if (!errorMessage.IsNullOrWhiteSpace())
            {
                ExceptionLogService.LogException($"AccumulativeAchievement.CreateNewAttempts got an error calling StreakTypeService.IterateStreakMap: {errorMessage}");
                return(null);
            }

            // The longest leftover accumulation is an open attempt
            if (accumulations.Any())
            {
                var longestStreak = accumulations.First();
                attempts.Add(GetAttempt(longestStreak, numberToAccumulate, false));
            }

            return(attempts);
        }
예제 #7
0
        /// <summary>
        /// Handles the Click event of the btnMigrateScheduledTransactions control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void btnMigrateScheduledTransactions_Click(object sender, EventArgs e)
        {
            var rockContext = new RockContext();

            var binaryFileService = new BinaryFileService(rockContext);
            var binaryFileId      = fuScheduleImportFile.BinaryFileId;

            BinaryFile binaryFile = null;

            if (binaryFileId.HasValue)
            {
                binaryFile = binaryFileService.Get(binaryFileId.Value);
            }

            Dictionary <string, string> subscriptionImportRecordLookup = null;

            var importData = binaryFile.ContentsToString();

            StringReader stringReader = new StringReader(importData);
            CsvReader    csvReader    = new CsvReader(stringReader);

            csvReader.Configuration.HasHeaderRecord = false;

            subscriptionImportRecordLookup = csvReader.GetRecords <SubscriptionCustomerImportRecord>().ToDictionary(k => k.NMISubscriptionId, v => v.PiCustomerId);

            var financialGatewayService = new FinancialGatewayService(rockContext);
            var nmiFinancialGatewayId   = ddlNMIGateway.SelectedValue.AsInteger();
            var nmiFinancialGateway     = financialGatewayService.Get(nmiFinancialGatewayId);
            var nmiGatewayComponent     = nmiFinancialGateway.GetGatewayComponent();
            var piFinancialGatewayId    = ddlPiGateway.SelectedValue.AsInteger();
            var piFinancialGateway      = financialGatewayService.Get(piFinancialGatewayId);
            var piGatewayComponent      = piFinancialGateway.GetGatewayComponent() as IHostedGatewayComponent;

            var financialScheduledTransactionService = new FinancialScheduledTransactionService(rockContext);

            // Get the ScheduledTransaction with NoTracking. If we need to update it, we'll track it with a different rockContext then save it.
            // Limit to active subscriptions that have a NextPaymentDate (onetime or canceled schedules might not have a NextPaymentDate)
            var scheduledTransactions = financialScheduledTransactionService.Queryable().Where(a => a.FinancialGatewayId == nmiFinancialGatewayId & a.IsActive && a.NextPaymentDate.HasValue).AsNoTracking().ToList();

            var earliestPiStartDate = piGatewayComponent.GetEarliestScheduledStartDate(piFinancialGateway);
            var oneTimeFrequencyId  = DefinedValueCache.GetId(Rock.SystemGuid.DefinedValue.TRANSACTION_FREQUENCY_ONE_TIME.AsGuid());

            string errorMessage;

            var scheduledTransactionResultsBuilder = new StringBuilder();

            var scheduledTransactionCount    = scheduledTransactions.Count();
            var scheduledTransactionProgress = 0;

            // Migrating Scheduled Transactions might take a while. Each migrated Scheduled Payment may take a half second or so to create on the Pi Gateway.
            var importTask = new Task(() =>
            {
                // wait a little so the browser can render and start listening to events
                Task.Delay(1000).Wait();
                _hubContext.Clients.All.setButtonVisibilty(this.SignalRNotificationKey, false);

                foreach (var scheduledTransaction in scheduledTransactions)
                {
                    System.Threading.Thread.Sleep(1000);

                    UpdateProgressMessage(string.Format("Migrating Scheduled Transactions: {0} of {1}", scheduledTransactionProgress, scheduledTransactionCount), " ");

                    scheduledTransactionProgress++;
                    var nmiSubscriptionId = scheduledTransaction.GatewayScheduleId;
                    var nmiCustomerId     = scheduledTransaction.ForeignKey;
                    var piCustomerId      = subscriptionImportRecordLookup.GetValueOrNull(nmiSubscriptionId);
                    if (piCustomerId == null)
                    {
                        scheduledTransactionResultsBuilder.AppendFormat(
                            "WARNING: No Pi CustomerId found for Financial Scheduled Transaction with Id: {0} which is associated NMI SubscriptionId: '{1}'" + Environment.NewLine,
                            scheduledTransaction.Id,
                            nmiSubscriptionId
                            );
                        continue;
                    }

                    // Pi requires that NextPaymentDate is in the Future (using UTC). That math is done in the gateway implementation...
                    // if the NextPayment null or earlier than whatever Pi considers the earliest start date, see if we can fix that up by calling GetStatus
                    if (scheduledTransaction.NextPaymentDate == null || scheduledTransaction.NextPaymentDate < earliestPiStartDate)
                    {
                        financialScheduledTransactionService.GetStatus(scheduledTransaction, out errorMessage);
                    }

                    if (scheduledTransaction.NextPaymentDate == null)
                    {
                        // Shouldn't happen, but just in case
                        scheduledTransactionResultsBuilder.AppendFormat(
                            "WARNING: Unknown NextPaymentDate for FinancialScheduledTransaction.Id: {0} NMI SubscriptionId: '{1}'" + Environment.NewLine,
                            scheduledTransaction.Id,
                            nmiSubscriptionId
                            );
                        continue;
                    }


                    if (scheduledTransaction.NextPaymentDate < earliestPiStartDate)
                    {
                        if ((scheduledTransaction.NextPaymentDate > RockDateTime.Today) && earliestPiStartDate.Subtract(scheduledTransaction.NextPaymentDate.Value).TotalDays <= 2)
                        {
                            // if the NextPaymentDate is after Today but before the Earliest Pi Start Date, it'll be off by less than 24 hrs, so just reschedule it for the Earliest Pi Start Date
                            scheduledTransaction.NextPaymentDate = earliestPiStartDate;
                        }
                        else
                        {
                            // if the NextPaymentDate is still too early AFTER getting the most recent status, then we can't safely figure it out, so report it
                            scheduledTransactionResultsBuilder.AppendFormat(
                                "WARNING: NextPaymentDate of {0} for FinancialScheduledTransaction.Id: {1} and NMI SubscriptionId: '{2}' must have a NextPaymentDate of at least {3}." + Environment.NewLine,
                                scheduledTransaction.NextPaymentDate,
                                scheduledTransaction.Id,
                                nmiSubscriptionId,
                                earliestPiStartDate
                                );
                        }
                    }

                    // create a subscription in the Pi System, then cancel the one on the NMI system
                    PaymentSchedule paymentSchedule = new PaymentSchedule
                    {
                        TransactionFrequencyValue = DefinedValueCache.Get(scheduledTransaction.TransactionFrequencyValueId),
                        StartDate = scheduledTransaction.NextPaymentDate.Value,
                        PersonId  = scheduledTransaction.AuthorizedPersonAlias.PersonId
                    };

                    ReferencePaymentInfo referencePaymentInfo = new ReferencePaymentInfo
                    {
                        GatewayPersonIdentifier = piCustomerId,
                        Description             = string.Format("Migrated from NMI SubscriptionID:{0}", nmiSubscriptionId)
                    };

                    var piGateway = (piGatewayComponent as PiGateway);
                    string alreadyMigratedPiSubscriptionId = null;

                    if (piGateway != null)
                    {
                        var customerPiSubscriptions     = piGateway.SearchCustomerSubscriptions(piFinancialGateway, piCustomerId);
                        alreadyMigratedPiSubscriptionId = customerPiSubscriptions.Data.Where(a => a.Description.Contains(referencePaymentInfo.Description)).Select(a => a.Customer.Id).FirstOrDefault();
                    }

                    if (string.IsNullOrEmpty(alreadyMigratedPiSubscriptionId))
                    {
                        // hasn't already been migrated, so go ahead and migrate it
                        var tempFinancialScheduledTransaction = piGatewayComponent.AddScheduledPayment(piFinancialGateway, paymentSchedule, referencePaymentInfo, out errorMessage);
                        if (tempFinancialScheduledTransaction != null)
                        {
                            ////////////#### DISABLE this when debugger #####
                            nmiGatewayComponent.CancelScheduledPayment(scheduledTransaction, out errorMessage);

                            // update the scheduled transaction to point to the Pi scheduled transaction
                            using (var updateRockContext = new RockContext())
                            {
                                // Attach the person to the updateRockContext so that it'll be tracked/saved using updateRockContext
                                updateRockContext.FinancialScheduledTransactions.Attach(scheduledTransaction);
                                scheduledTransaction.TransactionCode    = tempFinancialScheduledTransaction.TransactionCode;
                                scheduledTransaction.GatewayScheduleId  = tempFinancialScheduledTransaction.GatewayScheduleId;
                                scheduledTransaction.FinancialGatewayId = tempFinancialScheduledTransaction.FinancialGatewayId;
                                updateRockContext.SaveChanges();
                            }

                            scheduledTransactionResultsBuilder.AppendFormat(
                                "SUCCESS: Scheduled Transaction migration succeeded. (FinancialScheduledTransaction.Id: {0}, NMI SubscriptionId: '{1}', Pi CustomerId: {2}, Pi SubscriptionId: {3})" + Environment.NewLine,
                                scheduledTransaction.Id,
                                nmiSubscriptionId,
                                piCustomerId,
                                scheduledTransaction.GatewayScheduleId
                                );
                        }
                        else
                        {
                            scheduledTransactionResultsBuilder.AppendFormat(
                                "ERROR: Scheduled Transaction migration failed. ErrorMessage: {0}, FinancialScheduledTransaction.Id: {1}, NMI SubscriptionId: '{2}', Pi CustomerId: {3}" + Environment.NewLine,
                                errorMessage,
                                scheduledTransaction.Id,
                                nmiSubscriptionId,
                                piCustomerId
                                );
                        }
                    }
                    else
                    {
                        scheduledTransactionResultsBuilder.AppendFormat(
                            "INFO: Scheduled Transaction already migrated to PI. FinancialScheduledTransaction.Id: {0}, NMI SubscriptionId: '{1}', Pi SubscriptionId: '{2}', Pi CustomerId: {3}" + Environment.NewLine,
                            scheduledTransaction.Id,
                            nmiSubscriptionId,
                            alreadyMigratedPiSubscriptionId,
                            piCustomerId
                            );
                    }
                }
            });

            string importResult = string.Empty;

            importTask.ContinueWith((c) =>
            {
                if (c.Exception != null)
                {
                    ExceptionLogService.LogException(c.Exception);
                    scheduledTransactionResultsBuilder.AppendLine(string.Format("EXCEPTION: {0}", c.Exception.Flatten().Message));
                    importResult = "EXCEPTION";
                    UpdateProgressMessage(importResult, scheduledTransactionResultsBuilder.ToString());
                }
                else
                {
                    importResult = "Migrate Scheduled Transactions Completed Successfully";
                    UpdateProgressMessage(importResult, scheduledTransactionResultsBuilder.ToString());
                }

                this.SetBlockUserPreference("MigrateScheduledTransactionsResultSummary", importResult);
                this.SetBlockUserPreference("MigrateScheduledTransactionsResultDetails", scheduledTransactionResultsBuilder.ToString());
            });

            importTask.Start();

            nbMigrateScheduledTransactions.Visible = false;

            // wait for 5 seconds to see if this happens fast enough to do without Signal R. Otherwise, let the importTask continue and send progress to Signal R.
            var waitResult = importTask.Wait(5000);

            if (waitResult)
            {
                // wait just a little bit to make sure the importResult gets set
                System.Threading.Thread.Sleep(1000);

                nbMigrateScheduledTransactions.Visible             = true;
                nbMigrateScheduledTransactions.Title               = "Success";
                nbMigrateScheduledTransactions.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Success;

                var resultDetails = scheduledTransactionResultsBuilder.ToString();
                if (resultDetails.Contains("ERROR") || resultDetails.Contains("WARNING"))
                {
                    nbMigrateScheduledTransactions.Title = "Completed with Warnings";
                    nbMigrateScheduledTransactions.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Info;
                }

                nbMigrateScheduledTransactions.Text    = importResult;
                nbMigrateScheduledTransactions.Details = resultDetails.ConvertCrLfToHtmlBr();
            }
        }
        /// <summary>
        /// Sends the specified rock message.
        /// </summary>
        /// <param name="rockMessage">The rock message.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Send(RockMessage rockMessage, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes, out List <string> errorMessages)
        {
            errorMessages = new List <string>();

            var emailMessage = rockMessage as RockEmailMessage;

            if (emailMessage != null)
            {
                // Common Merge Field
                var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, rockMessage.CurrentPerson);
                foreach (var mergeField in rockMessage.AdditionalMergeFields)
                {
                    mergeFields.AddOrReplace(mergeField.Key, mergeField.Value);
                }

                string fromAddress = emailMessage.FromEmail;
                string fromName    = emailMessage.FromName;

                // Resolve any possible merge fields in the from address
                fromAddress = fromAddress.ResolveMergeFields(mergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands);
                fromName    = fromName.ResolveMergeFields(mergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands);

                // From - if none is set, use the one in the Organization's GlobalAttributes.
                var globalAttributes = GlobalAttributesCache.Get();
                if (string.IsNullOrWhiteSpace(fromAddress))
                {
                    fromAddress = globalAttributes.GetValue("OrganizationEmail");
                }

                if (string.IsNullOrWhiteSpace(fromName))
                {
                    fromName = globalAttributes.GetValue("OrganizationName");
                }

                if (fromAddress.IsNullOrWhiteSpace())
                {
                    errorMessages.Add("A From address was not provided and no Organization email address is configured.");
                    return(false);
                }

                MailMessage message = new MailMessage();

                // Reply To
                try
                {
                    if (emailMessage.ReplyToEmail.IsNotNullOrWhiteSpace())
                    {
                        // Resolve any possible merge fields in the replyTo address
                        message.ReplyToList.Add(new MailAddress(emailMessage.ReplyToEmail.ResolveMergeFields(mergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands)));
                    }
                }
                catch { }

                message.IsBodyHtml = true;
                message.Priority   = MailPriority.Normal;

                using (var smtpClient = GetSmtpClient())
                {
                    foreach (var recipientData in rockMessage.GetRecipientData())
                    {
                        try
                        {
                            foreach (var mergeField in mergeFields)
                            {
                                recipientData.MergeFields.AddOrIgnore(mergeField.Key, mergeField.Value);
                            }

                            message.To.Clear();
                            message.CC.Clear();
                            message.Bcc.Clear();
                            message.Headers.Clear();

                            // Set From/To and check safe sender
                            message.From = new MailAddress(fromAddress, fromName);
                            message.To.Add(new MailAddress(
                                               recipientData.To.ResolveMergeFields(recipientData.MergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands),
                                               recipientData.Name.ResolveMergeFields(recipientData.MergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands)));
                            CheckSafeSender(message, globalAttributes);

                            // cc
                            foreach (string cc in emailMessage.CCEmails.Where(e => e != ""))
                            {
                                // Resolve any possible merge fields in the cc address
                                string ccRecipient = cc.ResolveMergeFields(recipientData.MergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands);
                                message.CC.Add(new MailAddress(ccRecipient));
                            }

                            // bcc
                            foreach (string bcc in emailMessage.BCCEmails.Where(e => e != ""))
                            {
                                // Resolve any possible merge fields in the cc address
                                string bccRecipient = bcc.ResolveMergeFields(recipientData.MergeFields, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands);
                                message.Bcc.Add(new MailAddress(bccRecipient));
                            }

                            // Subject
                            string subject = ResolveText(emailMessage.Subject, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands, recipientData.MergeFields, emailMessage.AppRoot, emailMessage.ThemeRoot);

                            // Body
                            string body = ResolveText(emailMessage.Message, emailMessage.CurrentPerson, emailMessage.EnabledLavaCommands, recipientData.MergeFields, emailMessage.AppRoot, emailMessage.ThemeRoot);
                            body = Regex.Replace(body, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty);

                            message.Subject = subject.Left(998);
                            message.Body    = body;

                            var metaData = new Dictionary <string, string>(emailMessage.MessageMetaData);

                            // If a communication is going to get created, create a guid for tracking the opens/clicks
                            Guid?recipientGuid = null;
                            if (emailMessage.CreateCommunicationRecord)
                            {
                                recipientGuid = Guid.NewGuid();
                                metaData.Add("communication_recipient_guid", recipientGuid.Value.ToString());
                            }

                            using (var rockContext = new RockContext())
                            {
                                // Recreate the attachments
                                message.Attachments.Clear();
                                if (emailMessage.Attachments.Any())
                                {
                                    var binaryFileService = new BinaryFileService(rockContext);
                                    foreach (var binaryFileId in emailMessage.Attachments.Where(a => a != null).Select(a => a.Id))
                                    {
                                        var attachment = binaryFileService.Get(binaryFileId);
                                        if (attachment != null)
                                        {
                                            message.Attachments.Add(new Attachment(attachment.ContentStream, attachment.FileName));
                                        }
                                    }
                                }

                                AddAdditionalHeaders(message, metaData);

                                smtpClient.Send(message);
                            }

                            if (emailMessage.CreateCommunicationRecord)
                            {
                                var transaction = new SaveCommunicationTransaction(recipientData.To, emailMessage.FromName, emailMessage.FromName, subject, body);
                                transaction.RecipientGuid = recipientGuid;
                                RockQueue.TransactionQueue.Enqueue(transaction);
                            }
                        }
                        catch (Exception ex)
                        {
                            errorMessages.Add(ex.Message);
                            ExceptionLogService.LogException(ex);
                        }
                    }
                }
            }

            return(!errorMessages.Any());
        }
        /// <summary>
        /// Sends the specified communication.
        /// </summary>Medi
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        public override void Send(Rock.Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable()
                                .Include(a => a.CreatedByPersonAlias.Person)
                                .Include(a => a.CommunicationTemplate)
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();

                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (!hasPendingRecipients)
                {
                    return;
                }

                var    currentPerson      = communication.CreatedByPersonAlias?.Person;
                var    globalAttributes   = GlobalAttributesCache.Get();
                string publicAppRoot      = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                var    mergeFields        = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);
                var    cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false;

                string fromAddress = communication.FromEmail;
                string fromName    = communication.FromName;

                // Resolve any possible merge fields in the from address
                fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);
                fromName    = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);

                // From - if none is set, use the one in the Organization's GlobalAttributes.
                if (string.IsNullOrWhiteSpace(fromAddress))
                {
                    fromAddress = globalAttributes.GetValue("OrganizationEmail");
                }

                if (string.IsNullOrWhiteSpace(fromName))
                {
                    fromName = globalAttributes.GetValue("OrganizationName");
                }

                MailMessage message = new MailMessage();

                // Reply To
                try
                {
                    string replyTo = communication.ReplyToEmail;
                    if (!string.IsNullOrWhiteSpace(replyTo))
                    {
                        // Resolve any possible merge fields in the replyTo address
                        message.ReplyToList.Add(new MailAddress(replyTo.ResolveMergeFields(mergeFields, currentPerson)));
                    }
                }
                catch { }

                message.IsBodyHtml = true;
                message.Priority   = MailPriority.Normal;

                using (var smtpClient = GetSmtpClient())
                {
                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid();

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Rock.Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                try
                                {
                                    message.To.Clear();
                                    message.CC.Clear();
                                    message.Bcc.Clear();
                                    message.Headers.Clear();
                                    message.AlternateViews.Clear();

                                    // Set From/To and check safe sender
                                    message.From = new MailAddress(fromAddress, fromName);
                                    message.To.Add(new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName));
                                    CheckSafeSender(message, globalAttributes);

                                    // Create merge field dictionary
                                    var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                    // CC
                                    string cc = communication.CCEmails;
                                    if (!string.IsNullOrWhiteSpace(cc))
                                    {
                                        // Resolve any possible merge fields in the cc address
                                        cc = cc.ResolveMergeFields(mergeObjects, currentPerson);
                                        foreach (string ccRecipient in cc.SplitDelimitedValues())
                                        {
                                            message.CC.Add(new MailAddress(ccRecipient));
                                        }
                                    }

                                    // BCC
                                    string bcc = communication.BCCEmails;
                                    if (!string.IsNullOrWhiteSpace(bcc))
                                    {
                                        bcc = bcc.ResolveMergeFields(mergeObjects, currentPerson);
                                        foreach (string bccRecipient in bcc.SplitDelimitedValues())
                                        {
                                            // Resolve any possible merge fields in the bcc address
                                            message.Bcc.Add(new MailAddress(bccRecipient));
                                        }
                                    }

                                    // Subject
                                    message.Subject = ResolveText(communication.Subject, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                    // Plain text
                                    if (mediumAttributes.ContainsKey("DefaultPlainText"))
                                    {
                                        string plainText = ResolveText(mediumAttributes["DefaultPlainText"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        if (!string.IsNullOrWhiteSpace(plainText))
                                        {
                                            AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainText, new System.Net.Mime.ContentType(MediaTypeNames.Text.Plain));
                                            message.AlternateViews.Add(plainTextView);
                                        }
                                    }

                                    // Add Html view
                                    // Get the unsubscribe content and add a merge field for it
                                    string htmlBody = communication.Message;
                                    if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML"))
                                    {
                                        string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        mergeObjects.AddOrReplace("UnsubscribeOption", unsubscribeHtml);
                                        htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                        // Resolve special syntax needed if option was included in global attribute
                                        if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]"))
                                        {
                                            htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml);
                                        }

                                        // Add the unsubscribe option at end if it wasn't included in content
                                        if (!htmlBody.Contains(unsubscribeHtml))
                                        {
                                            htmlBody += unsubscribeHtml;
                                        }
                                    }
                                    else
                                    {
                                        htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty);
                                    }

                                    if (!string.IsNullOrWhiteSpace(htmlBody))
                                    {
                                        if (cssInliningEnabled)
                                        {
                                            // move styles inline to help it be compatible with more email clients
                                            htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes();
                                        }

                                        // add the main Html content to the email
                                        AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Html));
                                        message.AlternateViews.Add(htmlView);
                                    }

                                    // Add any additional headers that specific SMTP provider needs
                                    var metaData = new Dictionary <string, string>();
                                    metaData.Add("communication_recipient_guid", recipient.Guid.ToString());
                                    AddAdditionalHeaders(message, metaData);

                                    // Recreate the attachments
                                    message.Attachments.Clear();
                                    foreach (var binaryFile in communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile))
                                    {
                                        message.Attachments.Add(new Attachment(binaryFile.ContentStream, binaryFile.FileName));
                                    }

                                    smtpClient.Send(message);
                                    recipient.Status = CommunicationRecipientStatus.Delivered;

                                    string statusNote = StatusNote;
                                    if (!string.IsNullOrWhiteSpace(statusNote))
                                    {
                                        recipient.StatusNote = statusNote;
                                    }

                                    recipient.TransportEntityTypeName = this.GetType().FullName;

                                    try
                                    {
                                        var historyChangeList = new History.HistoryChangeList();
                                        historyChangeList.AddChange(
                                            History.HistoryVerb.Sent,
                                            History.HistoryChangeType.Record,
                                            $"Communication")
                                        .SetRelatedData(message.From.DisplayName, communicationEntityTypeId, communication.Id)
                                        .SetCaption(message.Subject);

                                        HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId);
                                    }
                                    catch (Exception ex)
                                    {
                                        ExceptionLogService.LogException(ex, null);
                                    }
                                }

                                catch (Exception ex)
                                {
                                    ExceptionLogService.LogException(ex);
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => ");
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string serverKey = GetAttributeValue("ServerKey");
                    var    sender    = new Sender(serverKey);

                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                try
                                {
                                    int personAlias = recipient.PersonAliasId;

                                    var           service = new PersonalDeviceService(recipientRockContext);
                                    List <string> devices = service.Queryable()
                                                            .Where(p => p.PersonAliasId.HasValue && p.PersonAliasId.Value == personAlias && p.NotificationsEnabled)
                                                            .Select(p => p.DeviceRegistrationId)
                                                            .ToList();

                                    if (devices != null)
                                    {
                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                        var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var title   = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var sound   = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                        var notification = new Message
                                        {
                                            RegistrationIds = devices.Distinct().ToList(),
                                            Notification    = new FCM.Net.Notification
                                            {
                                                Title = title,
                                                Body  = message,
                                                Sound = sound,
                                            }
                                        };

                                        ResponseContent response = Utility.AsyncHelpers.RunSync(() => sender.SendAsync(notification));

                                        bool failed = response.MessageResponse.Failure == devices.Count;
                                        var  status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered;

                                        if (failed)
                                        {
                                            recipient.StatusNote = "Firebase failed to notify devices";
                                        }
                                        else
                                        {
                                            recipient.SendDateTime = RockDateTime.Now;
                                        }

                                        recipient.Status = status;
                                        recipient.TransportEntityTypeName = this.GetType().FullName;
                                        recipient.UniqueMessageId         = response.MessageResponse.MulticastId;

                                        try
                                        {
                                            var historyService = new HistoryService(recipientRockContext);
                                            historyService.Add(new History
                                            {
                                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                EntityTypeId           = personEntityTypeId,
                                                CategoryId             = communicationCategoryId,
                                                EntityId            = recipient.PersonAlias.PersonId,
                                                Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                ValueName           = "Push Notification",
                                                Caption             = message.Truncate(200),
                                                RelatedEntityTypeId = communicationEntityTypeId,
                                                RelatedEntityId     = communication.Id
                                            });
                                        }
                                        catch (Exception ex)
                                        {
                                            ExceptionLogService.LogException(ex, null);
                                        }
                                    }
                                    else
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "No Personal Devices with Messaging Enabled";
                                    }
                                }
                                catch (Exception ex)
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "Firebase Exception: " + ex.Message;
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Gets the payments that have been processed for any scheduled transactions
        /// </summary>
        /// <param name="gateway">The gateway.</param>
        /// <param name="startDate">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        public override List <Payment> GetPayments(FinancialGateway gateway, DateTime startDate, DateTime endDate, out string errorMessage)
        {
            var today             = RockDateTime.Now;
            var lookupContext     = new RockContext();
            var accountLookup     = new FinancialAccountService(lookupContext);
            var transactionLookup = new FinancialTransactionService(lookupContext);
            var donationUrl       = GetBaseUrl(gateway, "donations", out errorMessage);
            var supporterUrl      = GetBaseUrl(gateway, "sponsorship_supporters", out errorMessage);
            var categoryUrl       = GetBaseUrl(gateway, "donation_categories", out errorMessage);
            var projectsUrl       = GetBaseUrl(gateway, "projects", out errorMessage);

            if (donationUrl.IsNullOrWhiteSpace() || supporterUrl.IsNullOrWhiteSpace())
            {
                // errorMessage already set
                return(null);
            }

            var authenticator = GetAuthenticator(gateway, out errorMessage);

            if (authenticator == null)
            {
                // errorMessage already set
                return(null);
            }

            var reachAccountMaps   = DefinedTypeCache.Get(GetAttributeValue(gateway, "AccountMap")).DefinedValues;
            var connectionStatus   = DefinedValueCache.Get(GetAttributeValue(gateway, "PersonStatus"));
            var reachSourceType    = DefinedValueCache.Get(GetAttributeValue(gateway, "SourceType"));
            var defaultAccount     = accountLookup.Get(GetAttributeValue(gateway, "DefaultAccount").AsGuid());
            var updatePrimaryEmail = GetAttributeValue(gateway, "UpdatePrimaryEmail").AsBoolean();

            if (connectionStatus == null || reachAccountMaps == null || reachSourceType == null || defaultAccount == null)
            {
                errorMessage = "The Reach Account Map, Person Status, Source Type, or Default Account is not configured correctly in gateway settings.";
                return(null);
            }

            var currentPage             = 1;
            var queryHasResults         = true;
            var skippedTransactionCount = 0;
            var errorMessages           = new List <string>();
            var newTransactions         = new List <FinancialTransaction>();
            var categoryResult          = Api.PostRequest(categoryUrl, authenticator, null, out errorMessage);
            var categories    = JsonConvert.DeserializeObject <List <Reporting.Category> >(categoryResult.ToStringSafe());
            var projectResult = Api.PostRequest(projectsUrl, authenticator, null, out errorMessage);
            var projects      = JsonConvert.DeserializeObject <List <Reporting.Project> >(projectResult.ToStringSafe());

            if (categories == null)
            {
                // errorMessage already set
                return(null);
            }

            while (queryHasResults)
            {
                var parameters = new Dictionary <string, string>
                {
                    { "from_date", startDate.ToString("yyyy-MM-dd") },
                    { "to_date", endDate.ToString("yyyy-MM-dd") },
                    { "per_page", "50" },
                    { "page", currentPage.ToString() }
                };

                // to_date doesn't have a timestamp, so it includes transactions posted after the cutoff
                var donationResult = Api.PostRequest(donationUrl, authenticator, parameters, out errorMessage);
                var donations      = JsonConvert.DeserializeObject <List <Donation> >(donationResult.ToStringSafe());
                if (donations != null && donations.Any() && errorMessage.IsNullOrWhiteSpace())
                {
                    // only process completed transactions with confirmation codes and within the date range
                    foreach (var donation in donations.Where(d => d.updated_at >= startDate && d.updated_at < endDate && d.status.Equals("complete") && d.confirmation.IsNotNullOrWhiteSpace()))
                    {
                        var transaction = transactionLookup.Queryable()
                                          .FirstOrDefault(t => t.FinancialGatewayId.HasValue &&
                                                          t.FinancialGatewayId.Value == gateway.Id &&
                                                          t.TransactionCode == donation.confirmation);
                        if (transaction == null)
                        {
                            // find or create this person asynchronously for performance
                            var personAlias = Api.FindPersonAsync(lookupContext, donation, connectionStatus.Id, updatePrimaryEmail);

                            var reachAccountName = string.Empty;
                            var donationItem     = donation.line_items.FirstOrDefault();
                            if (donationItem != null && donationItem.referral_type.Equals("DonationOption", StringComparison.InvariantCultureIgnoreCase))
                            {
                                // one-time gift, should match a known category
                                var category = categories.FirstOrDefault(c => c.id == donationItem.referral_id);
                                if (category != null)
                                {
                                    reachAccountName = category.title.Trim();
                                }
                            }
                            else if (donationItem != null && donationItem.referral_type.Equals("Project", StringComparison.InvariantCultureIgnoreCase))
                            {
                                // one-time gift, should match a known project
                                var project = projects.FirstOrDefault(c => c.id == donationItem.referral_id);
                                if (project != null)
                                {
                                    reachAccountName = string.Format("PROJECT {0}", project.title.Trim());
                                }
                            }
                            else
                            {
                                // recurring gift, lookup the sponsor info
                                var referralId       = donation.referral_id ?? donationItem.referral_id;
                                var supporterResults = Api.PostRequest(string.Format("{0}/{1}", supporterUrl, referralId), authenticator, null, out errorMessage);
                                var supporter        = JsonConvert.DeserializeObject <Supporter>(supporterResults.ToStringSafe());
                                if (supporter != null)
                                {
                                    var place           = supporter.sponsorship?.place?.title;
                                    var sponsorshipType = supporter.sponsorship?.sponsorship_type_title;
                                    var shareType       = supporter.share_type_id;

                                    string shareTypeName;
                                    switch (shareType)
                                    {
                                    case "668":
                                        shareTypeName = "Primary";
                                        break;

                                    case "669":
                                        shareTypeName = "Secondary";
                                        break;

                                    default:
                                        shareTypeName = string.Empty;
                                        break;
                                    }

                                    reachAccountName = string.Format("{0} {1} {2}", place, sponsorshipType, shareTypeName).Trim();
                                }
                            }

                            int?rockAccountId  = defaultAccount.Id;
                            var accountMapping = reachAccountMaps.FirstOrDefault(v => v.Value.Equals(reachAccountName, StringComparison.CurrentCultureIgnoreCase));
                            if (accountMapping != null)
                            {
                                var accountGuid = accountMapping.GetAttributeValue("RockAccount").AsGuidOrNull();
                                if (accountGuid.HasValue)
                                {
                                    rockAccountId = accountLookup.Get(( Guid )accountGuid).Id;
                                }
                            }

                            // verify person alias was found or created
                            personAlias.Wait();
                            if (!personAlias.Result.HasValue)
                            {
                                var infoMessage = string.Format("{0} Reach import skipped {1} {2}'s donation {3} for {4} because their record could not be found or created",
                                                                endDate.ToString("d"), donation.first_name, donation.last_name, donation.confirmation, reachAccountName);
                                ExceptionLogService.LogException(new Exception(infoMessage), null);
                                continue;
                            }

                            // create the transaction
                            var summary = string.Format("Reach Donation for {0} from {1} using {2} on {3} ({4})",
                                                        reachAccountName, donation.name, donation.payment_method, donation.updated_at, donation.token);
                            transaction = new FinancialTransaction
                            {
                                TransactionDateTime    = donation.updated_at,
                                ProcessedDateTime      = donation.updated_at,
                                TransactionCode        = donation.confirmation,
                                Summary                = summary,
                                SourceTypeValueId      = reachSourceType.Id,
                                TransactionTypeValueId = contributionTypeId,
                                Guid                    = Guid.NewGuid(),
                                CreatedDateTime         = today,
                                ModifiedDateTime        = today,
                                AuthorizedPersonAliasId = personAlias.Result.Value,
                                FinancialGatewayId      = gateway.Id,
                                ForeignId               = donation.id,
                                FinancialPaymentDetail  = new FinancialPaymentDetail(),
                                TransactionDetails      = new List <FinancialTransactionDetail>
                                {
                                    new FinancialTransactionDetail
                                    {
                                        AccountId        = (int)rockAccountId,
                                        Amount           = (decimal)donation.amount,
                                        Summary          = summary,
                                        Guid             = Guid.NewGuid(),
                                        CreatedDateTime  = today,
                                        ModifiedDateTime = today
                                    }
                                }
                            };

                            newTransactions.Add(transaction);
                        }
                        else if (transaction != null)
                        {
                            skippedTransactionCount++;
                        }
                    }
                }
                else
                {
                    queryHasResults = false;
                }

                currentPage++;
            }

            if (skippedTransactionCount > 0)
            {
                ExceptionLogService.LogException(new Exception(string.Format("{0} Reach import skipped downloading {1} transactions because they already exist",
                                                                             endDate.ToString("d"), skippedTransactionCount)), null);
            }

            if (newTransactions.Any())
            {
                using (var rockContext = new RockContext())
                {
                    // create batch and add transactions
                    var batchPrefix = GetAttributeValue(gateway, "BatchPrefix");
                    var batchDate   = newTransactions.GroupBy(t => t.TransactionDateTime.Value.Date).OrderByDescending(t => t.Count())
                                      .Select(g => g.Key).FirstOrDefault();
                    var batch = new FinancialBatchService(rockContext).GetByNameAndDate(string.Format("{0} {1}",
                                                                                                      batchPrefix, batchDate.ToString("d")), endDate, gateway.GetBatchTimeOffset());
                    batch.BatchStartDateTime = batchDate;
                    batch.BatchEndDateTime   = endDate;
                    batch.Note           = string.Format("{0} transactions downloaded starting {1} to {2}", batchPrefix, startDate, endDate);
                    batch.ControlAmount += newTransactions.Select(t => t.TotalAmount).Sum();

                    var currentChanges = 0;
                    foreach (var transaction in newTransactions)
                    {
                        // save in large batches so it doesn't overload context
                        batch.Transactions.Add(transaction);
                        if (currentChanges++ > 100)
                        {
                            rockContext.SaveChanges(disablePrePostProcessing: true);
                            currentChanges = 0;
                        }
                    }

                    // by default Rock associates with the current person
                    rockContext.SaveChanges(disablePrePostProcessing: true);
                }
            }

            if (errorMessages.Any())
            {
                errorMessage = string.Join("<br>", errorMessages);
            }

            return(new List <Payment>());
        }
예제 #12
0
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid()
        {
            var rockContext = new RockContext();

            var communications = new CommunicationService(rockContext)
                                 .Queryable().AsNoTracking()
                                 .Where(c => c.Status != CommunicationStatus.Transient);

            string subject = tbSubject.Text;

            if (!string.IsNullOrWhiteSpace(subject))
            {
                communications = communications.Where(c => (string.IsNullOrEmpty(c.Subject) && c.Name.Contains(subject)) || c.Subject.Contains(subject));
            }

            var communicationType = ddlType.SelectedValueAsEnumOrNull <CommunicationType>();

            if (communicationType != null)
            {
                communications = communications.Where(c => c.CommunicationType == communicationType);
            }

            string status = ddlStatus.SelectedValue;

            if (!string.IsNullOrWhiteSpace(status))
            {
                var communicationStatus = ( CommunicationStatus )System.Enum.Parse(typeof(CommunicationStatus), status);
                communications = communications.Where(c => c.Status == communicationStatus);
            }

            if (canApprove)
            {
                if (ppSender.PersonId.HasValue)
                {
                    communications = communications
                                     .Where(c =>
                                            c.SenderPersonAlias != null &&
                                            c.SenderPersonAlias.PersonId == ppSender.PersonId.Value);
                }
            }
            else
            {
                // If can't approve, only show current person's communications
                communications = communications
                                 .Where(c =>
                                        c.SenderPersonAlias != null &&
                                        c.SenderPersonAlias.PersonId == CurrentPersonId);
            }

            if (drpCreatedDates.LowerValue.HasValue)
            {
                communications = communications.Where(a => a.CreatedDateTime.HasValue && a.CreatedDateTime.Value >= drpCreatedDates.LowerValue.Value);
            }

            if (drpCreatedDates.UpperValue.HasValue)
            {
                DateTime upperDate = drpCreatedDates.UpperValue.Value.Date.AddDays(1);
                communications = communications.Where(a => a.CreatedDateTime.HasValue && a.CreatedDateTime.Value < upperDate);
            }

            if (drpSentDates.LowerValue.HasValue)
            {
                communications = communications.Where(a => (a.SendDateTime ?? a.FutureSendDateTime) >= drpSentDates.LowerValue.Value);
            }

            if (drpSentDates.UpperValue.HasValue)
            {
                DateTime upperDate = drpSentDates.UpperValue.Value.Date.AddDays(1);
                communications = communications.Where(a => (a.SendDateTime ?? a.FutureSendDateTime) < upperDate);
            }

            string content = tbContent.Text;

            if (!string.IsNullOrWhiteSpace(content))
            {
                communications = communications.Where(c =>
                                                      c.Message.Contains(content) ||
                                                      c.SMSMessage.Contains(content) ||
                                                      c.PushMessage.Contains(content));
            }

            var recipients = new CommunicationRecipientService(rockContext).Queryable();

            // We want to limit to only communications that they are authorized to view, but if there are a large number of communications, that could be very slow.
            // So, since communication security is based on CommunicationTemplate, take a shortcut and just limit based on authorized communication templates
            var authorizedCommunicationTemplateIds = new CommunicationTemplateService(rockContext).Queryable()
                                                     .Where(a => communications.Where(x => x.CommunicationTemplateId.HasValue).Select(x => x.CommunicationTemplateId.Value).Distinct().Contains(a.Id))
                                                     .ToList().Where(a => a.IsAuthorized(Rock.Security.Authorization.VIEW, this.CurrentPerson)).Select(a => a.Id).ToList();

            var queryable = communications.Where(a => a.CommunicationTemplateId == null || authorizedCommunicationTemplateIds.Contains(a.CommunicationTemplateId.Value))
                            .Select(c => new CommunicationItem
            {
                Id = c.Id,
                CommunicationType = c.CommunicationType,
                // Subject = string.IsNullOrEmpty( c.Subject ) ? c.Name : c.Subject,
                Subject             = string.IsNullOrEmpty(c.Name) ? (string.IsNullOrEmpty(c.Subject) ? c.PushTitle : c.Subject) : c.Name,
                CreatedDateTime     = c.CreatedDateTime,
                SendDateTime        = c.SendDateTime ?? c.FutureSendDateTime,
                SendDateTimePrefix  = c.SendDateTime == null && c.FutureSendDateTime != null ? "<span class='label label-info'>Future</span>&nbsp;" : "",
                Sender              = c.SenderPersonAlias != null ? c.SenderPersonAlias.Person : null,
                ReviewedDateTime    = c.ReviewedDateTime,
                Reviewer            = c.ReviewerPersonAlias != null ? c.ReviewerPersonAlias.Person : null,
                Status              = c.Status,
                Recipients          = recipients.Where(r => r.CommunicationId == c.Id).Count(),
                PendingRecipients   = recipients.Where(r => r.CommunicationId == c.Id && r.Status == CommunicationRecipientStatus.Pending).Count(),
                CancelledRecipients = recipients.Where(r => r.CommunicationId == c.Id && r.Status == CommunicationRecipientStatus.Cancelled).Count(),
                FailedRecipients    = recipients.Where(r => r.CommunicationId == c.Id && r.Status == CommunicationRecipientStatus.Failed).Count(),
                DeliveredRecipients = recipients.Where(r => r.CommunicationId == c.Id && (r.Status == CommunicationRecipientStatus.Delivered || r.Status == CommunicationRecipientStatus.Opened)).Count(),
                OpenedRecipients    = recipients.Where(r => r.CommunicationId == c.Id && r.Status == CommunicationRecipientStatus.Opened).Count()
            });

            var sortProperty = gCommunication.SortProperty;

            if (sortProperty != null)
            {
                queryable = queryable.Sort(sortProperty);
            }
            else
            {
                queryable = queryable.OrderByDescending(c => c.SendDateTime);
            }

            gCommunication.EntityTypeId = EntityTypeCache.Get <Rock.Model.Communication>().Id;
            nbBindError.Text            = string.Empty;

            try
            {
                gCommunication.SetLinqDataSource(queryable);
                gCommunication.DataBind();
            }
            catch (Exception e)
            {
                ExceptionLogService.LogException(e);

                Exception sqlException = e;
                while (sqlException != null && !(sqlException is System.Data.SqlClient.SqlException))
                {
                    sqlException = sqlException.InnerException;
                }

                nbBindError.Text = string.Format("<p>An error occurred trying to retrieve the communication history. Please try adjusting your filter settings and try again.</p><p>Error: {0}</p>",
                                                 sqlException != null ? sqlException.Message : e.Message);

                gCommunication.DataSource = new List <object>();
                gCommunication.DataBind();
            }
        }
예제 #13
0
        /// <summary>
        /// Enables processing of HTTP Web requests by a custom <see langword="HttpHandler" /> that implements the <see cref="T:System.Web.IHttpHandler" /> interface.
        /// </summary>
        /// <param name="context">An <see cref="T:System.Web.HttpContext" /> object that provides references to the intrinsic server objects (for example, <see langword="Request" />, <see langword="Response" />, <see langword="Session" />, and <see langword="Server" />) used to service HTTP requests.</param>
        public void ProcessRequest(HttpContext context)
        {
            // see https://sandbox.gotnpgateway.com/docs/webhooks/#core-webhook-response-format for example payload
            HttpRequest request  = context.Request;
            var         response = context.Response;

            response.ContentType = "text/plain";

            // Signature https://sandbox.gotnpgateway.com/docs/webhooks/#security
            // see signature @ https://sandbox.fluidpay.com/merchant/settings/webhooks/search
            var postedSignature = request.Headers["Signature"];

            string postedData = string.Empty;

            using (var reader = new StreamReader(request.InputStream))
            {
                postedData = reader.ReadToEnd();
            }

            var cardSyncWebhookResponse = postedData.FromJsonOrNull <CardSyncWebhookResponse>();

            if (cardSyncWebhookResponse == null)
            {
                response.StatusCode        = ( int )HttpStatusCode.BadRequest;
                response.StatusDescription = "Unable to determine response format.";
                return;
            }

            var paymentMethodData = cardSyncWebhookResponse.PaymentMethodData;

            if (paymentMethodData == null)
            {
                response.StatusCode        = ( int )HttpStatusCode.BadRequest;
                response.StatusDescription = "Unable to determine payment method 'data'.";
                return;
            }

            var rockContext = new RockContext();
            FinancialPersonSavedAccountService financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext);
            var financialPersonSavedAccountQuery = financialPersonSavedAccountService.Queryable()
                                                   .Where(a => a.GatewayPersonIdentifier == paymentMethodData.RecordId || a.FinancialPaymentDetail.GatewayPersonIdentifier == paymentMethodData.RecordId);

            var savedAccounts = financialPersonSavedAccountQuery.Include(a => a.FinancialPaymentDetail).Include(a => a.FinancialGateway).ToList();

            // There probably is only one saved account for the GatewayPersonIdentifier, but just in case, we'll loop thru.
            foreach (var savedAccount in savedAccounts)
            {
                var financialGateway = savedAccount.FinancialGateway;
                var myWellGateway    = savedAccount.FinancialGateway?.GetGatewayComponent() as MyWellGateway;
                if (myWellGateway == null)
                {
                    ExceptionLogService.LogException(new MyWellGatewayException($"Unable to determine Gateway for CardSync GatewayPersonIdentifier: {paymentMethodData.RecordId} and FinancialGatewayId: {savedAccount.FinancialGatewayId}"));

                    response.StatusCode        = ( int )HttpStatusCode.BadRequest;
                    response.StatusDescription = $"Unable to find matching financial gateway record for recordId: {paymentMethodData.RecordId}";
                    return;
                }

                financialGateway.LoadAttributes();
                var validSignature = myWellGateway.VerifySignature(financialGateway, postedSignature, postedData);
                if (!validSignature)
                {
                    ExceptionLogService.LogException(new MyWellGatewayException($"Invalid WebHook signature included in header. (PostedData for RecordId: {paymentMethodData.RecordId} and FinancialGatewayId: {savedAccount.FinancialGatewayId})"));
                    response.StatusCode        = ( int )HttpStatusCode.Forbidden;
                    response.StatusDescription = "Invalid WebHook signature included in header";
                    return;
                }

                var financialPaymentDetail = savedAccount.FinancialPaymentDetail;
                if (financialPaymentDetail == null)
                {
                    // shouldn't happen
                    continue;
                }

                if (paymentMethodData.ExpirationDate.IsNotNullOrWhiteSpace() && paymentMethodData.ExpirationDate.Length == 5)
                {
                    // now that we validated this is a 5 char string (MM/YY), extract MM and YY as integers
                    financialPaymentDetail.ExpirationMonth = paymentMethodData.ExpirationDate.Substring(0, 2).AsIntegerOrNull();
                    financialPaymentDetail.ExpirationYear  = paymentMethodData.ExpirationDate.Substring(3, 2).AsIntegerOrNull();

                    // ToDo: See if they send us the CreditCardType (visa, mastercard)
                    // ?? financialPaymentDetail.CreditCardTypeValueId
                }

                financialPaymentDetail.AccountNumberMasked = paymentMethodData.MaskedNumber;
                rockContext.SaveChanges();
            }

            // NOTE: If it takes us more than 5 seconds to respond, they'll retry.
            // Otherwise, if we respond with a 200, they'll assume we processed it.
            // See https://sandbox.gotnpgateway.com/docs/webhooks/#acknowledge-and-retry for additional details
            response.StatusCode = ( int )HttpStatusCode.OK;
        }
예제 #14
0
        public HttpResponseMessage Family(string param)
        {
            try
            {
                var session = HttpContext.Current.Session;

                var localDeviceConfigCookie = HttpContext.Current.Request.Cookies[CheckInCookieKey.LocalDeviceConfig].Value;
                var localDevice             = localDeviceConfigCookie.FromJsonOrNull <LocalDeviceConfiguration>();

                var  currentKioskId      = localDevice.CurrentKioskId.Value;
                Guid blockGuid           = ( Guid )session["BlockGuid"];
                var  currentCheckInState = new CheckInState(currentKioskId, localDevice.CurrentCheckinTypeId, localDevice.CurrentGroupTypeIds);
                currentCheckInState.CheckIn.UserEnteredSearch   = true;
                currentCheckInState.CheckIn.ConfirmSingleFamily = true;
                currentCheckInState.CheckIn.SearchType          = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CHECKIN_SEARCH_TYPE_PHONE_NUMBER);
                currentCheckInState.CheckIn.SearchValue         = param;

                var    rockContext      = new Rock.Data.RockContext();
                var    block            = BlockCache.Get(blockGuid);
                string workflowActivity = block.GetAttributeValue("WorkflowActivity");
                Guid?  workflowGuid     = block.GetAttributeValue("WorkflowType").AsGuidOrNull();

                List <string> errors;
                var           workflowService = new WorkflowService(rockContext);
                var           workflowType    = WorkflowTypeCache.Get(workflowGuid.Value);

                var CurrentWorkflow = Rock.Model.Workflow.Activate(workflowType, currentCheckInState.Kiosk.Device.Name, rockContext);

                var activityType = workflowType.ActivityTypes.Where(a => a.Name == workflowActivity).FirstOrDefault();
                if (activityType != null)
                {
                    WorkflowActivity.Activate(activityType, CurrentWorkflow, rockContext);
                    if (workflowService.Process(CurrentWorkflow, currentCheckInState, out errors))
                    {
                        if (errors.Any())
                        {
                            var innerException = new Exception(string.Join(" -- ", errors));
                            ExceptionLogService.LogException(new Exception("Process Mobile Checkin failed initial workflow. See inner exception for details.", innerException));
                        }

                        // Keep workflow active for continued processing
                        CurrentWorkflow.CompletedDateTime = null;
                        SaveState(session, currentCheckInState);
                        List <CheckInFamily> families = currentCheckInState.CheckIn.Families;
                        families = families.OrderBy(f => f.Caption).ToList();
                        return(ControllerContext.Request.CreateResponse(HttpStatusCode.OK, families));
                    }
                    else
                    {
                        if (errors.Any())
                        {
                            var innerException = new Exception(string.Join(" -- ", errors));
                            ExceptionLogService.LogException(new Exception("Process Mobile Checkin failed initial workflow. See inner exception for details.", innerException));
                        }
                        else
                        {
                            ExceptionLogService.LogException(new Exception("Process Mobile Checkin failed initial workflow. See inner exception for details."));
                        }
                    }
                }
                else
                {
                    return(ControllerContext.Request.CreateResponse(HttpStatusCode.InternalServerError, string.Format("Workflow type does not have a '{0}' activity type", workflowActivity)));
                }
                return(ControllerContext.Request.CreateResponse(HttpStatusCode.InternalServerError, String.Join("\n", errors)));
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(ex, HttpContext.Current);
                return(ControllerContext.Request.CreateResponse(HttpStatusCode.Forbidden, "Forbidden"));
            }
        }
예제 #15
0
        /// <summary>
        /// Creates the cache type mapping and analyzer.
        /// </summary>
        /// <param name="documentType">Type of the document.</param>
        /// <param name="deleteIfExists">if set to <c>true</c> [delete if exists].</param>
        public override void CreateIndex(Type documentType, bool deleteIfExists = true)
        {
            try
            {
                var indexName = documentType.Name.ToLower();

                object instance = Activator.CreateInstance(documentType);

                // Check if index already exists. If it exists, no need to create it again
                if (_indexes.ContainsKey(indexName))
                {
                    return;
                }

                Index index = new Index();

                // make sure this is an index document
                if (instance is IndexModelBase)
                {
                    Dictionary <string, TypeMappingProperties> typeMapping = new Dictionary <string, TypeMappingProperties>();
                    Dictionary <string, Analyzer> fieldAnalyzers           = new Dictionary <string, Analyzer>();

                    // get properties from the model and add them to the index (hint: attributes will be added dynamically as the documents are loaded)
                    var modelProperties = documentType.GetProperties();

                    foreach (var property in modelProperties)
                    {
                        var indexAttribute = property.GetCustomAttributes(typeof(RockIndexField), false);
                        if (indexAttribute.Length > 0)
                        {
                            var attribute = ( RockIndexField )indexAttribute[0];

                            var propertyName = property.Name;

                            // rewrite non-string index option (would be nice if they made the enums match up...)
                            if (attribute.Type != IndexFieldType.String)
                            {
                                if (attribute.Index == IndexType.NotIndexed)
                                {
                                    continue;
                                }
                            }

                            var typeMappingProperty = new TypeMappingProperties();
                            typeMappingProperty.Name  = propertyName;
                            typeMappingProperty.Boost = ( float )attribute.Boost;

                            switch (attribute.Type)
                            {
                            case IndexFieldType.Boolean:
                            case IndexFieldType.Date:
                            case IndexFieldType.Number:
                            {
                                typeMappingProperty.IndexType = IndexType.NotAnalyzed;
                                typeMappingProperty.Analyzer  = string.Empty;
                                break;
                            }

                            default:
                            {
                                typeMappingProperty.IndexType = attribute.Index;
                                if (!string.IsNullOrWhiteSpace(attribute.Analyzer))
                                {
                                    typeMappingProperty.Analyzer = attribute.Analyzer;
                                }

                                break;
                            }
                            }

                            typeMapping.Add(propertyName, typeMappingProperty);

                            if (typeMappingProperty.Analyzer?.ToLowerInvariant() == "snowball")
                            {
                                fieldAnalyzers[typeMappingProperty.Name] = Analyzer.NewAnonymous(createComponents: (fieldName, reader) =>
                                {
                                    var tokenizer = new StandardTokenizer(_matchVersion, reader);
                                    var sbpff     = new SnowballPorterFilterFactory(new Dictionary <string, string>()
                                    {
                                        { "language", "English" }
                                    });
                                    sbpff.Inform(new ClasspathResourceLoader(documentType));
                                    TokenStream result = sbpff.Create(new StandardTokenizer(_matchVersion, reader));
                                    return(new TokenStreamComponents(tokenizer, result));  // https://github.com/apache/lucenenet/blob/master/src/Lucene.Net.Analysis.Common/Analysis/Snowball/SnowballAnalyzer.cs
                                });
                            }
                            else if (typeMappingProperty.Analyzer?.ToLowerInvariant() == "whitespace")
                            {
                                fieldAnalyzers[propertyName] = Analyzer.NewAnonymous(createComponents: (fieldName, reader) =>
                                {
                                    var tokenizer      = new WhitespaceTokenizer(_matchVersion, reader);
                                    TokenStream result = new StandardFilter(_matchVersion, tokenizer);
                                    return(new TokenStreamComponents(tokenizer, result));
                                });
                            }
                        }
                    }

                    index.MappingProperties = typeMapping;
                    index.FieldAnalyzers    = fieldAnalyzers;
                    _indexes[indexName]     = index;
                }
            }
            catch (Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
            }
        }
 /// <summary>
 /// Shows the error message.
 /// </summary>
 /// <param name="ex">The ex.</param>
 /// <param name="friendlyMessage">The friendly message.</param>
 private void ShowErrorMessage(Exception ex, string friendlyMessage)
 {
     nbErrorMessage.Text    = friendlyMessage;
     nbErrorMessage.Visible = true;
     ExceptionLogService.LogException(ex, this.Context);
 }
예제 #17
0
        /// <summary>
        /// Update the open attempt record if there are changes.
        /// </summary>
        /// <param name="openAttempt"></param>
        /// <param name="streakTypeAchievementTypeCache">The streak type achievement type cache.</param>
        /// <param name="streak">The streak.</param>
        protected override void UpdateOpenAttempt(StreakAchievementAttempt openAttempt, StreakTypeAchievementTypeCache streakTypeAchievementTypeCache, Streak streak)
        {
            var rockContext       = new RockContext();
            var streakTypeService = new StreakTypeService(rockContext);
            var streakTypeCache   = streakTypeAchievementTypeCache.StreakTypeCache;

            // Validate the attribute values
            var numberToAccumulate = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.NumberToAccumulate).AsInteger();

            if (numberToAccumulate <= 0)
            {
                ExceptionLogService.LogException($"AccumulativeAchievement.UpdateOpenAttempt cannot process because the NumberToAccumulate attribute is less than 1");
                return;
            }

            var attributeTimespanDays = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.TimespanInDays).AsIntegerOrNull();

            if (attributeTimespanDays.HasValue && attributeTimespanDays.Value <= 0)
            {
                ExceptionLogService.LogException($"AccumulativeAchievement.UpdateOpenAttempt cannot process because the TimespanInDays attribute is less than 1");
                return;
            }

            // Calculate the date range where the open attempt can be validly fulfilled
            var attributeMaxDate = GetAttributeValue(streakTypeAchievementTypeCache, AttributeKey.EndDateTime).AsDateTime();
            var minDate          = openAttempt.AchievementAttemptStartDateTime;
            var maxDate          = CalculateMaxDateForAchievementAttempt(minDate, attributeMaxDate);

            // Track the accumulation
            var accumulation = new ComputedStreak(minDate)
            {
                EndDate = minDate
            };

            // Define what happens for each bit in the date range
            bool iterationAction(int currentUnit, DateTime currentDate, bool hasOccurrence, bool hasEngagement, bool hasExclusion)
            {
                // If there is an engagement, then increment the accumulation
                if (hasOccurrence && hasEngagement)
                {
                    accumulation.Count++;
                    accumulation.EndDate = currentDate;

                    // Check for a fulfilled attempt
                    if (accumulation.Count >= numberToAccumulate)
                    {
                        var progress = CalculateProgress(accumulation.Count, numberToAccumulate);

                        openAttempt.AchievementAttemptEndDateTime = accumulation.EndDate;
                        openAttempt.Progress     = progress;
                        openAttempt.IsClosed     = !streakTypeAchievementTypeCache.AllowOverAchievement;
                        openAttempt.IsSuccessful = progress >= 1m;
                    }
                }

                // If there is a timespan and this accumulation is too old, then the attempt is closed
                if (attributeTimespanDays.HasValue)
                {
                    var inclusiveAge = (currentDate - accumulation.StartDate).Days + 1;

                    if (inclusiveAge >= attributeTimespanDays.Value)
                    {
                        var progress = CalculateProgress(accumulation.Count, numberToAccumulate);

                        openAttempt.AchievementAttemptEndDateTime = accumulation.EndDate;
                        openAttempt.Progress     = progress;
                        openAttempt.IsClosed     = true;
                        openAttempt.IsSuccessful = progress >= 1m;
                    }
                }

                return(openAttempt.IsClosed);
            }

            // Iterate through the streak date for the date range specified
            streakTypeService.IterateStreakMap(streakTypeCache, streak.PersonAliasId, minDate, maxDate, iterationAction, out var errorMessage);

            if (!errorMessage.IsNullOrWhiteSpace())
            {
                ExceptionLogService.LogException($"AccumulativeAchievement.UpdateOpenAttempt got an error calling StreakTypeService.IterateStreakMap: {errorMessage}");
                return;
            }

            // If the attempt wasn't closed in the iteration, then it will remain open
            if (!openAttempt.IsClosed)
            {
                var progress = CalculateProgress(accumulation.Count, numberToAccumulate);

                openAttempt.Progress     = progress;
                openAttempt.IsSuccessful = progress >= 1m;
            }
        }
예제 #18
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            JobDataMap       dataMap             = context.JobDetail.JobDataMap;
            StringBuilder    results             = new StringBuilder();
            int              updatedDatasetCount = 0;
            int              updatedDatasetTotalCount;
            var              errors     = new List <string>();
            List <Exception> exceptions = new List <Exception>();

            using (var rockContext = new RockContext())
            {
                var currentDateTime = RockDateTime.Now;

                var persistedDatasetQuery = new PersistedDatasetService(rockContext).Queryable();
                updatedDatasetTotalCount = persistedDatasetQuery.Count();

                // exclude datasets that are no longer active
                persistedDatasetQuery = persistedDatasetQuery.Where(a => a.IsActive && (a.ExpireDateTime == null || a.ExpireDateTime > currentDateTime));

                // exclude datasets that are already up-to-date based on the Refresh Interval and LastRefreshTime
                persistedDatasetQuery = persistedDatasetQuery
                                        .Where(a =>
                                               a.LastRefreshDateTime == null ||
                                               (System.Data.Entity.SqlServer.SqlFunctions.DateAdd("mi", a.RefreshIntervalMinutes.Value, a.LastRefreshDateTime.Value) < currentDateTime));

                var expiredPersistedDatasetsList = persistedDatasetQuery.ToList();
                foreach (var persistedDataset in expiredPersistedDatasetsList)
                {
                    var name = persistedDataset.Name;
                    try
                    {
                        context.UpdateLastStatusMessage($"Updating {persistedDataset.Name}");
                        persistedDataset.UpdateResultData();
                        rockContext.SaveChanges();
                        updatedDatasetCount++;
                    }
                    catch (Exception ex)
                    {
                        // Capture and log the exception because we're not going to fail this job
                        // unless all the data views fail.
                        var errorMessage = $"An error occurred while trying to update persisted dataset '{name}' so it was skipped. Error: {ex.Message}";
                        errors.Add(errorMessage);
                        var ex2 = new Exception(errorMessage, ex);
                        exceptions.Add(ex2);
                        ExceptionLogService.LogException(ex2, null);
                        continue;
                    }
                }
            }

            int notUpdatedCount = updatedDatasetTotalCount - updatedDatasetCount;

            // Format the result message
            results.AppendLine($"Updated {updatedDatasetCount} {"persisted dataset".PluralizeIf( updatedDatasetCount != 1 )}.");
            if (notUpdatedCount > 0)
            {
                results.AppendLine($"Skipped {notUpdatedCount} {"persisted dataset".PluralizeIf( updatedDatasetCount != 1 )} that are already up-to-date or inactive.");
            }
            context.Result = results.ToString();

            if (errors.Any())
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine();
                sb.Append("Errors: ");
                errors.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                string errorMessage = sb.ToString();
                context.Result += errorMessage;
                // We're not going to throw an aggregate exception unless there were no successes.
                // Otherwise the status message does not show any of the success messages in
                // the last status message.
                if (updatedDatasetCount == 0)
                {
                    throw new AggregateException(exceptions.ToArray());
                }
            }
        }
예제 #19
0
파일: GroupSync.cs 프로젝트: philltran/Rock
        /// <summary>
        /// Job that will sync groups.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            // Get the job setting(s)
            JobDataMap dataMap = context.JobDetail.JobDataMap;
            bool       requirePasswordReset = dataMap.GetBoolean("RequirePasswordReset");

            // Counters for displaying results
            int groupsSynced  = 0;
            int groupsChanged = 0;

            try
            {
                // get groups set to sync
                var groupIdsThatSync = new List <int>();
                using (var rockContext = new RockContext())
                {
                    groupIdsThatSync = new GroupService(rockContext)
                                       .Queryable().AsNoTracking()
                                       .Where(g => g.SyncDataViewId != null)
                                       .Select(a => a.Id)
                                       .ToList();
                }

                foreach (var syncGroupId in groupIdsThatSync)
                {
                    bool hasGroupChanged = false;

                    // Use a fresh rockContext per group so that ChangeTracker doesn't get bogged down
                    using (var rockContext = new RockContext())
                    {
                        // increase the timeout just in case the dataview source is slow
                        rockContext.Database.CommandTimeout = 180;

                        // Get the Group
                        var syncGroup = new GroupService(rockContext)
                                        .Queryable().AsNoTracking()
                                        .FirstOrDefault(t => t.Id == syncGroupId);

                        // Ensure that the group's Sync Data View is a person dataview
                        if (syncGroup.SyncDataView.EntityTypeId == EntityTypeCache.Read(typeof(Person)).Id)
                        {
                            List <string> errorMessages = new List <string>();

                            // Get the person id's from the dataview (source)
                            var personService       = new PersonService(rockContext);
                            var parameterExpression = personService.ParameterExpression;
                            var whereExpression     = syncGroup.SyncDataView.GetExpression(personService, parameterExpression, out errorMessages);
                            var sourcePersonIds     = new PersonService(rockContext)
                                                      .Get(parameterExpression, whereExpression)
                                                      .Select(q => q.Id)
                                                      .ToList();

                            // Get the person id's in the group (target)
                            var targetPersonIds = new GroupMemberService(rockContext)
                                                  .Queryable().AsNoTracking()
                                                  .Where(gm => gm.GroupId == syncGroup.Id)
                                                  .Select(gm => gm.PersonId)
                                                  .ToList();

                            // Delete people from the group that are no longer in the dataview
                            foreach (var personId in targetPersonIds.Where(t => !sourcePersonIds.Contains(t)))
                            {
                                // Use a new context to limit the amount of change-tracking required
                                using (var groupMemberContext = new RockContext())
                                {
                                    // Delete any group members with the person id
                                    var groupMemberService = new GroupMemberService(groupMemberContext);
                                    foreach (var groupMember in groupMemberService
                                             .Queryable()
                                             .Where(m =>
                                                    m.GroupId == syncGroupId &&
                                                    m.PersonId == personId)
                                             .ToList())
                                    {
                                        groupMemberService.Delete(groupMember);
                                    }
                                    groupMemberContext.SaveChanges();

                                    // If the Group has an exit email, and person has an email address, send them the exit email
                                    if (syncGroup.ExitSystemEmail != null)
                                    {
                                        var person = new PersonService(groupMemberContext).Get(personId);
                                        if (person.Email.IsNotNullOrWhitespace())
                                        {
                                            // Send the exit email
                                            var mergeFields = new Dictionary <string, object>();
                                            mergeFields.Add("Group", syncGroup);
                                            mergeFields.Add("Person", person);
                                            var emailMessage = new RockEmailMessage(syncGroup.ExitSystemEmail);
                                            emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields));
                                            emailMessage.Send();
                                        }
                                    }
                                }

                                hasGroupChanged = true;
                            }

                            // Add people to the group that are in the dataview and not currently in the group
                            int groupRoleId = syncGroup.GroupType.DefaultGroupRoleId ?? syncGroup.GroupType.Roles.FirstOrDefault().Id;
                            foreach (var personId in sourcePersonIds.Where(s => !targetPersonIds.Contains(s)))
                            {
                                // Use a new context to limit the amount of change-tracking required
                                using (var groupMemberContext = new RockContext())
                                {
                                    // Add new person to the group
                                    var groupMemberService = new GroupMemberService(groupMemberContext);
                                    var newGroupMember     = new GroupMember {
                                        Id = 0
                                    };
                                    newGroupMember.PersonId          = personId;
                                    newGroupMember.GroupId           = syncGroup.Id;
                                    newGroupMember.GroupMemberStatus = GroupMemberStatus.Active;
                                    newGroupMember.GroupRoleId       = groupRoleId;
                                    groupMemberService.Add(newGroupMember);
                                    groupMemberContext.SaveChanges();

                                    // If the Group has a welcome email, and person has an email address, send them the welcome email and possibly create a login
                                    if (syncGroup.WelcomeSystemEmail != null)
                                    {
                                        var person = new PersonService(groupMemberContext).Get(personId);
                                        if (person.Email.IsNotNullOrWhitespace())
                                        {
                                            // If the group is configured to add a user account for anyone added to the group, and person does not yet have an
                                            // account, add one for them.
                                            string newPassword = string.Empty;
                                            bool   createLogin = syncGroup.AddUserAccountsDuringSync ?? false;
                                            if (createLogin && !person.Users.Any())
                                            {
                                                newPassword = System.Web.Security.Membership.GeneratePassword(9, 1);
                                                string username = Rock.Security.Authentication.Database.GenerateUsername(person.NickName, person.LastName);

                                                UserLogin login = UserLoginService.Create(
                                                    groupMemberContext,
                                                    person,
                                                    AuthenticationServiceType.Internal,
                                                    EntityTypeCache.Read(Rock.SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid()).Id,
                                                    username,
                                                    newPassword,
                                                    true,
                                                    requirePasswordReset);
                                            }

                                            // Send the welcome email
                                            var mergeFields = new Dictionary <string, object>();
                                            mergeFields.Add("Group", syncGroup);
                                            mergeFields.Add("Person", person);
                                            mergeFields.Add("NewPassword", newPassword);
                                            mergeFields.Add("CreateLogin", createLogin);
                                            var emailMessage = new RockEmailMessage(syncGroup.WelcomeSystemEmail);
                                            emailMessage.AddRecipient(new RecipientData(person.Email, mergeFields));
                                            emailMessage.Send();
                                        }
                                    }
                                }

                                hasGroupChanged = true;
                            }

                            // Increment Groups Changed Counter (if people were deleted or added to the group)
                            if (hasGroupChanged)
                            {
                                groupsChanged++;
                            }

                            // Increment the Groups Synced Counter
                            groupsSynced++;

                            // If the group changed, and it was a security group, flush the security for the group
                            if (hasGroupChanged && (syncGroup.IsSecurityRole || syncGroup.GroupType.Guid.Equals(Rock.SystemGuid.GroupType.GROUPTYPE_SECURITY_ROLE.AsGuid())))
                            {
                                Rock.Security.Role.Flush(syncGroup.Id);
                            }
                        }
                    }
                }

                // Format the result message
                var resultMessage = string.Empty;
                if (groupsSynced == 0)
                {
                    resultMessage = "No groups to sync";
                }
                else if (groupsSynced == 1)
                {
                    resultMessage = "1 group was sync'ed";
                }
                else
                {
                    resultMessage = string.Format("{0} groups were sync'ed", groupsSynced);
                }
                resultMessage += string.Format(" and {0} groups were changed", groupsChanged);
                context.Result = resultMessage;
            }
            catch (System.Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
                throw;
            }
        }
예제 #20
0
        /// <summary>
        /// Provides an end method for an asynchronous process.
        /// </summary>
        /// <param name="result">An IAsyncResult that contains information about the status of the process.</param>
        public void EndProcessRequest(IAsyncResult result)
        {
            // restore the context from the asyncResult.AsyncState
            HttpContext context = (HttpContext)result.AsyncState;

            try
            {
                context.Response.Clear();

                bool isBinaryFile = (bool)context.Items["isBinaryFile"];

                if (isBinaryFile)
                {
                    var rockContext = new RockContext();

                    bool       requiresViewSecurity = false;
                    BinaryFile binaryFile           = new BinaryFileService(rockContext).EndGet(result, context, out requiresViewSecurity);
                    if (binaryFile != null)
                    {
                        //// if the binaryFile's BinaryFileType requires security, check security
                        //// note: we put a RequiresViewSecurity flag on BinaryFileType because checking security for every file would be slow (~40ms+ per request)
                        if (requiresViewSecurity)
                        {
                            var    currentUser   = new UserLoginService(rockContext).GetByUserName(UserLogin.GetCurrentUserName());
                            Person currentPerson = currentUser != null ? currentUser.Person : null;
                            binaryFile.BinaryFileType = binaryFile.BinaryFileType ?? new BinaryFileTypeService(rockContext).Get(binaryFile.BinaryFileTypeId.Value);
                            if (!binaryFile.IsAuthorized(Authorization.VIEW, currentPerson))
                            {
                                SendNotAuthorized(context);
                                return;
                            }
                        }

                        SendFile(context, binaryFile.ContentStream, binaryFile.MimeType, binaryFile.FileName, binaryFile.Guid.ToString("N"));
                        return;
                    }
                }
                else
                {
                    Stream fileContents            = (Stream)context.Items["fileContents"];
                    string physicalContentFileName = context.Items["physicalContentFileName"] as string;

                    if (fileContents != null)
                    {
                        string mimeType = System.Web.MimeMapping.GetMimeMapping(physicalContentFileName);
                        string fileName = Path.GetFileName(physicalContentFileName);
                        SendFile(context, fileContents, mimeType, fileName, "");
                        return;
                    }
                }

                context.Response.StatusCode        = 404;
                context.Response.StatusDescription = "Unable to find the requested file.";
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(ex, context);
                try
                {
                    context.Response.StatusCode        = 500;
                    context.Response.StatusDescription = ex.Message;
                    context.Response.Flush();
                    context.ApplicationInstance.CompleteRequest();
                }
                catch (Exception ex2)
                {
                    ExceptionLogService.LogException(ex2, context);
                }
            }
        }
예제 #21
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            var expireDays = dataMap.GetString("ExpireDate").AsIntegerOrNull() ?? 1;

            int remindersSent = 0;
            var errors        = new List <string>();

            using (var rockContext = new RockContext())
            {
                DateTime now        = RockDateTime.Now;
                DateTime expireDate = now.AddDays(expireDays * -1);

                foreach (var instance in new RegistrationInstanceService(rockContext)
                         .Queryable("RegistrationTemplate,Registrations")
                         .Where(i =>
                                i.IsActive &&
                                i.RegistrationTemplate.IsActive &&
                                i.RegistrationTemplate.ReminderEmailTemplate != string.Empty &&
                                !i.ReminderSent &&
                                i.SendReminderDateTime.HasValue &&
                                i.SendReminderDateTime <= now &&
                                i.SendReminderDateTime >= expireDate)
                         .ToList())
                {
                    var template = instance.RegistrationTemplate;

                    foreach (var registration in instance.Registrations
                             .Where(r =>
                                    !r.IsTemporary &&
                                    r.ConfirmationEmail != null &&
                                    r.ConfirmationEmail != string.Empty))
                    {
                        try
                        {
                            var mergeFields = new Dictionary <string, object>();
                            mergeFields.Add("RegistrationInstance", registration.RegistrationInstance);
                            mergeFields.Add("Registration", registration);

                            var emailMessage = new RockEmailMessage();
                            emailMessage.AdditionalMergeFields = mergeFields;

                            emailMessage.AddRecipient(registration.GetConfirmationRecipient(mergeFields));

                            emailMessage.FromEmail = template.ReminderFromEmail;
                            emailMessage.FromName  = template.ReminderFromName;
                            emailMessage.Subject   = template.ReminderSubject;
                            emailMessage.Message   = template.ReminderEmailTemplate;

                            var emailErrors = new List <string>();
                            emailMessage.Send(out emailErrors);
                            errors.AddRange(emailErrors);
                        }
                        catch (Exception exception)
                        {
                            ExceptionLogService.LogException(exception);
                            continue;
                        }
                    }

                    // Even if an error occurs, still mark as completed to prevent _everyone_ being sent the reminder multiple times due to a single failing address


                    instance.SendReminderDateTime = now;
                    instance.ReminderSent         = true;
                    remindersSent++;

                    rockContext.SaveChanges();
                }

                if (remindersSent == 0)
                {
                    context.Result = "No reminders to send";
                }
                else if (remindersSent == 1)
                {
                    context.Result = "1 reminder was sent";
                }
                else
                {
                    context.Result = string.Format("{0} reminders were sent", remindersSent);
                }

                if (errors.Any())
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine();
                    sb.Append(string.Format("{0} Errors: ", errors.Count()));
                    errors.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                    string errorMessage = sb.ToString();
                    context.Result += errorMessage;
                    var         exception = new Exception(errorMessage);
                    HttpContext context2  = HttpContext.Current;
                    ExceptionLogService.LogException(exception, context2);
                    throw exception;
                }
            }
        }
예제 #22
0
파일: DbContext.cs 프로젝트: waldo2590/Rock
        /// <summary>
        /// Updates the Created/Modified data for any model being created or modified
        /// </summary>
        /// <param name="dbContext">The database context.</param>
        /// <param name="personAlias">The person alias.</param>
        /// <param name="enableAuditing">if set to <c>true</c> [enable auditing].</param>
        /// <returns></returns>
        protected virtual List <ContextItem> RockPreSave(DbContext dbContext, PersonAlias personAlias, bool enableAuditing = false)
        {
            int?personAliasId = null;

            if (personAlias != null)
            {
                personAliasId = personAlias.Id;
            }

            var preSavedEntities = new HashSet <Guid>();

            // First loop through all models calling the PreSaveChanges
            foreach (var entry in dbContext.ChangeTracker.Entries()
                     .Where(c =>
                            c.Entity is IEntity &&
                            (c.State == EntityState.Added || c.State == EntityState.Modified || c.State == EntityState.Deleted)))
            {
                if (entry.Entity is IModel)
                {
                    var model = entry.Entity as IModel;
                    model.PreSaveChanges(this, entry, entry.State);

                    if (!preSavedEntities.Contains(model.Guid))
                    {
                        preSavedEntities.Add(model.Guid);
                    }
                }
            }

            // Then loop again, as new models may have been added by PreSaveChanges events
            var updatedItems = new List <ContextItem>();

            foreach (var entry in dbContext.ChangeTracker.Entries()
                     .Where(c =>
                            c.Entity is IEntity &&
                            (c.State == EntityState.Added || c.State == EntityState.Modified || c.State == EntityState.Deleted)))
            {
                // Cast entry as IEntity
                var entity = entry.Entity as IEntity;

                // Get the context item to track audits
                var contextItem = new ContextItem(entity, entry, enableAuditing);

                // If entity was added or modified, update the Created/Modified fields
                if (entry.State == EntityState.Added || entry.State == EntityState.Modified)
                {
                    // instead of passing "true" the trigger model and UI would support a
                    // on-value-changed checkbox (or perhaps it should be the default/only behavior)
                    // and its value would be passed in to the onValueChange
                    if (!TriggerWorkflows(contextItem, WorkflowTriggerType.PreSave, personAlias))
                    {
                        return(null);
                    }

                    if (entry.Entity is IModel)
                    {
                        var model = entry.Entity as IModel;

                        if (!preSavedEntities.Contains(model.Guid))
                        {
                            model.PreSaveChanges(this, entry);
                        }

                        // Update Guid/Created/Modified person and times
                        if (entry.State == EntityState.Added)
                        {
                            if (!model.CreatedDateTime.HasValue)
                            {
                                model.CreatedDateTime = RockDateTime.Now;
                            }
                            if (!model.CreatedByPersonAliasId.HasValue)
                            {
                                model.CreatedByPersonAliasId = personAliasId;
                            }

                            if (model.Guid == Guid.Empty)
                            {
                                model.Guid = Guid.NewGuid();
                            }

                            model.ModifiedDateTime = RockDateTime.Now;

                            if (!model.ModifiedAuditValuesAlreadyUpdated || model.ModifiedByPersonAliasId == null)
                            {
                                model.ModifiedByPersonAliasId = personAliasId;
                            }
                        }
                        else if (entry.State == EntityState.Modified)
                        {
                            model.ModifiedDateTime = RockDateTime.Now;

                            if (!model.ModifiedAuditValuesAlreadyUpdated || model.ModifiedByPersonAliasId == null)
                            {
                                model.ModifiedByPersonAliasId = personAliasId;
                            }
                        }
                    }
                }
                else if (entry.State == EntityState.Deleted)
                {
                    if (!TriggerWorkflows(contextItem, WorkflowTriggerType.PreDelete, personAlias))
                    {
                        return(null);
                    }
                }

                if (enableAuditing)
                {
                    try
                    {
                        GetAuditDetails(dbContext, contextItem, personAliasId);
                    }
                    catch (SystemException ex)
                    {
                        contextItem.Audit = null;
                        System.Diagnostics.Debug.WriteLine($"Exception when getting Audit details for {contextItem?.GetType().Name} - {ex}");
                        ExceptionLogService.LogException(ex, null);
                    }
                }

                updatedItems.Add(contextItem);
            }

            return(updatedItems);
        }
예제 #23
0
 /// <summary>
 /// Tries the delete.
 /// </summary>
 /// <remarks>
 /// This method will always log any exception that occurs even if the exception isn't thrown.
 /// </remarks>
 /// <param name="filePath">The file path.</param>
 /// <param name="shouldBubbleException">if set to <c>true</c> [should bubble exception].</param>
 public static void TryDelete(string filePath, bool shouldBubbleException)
 {
     TryDelete(filePath, (ex) => ExceptionLogService.LogException(ex), shouldBubbleException);
 }
예제 #24
0
파일: DbContext.cs 프로젝트: waldo2590/Rock
        /// <summary>
        /// Creates audit logs and/or triggers workflows for items that were changed
        /// </summary>
        /// <param name="updatedItems">The updated items.</param>
        /// <param name="personAlias">The person alias.</param>
        /// <param name="enableAuditing">if set to <c>true</c> [enable auditing].</param>
        protected virtual void RockPostSave(List <ContextItem> updatedItems, PersonAlias personAlias, bool enableAuditing = false)
        {
            if (enableAuditing)
            {
                try
                {
                    var audits = updatedItems.Where(a => a.Audit != null).Select(i => i.Audit).ToList();
                    if (audits.Any(a => a.Details.Any()))
                    {
                        var transaction = new Rock.Transactions.AuditTransaction();
                        transaction.Audits = audits.Where(a => a.Details.Any() == true).ToList();
                        Rock.Transactions.RockQueue.TransactionQueue.Enqueue(transaction);
                    }
                }
                catch (SystemException ex)
                {
                    ExceptionLogService.LogException(ex, null);
                }
            }

            List <ITransaction> indexTransactions = new List <ITransaction>();

            foreach (var item in updatedItems)
            {
                if (item.State == EntityState.Detached || item.State == EntityState.Deleted)
                {
                    TriggerWorkflows(item, WorkflowTriggerType.PostDelete, personAlias);
                }
                else
                {
                    if (item.PreSaveState == EntityState.Added)
                    {
                        TriggerWorkflows(item, WorkflowTriggerType.PostAdd, personAlias);
                    }

                    TriggerWorkflows(item, WorkflowTriggerType.ImmediatePostSave, personAlias);
                    TriggerWorkflows(item, WorkflowTriggerType.PostSave, personAlias);
                }

                if (item.Entity is IModel)
                {
                    var model = item.Entity as IModel;
                    model.PostSaveChanges(this);
                }

                // check if this entity should be passed on for indexing
                if (item.Entity is IRockIndexable)
                {
                    if (item.State == EntityState.Detached || item.State == EntityState.Deleted)
                    {
                        DeleteIndexEntityTransaction transaction = new DeleteIndexEntityTransaction();
                        transaction.EntityTypeId = item.Entity.TypeId;
                        transaction.EntityId     = item.Entity.Id;

                        indexTransactions.Add(transaction);
                    }
                    else
                    {
                        IndexEntityTransaction transaction = new IndexEntityTransaction();
                        transaction.EntityTypeId = item.Entity.TypeId;
                        transaction.EntityId     = item.Entity.Id;

                        indexTransactions.Add(transaction);
                    }
                }

                if (item.Entity is ICacheable)
                {
                    (item.Entity as ICacheable).UpdateCache(item.PreSaveState, this);
                }
            }

            // check if Indexing is enabled in another thread to avoid deadlock when Snapshot Isolation is turned off when the Index components upload/load attributes
            if (indexTransactions.Any())
            {
                System.Threading.Tasks.Task.Run(() =>
                {
                    var indexingEnabled = IndexContainer.GetActiveComponent() == null ? false : true;
                    if (indexingEnabled)
                    {
                        indexTransactions.ForEach(t => RockQueue.TransactionQueue.Enqueue(t));
                    }
                });
            }
        }
예제 #25
0
        /// <summary>
        /// Called by the <see cref="IScheduler"/> after a <see cref="IJobDetail"/>
        /// has been executed, and before the associated <see cref="Quartz.Spi.IOperableTrigger"/>'s
        /// <see cref="Quartz.Spi.IOperableTrigger.Triggered"/> method has been called.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="jobException"></param>
        public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
        {
            RockJobResultSpecifier result;
            IRockJobResult         resultInfo;
            Exception  exceptionToLog = null;
            ServiceJob job            = null;

            // If the Job threw an Exception, create a corresponding RockJobResult object and find the appropriate Exception to log.
            if (jobException != null)
            {
                exceptionToLog = jobException;

                resultInfo = new RockJobResult();

                resultInfo.Result = RockJobResultSpecifier.Failed;

                // Unpack the Scheduler Exceptions to get the Exception thrown by the Task itself.
                while (exceptionToLog is SchedulerException &&
                       exceptionToLog.InnerException != null)
                {
                    exceptionToLog = exceptionToLog.InnerException;
                }

                var summaryException = exceptionToLog;

                if (summaryException is AggregateException)
                {
                    var aggregateException = (AggregateException)summaryException;

                    if (aggregateException.InnerExceptions != null)
                    {
                        if (aggregateException.InnerExceptions.Count == 1)
                        {
                            // if it's an aggregate, but there is only one, convert it to a single exception
                            summaryException = aggregateException.InnerExceptions[0];
                        }
                        else
                        {
                            summaryException = aggregateException.Flatten();
                        }
                    }
                }

                resultInfo.ResultDescription = summaryException.Message;

                var ex = summaryException.InnerException;

                string details = string.Empty;;

                while (ex != null)
                {
                    details += "\n--> " + ex.Message;

                    ex = ex.InnerException;
                }

                resultInfo.ResultDetails = details.Trim('\n');
            }
            else
            {
                resultInfo = context.Result as IRockJobResult;

                // If the Job did not return a result object and did not throw an Exception, assume success.
                if (resultInfo == null)
                {
                    resultInfo        = new RockJobResult();
                    resultInfo.Result = RockJobResultSpecifier.Succeeded;
                }
                else
                {
                    // If the Job returned a failure in the result object, create a corresponding Exception for logging purposes.
                    if (resultInfo.Result.HasValue &&
                        resultInfo.Result.Value == RockJobResultSpecifier.Failed)
                    {
                        exceptionToLog = new Exception(resultInfo.ResultDescription);
                    }
                }
            }

            // Update the Job with the most recent result.
            result = resultInfo.Result.GetValueOrDefault(RockJobResultSpecifier.Succeeded);

            // Retrieve the Job details.
            int jobId = Convert.ToInt16(context.JobDetail.Description);

            using (var rockContext = new RockContext())
            {
                var jobService = new ServiceJobService(rockContext);

                job = jobService.Get(jobId);

                // set last run date
                job.LastRunDateTime = RockDateTime.Now;

                // set run time
                job.LastRunDurationSeconds = Convert.ToInt32(context.JobRunTime.TotalSeconds);

                // set the scheduler name
                job.LastRunSchedulerName = context.Scheduler.SchedulerName;
                switch (result)
                {
                case RockJobResultSpecifier.Succeeded:
                    job.LastStatus = "Success";
                    job.LastSuccessfulRunDateTime = job.LastRunDateTime;
                    break;

                case RockJobResultSpecifier.CompletedWithWarnings:
                    job.LastStatus = "Warning";
                    job.LastSuccessfulRunDateTime = job.LastRunDateTime;
                    break;

                case RockJobResultSpecifier.Failed:
                    job.LastStatus = "Exception";
                    break;
                }

                job.LastStatusMessage = resultInfo.ResultDescription;

                if (!string.IsNullOrEmpty(resultInfo.ResultDetails))
                {
                    job.LastStatusMessage += "\n" + resultInfo.ResultDetails;
                }

                // Save changes to the Job.
                rockContext.SaveChanges();
            }

            if (result == RockJobResultSpecifier.Failed)
            {
                // log the exception to the database
                ExceptionLogService.LogException(exceptionToLog, null);
            }

            this.ProcessNotificationMessage(context, job, resultInfo);
        }
예제 #26
0
파일: DbContext.cs 프로젝트: waldo2590/Rock
        /// <summary>
        /// Determines whether the entity matches the current and/or previous qualifier values.
        /// If
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="properties">The properties.</param>
        /// <param name="trigger">The trigger.</param>
        /// <returns>true if matches; false otherwise</returns>
        private static bool IsQualifierMatch(ContextItem item, Dictionary <string, PropertyInfo> properties, WorkflowTrigger trigger)
        {
            bool match = false;

            try
            {
                var dbEntity = item.DbEntityEntry;

                // Now attempt to find a match taking into account the EntityTypeQualifierValue and/or EntityTypeQualifierValuePrevious
                if (properties.ContainsKey(trigger.EntityTypeQualifierColumn.ToLower()))
                {
                    var propertyInfo = properties[trigger.EntityTypeQualifierColumn.ToLower()];

                    bool hasPrevious = !string.IsNullOrEmpty(trigger.EntityTypeQualifierValuePrevious);
                    bool hasCurrent  = !string.IsNullOrEmpty(trigger.EntityTypeQualifierValue);

                    var currentProperty = propertyInfo.GetValue(item.Entity, null);
                    var currentValue    = currentProperty != null?currentProperty.ToString() : string.Empty;

                    var previousValue = string.Empty;

                    if (item.OriginalValues != null && item.OriginalValues.ContainsKey(propertyInfo.Name))
                    {
                        previousValue = item.OriginalValues[propertyInfo.Name].ToStringSafe();
                    }
                    else
                    {
                        var dbPropertyEntry = dbEntity.Property(propertyInfo.Name);
                        if (dbPropertyEntry != null)
                        {
                            previousValue = item.PreSaveState == EntityState.Added ? string.Empty : dbPropertyEntry.OriginalValue.ToStringSafe();
                        }
                    }

                    if (trigger.WorkflowTriggerType == WorkflowTriggerType.PreDelete ||
                        trigger.WorkflowTriggerType == WorkflowTriggerType.PostDelete)
                    {
                        match = (previousValue == trigger.EntityTypeQualifierValue);
                    }

                    if (trigger.WorkflowTriggerType == WorkflowTriggerType.PostAdd)
                    {
                        match = (currentValue == trigger.EntityTypeQualifierValue);
                    }

                    if (trigger.WorkflowTriggerType == WorkflowTriggerType.ImmediatePostSave ||
                        trigger.WorkflowTriggerType == WorkflowTriggerType.PostSave ||
                        trigger.WorkflowTriggerType == WorkflowTriggerType.PreSave)
                    {
                        if (trigger.WorkflowTriggerValueChangeType == WorkflowTriggerValueChangeType.ValueEqual)
                        {
                            match = trigger.EntityTypeQualifierValue == currentValue;
                        }
                        else
                        {
                            if (hasCurrent && !hasPrevious)
                            {
                                // ...and previous cannot be the same as the current (must be a change)
                                match = (currentValue == trigger.EntityTypeQualifierValue &&
                                         currentValue != previousValue);
                            }
                            else if (!hasCurrent && hasPrevious)
                            {
                                // ...and previous cannot be the same as the current (must be a change)
                                match = (previousValue == trigger.EntityTypeQualifierValuePrevious &&
                                         previousValue != currentValue);
                            }
                            else if (hasCurrent && hasPrevious)
                            {
                                match = (currentValue == trigger.EntityTypeQualifierValue &&
                                         previousValue == trigger.EntityTypeQualifierValuePrevious);
                            }
                            else if (!hasCurrent && !hasPrevious)
                            {
                                match = previousValue != currentValue;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(ex, null);
            }

            return(match);
        }
예제 #27
0
        protected override void ExtractPackageFilesToProject(IPackage package)
        {
            List <IPackageFile>         contentFiles     = package.GetContentFiles().ToList();
            Dictionary <string, string> transformedFiles = new Dictionary <string, string>();
            string packageRestorePath = Path.Combine(Project.Root, "App_Data", "PackageRestore");

            // go through each *.rock.xdt file and apply the transform first,
            foreach (var xdtFile in contentFiles.Where(f => f.Path.EndsWith(TRANSFORM_FILE_PREFIX, StringComparison.OrdinalIgnoreCase)))
            {
                using (Stream stream = xdtFile.GetStream())
                {
                    var fileName = xdtFile.EffectivePath;

                    // write the transform file out to the PackageRestore/xdt folder
                    var transformFilefullPath = Path.Combine(packageRestorePath, "xdt", fileName);
                    Directory.CreateDirectory(Path.GetDirectoryName(transformFilefullPath));
                    using (var fileStream = File.Create(transformFilefullPath))
                    {
                        stream.CopyTo(fileStream);
                    }

                    var sourceFile                = fileName.Remove(fileName.Length - TRANSFORM_FILE_PREFIX.Length);
                    var sourceFileFullPath        = Path.Combine(Project.Root, sourceFile);
                    var tempPathOfTransformedFile = Path.Combine(packageRestorePath, "xdt", sourceFile);

                    // now transform the Rock file using the xdt file, but write it to the PackageRestore\xdt folder and we'll
                    // move it into place after the update is finished.
                    // If the transform fails, then we have to quit and inform the user.
                    if (!ProcessXmlDocumentTransformation(transformFilefullPath, sourceFileFullPath, tempPathOfTransformedFile))
                    {
                        throw new System.Xml.XmlException(sourceFile);
                    }
                    transformedFiles.Add(tempPathOfTransformedFile, sourceFile);
                }
            }

            // now let the package installation proceed as normal
            base.ExtractPackageFilesToProject(package);

            // lastly, move the transformed xml files into place
            MoveTransformedFiles(transformedFiles);

            try
            {
                try
                {
                    Directory.Delete(packageRestorePath, recursive: true);
                }
                catch (IOException)
                {
                    // try one more time
                    System.Threading.Tasks.Task.Delay(10).Wait();
                    if (Directory.Exists(packageRestorePath))
                    {
                        Directory.Delete(packageRestorePath, recursive: true);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(new Exception(string.Format("Note: Unable to delete the temporary package restore folder ({0}) after a successful update.", packageRestorePath), ex), System.Web.HttpContext.Current);
            }
        }
        /// <summary>
        /// Job that will send scheduled group emails.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            var dataMap                         = context.JobDetail.JobDataMap;
            int?commandTimeout                  = dataMap.GetString("CommandTimeout").AsIntegerOrNull();
            int?lastRunBuffer                   = dataMap.GetString("LastRunBuffer").AsIntegerOrNull();
            var enabledLavaCommands             = dataMap.GetString("EnabledLavaCommands");
            var JobStartDateTime                = RockDateTime.Now;
            var dateAttributes                  = new List <AttributeValue>();
            var dAttributeMatrixItemAndGroupIds = new Dictionary <int, int>(); // Key: AttributeMatrixItemId   Value: GroupId
            int communicationsSent              = 0;
            var emailMediumType                 = EntityTypeCache.Get("Rock.Communication.Medium.Email");
            var dateAttributeId                 = Rock.Web.Cache.AttributeCache.Get(KFSConst.Attribute.MATRIX_ATTRIBUTE_EMAIL_SEND_DATE.AsGuid()).Id;
            var recurrenceAttributeId           = Rock.Web.Cache.AttributeCache.Get(KFSConst.Attribute.MATRIX_ATTRIBUTE_EMAIL_SEND_RECURRENCE.AsGuid()).Id;
            var fromEmailAttributeId            = Rock.Web.Cache.AttributeCache.Get(KFSConst.Attribute.MATRIX_ATTRIBUTE_EMAIL_FROM_EMAIL.AsGuid()).Id;
            var fromNameAttributeId             = Rock.Web.Cache.AttributeCache.Get(KFSConst.Attribute.MATRIX_ATTRIBUTE_EMAIL_FROM_NAME.AsGuid()).Id;
            var subjectAttributeId              = Rock.Web.Cache.AttributeCache.Get(KFSConst.Attribute.MATRIX_ATTRIBUTE_EMAIL_SUBJECT.AsGuid()).Id;
            var messageAttributeId              = Rock.Web.Cache.AttributeCache.Get(KFSConst.Attribute.MATRIX_ATTRIBUTE_EMAIL_MESSAGE.AsGuid()).Id;

            try
            {
                using (var rockContext = new RockContext())
                {
                    // get the last run date or yesterday
                    DateTime?lastStartDateTime = null;

                    // get job type id
                    int jobId = context.JobDetail.Description.AsInteger();

                    // load job
                    var job = new ServiceJobService(rockContext)
                              .GetNoTracking(jobId);

                    if (job != null && job.Guid != Rock.SystemGuid.ServiceJob.JOB_PULSE.AsGuid())
                    {
                        lastStartDateTime = job.LastRunDateTime?.AddSeconds(0.0d - ( double )(job.LastRunDurationSeconds + lastRunBuffer));
                    }
                    var beginDateTime = lastStartDateTime ?? JobStartDateTime.AddDays(-1);

                    // get the date attributes
                    dateAttributes = new AttributeValueService(rockContext)
                                     .Queryable().AsNoTracking()
                                     .Where(d => d.AttributeId == dateAttributeId &&
                                            d.EntityId.HasValue &&
                                            d.ValueAsDateTime >= beginDateTime &&
                                            d.ValueAsDateTime <= JobStartDateTime)
                                     .ToList();
                }

                foreach (var d in dateAttributes)
                {
                    // Use a new context to limit the amount of change-tracking required
                    using (var rockContext = new RockContext())
                    {
                        var attributeMatrixId = new AttributeMatrixItemService(rockContext)
                                                .GetNoTracking(d.EntityId.Value)
                                                .AttributeMatrixId;

                        var attributeMatrixGuid = new AttributeMatrixService(rockContext)
                                                  .GetNoTracking(attributeMatrixId)
                                                  .Guid
                                                  .ToString();

                        var attributeValue = new AttributeValueService(rockContext)
                                             .Queryable().AsNoTracking()
                                             .FirstOrDefault(a => a.Value.Equals(attributeMatrixGuid, StringComparison.CurrentCultureIgnoreCase));

                        if (attributeValue != null && attributeValue.EntityId.HasValue)
                        {
                            dAttributeMatrixItemAndGroupIds.Add(d.EntityId.Value, attributeValue.EntityId.Value);
                        }
                    }
                }

                foreach (var attributeMatrixItemAndGroupId in dAttributeMatrixItemAndGroupIds)
                {
                    // Use a new context to limit the amount of change-tracking required
                    using (var rockContext = new RockContext())
                    {
                        rockContext.Database.CommandTimeout = commandTimeout;

                        var fromEmail = new AttributeValueService(rockContext)
                                        .GetByAttributeIdAndEntityId(fromEmailAttributeId, attributeMatrixItemAndGroupId.Key)
                                        .Value;

                        var fromName = new AttributeValueService(rockContext)
                                       .GetByAttributeIdAndEntityId(fromNameAttributeId, attributeMatrixItemAndGroupId.Key)
                                       .Value;

                        var subject = new AttributeValueService(rockContext)
                                      .GetByAttributeIdAndEntityId(subjectAttributeId, attributeMatrixItemAndGroupId.Key)
                                      .Value;

                        var message = new AttributeValueService(rockContext)
                                      .GetByAttributeIdAndEntityId(messageAttributeId, attributeMatrixItemAndGroupId.Key)
                                      .Value;

                        var attachments = new List <BinaryFile>();

                        var group = new GroupService(rockContext)
                                    .GetNoTracking(attributeMatrixItemAndGroupId.Value);

                        if (!message.IsNullOrWhiteSpace() && emailMediumType != null)
                        {
                            var groupMembers = group.Members.Where(m => m.Person != null && m.Person.Email != null && m.Person.Email != string.Empty && m.GroupMemberStatus == GroupMemberStatus.Active);

                            if (!groupMembers.Any())
                            {
                                continue;
                            }

                            var communicationService = new CommunicationService(rockContext);

                            var communication = new Rock.Model.Communication();
                            communication.Status                 = CommunicationStatus.Transient;
                            communication.ReviewedDateTime       = JobStartDateTime;
                            communication.ReviewerPersonAliasId  = group.ModifiedByPersonAliasId;
                            communication.SenderPersonAliasId    = group.ModifiedByPersonAliasId;
                            communication.CreatedByPersonAliasId = group.ModifiedByPersonAliasId;
                            communicationService.Add(communication);

                            communication.EnabledLavaCommands = enabledLavaCommands;

                            var personIdHash = new HashSet <int>();
                            foreach (var member in groupMembers)
                            {
                                if (!personIdHash.Contains(member.PersonId))
                                {
                                    personIdHash.Add(member.PersonId);
                                    var communicationRecipient = new CommunicationRecipient();
                                    communicationRecipient.PersonAliasId         = member.Person.PrimaryAliasId;
                                    communicationRecipient.AdditionalMergeValues = new Dictionary <string, object>();
                                    communicationRecipient.AdditionalMergeValues.Add("GroupMember", member);
                                    //communicationRecipient.AdditionalMergeValues.Add( "Group", group );
                                    communication.Recipients.Add(communicationRecipient);
                                }
                            }

                            communication.IsBulkCommunication     = false;
                            communication.CommunicationType       = CommunicationType.Email;
                            communication.CommunicationTemplateId = null;

                            foreach (var recipient in communication.Recipients)
                            {
                                recipient.MediumEntityTypeId = emailMediumType.Id;
                            }

                            communication.FromEmail = fromEmail;
                            communication.FromName  = fromName;
                            communication.Subject   = subject;
                            communication.Message   = message;
                            communication.Status    = CommunicationStatus.Approved;

                            rockContext.SaveChanges();

                            Rock.Model.Communication.Send(communication);

                            communicationsSent += personIdHash.Count;

                            var recurrence = new AttributeValueService(rockContext)
                                             .GetByAttributeIdAndEntityId(recurrenceAttributeId, attributeMatrixItemAndGroupId.Key);

                            if (recurrence != null && !string.IsNullOrWhiteSpace(recurrence.Value))
                            {
                                var sendDate = new AttributeValueService(rockContext)
                                               .GetByAttributeIdAndEntityId(dateAttributeId, attributeMatrixItemAndGroupId.Key);

                                switch (recurrence.Value)
                                {
                                case "1":
                                    sendDate.Value = sendDate.ValueAsDateTime.Value.AddDays(7).ToString();
                                    break;

                                case "2":
                                    sendDate.Value = sendDate.ValueAsDateTime.Value.AddDays(14).ToString();
                                    break;

                                case "3":
                                    sendDate.Value = sendDate.ValueAsDateTime.Value.AddMonths(1).ToString();
                                    break;

                                case "4":
                                    sendDate.Value = sendDate.ValueAsDateTime.Value.AddDays(1).ToString();
                                    break;

                                default:
                                    break;
                                }
                                rockContext.SaveChanges();
                            }
                        }
                    }
                }

                if (communicationsSent > 0)
                {
                    context.Result = string.Format("Sent {0} {1}", communicationsSent, "communication".PluralizeIf(communicationsSent > 1));
                }
                else
                {
                    context.Result = "No communications to send";
                }
            }
            catch (System.Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
                throw;
            }
        }
예제 #29
0
        /// <summary>
        /// Job that will run quick SQL queries on a schedule.
        ///
        /// Called by the <see cref="IScheduler" /> when a
        /// <see cref="ITrigger" /> fires that is associated with
        /// the <see cref="IJob" />.
        /// </summary>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            // get job parms
            bool runIntegrityCheck   = dataMap.GetBoolean("RunIntegrityCheck");
            bool runIndexRebuild     = dataMap.GetBoolean("RunIndexRebuild");
            bool runStatisticsUpdate = dataMap.GetBoolean("RunStatisticsUpdate");

            int           commandTimeout        = dataMap.GetString("CommandTimeout").AsInteger();
            StringBuilder resultsMessage        = new StringBuilder();
            bool          integrityCheckPassed  = false;
            bool          integrityCheckIgnored = false;

            /*
             * DJL 2020-04-08
             * For Microsoft Azure, disable the Integrity Check and Statistics Update tasks.
             * Refer: https://azure.microsoft.com/en-us/blog/data-integrity-in-azure-sql-database/
             */
            if (RockInstanceConfig.Database.Platform == RockInstanceDatabaseConfiguration.PlatformSpecifier.AzureSql)
            {
                runIntegrityCheck   = false;
                runStatisticsUpdate = false;
            }

            // run integrity check
            if (runIntegrityCheck)
            {
                try
                {
                    string alertEmail = dataMap.GetString("AlertEmail");
                    integrityCheckPassed = IntegrityCheck(commandTimeout, alertEmail, resultsMessage);
                }
                catch (Exception ex)
                {
                    ExceptionLogService.LogException(ex, HttpContext.Current);
                    ExceptionLogService.LogException(resultsMessage.ToString());
                    throw;
                }
            }
            else
            {
                integrityCheckIgnored = true;
            }

            if (integrityCheckPassed || integrityCheckIgnored)
            {
                // rebuild fragmented indexes
                if (runIndexRebuild)
                {
                    try
                    {
                        RebuildFragmentedIndexes(dataMap, commandTimeout, resultsMessage);
                    }
                    catch (Exception ex)
                    {
                        ExceptionLogService.LogException(ex, HttpContext.Current);
                        ExceptionLogService.LogException(resultsMessage.ToString());
                        throw;
                    }
                }

                // update statistics
                if (runStatisticsUpdate)
                {
                    try
                    {
                        UpdateStatistics(commandTimeout, resultsMessage);
                    }
                    catch (Exception ex)
                    {
                        ExceptionLogService.LogException(ex, HttpContext.Current);
                        ExceptionLogService.LogException(resultsMessage.ToString());
                        throw;
                    }
                }
            }

            context.Result = resultsMessage.ToString().TrimStart(',');
        }
예제 #30
0
        /// <summary>
        /// Gets the parent page references.
        /// </summary>
        /// <returns></returns>
        public static List <PageReference> GetParentPageReferences(RockPage rockPage, PageCache currentPage, PageReference currentPageReference)
        {
            // Get previous page references in nav history
            var pageReferenceHistory = HttpContext.Current.Session["RockPageReferenceHistory"] as List <PageReference>;

            // Current page heirarchy references
            var pageReferences = new List <PageReference>();

            if (currentPage != null)
            {
                var parentPage = currentPage.ParentPage;
                if (parentPage != null)
                {
                    var currentParentPages = parentPage.GetPageHierarchy();
                    if (currentParentPages != null && currentParentPages.Count > 0)
                    {
                        currentParentPages.Reverse();
                        foreach (PageCache page in currentParentPages)
                        {
                            PageReference parentPageReference = null;
                            if (pageReferenceHistory != null)
                            {
                                parentPageReference = pageReferenceHistory.Where(p => p.PageId == page.Id).FirstOrDefault();
                            }

                            if (parentPageReference == null)
                            {
                                parentPageReference        = new PageReference( );
                                parentPageReference.PageId = page.Id;

                                parentPageReference.BreadCrumbs = new List <BreadCrumb>();
                                parentPageReference.QueryString = new NameValueCollection();
                                parentPageReference.Parameters  = new Dictionary <string, string>();

                                string bcName = page.BreadCrumbText;
                                if (bcName != string.Empty)
                                {
                                    parentPageReference.BreadCrumbs.Add(new BreadCrumb(bcName, parentPageReference.BuildUrl()));
                                }

                                foreach (var block in page.Blocks.Where(b => b.BlockLocation == Model.BlockLocation.Page))
                                {
                                    try
                                    {
                                        System.Web.UI.Control control = rockPage.TemplateControl.LoadControl(block.BlockType.Path);
                                        if (control is RockBlock)
                                        {
                                            RockBlock rockBlock = control as RockBlock;
                                            rockBlock.SetBlock(page, block);
                                            rockBlock.GetBreadCrumbs(parentPageReference).ForEach(c => parentPageReference.BreadCrumbs.Add(c));
                                        }
                                        control = null;
                                    }
                                    catch (Exception ex)
                                    {
                                        ExceptionLogService.LogException(ex, HttpContext.Current, currentPage.Id, currentPage.Layout.SiteId);
                                    }
                                }
                            }

                            parentPageReference.BreadCrumbs.ForEach(c => c.Active = false);
                            pageReferences.Add(parentPageReference);
                        }
                    }
                }
            }

            return(pageReferences);
        }