/// <summary>
        /// Parses the attributes of the Lava element tag to extract the parameter settings.
        /// Any merge fields in the attributes markup are resolved before the settings are extracted.
        /// </summary>
        /// <param name="elementAttributesMarkup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public static Dictionary <string, string> GetElementAttributes(string elementAttributesMarkup, ILavaRenderContext context = null)
        {
            // First, resolve any Lava merge fields that exist in the element attributes markup.
            if (context != null)
            {
                elementAttributesMarkup = elementAttributesMarkup.ResolveMergeFields(context.GetMergeFields());
            }

            // Get the set of parameters using variations of the following pattern:
            // param1:'value1 with spaces' param2:value2_without_spaces param3:'value3 with spaces'
            var parms = new Dictionary <string, string>();

            var markupItems = Regex.Matches(elementAttributesMarkup, @"(\S*?:('[^']+'|[\\d.]+|[\S*]+))")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    if (itemParts[1].Trim()[0] == '\'')
                    {
                        parms.AddOrReplace(itemParts[0].Trim(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                    }
                    else
                    {
                        parms.AddOrReplace(itemParts[0].Trim(), itemParts[1].Trim());
                    }
                }
            }

            return(parms);
        }
Esempio n. 2
0
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            var parms = new Dictionary <string, string>();

            parms.Add("return", "results");
            parms.Add("statement", "select");

            var markupItems = Regex.Matches(resolvedMarkup, @"(\S*?:'[^']+')")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    parms.AddOrReplace(itemParts[0].Trim().ToLower(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                }
            }
            return(parms);
        }
Esempio n. 3
0
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            var parms = new Dictionary <string, string>();

            parms.Add("iterator", "results");
            parms.Add("searchtype", "wildcard");

            var markupItems = Regex.Matches(resolvedMarkup, @"(\S*?:'[^']+')")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            if (markupItems.Count == 0)
            {
                throw new Exception("No parameters were found in your command. The syntax for a parameter is parmName:'' (note that you must use single quotes).");
            }

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    parms.AddOrReplace(itemParts[0].Trim().ToLower(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                }
            }
            return(parms);
        }
Esempio n. 4
0
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            var parms = new Dictionary <string, string>();

            parms.Add("method", "GET");
            parms.Add("return", "results");
            parms.Add("basicauth", "");
            parms.Add("parameters", "");
            parms.Add("headers", "");
            parms.Add("responsecontenttype", "json");
            parms.Add("body", "");
            parms.Add("requesttype", "text/plain");
            parms.Add("timeout", "12000");

            var markupItems = Regex.Matches(resolvedMarkup, @"(\S*?:'[^']+')")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    parms.AddOrReplace(itemParts[0].Trim().ToLower(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                }
            }
            return(parms);
        }
Esempio n. 5
0
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            var parms = new Dictionary <string, string>();

            parms.Add(SCHEDULE_ID, "");
            parms.Add(ROLE_ID, "");
            parms.Add(SHOW_WHEN, "live");
            parms.Add(LOOK_AHEAD_DAYS, "30");
            parms.Add(SCHEDULE_CATEGORY_ID, "");
            parms.Add(AS_AT_DATE, "");

            var markupItems = Regex.Matches(resolvedMarkup, @"(\S*?:'[^']+')")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    parms.AddOrReplace(itemParts[0].Trim().ToLower(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                }
            }
            return(parms);
        }
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            return(ParseResolvedMarkup(resolvedMarkup));
        }
