/// <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); }
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 { } }