From d5cad54e7e7b5d7e95c700382feb653807d5c5fe Mon Sep 17 00:00:00 2001 From: pierre3 Date: Sat, 4 Nov 2017 11:58:47 +0900 Subject: [PATCH] Supports the rich menu api --- FunctionAppSample/HttpTriggerFunction.cs | 19 +- .../LineBotFunctionSample - Web Deploy.pubxml | 2 +- .../{ => Models}/EventSourceLocation.cs | 0 .../Models}/EventSourceState.cs | 0 .../Samples/RichMenuSampleApp.cs | 68 +++-- FunctionAppSample2/.gitignore | 264 ++++++++++++++++++ FunctionAppSample2/FunctionAppSample2.csproj | 20 ++ FunctionAppSample2/host.json | 2 + Line.Messaging/Line.Messaging.csproj | 11 +- Line.Messaging/LineMessagingClient.cs | 28 +- .../Messages/RichMenu/ActionArea.cs | 31 ++ Line.Messaging/Messages/RichMenu/RichMenu.cs | 16 +- .../Template/DateTimePickerTemplateAction.cs | 32 ++- .../Template/MessageTemplateAction.cs | 5 + .../Template/PostbackTemplateAction.cs | 5 + .../Messages/Template/UriTemplateAction.cs | 5 + LineMessagingApi.sln | 2 +- 17 files changed, 459 insertions(+), 51 deletions(-) rename FunctionAppSample/Samples/{ => Models}/EventSourceLocation.cs (100%) rename FunctionAppSample/{CloudStorage => Samples/Models}/EventSourceState.cs (100%) create mode 100644 FunctionAppSample2/.gitignore create mode 100644 FunctionAppSample2/FunctionAppSample2.csproj create mode 100644 FunctionAppSample2/host.json diff --git a/FunctionAppSample/HttpTriggerFunction.cs b/FunctionAppSample/HttpTriggerFunction.cs index 8c8f576..8af8922 100644 --- a/FunctionAppSample/HttpTriggerFunction.cs +++ b/FunctionAppSample/HttpTriggerFunction.cs @@ -4,7 +4,6 @@ using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Azure.WebJobs.Host; using System; -using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; @@ -30,17 +29,16 @@ public static async Task Run([HttpTrigger(AuthorizationLeve var channelSecret = System.Configuration.ConfigurationManager.AppSettings["ChannelSecret"]; var events = await req.GetWebhookEventsAsync(channelSecret); - //var connectionString = System.Configuration.ConfigurationManager.AppSettings["AzureWebJobsStorage"]; - //var eventSourceState = await TableStorage.CreateAsync(connectionString, "eventsourcestate"); - //var blobStorage = await BlobStorage.CreateAsync(connectionString, "linebotcontainer"); - //var app = new LineBotApp(lineMessagingClient, eventSourceState, blobStorage, log); + var connectionString = System.Configuration.ConfigurationManager.AppSettings["AzureWebJobsStorage"]; + var eventSourceState = await TableStorage.CreateAsync(connectionString, "eventsourcestate"); + var blobStorage = await BlobStorage.CreateAsync(connectionString, "linebotcontainer"); + var app = new LineBotApp(lineMessagingClient, eventSourceState, blobStorage, log); + //Samples app //var app = new DateTimePickerSampleApp(lineMessagingClient, log); //var app = new ImagemapSampleApp(lineMessagingClient, blobStorage, log); //var app = new ImageCarouselSampleApp(lineMessagingClient, blobStorage, log); - - var app = new RichMenuSampleApp(lineMessagingClient, log); - + //var app = new RichMenuSampleApp(lineMessagingClient, log); //var eventSourceLocation = await TableStorage.CreateAsync(connectionString, "eventsourcelocation"); //var app = new PostbackMessageSampleApp(lineMessagingClient, eventSourceLocation, log); @@ -63,6 +61,11 @@ public static async Task Run([HttpTrigger(AuthorizationLeve catch (Exception e) { log.Error(e.ToString()); + var debugUserId = System.Configuration.ConfigurationManager.AppSettings["DebugUser"]; + if (debugUserId != null) + { + await lineMessagingClient.PushMessageAsync(debugUserId, e.Message); + } } return req.CreateResponse(HttpStatusCode.OK); diff --git a/FunctionAppSample/Properties/PublishProfiles/LineBotFunctionSample - Web Deploy.pubxml b/FunctionAppSample/Properties/PublishProfiles/LineBotFunctionSample - Web Deploy.pubxml index 7702e25..838f852 100644 --- a/FunctionAppSample/Properties/PublishProfiles/LineBotFunctionSample - Web Deploy.pubxml +++ b/FunctionAppSample/Properties/PublishProfiles/LineBotFunctionSample - Web Deploy.pubxml @@ -7,7 +7,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt MSDeploy AzureWebSite - Debug + Release Any CPU http://linebotfunctionsample.azurewebsites.net False diff --git a/FunctionAppSample/Samples/EventSourceLocation.cs b/FunctionAppSample/Samples/Models/EventSourceLocation.cs similarity index 100% rename from FunctionAppSample/Samples/EventSourceLocation.cs rename to FunctionAppSample/Samples/Models/EventSourceLocation.cs diff --git a/FunctionAppSample/CloudStorage/EventSourceState.cs b/FunctionAppSample/Samples/Models/EventSourceState.cs similarity index 100% rename from FunctionAppSample/CloudStorage/EventSourceState.cs rename to FunctionAppSample/Samples/Models/EventSourceState.cs diff --git a/FunctionAppSample/Samples/RichMenuSampleApp.cs b/FunctionAppSample/Samples/RichMenuSampleApp.cs index 6a27716..ee35cc4 100644 --- a/FunctionAppSample/Samples/RichMenuSampleApp.cs +++ b/FunctionAppSample/Samples/RichMenuSampleApp.cs @@ -17,6 +17,7 @@ class RichMenuSampleApp : WebhookApplication private TraceWriter Log { get; } + #region RichMenu definitions private static readonly ImagemapSize _richMenuSize = ImagemapSize.RichMenuShort; private static readonly int _buttonWidth = _richMenuSize.Width / 4; private static readonly int _buttonHeight = _richMenuSize.Height; @@ -26,31 +27,29 @@ class RichMenuSampleApp : WebhookApplication private static readonly string MenuNameC = "RichMenuC"; private static readonly string MenuNameD = "RichMenuD"; - private static readonly IList _menuActionAreas = new[] { new ActionArea() { Bounds = new ImagemapArea(_buttonWidth * 0, 0, _buttonWidth, _buttonHeight), - Action = new PostbackTemplateAction("ButtonA", MenuNameA, "Change To Menu A") + Action = new PostbackTemplateAction("ButtonA", MenuNameA, "Menu A") }, new ActionArea() { Bounds = new ImagemapArea(_buttonWidth * 1, 0, _buttonWidth, _buttonHeight), - Action = new PostbackTemplateAction("ButtonB", MenuNameB, "Change To Menu B") + Action = new PostbackTemplateAction("ButtonB", MenuNameB, "Menu B") }, new ActionArea() { Bounds = new ImagemapArea(_buttonWidth * 2, 0, _buttonWidth, _buttonHeight), - Action = new PostbackTemplateAction("ButtonC", MenuNameC, "Change To Menu C") + Action = new PostbackTemplateAction("ButtonC", MenuNameC, "Menu C") }, new ActionArea() { Bounds = new ImagemapArea(_buttonWidth * 3, 0, _buttonWidth, _buttonHeight), - Action = new PostbackTemplateAction("ButtonD", MenuNameD, "Change To Menu D") + Action = new PostbackTemplateAction("ButtonD", MenuNameD, "Menu D") }, }; - private List _richMenus = new List(); private static readonly RichMenu RichMenuA = new RichMenu { @@ -84,6 +83,7 @@ class RichMenuSampleApp : WebhookApplication ChatBarText = "Menu D", Areas = _menuActionAreas }; + #endregion public RichMenuSampleApp(LineMessagingClient lineMessagingClient, TraceWriter log) { @@ -91,16 +91,17 @@ public RichMenuSampleApp(LineMessagingClient lineMessagingClient, TraceWriter lo Log = log; } - public async Task CreateRichMenuAsync() + public async Task> CreateRichMenuAsync() { - _richMenus.Clear(); - - var menuList = await MessagingClient.GetRichMenuList(); + var menuList = await MessagingClient.GetRichMenuListAsync(); + //await DeleteRichMenusAsync(menuList); - _richMenus.Add(await RegisterRichMenuAsync(RichMenuA)); - _richMenus.Add(await RegisterRichMenuAsync(RichMenuB)); - _richMenus.Add(await RegisterRichMenuAsync(RichMenuC)); - _richMenus.Add(await RegisterRichMenuAsync(RichMenuD)); + var newMenuList = new List(); + newMenuList.Add(await RegisterRichMenuAsync(RichMenuA)); + newMenuList.Add(await RegisterRichMenuAsync(RichMenuB)); + newMenuList.Add(await RegisterRichMenuAsync(RichMenuC)); + newMenuList.Add(await RegisterRichMenuAsync(RichMenuD)); + return newMenuList; async Task RegisterRichMenuAsync(RichMenu newItem) { @@ -111,12 +112,20 @@ async Task RegisterRichMenuAsync(RichMenu newItem) var image = CreateRichMenuImage(newItem); await UploadRichMenuImageAsync(image, id); item = newItem.ToResponseRichMenu(id); - } return item; } } + private async Task DeleteRichMenusAsync(IList menuList) + { + foreach (var menu in menuList) + { + await MessagingClient.DeleteRichMenuAsync(menu.RichMenuId); + } + menuList.Clear(); + } + private async Task UploadRichMenuImageAsync(Image image, string richMenuId) { using (var stream = new MemoryStream()) @@ -133,6 +142,7 @@ private Image CreateRichMenuImage(RichMenu menu) var g = Graphics.FromImage(bitmap); var bkBrush = Brushes.White; + if (menu.Name == RichMenuA.Name) { bkBrush = Brushes.Red; @@ -151,8 +161,8 @@ private Image CreateRichMenuImage(RichMenu menu) } g.FillRectangle(bkBrush, new Rectangle(0, 0, menu.Size.Width, menu.Size.Height)); - using (var pen = new Pen(Color.DarkGray, 6.0f)) - using (var font = new Font(FontFamily.GenericSansSerif, 40)) + using (var pen = new Pen(Color.DarkGray, 10.0f)) + using (var font = new Font(FontFamily.GenericSansSerif, 80)) { foreach (var area in menu.Areas) { @@ -176,16 +186,30 @@ protected override async Task OnMessageAsync(MessageEvent ev) { Log.WriteInfo($"SourceType:{ev.Source.Type}, SourceId:{ev.Source.Id}, MessageType:{ev.Message.Type}"); - await MessagingClient.LinkRichMenuToUserAsync(ev.Source.UserId, _richMenus[0].RichMenuId); - await MessagingClient.ReplyMessageAsync(ev.ReplyToken, "Open the Rich Menu!"); + var textMessage = ev.Message as TextEventMessage; + if (textMessage?.Text?.StartsWith("Menu") ?? false) + { + return; + } + + var memuList = await CreateRichMenuAsync(); + var menuA = memuList.FirstOrDefault(m => m.Name == MenuNameA); + if (menuA == null) { return; } + + await MessagingClient.LinkRichMenuToUserAsync(ev.Source.UserId, menuA.RichMenuId); + await MessagingClient.ReplyMessageAsync(ev.ReplyToken, "Hello Rich Menu!"); } protected override async Task OnPostbackAsync(PostbackEvent ev) { - var nextMenu = _richMenus.FirstOrDefault(menu => menu.Name == ev.Postback.Data); + var menuList = await MessagingClient.GetRichMenuListAsync(); + var nextMenu = menuList.FirstOrDefault(menu => menu.Name == ev.Postback.Data); + if (nextMenu == null) + { + await MessagingClient.ReplyMessageAsync(ev.ReplyToken, $"Error!! {ev.Postback.Data} not found."); + } await MessagingClient.LinkRichMenuToUserAsync(ev.Source.UserId, nextMenu.RichMenuId); - await MessagingClient.ReplyMessageAsync(ev.ReplyToken, $"Change the rich menu to {nextMenu.ChatBarText}"); + await MessagingClient.ReplyMessageAsync(ev.ReplyToken, $"I changed a rich menu to {nextMenu.ChatBarText}"); } - } } diff --git a/FunctionAppSample2/.gitignore b/FunctionAppSample2/.gitignore new file mode 100644 index 0000000..ff5b00c --- /dev/null +++ b/FunctionAppSample2/.gitignore @@ -0,0 +1,264 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Azure Functions localsettings file +local.settings.json + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/FunctionAppSample2/FunctionAppSample2.csproj b/FunctionAppSample2/FunctionAppSample2.csproj new file mode 100644 index 0000000..bbec6af --- /dev/null +++ b/FunctionAppSample2/FunctionAppSample2.csproj @@ -0,0 +1,20 @@ + + + net461 + + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + diff --git a/FunctionAppSample2/host.json b/FunctionAppSample2/host.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/FunctionAppSample2/host.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/Line.Messaging/Line.Messaging.csproj b/Line.Messaging/Line.Messaging.csproj index f2ab68b..f3723c1 100644 --- a/Line.Messaging/Line.Messaging.csproj +++ b/Line.Messaging/Line.Messaging.csproj @@ -6,7 +6,7 @@ Line Messaging API Line Messaging API for .Net - 0.6.0-beta + 0.7.0-beta © 2017 pierre3 https://github.com/pierre3/LineMessagingApi/blob/master/LICENSE true @@ -15,9 +15,12 @@ true https://github.com/pierre3/LineMessagingApi/ git - - Supports the Image Carousel template. - 0.6.0.0 - 0.6.0.0 + - Supports the rich menu api +- Add OAuth methods + - LineMessagingClient.IssueChannelAccessTokenAsync() + - LineMessagingClient.RevokeChannelAccessTokenAsync() + 0.7.0.0 + 0.7.0.0 diff --git a/Line.Messaging/LineMessagingClient.cs b/Line.Messaging/LineMessagingClient.cs index 0e735ec..7175b5e 100644 --- a/Line.Messaging/LineMessagingClient.cs +++ b/Line.Messaging/LineMessagingClient.cs @@ -225,7 +225,7 @@ public async Task GetRichMenuAsync(string richMenuId) public async Task CreateRichMenuAsync(RichMenu richMenu) { - var request = new HttpRequestMessage(HttpMethod.Post, "https://api.line.me/v2/bot/message/reply"); + var request = new HttpRequestMessage(HttpMethod.Post, "https://api.line.me/v2/bot/richmenu"); var content = JsonConvert.SerializeObject(richMenu, _jsonSerializerSettings); request.Content = new StringContent(content, Encoding.UTF8, "application/json"); @@ -276,10 +276,26 @@ public Task UploadRichMenuPngImageAsync(Stream stream, string richMenuId) return UploadRichMenuImageAsync(stream, richMenuId, "image/png"); } - public async Task> GetRichMenuList() + public async Task> GetRichMenuListAsync() { - var json = await GetStringAsync("https://api.line.me/v2/bot/richmenu/list").ConfigureAwait(false); - return JsonConvert.DeserializeObject>(json, _jsonSerializerSettings); + var response = await _client.GetAsync("https://api.line.me/v2/bot/richmenu/list").ConfigureAwait(false); + var menus = new List(); + if (response.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return menus; + } + await response.EnsureSuccessStatusCodeAsync().ConfigureAwait(false); + + var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + + dynamic result = JsonConvert.DeserializeObject(json); + if (result == null) { return menus; } + + foreach (var dynamicObj in result.richmenus) + { + menus.Add(ResponseRichMenu.CreateFrom(dynamicObj)); + } + return menus; } public void Dispose() @@ -297,10 +313,12 @@ private async Task GetStringAsync(string requestUri) private async Task UploadRichMenuImageAsync(Stream stream, string richMenuId, string mediaType) { var request = new HttpRequestMessage(HttpMethod.Post, $"https://api.line.me/v2/bot/richmenu/{richMenuId}/content"); - request.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType); request.Content = new StreamContent(stream); + request.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType); var response = await _client.SendAsync(request).ConfigureAwait(false); await response.EnsureSuccessStatusCodeAsync().ConfigureAwait(false); + + } } diff --git a/Line.Messaging/Messages/RichMenu/ActionArea.cs b/Line.Messaging/Messages/RichMenu/ActionArea.cs index 155a3ff..afb9fa5 100644 --- a/Line.Messaging/Messages/RichMenu/ActionArea.cs +++ b/Line.Messaging/Messages/RichMenu/ActionArea.cs @@ -6,5 +6,36 @@ public class ActionArea { public ImagemapArea Bounds { get; set; } public ITemplateAction Action { get; set; } + + public static ActionArea CreateFrom(dynamic dynamicObj) + { + return new ActionArea() + { + Bounds = new ImagemapArea( + (int)(dynamicObj?.bounds?.x ?? 0), + (int)(dynamicObj?.bounds.y ?? 0), + (int)(dynamicObj?.bounds?.width ?? 0), + (int)(dynamicObj?.bounds?.height ?? 0)), + Action = ParseTemplateAction(dynamicObj?.action) + }; + } + + public static ITemplateAction ParseTemplateAction(dynamic dynamicObj) + { + var type = (TemplateActionType)System.Enum.Parse(typeof(TemplateActionType), (string)dynamicObj?.type); + switch (type) + { + case TemplateActionType.Message: + return MessageTemplateAction.CreateFrom(dynamicObj); + case TemplateActionType.Uri: + return UriTemplateAction.CreateFrom(dynamicObj); + case TemplateActionType.Postback: + return PostbackTemplateAction.CreateFrom(dynamicObj); + case TemplateActionType.Datetimepicker: + return DateTimePickerTemplateAction.CreateFrom(dynamicObj); + default: + return null; + } + } } } diff --git a/Line.Messaging/Messages/RichMenu/RichMenu.cs b/Line.Messaging/Messages/RichMenu/RichMenu.cs index 8237c4a..02f7c66 100644 --- a/Line.Messaging/Messages/RichMenu/RichMenu.cs +++ b/Line.Messaging/Messages/RichMenu/RichMenu.cs @@ -10,7 +10,7 @@ public class RichMenu public string ChatBarText { set; get; } public IList Areas { set; get; } - public ResponseRichMenu ToResponseRichMenu(string richMenuId="") + public ResponseRichMenu ToResponseRichMenu(string richMenuId = "") { return new ResponseRichMenu(richMenuId, this); } @@ -29,6 +29,18 @@ public ResponseRichMenu(string richMenuId, RichMenu source) ChatBarText = source.ChatBarText; Areas = source.Areas; } - + + public static ResponseRichMenu CreateFrom(dynamic dynamicObj) + { + var menu = new RichMenu() + { + Name = (string)dynamicObj?.name, + Size = new ImagemapSize((int)(dynamicObj?.size?.width ?? 0), (int)(dynamicObj?.size?.height ?? 0)), + Selected = (bool)(dynamicObj?.selected ?? false), + ChatBarText = (string)dynamicObj?.chatBarText + }; + return new ResponseRichMenu((string)dynamicObj?.richMenuId, menu); + } + } } diff --git a/Line.Messaging/Messages/Template/DateTimePickerTemplateAction.cs b/Line.Messaging/Messages/Template/DateTimePickerTemplateAction.cs index e0d5d3a..da469e3 100644 --- a/Line.Messaging/Messages/Template/DateTimePickerTemplateAction.cs +++ b/Line.Messaging/Messages/Template/DateTimePickerTemplateAction.cs @@ -24,6 +24,22 @@ public DateTimePickerTemplateAction(string label, string data, DateTimePickerMod } public DateTimePickerTemplateAction(string label, string data, DateTimePickerMode mode, DateTime initial, DateTime min, DateTime max) + { + var format = GetDateTimeFormat(mode); + Initialize(label, data, mode, initial.ToString(format), min.ToString(format), max.ToString(format)); + } + + protected void Initialize(string label, string data, DateTimePickerMode mode, string initial, string min, string max) + { + Label = label; + Data = data; + Mode = mode; + Initial = initial; + Min = min; + Max = max; + } + + protected static string GetDateTimeFormat(DateTimePickerMode mode) { var format = ""; switch (mode) @@ -38,17 +54,17 @@ public DateTimePickerTemplateAction(string label, string data, DateTimePickerMod format = "yyyy-MM-ddTHH:mm"; break; } - Initialize(label, data, mode, initial.ToString(format), min.ToString(format), max.ToString(format)); + return format; } - protected void Initialize(string label, string data, DateTimePickerMode mode, string initial, string min, string max) + public static DateTimePickerTemplateAction CreateFrom(dynamic dynamicObj) { - Label = label; - Data = data; - Mode = mode; - Initial = initial; - Min = min; - Max = max; + var mode = (DateTimePickerMode)Enum.Parse(typeof(DateTimePickerMode), dynamicObj?.mode); + var format = GetDateTimeFormat(mode); + var initial = DateTime.ParseExact(dynamicObj?.initial, format, null); + var min = DateTime.ParseExact(dynamicObj?.min, format, null); + var max = DateTime.ParseExact(dynamicObj?.max, format, null); + return new DateTimePickerTemplateAction((string)dynamicObj?.label, (string)dynamicObj?.data, mode, initial, min, max); } } } diff --git a/Line.Messaging/Messages/Template/MessageTemplateAction.cs b/Line.Messaging/Messages/Template/MessageTemplateAction.cs index f9e1913..06ba0e3 100644 --- a/Line.Messaging/Messages/Template/MessageTemplateAction.cs +++ b/Line.Messaging/Messages/Template/MessageTemplateAction.cs @@ -13,5 +13,10 @@ public MessageTemplateAction(string label,string text) Label = label; Text = text; } + + public static MessageTemplateAction CreateFrom(dynamic dynamicObj) + { + return new MessageTemplateAction((string)dynamicObj?.label, (string)dynamicObj?.text); + } } } diff --git a/Line.Messaging/Messages/Template/PostbackTemplateAction.cs b/Line.Messaging/Messages/Template/PostbackTemplateAction.cs index 15b5630..4d2931a 100644 --- a/Line.Messaging/Messages/Template/PostbackTemplateAction.cs +++ b/Line.Messaging/Messages/Template/PostbackTemplateAction.cs @@ -16,5 +16,10 @@ public PostbackTemplateAction(string label,string data,string text) Label = label; Text = text; } + + public static PostbackTemplateAction CreateFrom(dynamic dynamicObj) + { + return new PostbackTemplateAction((string)dynamicObj?.label, (string)dynamicObj?.data, (string)dynamicObj?.text); + } } } diff --git a/Line.Messaging/Messages/Template/UriTemplateAction.cs b/Line.Messaging/Messages/Template/UriTemplateAction.cs index 3f377f5..c2f4524 100644 --- a/Line.Messaging/Messages/Template/UriTemplateAction.cs +++ b/Line.Messaging/Messages/Template/UriTemplateAction.cs @@ -13,5 +13,10 @@ public UriTemplateAction(string label, string uri) Label = label; Uri = uri; } + + public static UriTemplateAction CreateFrom(dynamic dynamicObj) + { + return new UriTemplateAction((string)dynamicObj?.label, (string)dynamicObj?.uri); + } } } diff --git a/LineMessagingApi.sln b/LineMessagingApi.sln index 2195fdd..bb67c8a 100644 --- a/LineMessagingApi.sln +++ b/LineMessagingApi.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.3 +VisualStudioVersion = 15.0.27004.2006 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionAppSample", "FunctionAppSample\FunctionAppSample.csproj", "{D98AD580-F55C-47FC-A753-C67456306F89}" EndProject