Esempio n. 7
0
        /// <summary>
        /// Parses the Lava Command markup, first resolving merge fields and then harvesting any provided parameters.
        /// </summary>
        /// <param name="markup">The Lava Command markup.</param>
        /// <param name="context">The DotLiquid context.</param>
        /// <param name="parms">
        /// A dictionary into which any parameters discovered within the <paramref name="markup"/> will be added or replaced.
        /// Default values may be pre-loaded into this collection, and will be overwritten if a matching key is present within the <paramref name="markup"/>.
        /// Note that parameter keys should be added in lower case.
        /// <para>
        /// When searching the <paramref name="markup"/> for key/value parameter pairs, the following <see cref="Regex"/> pattern will be used: @"\S+:('[^']+'|\d+)".
        /// This means that the following patterns will be matched: "key:'value'" OR "key:integer". While this should work for most - if not all - Lava Command parameters,
        /// you can always choose to not use this helper method and instead roll your own implementation.
        /// </para>
        /// </param>
        public static void ParseCommandMarkup(string markup, ILavaRenderContext context, Dictionary <string, string> parms)
        {
            if (markup.IsNull())
            {
                return;
            }

            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (parms == null)
            {
                throw new ArgumentNullException(nameof(parms));
            }

            var mergeFields = context.GetMergeFields();

            // Resolve merge fields.
            var resolvedMarkup = markup.ResolveMergeFields(mergeFields);

            // Harvest parameters.
            var markupParms = Regex.Matches(resolvedMarkup, @"\S+:('[^']+'|\d+)")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            foreach (var parm in markupParms)
            {
                var itemParts = parm.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    var key   = itemParts[0].Trim().ToLower();
                    var value = itemParts[1].Trim();

                    if (value[0] == '\'')
                    {
                        // key:'value'
                        parms.AddOrReplace(key, value.Substring(1, value.Length - 2));
                    }
                    else
                    {
                        // key:integer
                        parms.AddOrReplace(key, value);
                    }
                }
            }
        }
Esempio n. 8
0
        /// <summary>
        /// Merges the lava.
        /// </summary>
        /// <param name="lavaTemplate">The lava template.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private string MergeLava(string lavaTemplate, ILavaRenderContext context)
        {
            // Resolve the Lava template contained in this block in a new context.
            var engine = context.GetService <ILavaEngine>();

            var newContext = engine.NewRenderContext();

            newContext.SetMergeFields(context.GetMergeFields());
            newContext.SetInternalFields(context.GetInternalFields());

            // Resolve the inner template.
            var result = engine.RenderTemplate(lavaTemplate, LavaRenderParameters.WithContext(newContext));

            return(result.Text);
        }
Esempio n. 9
0
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            /*
             * var internalMergeFields = new Dictionary<string, object>();
             *
             * // get variables defined in the lava source
             * foreach ( var scope in context.GetScopes )
             * {
             *  foreach ( var item in scope )
             *  {
             *      internalMergeFields.AddOrReplace( item.Key, item.Value );
             *  }
             * }
             *
             * // get merge fields loaded by the block or container
             * if ( context.GetEnvironments.Count > 0 )
             * {
             *  foreach ( var item in context.GetEnvironments[0] )
             *  {
             *      internalMergeFields.AddOrReplace( item.Key, item.Value );
             *  }
             * }
             */

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            var parms = new Dictionary <string, string>();

            parms.Add("cacheduration", "0");

            var markupItems = Regex.Matches(resolvedMarkup, @"(\S*?:'[^']+')")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    parms.AddOrReplace(itemParts[0].Trim().ToLower(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                }
            }
            return(parms);
        }
