Example #1
0
 public void Put(Daton daton)
 {
     Cache[daton.Key] = new Item
     {
         Daton = daton
     };
 }
        /// <summary>
        /// Return readable strings describing any disallowed writes for this user
        /// </summary>
        /// <param name="pristineDaton">null for new unsaved persistons, else the pristine version being edited</param>
        public IEnumerable <string> GetDisallowedWrites(Daton pristineDaton, DatonDef datondef, PersistonDiff diff)
        {
            var errors = new List <string>();

            FindDisallowedWrites(errors, pristineDaton, datondef.MainTableDef, diff.MainTable);
            return(errors);
        }
 private void HidePrivateParts(Daton daton, RowRecurPoint rr)
 {
     foreach (var rt in rr.GetChildren())
     {
         HidePrivateParts(daton, rt);
     }
 }
        private void HidePrivateParts(Daton daton, TableRecurPoint rt)
        {
            //clear out the invisible cols in each row and recur
            var invisibleFields = GetInvisibleFields(daton, rt);

            foreach (var rr in rt.GetRows())
            {
                ClearInvisibleFields(invisibleFields, rr.Row);
                HidePrivateParts(daton, rr);
            }
        }
        /// <summary>
        /// determine which cols are not visible
        /// </summary>
        private List <FieldInfo> GetInvisibleFields(Daton daton, RecurPoint r)
        {
            var invisibleFields = new List <FieldInfo>();

            foreach (var coldef in r.TableDef.Cols)
            {
                var colLev = FinalLevel(daton, r.TableDef.Name, coldef.Name);
                if (!CanView(colLev))
                {
                    invisibleFields.Add(r.TableDef.RowType.GetField(coldef.Name));
                }
            }
            return(invisibleFields);
        }
Example #6
0
        /// <summary>
        /// determine which cols are not visible
        /// </summary>
        private List <ColDef> GetInvisibleCols(Daton daton, RecurPoint r)
        {
            var invisibles = new List <ColDef>();

            foreach (var coldef in r.TableDef.Cols)
            {
                var colLev = FinalLevel(daton, r.TableDef.Name, coldef.Name);
                if (!CanView(colLev))
                {
                    invisibles.Add(coldef);
                }
            }
            return(invisibles);
        }
Example #7
0
 /// <summary>
 /// Change the value of certain defaults to be more user friendly (namely, non-nullable dates and times)
 /// </summary>
 /// <param name="d">a newly created persisto</param>
 public static void FixTopLevelDefaultsInNewPersiston(DatonDef datondef, Daton d)
 {
     if (datondef.MultipleMainRows)
     {
         return;
     }
     foreach (var coldef in datondef.MainTableDef.Cols)
     {
         if (coldef.CSType == typeof(DateTime))
         {
             var field = datondef.Type.GetField(coldef.Name);
             field.SetValue(d, DateTime.UtcNow);
         }
     }
 }
Example #8
0
        /// <summary>
        /// Convert daton to JSON wire format
        /// </summary>
        public static string ToWire(DataDictionary dbdef, Daton daton, bool compatibleFormat)
        {
            var datondef  = dbdef.FindDef(daton);
            var buf       = new StringBuilder(1000);
            var writerOLD = new StringWriter(buf);
            var writer    = new JsonTextWriter(writerOLD);

            writer.WriteStartObject();
            writer.WritePropertyName("key");
            writer.WriteValue(daton.Key.ToString());
            writer.WritePropertyName("version");
            writer.WriteValue(daton.Version);
            if (daton is Viewon viewon && !viewon.IsCompleteLoad)
            {
                writer.WritePropertyName("isComplete");
                writer.WriteValue(false);
            }
            var r = RecurPoint.FromDaton(datondef, daton);

            if (compatibleFormat)
            {
                if (r is TableRecurPoint rt)
                {
                    WriteToCompatibleWire(writer, rt);
                }
                if (r is RowRecurPoint rr)
                {
                    writer.WritePropertyName(CamelCasify(datondef.MainTableDef.Name));
                    WriteToCompatibleWire(writer, rr);
                }
            }
            else //dense
            {
                writer.WritePropertyName("content");
                if (r is TableRecurPoint rt)
                {
                    WriteToDenseWire(writer, rt);
                }
                if (r is RowRecurPoint rr)
                {
                    writer.WriteStartArray();
                    WriteToDenseWire(writer, rr);
                    writer.WriteEndArray();
                }
            }
            writer.WriteEndObject();
            return(buf.ToString());
        }
