protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            if (this.LeftChildNode.GetValue(rc, forceMatch) == null ||
                this.RightChildNode.GetValue(rc, forceMatch) == null)
            {
                return(null);
            }

            switch (this.Operator)
            {
            case "==":
                return(this.LeftChildNode.GetValue(rc, forceMatch) == this.RightChildNode.GetValue(rc, forceMatch));

            case "<>":
            case "!=":
                return(this.LeftChildNode.GetValue(rc, forceMatch) != this.RightChildNode.GetValue(rc, forceMatch));

            case ">":
                return(this.LeftChildNode.GetValue(rc, forceMatch) > this.RightChildNode.GetValue(rc, forceMatch));

            case "<":
                return(this.LeftChildNode.GetValue(rc, forceMatch) < this.RightChildNode.GetValue(rc, forceMatch));

            case ">=":
                return(this.LeftChildNode.GetValue(rc, forceMatch) >= this.RightChildNode.GetValue(rc, forceMatch));

            case "<=":
                return(this.LeftChildNode.GetValue(rc, forceMatch) <= this.RightChildNode.GetValue(rc, forceMatch));
            }

            return(null);
        }
예제 #2
0
        private void SendToIrc(IEnumerable <IStalk> stalks, IRecentChange rc)
        {
            var splitStalks = new Dictionary <string, List <IStalk> >();

            foreach (var stalk in stalks)
            {
                if (!splitStalks.ContainsKey(stalk.Channel))
                {
                    splitStalks.Add(stalk.Channel, new List <IStalk>());
                }

                splitStalks[stalk.Channel].Add(stalk);
            }

            try
            {
                foreach (var stalkList in splitStalks)
                {
                    this.freenodeClient.SendMessage(stalkList.Key, this.FormatMessageForIrc(stalkList.Value, rc));
                }
            }
            catch (Exception ex)
            {
                this.logger.ErrorFormat(ex, "Failed to send notification IRC message for RC {0}", rc);
            }
        }
예제 #3
0
        private void SendIndividualEmail(IList <IStalk> stalks, IRecentChange rc, IBotUser botUser)
        {
            if (!botUser.EmailAddressConfirmed)
            {
                return;
            }

            var stalkList = string.Join(", ", stalks.Select(x => x.Identifier));

            try
            {
                var extraHeaders = new Dictionary <string, string>
                {
                    { "StalkList", stalkList }
                };

                this.emailHelper.SendEmail(
                    this.emailTemplateFormatter.FormatRecentChangeStalksForEmail(stalks, rc, botUser),
                    string.Format(this.templates.EmailRcSubject, stalkList, rc.Page),
                    null,
                    botUser,
                    extraHeaders);
            }
            catch (Exception ex)
            {
                this.logger.ErrorFormat(ex, "Failed to send notification email for RC {0}", rc);
            }
        }
예제 #4
0
 protected virtual void SanityCheck(IRecentChange rc)
 {
     if (rc == null)
     {
         throw new ArgumentNullException("rc");
     }
 }
예제 #5
0
        public void HandleRcEvent(MessageReceivedEventArgs e, IRecentChange rc)
        {
            var stalks = this.channelConfig.MatchStalks(rc, e.Target).ToList();

            if (stalks.Count == 0)
            {
                return;
            }

            this.logger.InfoFormat(
                "Seen stalked change for stalks: {0}",
                string.Join(" ", stalks.Select(x => x.Identifier)));

            // Touch expiry date (*before* email is sent)
            foreach (var stalk in stalks)
            {
                stalk.TriggerDynamicExpiry();
            }

            // send notifications
            this.SendToIrc(stalks, rc);
            this.SendEmail(stalks, rc);

            // touch update/count
            foreach (var stalk in stalks)
            {
                stalk.LastTriggerTime = DateTime.UtcNow;
                stalk.TriggerCount++;
            }

            this.channelConfig.Save();
        }
예제 #6
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            var leftResult  = this.LeftChildNode.Match(rc, false);
            var rightResult = this.RightChildNode.Match(rc, false);

            if (leftResult.HasValue && rightResult.HasValue && leftResult.Value == rightResult.Value)
            {
                return(false);
            }

            if (leftResult.HasValue && rightResult.HasValue)
            {
                // leftResult!=rightResult is always true because above condition, hence excluded

                return(true);
            }

            if (!forceMatch)
            {
                return(null);
            }

            leftResult  = leftResult ?? this.LeftChildNode.Match(rc, true);
            rightResult = rightResult ?? this.RightChildNode.Match(rc, true);

            if (!leftResult.HasValue || !rightResult.HasValue)
            {
                return(null);
            }

            return(leftResult.Value != rightResult.Value);
        }
        public override long?GetValue(IRecentChange rc, bool forceMatch)
        {
            if (!forceMatch)
            {
                return(null);
            }

            return(rc.GetPageSize());
        }
