Beispiel #1
0
        /// <summary>
        /// Check the validity of the field based on the data submitted. Note that
        /// this validation is performed on the wire data - i.e. that which is
        /// submitted, before any setFormatter is run
        /// </summary>
        /// <param name="data">Data from HTTP to check</param>
        /// <param name="editor">Editor instance</param>
        /// <param name="id">Row id for the row being edited</param>
        /// <returns>`null` if valid, or error message string if not valid</returns>
        internal string Validate(Dictionary <string, object> data, Editor editor, string id = null)
        {
            if (_validators == null)
            {
                return(null);
            }

            var val         = NestedData.ReadProp(Name(), data);
            var processData = editor.InData();
            var host        = new ValidationHost
            {
                Action = processData.Action,
                Id     = id,
                Field  = this,
                Editor = editor,
                Db     = editor.Db()
            };

            foreach (var validator in _validators)
            {
                var res = validator(val, data, host);

                if (res != null)
                {
                    return(res);
                }
            }

            return(null);
        }
Beispiel #2
0
        /// <summary>
        /// Get the value of the field, taking into account if it is coming from the
        /// DB or from a POST. If formatting has been specified for this field, it
        /// will be applied here.
        /// </summary>
        /// <param name="direction">Direction that the data is travelling  - 'get' is reading DB data, `create` and `edit` for writing to the DB</param>
        /// <param name="data">Data submitted from the client-side when setting.</param>
        /// <returns>Value for the field</returns>
        internal object Val(string direction, Dictionary <string, Object> data)
        {
            object val;

            if (direction == "get")
            {
                // Use data from the database, so the db name
                if (_getValue != null)
                {
                    val = _GetAssignedValue(_getValue);
                }
                else
                {
                    val = data.ContainsKey(_dbField) ?
                          data[_dbField] :
                          null;
                }

                return(_Format(val, data, _getFormatter));
            }

            // Use data from setting from the POST / GET data, so use the name
            val = _setValue != null?
                  _GetAssignedValue(_setValue) :
                      NestedData.ReadProp(Name(), data);

            // XSS prevention
            if (val is string && _xssFormat)
            {
                val = XssSafety((string)val);
            }

            return(_Format(val, data, _setFormatter));
        }
Beispiel #3
0
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * Internal methods
         */

        /// <summary>
        /// Check to see if a field should be used for a particular action (get or set).
        ///
        /// Called by the Editor / Join class instances - not expected for general
        /// consumption - internal.
        /// </summary>
        /// <param name="action">Direction that the data is travelling  - 'get' is reading DB data, `create` and `edit` for writing to the DB</param>
        /// <param name="data">Data submitted from the client-side when setting.</param>
        /// <returns>true if the field should be used in the get / set.</returns>
        internal bool Apply(string action, Dictionary <string, object> data = null)
        {
            if (action == "get")
            {
                // Get action - can we get this field
                return(_get);
            }

            // Set - Note that validation must be done on input data before we get here.
            // Create or edit action, are we configured to use this field
            if (action == "create" && (_set == SetType.None || _set == SetType.Edit))
            {
                return(false);
            }

            if (action == "edit" && (_set == SetType.None || _set == SetType.Create))
            {
                return(false);
            }

            // Check it was in the submitted data. If not, then not required
            // (validation would have failed if it was) and therefore we don't
            // Set it. Check for a value as well, as it can come from another
            // source
            if (_setValue == null && !NestedData.InData(Name(), data))
            {
                return(false);
            }

            // In the data set, so use it
            return(true);
        }
        private IEnumerable <Variable> LoadData(NestedData data, string packageId)
        {
            // load the variables
            foreach (var pair in data.Variables)
            {
                var value = CreateFromJToken(pair.Value);
                if (value == null)
                {
                    continue;
                }

                value.PackageId = packageId;
                value.Name      = pair.Key;
                yield return(value);
            }

            // Load any child scopes
            if (data.SubScopes == null)
            {
                yield break;
            }

            foreach (var pair in data.SubScopes)
            {
                foreach (var variable in LoadData(pair.Value, $"{packageId}.{pair.Key}"))
                {
                    yield return(variable);
                }
            }
        }
        public void CanDeserializeNestedTypes()
        {
            // Arrange
            string s = "MyInt=555&Simple.MyInt=10&Simple.MyString=Abc";

            // Act
            NestedData data = Deserialize <NestedData>(s);

            // Assert
            Assert.IsNotNull(data);
            Assert.AreEqual(555, data.MyInt);
            Assert.IsNotNull(data.Simple);
            Assert.AreEqual("Abc", data.Simple.MyString);
            Assert.AreEqual(10, data.Simple.MyInt);
        }
