Exemple #1
0
        public virtual void Process <T>(EActionType type, EActionScope scope, Mutator mutator, T current, T source) where T : Data <T>
        {
            var client = new AmazonSimpleNotificationServiceClient(Region);

            var payload = RenderPayload(type, scope, mutator, current, source);

            SendMessage(client, payload).Wait();
        }
Exemple #2
0
 public virtual PublishRequest RenderPayload <T>(EActionType type, EActionScope scope, Mutator mutator, T current, T source) where T : Data <T>
 {
     return(new PublishRequest
     {
         Message =
             new { type = type.ToString(), scope = scope.ToString(), payload = current ?? source }.ToJson(),
         Subject = $"{(current ?? source).GetFullIdentifier()}",
         TopicArn = Topic
     });
 }
Exemple #3
0
Fichier : Data.cs Projet : lr030/ML
        private static void ProcAfterPipeline(EActionType action, EActionScope scope, Mutator mutator, T currentModel, T originalModel)
        {
            if (Info <T> .Settings?.Pipelines?.After == null)
            {
                return;
            }

            foreach (var afterActionPipeline in Info <T> .Settings.Pipelines.After)
            {
                try
                {
                    afterActionPipeline.Process(action, scope, mutator, currentModel, originalModel);
                }
                catch (Exception e)
                {
                    if (!Info <T> .Settings.Silent)
                    {
                        Current.Log.Add <T>(e);
                    }
                }
            }
        }
Exemple #4
0
Fichier : Data.cs Projet : lr030/ML
        private static T ProcBeforePipeline(EActionType action, EActionScope scope, Mutator mutator, T currentModel, T originalModel)
        {
            if (Info <T> .Settings?.Pipelines?.Before == null)
            {
                return(currentModel);
            }

            foreach (var beforeActionPipeline in Info <T> .Settings.Pipelines.Before)
            {
                try
                {
                    currentModel = beforeActionPipeline.Process(action, scope, mutator, currentModel, originalModel);
                }
                catch (Exception e)
                {
                    if (!Info <T> .Settings.Silent)
                    {
                        Current.Log.Add <T>(e);
                    }
                }
            }

            return(currentModel);
        }
Exemple #5
0
        public virtual Dictionary <string, object> Headers <T>(ref DataAccessControl accessControl, Dictionary <string, StringValues> requestHeaders, EActionScope scope, T model) where T : Data <T>
        {
            var moderationSetup = ModerationHelper.Setup <T>();

            var ctx = new Dictionary <string, object> {
                { "moderated", true }
            };

            var customModerationPipeline = moderationSetup.CustomModerationPipeline;

            var allowedActions = moderationSetup.ModerationActions;

            if (customModerationPipeline != null && scope == EActionScope.Model)
            {
                allowedActions = customModerationPipeline.GetModerationActions(EActionType.Read, scope, null, model, null) ?? allowedActions;
            }

            if (allowedActions.Moderate)
            {
                ctx.Add("moderator", true);
            }
            if (allowedActions.Whitelisted)
            {
                ctx.Add("whiteListed", true);
            }
            if (allowedActions.Author)
            {
                ctx.Add("canPost", true);
            }

            if (customModerationPipeline != null)
            {
                var headerPayloadDictionary = new Dictionary <string, List <string> >();

                var onInsert = customModerationPipeline.OnInsertAbstracts();
                if (onInsert?.Any() == true)
                {
                    headerPayloadDictionary.Add("add", onInsert);
                }

                var onUpdate = customModerationPipeline.OnUpdateAbstracts();
                if (onUpdate?.Any() == true)
                {
                    headerPayloadDictionary.Add("edit", onUpdate);
                }

                var onRemove = customModerationPipeline.OnRemoveAbstracts();
                if (onRemove?.Any() == true)
                {
                    headerPayloadDictionary.Add("del", onRemove);
                }

                if (headerPayloadDictionary.Any())
                {
                    ctx.Add("abstract", headerPayloadDictionary);
                }
            }

            var canShow = allowedActions.Read;

            ctx.Add("canShow", canShow);

            if (canShow)
            {
                var path = Current.Context.Request.Path.ToUriComponent();
                path = path.Remove(path.Length - 1);

                if (path.Contains("moderation/task"))
                {
                    path = path.Replace("moderation/task", "");
                }

                ctx.Add("baseUrl", path);
            }

            var ret = new Dictionary <string, object> {
                { "x-zen-moderation", ctx }
            };

            return(ret);
        }
