Example #1
0
        public FromPart AddFrom(string value, string name, FromOperator @operator)
        {
            var part = new FromPart(value, name, @operator);

            From.Add(part);
            return(part);
        }
Example #2
0
        /// <summary>
        /// Returns a new <see cref="TimeBlock"/> in which its entries are offset by the specified <see cref="TimeSpan"/>.
        /// </summary>
        public TimeBlock Offset(TimeSpan time)
        {
            TimeBlock next = Clone();

            next.From = From.Add(time);
            next.To   = To.Add(time);

            return(next);
        }
Example #3
0
 public Message(string sender, string recipient, string subject, string body, DateTime date)
 {
     From.Add(new MailboxAddress("", sender));
     To.Add(new MailboxAddress("", recipient));
     Subject = subject;
     Body    = new TextPart(TextFormat.Plain)
     {
         Text = body
     };
     Date = date;
 }
Example #4
0
            internal ICollection <FetchData> Partition()
            {
                //TODO: maybe partition on MetricNames first, but not sure if that's gonna affect minimal timegrain
                //TODO: make sure we actually decreased the interval
                var range = Till - From;
                var half  = TimeSpan.FromSeconds(Math.Floor(range.TotalSeconds / 2));

                return(new [] {
                    new FetchData {
                        ResourceId = ResourceId, From = From, Till = From.Add(half), MetricNames = MetricNames, TimeGrain = TimeGrain
                    },
                    new FetchData {
                        ResourceId = ResourceId, From = From.Add(half), Till = Till, MetricNames = MetricNames, TimeGrain = TimeGrain
                    },
                });
            }
Example #5
0
 internal void addFrom(Query table)
 {
     if (From == null)
     {
         From = new List <Query>();
     }
     if (From.Count == 0)
     {
         if (table.Name == null) // es query
         {
             From.Add(table);
         }
         else // es tabla
         {
             From      = table.From;
             PreSelect = table.PreSelect;
         }
     }
     else
     {
         From.Add(table);
     }
 }
Example #6
0
 public void Shift(TimeSpan amount)
 {
     From = From.Add(amount);
     To   = To.Add(amount);
 }
Example #7
0
 public EmailMessage(EmailAddress from, EmailAddress to)
 {
     From.Add(from);
     To.Add(to);
 }
Example #8
0
 public Period Move(TimeSpan duration)
 => new Period(From.Add(duration), To.Add(duration));
Example #9
0
 public Delete(Table tableName)
 {
     From.Add(tableName);
 }
Example #10
0
 public Select From(string table, string alias)
 {
     _from.Add(table, alias);
     return(this);
 }
Example #11
0
 public void Shift(int milliseconds)
 {
     From = From.Add(new TimeSpan(0, 0, 0, 0, milliseconds));
     To   = To.Add(new TimeSpan(0, 0, 0, 0, milliseconds));
 }
Example #12
0
 public Select(Table tableName)
 {
     From.Add(tableName);
 }
