Exemple #1
0
        //see DataDictionaryToWire
        private static ColDefResponse ToWire(SecurityGuard guard, TableDef source, ColDef c, IUser user)
        {
            bool isDBAssignedKey = source.PrimaryKeyColName == c.Name && source.DatabaseAssignsKey;

            return(new ColDefResponse
            {
                PermissionLevel = (int)guard.FinalLevel(null, source.Name, c.Name),
                AllowSort = c.AllowSort,
                ForeignKeyDatonTypeName = c.ForeignKeyDatonTypeName,
                LeftJoin = ToWire(c.LeftJoin),
                SelectBehavior = ToWire(c.SelectBehavior),
                ImageUrlColumName = c.Image?.UrlColumName,
                IsComputed = c.IsComputed || isDBAssignedKey,
                IsMainColumn = c.IsMainColumn,
                IsVisibleInDropdown = c.IsVisibleInDropdown,
                LengthValidationMessage = DataDictionary.ResolvePrompt(c.LengthValidationMessage, user, defaultValue: null),
                MaxLength = c.MaxLength,
                MaxNumberValue = c.MaxNumberValue,
                MinLength = c.MinLength,
                MinNumberValue = c.MinNumberValue,
                Name = CamelCasify(c.Name),
                Prompt = DataDictionary.ResolvePrompt(c.Prompt, user, c.Name),
                RangeValidationMessage = DataDictionary.ResolvePrompt(c.RangeValidationMessage, user, defaultValue: null),
                Regex = c.Regex,
                RegexValidationMessage = DataDictionary.ResolvePrompt(c.RegexValidationMessage, user, defaultValue: null),
                WireType = c.WireType
            });
        }
 public MultiSaver(Retroverse retroverse, IUser user, PersistonDiff[] diffs)
 {
     Retroverse = retroverse;
     User       = user;
     Guard      = new SecurityGuard(retroverse.DataDictionary, user);
     SaveItems  = diffs.Select(d => new SaveItem {
         Diff = d
     }).ToArray();
 }
        /// <summary>
        /// Notify clients of changed persistons. This should be called when any persiston changes, in case a client is subscribed to it.
        /// No action will be taken if the change didn't change the version, so it is performant to call this repeatedly, or if it might
        /// not have really changed.
        /// </summary>
        public void NotifyClientsOf(DataDictionary dbdef, Daton[] datons)
        {
            foreach (var cli in Sessions.Values)
            {
                bool thisClientChanged = false;
                foreach (var daton in datons)
                {
                    //skip if this user doesn't need this daton
                    if (!cli.Subscriptions.TryGetValue(daton.Key, out string version))
                    {
                        continue;
                    }
                    if (version == daton.Version)
                    {
                        continue;                           //don't send if client already has the latest version
                    }
                    //remember we sent it
                    cli.Subscriptions[daton.Key] = daton.Version;
                    thisClientChanged            = true;

                    //hide cols by permissions
                    var datondef     = dbdef.FindDef(daton);
                    var trimmedDaton = daton.Clone(datondef);
                    var guard        = new SecurityGuard(dbdef, cli.User);
                    guard.HidePrivateParts(trimmedDaton);

                    //queue it for sending
                    lock (cli.DatonsToPush)
                    {
                        cli.DatonsToPush.Add(trimmedDaton);
                    }
                }

                //send queued datons now
                if (thisClientChanged)
                {
                    var completer = cli.LongPollingCompleter; //another thread could change cli.LongPollingCompleter, so access only through local var
                    if (completer != null)
                    {
                        try { completer.SetResult(true); }
                        catch { } //see note in LongPollingCompleted
                    }
                }
            }
        }
Exemple #4
0
        //see DataDictionaryToWire
        private static TableDefResponse ToWire(SecurityGuard guard, TableDef source, IUser user, bool isCriteria)
        {
            if (source == null)
            {
                return(null);
            }
            var wire = new TableDefResponse()
            {
                Name              = CamelCasify(source.Name),
                PermissionLevel   = (int)guard.FinalLevel(null, source.Name, null),
                Cols              = source.Cols.Select(c => ToWire(guard, source, c, user)).ToList(),
                PrimaryKeyColName = CamelCasify(source.PrimaryKeyColName),
                Prompt            = DataDictionary.ResolvePrompt(source.Prompt, user, source.Name),
                IsCriteria        = isCriteria,
                Children          = source.Children?.Select(t => ToWire(guard, t, user, false)).ToList()
            };

            return(wire);
        }
Exemple #5
0
        /// <summary>
        /// Convert the serializable portions of a data dictionary to a wire-ready structure.
        /// </summary>
        /// <param name="languageMessages">may be null; see Retroverse.LanguageMessages</param>
        public static DataDictionaryResponse DataDictionaryToWire(DataDictionary ddict, IUser user, Dictionary <string, Dictionary <string, string> > languageMessages)
        {
            var guard      = new SecurityGuard(ddict, user);
            var datonWires = new List <DatonDefResponse>();

            foreach (var name in ddict.DatonDefs.Keys)
            {
                var datondef = ddict.DatonDefs[name];
                datonWires.Add(new DatonDefResponse
                {
                    Name             = name,
                    IsPersiston      = typeof(Persiston).IsAssignableFrom(datondef.Type),
                    CriteriaDef      = ToWire(guard, datondef.CriteriaDef, user, true),
                    MainTableDef     = ToWire(guard, datondef.MainTableDef, user, false),
                    MultipleMainRows = datondef.MultipleMainRows
                });
            }

            var messages = new Dictionary <string, string>();
            Dictionary <string, string> dictByLanguage = null;

            languageMessages?.TryGetValue(user.LangCode, out dictByLanguage);
            foreach ((string code, string englishMessage) in Constants.EnglishMessages)
            {
                messages[code] = englishMessage;
                string overrideMessage = null;
                if (dictByLanguage?.TryGetValue(code, out overrideMessage) == true)
                {
                    messages[code] = overrideMessage;
                }
            }

            return(new DataDictionaryResponse
            {
                DatonDefs = datonWires,
                MessageConstants = messages
            });
        }
Exemple #6
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
            });
        }