Esempio n. 10
0
        /// <summary>
        /// Parses the markup.
        /// </summary>
        /// <param name="markup">The markup.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        private Dictionary <string, string> ParseMarkup(string markup, ILavaRenderContext context)
        {
            // first run lava across the inputted markup
            var internalMergeFields = context.GetMergeFields();

            /*
             * var internalMergeFields = new Dictionary<string, object>();
             *
             * // get variables defined in the lava source
             * foreach ( var scope in context.GetScopes )
             * {
             *  foreach ( var item in scope )
             *  {
             *      internalMergeFields.AddOrReplace( item.Key, item.Value );
             *  }
             * }
             *
             * // get merge fields loaded by the block or container
             * if ( context.GetEnvironments.Count > 0 )
             * {
             *  foreach ( var item in context.GetEnvironments[0] )
             *  {
             *      internalMergeFields.AddOrReplace( item.Key, item.Value );
             *  }
             * }
             */

            var resolvedMarkup = markup.ResolveMergeFields(internalMergeFields);

            var parms = new Dictionary <string, string>();

            parms.Add("iterator", string.Format("{0}Items", EntityName));
            parms.Add("securityenabled", "true");

            var markupItems = Regex.Matches(resolvedMarkup, @"(\S*?:'[^']+')")
                              .Cast <Match>()
                              .Select(m => m.Value)
                              .ToList();

            if (markupItems.Count == 0)
            {
                throw new Exception("No parameters were found in your command. The syntax for a parameter is parmName:'' (note that you must use single quotes).");
            }

            foreach (var item in markupItems)
            {
                var itemParts = item.ToString().Split(new char[] { ':' }, 2);
                if (itemParts.Length > 1)
                {
                    parms.AddOrReplace(itemParts[0].Trim().ToLower(), itemParts[1].Trim().Substring(1, itemParts[1].Length - 2));
                }
            }

            // override any dynamic parameters
            List <string> dynamicFilters = new List <string>(); // will be used to process dynamic filters

            if (parms.ContainsKey("dynamicparameters"))
            {
                var dynamicParms    = parms["dynamicparameters"];
                var dynamicParmList = dynamicParms.Split(',')
                                      .Select(x => x.Trim())
                                      .Where(x => !string.IsNullOrWhiteSpace(x))
                                      .ToList();

                foreach (var dynamicParm in dynamicParmList)
                {
                    if (HttpContext.Current.Request[dynamicParm] != null)
                    {
                        var dynamicParmValue = HttpContext.Current.Request[dynamicParm].ToString();

                        switch (dynamicParm)
                        {
                        case "id":
                        case "limit":
                        case "offset":
                        case "dataview":
                        case "expression":
                        case "sort":
                        case "iterator":
                        case "checksecurity":
                        case "includedeceased":
                        case "lazyloadenabled":
                        case "include":
                        case "select":
                        case "selectmany":
                        case "groupby":
                        case "securityenabled":
                        {
                            parms.AddOrReplace(dynamicParm, dynamicParmValue);
                            break;
                        }

                        default:
                        {
                            dynamicFilters.Add(dynamicParm);
                            break;
                        }
                        }
                    }
                }

                parms.AddOrReplace("dynamicparameters", string.Join(",", dynamicFilters));
            }


            return(parms);
        }