Example #13
0
        protected async Task GenerateTextContentExtractUsersAndUpdateSubject()
        {
            if (ctx == null || !ctx.HasValue)
            {
                return;
            }
            var nonNullContext = ctx.Value;

            try {
                var textContent = new StringBuilder();
                if (Messagetype == MessageType.RichText_Html)
                {
                    HtmlContent = Internal_Content;
                }
                else
                if (Messagetype == MessageType.ThreadActivity_AddMember ||
                    (Messagetype == MessageType.ThreadActivity_MemberJoined && Internal_Content.StartsWith("<addmember>"))        // there seem to be (old?) addmember messages that come with the wrong message type of ThreadActivity_MemberJoined... handle this here
                    )
                {
                    XmlDocument doc = new XmlDocument();
                    // need to force single XML values into array type since we know it also can be an array
                    doc.LoadXml($"<root xmlns:json='http://james.newtonking.com/projects/json'>{Internal_Content.Replace("<target", "<target json:Array='true'").Replace("<detailedtargetinfo", "<detailedtargetinfo json:Array='true'") ?? ""}</root>");
                    var json = JsonConvert.SerializeXmlNode(doc);
                    var data = JsonUtils.DeserializeObject <ThreadActivityAddMemberWrapper>(logger, json);

                    await Task.WhenAll(data.root.addmember.detailedtargetinfo?.Select(targetInfo => teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)targetInfo.id, targetInfo.friendlyName, OriginalArrivalTime)) ?? new List <Task>());

                    if (!string.IsNullOrWhiteSpace(data.root.addmember.initiator))
                    {
                        await teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)data.root.addmember.initiator, data.root.addmember.detailedinitiatorinfo?.friendlyName, OriginalArrivalTime);
                    }

                    // TODO: process alternate user display name
                    var memberNames = await Task.WhenAll(data.root.addmember.target.Select(t => teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)t)));

                    MessageSubject = $"✈️ {await teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)data.root.addmember.initiator)} added: " + string.Join(", ", memberNames);
                    textContent.Append(MessageSubject);
                }
                else
                if (Messagetype == MessageType.ThreadActivity_DeleteMember)
                {
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml($"<root xmlns:json='http://james.newtonking.com/projects/json'>{Internal_Content.Replace("<target", "<target json:Array='true'").Replace("<detailedtargetinfo", "<detailedtargetinfo json:Array='true'")}</root>");
                    var json = JsonConvert.SerializeXmlNode(doc);
                    var data = JsonUtils.DeserializeObject <ThreadActivityDeleteMemberWrapper>(logger, json);

                    await Task.WhenAll(data.root.deletemember.detailedtargetinfo?.Select(targetInfo => teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)targetInfo.id, targetInfo.friendlyName, OriginalArrivalTime)) ?? new List <Task>());

                    if (!string.IsNullOrWhiteSpace(data.root.deletemember.initiator))
                    {
                        await teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)data.root.deletemember.initiator, data.root.deletemember.detailedinitiatorinfo?.friendlyName, OriginalArrivalTime);
                    }

                    var memberNames = await Task.WhenAll(data.root.deletemember.target.Select(t => teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)t)));

                    MessageSubject = $"✈️ {await teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, new TeamsParticipant(data.root.deletemember?.initiator))} removed: " + string.Join(", ", memberNames);
                    textContent.Append(MessageSubject);
                }
                else
                if (Messagetype == MessageType.Event_Call)
                {
                    XmlDocument doc = new XmlDocument();
                    // prepare XML to JSON conversion; force "part" being a list which cannot be infered from XML if there is only one element
                    doc.LoadXml($"<root xmlns:json='http://james.newtonking.com/projects/json'>{Internal_Content.Replace("<part ", "<part json:Array='true' ")}</root>");
                    var json = JsonConvert.SerializeXmlNode(doc);
                    var data = JsonUtils.DeserializeObject <EventCallWrapper>(logger, json);

                    await Task.WhenAll(data.root.partlist?.part?.Select(member => teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)member.identity, member.displayName, OriginalArrivalTime)) ?? new List <Task>());

                    // sometimes p.name contains the user id and p.identity is empty
                    var memberNames = await Task.WhenAll(data.root.partlist?.part?.Select(p => teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, TeamsParticipant.FromFirstValid(p.identity, p.name))) ?? new List <Task <string> >());

                    var callEnded = Internal_Content.Contains("<ended/>");
                    if (callEnded)
                    {
                        MessageSubject = "☎️ Call ended for: " + string.Join(", ", memberNames);
                    }
                    else
                    {
                        var from        = (TeamsParticipant)Internal_FromContactUrl;
                        var displayName = await teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, from);

                        MessageSubject = $"☎️ Call started by {displayName}";
                    }
                    textContent.Append(MessageSubject);
                }
                else
                if (Messagetype == MessageType.ThreadActivity_MemberJoined)
                {
                    var data = JsonUtils.DeserializeObject <ThreadEventMemberJoined>(logger, Internal_Content);

                    await Task.WhenAll(data.members.Select(member => teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)member.id, member.friendlyname, OriginalArrivalTime)));

                    var memberNames = (await Task.WhenAll(data.members.Select(member => teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)member.id))));
                    MessageSubject = "✈️ Member(s) joined: " + string.Join(", ", memberNames); // note: friendlyname is sometimes empty; second note: für ehemalige Mitarbeiter kann ein ID-Lookup fehlschlagen, aber der friendlyName dennoch gesetzt sein
                    textContent.Append(MessageSubject);
                }
                else
                if (Messagetype == MessageType.ThreadActivity_MemberLeft)
                {
                    var data = JsonUtils.DeserializeObject <ThreadEventMemberLeft>(logger, Internal_Content);

                    await Task.WhenAll(data.members.Select(member => teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)member.id, member.friendlyname, OriginalArrivalTime)));

                    var memberNames = await Task.WhenAll(data.members.Select(member => teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)member.id)));

                    MessageSubject = "✈️ Member(s) left: " + string.Join(", ", memberNames);
                    textContent.Append(MessageSubject);
                }
                else
                if (Messagetype == MessageType.RichText_Media_CallRecording)
                {
                    XmlDocument doc = new XmlDocument();
                    // prepare XML to JSON conversion; force "part" being a list which cannot be infered from XML if there is only one element
                    doc.LoadXml($"<root xmlns:json='http://james.newtonking.com/projects/json'>{Internal_Content.Replace("<Identifiers>", "<Identifiers json:Array='true'>").Replace("<RecordingContent ", "<RecordingContent json:Array='true' ").Replace("<RequestedExports ", "<RequestedExports json:Array='true' ")}</root>");
                    var json = JsonConvert.SerializeXmlNode(doc);
                    var data = JsonUtils.DeserializeObject <RichTextMedia_CallRecordingWrapper>(logger, json);

                    MessageSubject = $"✍️ Recording started by {await teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, new TeamsParticipant(data.root?.URIObject?.RecordingInitiatorId?.value))}";
                    textContent.Append(MessageSubject);
                }
                else if (Messagetype == MessageType.Text)
                {
                    HtmlContent = Internal_Content;
                }
                else if (Messagetype == MessageType.ThreadActivity_TopicUpdate)
                {
                    XmlDocument doc = new XmlDocument();
                    // <topicupdate><eventtime>0000000000000</eventtime><initiator>8:orgid:00000000-0000-beef-0000-000000000000</initiator><value>New topic</value></topicupdate>
                    doc.LoadXml($"<root xmlns:json='http://james.newtonking.com/projects/json'>{Internal_Content}</root>");
                    var json = JsonConvert.SerializeXmlNode(doc);
                    var data = JsonUtils.DeserializeObject <ThreadActivityTopicUpdateWrapper>(logger, json);

                    var user = await teamsUserRegistry.GetUserByIdAsync(nonNullContext, (TeamsParticipant)data.root.topicupdate.initiator, false);

                    if (user != null && user.HasDisplayName)
                    {
                        if (From.Count == 1 && (From[0].UserId.Kind == ParticipantKind.TeamsChat || From[0].UserId.Kind == ParticipantKind.Unknown))
                        {
                            From.Clear();
                            From.Add(user);
                        }
                    }

                    MessageSubject = $"®️ Topic set to '{data.root.topicupdate.value}' by {await teamsUserRegistry.GetDisplayNameForUserIdAsync(nonNullContext, new TeamsParticipant(data.root.topicupdate.initiator))}";
                    textContent.Append(MessageSubject);
                }
                else
                {
                    textContent.Append("Unknown message type, don't know how to render: " + Messagetype);
                }

                if (string.IsNullOrWhiteSpace(HtmlContent))
                {
                    HtmlContent = MessageSubject;
                }
                TextContent = textContent.ToString();
            } catch (Exception e)
            {
                // exceptions here will cancel the whole chat from being parsed; log the message content to analyze it later
                logger.Error(e, "[{TenantName}] Exception while processing message content in method {MethodName}; Original message content: {MessageContent}", nonNullContext.Tenant.TenantName, nameof(GenerateTextContentExtractUsersAndUpdateSubject), SerializeOriginalMessageAsJson());
                // don't just skip a failed message, but cancel chat retrieval and fix the underlying issue, then try again
                throw;
            }
        }
