示例#1
0
        /// <summary>
        /// Validates the JWT using the provided configuration and returns the parsed token if valid
        /// </summary>
        /// <param name="jwtString">The token.</param>
        /// <param name="jwtConfig">The configuration on how to validate the token</param>
        /// <returns></returns>
        private static JwtSecurityToken ValidateToken(JwtConfig jwtConfig, string jwtString)
        {
            if (jwtString.IsNullOrWhiteSpace())
            {
                return(null);
            }

            if (jwtConfig == null)
            {
                return(null);
            }

            // It is standard to prefix JWTs with "Bearer ", but JwtSecurityTokenHandler.ValidateToken will
            // say the token is malformed if the prefix is not removed
            if (jwtString.StartsWith(HeaderTokens.JwtPrefix))
            {
                jwtString = jwtString.Substring(HeaderTokens.JwtPrefix.Length);
            }

            // Retrieve the configuration manager, which is cached according to the jwtConfig.JwksJsonFileUrl
            var configurationManager = GetConfigurationManager(jwtConfig.OpenIdConfigurationUrl);

            if (configurationManager == null)
            {
                return(null);
            }

            // The configuration manager handles caching the configuration documents and keys, which are from another
            // server or provider like Auth0.
            var openIdConnectConfiguration = AsyncHelper.RunSync(() => configurationManager.GetConfigurationAsync());

            if (openIdConnectConfiguration == null || openIdConnectConfiguration.SigningKeys == null || !openIdConnectConfiguration.SigningKeys.Any())
            {
                return(null);
            }

            // Validate the items that are configured to be validated
            var validateAudience = !jwtConfig.Audience.IsNullOrWhiteSpace();
            var validateIssuer   = !jwtConfig.Issuer.IsNullOrWhiteSpace();

            var validationParameters = new TokenValidationParameters
            {
                ValidateAudience         = validateAudience,
                ValidAudience            = validateAudience ? jwtConfig.Audience : null,
                ValidateIssuer           = validateIssuer,
                ValidIssuer              = validateIssuer ? jwtConfig.Issuer : null,
                RequireExpirationTime    = true,
                RequireSignedTokens      = true,
                ValidateIssuerSigningKey = true,
                IssuerSigningKeys        = openIdConnectConfiguration.SigningKeys,
                ValidateLifetime         = true,
                ClockSkew = TimeSpan.FromMinutes(1)   // Allow a minute of play in server times since we're dealing with a third party key provider
            };

            try
            {
                var principal = new JwtSecurityTokenHandler().ValidateToken(jwtString, validationParameters, out var validatedToken);

                // If the principal identity is null, we should not accept this as a validated token
                if (principal == null || principal.Identity == null)
                {
                    return(null);
                }

                var jwtToken = validatedToken as JwtSecurityToken;
                return(jwtToken);
            }
            catch (Exception ex)
            {
                // The JWT was not well formed or did not validate in some other way
                ExceptionLogService.LogException(ex);
                Debug.WriteLine(ex.Message);
                return(null);
            }
        }
示例#2
0
        /// <summary>
        /// Handles the Click event of the btnDefault 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 btnDefault_Click(object sender, EventArgs e)
        {
            var bioBlock = BlockCache.Get(Rock.SystemGuid.Block.BIO.AsGuid());

            // Record an exception if the stock Bio block has been deleted but continue processing
            // the remaining settings.
            if (bioBlock == null)
            {
                var errorMessage = string.Format("Stock Bio block ({0}) is missing.", Rock.SystemGuid.Block.BIO);
                ExceptionLogService.LogException(new Exception(errorMessage));
            }
            else
            {
                List <Guid> workflowActionGuidList = bioBlock.GetAttributeValues("WorkflowActions").AsGuidList();
                if (workflowActionGuidList == null || workflowActionGuidList.Count == 0)
                {
                    // Add to Bio Workflow Actions
                    bioBlock.SetAttributeValue("WorkflowActions", Rock.SystemGuid.WorkflowType.PROTECTMYMINISTRY);
                    ///BackgroundCheckContainer.Instance.Components
                }
                else
                {
                    //var workflowActionValues = workflowActionValue.Split( new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries ).ToList();
                    Guid guid = Rock.SystemGuid.WorkflowType.PROTECTMYMINISTRY.AsGuid();
                    if (!workflowActionGuidList.Any(w => w == guid))
                    {
                        // Add Checkr to Bio Workflow Actions
                        workflowActionGuidList.Add(guid);
                    }

                    // Remove PMM from Bio Workflow Actions
                    guid = CheckrSystemGuid.CHECKR_WORKFLOW_TYPE.AsGuid();
                    workflowActionGuidList.RemoveAll(w => w == guid);
                    bioBlock.SetAttributeValue("WorkflowActions", workflowActionGuidList.AsDelimited(","));
                }

                bioBlock.SaveAttributeValue("WorkflowActions");
            }

            string pmmTypeName  = (typeof(Rock.Security.BackgroundCheck.ProtectMyMinistry)).FullName;
            var    pmmComponent = BackgroundCheckContainer.Instance.Components.Values.FirstOrDefault(c => c.Value.TypeName == pmmTypeName);

            pmmComponent.Value.SetAttributeValue("Active", "True");
            pmmComponent.Value.SaveAttributeValue("Active");
            // Set as the default provider in the system setting
            SystemSettings.SetValue(Rock.SystemKey.SystemSetting.DEFAULT_BACKGROUND_CHECK_PROVIDER, pmmTypeName);

            using (var rockContext = new RockContext())
            {
                WorkflowTypeService workflowTypeService = new WorkflowTypeService(rockContext);
                // Rename PMM Workflow
                var pmmWorkflowAction = workflowTypeService.Get(Rock.SystemGuid.WorkflowType.PROTECTMYMINISTRY.AsGuid());
                pmmWorkflowAction.Name = "Background Check";

                var checkrWorkflowAction = workflowTypeService.Get(CheckrSystemGuid.CHECKR_WORKFLOW_TYPE.AsGuid());
                // Rename Checkr Workflow
                checkrWorkflowAction.Name = CheckrConstants.CHECKR_WORKFLOW_TYPE_NAME;

                rockContext.SaveChanges();

                // Enable PMM packages and disable Checkr packages
                DefinedValueService definedValueService = new DefinedValueService(rockContext);
                var packages = definedValueService
                               .GetByDefinedTypeGuid(Rock.SystemGuid.DefinedType.BACKGROUND_CHECK_TYPES.AsGuid())
                               .ToList();

                foreach (var package in packages)
                {
                    package.IsActive = package.ForeignId == 1;
                }

                rockContext.SaveChanges();
            }

            ShowDetail();
        }
示例#3
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();

                var rockContext = new RockContext();

                bool requiresViewSecurity = false;

                BinaryFile binaryFile = null;

                try {
                    binaryFile = new BinaryFileService(rockContext).EndGet(result, context, out requiresViewSecurity);
                }
                catch (Exception ex)
                {
                    // Ignore Error (Will fall though to 404)
                }

                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;
                }

                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);
                }
            }
        }
示例#4
0
        /// <summary> 
        /// Job that updates the JobPulse setting with the current date/time.
        /// This will allow us to notify an admin if the jobs stop running.
        /// 
        /// 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 map
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            // delete accounts that have not been confirmed in X hours
            int userExpireHours = Int32.Parse( dataMap.GetString( "HoursKeepUnconfirmedAccounts" ) );
            DateTime userAccountExpireDate = DateTime.Now.Add( new TimeSpan( userExpireHours * -1,0,0 ) );

            UserService userService = new UserService();

            foreach (var user in userService.Queryable().Where(u => u.IsConfirmed == false && u.CreationDate < userAccountExpireDate))
            {
                userService.Delete( user, null );
            }

            userService.Save( null, null );

            // purge exception log
            int exceptionExpireDays = Int32.Parse( dataMap.GetString( "DaysKeepExceptions" ) );
            DateTime exceptionExpireDate = DateTime.Now.Add( new TimeSpan( userExpireHours * -1, 0, 0 ) );

            ExceptionLogService exceptionLogService = new ExceptionLogService();

            foreach ( var exception in exceptionLogService.Queryable().Where( e => e.ExceptionDate < exceptionExpireDate ) )
            {
                exceptionLogService.Delete( exception, null );
            }

            exceptionLogService.Save( null, null );
        }
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap           = context.JobDetail.JobDataMap;
            var        emailTemplateGuid = dataMap.Get("SystemEmail").ToString().AsGuid();
            var        groupGuid         = dataMap.Get("Group").ToString().AsGuid();
            var        sendToDescendants = dataMap.Get("SendToDescendantGroups").ToString().AsBoolean();

            var rockContext = new RockContext();
            var group       = new GroupService(rockContext).Get(groupGuid);

            if (group != null)
            {
                List <int> groupIds = new List <int>();
                GetGroupIds(groupIds, sendToDescendants, group);

                var recipients = new List <RecipientData>();

                var groupMemberList = new GroupMemberService(rockContext).Queryable().Where(gm =>
                                                                                            groupIds.Contains(gm.GroupId) &&
                                                                                            gm.GroupMemberStatus == GroupMemberStatus.Active)
                                      .ToList();
                foreach (GroupMember groupMember in groupMemberList)
                {
                    var person = groupMember.Person;
                    if (!person.IsEmailActive || person.Email.IsNullOrWhiteSpace() || person.EmailPreference == EmailPreference.DoNotEmail)
                    {
                        continue;
                    }

                    var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null);
                    mergeFields.Add("Person", person);
                    mergeFields.Add("GroupMember", groupMember);
                    mergeFields.Add("Group", groupMember.Group);

                    recipients.Add(new RecipientData(groupMember.Person.Email, mergeFields));
                }

                var errors = new List <string>();
                if (recipients.Any())
                {
                    var emailMessage = new RockEmailMessage(emailTemplateGuid);
                    emailMessage.SetRecipients(recipients);
                    emailMessage.Send(out errors);
                }

                context.Result = string.Format("{0} emails sent", recipients.Count());

                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;
                }
            }
        }