Esempio n. 11
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        public override void OnRender(ILavaRenderContext context, TextWriter result)
        {
            if (_shortcode == null)
            {
                result.Write($"An error occurred while processing the {0} shortcode.", _tagName);
            }

            // Get the parameters and default values defined by the shortcode, then apply the parameters that have been specified in the shortcode tag attributes
            // and those that are stored in the current render context.
            var parms = new Dictionary <string, object>();

            foreach (var shortcodeParm in _shortcode.Parameters)
            {
                parms.AddOrReplace(shortcodeParm.Key, shortcodeParm.Value);
            }

            SetParametersFromElementAttributes(parms, _elementAttributesMarkup, context);

            // Set a unique id for the shortcode.
            parms.AddOrReplace("uniqueid", "id-" + Guid.NewGuid().ToString());

            // Apply the merge fields in the block context.
            var internalMergeFields = context.GetMergeFields();

            foreach (var item in parms)
            {
                internalMergeFields.AddOrReplace(item.Key, item.Value);
            }

            // Add parameters for tracking the recursion depth.
            int currentRecursionDepth = 0;

            if (parms.ContainsKey("RecursionDepth"))
            {
                currentRecursionDepth = parms["RecursionDepth"].ToString().AsInteger() + 1;

                if (currentRecursionDepth > _maxRecursionDepth)
                {
                    result.Write("A recursive loop was detected and processing of this shortcode has stopped.");
                    return;
                }
            }

            parms.AddOrReplace("RecursionDepth", currentRecursionDepth);

            // Resolve the merge fields in the shortcode template in a separate context, using the set of merge fields that have been modified by the shortcode parameters.
            // Apply the set of enabled commands specified by the shortcode definition, or those enabled for the current context if none are defined by the shortcode.
            // The resulting content is a shortcode template that is ready to be processed to resolve its child elements.
            var enabledCommands = _shortcode.EnabledLavaCommands ?? new List <string>();

            enabledCommands = enabledCommands.Where(x => !string.IsNullOrWhiteSpace(x)).ToList();

            if (!enabledCommands.Any())
            {
                enabledCommands = context.GetEnabledCommands();
            }

            var shortcodeTemplateContext = _engine.NewRenderContext(internalMergeFields, enabledCommands);

            var blockMarkupRenderResult = _engine.RenderTemplate(_blockMarkup.ToString(), LavaRenderParameters.WithContext(shortcodeTemplateContext));

            var shortcodeTemplateMarkup = blockMarkupRenderResult.Text;

            // Extract child elements from the shortcode template content.
            // One or more child elements can be added to a shortcode block using the syntax "[[ <childElementName> <paramName1>:value1 <paramName2>:value2 ... ]] ... [[ end<childElementName> ]]",
            // where <childElementName> is a shortcode-specific tag name, <param1> is a shortcode parameter name, and <value1> is the parameter value.
            // Child elements are grouped by <childElementName>, and each collection is passed as a separate parameter to the shortcode template
            // using the variable name "<childElementNameItems>". The first element of the array is also added using the variable name "<childElementName>".
            // Parameters declared on child elements can be referenced in the shortcode template as <childElementName>.<paramName>.
            Dictionary <string, object> childElements;

            var residualMarkup = ExtractShortcodeBlockChildElements(shortcodeTemplateMarkup, out childElements);

            // Add the collections of child to the set of parameters that will be passed to the shortcode template.
            foreach (var item in childElements)
            {
                parms.AddOrReplace(item.Key, item.Value);
            }

            // Set context variables related to the block content so they can be referenced by the shortcode template.
            if (residualMarkup.IsNotNullOrWhiteSpace())
            {
                // JME (7/23/2019) Commented out the two lines below and substituted the line after to allow for better
                // processing of the block content. Testing was done on all existing shortcodes but leaving
                // this code in place in case a future edge case is found. Could/should remove this in the future.
                // Regex rgx = new Regex( @"{{\s*blockContent\s*}}", RegexOptions.IgnoreCase );
                // lavaTemplate = rgx.Replace( lavaTemplate, blockMarkup );
                parms.AddOrReplace("blockContent", residualMarkup);

                parms.AddOrReplace("blockContentExists", true);
            }
            else
            {
                parms.AddOrReplace("blockContentExists", false);
            }

            // Now ensure there aren't any entity commands in the block that are not allowed.
            // This is necessary because the shortcode may be configured to allow more entities for processing
            // than the source block, template, action, etc. permits.
            var securityCheckResult = _engine.RenderTemplate(residualMarkup, LavaRenderParameters.WithContext(context));

            Regex securityErrorPattern = new Regex(string.Format(Constants.Messages.NotAuthorizedMessage, ".*"));
            Match securityErrorMatch   = securityErrorPattern.Match(securityCheckResult.Text);

            // If the security check failed, return the error message.
            if (securityErrorMatch.Success)
            {
                result.Write(securityErrorMatch.Value);

                return;
            }

            // Merge the shortcode template in a new context, using the parameters and security allowed by the shortcode.
            var shortcodeContext = _engine.NewRenderContext(parms);

            // If the shortcode specifies a set of enabled Lava commands, set these for the current context.
            // If not, use the commands enabled for the current context.
            if (_shortcode.EnabledLavaCommands != null &&
                _shortcode.EnabledLavaCommands.Any())
            {
                shortcodeContext.SetEnabledCommands(_shortcode.EnabledLavaCommands);
            }
            else
            {
                shortcodeContext.SetEnabledCommands(context.GetEnabledCommands());
            }

            var results = _engine.RenderTemplate(_shortcode.TemplateMarkup, LavaRenderParameters.WithContext(shortcodeContext));

            result.Write(results.Text.Trim());
        }
