/// <summary>
        /// Convert video card to WeChat response message.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains video card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private async Task <IList <IResponseMessageBase> > ProcessVideoCardAsync(IMessageActivity activity, Attachment attachment)
        {
            var messages  = new List <IResponseMessageBase>();
            var videoCard = attachment.ContentAs <VideoCard>();

            var body = videoCard.Subtitle;

            body = AddLine(body, videoCard.Text);
            Video video = null;

            // upload thumbnail image.
            if (!string.IsNullOrEmpty(videoCard.Image?.Url))
            {
                // TODO: WeChat doc have thumb_media_id for video mesasge, but not implemented in current package.
                var reponseList = await MediaContentToWeChatResponse(activity, videoCard.Title, videoCard.Media[0].Url, MediaTypes.Video).ConfigureAwait(false);

                if (reponseList is VideoResponse videoResponse)
                {
                    video = new Video(videoResponse.Video.MediaId, videoCard.Title, body);
                }
            }

            messages.Add(new VideoResponse(activity.From.Id, activity.Recipient.Id, video));
            messages.AddRange(ProcessCardActions(activity, videoCard.Buttons));

            return(messages);
        }
        /// <summary>
        /// Convert audio card as music resposne.
        /// Thumbnail image size limitation is not clear.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains audio card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private async Task <IList <IResponseMessageBase> > ProcessAudioCardAsync(IMessageActivity activity, Attachment attachment)
        {
            var messages  = new List <IResponseMessageBase>();
            var audioCard = attachment.ContentAs <AudioCard>();

            var body = audioCard.Subtitle;

            body = AddLine(body, audioCard.Text);
            var music = new Music
            {
                Title       = audioCard.Title,
                MusicUrl    = audioCard.Media[0].Url,
                HQMusicUrl  = audioCard.Media[0].Url,
                Description = body,
            };

            // upload thumbnail image.
            if (!string.IsNullOrEmpty(audioCard.Image?.Url))
            {
                var reponseList = await MediaContentToWeChatResponse(activity, audioCard.Image.Alt, audioCard.Image.Url, MediaTypes.Image).ConfigureAwait(false);

                if (reponseList is ImageResponse imageResponse)
                {
                    music.ThumbMediaId = imageResponse.Image.MediaId;
                }
            }

            var musicResponse = new MusicResponse(activity.From.Id, activity.Recipient.Id, music);

            messages.Add(musicResponse);
            messages.AddRange(ProcessCardActions(activity, audioCard.Buttons));

            return(messages);
        }
        /// <summary>
        /// Process adaptive card and convert it into WeChat response messages.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains adaptive card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private async Task <IList <IResponseMessageBase> > ProcessAdaptiveCardAsync(IMessageActivity activity, Attachment attachment)
        {
            var messages     = new List <IResponseMessageBase>();
            var adaptiveCard = attachment.ContentAs <AdaptiveCard>();

            try
            {
                var news = await CreateNewsFromAdaptiveCard(activity, adaptiveCard, attachment.Name).ConfigureAwait(false);

                // TODO: Upload news image must be persistent media.
                var uploadResult = await _wechatClient.UploadNewsAsync(new News[] { news }, false).ConfigureAwait(false);

                var mpnews = new MPNewsResponse(activity.From.Id, activity.Recipient.Id, uploadResult.MediaId);
                messages.Add(mpnews);
            }
#pragma warning disable CA1031 // Do not catch general exception types, use fallback text instead.
            catch
#pragma warning disable CA1031 // Do not catch general exception types, use fallback text instead.
            {
                _logger.LogInformation("Convert adaptive card failed.");
                messages.AddRange(GetFixedMessages(activity, adaptiveCard.FallbackText));
            }

            return(messages);
        }
        /// <summary>
        /// Downgrade ReceiptCard into text replies for low-fi channels.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains animation card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private static IList <IResponseMessageBase> ProcessReceiptCard(IMessageActivity activity, Attachment attachment)
        {
            var messages    = new List <IResponseMessageBase>();
            var receiptCard = attachment.ContentAs <ReceiptCard>();

            // Build text portion of receipt
            var body = receiptCard.Title;

            foreach (var fact in receiptCard.Facts ?? new List <Fact>())
            {
                body = AddLine(body, $"{fact.Key}:  {fact.Value}");
            }

            // Add items, grouping text only ones into a single post
            foreach (var item in receiptCard.Items ?? new List <ReceiptItem>())
            {
                body = AddLine(body, $"{item.Title}: {item.Price}");
                body = AddLine(body, item.Subtitle);
                body = AddLine(body, item.Text);
            }

            // Add totals
            body = AddLine(body, $"Tax:  {receiptCard.Tax}");
            body = AddLine(body, $"Total:  {receiptCard.Total}");
            messages.AddRange(GetFixedMessages(activity, body));
            messages.AddRange(ProcessCardActions(activity, receiptCard.Buttons));

            return(messages);
        }
        /// <summary>
        /// Process animation card and convert it to WeChat response messages.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains animation card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private async Task <IList <IResponseMessageBase> > ProcessAnimationCardAsync(IMessageActivity activity, Attachment attachment)
        {
            var messages      = new List <IResponseMessageBase>();
            var animationCard = attachment.ContentAs <AnimationCard>();

            // Add text body
            var body = animationCard.Title;

            body = AddLine(body, animationCard.Subtitle);
            body = AddLine(body, animationCard.Text);
            messages.AddRange(GetFixedMessages(activity, body));

            // Add image
            if (!string.IsNullOrEmpty(animationCard.Image?.Url))
            {
                messages.Add(await MediaContentToWeChatResponse(activity, animationCard.Image.Alt, animationCard.Image.Url, MediaTypes.Image).ConfigureAwait(false));
            }

            // Add mediaUrls
            foreach (var mediaUrl in animationCard.Media ?? new List <MediaUrl>())
            {
                messages.Add(await MediaContentToWeChatResponse(activity, mediaUrl.Profile, mediaUrl.Url, MediaTypes.Image).ConfigureAwait(false));
            }

            // Add buttons
            messages.AddRange(ProcessCardActions(activity, animationCard.Buttons));

            return(messages);
        }
        /// <summary>
        /// Process thumbnail card and return the WeChat response message.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains animation card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private static IList <IResponseMessageBase> ProcessThumbnailCard(IMessageActivity activity, Attachment attachment)
        {
            var messages      = new List <IResponseMessageBase>();
            var thumbnailCard = attachment.ContentAs <ThumbnailCard>();

            // Add text
            var body = thumbnailCard.Subtitle;

            body = AddLine(body, thumbnailCard.Text);
            var article = new Article
            {
                Title       = thumbnailCard.Title,
                Description = body,
                Url         = thumbnailCard.Tap?.Value.ToString(),
                PicUrl      = thumbnailCard.Images.FirstOrDefault().Url,
            };
            var newsResponse = new NewsResponse(activity.From.Id, activity.Recipient.Id, new List <Article>()
            {
                article
            });

            messages.Add(newsResponse);
            messages.AddRange(ProcessCardActions(activity, thumbnailCard.Buttons));

            return(messages);
        }
        /// <summary>
        /// Downgrade OAuthCard into text replies for low-fi channels.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains animation card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private static List <IResponseMessageBase> ProcessOAuthCard(IMessageActivity activity, Attachment attachment)
        {
            var messages  = new List <IResponseMessageBase>();
            var oauthCard = attachment.ContentAs <OAuthCard>();

            // Add text
            messages.AddRange(GetFixedMessages(activity, oauthCard.Text));
            messages.AddRange(ProcessCardActions(activity, oauthCard.Buttons));
            return(messages);
        }
        /// <summary>
        /// Downgrade SigninCard into text replies for low-fi channels.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains animation card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private static IList <IResponseMessageBase> ProcessSigninCard(IMessageActivity activity, Attachment attachment)
        {
            var messages   = new List <IResponseMessageBase>();
            var signinCard = attachment.ContentAs <SigninCard>();

            messages.AddRange(GetFixedMessages(activity, signinCard.Text));
            messages.AddRange(ProcessCardActions(activity, signinCard.Buttons));

            return(messages);
        }
 /// <summary>
 /// Convert the attachment Content to the type T or throw a ValidationException if that is not possible.
 /// </summary>
 /// <remarks>
 /// If this method is called then the Attachment.ContentType is assumed to be a well-known type. If conversion fails, for any reason, then we want to let the
 /// developer know there is an issue by throwing a ValidationException. If the type is not a well-known type then this method will not be called and the attachment
 /// will not be converted (it will be ignored).
 /// </remarks>
 public static void Convert <T>(Attachment attachment)
 {
     try
     {
         attachment.Content = attachment.ContentAs <T>();
     }
     catch (Exception ex)
     {
         throw new ValidationException($"Failed to convert Attachment with ContentType {attachment?.ContentType} to {typeof(T).Name}", ex);
     }
 }
        /// <summary>
        /// Convert hero card to WeChat response message.
        /// </summary>
        /// <param name="activity">Message activity from bot.</param>
        /// <param name="attachment">An <see cref="Attachment"/> contains hero card content.</param>
        /// <returns>List of WeChat response message.</returns>
        private async Task <IList <IResponseMessageBase> > ProcessHeroCardAsync(IMessageActivity activity, Attachment attachment)
        {
            var messages = new List <IResponseMessageBase>();
            var heroCard = attachment.ContentAs <HeroCard>();
            var news     = await CreateNewsFromHeroCard(activity, heroCard).ConfigureAwait(false);

            var uploadResult = await _wechatClient.UploadNewsAsync(new News[] { news }, _uploadTemporaryMedia).ConfigureAwait(false);

            var mpnews = new MPNewsResponse(activity.From.Id, activity.Recipient.Id, uploadResult.MediaId);

            messages.Add(mpnews);
            messages.AddRange(ProcessCardActions(activity, heroCard.Buttons));

            return(messages);
        }
Exemple #11
0
 private static void Convert <T>(Attachment attachment)
 {
     // Alexa-skills-dotnet has a custom JsonConverter that converts ICards and IDirective to their correct type so we don't need to do that.
     // However, it throws in two main cases:
     //  1) [JsonException] When the json fails to deserialize due to various reasons. In this case we want to throw a validation exception to
     //     let the bot developer know something is wrong.
     //  2) [Exception] When it doesn't recognize the type. In this case we want to leave the attachment unconverted - we ignore it.
     //
     //  See: https://github.com/timheuer/alexa-skills-dotnet/blob/master/Alexa.NET/Response/Converters/CardConverter.cs
     //       https://github.com/timheuer/alexa-skills-dotnet/blob/master/Alexa.NET/Response/Converters/DirectiveConverter.cs
     try
     {
         attachment.Content = attachment.ContentAs <T>();
     }
     catch (JsonException ex)
     {
         throw new ValidationException($"Failed to convert Alexa Attachment with ContentType {attachment?.ContentType} to {typeof(T).Name}", ex);
     }
     catch
     {
     }
 }