示例#6
0
        /// <summary>
        /// Gets the objects in folder without recursion. i.e. will get the list of files
        /// and folders in the folder but not the contents of the subfolders. Subfolders
        /// will not have the ModifiedDate prop filled in as Amazon doesn't provide it in
        /// this context.
        /// </summary>
        /// <param name="assetStorageProvider">The asset storage Provider.</param>
        /// <param name="asset">The asset.</param>
        /// <returns></returns>
        public override List <Asset> ListObjectsInFolder(AssetStorageProvider assetStorageProvider, Asset asset)
        {
            string rootFolder = FixRootFolder(GetAttributeValue(assetStorageProvider, AttributeKeys.RootFolder));
            string bucketName = GetAttributeValue(assetStorageProvider, AttributeKeys.Bucket);

            asset.Key = FixKey(asset, rootFolder);
            HasRequirementsFolder(asset);

            try
            {
                AmazonS3Client client = GetAmazonS3Client(assetStorageProvider);

                ListObjectsV2Request request = new ListObjectsV2Request();
                request.BucketName = bucketName;
                request.Prefix     = asset.Key == "/" ? rootFolder : asset.Key;
                request.Delimiter  = "/";

                var assets     = new List <Asset>();
                var subFolders = new HashSet <string>();

                ListObjectsV2Response response;

                // S3 will only return 1,000 keys per response and sets IsTruncated = true, the do-while loop will run and fetch keys until IsTruncated = false.
                do
                {
                    response = client.ListObjectsV2(request);
                    foreach (S3Object s3Object in response.S3Objects)
                    {
                        if (s3Object.Key == null)
                        {
                            continue;
                        }

                        var responseAsset = CreateAssetFromS3Object(assetStorageProvider, s3Object, client.Config.RegionEndpoint.SystemName);
                        assets.Add(responseAsset);
                    }

                    // After setting the delimiter S3 will filter out any prefixes below that in response.S3Objects.
                    // So we need to inspect response.CommonPrefixes to get the prefixes inside the folder.
                    foreach (string subFolder in response.CommonPrefixes)
                    {
                        if (subFolder.IsNotNullOrWhiteSpace())
                        {
                            subFolders.Add(subFolder);
                        }
                    }

                    request.ContinuationToken = response.NextContinuationToken;
                } while (response.IsTruncated);

                // Add the subfolders to the asset collection
                foreach (string subFolder in subFolders)
                {
                    var subFolderAsset = CreateAssetFromCommonPrefix(subFolder, client.Config.RegionEndpoint.SystemName, bucketName);
                    assets.Add(subFolderAsset);
                }

                return(assets.OrderBy(a => a.Key, StringComparer.OrdinalIgnoreCase).ToList());
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(ex);
                throw;
            }
        }