예제 #8
0
        public bool Match(IRecentChange rc)
        {
            if (!this.IsActive())
            {
                return(false);
            }

            return(this.baseNode.Match(rc));
        }
예제 #9
0
        protected override void SanityCheck(IRecentChange rc)
        {
            base.SanityCheck(rc);

            if (!this.Minimum.HasValue && !this.Maximum.HasValue)
            {
                throw new InvalidOperationException("Must define at least one of min or max");
            }
        }
예제 #10
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            if (DateTime.UtcNow > this.Expiry)
            {
                return(false);
            }

            return(this.ChildNode.Match(rc, forceMatch));
        }
예제 #11
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            if (!forceMatch)
            {
                return(null);
            }

            return(rc.PageIsInCategory(this.Expression));
        }
        protected override void SanityCheck(IRecentChange rc)
        {
            base.SanityCheck(rc);

            if (this.ChildNode == null)
            {
                throw new InvalidOperationException("No child node defined!");
            }
        }
예제 #13
0
        protected override void SanityCheck(IRecentChange rc)
        {
            base.SanityCheck(rc);

            if (this.Expression == null)
            {
                throw new InvalidOperationException("No match expression has been set!");
            }
        }
예제 #14
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            if (!forceMatch)
            {
                return(null);
            }

            return(rc.GetUserGroups().Contains(this.Expression));
        }
예제 #15
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            this.Compile();

            if (rc.EditFlags != null)
            {
                return(this.RegexExpression.Match(rc.EditFlags).Success);
            }

            return(false);
        }
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            this.Compile();

            var result = false;

            if (rc.User != null)
            {
                result |= this.RegexExpression.Match(rc.User).Success;
            }

            return(result);
        }
        protected override void SanityCheck(IRecentChange rc)
        {
            base.SanityCheck(rc);

            if (this.ChildNodes == null)
            {
                throw new InvalidOperationException("Child node list is null");
            }

            if (!this.ChildNodes.Any())
            {
                throw new InvalidOperationException("No child nodes present");
            }
        }
예제 #18
0
        public bool Match(IRecentChange rc)
        {
            var initialResult = this.Match(rc, false);

            if (initialResult.HasValue)
            {
                return(initialResult.Value);
            }

            var match = this.Match(rc, true);

            if (match.HasValue)
            {
                return(match.Value);
            }

            throw new InvalidOperationException("Result of forced match is null!");
        }
        public IEnumerable <IStalk> MatchStalks(IRecentChange rc, string channel)
        {
            if (!this.Initialised)
            {
                throw new ApplicationException("Cannot match when not initialised!");
            }

            using (GlobalMatchDuration.NewTimer())
            {
                SortedList <string, IStalk> stalkListClone;
                lock (this.ItemList)
                {
                    stalkListClone = new SortedList <string, IStalk>(
                        this.ItemList.SelectMany(x => x.Value.Stalks.Values)
                        .Where(x => x.WatchChannel == channel)
                        .Where(x => x.IsActive())
                        .ToDictionary(x => x.Identifier + "@" + x.Channel));
                }

                foreach (var s in stalkListClone)
                {
                    bool isMatch;

                    try
                    {
                        using (IndividualMatchDuration.WithLabels(s.Value.Channel, s.Value.Identifier).NewTimer())
                        {
                            isMatch = s.Value.Match(rc);
                        }
                    }
                    catch (InvalidOperationException ex)
                    {
                        this.Logger.ErrorFormat(ex, "Error during evaluation of stalk {0}", s.Key);
                        // skip this stalk, resume with the others
                        continue;
                    }

                    if (isMatch)
                    {
                        yield return(s.Value);
                    }
                }
            }
        }
        protected override void SanityCheck(IRecentChange rc)
        {
            base.SanityCheck(rc);

            if (this.LeftChildNode == null)
            {
                throw new InvalidOperationException("No left child node defined!");
            }

            if (this.RightChildNode == null)
            {
                throw new InvalidOperationException("No right child node defined!");
            }

            if (this.Operator == null)
            {
                throw new InvalidOperationException("No operator defined!");
            }
        }