Exemple #6
0
        public T Process <T>(EActionType type, EActionScope scope, Mutator mutator, T current, T source) where T : Data <T>
        {
            // This is the main Moderation control flow. Let's start by setting up some helper classes:

            var moderationSetup          = ModerationHelper.Setup <T>();
            var customModerationPipeline = moderationSetup.CustomModerationPipeline;
            var allowedActions           = customModerationPipeline?.GetModerationActions(type, scope, mutator, current, source) ?? moderationSetup.ModerationActions;
            var currentPerson            = App.Current.Orchestrator.Person?.Locator;

            //Log.Info<T>($"MOD {type} | {currentPerson}");
            //Log.Info<T>($"MOD {type} | {allowedActions.ToJson()}");
            //Log.Info<T>($"MOD {type} | {current.ToReference()}");

            var currentKey = current.GetDataKey();

            // What can this user do?

            // Before anything, check if the target entry is marked as Imported. In that case the whole Moderation pipeline is sidestepped.

            var importModelMember = moderationSetup.Setup.ImportModelMember;

            if (importModelMember != null)
            {
                if (!current.HasMember(importModelMember))
                {
                    var msg = $"Moderation Pipeline: Invalid configuration - missing [{importModelMember}] ImportModelMember";
                    Base.Current.Log.Warn <T>(msg);
                    throw new InvalidOperationException(msg);
                }

                switch (type)
                {
                case EActionType.Insert:
                    var status = current.GetMemberValue <bool>(importModelMember);
                    if (status)
                    {
                        return(current);            // Imported record, nothing to be done here.
                    }
                    break;

                case EActionType.Update:
                    var newStatus = current.GetMemberValue <bool>(importModelMember);
                    var oldStatus = source.GetMemberValue <bool>(importModelMember);

                    if (source != null)
                    {
                        if (newStatus != oldStatus)
                        {
                            throw new ArgumentException($"Moderation Pipeline: Import flag [{importModelMember}] cannot be changed.");
                        }
                    }

                    if (newStatus)
                    {
                        return(current);
                    }
                    break;
                }
            }

            // Let's determine the Creator of this record.

            string creatorLocator = null;

            var creatorLocatorModelMember = moderationSetup.Setup.CreatorLocatorModelMember;

            if (creatorLocatorModelMember != null)
            {
                if (!current.HasMember(creatorLocatorModelMember))
                {
                    var msg = $"Moderation Pipeline: Invalid configuration - missing [{creatorLocatorModelMember}] CreatorLocatorModelMember";
                    Base.Current.Log.Warn <T>(msg);
                    throw new InvalidOperationException(msg);
                }

                creatorLocator = current.GetMemberValue <string>(creatorLocatorModelMember);
            }

            var    isCreator  = creatorLocator == currentPerson;
            string oRationale = null;

            // There are two kinds of Moderation action that this pipeline can handle. One is a Moderation Task....

            var controlPayload = ModerationHelper.GetModerationControlPayload();

            if (controlPayload != null)
            {
                // This is a Moderation Task operation - say, like an User trying to delete their own entry,
                // or a Mod changing things. We can use some extra data to help with the process.

                var oTaskId = controlPayload?.___ModerationTaskId;
                oRationale = controlPayload?.___ModerationRationale;

                if (oTaskId != null)
                {
                    var oTask = ModerationTask <T> .Get(oTaskId);

                    switch (type)
                    {
                    case EActionType.Insert:
                    case EActionType.Update:
                        // Let's change the payload to the new content.

                        var _os = oTask.Entry.ToJson();
                        var _ns = current.ToJson();

                        if (_ns != _os)
                        {
                            oTask.Entry = current;
                            oTask.Save();

                            new ModerationLog <T>
                            {
                                SourceId = currentKey,
                                Entry    = current,
                                Action   = type.ToString()
                            }.Save();

                            Base.Current.Log.Info <T>($"Moderation Pipeline: PATCH {oTaskId}");
                        }

                        // Moderator/Whitelisted? Accept it.

                        if (allowedActions.Moderate || allowedActions.Whitelisted || moderationSetup.Setup.CreatorCanWithdraw && isCreator)
                        {
                            ModerationTask <T> .Approve(oTaskId);
                        }

                        break;

                    case EActionType.Remove:
                        if (allowedActions.Moderate || allowedActions.Whitelisted)
                        {
                            ModerationTask <T> .Withdraw(oTaskId);
                        }
                        else
                        {
                            ModerationTask <T> .Reject(oTaskId);
                        }
                        break;
                    }
                }
            }

            // The second kind is regular models posted by users. Let's determine their fate:

            var mustCreateTask = false;
            var clearModel     = false;

            if (!(allowedActions.Author || allowedActions.Whitelisted))
            {
                throw new InvalidOperationException("Moderation Pipeline: Not authorized.");
            }

            switch (type)
            {
            case EActionType.Insert:
            case EActionType.Update:

                if (!(allowedActions.Moderate || allowedActions.Whitelisted))
                {
                    mustCreateTask = true;
                }

                if (allowedActions.Whitelisted)     // User is Whitelisted
                {
                    if (type == EActionType.Update) // If it's an update,
                    {
                        if (!isCreator)             // Whitelisted user isn't the creator
                        {
                            mustCreateTask = true;
                        }
                    }
                }

                break;

            case EActionType.Remove:
                if (allowedActions.Moderate)
                {
                    break;
                }
                if (allowedActions.Whitelisted && isCreator)
                {
                    break;
                }
                if (moderationSetup.Setup.CreatorCanWithdraw && isCreator)
                {
                    break;
                }

                mustCreateTask = true;

                break;

            default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }

            if (mustCreateTask) //
            {
                var statusModelMember = moderationSetup.Setup.StatusModelMember;
                if (statusModelMember != null)
                {
                    if (current.HasMember(statusModelMember))
                    {
                        if (!current.SetMemberValue(statusModelMember, null)) // Mark as 'Waiting Moderation'.
                        {
                            Base.Current.Log.Warn <T>($"Could NOT change moderation status on [{statusModelMember}] | {type}, entry {{{currentKey}}}");
                        }
                    }
                }

                var moderationTask = new ModerationTask <T>
                {
                    SourceId      = currentKey,
                    Entry         = current,
                    Action        = type.ToString(),
                    AuthorLocator = currentPerson,
                    Rationale     = oRationale
                };

                moderationTask.Save();

                clearModel = true;
            }

            new ModerationLog <T>
            {
                SourceId      = currentKey,
                Entry         = current,
                Action        = type.ToString(),
                AuthorLocator = currentPerson,
                Result        = mustCreateTask ? States.EResult.TaskCreated : States.EResult.Approved
            }.Save();

            if (moderationSetup.Setup.NotifyChanges)
            {
                var ePer = new Email();

                var emailContent =
                    "A new entry has been submitted.<br/><br/>" +
                    "Entry: " + current.ToReference() + "<br/>" +
                    "Creator: " + App.Current.Orchestrator.Person + "<br/><br/>";

                ePer.AddTo(App.Current.Orchestrator.Application.GetGroup("CUR"));
                ePer.AddCc(App.Current.Orchestrator.Application.GetGroup("MOD"));

                ePer.Title = $"{currentPerson}: {type} {Info<T>.Settings.FriendlyName}";

                emailContent += !mustCreateTask
                    ? "User was whitelisted: Action was automatically approved."
                    : "Action was submitted for moderation.";

                ePer.Content = emailContent;
                ePer.Send();
            }

            if (clearModel)
            {
                current = null;
            }
            return(current);
        }