示例#7
0
        /// <summary>
        /// Trigger Future Followup Workflow
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="futureFollowupDateWorkflows">The future follow-up date workflows.</param>
        /// <returns></returns>
        private string TriggerFutureFollowupWorkFlow(IJobExecutionContext context, List <ConnectionWorkflow> futureFollowupDateWorkflows)
        {
            try
            {
                JobDataMap dataMap = context.JobDetail.JobDataMap;

                context.UpdateLastStatusMessage($"Processing future follow-up workFlows.");

                int recordsUpdated   = 0;
                int triggerWorkflow  = 0;
                int recordsWithError = 0;

                if (futureFollowupDateWorkflows.Any())
                {
                    var rockContext = new RockContext();

                    var connectionOpportunityIds = futureFollowupDateWorkflows
                                                   .Where(a => a.ConnectionOpportunityId.HasValue)
                                                   .Select(a => a.ConnectionOpportunityId.Value)
                                                   .ToList();

                    var connectionTypeIds = futureFollowupDateWorkflows
                                            .Where(a => a.ConnectionTypeId.HasValue)
                                            .Select(a => a.ConnectionTypeId.Value)
                                            .ToList();

                    var allConnectionOpportunities = new List <ConnectionOpportunity>();
                    if (connectionOpportunityIds.Any() || connectionTypeIds.Any())
                    {
                        var relatedConnectionOpportunities = new ConnectionOpportunityService(rockContext)
                                                             .Queryable()
                                                             .AsNoTracking()
                                                             .Where(o => connectionOpportunityIds.Contains(o.Id) || connectionTypeIds.Contains(o.ConnectionTypeId))
                                                             .ToList();
                        allConnectionOpportunities.AddRange(relatedConnectionOpportunities);
                    }


                    if (allConnectionOpportunities.Any())
                    {
                        connectionOpportunityIds = allConnectionOpportunities.Select(a => a.Id).ToList();
                        var      numberOfDaysToLookBack = dataMap.GetString(AttributeKeys.NumberOfDaysToLookBack).AsInteger();
                        DateTime midnightToday          = RockDateTime.Today.AddDays(1);
                        DateTime startDate = RockDateTime.Today.AddDays(-numberOfDaysToLookBack);

                        var connectionRequestService   = new ConnectionRequestService(rockContext);
                        var eligibleConnectionRequests = connectionRequestService
                                                         .Queryable("ConnectionRequestWorkflows")
                                                         .AsNoTracking()
                                                         .Where(c => connectionOpportunityIds.Contains(c.ConnectionOpportunityId) &&
                                                                c.ConnectionState == ConnectionState.FutureFollowUp &&
                                                                c.FollowupDate.HasValue &&
                                                                c.FollowupDate >= startDate &&
                                                                c.FollowupDate < midnightToday
                                                                )
                                                         .ToList();

                        foreach (var connectionRequest in eligibleConnectionRequests)
                        {
                            try
                            {
                                using (var updateRockContext = new RockContext())
                                {
                                    // increase the timeout just in case.
                                    updateRockContext.Database.CommandTimeout = 180;
                                    updateRockContext.SourceOfChange          = SOURCE_OF_CHANGE;
                                    var connectionOpportunity = allConnectionOpportunities.SingleOrDefault(a => a.Id == connectionRequest.ConnectionOpportunityId);
                                    if (connectionOpportunity != null)
                                    {
                                        var opportunityWorkflows = futureFollowupDateWorkflows
                                                                   .Where(w =>
                                                                          (w.ConnectionOpportunityId.HasValue && w.ConnectionOpportunityId.Value == connectionOpportunity.Id) ||
                                                                          (w.ConnectionTypeId.HasValue && w.ConnectionTypeId.Value == connectionOpportunity.ConnectionTypeId));

                                        foreach (var connectionWorkflow in opportunityWorkflows
                                                 .Where(a => !connectionRequest.ConnectionRequestWorkflows.Any(b => b.ConnectionWorkflowId == a.Id)))
                                        {
                                            LaunchWorkflow(updateRockContext, connectionRequest, connectionWorkflow, ConnectionWorkflowTriggerType.FutureFollowupDateReached.ConvertToString());
                                            triggerWorkflow += 1;
                                        }

                                        updateRockContext.ConnectionRequests.Attach(connectionRequest);
                                        connectionRequest.ConnectionState = ConnectionState.Active;
                                        updateRockContext.SaveChanges();
                                        recordsUpdated += 1;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                // Log exception and keep on trucking.
                                ExceptionLogService.LogException(new Exception($"Exception occurred trying to trigger future followup workFlow:{connectionRequest.Id}.", ex), _httpContext);
                                recordsWithError += 1;
                            }
                        }
                    }
                }

                // Format the result message
                string result = $"{recordsUpdated:N0} connection request records triggered {triggerWorkflow} workflows.";
                if (recordsWithError > 0)
                {
                    result += $"{recordsWithError:N0} records logged an exception.";
                }

                return(result);
            }
            catch (Exception ex)
            {
                // Log exception and return the exception messages.
                ExceptionLogService.LogException(ex, _httpContext);

                return(ex.Messages().AsDelimited("; "));
            }
        }
示例#8
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public virtual void Execute(IJobExecutionContext context)
        {
            JobDataMap dataMap            = context.JobDetail.JobDataMap;
            int        expirationDays     = dataMap.GetInt("ExpirationPeriod");
            int        delayMinutes       = dataMap.GetInt("DelayPeriod");
            int        maxParallelization = dataMap.GetInt("ParallelCommunications");

            List <Model.Communication> sendCommunications = null;
            var stopWatch = Stopwatch.StartNew();

            using (var rockContext = new RockContext())
            {
                sendCommunications = new CommunicationService(rockContext)
                                     .GetQueued(expirationDays, delayMinutes, false, false)
                                     .AsNoTracking()
                                     .ToList()
                                     .OrderBy(c => c.Id)
                                     .ToList();
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: Queued communication query runtime: {1} ms", nameof(SendCommunications), stopWatch.ElapsedMilliseconds);

            if (sendCommunications == null)
            {
                context.Result = "No communications to send";
            }

            var exceptionMsgs      = new List <string>();
            int communicationsSent = 0;

            stopWatch = Stopwatch.StartNew();
            var sendCommunicationTasks = new List <Task <SendCommunicationAsyncResult> >();

            RockLogger.Log.Debug(RockLogDomains.Jobs, "{0}: Send communications {1} communications.", nameof(SendCommunications), sendCommunicationTasks.Count);
            using (var mutex = new SemaphoreSlim(maxParallelization))
            {
                for (var i = 0; i < sendCommunications.Count(); i++)
                {
                    mutex.Wait();
                    var comm = sendCommunications[i];

                    sendCommunicationTasks.Add(Task.Run <SendCommunicationAsyncResult>(async() => await SendCommunicationAsync(comm, mutex).ConfigureAwait(false)));
                }

                /*
                 * Now that we have fired off all of the task, we need to wait for them to complete, get their results,
                 * and then process that result. Once all of the task have been completed we can continue.
                 */
                while (sendCommunicationTasks.Count > 0)
                {
                    // Wait for a task to complete using WhenAny and then return the completed task. Since we are not running in an asynchronous method we need to use RunSync.
                    var completedTask = AsyncHelper.RunSync(() => Task.WhenAny <SendCommunicationAsyncResult>(sendCommunicationTasks.ToArray()));

                    // Get and process the result of the completed task.
                    var communicationResult = completedTask.Result;
                    if (communicationResult.Exception != null)
                    {
                        var agException = communicationResult.Exception as AggregateException;
                        if (agException == null)
                        {
                            exceptionMsgs.Add($"Exception occurred sending communication ID:{communicationResult.Communication.Id}:{Environment.NewLine}    {communicationResult.Exception.Messages().AsDelimited( Environment.NewLine + "   " )}");
                        }
                        else
                        {
                            var allExceptions = agException.Flatten();
                            foreach (var ex in allExceptions.InnerExceptions)
                            {
                                exceptionMsgs.Add($"Exception occurred sending communication ID:{communicationResult.Communication.Id}:{Environment.NewLine}    {ex.Messages().AsDelimited( Environment.NewLine + "   " )}");
                            }
                        }

                        ExceptionLogService.LogException(communicationResult.Exception, System.Web.HttpContext.Current);
                    }
                    else
                    {
                        communicationsSent++;
                    }

                    sendCommunicationTasks.Remove(completedTask);
                }
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: Send communications runtime: {1} ms", nameof(SendCommunications), stopWatch.ElapsedMilliseconds);

            if (communicationsSent > 0)
            {
                context.Result = string.Format("Sent {0} {1}", communicationsSent, "communication".PluralizeIf(communicationsSent > 1));
            }
            else
            {
                context.Result = "No communications to send";
            }

            if (exceptionMsgs.Any())
            {
                throw new Exception("One or more exceptions occurred sending communications..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
            }

            // check for communications that have not been sent but are past the expire date. Mark them as failed and set a warning.
            var expireDateTimeEndWindow = RockDateTime.Now.AddDays(0 - expirationDays);

            // limit the query to only look a week prior to the window to avoid performance issue (it could be slow to query at ALL the communication recipient before the expire date, as there could several years worth )
            var expireDateTimeBeginWindow = expireDateTimeEndWindow.AddDays(-7);

            stopWatch = Stopwatch.StartNew();
            using (var rockContext = new RockContext())
            {
                var qryExpiredRecipients = new CommunicationRecipientService(rockContext).Queryable()
                                           .Where(cr =>
                                                  cr.Communication.Status == CommunicationStatus.Approved &&
                                                  cr.Status == CommunicationRecipientStatus.Pending &&
                                                  (
                                                      (!cr.Communication.FutureSendDateTime.HasValue && cr.Communication.ReviewedDateTime.HasValue && cr.Communication.ReviewedDateTime <expireDateTimeEndWindow && cr.Communication.ReviewedDateTime> expireDateTimeBeginWindow) ||
                                                      (cr.Communication.FutureSendDateTime.HasValue && cr.Communication.FutureSendDateTime <expireDateTimeEndWindow && cr.Communication.FutureSendDateTime> expireDateTimeBeginWindow)
                                                  ));

                rockContext.BulkUpdate(qryExpiredRecipients, c => new CommunicationRecipient {
                    Status = CommunicationRecipientStatus.Failed, StatusNote = "Communication was not sent before the expire window (possibly due to delayed approval)."
                });
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: Query expired communications runtime: {1} ms", nameof(SendCommunications), stopWatch.ElapsedMilliseconds);
        }
示例#9
0
        /// <summary>
        /// Uses Lava to resolve any merge codes within the content using the values in the merge objects.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <param name="mergeObjects">The merge objects.</param>
        /// <param name="enabledLavaCommands">The enabled lava commands.</param>
        /// <param name="encodeStrings">if set to <c>true</c> [encode strings].</param>
        /// <param name="throwExceptionOnErrors">if set to <c>true</c> [throw exception on errors].</param>
        /// <returns></returns>
        public static string ResolveMergeFields(this string content, IDictionary <string, object> mergeObjects, string enabledLavaCommands, bool encodeStrings = false, bool throwExceptionOnErrors = false)
        {
            try
            {
                if (!content.HasMergeFields())
                {
                    return(content ?? string.Empty);
                }

                if (GlobalAttributesCache.Get().LavaSupportLevel == Lava.LavaSupportLevel.LegacyWithWarning && mergeObjects.ContainsKey("GlobalAttribute"))
                {
                    if (hasLegacyGlobalAttributeLavaMergeFields.IsMatch(content))
                    {
                        Rock.Model.ExceptionLogService.LogException(new Rock.Lava.LegacyLavaSyntaxDetectedException("GlobalAttribute", ""), System.Web.HttpContext.Current);
                    }
                }

                Template template = GetTemplate(content);
                template.Registers.AddOrReplace("EnabledCommands", enabledLavaCommands);

                string result;

                if (encodeStrings)
                {
                    // if encodeStrings = true, we want any string values to be XML Encoded (
                    RenderParameters renderParameters = new RenderParameters();
                    renderParameters.LocalVariables        = Hash.FromDictionary(mergeObjects);
                    renderParameters.ValueTypeTransformers = new Dictionary <Type, Func <object, object> >();
                    renderParameters.ValueTypeTransformers[typeof(string)] = EncodeStringTransformer;
                    result = template.Render(renderParameters);
                }
                else
                {
                    result = template.Render(Hash.FromDictionary(mergeObjects));
                }

                if (throwExceptionOnErrors && template.Errors.Any())
                {
                    if (template.Errors.Count == 1)
                    {
                        throw template.Errors[0];
                    }
                    else
                    {
                        throw new AggregateException(template.Errors);
                    }
                }

                return(result);
            }
            catch (System.Threading.ThreadAbortException)
            {
                // Do nothing...it's just a Lava PageRedirect that just happened.
                return(string.Empty);
            }
            catch (Exception ex)
            {
                if (throwExceptionOnErrors)
                {
                    throw;
                }
                else
                {
                    ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                    return("Error resolving Lava merge fields: " + ex.Message);
                }
            }
        }
 /// <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);
 }
示例#11
0
文件: Twilio.cs 项目: sjison/Rock
        /// <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 smsMessage = rockMessage as RockSMSMessage;

            if (smsMessage != null)
            {
                // Validate From Number
                if (smsMessage.FromNumber == null)
                {
                    errorMessages.Add("A From Number was not provided.");
                    return(false);
                }

                string accountSid = GetAttributeValue("SID");
                string authToken  = GetAttributeValue("Token");
                TwilioClient.Init(accountSid, authToken);

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

                int?throttlingWaitTimeMS = null;
                if (this.IsLongCodePhoneNumber(smsMessage.FromNumber.Value))
                {
                    throttlingWaitTimeMS = this.GetAttributeValue("Long-CodeThrottling").AsIntegerOrNull();
                }

                List <Uri> attachmentMediaUrls = GetAttachmentMediaUrls(rockMessage.Attachments.AsQueryable());

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

                        string message = ResolveText(smsMessage.Message, smsMessage.CurrentPerson, smsMessage.EnabledLavaCommands, recipientData.MergeFields, smsMessage.AppRoot, smsMessage.ThemeRoot);

                        MessageResource response = SendToTwilio(smsMessage.FromNumber.Value, null, attachmentMediaUrls, message, recipientData.To);

                        if (response.ErrorMessage.IsNotNullOrWhitespace())
                        {
                            errorMessages.Add(response.ErrorMessage);
                        }
                    }
                    catch (Exception ex)
                    {
                        errorMessages.Add(ex.Message);
                        ExceptionLogService.LogException(ex);
                    }

                    if (throttlingWaitTimeMS.HasValue)
                    {
                        System.Threading.Thread.Sleep(throttlingWaitTimeMS.Value);
                    }
                }
            }

            return(!errorMessages.Any());
        }
示例#12
0
文件: Twilio.cs 项目: sjison/Rock
        /// <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>
        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).Get(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 = Rock.Web.Cache.GlobalAttributesCache.Read();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string fromPhone = communication.SMSFromDefinedValue?.Value;
                    if (string.IsNullOrWhiteSpace(fromPhone))
                    {
                        // just in case we got this far without a From Number, throw an exception
                        throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString());
                    }

                    if (!string.IsNullOrWhiteSpace(fromPhone))
                    {
                        int?throttlingWaitTimeMS = null;
                        if (this.IsLongCodePhoneNumber(fromPhone))
                        {
                            throttlingWaitTimeMS = this.GetAttributeValue("Long-CodeThrottling").AsIntegerOrNull();
                        }

                        string accountSid = GetAttributeValue("SID");
                        string authToken  = GetAttributeValue("Token");
                        TwilioClient.Init(accountSid, authToken);

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

                        string callbackUrl = publicAppRoot + "Webhooks/Twilio.ashx";

                        var        smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS);
                        List <Uri> attachmentMediaUrls            = new List <Uri>();
                        if (smsAttachmentsBinaryFileIdList.Any())
                        {
                            attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(communicationRockContext).GetByIds(smsAttachmentsBinaryFileIdList));
                        }

                        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
                                    {
                                        var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers
                                                          .Where(p => p.IsMessagingEnabled)
                                                          .FirstOrDefault();

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

                                            string message = ResolveText(communication.SMSMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                            string twilioNumber = phoneNumber.Number;
                                            if (!string.IsNullOrWhiteSpace(phoneNumber.CountryCode))
                                            {
                                                twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number;
                                            }

                                            MessageResource response = SendToTwilio(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber);

                                            recipient.Status = CommunicationRecipientStatus.Delivered;
                                            recipient.TransportEntityTypeName = this.GetType().FullName;
                                            recipient.UniqueMessageId         = response.Sid;

                                            try
                                            {
                                                var historyService = new HistoryService(recipientRockContext);
                                                historyService.Add(new History
                                                {
                                                    CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                    EntityTypeId           = personEntityTypeId,
                                                    CategoryId             = communicationCategoryId,
                                                    EntityId            = recipient.PersonAlias.PersonId,
                                                    Summary             = "Sent SMS message.",
                                                    Caption             = message.Truncate(200),
                                                    RelatedEntityTypeId = communicationEntityTypeId,
                                                    RelatedEntityId     = communication.Id
                                                });
                                            }
                                            catch (Exception ex)
                                            {
                                                ExceptionLogService.LogException(ex, null);
                                            }
                                        }
                                        else
                                        {
                                            recipient.Status     = CommunicationRecipientStatus.Failed;
                                            recipient.StatusNote = "No Phone Number with Messaging Enabled";
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "Twilio Exception: " + ex.Message;
                                    }
                                }

                                recipientRockContext.SaveChanges();

                                if (throttlingWaitTimeMS.HasValue)
                                {
                                    System.Threading.Thread.Sleep(throttlingWaitTimeMS.Value);
                                }
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
示例#13
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);
                }
            }
        }