Beispiel #6
0
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * Internal methods
         */

        /// <summary>
        /// Data "get" request - get the joined data
        /// </summary>
        /// <param name="editor">Host Editor instance</param>
        /// <param name="response">DataTables response object for where the data
        /// should be written to</param>
        internal void Data(Editor editor, DtResponse response)
        {
            _Prepare(editor);

            if (response.data.Count() != 0)
            {
                // This is something that will likely come in a future version, but it
                // is a relatively low use feature. Please get in touch if this is
                // something you require.
                var pkeyA = editor.Pkey();
                if (pkeyA.Length > 1)
                {
                    throw new Exception("MJoin is not currently supported with a compound primary key for the main table.");
                }

                // If the Editor primary key is join key, then it is read automatically
                // and into Editor's primary key store
                var pkeyIsJoin = _hostField == pkeyA[0] ||
                                 _hostField == editor.Table()[0];

                // Build the basic query
                var query = editor.Db()
                            .Query("select")
                            .Distinct(true)
                            .Get(_hostField + " as dteditor_pkey")
                            .Table(editor.Table()[0]);

                if (Order() != null)
                {
                    query.Order(Order());
                }

                _ApplyWhere(query);

                foreach (var field in _fields.Where(field => field.Apply("get") && field.GetValue() == null))
                {
                    if (field.DbField().IndexOf('.') == -1)
                    {
                        query.Get(_table + "." + field.DbField() + " as " + field.DbField());
                    }
                    else
                    {
                        query.Get(field.DbField());
                    }
                }

                // Create the joins
                if (_linkTable != null)
                {
                    query.Join(_linkTable, _hostField + " = " + _linkHostField);
                    query.Join(_table, _childField + " = " + _linkChildField);
                }
                else
                {
                    query.Join(_table, _childField + " = " + _hostField);
                }

                var readField     = "";
                var joinFieldName = _hostField.Split('.')[1];
                if (NestedData.InData(_hostField, response.data[0]))
                {
                    readField = _hostField;
                }
                else if (NestedData.InData(joinFieldName, response.data[0]))
                {
                    readField = joinFieldName;
                }
                else if (!pkeyIsJoin)
                {
                    throw new Exception(
                              "Join was performed on the field '" + _hostField + "' which was not " +
                              "included in the Editor field list. The join field must be " +
                              "included as a regular field in the Editor instance."
                              );
                }

                // There appears to be a bug in the MySQL drivers for .NETCore whereby if there is
                // only one result in the original data set, then it can only read one result into
                // the new data set when using WHERE IN. Any other number of rows is fine. Tried
                // different versions of the server and driver but to no avail, so this is a workaround.
                if (editor.Db().DbType() != "mysql" || response.data.Count != 1)
                {
                    // Get list of pkey values and apply as a WHERE IN condition
                    // This is primarily useful in server-side processing mode and when filtering
                    // the table as it means only a sub-set will be selected
                    // This is only applied for "sensible" data sets. It will just complicate
                    // matters for really large data sets:
                    // https://stackoverflow.com/questions/21178390/in-clause-limitation-in-sql-server
                    if (response.data.Count < 1000)
                    {
                        var whereIn = new List <object>();

                        foreach (var data in response.data)
                        {
                            whereIn.Add(pkeyIsJoin
                                ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "")
                                : NestedData.ReadProp(readField, data).ToString()
                                        );
                        }

                        query.WhereIn(_hostField, whereIn);
                    }
                }

                var result = query.Exec();

                // Map the data to the primary key for fast look up
                var join = new Dictionary <string, List <Dictionary <string, object> > >();
                Dictionary <string, object> row;

                while ((row = result.Fetch()) != null)
                {
                    var inner = new Dictionary <string, object>();

                    foreach (var field in _fields.Where(field => field.Apply("get")))
                    {
                        field.Write(inner, row);
                    }

                    var lookup = row["dteditor_pkey"].ToString();
                    if (!join.ContainsKey(lookup))
                    {
                        join.Add(lookup, new List <Dictionary <string, object> >());
                    }

                    join[lookup].Add(inner);
                }

                // Loop over the data and do a join based on the data available
                foreach (var data in response.data)
                {
                    var linkField = pkeyIsJoin
                        ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "")
                        : NestedData.ReadProp(readField, data).ToString();

                    data.Add(_name, join.ContainsKey(linkField)
                        ? join[linkField]
                        : new List <Dictionary <string, object> >()
                             );
                }
            }

            // Field options
            foreach (var field in _fields)
            {
                var opts = field.OptionsExec(editor.Db());

                if (opts != null)
                {
                    response.options.Add(_name + "[]." + field.Name(), opts);
                }
            }
        }