Exemple #7
0
        public void Process <T>(EActionType type, EActionScope scope, Mutator mutator, T current, T source) where T : Data <T>
        {
            if (scope != EActionScope.Model)
            {
                return;
            }

            var sourceId = current.GetDataKey();

            var versionModel = new ModelVersioning <T>
            {
                SourceId = sourceId,
                Entry    = current,
                Action   = type
            };

            try
            {
                if (type == EActionType.Update)
                {
                    var    diffMap        = new List <string>();
                    string diffExpression = null;

                    var serializedSource = source.ToJson();
                    var serializedModel  = current.ToJson();

                    if (serializedSource == serializedModel)
                    {
                        return;                                      // Completely similar records. Ignore.
                    }
                    try
                    {
                        var sourcePropertyDictionary = source.ToMemberDictionary();
                        var modelPropertyDictionary  = current.ToMemberDictionary();

                        var compareMap = new List <string>();
                        compareMap.AddRange(sourcePropertyDictionary.Keys);

                        foreach (var coKey in modelPropertyDictionary.Keys)
                        {
                            if (!compareMap.Contains(coKey))
                            {
                                compareMap.Add(coKey);
                            }
                        }

                        foreach (var i in compareMap)
                        {
                            var sourceValue = (sourcePropertyDictionary.ContainsKey(i) ? sourcePropertyDictionary[i] : null).ToJson();
                            var modelValue  = (modelPropertyDictionary.ContainsKey(i) ? modelPropertyDictionary[i] : null).ToJson();

                            if (!sourceValue.Equals(modelValue))
                            {
                                diffMap.Add(i);
                            }
                        }

                        if (diffMap.Count > 0)
                        {
                            diffExpression = diffMap.Aggregate((i, j) => i + ", " + j);
                        }
                    } catch (Exception) { }

                    var delta = serializedModel.Length - serializedSource.Length;

                    if (delta > 0)
                    {
                        versionModel.Summary = $"+{Math.Abs(delta)}";
                    }
                    if (delta < 0)
                    {
                        versionModel.Summary = $"-{Math.Abs(delta)}";
                    }
                    if (delta == 0)
                    {
                        versionModel.Summary = "!=";
                    }

                    if (diffExpression != null)
                    {
                        versionModel.Summary += " | " + diffExpression;
                    }
                }
            } catch (Exception) { }

            Base.Log.Add <T>($"{versionModel.Id} {type} {versionModel.Summary}");

            versionModel.Insert();
        }