示例#14
0
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid()
        {
            var rockContext = new RockContext();

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

            string subject = tbSubject.Text;

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

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

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

            string status = ddlStatus.SelectedValue;

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

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

            if (nreRecipientCount.LowerValue.HasValue)
            {
                communicationsQuery = communicationsQuery.Where(a => a.Recipients.Count() >= nreRecipientCount.LowerValue.Value);
            }

            if (nreRecipientCount.UpperValue.HasValue)
            {
                communicationsQuery = communicationsQuery.Where(a => a.Recipients.Count() <= nreRecipientCount.UpperValue.Value);
            }

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

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

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

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

            string content = tbContent.Text;

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

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

            var communicationItemQuery = communicationsQuery
                                         .WherePersonAuthorizedToView(rockContext, this.CurrentPerson)
                                         .Select(c => new CommunicationItem
            {
                Id = c.Id,
                CommunicationType   = c.CommunicationType,
                Subject             = string.IsNullOrEmpty(c.Subject) ? (string.IsNullOrEmpty(c.PushTitle) ? c.Name : c.PushTitle) : c.Subject,
                CreatedDateTime     = c.CreatedDateTime,
                SendDateTime        = c.SendDateTime ?? c.FutureSendDateTime,
                SendDateTimePrefix  = c.SendDateTime == null && c.FutureSendDateTime != null ? "<span class='label label-info'>Future</span>&nbsp;" : string.Empty,
                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)
            {
                communicationItemQuery = communicationItemQuery.Sort(sortProperty);
            }
            else
            {
                communicationItemQuery = communicationItemQuery.OrderByDescending(c => c.SendDateTime);
            }

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

            try
            {
                gCommunication.SetLinqDataSource(communicationItemQuery);
                gCommunication.DataBind();
            }
            catch (Exception exception)
            {
                ExceptionLogService.LogException(exception);

                var sqlTimeoutException = ReportingHelper.FindSqlTimeoutException(exception);

                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>",
                    sqlTimeoutException != null ? sqlTimeoutException.Message : exception.Message);

                // if an error occurred, bind the grid with an empty object list
                gCommunication.DataSource = new List <object>();
                gCommunication.DataBind();
            }
        }
示例#15
0
        /// <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;
            var messages         = new List <string>();
            var workflowsStarted = 0;
            var workflowTypeGuid = dataMap.GetString("WorkflowType").AsGuidOrNull();

            if (workflowTypeGuid.HasValue)
            {
                var workflowType = WorkflowTypeCache.Get(workflowTypeGuid.Value);

                if (workflowType != null)
                {
                    var username     = Encryption.DecryptString(dataMap.GetString("Username"));
                    var password     = Encryption.DecryptString(dataMap.GetString("Password"));
                    var emailAddress = dataMap.GetString("EmailAddress");
                    var url          = new Uri(dataMap.GetString("ServerUrl"));
                    var maxEmails    = dataMap.GetString("MaxEmails").AsInteger();
                    var delete       = dataMap.GetString("DeleteMessages").AsBoolean();
                    var onePer       = dataMap.GetString("OneWorkflowPerConversation").AsBoolean();

                    Dictionary <string, string> attributeKeyMap = null;
                    var workflowAttributeKeys = dataMap.GetString("WorkflowAttributes");
                    if (workflowAttributeKeys.IsNotNullOrWhiteSpace())
                    {
                        attributeKeyMap = workflowAttributeKeys.AsDictionaryOrNull();
                    }

                    attributeKeyMap = attributeKeyMap ?? new Dictionary <string, string>();

                    try
                    {
                        using (var rockContext = new RockContext())
                        {
                            var service = new ExchangeService();
                            service.Credentials  = new WebCredentials(username, password);
                            service.TraceEnabled = true;
                            service.TraceFlags   = TraceFlags.All;
                            service.Url          = url;

                            var findItemPropertySet = new PropertySet(BasePropertySet.IdOnly);
                            findItemPropertySet.Add(ItemSchema.DateTimeReceived);

                            var userMailbox = new Mailbox(emailAddress);
                            var folderId    = new FolderId(WellKnownFolderName.Inbox, userMailbox);
                            var sf          = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
                            var view        = new ItemView(maxEmails);
                            view.PropertySet = findItemPropertySet;
                            view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Descending);
                            var findResults = service.FindItems(folderId, sf, view);

                            if (findResults.Items.Count > 0)
                            {
                                var getMessagePropertySet = new PropertySet(BasePropertySet.FirstClassProperties);
                                //getMessagePropertySet.Add( ItemSchema.Attachments ); // for future

                                foreach (var item in findResults)
                                {
                                    var message = EmailMessage.Bind(service, item.Id, getMessagePropertySet);
                                    message.Load();

                                    var foreignKey       = string.Empty;
                                    var existingWorkflow = new Workflow();
                                    var createWorkflow   = true;

                                    if (onePer)
                                    {
                                        var conversationId = message.ConversationId.UniqueId.ToString();

                                        if (conversationId.Length > 100)
                                        {
                                            foreignKey = conversationId.Substring(conversationId.Length - 100, 100);
                                        }
                                        else
                                        {
                                            foreignKey = conversationId;
                                        }

                                        existingWorkflow = new WorkflowService(rockContext)
                                                           .Queryable()
                                                           .AsNoTracking()
                                                           .FirstOrDefault(w => w.ActivatedDateTime.HasValue && !w.CompletedDateTime.HasValue && w.ForeignKey.Equals(foreignKey, StringComparison.Ordinal));

                                        createWorkflow = existingWorkflow.IsNull();
                                    }
                                    else
                                    {
                                        var emailId = message.Id.UniqueId.ToString();

                                        if (emailId.Length > 100)
                                        {
                                            foreignKey = emailId.Substring(emailId.Length - 100, 100);
                                        }
                                        else
                                        {
                                            foreignKey = emailId;
                                        }
                                    }

                                    if (createWorkflow)
                                    {
                                        var workflow = Rock.Model.Workflow.Activate(workflowType, string.Format("{0} <{1}> [{2}]", message.From.Name.ToStringSafe(), message.From.Address.ToStringSafe(), message.DateTimeReceived.ToShortDateTimeString()));
                                        workflow.ForeignKey = foreignKey;

                                        workflow.LoadAttributes(rockContext);

                                        foreach (var keyPair in attributeKeyMap)
                                        {
                                            var value = string.Empty;

                                            switch (keyPair.Value)
                                            {
                                            case "DateReceived":
                                                value = message.DateTimeReceived.ToString("o", CultureInfo.CreateSpecificCulture("en-US"));
                                                break;

                                            case "FromEmail":
                                                value = message.From.Address.ToStringSafe();
                                                break;

                                            case "FromName":
                                                value = message.From.Name.ToStringSafe();
                                                break;

                                            case "Subject":
                                                value = message.Subject.ToStringSafe();
                                                break;

                                            case "Body":
                                                value = message.Body.Text;
                                                break;

                                            default:
                                                break;
                                            }

                                            if (workflow.Attributes.ContainsKey(keyPair.Key))
                                            {
                                                workflow.SetAttributeValue(keyPair.Key, value);
                                            }
                                            else
                                            {
                                                messages.Add(string.Format("'{0}' is not an attribute key in the activated workflow: '{1}'", keyPair.Key, workflow.Name));
                                            }
                                        }

                                        List <string> workflowErrorMessages = new List <string>();
                                        new Rock.Model.WorkflowService(rockContext).Process(workflow, out workflowErrorMessages);
                                        messages.AddRange(workflowErrorMessages);
                                        workflowsStarted++;
                                    }
                                    else if (existingWorkflow?.Id > 0)
                                    {
                                        existingWorkflow.LoadAttributes();

                                        foreach (var keyPair in attributeKeyMap)
                                        {
                                            if (keyPair.Value.Contains("Body"))
                                            {
                                                var newValue = message.Body.Text;

                                                if (existingWorkflow.Attributes.ContainsKey(keyPair.Key))
                                                {
                                                    var existingValue = existingWorkflow.GetAttributeValue(keyPair.Key);
                                                    var value         = string.Format("{0}{1}{2}", existingValue, Environment.NewLine, newValue);
                                                    existingWorkflow.SetAttributeValue(keyPair.Key, value);
                                                }
                                                else
                                                {
                                                    messages.Add(string.Format("'{0}' is not an attribute key in the activated workflow: '{1}'", keyPair.Key, existingWorkflow.Name));
                                                }
                                            }
                                        }

                                        existingWorkflow.SaveAttributeValues();

                                        messages.Add(string.Format("{0} workflow was appended.", existingWorkflow.Name));
                                    }

                                    message.IsRead = true;
                                    message.Update(ConflictResolutionMode.AlwaysOverwrite, true);

                                    if (delete)
                                    {
                                        message.Delete(DeleteMode.MoveToDeletedItems);
                                    }
                                }
                            }

                            if (workflowsStarted > 0)
                            {
                                messages.Add(string.Format("Started {0} {1}", workflowsStarted, "workflow".PluralizeIf(workflowsStarted > 1)));
                            }
                            else
                            {
                                messages.Add("No workflows started");
                            }

                            var results = new StringBuilder();
                            foreach (var message in messages)
                            {
                                results.AppendLine(message);
                            }
                            context.Result = results.ToString();
                        }
                    }
                    catch (System.Exception ex)
                    {
                        var context2 = HttpContext.Current;
                        ExceptionLogService.LogException(ex, context2);
                        throw;
                    }
                }
                else
                {
                    context.Result = "No valid workflow type found.";
                }
            }
            else
            {
                context.Result = "Valid workflow type guid was not set.";
            }
        }
