Beispiel #1
0
        private Attachment ToAdaptiveCard(PostNotify post, string avatarUrl)
        {
            var card = new AdaptiveCard("1.2")
            {
                Body = new List <AdaptiveElement>
                {
                    // Header
                    new AdaptiveTextBlock
                    {
                        Size   = AdaptiveTextSize.Large,
                        Weight = AdaptiveTextWeight.Bolder,
                        Text   = GetLink(DomainName, post.Regarding)
                    },

                    // Author
                    new AdaptiveColumnSet
                    {
                        Columns = new List <AdaptiveColumn>
                        {
                            new AdaptiveColumn
                            {
                                Items = new List <AdaptiveElement>
                                {
                                    new AdaptiveImage
                                    {
                                        Style = AdaptiveImageStyle.Person,
                                        Size  = AdaptiveImageSize.Small,
                                        Url   = new Uri(avatarUrl)
                                    }
                                },
                                Width = "auto",
                            },
                            new AdaptiveColumn
                            {
                                Items = new List <AdaptiveElement>
                                {
                                    new AdaptiveTextBlock
                                    {
                                        Weight = AdaptiveTextWeight.Bolder,
                                        Text   = GetLink(DomainName, (EntityReference)(post.Comment ?? post.Post)["createdby"]),
                                        Wrap   = true
                                    },
                                    new AdaptiveTextBlock
                                    {
                                        Text     = $"{{{{DATE({(post.Comment ?? post.Post)["createdon"]:yyyy-MM-ddTHH:mm:ssZ})}}}} {{{{TIME({(post.Comment ?? post.Post)["createdon"]:yyyy-MM-ddTHH:mm:ssZ})}}}}",
                                        Size     = AdaptiveTextSize.Small,
                                        IsSubtle = true,
                                        Spacing  = AdaptiveSpacing.None
                                    }
                                },
Beispiel #2
0
        public async Task <IActionResult> PostAsync([FromQuery] string code, [FromBody] JObject requestContext)
        {
            if (code != _config.GetValue <string>("WebhookKey"))
            {
                return(Unauthorized());
            }

            try
            {
                // Get a reference to the post/postcomment that has just been created. The requestContext holds a RemoteExecutionContext
                // object, so extract out the PrimaryEntityName and PrimaryEntityId properties
                var postReference = new EntityReference(requestContext.Value <string>("PrimaryEntityName"), new Guid(requestContext.Value <string>("PrimaryEntityId")));

                using (var org = new CdsServiceClient(new Uri("https://" + DomainName), _config.GetValue <string>("MicrosoftAppId"), _config.GetValue <string>("MicrosoftAppPassword"), true, null))
                {
                    var post        = org.Retrieve(postReference.LogicalName, postReference.Id, new ColumnSet(true));
                    var postComment = post;

                    if (postReference.LogicalName == "postcomment")
                    {
                        // This is a comment to an existing post, go and retrieve the original post
                        post = org.Retrieve("post", postComment.GetAttributeValue <EntityReference>("postid").Id, new ColumnSet(true));
                    }

                    // Get the entity the post is on
                    var entityRef = post.GetAttributeValue <EntityReference>("regardingobjectid");
                    var entity    = org.Retrieve(entityRef.LogicalName, entityRef.Id, new ColumnSet(true));

                    post = GetFullPostText(org, entityRef, post, ref postComment);

                    // Get the users to notify
                    var entityRelationships = new Dictionary <Guid, Link>();
                    var usersToNotify       = new HashSet <EntityReference>();

                    if (postComment != post)
                    {
                        entityRelationships.Add(postComment.Id, new Link {
                            From = post.ToEntityReference(), Description = "Contains Comment"
                        });
                        entityRelationships.Add(post.Id, new Link {
                            From = postComment.ToEntityReference(), Description = "Is Comment On"
                        });
                    }

                    entityRelationships.Add(entity.Id, new Link {
                        From = post.ToEntityReference(), Description = "Is Posted On"
                    });

                    if (entity.LogicalName == "systemuser")
                    {
                        usersToNotify.Add(entity.ToEntityReference());
                    }

                    GetInterestedUsers(post, postComment, entity, org, usersToNotify, entityRelationships);
                    ExpandTeamsToUsers(usersToNotify, org, entityRelationships);
                    AddUserFollows(usersToNotify, org, entityRelationships);

                    // Remove the user who added the post
                    usersToNotify.Remove(postComment.GetAttributeValue <EntityReference>("createdby"));

                    // Remove any possible null value
                    usersToNotify.Remove(null);

                    if (usersToNotify.Any())
                    {
                        string avatarUrl = null;

                        // Connect to storage account so we can look up the details we need to send the message to each user
                        var connectionString = _config.GetConnectionString("Storage");
                        var storageAccount   = CloudStorageAccount.Parse(connectionString);
                        var tableClient      = storageAccount.CreateCloudTableClient();
                        var table            = tableClient.GetTableReference("users");

                        foreach (var userRef in usersToNotify)
                        {
                            var user             = org.Retrieve(userRef.LogicalName, userRef.Id, new ColumnSet("domainname"));
                            var username         = user.GetAttributeValue <string>("domainname");
                            var userTeamsDetails = (User)table.Execute(TableOperation.Retrieve <User>(username, "")).Result;

                            if (userTeamsDetails == null)
                            {
                                continue;
                            }

                            MicrosoftAppCredentials.TrustServiceUrl(userTeamsDetails.ServiceUrl);
                            var client = new ConnectorClient(new Uri(userTeamsDetails.ServiceUrl), _config.GetValue <string>("MicrosoftAppId"), _config.GetValue <string>("MicrosoftAppPassword"));

                            if (avatarUrl == null)
                            {
                                var sender = org.Retrieve("systemuser", postComment.GetAttributeValue <EntityReference>("createdby").Id, new ColumnSet("domainname"));
                                avatarUrl = await GetAvatarUrlAsync(userTeamsDetails.TenantId, sender.GetAttributeValue <string>("domainname"), postComment.GetAttributeValue <EntityReference>("createdby").Name);
                            }

                            // Create or get existing chat conversation with user
                            var parameters = new ConversationParameters
                            {
                                Bot         = new ChannelAccount("28:" + _config.GetValue <string>("MicrosoftAppId")),
                                Members     = new[] { new ChannelAccount(userTeamsDetails.UserId) },
                                ChannelData = new TeamsChannelData
                                {
                                    Tenant = new TenantInfo(userTeamsDetails.TenantId),
                                },
                            };

                            var response = await client.Conversations.CreateConversationAsync(parameters);

                            // Construct the message to post to conversation
                            var model = new PostNotify
                            {
                                Regarding = entityRef,
                                Post      = post,
                                Comment   = postComment == post ? null : postComment,
                                Links     = GetChain(postComment.Id, userRef.Id, entityRelationships)
                            };

                            EnsureChainDetails(org, model.Links);

                            var newActivity = new Activity
                            {
                                //Text = model.ToString(),
                                Type         = ActivityTypes.Message,
                                Conversation = new ConversationAccount
                                {
                                    Id = response.Id
                                },
                                Attachments = new List <Attachment>
                                {
                                    ToAdaptiveCard(model, avatarUrl)
                                }
                            };

                            // Post the message to chat conversation with user
                            await client.Conversations.SendToConversationAsync(response.Id, new Activity { Type = ActivityTypes.Typing });

                            await Task.Delay(TimeSpan.FromSeconds(2));

                            await client.Conversations.SendToConversationAsync(response.Id, newActivity);

                            // Update the user to record the details of which post should be replied to if the user sends a message back
                            var updatedUser = new User(username)
                            {
                                LastDomainName = DomainName,
                                LastPostId     = post.Id,
                                ETag           = userTeamsDetails.ETag
                            };
                            var update = TableOperation.Merge(updatedUser);

                            try
                            {
                                await table.ExecuteAsync(update);
                            }
                            catch (StorageException ex)
                            {
                                if (ex.RequestInformation.HttpStatusCode != 412)
                                {
                                    throw;
                                }
                            }
                        }
                    }
                }

                return(Ok());
            }
            catch (Exception ex)
            {
                return(Problem(ex.ToString(), statusCode: 500));
            }
        }