Example #9
0
 /// <summary>
 /// Get a RecurPoint for the top level of a daton, which will be a RowRecurPoint for single-main-row type, else a TableRecurPoint
 /// </summary>
 public static RecurPoint FromDaton(DatonDef datondef, Daton daton)
 {
     if (datondef.MultipleMainRows)
     {
         return new TableRecurPoint {
                    TableDef = datondef.MainTableDef, Table = GetMainTable(datondef, daton, createIfMissing: true)
         }
     }
     ;
     else
     {
         return new RowRecurPoint {
                    TableDef = datondef.MainTableDef, Row = daton
         }
     };
 }
Example #10
0
        /// <summary>
        /// Get the final permission level for a user for a daton, and optionally a table and column. Uses
        /// the permissions base level overridden by the injected resolver function
        /// </summary>
        /// <param name="pristineDaton">null for new persistons, or the pristine version being edited</param>
        /// <param name="tablename">null ok</param>
        /// <param name="colname">null ok</param>
        public PermissionLevel FinalLevel(Daton pristineDaton, string tablename, string colname)
        {
            var max = PermissionLevel.None;

            foreach (var role in User.Roles)
            {
                var lev = role.BaseLevel;
                if (role.Level != null)
                {
                    lev = role.Level(User, pristineDaton);
                }
                if (tablename != null && role.TableOverrides != null)
                {
                    var trole = role.TableOverrides.FirstOrDefault(o => o.TableName == tablename);
                    if (trole != null)
                    {
                        lev = trole.BaseLevel;
                        if (trole.Level != null)
                        {
                            lev = trole.Level(User, pristineDaton, tablename);
                        }
                        if (colname != null && trole.ColumnOverrides != null)
                        {
                            var crole = trole.ColumnOverrides.FirstOrDefault(o => o.ColumnName == colname);
                            if (crole != null)
                            {
                                lev = crole.BaseLevel;
                                if (crole.Level != null)
                                {
                                    lev = crole.Level(User, pristineDaton, tablename, colname);
                                }
                            }
                        }
                    }
                }

                //force modify for columns that inhert create permission from table level
                if (colname != null && lev == PermissionLevel.Create)
                {
                    lev = PermissionLevel.Create | PermissionLevel.Modify;
                }

                max |= lev;
            }
            return(max);
        }
Example #11
0
        /// <summary>
        /// Modify the given daton by setting fields to null if the user does not have permission to view
        /// </summary>
        public void HidePrivateParts(Daton daton)
        {
            var datondef = Dbdef.FindDef(daton);
            var recur    = RecurPoint.FromDaton(datondef, daton);

            if (recur is TableRecurPoint rt)
            {
                HidePrivateParts(daton, rt);
            }
            else if (recur is RowRecurPoint rr)
            {
                //clear out the invisible cols in the single main row
                var invisibleFields = GetInvisibleFields(daton, rr);
                ClearInvisibleFields(invisibleFields, rr.Row);

                HidePrivateParts(daton, rr);
            }
        }
Example #12
0
        /// <summary>
        /// determine which col names are not writable
        /// </summary>
        private List <string> GetUnwritableColumnNames(Daton pristineDaton, TableDef tabledef)
        {
            var unwritableCols = new List <string>();

            foreach (var coldef in tabledef.Cols)
            {
                if (coldef.Name == tabledef.PrimaryKeyColName)
                {
                    continue;
                }
                var colLev = FinalLevel(pristineDaton, tabledef.Name, coldef.Name);
                if (!CanUpdate(colLev))
                {
                    unwritableCols.Add(coldef.Name);
                }
            }
            return(unwritableCols);
        }