示例#16
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)
        {
            HttpContext context = (HttpContext)result.AsyncState;

            try
            {
                // restore the command from the context
                SqlCommand cmd = (SqlCommand)context.Items["cmd"];
                using (SqlDataReader reader = cmd.EndExecuteReader(result))
                {
                    reader.Read();
                    context.Response.Clear();
                    var fileName = (string)reader["FileName"];
                    context.Response.AddHeader("content-disposition", string.Format("inline;filename={0}", fileName));
                    context.Response.ContentType = (string)reader["MimeType"];

                    var entityTypeName = (string)reader["StorageTypeName"];
                    var provider       = ProviderContainer.GetComponent(entityTypeName);

                    if (provider is Database)
                    {
                        context.Response.BinaryWrite((byte[])reader["Data"]);
                    }
                    else
                    {
                        var    url = (string)reader["Url"];
                        Stream stream;

                        if (url.StartsWith("~/"))
                        {
                            var path     = context.Server.MapPath(url);
                            var fileInfo = new FileInfo(path);
                            stream = fileInfo.Open(FileMode.Open, FileAccess.Read);
                        }
                        else
                        {
                            var request  = WebRequest.Create(url);
                            var response = request.GetResponse();
                            stream = response.GetResponseStream();
                        }

                        if (stream != null)
                        {
                            using (var memoryStream = new MemoryStream())
                            {
                                stream.CopyTo(memoryStream);
                                stream.Close();
                                context.Response.BinaryWrite(memoryStream.ToArray());
                            }
                        }
                        else
                        {
                            context.Response.StatusCode        = 404;
                            context.Response.StatusDescription = "Unable to find the requested file.";
                        }
                    }

                    context.Response.Flush();
                    context.Response.End();
                }
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(ex, context);
                context.Response.StatusCode        = 500;
                context.Response.StatusDescription = ex.Message;
                context.Response.Flush();
                context.Response.End();
            }
        }
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute( IJobExecutionContext context )
        {
            JobDataMap dataMap = context.JobDetail.JobDataMap;
            int sqlCommandTimeout = dataMap.GetString( TIMEOUT_KEY ).AsIntegerOrNull() ?? 300;
            StringBuilder results = new StringBuilder();
            int updatedDataViewCount = 0;
            var errors = new List<string>();
            List<Exception> exceptions = new List<Exception>();

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

                // get a list of all the data views that need to be refreshed
                var expiredPersistedDataViews = new DataViewService( rockContext ).Queryable()
                    .Where( a => a.PersistedScheduleIntervalMinutes.HasValue )
                    .Where( a =>
                        ( a.PersistedLastRefreshDateTime == null )
                        || ( System.Data.Entity.SqlServer.SqlFunctions.DateAdd( "mi", a.PersistedScheduleIntervalMinutes.Value, a.PersistedLastRefreshDateTime.Value ) < currentDateTime )
                        );

                var expiredPersistedDataViewsList = expiredPersistedDataViews.ToList();
                foreach ( var dataView in expiredPersistedDataViewsList )
                {
                    var name = dataView.Name;
                    try
                    {
                        context.UpdateLastStatusMessage( $"Updating {dataView.Name}" );
                        dataView.PersistResult( sqlCommandTimeout );
                        dataView.PersistedLastRefreshDateTime = RockDateTime.Now;
                        rockContext.SaveChanges();
                        updatedDataViewCount++;
                    }
                    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 data view '{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;
                    }
                }
            }

            // Format the result message
            results.AppendLine( $"Updated {updatedDataViewCount} {"dataview".PluralizeIf( updatedDataViewCount != 1 )}" );
            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 ( updatedDataViewCount == 0 )
                {
                    throw new AggregateException( exceptions.ToArray() );
                }
            }
        }
        /// <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 registrations where
            //    + template is active
            //    + instance is active
            //    + template has a number of days between reminders
            //    + template as fields needed to send a reminder email
            //    + the registration has a cost
            //    + the registration has been closed within the last xx days (to prevent eternal nagging)

            using (RockContext rockContext = new RockContext())
            {
                int sendCount = 0;
                int registrationInstanceCount = 0;

                var appRoot = GlobalAttributesCache.Get().GetValue("PublicApplicationRoot");

                RegistrationService registrationService = new RegistrationService(rockContext);

                var currentDate = RockDateTime.Today;
                var cutoffDays  = dataMap.GetString("CutoffDate").AsIntegerOrNull() ?? 30;

                var registrations = registrationService.Queryable("RegistrationInstance")
                                    .Where(r =>
                                           r.RegistrationInstance.RegistrationTemplate.IsActive &&
                                           r.RegistrationInstance.IsActive == true &&
                                           (r.RegistrationInstance.RegistrationTemplate.PaymentReminderTimeSpan != null && r.RegistrationInstance.RegistrationTemplate.PaymentReminderTimeSpan != 0) &&
                                           r.RegistrationInstance.RegistrationTemplate.PaymentReminderEmailTemplate != null && r.RegistrationInstance.RegistrationTemplate.PaymentReminderEmailTemplate.Length > 0 &&
                                           r.RegistrationInstance.RegistrationTemplate.PaymentReminderFromEmail != null && r.RegistrationInstance.RegistrationTemplate.PaymentReminderFromEmail.Length > 0 &&
                                           r.RegistrationInstance.RegistrationTemplate.PaymentReminderSubject != null && r.RegistrationInstance.RegistrationTemplate.PaymentReminderSubject.Length > 0 &&
                                           (r.RegistrationInstance.RegistrationTemplate.Cost != 0 || (r.RegistrationInstance.Cost != null && r.RegistrationInstance.Cost != 0)) &&
                                           (r.RegistrationInstance.EndDateTime == null || currentDate <= System.Data.Entity.SqlServer.SqlFunctions.DateAdd("day", cutoffDays, r.RegistrationInstance.EndDateTime)))
                                    .ToList();

                registrationInstanceCount = registrations.Select(r => r.RegistrationInstance.Id).Distinct().Count();

                var errors = new List <string>();
                foreach (var registration in registrations)
                {
                    if (registration.DiscountedCost > registration.TotalPaid)
                    {
                        var reminderDate = RockDateTime.Now.AddDays(registration.RegistrationInstance.RegistrationTemplate.PaymentReminderTimeSpan.Value * -1);

                        if (registration.LastPaymentReminderDateTime < reminderDate)
                        {
                            Dictionary <string, object> mergeObjects = new Dictionary <string, object>();
                            mergeObjects.Add("Registration", registration);
                            mergeObjects.Add("RegistrationInstance", registration.RegistrationInstance);

                            var emailMessage = new RockEmailMessage();
                            emailMessage.AdditionalMergeFields = mergeObjects;
                            emailMessage.AddRecipient(new RecipientData(registration.ConfirmationEmail, mergeObjects));
                            emailMessage.FromEmail = registration.RegistrationInstance.RegistrationTemplate.PaymentReminderFromEmail;
                            emailMessage.FromName  = registration.RegistrationInstance.RegistrationTemplate.PaymentReminderSubject;
                            emailMessage.Subject   = registration.RegistrationInstance.RegistrationTemplate.PaymentReminderFromName;
                            emailMessage.Message   = registration.RegistrationInstance.RegistrationTemplate.PaymentReminderEmailTemplate;
                            var emailErrors = new List <string>();
                            emailMessage.Send(out errors);

                            registration.LastPaymentReminderDateTime = RockDateTime.Now;
                            rockContext.SaveChanges();

                            if (!emailErrors.Any())
                            {
                                sendCount++;
                            }
                        }
                    }
                }

                context.Result = string.Format("Sent {0} from {1}", "reminder".ToQuantity(sendCount), "registration instances".ToQuantity(registrationInstanceCount));
                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;
                }
            }
        }
示例#19
0
        /// <summary>
        /// Updates the scheduled jobs.
        /// </summary>
        /// <param name="context">The context.</param>
        private void UpdateScheduledJobs(IJobExecutionContext context)
        {
            var scheduler           = context.Scheduler;
            int jobsDeleted         = 0;
            int jobsScheduleUpdated = 0;

            var rockContext = new Rock.Data.RockContext();
            ServiceJobService    jobService          = new ServiceJobService(rockContext);
            List <ServiceJob>    activeJobList       = jobService.GetActiveJobs().ToList();
            List <Quartz.JobKey> scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList();

            // delete any jobs that are no longer exist (are are not set to active) in the database
            var quartsJobsToDelete = scheduledQuartzJobs.Where(a => !activeJobList.Any(j => j.Guid.Equals(a.Name.AsGuid())));

            foreach (JobKey jobKey in quartsJobsToDelete)
            {
                scheduler.DeleteJob(jobKey);
                jobsDeleted++;
            }

            // add any jobs that are not yet scheduled
            var newActiveJobs = activeJobList.Where(a => !scheduledQuartzJobs.Any(q => q.Name.AsGuid().Equals(a.Guid)));

            foreach (Rock.Model.ServiceJob job in newActiveJobs)
            {
                const string errorSchedulingStatus = "Error scheduling Job";
                try
                {
                    IJobDetail jobDetail  = jobService.BuildQuartzJob(job);
                    ITrigger   jobTrigger = jobService.BuildQuartzTrigger(job);

                    scheduler.ScheduleJob(jobDetail, jobTrigger);
                    jobsScheduleUpdated++;

                    if (job.LastStatus == errorSchedulingStatus)
                    {
                        job.LastStatusMessage = string.Empty;
                        job.LastStatus        = string.Empty;
                        rockContext.SaveChanges();
                    }
                }
                catch (Exception ex)
                {
                    ExceptionLogService.LogException(ex, null);

                    // create a friendly error message
                    string message = string.Format("Error scheduling the job: {0}.\n\n{2}", job.Name, job.Assembly, ex.Message);
                    job.LastStatusMessage = message;
                    job.LastStatus        = errorSchedulingStatus;
                }
            }

            rockContext.SaveChanges();

            // reload the jobs in case any where added/removed
            scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList();

            // update schedule if the schedule has changed
            foreach (var jobKey in scheduledQuartzJobs)
            {
                var jobCronTrigger = scheduler.GetTriggersOfJob(jobKey).OfType <ICronTrigger>().FirstOrDefault();
                if (jobCronTrigger != null)
                {
                    var activeJob = activeJobList.FirstOrDefault(a => a.Guid.Equals(jobKey.Name.AsGuid()));
                    if (activeJob != null)
                    {
                        bool rescheduleJob = false;

                        // fix up the schedule if it has changed
                        if (activeJob.CronExpression != jobCronTrigger.CronExpressionString)
                        {
                            rescheduleJob = true;
                        }

                        // update the job detail if it has changed
                        var scheduledJobDetail = scheduler.GetJobDetail(jobKey);
                        var jobDetail          = jobService.BuildQuartzJob(activeJob);

                        if (scheduledJobDetail != null && jobDetail != null)
                        {
                            if (scheduledJobDetail.JobType != jobDetail.JobType)
                            {
                                rescheduleJob = true;
                            }

                            if (scheduledJobDetail.JobDataMap.ToJson() != jobDetail.JobDataMap.ToJson())
                            {
                                rescheduleJob = true;
                            }
                        }

                        if (rescheduleJob)
                        {
                            const string errorReschedulingStatus = "Error re-scheduling Job";
                            try
                            {
                                ITrigger newJobTrigger       = jobService.BuildQuartzTrigger(activeJob);
                                bool     deletedSuccessfully = scheduler.DeleteJob(jobKey);
                                scheduler.ScheduleJob(jobDetail, newJobTrigger);
                                jobsScheduleUpdated++;

                                if (activeJob.LastStatus == errorReschedulingStatus)
                                {
                                    activeJob.LastStatusMessage = string.Empty;
                                    activeJob.LastStatus        = string.Empty;
                                    rockContext.SaveChanges();
                                }
                            }
                            catch (Exception ex)
                            {
                                ExceptionLogService.LogException(ex, null);

                                // create a friendly error message
                                string message = string.Format("Error re-scheduling the job: {0}.\n\n{2}", activeJob.Name, activeJob.Assembly, ex.Message);
                                activeJob.LastStatusMessage = message;
                                activeJob.LastStatus        = errorReschedulingStatus;
                            }
                        }
                    }
                }
            }

            context.Result = string.Empty;

            if (jobsDeleted > 0)
            {
                context.Result += string.Format("Deleted {0} job schedule(s)", jobsDeleted);
            }

            if (jobsScheduleUpdated > 0)
            {
                context.Result += (string.IsNullOrEmpty(context.Result as string) ? "" : " and ") + string.Format("Updated {0} schedule(s)", jobsScheduleUpdated);
            }
        }
