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); }
/// <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); }
/// <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); } } }
/// <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()); }
/// <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 } }; }
/// <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); }
/// <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); } }
/// <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); }
/// <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]); } } } }
/// <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); }
/// <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 }); }
/// <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 }); }
/// <summary> /// When overridden, computes values of computed columns in the row /// </summary> public virtual void Recompute(Daton daton) { }
public static IList GetMainTable(DatonDef datondef, Daton daton, bool createIfMissing = false) { var f = daton.GetType().GetField(datondef.MainTableDef.Name); return(GetChildTable(daton, f, createIfMissing)); }