Example #13
0
        /// <summary>
        /// Locate all writes that are disallowed for the table and append readable errors to the errors list
        /// </summary>
        private void FindDisallowedWrites(List <string> errors, Daton pristineDaton, TableDef tabledef, List <PersistonDiff.DiffRow> table)
        {
            var  unwritableColNames = GetUnwritableColumnNames(pristineDaton, tabledef);
            var  tableLev = FinalLevel(pristineDaton, tabledef.Name, null);
            bool canCreate = CanCreate(tableLev), canDelete = CanDelete(tableLev);

            foreach (var row in table)
            {
                if (row.Kind == DiffKind.DeletedRow)
                {
                    if (!canDelete)
                    {
                        errors.Add($"Unallowed: delete {tabledef.Name} rows");
                    }
                }
                else if (row.Kind == DiffKind.NewRow)
                {
                    if (!canCreate)
                    {
                        errors.Add($"Unallowed: create {tabledef.Name} rows");
                    }
                }
                else //update
                {
                    foreach (string colName in unwritableColNames)
                    {
                        if (row.Columns.ContainsKey(colName))
                        {
                            errors.Add($"Unallowed: update {tabledef.Name}.{colName}");
                        }
                    }
                }

                //recur to child tables
                if (row.ChildTables != null)
                {
                    foreach (var childTableDef in row.ChildTables.Keys)
                    {
                        FindDisallowedWrites(errors, pristineDaton, childTableDef, row.ChildTables[childTableDef]);
                    }
                }
            }
        }
Example #14
0
        /// <summary>
        /// determine which col names are not writable
        /// </summary>
        private List <string> GetUnwritableColumnNames(Daton pristineDaton, TableDef tabledef)
        {
            var unwritableCols = new List <string>();

            foreach (var coldef in tabledef.Cols)
            {
                if (coldef.Name == tabledef.PrimaryKeyColName)
                {
                    continue;
                }
                var  colLev            = FinalLevel(pristineDaton, tabledef.Name, coldef.Name);
                bool canUpdateExisting = CanUpdate(colLev);
                bool canUpdateNew      = pristineDaton == null && CanCreate(colLev); //new row doesn't require edit permission, only create
                bool canUpdate         = canUpdateExisting || canUpdateNew;
                if (!canUpdate)
                {
                    unwritableCols.Add(coldef.Name);
                }
            }
            return(unwritableCols);
        }
Example #15
0
        /// <summary>
        /// Get a daton, from cache or load from database. The reutrn value is a shared instance so the caller may not modify it.
        /// For new unsaved persistons with -1 as the key, this will create the instance with default values.
        /// </summary>
        /// <param name="user">if null, the return value is a shared guaranteed complete daton; if user is provided,
        /// the return value may be a clone with some rows removed or columns set to null</param>
        /// <param name="forceCheckLatest">if true then checks database to ensure latest version even if it was cached</param>
        /// <returns>object with daton, or readable errors</returns>
        public async Task <RetroSql.LoadResult> GetDaton(DatonKey key, IUser user, bool forceCheckLatest = false)
        {
            //new persiston: return now
            if (key.IsNew)
            {
                var   datondef2 = DataDictionary.FindDef(key);
                Daton newDaton  = Utils.Construct(datondef2.Type) as Daton;
                Utils.FixTopLevelDefaultsInNewPersiston(datondef2, newDaton);
                newDaton.Key = key;
                if (datondef2.Initializer != null)
                {
                    await datondef2.Initializer(newDaton);
                }
                return(new RetroSql.LoadResult {
                    Daton = newDaton
                });
            }

            //get from cache if possible, and optionally ignore cached version if it is not the latest
            string verifiedVersion = null;
            Daton  daton           = DatonCache.Get(key);

            if (forceCheckLatest && daton != null)
            {
                //viewons: always ignore cache; persistons: use cached only if known to be latest
                if (daton is Persiston)
                {
                    verifiedVersion = LockManager.GetVersion(key);
                    if (verifiedVersion != daton.Version)
                    {
                        daton = null;
                    }
                }
                else
                {
                    daton = null;
                }
            }

            //get from database if needed (and cache it), or abort
            var datondef = DataDictionary.FindDef(key);

            if (typeof(Persiston).IsAssignableFrom(datondef.Type) && (key is ViewonKey))
            {
                throw new Exception("Persiston requested but key format is for viewon");
            }
            if (typeof(Viewon).IsAssignableFrom(datondef.Type) && (key is PersistonKey))
            {
                throw new Exception("Viewon requested but key format is for persiston");
            }
            if (daton == null)
            {
                var sql = GetSqlInstance(key);
                RetroSql.LoadResult loadResult;
                using (var db = GetDbConnection(datondef.DatabaseNumber))
                    loadResult = await sql.Load(db, DataDictionary, user, key, ViewonPageSize);
                if (loadResult.Daton == null)
                {
                    return(loadResult);
                }
                daton = loadResult.Daton;
                if (verifiedVersion == null && daton is Persiston)
                {
                    verifiedVersion = LockManager.GetVersion(key);
                }
                daton.Version = verifiedVersion;
                DatonCache.Put(daton);
                Diagnostics.IncrementLoadCount();
            }

            //enforce permissions on the user
            if (user != null)
            {
                daton = daton.Clone(datondef);
                var guard = new SecurityGuard(DataDictionary, user);
                guard.HidePrivateParts(daton);
            }

            return(new RetroSql.LoadResult {
                Daton = daton
            });
        }