示例#20
0
        /// <summary>
        /// Handles the Click event of the lbSave 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 lbSave_Click(object sender, EventArgs e)
        {
            if (_group != null && _occurrence != null)
            {
                var rockContext        = new RockContext();
                var attendanceService  = new AttendanceService(rockContext);
                var personAliasService = new PersonAliasService(rockContext);
                var locationService    = new LocationService(rockContext);

                bool dateAdjusted = false;

                DateTime startDate = _occurrence.Date;

                // If this is a manuall entered occurrence, check to see if date was changed
                if (!_occurrence.ScheduleId.HasValue)
                {
                    DateTime?originalDate = PageParameter("Date").AsDateTime();
                    if (originalDate.HasValue && originalDate.Value.Date != startDate.Date)
                    {
                        startDate    = originalDate.Value.Date;
                        dateAdjusted = true;
                    }
                }
                DateTime endDate = startDate.AddDays(1);

                var existingAttendees = attendanceService
                                        .Queryable("PersonAlias")
                                        .Where(a =>
                                               a.GroupId == _group.Id &&
                                               a.LocationId == _occurrence.LocationId &&
                                               a.ScheduleId == _occurrence.ScheduleId &&
                                               a.StartDateTime >= startDate &&
                                               a.StartDateTime < endDate);

                if (dateAdjusted)
                {
                    foreach (var attendee in existingAttendees)
                    {
                        attendee.StartDateTime = _occurrence.Date;
                    }
                }

                // If did not meet was selected and this was a manually entered occurrence (not based on a schedule/location)
                // then just delete all the attendance records instead of tracking a 'did not meet' value
                if (cbDidNotMeet.Checked && !_occurrence.ScheduleId.HasValue)
                {
                    foreach (var attendance in existingAttendees)
                    {
                        attendanceService.Delete(attendance);
                    }
                }
                else
                {
                    if (cbDidNotMeet.Checked)
                    {
                        // If the occurrence is based on a schedule, set the did not meet flags
                        foreach (var attendance in existingAttendees)
                        {
                            attendance.DidAttend   = null;
                            attendance.DidNotOccur = true;
                        }
                    }

                    foreach (var attendee in _attendees)
                    {
                        var attendance = existingAttendees
                                         .Where(a => a.PersonAlias.PersonId == attendee.PersonId)
                                         .FirstOrDefault();

                        if (attendance == null)
                        {
                            int?personAliasId = personAliasService.GetPrimaryAliasId(attendee.PersonId);
                            if (personAliasId.HasValue)
                            {
                                attendance               = new Attendance();
                                attendance.GroupId       = _group.Id;
                                attendance.ScheduleId    = _group.ScheduleId;
                                attendance.PersonAliasId = personAliasId;
                                attendance.StartDateTime = _occurrence.Date.Date.Add(_occurrence.StartTime);
                                attendance.LocationId    = _occurrence.LocationId;
                                attendance.CampusId      = locationService.GetCampusIdForLocation(_occurrence.LocationId);
                                attendance.ScheduleId    = _occurrence.ScheduleId;
                                attendanceService.Add(attendance);
                            }
                        }

                        if (attendance != null)
                        {
                            if (cbDidNotMeet.Checked)
                            {
                                attendance.DidAttend   = null;
                                attendance.DidNotOccur = true;
                            }
                            else
                            {
                                attendance.DidAttend   = attendee.Attended;
                                attendance.DidNotOccur = null;
                            }
                        }
                    }
                }

                if (_occurrence.LocationId.HasValue)
                {
                    Rock.CheckIn.KioskLocationAttendance.Flush(_occurrence.LocationId.Value);
                }

                rockContext.SaveChanges();

                WorkflowType workflowType     = null;
                Guid?        workflowTypeGuid = GetAttributeValue("Workflow").AsGuidOrNull();
                if (workflowTypeGuid.HasValue)
                {
                    var workflowTypeService = new WorkflowTypeService(rockContext);
                    workflowType = workflowTypeService.Get(workflowTypeGuid.Value);
                    if (workflowType != null)
                    {
                        try
                        {
                            var workflow = Workflow.Activate(workflowType, _group.Name);

                            workflow.SetAttributeValue("StartDateTime", _occurrence.Date.ToString("o"));
                            workflow.SetAttributeValue("Schedule", _group.Schedule.Guid.ToString());

                            List <string> workflowErrors;
                            new WorkflowService(rockContext).Process(workflow, _group, out workflowErrors);
                        }
                        catch (Exception ex)
                        {
                            ExceptionLogService.LogException(ex, this.Context);
                        }
                    }
                }

                NavigateToParentPage(new Dictionary <string, string> {
                    { "GroupId", _group.Id.ToString() }
                });
            }
        }