Exemple #8
0
 public Dictionary <string, object> Headers <T>(ref DataAccessControl accessControl, Dictionary <string, StringValues> requestHeaders, EActionScope scope, T model) where T : Data <T>
 {
     return(null);
 }
Exemple #9
0
        internal static IHeaderDictionary AddModelHeaders <T>(this IHeaderDictionary responseHeaders, ref DataAccessControl accessControl, IQueryCollection sourceQuery, EActionScope scope, T model = null) where T : Data <T>
        {
            var sourceParameters = sourceQuery.ToDictionary(i => i.Key, i => i.Value);

            if (Info <T> .Settings?.Pipelines?.Before != null)
            {
                foreach (var pipelineMember in Info <T> .Settings.Pipelines.Before)
                {
                    AddHeaders(responseHeaders, pipelineMember.Headers(ref accessControl, sourceParameters, scope, model));
                }
            }

            if (Info <T> .Settings?.Pipelines?.After != null)
            {
                foreach (var pipelineMember in Info <T> .Settings.Pipelines.After)
                {
                    AddHeaders(responseHeaders, pipelineMember.Headers(ref accessControl, sourceParameters, scope, model));
                }
            }

            return(responseHeaders);
        }
Exemple #10
0
 public T Process <T>(EActionType type, EActionScope scope, Mutator mutator, T current, T source) where T : Data <T>
 {
     return(current);
 }
Exemple #11
0
        public virtual Dictionary <string, object> Headers <T>(ref DataAccessControl accessControl, Dictionary <string, StringValues> requestHeaders, EActionScope scope, T model) where T : Data <T>
        {
            var ctx = new List <string>();

            if (!CanBrowse())
            {
                accessControl.Read = false;
                return(new Dictionary <string, object>());
            }

            ctx.Add("browse");

            if (requestHeaders?.ContainsKey(Mutator.CommonMetadataKeys.Set) == true)
            {
                if (!string.IsNullOrEmpty(requestHeaders[Mutator.CommonMetadataKeys.Set]))
                {
                    if (requestHeaders[Mutator.CommonMetadataKeys.Set] != Constants.CURRENT_LIVE_WORKSET_TAG)
                    {
                        accessControl.Write  = false;
                        accessControl.Remove = false;
                    }
                }
            }

            if (CanModify())
            {
                ctx.Add("modify");
            }
            else
            {
                accessControl.Write  = false;
                accessControl.Remove = false;
            }

            return(new Dictionary <string, object> {
                { "x-zen-setversion", ctx }
            });
        }