예제 #21
0
        private void SendEmail(IEnumerable <IStalk> stalks, IRecentChange rc)
        {
            if (this.appConfig.EmailConfiguration == null)
            {
                this.logger.Debug("Not sending email; email configuration is disabled");
                return;
            }

            var stalkSplit = this.botUserConfiguration.Items.ToDictionary(x => x, y => new HashSet <IStalk>());

            foreach (var stalk in stalks)
            {
                var channel = this.channelConfig[stalk.Channel];
                var userSubscriptionsToStalk = this.subscriptionHelper.GetUserSubscriptionsToStalk(channel, stalk);

                foreach (var subscription in userSubscriptionsToStalk.Where(x => x.IsSubscribed))
                {
                    stalkSplit[subscription.BotUser].Add(subscription.Stalk);
                }
            }

            foreach (var kvp in stalkSplit)
            {
                var stalkList = kvp.Value;
                var botUser   = kvp.Key;

                if (!stalkList.Any())
                {
                    continue;
                }

                if (!botUser.EmailAddressConfirmed)
                {
                    continue;
                }

                this.SendIndividualEmail(stalkList.ToList(), rc, botUser);
            }
        }
예제 #22
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            int maxLimit = 0;
            int minLimit = 0;

            foreach (var node in this.ChildNodes)
            {
                var localResult = node.Match(rc, forceMatch);

                if (!localResult.HasValue)
                {
                    maxLimit++;
                    continue;
                }

                if (localResult.Value)
                {
                    maxLimit++;
                    minLimit++;
                }
            }

            if (this.Maximum.HasValue && minLimit > this.Maximum)
            {
                return(false);
            }

            if (this.Minimum.HasValue && maxLimit < this.Minimum)
            {
                return(false);
            }

            if (minLimit < this.Minimum || maxLimit > this.Maximum)
            {
                return(null);
            }

            return(true);
        }
예제 #23
0
        public string FormatMessageForIrc(IEnumerable <IStalk> stalks, IRecentChange rc)
        {
            var  stalkTags = new StringBuilder();
            bool first     = true;

            foreach (var s in stalks)
            {
                if (!first)
                {
                    stalkTags.Append(this.templates.IrcStalkTagSeparator);
                }

                first = false;

                stalkTags.Append(s.Identifier);
            }

            var sizeDiff = "N/A";

            if (rc.SizeDiff.HasValue)
            {
                sizeDiff = (rc.SizeDiff.Value > 0 ? "+" : string.Empty) +
                           rc.SizeDiff.Value.ToString(CultureInfo.InvariantCulture);
            }

            return(string.Format(
                       this.templates.IrcAlertFormat,
                       stalkTags,
                       rc.Url,
                       rc.Page,
                       rc.User,
                       rc.EditSummary,
                       sizeDiff,
                       rc.EditFlags,
                       DateTime.UtcNow.ToString(this.appConfig.DateFormat)
                       ));
        }
예제 #24
0
        protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
        {
            // Optimism!
            bool?result = true;

            foreach (var childNode in this.ChildNodes)
            {
                var localResult = childNode.Match(rc, forceMatch);

                if (localResult.GetValueOrDefault(true) == false)
                {
                    return(false);
                }

                if (localResult != null)
                {
                    continue;
                }

                result = null;
            }

            return(result);
        }
        public string FormatRecentChangeStalksForEmail(IEnumerable <IStalk> stalks, IRecentChange rc, IBotUser botUser)
        {
            var stalksFormatted = this.FormatStalkListForEmail(stalks, botUser);

            var sizeDiff = "N/A";

            if (rc.SizeDiff.HasValue)
            {
                sizeDiff = (rc.SizeDiff.Value > 0 ? "+" : string.Empty) +
                           rc.SizeDiff.Value.ToString(CultureInfo.InvariantCulture);
            }

            return(string.Format(
                       this.templates.EmailRcTemplate,
                       stalksFormatted,
                       rc.Url,
                       rc.Page,
                       rc.User,
                       rc.EditSummary,
                       sizeDiff,
                       rc.EditFlags,
                       DateTime.UtcNow.ToString(this.appConfig.DateFormat)
                       ));
        }
예제 #26
0
 public abstract long?GetValue(IRecentChange rc, bool forceMatch);
예제 #27
0
 public void LocalSetup()
 {
     this.rc = this.RecentChangeBuilder().Object;
 }
예제 #28
0
 public override long?GetValue(IRecentChange rc, bool forceMatch)
 {
     return(this.Value);
 }
예제 #29
0
 protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
 {
     return(this.ChildNode.Match(rc, forceMatch));
 }
예제 #30
0
 protected override bool?DoMatch(IRecentChange rc, bool forceMatch)
 {
     return(false);
 }