示例#21
0
        /// <summary>
        /// Creates the filter control.
        /// </summary>
        /// <param name="parentControl">The parent control.</param>
        /// <param name="filter">The filter.</param>
        /// <param name="setSelection">if set to <c>true</c> [set selection].</param>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="contentChannel">The content channel.</param>
        private void CreateFilterControl(Control parentControl, DataViewFilter filter, bool setSelection, RockContext rockContext, ContentChannel contentChannel)
        {
            try
            {
                if (filter.ExpressionType == FilterExpressionType.Filter)
                {
                    var filterControl = new FilterField
                    {
                        Entity = new ContentChannelItem
                        {
                            ContentChannelId     = contentChannel.Id,
                            ContentChannelTypeId = contentChannel.ContentChannelTypeId
                        }
                    };

                    parentControl.Controls.Add(filterControl);
                    filterControl.DataViewFilterGuid = filter.Guid;
                    filterControl.ID = string.Format("ff_{0}", filterControl.DataViewFilterGuid.ToString("N"));

                    // Remove the 'Other Data View' Filter as it doesn't really make sense to have it available in this scenario
                    filterControl.ExcludedFilterTypes    = new string[] { typeof(Rock.Reporting.DataFilter.OtherDataViewFilter).FullName };
                    filterControl.FilteredEntityTypeName = ITEM_TYPE_NAME;

                    if (filter.EntityTypeId.HasValue)
                    {
                        var entityTypeCache = EntityTypeCache.Get(filter.EntityTypeId.Value, rockContext);
                        if (entityTypeCache != null)
                        {
                            filterControl.FilterEntityTypeName = entityTypeCache.Name;
                        }
                    }

                    filterControl.Expanded = filter.Expanded;
                    if (setSelection)
                    {
                        try
                        {
                            filterControl.SetSelection(filter.Selection);
                        }
                        catch (Exception ex)
                        {
                            ExceptionLogService.LogException(new Exception("Exception setting selection for DataViewFilter: " + filter.Guid, ex));
                        }
                    }

                    filterControl.DeleteClick += filterControl_DeleteClick;
                }
                else
                {
                    var groupControl = new FilterGroup();
                    parentControl.Controls.Add(groupControl);
                    groupControl.DataViewFilterGuid = filter.Guid;
                    groupControl.ID = string.Format("fg_{0}", groupControl.DataViewFilterGuid.ToString("N"));
                    groupControl.FilteredEntityTypeName = ITEM_TYPE_NAME;
                    groupControl.IsDeleteEnabled        = parentControl is FilterGroup;
                    if (setSelection)
                    {
                        groupControl.FilterType = filter.ExpressionType;
                    }

                    groupControl.AddFilterClick   += groupControl_AddFilterClick;
                    groupControl.AddGroupClick    += groupControl_AddGroupClick;
                    groupControl.DeleteGroupClick += groupControl_DeleteGroupClick;
                    foreach (var childFilter in filter.ChildFilters)
                    {
                        CreateFilterControl(groupControl, childFilter, setSelection, rockContext, contentChannel);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionLogService.LogException(new Exception("Exception creating FilterControl for DataViewFilter: " + filter.Guid, ex));
            }
        }
示例#22
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)
        {
            StringBuilder message     = new StringBuilder();
            bool          sendMessage = false;

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

            // load job
            var rockContext = new RockContext();
            var jobService  = new ServiceJobService(rockContext);
            var job         = jobService.Get(jobId);

            // format the message
            message.Append(string.Format("The job {0} ran for {1} seconds on {2}.  Below is the results:<p>", job.Name, context.JobRunTime.TotalSeconds, context.FireTimeUtc.Value.DateTime.ToLocalTime()));

            // if noticiation staus is all set flag to send message
            if (job.NotificationStatus == JobNotificationStatus.All)
            {
                sendMessage = true;
            }

            // set last run date
            job.LastRunDateTime = RockDateTime.Now; // context.FireTimeUtc.Value.DateTime.ToLocalTime();

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

            // set the scheduler name
            job.LastRunSchedulerName = context.Scheduler.SchedulerName;

            // determine if an error occured
            if (jobException == null)
            {
                job.LastSuccessfulRunDateTime = job.LastRunDateTime;
                job.LastStatus        = "Success";
                job.LastStatusMessage = string.Empty;

                message.Append("Result: Success");

                // determine if message should be sent
                if (job.NotificationStatus == JobNotificationStatus.Success)
                {
                    sendMessage = true;
                }
            }
            else
            {
                Exception exceptionToLog = jobException;

                // drill down to the interesting exception
                while (exceptionToLog is Quartz.SchedulerException && exceptionToLog.InnerException != null)
                {
                    exceptionToLog = exceptionToLog.InnerException;
                }

                // log the exception to the database
                ExceptionLogService.LogException(exceptionToLog, null);

                var summaryException = exceptionToLog;

                // put the exception into the status
                job.LastStatus = "Exception";

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

                if (aggregateException != null)
                {
                    var firstException = aggregateException.InnerExceptions.First();
                    job.LastStatusMessage = "One or more exceptions occurred. First Exception: " + firstException.Message;
                    summaryException      = firstException;
                }
                else
                {
                    job.LastStatusMessage = summaryException.Message;
                }

                message.Append("Result: Exception<p>Message:<br>" + job.LastStatusMessage);

                if (summaryException.InnerException != null)
                {
                    job.LastStatusMessage += " (" + summaryException.InnerException.Message + ")";
                    message.Append("<p>Inner Exception:<br>" + summaryException.InnerException.Message);
                }

                if (job.NotificationStatus == JobNotificationStatus.Error)
                {
                    sendMessage = true;
                }
            }

            rockContext.SaveChanges();

            // send notification
            if (sendMessage)
            {
                // TODO: implement email send once it's available
            }
        }
示例#23
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var exceptionMsgs = new List <string>();

            JobDataMap dataMap         = context.JobDetail.JobDataMap;
            Guid?      groupGuid       = dataMap.GetString("EligibleFollowers").AsGuidOrNull();
            Guid?      systemEmailGuid = dataMap.GetString("EmailTemplate").AsGuidOrNull();
            int        followingSuggestionsEmailsSent       = 0;
            int        followingSuggestionsSuggestionsTotal = 0;

            if (groupGuid.HasValue && systemEmailGuid.HasValue)
            {
                using (var rockContext = new RockContext())
                {
                    var followingService = new FollowingService(rockContext);

                    // The people who are eligible to get following suggestions 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 != string.Empty &&
                                                   m.Person.EmailPreference != EmailPreference.DoNotEmail &&
                                                   m.Person.IsEmailActive)
                                            .Select(m => m.PersonId)
                                            .Distinct();

                    // check to see if there are any event types that require notification
                    var followerPersonIds = new List <int>();
                    if (new FollowingEventTypeService(rockContext)
                        .Queryable().AsNoTracking()
                        .Any(e => e.IsNoticeRequired))
                    {
                        // if so, include all eligible people
                        followerPersonIds = eligiblePersonIds.ToList();
                    }
                    else
                    {
                        // if not, filter the list of eligible people down to only those that actually have subscribed to one or more following events
                        followerPersonIds = new FollowingEventSubscriptionService(rockContext)
                                            .Queryable().AsNoTracking()
                                            .Where(f => eligiblePersonIds.Contains(f.PersonAlias.PersonId))
                                            .Select(f => f.PersonAlias.PersonId)
                                            .Distinct()
                                            .ToList();
                    }

                    if (followerPersonIds.Any())
                    {
                        // Get the primary person alias id for each of the followers
                        var primaryAliasIds = new Dictionary <int, int>();
                        new PersonAliasService(rockContext)
                        .Queryable().AsNoTracking()
                        .Where(a =>
                               followerPersonIds.Contains(a.PersonId) &&
                               a.PersonId == a.AliasPersonId)
                        .ToList()
                        .ForEach(a => primaryAliasIds.AddOrIgnore(a.PersonId, a.Id));

                        // Get current date/time.
                        var timestamp = RockDateTime.Now;

                        var suggestionTypes = new FollowingSuggestionTypeService(rockContext)
                                              .Queryable().AsNoTracking()
                                              .Where(s => s.IsActive)
                                              .OrderBy(s => s.Name)
                                              .ToList();

                        var components        = new Dictionary <int, SuggestionComponent>();
                        var suggestedEntities = new Dictionary <int, Dictionary <int, IEntity> >();

                        foreach (var suggestionType in suggestionTypes)
                        {
                            try
                            {
                                // Get the suggestion type component
                                var suggestionComponent = suggestionType.GetSuggestionComponent();
                                if (suggestionComponent != null)
                                {
                                    components.Add(suggestionType.Id, suggestionComponent);

                                    // Get the entitytype for this suggestion type
                                    var suggestionEntityType = EntityTypeCache.Get(suggestionComponent.FollowedType);
                                    if (suggestionEntityType != null)
                                    {
                                        var entityIds = new List <int>();

                                        // Call the components method to return all of it's suggestions
                                        var personEntitySuggestions = suggestionComponent.GetSuggestions(suggestionType, followerPersonIds);

                                        // If any suggestions were returned by the component
                                        if (personEntitySuggestions.Any())
                                        {
                                            int    entityTypeId = suggestionEntityType.Id;
                                            string reasonNote   = suggestionType.ReasonNote;

                                            // Get the existing followings for any of the followers
                                            var existingFollowings = new Dictionary <int, List <int> >();
                                            foreach (var following in followingService.Queryable("PersonAlias").AsNoTracking()
                                                     .Where(f =>
                                                            f.EntityTypeId == entityTypeId &&
                                                            followerPersonIds.Contains(f.PersonAlias.PersonId)))
                                            {
                                                existingFollowings.AddOrIgnore(following.PersonAlias.PersonId, new List <int>());
                                                existingFollowings[following.PersonAlias.PersonId].Add(following.EntityId);
                                            }

                                            // Loop through each follower
                                            foreach (var followerPersonId in personEntitySuggestions
                                                     .Select(s => s.PersonId)
                                                     .Distinct())
                                            {
                                                using (var suggestionContext = new RockContext())
                                                {
                                                    var followingSuggestedService = new FollowingSuggestedService(suggestionContext);

                                                    // Read all the existing suggestions for this type and the returned followers
                                                    var existingSuggestions = followingSuggestedService
                                                                              .Queryable("PersonAlias")
                                                                              .Where(s =>
                                                                                     s.SuggestionTypeId == suggestionType.Id &&
                                                                                     s.PersonAlias.PersonId == followerPersonId)
                                                                              .ToList();

                                                    // Look  through the returned suggestions
                                                    foreach (var followedEntityId in personEntitySuggestions
                                                             .Where(s => s.PersonId == followerPersonId)
                                                             .Select(s => s.EntityId))
                                                    {
                                                        // Make sure person isn't already following this entity
                                                        if (!existingFollowings.ContainsKey(followerPersonId) ||
                                                            !existingFollowings[followerPersonId].Contains(followedEntityId))
                                                        {
                                                            // If this person had a primary alias id
                                                            if (primaryAliasIds.ContainsKey(followerPersonId))
                                                            {
                                                                entityIds.Add(followedEntityId);

                                                                // Look for existing suggestion for this person and entity
                                                                var suggestion = existingSuggestions
                                                                                 .Where(s => s.EntityId == followedEntityId)
                                                                                 .OrderByDescending(s => s.StatusChangedDateTime)
                                                                                 .FirstOrDefault();

                                                                // If not found, add one
                                                                if (suggestion == null)
                                                                {
                                                                    suggestion = new FollowingSuggested();
                                                                    suggestion.EntityTypeId          = entityTypeId;
                                                                    suggestion.EntityId              = followedEntityId;
                                                                    suggestion.PersonAliasId         = primaryAliasIds[followerPersonId];
                                                                    suggestion.SuggestionTypeId      = suggestionType.Id;
                                                                    suggestion.Status                = FollowingSuggestedStatus.PendingNotification;
                                                                    suggestion.StatusChangedDateTime = timestamp;
                                                                    followingSuggestedService.Add(suggestion);
                                                                }
                                                                else
                                                                {
                                                                    // If found, and it has not been ignored, and it's time to promote again, update the promote date
                                                                    if (suggestion.Status != FollowingSuggestedStatus.Ignored &&
                                                                        suggestionType.ReminderDays.HasValue &&
                                                                        (
                                                                            !suggestion.LastPromotedDateTime.HasValue ||
                                                                            suggestion.LastPromotedDateTime.Value.AddDays(suggestionType.ReminderDays.Value) <= timestamp
                                                                        ))
                                                                    {
                                                                        if (suggestion.Status != FollowingSuggestedStatus.PendingNotification)
                                                                        {
                                                                            suggestion.StatusChangedDateTime = timestamp;
                                                                            suggestion.Status = FollowingSuggestedStatus.PendingNotification;
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }

                                                    // Save the suggestions for this type
                                                    suggestionContext.SaveChanges();
                                                }
                                            }
                                        }

                                        // If any entities are being suggested for this type, query database for them and save to dictionary
                                        if (entityIds.Any())
                                        {
                                            if (suggestionEntityType.AssemblyName != null)
                                            {
                                                // get the actual type of what is being followed
                                                Type entityType = suggestionEntityType.GetEntityType();
                                                if (entityType != null)
                                                {
                                                    // Get generic queryable method and query all the entities that are being followed
                                                    Type[]             modelType          = { entityType };
                                                    Type               genericServiceType = typeof(Rock.Data.Service <>);
                                                    Type               modelServiceType   = genericServiceType.MakeGenericType(modelType);
                                                    Rock.Data.IService serviceInstance    = Activator.CreateInstance(modelServiceType, new object[] { rockContext }) as IService;
                                                    MethodInfo         qryMethod          = serviceInstance.GetType().GetMethod("Queryable", new Type[] { });
                                                    var entityQry  = qryMethod.Invoke(serviceInstance, new object[] { }) as IQueryable <IEntity>;
                                                    var entityList = entityQry.AsNoTracking().Where(q => entityIds.Contains(q.Id)).ToList();
                                                    if (entityList != null && entityList.Any())
                                                    {
                                                        var entities = new Dictionary <int, IEntity>();
                                                        entityList.ForEach(e => entities.Add(e.Id, e));
                                                        suggestedEntities.Add(suggestionType.Id, entities);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                exceptionMsgs.Add(string.Format("An exception occurred calculating suggestions for the '{0}' suggestion type:{1}    {2}", suggestionType.Name, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                                ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                            }
                        }

                        var allSuggestions = new FollowingSuggestedService(rockContext)
                                             .Queryable("PersonAlias")
                                             .Where(s => s.Status == FollowingSuggestedStatus.PendingNotification)
                                             .ToList();

                        var suggestionPersonIds = allSuggestions
                                                  .Where(s => followerPersonIds.Contains(s.PersonAlias.PersonId))
                                                  .Select(s => s.PersonAlias.PersonId)
                                                  .Distinct()
                                                  .ToList();

                        var appRoot = GlobalAttributesCache.Get().GetValue("PublicApplicationRoot", rockContext);

                        foreach (var person in new PersonService(rockContext)
                                 .Queryable().AsNoTracking()
                                 .Where(p => suggestionPersonIds.Contains(p.Id))
                                 .ToList())
                        {
                            try
                            {
                                var personSuggestionNotices = new List <FollowingSuggestionNotices>();

                                foreach (var suggestionType in suggestionTypes)
                                {
                                    var component = components.ContainsKey(suggestionType.Id) ? components[suggestionType.Id] : null;
                                    if (component != null && suggestedEntities.ContainsKey(suggestionType.Id))
                                    {
                                        var entities = new List <IEntity>();
                                        foreach (var suggestion in allSuggestions
                                                 .Where(s =>
                                                        s.PersonAlias.PersonId == person.Id &&
                                                        s.SuggestionTypeId == suggestionType.Id)
                                                 .ToList())
                                        {
                                            if (suggestedEntities[suggestionType.Id].ContainsKey(suggestion.EntityId))
                                            {
                                                entities.Add(suggestedEntities[suggestionType.Id][suggestion.EntityId]);
                                                suggestion.LastPromotedDateTime = timestamp;
                                                suggestion.Status = FollowingSuggestedStatus.Suggested;
                                            }
                                        }

                                        var notices = new List <string>();
                                        foreach (var entity in component.SortEntities(entities))
                                        {
                                            notices.Add(component.FormatEntityNotification(suggestionType, entity));
                                        }

                                        if (notices.Any())
                                        {
                                            personSuggestionNotices.Add(new FollowingSuggestionNotices(suggestionType, notices));
                                        }
                                    }
                                }

                                if (personSuggestionNotices.Any())
                                {
                                    // Send the notice
                                    var mergeFields = new Dictionary <string, object>();
                                    mergeFields.Add("Person", person);
                                    mergeFields.Add("Suggestions", personSuggestionNotices.OrderBy(s => s.SuggestionType.Order).ToList());

                                    var emailMessage = new RockEmailMessage(systemEmailGuid.Value);
                                    emailMessage.AddRecipient(new RockEmailMessageRecipient(person, mergeFields));
                                    var errors = new List <string>();
                                    emailMessage.Send(out errors);
                                    exceptionMsgs.AddRange(errors);

                                    followingSuggestionsEmailsSent       += 1;
                                    followingSuggestionsSuggestionsTotal += personSuggestionNotices.Count();
                                }

                                rockContext.SaveChanges();
                            }
                            catch (Exception ex)
                            {
                                exceptionMsgs.Add(string.Format("An exception occurred sending suggestions to '{0}':{1}    {2}", person.FullName, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + "   ")));
                                ExceptionLogService.LogException(ex, System.Web.HttpContext.Current);
                            }
                        }
                    }
                }
            }

            context.Result = string.Format("A total of {0} following suggestions sent to {1} people", followingSuggestionsSuggestionsTotal, followingSuggestionsEmailsSent);

            if (exceptionMsgs.Any())
            {
                throw new Exception("One or more exceptions occurred calculating suggestions..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
            }
        }
示例#24
0
        private void LogError(Exception ex, int parentException, string status, System.Web.HttpContext context)
        {
            try
            {
                // get the current user
                Rock.CMS.User user = Rock.CMS.UserService.GetCurrentUser();

                // save the exception info to the db
                ExceptionLogService service      = new ExceptionLogService();
                ExceptionLog        exceptionLog = new ExceptionLog();;

                exceptionLog.ParentId      = parentException;
                exceptionLog.ExceptionDate = DateTime.Now;

                if (ex.InnerException != null)
                {
                    exceptionLog.HasInnerException = true;
                }

                exceptionLog.Description = ex.Message;
                exceptionLog.StackTrace  = ex.StackTrace;
                exceptionLog.Source      = ex.Source;
                exceptionLog.StatusCode  = status;

                if (context.Items["Rock:SiteId"] != null)
                {
                    exceptionLog.SiteId = Int32.Parse(context.Items["Rock:SiteId"].ToString());
                }

                if (context.Items["Rock:PageId"] != null)
                {
                    exceptionLog.PageId = Int32.Parse(context.Items["Rock:PageId"].ToString());
                }

                exceptionLog.ExceptionType = ex.GetType().Name;
                exceptionLog.PageUrl       = context.Request.RawUrl;

                exceptionLog.QueryString = context.Request.QueryString.ToString();

                // write cookies
                StringBuilder cookies = new StringBuilder();
                cookies.Append("<table class=\"cookies\">");

                foreach (string cookie in context.Request.Cookies)
                {
                    cookies.Append("<tr><td><b>" + cookie + "</b></td><td>" + context.Request.Cookies[cookie].Value + "</td></tr>");
                }

                cookies.Append("</table>");
                exceptionLog.Cookies = cookies.ToString();

                // write form items
                StringBuilder formItems = new StringBuilder();
                cookies.Append("<table class=\"formItems\">");

                foreach (string formItem in context.Request.Form)
                {
                    cookies.Append("<tr><td><b>" + formItem + "</b></td><td>" + context.Request.Form[formItem].ToString() + "</td></tr>");
                }

                cookies.Append("</table>");
                exceptionLog.Form = formItems.ToString();

                // write server vars
                StringBuilder serverVars = new StringBuilder();
                cookies.Append("<table class=\"server-variables\">");

                foreach (string serverVar in context.Request.ServerVariables)
                {
                    serverVars.Append("<tr><td><b>" + serverVar + "</b></td><td>" + context.Request.ServerVariables[serverVar].ToString() + "</td></tr>");
                }

                cookies.Append("</table>");
                exceptionLog.ServerVariables = serverVars.ToString();

                if (user != null)
                {
                    exceptionLog.PersonId = user.PersonId;
                }

                service.Add(exceptionLog, null);
                service.Save(exceptionLog, null);

                //  log inner exceptions
                if (ex.InnerException != null)
                {
                    LogError(ex.InnerException, exceptionLog.Id, status, context);
                }
            }
            catch (Exception exception)
            {
                // if you get an exception while logging an exception I guess you're hosed...
            }
        }
示例#25
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 && !string.IsNullOrEmpty(p.DeviceRegistrationId))
                                                            .Select(p => p.DeviceRegistrationId)
                                                            .ToList();

                                    if (devices.Any())
                                    {
                                        // 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;
                        }
                    }
                }
            }
        }
示例#26
0
        private void LogError( Exception ex, int parentException, string status, System.Web.HttpContext context )
        {
            try
            {
                // get the current user
                Rock.CMS.User user = Rock.CMS.UserService.GetCurrentUser();

                // save the exception info to the db
                ExceptionLogService service = new ExceptionLogService();
                ExceptionLog exceptionLog = new ExceptionLog(); ;

                exceptionLog.ParentId = parentException;
                exceptionLog.ExceptionDate = DateTime.Now;

                if ( ex.InnerException != null )
                    exceptionLog.HasInnerException = true;

                exceptionLog.Description = ex.Message;
                exceptionLog.StackTrace = ex.StackTrace;
                exceptionLog.Source = ex.Source;
                exceptionLog.StatusCode = status;

                if ( context.Items["Rock:SiteId"] != null )
                    exceptionLog.SiteId = Int32.Parse( context.Items["Rock:SiteId"].ToString() );

                if ( context.Items["Rock:PageId"] != null )
                    exceptionLog.PageId = Int32.Parse( context.Items["Rock:PageId"].ToString() );

                exceptionLog.ExceptionType = ex.GetType().Name;
                exceptionLog.PageUrl = context.Request.RawUrl;

                exceptionLog.QueryString = context.Request.QueryString.ToString();

                // write cookies
                StringBuilder cookies = new StringBuilder();
                cookies.Append("<table class=\"cookies\">");

                foreach ( string cookie in context.Request.Cookies )
                    cookies.Append( "<tr><td><b>" + cookie + "</b></td><td>" + context.Request.Cookies[cookie].Value + "</td></tr>" );

                cookies.Append( "</table>" );
                exceptionLog.Cookies = cookies.ToString();

                // write form items
                StringBuilder formItems = new StringBuilder();
                cookies.Append( "<table class=\"formItems\">" );

                foreach ( string formItem in context.Request.Form )
                    cookies.Append( "<tr><td><b>" + formItem + "</b></td><td>" + context.Request.Form[formItem].ToString() + "</td></tr>" );

                cookies.Append( "</table>" );
                exceptionLog.Form = formItems.ToString();

                // write server vars
                StringBuilder serverVars = new StringBuilder();
                cookies.Append( "<table class=\"server-variables\">" );

                foreach ( string serverVar in context.Request.ServerVariables )
                    serverVars.Append( "<tr><td><b>" + serverVar + "</b></td><td>" + context.Request.ServerVariables[serverVar].ToString() + "</td></tr>" );

                cookies.Append( "</table>" );
                exceptionLog.ServerVariables = serverVars.ToString();

                if (user != null)
                    exceptionLog.PersonId = user.PersonId;

                service.Add( exceptionLog, null );
                service.Save( exceptionLog, null );

                //  log inner exceptions
                if ( ex.InnerException != null )
                    LogError( ex.InnerException, exceptionLog.Id, status, context );

            }
            catch ( Exception exception )
            {
                // if you get an exception while logging an exception I guess you're hosed...
            }
        }
示例#27
0
        /// <summary>
        /// If the JWT is valid, the person claimed by that token will be returned. This method uses the configured validation parameters from the
        /// JSON Web Token Configuration Defined Type.
        /// </summary>
        /// <param name="jwtString"></param>
        /// <returns></returns>
        public static Person GetPersonFromJWTPersonSearchKey(string jwtString)
        {
            /*
             * 2/16/2022 MDP
             *
             * Note that this feature is not very well documented, see why at https://app.asana.com/0/0/1201611176520656/f
             *
             */

            if (jwtString.IsNullOrWhiteSpace())
            {
                return(null);
            }

            // Get the configs from the JSON Web Token Configuration defined values
            var configs = GetJwtConfigs();

            if (configs == null)
            {
                return(null);
            }

            // The configs are required to specify a person search key type. The subject of the JWT should match a search key value so that we know
            // which Person the sender of the token claims to be.
            var rockContext            = new RockContext();
            var personSearchKeyService = new PersonSearchKeyService(rockContext);
            var query = personSearchKeyService.Queryable().AsNoTracking();

            // Try each config in order, which are pre-ordered. The SearchTypeValueId is required (if null we couldn't match a person even if the
            // token validates)
            foreach (var config in configs.Where(c => c.SearchTypeValueId.HasValue))
            {
                // If the token is valid, this method will return it as an object that we can pull subject from. Even if the token is valid,
                // if the subject is not set, we cannot match it to a person search key
                var jwt = ValidateToken(config, jwtString);

                if (jwt == null || jwt.Subject.IsNullOrWhiteSpace())
                {
                    continue;
                }

                // Get all the people (it is possible to get more than one) that have the matching search key
                var people = query
                             .Where(psk => psk.SearchTypeValueId == config.SearchTypeValueId.Value && psk.SearchValue == jwt.Subject)
                             .Select(psk => psk.PersonAlias.Person)
                             .ToList();

                // If there are more than one match, then the Rock admin needs to take action and fix the data as this could be a security hole and we
                // cannot tell which person is the bearer of the JWT
                if (people.Count > 1)
                {
                    ExceptionLogService.LogException($"{people.Count} people matched the JWT subject '{jwt.Subject}' for search value id '{config.SearchTypeValueId.Value}'");
                    continue;
                }

                // If there is a single match, then this method is done and there is no need to check more configurations
                if (people.Count == 1)
                {
                    return(people.Single());
                }
            }

            // None of the configurations was able to validate the token and find a matching person
            return(null);
        }