Esempio n. 12
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        public override void OnRender(ILavaRenderContext context, TextWriter result)
        {
            var rockContext = LavaHelper.GetRockContextFromLavaContext(context);

            // Get enabled security commands
            _enabledSecurityCommands = context.GetEnabledCommands().JoinStrings(",");

            using (TextWriter writer = new StringWriter())
            {
                bool filterProvided = false;

                base.OnRender(context, writer);

                var parms              = ParseMarkup(_markup, context);
                var lookAheadDays      = parms[LOOK_AHEAD_DAYS].AsInteger();
                var scheduleCategoryId = parms[SCHEDULE_CATEGORY_ID].AsIntegerOrNull();
                var asAtDate           = parms[AS_AT_DATE].AsDateTime();

                var now = asAtDate ?? RockDateTime.Now;

                var scheduleIds = new List <int>();

                var requestedSchedules = parms[SCHEDULE_ID].StringToIntList();

                var schedulesQry = new ScheduleService(rockContext).Queryable().AsNoTracking()
                                   .Where(s => s.IsActive == true);

                if (requestedSchedules.Count() > 0)
                {
                    schedulesQry   = schedulesQry.Where(s => requestedSchedules.Contains(s.Id));
                    filterProvided = true;
                }

                if (scheduleCategoryId.HasValue)
                {
                    schedulesQry   = schedulesQry.Where(s => s.CategoryId == scheduleCategoryId.Value);
                    filterProvided = true;
                }

                // If neither a schedule id nor a schedule category id was provided stop
                if (!filterProvided)
                {
                    return;
                }

                // Get the schedules are order them by the next start time
                var schedules = schedulesQry.ToList()
                                .Where(s => s.GetNextStartDateTime(now) != null)
                                .OrderBy(s => s.GetNextStartDateTime(now));

                if (schedules.Count() == 0)
                {
                    return;
                }

                var nextSchedule = schedules.FirstOrDefault();

                var      nextStartDateTime     = nextSchedule.GetNextStartDateTime(now);
                var      isLive                = false;
                DateTime?occurrenceEndDateTime = null;

                // Determine if we're live
                if (nextSchedule.WasScheduleActive(now))
                {
                    isLive = true;
                    var occurrences      = nextSchedule.GetICalOccurrences(now, now.AddDays(lookAheadDays)).Take(2);
                    var activeOccurrence = occurrences.FirstOrDefault();
                    occurrenceEndDateTime = (DateTime)activeOccurrence.Period.EndTime.Value;

                    // Set the next occurrence to be the literal next occurrence (vs the current occurrence)
                    nextStartDateTime = null;
                    if (occurrences.Count() > 1)
                    {
                        nextStartDateTime = occurrences.Last().Period.EndTime.Value;
                    }
                }

                // Determine when not to show the content
                if ((parms[SHOW_WHEN] == "notlive" && isLive) ||
                    (parms[SHOW_WHEN] == "live" && !isLive))
                {
                    return;
                }

                // Check role membership
                var roleId = parms[ROLE_ID].AsIntegerOrNull();

                if (roleId.HasValue)
                {
                    var currentPerson = GetCurrentPerson(context);

                    var isInRole = new GroupMemberService(rockContext).Queryable()
                                   .Where(m =>
                                          m.GroupId == roleId &&
                                          m.PersonId == currentPerson.Id
                                          )
                                   .Any();

                    if (!isInRole)
                    {
                        return;
                    }
                }

                var mergeFields = context.GetMergeFields();

                mergeFields.Add("NextOccurrenceDateTime", nextStartDateTime);
                mergeFields.Add("OccurrenceEndDateTime", occurrenceEndDateTime);
                mergeFields.Add("Schedule", nextSchedule);
                mergeFields.Add("IsLive", isLive);

                var engine = context.GetService <ILavaEngine>();

                var renderContext = engine.NewRenderContext(mergeFields, _enabledSecurityCommands.SplitDelimitedValues());

                var results = engine.RenderTemplate(_blockMarkup.ToString(), LavaRenderParameters.WithContext(renderContext));

                result.Write(results.Text.Trim());
            }
        }