Beispiel #7
0
        /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
         * Internal methods
         */

        /// <summary>
        /// Data "get" request - get the joined data
        /// </summary>
        /// <param name="editor">Host Editor instance</param>
        /// <param name="response">DataTables reponse object for where the data
        /// should be written to</param>
        internal void Data(Editor editor, DtResponse response)
        {
            _Prepare(editor);

            // This is something that will likely come in a future version, but it
            // is a relatively low use feature. Please get in touch if this is
            // something you require.
            var pkeyA = editor.Pkey();

            if (pkeyA.Length > 1)
            {
                throw new Exception("MJoin is not currently supported with a compound primary key for the main table.");
            }

            // If the Editor primary key is join key, then it is read automatically
            // and into Editor's primary key store
            var pkeyIsJoin = _hostField == pkeyA[0] ||
                             _hostField == editor.Table()[0];

            // Build the basic query
            var query = editor.Db()
                        .Query("select")
                        .Distinct(true)
                        .Get(_hostField + " as dteditor_pkey")
                        .Table(editor.Table()[0]);

            if (Order() != null)
            {
                query.Order(Order());
            }

            _ApplyWhere(query);

            foreach (var field in _fields.Where(field => field.Apply("get") && field.GetValue() == null))
            {
                if (field.DbField().IndexOf('.') == -1)
                {
                    query.Get(_table + "." + field.DbField() + " as " + field.DbField());
                }
                else
                {
                    query.Get(field.DbField());
                }
            }

            // Create the joins
            if (_linkTable != null)
            {
                query.Join(_linkTable, _hostField + " = " + _linkHostField);
                query.Join(_table, _childField + " = " + _linkChildField);
            }
            else
            {
                query.Join(_table, _childField + " = " + _hostField);
            }

            var result = query.Exec();

            if (result.Count() != 0)
            {
                var readField     = "";
                var joinFieldName = _hostField.Split('.')[1];

                if (NestedData.InData(_hostField, response.data[0]))
                {
                    readField = _hostField;
                }
                else if (NestedData.InData(joinFieldName, response.data[0]))
                {
                    readField = joinFieldName;
                }
                else if (!pkeyIsJoin)
                {
                    throw new Exception(
                              "Join was performed on the field '" + _hostField + "' which was not " +
                              "included in the Editor field list. The join field must be " +
                              "included as a regular field in the Editor instance."
                              );
                }

                // Map the data to the primary key for fast look up
                var join = new Dictionary <string, List <object> >();
                Dictionary <string, object> row;

                while ((row = result.Fetch()) != null)
                {
                    var inner = new Dictionary <string, object>();

                    foreach (var field in _fields.Where(field => field.Apply("get")))
                    {
                        field.Write(inner, row);
                    }

                    var lookup = row["dteditor_pkey"].ToString();
                    if (!join.ContainsKey(lookup))
                    {
                        join.Add(lookup, new List <object>());
                    }

                    join[lookup].Add(inner);
                }

                // Loop over the data and do a join based on the data available
                foreach (var data in response.data)
                {
                    var linkField = pkeyIsJoin
                        ? (data["DT_RowId"].ToString()).Replace(editor.IdPrefix(), "")
                        : NestedData.ReadProp(readField, data).ToString();

                    data.Add(_name, join.ContainsKey(linkField)
                        ? join[linkField]
                        : new List <object>()
                             );
                }
            }

            // Field options
            foreach (var field in _fields)
            {
                var opts = field.OptionsExec(editor.Db());

                if (opts != null)
                {
                    response.options.Add(_name + "[]." + field.Name(), opts);
                }
            }
        }
Beispiel #8
0
 /// <summary>
 /// Write the value for this field to the output array for a read operation
 /// </summary>
 /// <param name="outData">Row output data (to the JSON)</param>
 /// <param name="srcData">Row input data (raw, from the database)</param>
 internal void Write(Dictionary <string, object> outData, Dictionary <string, object> srcData)
 {
     NestedData.WriteProp(outData, Name(), Val("get", srcData), _type);
 }
 public void MethodClassParameter(string str, NestedData nested)
 {
 }