Example #14
0
        protected async Task ExtractSendersReceiversAndSubject(string chatId)
        {
            if (ctx == null || !ctx.HasValue)
            {
                return;
            }
            var nonNullContext = ctx.Value;


            var messageFromTeams = false;
            var messageFromMe    = false;

            if (Internal_FromContactUrl?.EndsWith(chatId, StringComparison.InvariantCultureIgnoreCase) ?? false)
            {
                messageFromTeams = true;
            }

#pragma warning disable CS8604 // Possible null reference argument.
            if (Internal_FromContactUrl?.ToString().EndsWith(nonNullContext.Tenant.UserId, StringComparison.InvariantCultureIgnoreCase) ?? false)
#pragma warning restore CS8604 // Possible null reference argument.
            {
                messageFromMe = true;
            }

            // determine senders
            if (messageFromTeams)
            {
                var teamsChatUser = new ProcessedTeamsUser(nonNullContext, (TeamsParticipant)chatId);
                teamsChatUser.RegisterAlternateDisplayName(Constants.MicrosoftTeamsChatSenderName, OriginalArrivalTime);
                teamsChatUser.RegisterAlternateEmailAddress(Constants.MicrosoftTeamsChatSenderEmailAddress, OriginalArrivalTime);
                From.Add(teamsChatUser);
            }
            else
            {
                var userId = (TeamsParticipant)Internal_FromContactUrl;
                if (userId.IsValid)
                {
                    await teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, userId, Internal_DisplayName, OriginalArrivalTime);

                    var user = await teamsUserRegistry.GetUserByIdOrDummyAsync(nonNullContext, userId);

                    if (user.HasDisplayName && user.HasEmailAddress)
                    {
                        From.Add(user);
                    }
                }
                else
                {
                    if (From.Count == 0)
                    {
                        // no valid user id? phew...
                        var dummyUser = new ProcessedTeamsUser(nonNullContext, userId);
                        dummyUser.RegisterAlternateDisplayName(Internal_DisplayName, OriginalArrivalTime);
                        From.Add(dummyUser);
                    }
                }
            }

            // determine receivers
            if (Internal_Mentions?.Count > 0)
            {
                foreach (var mention in Internal_Mentions)
                {
                    var userId = (TeamsParticipant)mention.mri;
                    var user   = await teamsUserRegistry.GetUserByIdAsync(nonNullContext, userId, true);

                    if (user != null && user.HasDisplayName && user.HasEmailAddress)
                    {
                        To.Add(user);
                    }
                    else
                    {
                        var toUser = new ProcessedTeamsUser(nonNullContext, userId);
                        toUser.RegisterAlternateDisplayName(mention.displayName, OriginalArrivalTime);
                        toUser.RegisterAlternateEmailAddress(mention.IsChannelMention ? Constants.ChannelMentionEmailAddress : Constants.UnknownUserEmailAddress, OriginalArrivalTime);
                        To.Add(toUser);
                    }
                }
            }
            else
            {
                var toUser = new ProcessedTeamsUser(nonNullContext, TeamsParticipant.Null);
                toUser.RegisterAlternateDisplayName(Constants.UnknownReceiversDisplayName, OriginalArrivalTime);
                toUser.RegisterAlternateEmailAddress(Constants.UnknownUserEmailAddress, OriginalArrivalTime);
                To.Add(toUser);
            }

            // determine subject
            if (!string.IsNullOrWhiteSpace(Internal_Subject))
            {
                MessageSubject = Internal_Subject;
            }
            else
            {
                string displayName = Internal_DisplayName ?? "";
                if (displayName == null && (Messagetype != MessageType.Text || Messagetype != MessageType.RichText_Html))
                {
                    displayName = "Microsoft Teams";
                }

                await teamsUserRegistry.RegisterDisplayNameForUserIdAsync(nonNullContext, (TeamsParticipant)Internal_FromContactUrl, displayName, OriginalArrivalTime);

                displayName = await teamsUserRegistry.ReplaceUserIdsWithDisplayNamesAsync(nonNullContext, displayName);

                var messagePreview = "Message";
                if (Messagetype == MessageType.RichText_Html)
                {
                    // not sure if needed
                    string       html = string.Format("<html><head></head><body>{0}</body></html>", Internal_Content);
                    HtmlDocument doc  = new HtmlDocument();
                    doc.LoadHtml(html);
                    var body = doc.DocumentNode.SelectSingleNode("//body");
                    messagePreview = body.InnerText ?? "";
                }
                else if (Messagetype == MessageType.Text)
                {
                    messagePreview = Internal_Content ?? "";
                }
                messagePreview = HttpUtility.HtmlDecode(messagePreview).Trim(); // need to replace &nbsp; etc.
                if (messagePreview.Length > 100)
                {
                    messagePreview = messagePreview.Truncate(100) + "...";
                }
                else
                if (messagePreview.Length == 0)
                {
                    messagePreview = $"Message";
                }
                var truncatedDisplayName = displayName.Truncate(10)?.Trim() ?? "";
                MessageSubject = $"[{(messageFromMe ? "ME" : truncatedDisplayName)}] {messagePreview}";
            }
        }
Example #15
0
 /// <summary>
 /// Constructs a new <see cref="TimeBlock"/> starting from <see cref="DateTime.UtcNow"/> offset by a specified <see cref="TimeSpan"/>.
 /// </summary>
 public TimeBlock(TimeSpan length)
 {
     From = DateTime.UtcNow;
     To   = From.Add(length);
 }
 public State(string name, State from)
     : this(name)
 {
     from.To.Add(this);
     From.Add(from);
 }