Example #16
0
        /// <summary>
        /// Load daton from database. Caller is responsible for setting the version (this does not deal with locks or versions)
        /// </summary>
        /// <param name="pageSize">only inspected for viewons main table</param>
        /// <returns>null if not found</returns>
        public virtual async Task <LoadResult> Load(IDbConnection db, DataDictionary dbdef, IUser user, DatonKey key, int pageSize)
        {
            var datondef = dbdef.FindDef(key);

            //viewon validation
            if (key is ViewonKey vkey2)
            {
                var validator = new Validator(user);
                await validator.ValidateCriteria(datondef, vkey2);

                if (validator.Errors.Any())
                {
                    return new LoadResult {
                               Errors = validator.Errors.ToArray()
                    }
                }
                ;
            }

            //handle viewon paging and ordering
            string sortColName = datondef.MainTableDef.DefaulSortColName;
            int    pageNo      = 0;

            if (key is ViewonKey vkey)
            {
                pageNo = vkey.PageNumber;
                if (vkey.SortColumnName != null)
                {
                    sortColName = vkey.SortColumnName;
                }
            }
            else
            {
                pageSize = 0;  //prohibit paging in persistons
            }
            //load main table
            var whereClause = MainTableWhereClause(datondef.MainTableDef, key);
            var loadResult  = await LoadTable(db, dbdef, datondef.MainTableDef, whereClause, sortColName, pageSize, pageNo);

            loadResult.RowsByParentKey.TryGetValue("", out var rowsForParent);

            //single-main-row datons cannot have zero main rows
            if (!datondef.MultipleMainRows && (rowsForParent == null || rowsForParent.Count == 0))
            {
                return(null);                                                                                   //was throw new Exception("Single-main-row not found using: " + whereClause.ToString());
            }
            Daton daton = Utils.Construct(datondef.Type) as Daton;

            if (datondef.MultipleMainRows)
            {
                if (daton is Viewon viewon)
                {
                    viewon.IsCompleteLoad = loadResult.IsComplete;
                }

                //copy rowsDict into daton's main table IList
                var listField = datondef.Type.GetField(datondef.MainTableDef.Name);
                if (rowsForParent != null)
                {
                    var list = Utils.CreateOrGetFieldValue <IList>(daton, listField);
                    foreach (var row in rowsForParent)
                    {
                        list.Add(row);
                    }
                }
            }
            else //single main row
            {
                if (rowsForParent != null)
                {
                    daton = rowsForParent?[0] as Daton;
                }
            }

            //child tables
            var rowsByPK = RestructureByPrimaryKey(datondef.MainTableDef, loadResult.RowsByParentKey);

            await LoadChildTablesRecursive(rowsByPK, db, dbdef, datondef.MainTableDef);

            daton.Key = key;
            daton.Recompute(datondef);
            return(new LoadResult {
                Daton = daton
            });
        }
Example #17
0
 /// <summary>
 /// When overridden, computes values of computed columns in the row
 /// </summary>
 public virtual void Recompute(Daton daton)
 {
 }
Example #18
0
        public static IList GetMainTable(DatonDef datondef, Daton daton, bool createIfMissing = false)
        {
            var f = daton.GetType().GetField(datondef.MainTableDef.Name);

            return(GetChildTable(daton, f, createIfMissing));
        }