├── .gitattributes ├── .gitignore ├── FunctionAppSample.v2 ├── CloudStorage │ ├── BlobStorage.cs │ └── TableStorage.cs ├── Images │ ├── GitHubIcon │ │ ├── 240 │ │ ├── 300 │ │ ├── 460 │ │ ├── 700 │ │ ├── 1040 │ │ ├── 1040.png │ │ ├── 240.png │ │ ├── 300.png │ │ ├── 460.png │ │ └── 700.png │ └── richmenu.PNG ├── LINEBOT.csproj ├── LINEBOT │ ├── LineBotApp.cs │ ├── function.json │ └── run.cs ├── Models │ ├── EventSourceLocation.cs │ └── EventSourceState.cs ├── README.md ├── README_JP.md ├── Services │ └── TraceWriterExtension.cs ├── host.json └── local.settings.json ├── FunctionAppSample ├── .gitignore ├── CloudStorage │ ├── BlobStorage.cs │ └── TableStorage.cs ├── FunctionAppSample.csproj ├── HttpTriggerFunction.cs ├── LineBotApp.cs ├── Properties │ ├── PublishProfiles │ │ └── LineBotFunctionSample - Web Deploy.pubxml │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ └── sample_image.jpg ├── Samples │ ├── AppSwitcher.cs │ ├── ButtonsTemplateSampleApp.cs │ ├── CarouselTemplateSampleApp.cs │ ├── DateTimePickerSampleApp.cs │ ├── FlexMessageSampleApp.cs │ ├── GetNumberOfSentMessagesSampleApp.cs │ ├── ImageCarouselSampleApp.cs │ ├── ImagemapSampleApp.cs │ ├── Models │ │ ├── BotStatus.cs │ │ └── EventSourceState.cs │ ├── PostbackMessageSampleApp.cs │ └── RichMenuSampleApp.cs ├── TraceWriterExtensions.cs └── host.json ├── ImagesForREADME ├── AttachToFunction.PNG ├── ExtensionSearch.PNG ├── ExtensionSearch_ja.PNG ├── FunctionAppSettings.PNG ├── FunctionAppSettings_ja.PNG ├── FunctionUrl.PNG ├── FunctionUrl_ja.PNG ├── LINEBotTemplates.PNG ├── LINEBotTemplates_ja.PNG ├── LINEWebhookUrl.PNG ├── RuntimeVersion.PNG ├── RuntimeVersion_ja.PNG ├── SetWebAppStartUpProject.PNG ├── SetWebAppStartUpProject_JA.PNG └── ngrok.PNG ├── LICENSE ├── LiffManager ├── App.config ├── App.xaml ├── App.xaml.cs ├── LiffManager.csproj ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MainWindowViewModel.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── packages.config ├── Line.Messaging ├── ContentStream.cs ├── Exceptions │ ├── ErrorResponseMessage.cs │ ├── InvalidSignatureException.cs │ ├── LineResponseException.cs │ └── UserIdMismatchException.cs ├── HttpResponseMessageExtensions.cs ├── ILineMessagingClient.cs ├── Json │ ├── CamelCaseJsonSerializerSettings.cs │ ├── CustomStringEnumConverter.cs │ └── ToStringJsonConverter.cs ├── Liff │ ├── LiffApp.cs │ ├── LiffClient.cs │ ├── View.cs │ └── ViewType.cs ├── Line.Messaging.csproj ├── LineMessagingClient.cs ├── LineObjects │ ├── ChannelAccessToken.cs │ ├── ImagemapSize.cs │ ├── MemberIds.cs │ ├── NumberOfMessages.cs │ ├── NumberOfSentMessagesStatus.cs │ └── UserProfile.cs ├── LineSchemeUrl.cs ├── Messages │ ├── Action │ │ ├── CameraRollTemplateAction.cs │ │ ├── CameraTemplateAction.cs │ │ ├── DateTimePickerMode.cs │ │ ├── DateTimePickerTemplateAction.cs │ │ ├── LocationTemplateAction.cs │ │ ├── MessageTemplateAction.cs │ │ ├── PostbackTemplateAction.cs │ │ ├── TemplateActionType.cs │ │ └── UriTemplateAction.cs │ ├── AudioMessage.cs │ ├── Flex │ │ ├── BubbleContainer.cs │ │ ├── CarouselContainer.cs │ │ ├── Component │ │ │ ├── BoxComponent.cs │ │ │ ├── ButtonComponent.cs │ │ │ ├── FillerComponent.cs │ │ │ ├── FlexComponentType.cs │ │ │ ├── IFlexComponent.cs │ │ │ ├── IconComponent.cs │ │ │ ├── ImageComponent.cs │ │ │ ├── SeparatorComponent.cs │ │ │ ├── SpacerComponent.cs │ │ │ └── TextComponent.cs │ │ ├── Extensions │ │ │ ├── BoxComponentEntensions.cs │ │ │ ├── BubbleContainerEntensions.cs │ │ │ ├── BubbleContainerFlexMessages.cs │ │ │ └── CarouselContainerFlexMessges.cs │ │ ├── IFlexContainer.cs │ │ ├── ParameterTypes │ │ │ ├── Align.cs │ │ │ ├── AltUri.cs │ │ │ ├── AspectMode.cs │ │ │ ├── AspectRatio.cs │ │ │ ├── BoxLayout.cs │ │ │ ├── ButtonHeight.cs │ │ │ ├── ButtonStyle.cs │ │ │ ├── ColorCode.cs │ │ │ ├── ComponentDirection.cs │ │ │ ├── ComponentSize.cs │ │ │ ├── FlexContainerType.cs │ │ │ ├── Gravity.cs │ │ │ ├── Spacing.cs │ │ │ └── Weight.cs │ │ └── Style │ │ │ ├── BoxStyle.cs │ │ │ └── BubbleStyles.cs │ ├── FlexMessage.cs │ ├── ISendMessage.cs │ ├── ImageMessage.cs │ ├── Imagemap │ │ ├── ExternalLink.cs │ │ ├── IImagemapAction.cs │ │ ├── ImagemapActionType.cs │ │ ├── ImagemapArea.cs │ │ ├── MessageImagemapAction.cs │ │ ├── UriImagemapAction.cs │ │ └── Video.cs │ ├── ImagemapMessage.cs │ ├── LocationMessage.cs │ ├── MessageType.cs │ ├── QuickReply │ │ ├── QuickItem.cs │ │ └── QuickReply.cs │ ├── RichMenu │ │ ├── ActionArea.cs │ │ ├── ResponseRichMenu.cs │ │ └── RichMenu.cs │ ├── StickerMessage.cs │ ├── Template │ │ ├── ButtonsTemplate.cs │ │ ├── CarouselColumn.cs │ │ ├── CarouselTemplate.cs │ │ ├── ConfirmTemplate.cs │ │ ├── ITemplate.cs │ │ ├── ITemplateAction.cs │ │ ├── ImageAspectRatioType.cs │ │ ├── ImageCarouselColumn.cs │ │ ├── ImageCarouselTemplate.cs │ │ ├── ImageSizeType.cs │ │ └── TemplateType.cs │ ├── TemplateMessage.cs │ ├── TextMessage.cs │ └── VideoMessage.cs └── Webhooks │ ├── AccountLinkEvent.cs │ ├── Beacon.cs │ ├── BeaconEvent.cs │ ├── BeaconType.cs │ ├── ContentProvider.cs │ ├── ContentProviderType.cs │ ├── DeviceEvent.cs │ ├── DeviceLinkEvent.cs │ ├── DeviceUnLinkEvent.cs │ ├── EventMessage.cs │ ├── EventMessageType.cs │ ├── EventSourceType.cs │ ├── FileEventMessage.cs │ ├── FollowEvent.cs │ ├── JoinEvent.cs │ ├── LeaveEvent.cs │ ├── Link.cs │ ├── LinkResult.cs │ ├── LocationEventMessage.cs │ ├── MemberJoinEvent.cs │ ├── MemberLeaveEvent.cs │ ├── MessageEvent.cs │ ├── MidiaEventMessage.cs │ ├── Moved.cs │ ├── Postback.cs │ ├── PostbackEvent.cs │ ├── PostbackParams.cs │ ├── ReplyableEvent.cs │ ├── StickerEventMessage.cs │ ├── TextEventMessage.cs │ ├── Things.cs │ ├── ThingsType.cs │ ├── UnfollowEvent.cs │ ├── WebhookApplication.cs │ ├── WebhookEvent.cs │ ├── WebhookEventParser.cs │ ├── WebhookEventSource.cs │ ├── WebhookEventType.cs │ └── WebhookRequestMessageHelper.cs ├── Line.MessagingTest ├── CustomStringEnumConverterTest.cs ├── FlexObjectSerializeTest.cs ├── Line.MessagingTest.csproj ├── Properties │ └── AssemblyInfo.cs ├── WebhookEventParserTest.cs └── packages.config ├── LineMessagingApi.sln ├── ProjectTemplate ├── LICENSE.txt ├── ProjectTemplate.csproj ├── ProjectTemplates │ └── CSharp │ │ └── Cloud │ │ ├── LINEBotApplication.zip │ │ ├── LineBotFunction.zip │ │ └── LineWithBotFrameworkApplication.zip ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── README_JP.md ├── __TemplateIcon.ico ├── index.html ├── ja-JP │ └── Extension.vsixlangpack ├── source.extension.vsixmanifest └── stylesheet.css ├── README.md ├── README_JP.md ├── WebAppSample ├── App_Start │ └── WebApiConfig.cs ├── CloudStorage │ ├── BlobStorage.cs │ └── TableStorage.cs ├── Controllers │ ├── ImagesController.cs │ └── LineBotController.cs ├── Global.asax ├── Global.asax.cs ├── Images │ ├── GitHubIcon │ │ ├── 1040.png │ │ ├── 240.png │ │ ├── 300.png │ │ ├── 460.png │ │ └── 700.png │ └── richmenu.PNG ├── LineBotApp.cs ├── Models │ ├── EventSourceLocation.cs │ └── EventSourceState.cs ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── README_JP.md ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── WebAppSample.csproj └── packages.config ├── WebAppWithBotFrameworkSample ├── App_Start │ └── WebApiConfig.cs ├── CloudStorage │ ├── BlobStorage.cs │ └── TableStorage.cs ├── Controllers │ └── LineBotController.cs ├── Global.asax ├── Global.asax.cs ├── LineBotApp.cs ├── Models │ ├── EventSourceLocation.cs │ └── EventSourceState.cs ├── Properties │ └── AssemblyInfo.cs ├── README.md ├── README_JP.md ├── Services │ └── CacheService.cs ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── WebAppWithBotFrameworkSample.csproj └── packages.config └── ter /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /FunctionAppSample.v2/CloudStorage/BlobStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Blob; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace FunctionAppSample 10 | { 11 | public class BlobStorage 12 | { 13 | private CloudBlobClient _blobClient; 14 | private CloudBlobContainer _blobContainer; 15 | 16 | public BlobStorage(string connectionString) 17 | { 18 | var strageAccount = CloudStorageAccount.Parse(connectionString); 19 | _blobClient = strageAccount.CreateCloudBlobClient(); 20 | } 21 | 22 | public static async Task CreateAsync(string connectionString, string containerName) 23 | { 24 | var instance = new BlobStorage(connectionString); 25 | await instance.InitializeAsync(containerName); 26 | return instance; 27 | } 28 | 29 | public async Task InitializeAsync(string containerName) 30 | { 31 | _blobContainer = _blobClient.GetContainerReference(containerName); 32 | await _blobContainer.CreateIfNotExistsAsync(); 33 | await _blobContainer.SetPermissionsAsync( 34 | new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }); 35 | } 36 | 37 | public async Task UploadFromStreamAsync(Stream stream, string directoryName, string blobName) 38 | { 39 | var directory = _blobContainer.GetDirectoryReference(directoryName); 40 | var blob = directory.GetBlockBlobReference(blobName); 41 | await blob.UploadFromStreamAsync(stream); 42 | return blob.Uri; 43 | } 44 | 45 | public async Task DeleteImageAsync(string directoryName, string blobName) 46 | { 47 | var directory = _blobContainer.GetDirectoryReference(directoryName); 48 | var blob = directory.GetBlockBlobReference(blobName); 49 | await blob.DeleteIfExistsAsync(); 50 | } 51 | 52 | public async Task DeleteDirectoryAsync(string directoryName) 53 | { 54 | var directory = _blobContainer.GetDirectoryReference(directoryName); 55 | foreach (CloudBlob blob in (await directory.ListBlobsSegmentedAsync(new BlobContinuationToken())).Results) 56 | { 57 | await blob.DeleteIfExistsAsync(); 58 | } 59 | } 60 | 61 | public async Task> ListBlobUri(string directoryName) 62 | { 63 | var directory = _blobContainer.GetDirectoryReference(directoryName); 64 | return (await directory.ListBlobsSegmentedAsync(new BlobContinuationToken())).Results.Select(blob => blob.Uri); 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /FunctionAppSample.v2/CloudStorage/TableStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Table; 3 | using System.Threading.Tasks; 4 | 5 | namespace FunctionAppSample 6 | { 7 | 8 | public class TableStorage where T : TableEntity, new() 9 | { 10 | private CloudTableClient _tableClient; 11 | private CloudTable _table; 12 | 13 | protected TableStorage(string connectionString) 14 | { 15 | var strageAccount = CloudStorageAccount.Parse(connectionString); 16 | _tableClient = strageAccount.CreateCloudTableClient(); 17 | } 18 | 19 | protected async Task InitializeAsync(string tableName) 20 | { 21 | _table = _tableClient.GetTableReference(tableName); 22 | await _table.CreateIfNotExistsAsync(); 23 | } 24 | 25 | public static async Task> CreateAsync(string connectionString,string tableName) 26 | { 27 | var result = new TableStorage(connectionString); 28 | await result.InitializeAsync(tableName); 29 | return result; 30 | } 31 | 32 | public async Task AddAsync(string partitionKey, string rowKey) 33 | { 34 | if ((await FindAsync(partitionKey, rowKey)) != null) { return; } 35 | 36 | var newItem = new T() { PartitionKey = partitionKey, RowKey = rowKey }; 37 | await _table.ExecuteAsync(TableOperation.Insert(newItem)); 38 | } 39 | 40 | public async Task UpdateAsync(T item) 41 | { 42 | await _table.ExecuteAsync(TableOperation.InsertOrReplace(item)); 43 | } 44 | 45 | public async Task FindAsync(string partitionKey, string rowKey) 46 | { 47 | var ope = TableOperation.Retrieve(partitionKey, rowKey); 48 | var retrieveResult = await _table.ExecuteAsync(ope); 49 | if (retrieveResult.Result == null) { return null; } 50 | return (T)(retrieveResult.Result); 51 | } 52 | 53 | public async Task DeleteAsync(string partitionKey, string rowKey) 54 | { 55 | var item = await FindAsync(partitionKey, rowKey); 56 | if (item == null) { return; } 57 | 58 | var ope = TableOperation.Delete(item); 59 | await _table.ExecuteAsync(ope); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/1040: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/1040 -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/1040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/1040.png -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/240: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/240 -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/240.png -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/300: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/300 -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/300.png -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/460: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/460 -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/460.png -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/700: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/700 -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/GitHubIcon/700.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/GitHubIcon/700.png -------------------------------------------------------------------------------- /FunctionAppSample.v2/Images/richmenu.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample.v2/Images/richmenu.PNG -------------------------------------------------------------------------------- /FunctionAppSample.v2/LINEBOT.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | true 5 | NU1701,NU1702 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | PreserveNewest 30 | 31 | 32 | PreserveNewest 33 | 34 | 35 | PreserveNewest 36 | 37 | 38 | -------------------------------------------------------------------------------- /FunctionAppSample.v2/LINEBOT/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "function", 6 | "name": "req", 7 | "type": "httpTrigger", 8 | "direction": "in" 9 | }, 10 | { 11 | "name": "$return", 12 | "type": "http", 13 | "direction": "out" 14 | } 15 | ], 16 | "scriptFile": "../LINEBOT.dll", 17 | "entryPoint": "FunctionAppSample.HttpTriggerFunction.Run" 18 | } -------------------------------------------------------------------------------- /FunctionAppSample.v2/Models/EventSourceLocation.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace FunctionAppSample 4 | { 5 | public class EventSourceLocation : EventSourceState 6 | { 7 | public string Location { get; set; } 8 | 9 | public EventSourceLocation() { } 10 | } 11 | } -------------------------------------------------------------------------------- /FunctionAppSample.v2/Models/EventSourceState.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace FunctionAppSample 4 | { 5 | public class EventSourceState : TableEntity 6 | { 7 | [IgnoreProperty] 8 | public string SourceType { get => PartitionKey; set => PartitionKey = value; } 9 | [IgnoreProperty] 10 | public string SourceId { get => RowKey; set => RowKey = value; } 11 | 12 | public EventSourceState() { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /FunctionAppSample.v2/Services/TraceWriterExtension.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.WebJobs.Host; 2 | using System; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace FunctionAppSample 6 | { 7 | static class TraceWriterExtensions 8 | { 9 | public static void WriteError(this TraceWriter trace, string message, Exception e = null, [CallerMemberName] string callerName = "") 10 | { 11 | trace.Error($"[{callerName}] {message}", e); 12 | } 13 | 14 | public static void WriteWarning(this TraceWriter trace, string message, [CallerMemberName] string callerName = "") 15 | { 16 | trace.Warning($"[{callerName}] {message}"); 17 | } 18 | 19 | public static void WriteInfo(this TraceWriter trace, string message, [CallerMemberName] string callerName = "") 20 | { 21 | trace.Info($"[{callerName}] {message}"); 22 | } 23 | 24 | public static void WriteVerbose(this TraceWriter trace, string message, [CallerMemberName] string callerName = "") 25 | { 26 | trace.Verbose($"[{callerName}] {message}"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FunctionAppSample.v2/host.json: -------------------------------------------------------------------------------- 1 | { } -------------------------------------------------------------------------------- /FunctionAppSample.v2/local.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "", 5 | "ChannelSecret":"", 6 | "ChannelAccessToken":"" 7 | } 8 | } -------------------------------------------------------------------------------- /FunctionAppSample/CloudStorage/TableStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Table; 3 | using System.Threading.Tasks; 4 | 5 | namespace FunctionAppSample 6 | { 7 | 8 | public class TableStorage where T : TableEntity, new() 9 | { 10 | private CloudTableClient _tableClient; 11 | private CloudTable _table; 12 | 13 | protected TableStorage(string connectionString) 14 | { 15 | var strageAccount = CloudStorageAccount.Parse(connectionString); 16 | _tableClient = strageAccount.CreateCloudTableClient(); 17 | } 18 | 19 | protected async Task InitializeAsync(string tableName) 20 | { 21 | _table = _tableClient.GetTableReference(tableName); 22 | await _table.CreateIfNotExistsAsync(); 23 | } 24 | 25 | public static async Task> CreateAsync(string connectionString,string tableName) 26 | { 27 | var result = new TableStorage(connectionString); 28 | await result.InitializeAsync(tableName); 29 | return result; 30 | } 31 | 32 | public async Task AddAsync(string partitionKey, string rowKey) 33 | { 34 | if ((await FindAsync(partitionKey, rowKey)) != null) { return; } 35 | 36 | var newItem = new T() { PartitionKey = partitionKey, RowKey = rowKey }; 37 | await _table.ExecuteAsync(TableOperation.Insert(newItem)); 38 | } 39 | 40 | public async Task UpdateAsync(T item) 41 | { 42 | await _table.ExecuteAsync(TableOperation.InsertOrReplace(item)); 43 | } 44 | 45 | public async Task FindAsync(string partitionKey, string rowKey) 46 | { 47 | var ope = TableOperation.Retrieve(partitionKey, rowKey); 48 | var retrieveResult = await _table.ExecuteAsync(ope); 49 | if (retrieveResult.Result == null) { return null; } 50 | return (T)(retrieveResult.Result); 51 | } 52 | 53 | public async Task DeleteAsync(string partitionKey, string rowKey) 54 | { 55 | var item = await FindAsync(partitionKey, rowKey); 56 | if (item == null) { return; } 57 | 58 | var ope = TableOperation.Delete(item); 59 | await _table.ExecuteAsync(ope); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /FunctionAppSample/FunctionAppSample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net47 4 | 5 | 6 | bin\debug\ 7 | 1701;1702;1705;NU1608 8 | 9 | 10 | 1701;1702;1705;NU1608 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | PreserveNewest 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | True 37 | True 38 | Resources.resx 39 | 40 | 41 | 42 | 43 | ResXFileCodeGenerator 44 | Resources.Designer.cs 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /FunctionAppSample/Properties/PublishProfiles/LineBotFunctionSample - Web Deploy.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 | $LineBotFunctionSample 9 | MSDeploy 10 | AzureWebSite 11 | Debug 12 | Any CPU 13 | http://linebotfunctionsample.azurewebsites.net 14 | False 15 | False 16 | linebotfunctionsample.scm.azurewebsites.net:443 17 | LineBotFunctionSample 18 | False 19 | WMSVC 20 | True 21 | <_SavePWD>True 22 | False 23 | /subscriptions/68ba8c50-8dba-4c1a-b98d-92ba86087496/resourceGroups/LineBotFunctionApp_rg/providers/Microsoft.Web/sites/LineBotFunctionSample 24 | net47 25 | 26 | -------------------------------------------------------------------------------- /FunctionAppSample/Resources/sample_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/FunctionAppSample/Resources/sample_image.jpg -------------------------------------------------------------------------------- /FunctionAppSample/Samples/DateTimePickerSampleApp.cs: -------------------------------------------------------------------------------- 1 | using Line.Messaging; 2 | using Line.Messaging.Webhooks; 3 | using Microsoft.Azure.WebJobs.Host; 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | namespace FunctionAppSample 8 | { 9 | 10 | class DateTimePickerSampleApp : WebhookApplication 11 | { 12 | private LineMessagingClient MessagingClient { get; } 13 | private TraceWriter Log { get; } 14 | 15 | public DateTimePickerSampleApp(LineMessagingClient lineMessagingClient, TraceWriter log) 16 | { 17 | MessagingClient = lineMessagingClient; 18 | Log = log; 19 | } 20 | 21 | protected override async Task OnMessageAsync(MessageEvent ev) 22 | { 23 | Log.WriteInfo($"SourceType:{ev.Source.Type}, Id:{ev.Source.Id}, MessageType:{ev.Message.Type}"); 24 | 25 | var template = new TemplateMessage("DataTimePickerTest", 26 | new ButtonsTemplate( 27 | text: "DateTimePicker TEST", 28 | thumbnailImageUrl: null, 29 | title: "Select a date or time.", 30 | actions: new[] { 31 | new DateTimePickerTemplateAction("Date","Date", DateTimePickerMode.Date, DateTime.Today, new DateTime(2000,1,1), new DateTime(2020,12,31)), 32 | new DateTimePickerTemplateAction("Time","Time", DateTimePickerMode.Time, DateTime.Now.ToString("HH:mm"), "00:00", "23:59"), 33 | new DateTimePickerTemplateAction("DatetTime","DateTime", DateTimePickerMode.Datetime, DateTime.Now, new DateTime(2000,1,1,0,0,0), new DateTime(2020,12,31,23,59,59)) 34 | })); 35 | await MessagingClient.ReplyMessageAsync(ev.ReplyToken, new[] { template }); 36 | } 37 | 38 | 39 | 40 | protected override async Task OnPostbackAsync(PostbackEvent ev) 41 | { 42 | Log.WriteInfo($"SourceType:{ev.Source.Type}, EntryId:{ev.Source.Id}"); 43 | 44 | switch (ev.Postback.Data) 45 | { 46 | case "Date": 47 | await MessagingClient.ReplyMessageAsync(ev.ReplyToken, "You chose the date: " + ev.Postback.Params.Date); 48 | break; 49 | case "Time": 50 | await MessagingClient.ReplyMessageAsync(ev.ReplyToken, "You chose the time: " + ev.Postback.Params.Time); 51 | break; 52 | case "DateTime": 53 | await MessagingClient.ReplyMessageAsync(ev.ReplyToken, "You chose the date-time: " + ev.Postback.Params.DateTime); 54 | break; 55 | } 56 | 57 | } 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /FunctionAppSample/Samples/Models/BotStatus.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace FunctionAppSample 4 | { 5 | public class BotStatus : EventSourceState 6 | { 7 | public string Location { get; set; } 8 | public string CurrentApp { get; set; } 9 | 10 | public BotStatus() { } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /FunctionAppSample/Samples/Models/EventSourceState.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace FunctionAppSample 4 | { 5 | public class EventSourceState : TableEntity 6 | { 7 | [IgnoreProperty] 8 | public string SourceType { get => PartitionKey; set => PartitionKey = value; } 9 | [IgnoreProperty] 10 | public string SourceId { get => RowKey; set => RowKey = value; } 11 | 12 | public EventSourceState() { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /FunctionAppSample/TraceWriterExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.WebJobs.Host; 2 | using System; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace FunctionAppSample 6 | { 7 | static class TraceWriterExtensions 8 | { 9 | public static void WriteError(this TraceWriter trace, string message, Exception e = null, [CallerMemberName] string callerName = "") 10 | { 11 | trace.Error($"[{callerName}] {message}", e); 12 | } 13 | 14 | public static void WriteWarning(this TraceWriter trace, string message, [CallerMemberName] string callerName = "") 15 | { 16 | trace.Warning($"[{callerName}] {message}"); 17 | } 18 | 19 | public static void WriteInfo(this TraceWriter trace, string message, [CallerMemberName] string callerName = "") 20 | { 21 | trace.Info($"[{callerName}] {message}"); 22 | } 23 | 24 | public static void WriteVerbose(this TraceWriter trace, string message, [CallerMemberName] string callerName = "") 25 | { 26 | trace.Verbose($"[{callerName}] {message}"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /FunctionAppSample/host.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /ImagesForREADME/AttachToFunction.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/AttachToFunction.PNG -------------------------------------------------------------------------------- /ImagesForREADME/ExtensionSearch.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/ExtensionSearch.PNG -------------------------------------------------------------------------------- /ImagesForREADME/ExtensionSearch_ja.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/ExtensionSearch_ja.PNG -------------------------------------------------------------------------------- /ImagesForREADME/FunctionAppSettings.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/FunctionAppSettings.PNG -------------------------------------------------------------------------------- /ImagesForREADME/FunctionAppSettings_ja.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/FunctionAppSettings_ja.PNG -------------------------------------------------------------------------------- /ImagesForREADME/FunctionUrl.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/FunctionUrl.PNG -------------------------------------------------------------------------------- /ImagesForREADME/FunctionUrl_ja.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/FunctionUrl_ja.PNG -------------------------------------------------------------------------------- /ImagesForREADME/LINEBotTemplates.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/LINEBotTemplates.PNG -------------------------------------------------------------------------------- /ImagesForREADME/LINEBotTemplates_ja.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/LINEBotTemplates_ja.PNG -------------------------------------------------------------------------------- /ImagesForREADME/LINEWebhookUrl.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/LINEWebhookUrl.PNG -------------------------------------------------------------------------------- /ImagesForREADME/RuntimeVersion.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/RuntimeVersion.PNG -------------------------------------------------------------------------------- /ImagesForREADME/RuntimeVersion_ja.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/RuntimeVersion_ja.PNG -------------------------------------------------------------------------------- /ImagesForREADME/SetWebAppStartUpProject.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/SetWebAppStartUpProject.PNG -------------------------------------------------------------------------------- /ImagesForREADME/SetWebAppStartUpProject_JA.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/SetWebAppStartUpProject_JA.PNG -------------------------------------------------------------------------------- /ImagesForREADME/ngrok.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ImagesForREADME/ngrok.PNG -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 pierre3 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LiffManager/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LiffManager/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /LiffManager/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace LiffManager 10 | { 11 | /// 12 | /// App.xaml の相互作用ロジック 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LiffManager/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace LiffManager 17 | { 18 | /// 19 | /// MainWindow.xaml の相互作用ロジック 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | private MainWindowViewModel VM { get => DataContext as MainWindowViewModel; } 24 | public MainWindow() 25 | { 26 | InitializeComponent(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LiffManager/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 8 | // アセンブリに関連付けられている情報を変更するには、 9 | // これらの属性値を変更してください。 10 | [assembly: AssemblyTitle("LiffManager")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("LiffManager")] 15 | [assembly: AssemblyCopyright("Copyright © 2018")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから 20 | // 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 21 | // その型の ComVisible 属性を true に設定してください。 22 | [assembly: ComVisible(false)] 23 | 24 | //ローカライズ可能なアプリケーションのビルドを開始するには、 25 | //.csproj ファイルの CultureYouAreCodingWith を 26 | // 内部で設定します。たとえば、 27 | //ソース ファイルで英語を使用している場合、 を en-US に設定します。次に、 28 | //下の NeutralResourceLanguage 属性のコメントを解除します。下の行の "en-US" を 29 | //プロジェクト ファイルの UICulture 設定と一致するよう更新します。 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //テーマ固有のリソース ディクショナリが置かれている場所 36 | //(リソースがページ、 37 | //またはアプリケーション リソース ディクショナリに見つからない場合に使用されます) 38 | ResourceDictionaryLocation.SourceAssembly //汎用リソース ディクショナリが置かれている場所 39 | //(リソースがページ、 40 | //アプリケーション、またはいずれのテーマ固有のリソース ディクショナリにも見つからない場合に使用されます) 41 | )] 42 | 43 | 44 | // アセンブリのバージョン情報は次の 4 つの値で構成されています: 45 | // 46 | // メジャー バージョン 47 | // マイナー バージョン 48 | // ビルド番号 49 | // Revision 50 | // 51 | // すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます 52 | // 既定値にすることができます: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /LiffManager/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // このコードはツールによって生成されました。 4 | // ランタイム バージョン:4.0.30319.42000 5 | // 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 7 | // コードが再生成されるときに損失したりします 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace LiffManager.Properties 12 | { 13 | 14 | 15 | /// 16 | /// ローカライズされた文字列などを検索するための、厳密に型指定されたリソース クラスです。 17 | /// 18 | // このクラスは StronglyTypedResourceBuilder クラスによって ResGen 19 | // または Visual Studio のようなツールを使用して自動生成されました。 20 | // メンバーを追加または削除するには、.ResX ファイルを編集して、/str オプションと共に 21 | // ResGen を実行し直すか、または VS プロジェクトをリビルドします。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// このクラスで使用されるキャッシュされた ResourceManager インスタンスを返します。 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LiffManager.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// 厳密に型指定されたこのリソース クラスを使用して、すべての検索リソースに対し、 56 | /// 現在のスレッドの CurrentUICulture プロパティをオーバーライドします。 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /LiffManager/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace LiffManager.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LiffManager/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /LiffManager/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Line.Messaging/ContentStream.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Http.Headers; 4 | 5 | namespace Line.Messaging 6 | { 7 | /// 8 | /// Stream object for content such as image, file, etc. 9 | /// 10 | public class ContentStream : Stream 11 | { 12 | protected Stream _baseStream; 13 | 14 | protected Stream BaseStream 15 | { 16 | get 17 | { 18 | if (_baseStream == null) { throw new ObjectDisposedException(nameof(BaseStream)); } 19 | return _baseStream; 20 | } 21 | } 22 | 23 | public HttpContentHeaders ContentHeaders { get; } 24 | 25 | public ContentStream(Stream baseStream, HttpContentHeaders contentHeaders) 26 | { 27 | _baseStream = baseStream; 28 | ContentHeaders = contentHeaders; 29 | } 30 | 31 | public override bool CanRead => _baseStream?.CanRead ?? false; 32 | 33 | public override bool CanSeek => _baseStream?.CanSeek ?? false; 34 | 35 | public override bool CanWrite => _baseStream?.CanWrite ?? false; 36 | 37 | public override long Length => BaseStream.Length; 38 | 39 | public override long Position { get => BaseStream.Position; set => BaseStream.Position = value; } 40 | 41 | public override void Flush() => BaseStream.Flush(); 42 | 43 | public override int Read(byte[] buffer, int offset, int count) => BaseStream.Read(buffer, offset, count); 44 | 45 | public override long Seek(long offset, SeekOrigin origin) => BaseStream.Seek(offset, origin); 46 | 47 | public override void SetLength(long value) => BaseStream.SetLength(value); 48 | 49 | public override void Write(byte[] buffer, int offset, int count) => BaseStream.Write(buffer, offset, count); 50 | 51 | protected override void Dispose(bool disposing) 52 | { 53 | base.Dispose(disposing); 54 | if (disposing) 55 | { 56 | _baseStream?.Dispose(); 57 | _baseStream = null; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Line.Messaging/Exceptions/ErrorResponseMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Error returned from LINE Platform 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#error-responses 8 | /// 9 | public class ErrorResponseMessage 10 | { 11 | /// 12 | /// Summary of the error 13 | /// 14 | public string Message { get; set; } 15 | 16 | /// 17 | /// Details of the error 18 | /// 19 | public IList Details { get; set; } 20 | 21 | public ErrorResponseMessage() 22 | {} 23 | 24 | public override string ToString() 25 | { 26 | return (Details == null) ? Message : $"{Message},[{string.Join(",", Details)}]"; 27 | } 28 | 29 | /// 30 | /// Details of the error 31 | /// 32 | public class ErrorDetails 33 | { 34 | /// 35 | /// Details of the error 36 | /// 37 | public string Message { get; set; } 38 | 39 | /// 40 | /// Location of where the error occurred 41 | /// 42 | public string Property { get; set; } 43 | 44 | public ErrorDetails() 45 | { 46 | } 47 | 48 | public override string ToString() 49 | { 50 | return $"{{{Message}, {Property}}}"; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Line.Messaging/Exceptions/InvalidSignatureException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Capture Invalid Signature Exception. 7 | /// 8 | public class InvalidSignatureException : Exception 9 | { 10 | public InvalidSignatureException() 11 | { 12 | } 13 | 14 | public InvalidSignatureException(string message) : base(message) 15 | { 16 | } 17 | 18 | public InvalidSignatureException(string message, Exception innerException) : base(message, innerException) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Line.Messaging/Exceptions/LineResponseException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace Line.Messaging 5 | { 6 | /// 7 | /// Capture Error from LINE platform 8 | /// 9 | public class LineResponseException : Exception 10 | { 11 | /// 12 | /// HTTP Status Code 13 | /// 14 | public HttpStatusCode StatusCode { get; set; } 15 | 16 | /// 17 | /// Error returned from LINE Platform 18 | /// 19 | public ErrorResponseMessage ResponseMessage { get; set; } 20 | 21 | public LineResponseException() 22 | {} 23 | 24 | public LineResponseException(string message) : base(message) 25 | {} 26 | 27 | public LineResponseException(string message, Exception innerException) : base(message, innerException) 28 | {} 29 | 30 | public override string ToString() 31 | { 32 | return $"StatusCode={StatusCode}, {ResponseMessage}" + Environment.NewLine 33 | + base.ToString(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Line.Messaging/Exceptions/UserIdMismatchException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Capture Invalid Signature Exception. 7 | /// 8 | public class UserIdMismatchException : Exception 9 | { 10 | public UserIdMismatchException() 11 | { 12 | } 13 | 14 | public UserIdMismatchException(string message) : base(message) 15 | { 16 | } 17 | 18 | public UserIdMismatchException(string message, Exception innerException) : base(message, innerException) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Line.Messaging/HttpResponseMessageExtensions.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Net.Http; 3 | using System.Threading.Tasks; 4 | 5 | namespace Line.Messaging 6 | { 7 | internal static class HttpResponseMessageExtensions 8 | { 9 | /// 10 | /// Validate the response status. 11 | /// 12 | /// HttpResponseMessage 13 | /// HttpResponseMessage 14 | internal static async Task EnsureSuccessStatusCodeAsync(this HttpResponseMessage response) 15 | { 16 | if (response.IsSuccessStatusCode) 17 | { 18 | return response; 19 | } 20 | else 21 | { 22 | ErrorResponseMessage errorMessage; 23 | var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); 24 | try 25 | { 26 | errorMessage = JsonConvert.DeserializeObject(content, new CamelCaseJsonSerializerSettings()); 27 | } 28 | catch 29 | { 30 | errorMessage = new ErrorResponseMessage() { Message = content, Details = new ErrorResponseMessage.ErrorDetails[0] }; 31 | } 32 | throw new LineResponseException(errorMessage.Message) { StatusCode = response.StatusCode, ResponseMessage = errorMessage }; 33 | 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Line.Messaging/Json/CamelCaseJsonSerializerSettings.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace Line.Messaging 6 | { 7 | internal class CamelCaseJsonSerializerSettings : JsonSerializerSettings 8 | { 9 | public CamelCaseJsonSerializerSettings() 10 | { 11 | ContractResolver = new CamelCasePropertyNamesContractResolver(); 12 | Converters.Add(new StringEnumConverter { CamelCaseText = true }); 13 | NullValueHandling = NullValueHandling.Ignore; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Line.Messaging/Json/CustomStringEnumConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Converters; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace Line.Messaging 8 | { 9 | 10 | 11 | public class CustomStringEnumConverter : StringEnumConverter where TEnum : struct, Enum 12 | { 13 | private readonly IDictionary enumStrPairs; 14 | 15 | 16 | public override bool CanConvert(Type objectType) 17 | { 18 | return objectType == typeof(ComponentSize); 19 | } 20 | 21 | public CustomStringEnumConverter(IDictionary enumStrPairs) 22 | { 23 | this.enumStrPairs = enumStrPairs ?? new Dictionary(); 24 | } 25 | 26 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 27 | { 28 | if (reader.TokenType == JsonToken.String) 29 | { 30 | var value = (string)reader.Value; 31 | 32 | if (enumStrPairs.Any(kvp => value == kvp.Value)) 33 | { 34 | return enumStrPairs.First(kvp => value == kvp.Value).Key; 35 | } 36 | } 37 | 38 | return base.ReadJson(reader, objectType, existingValue, serializer); 39 | } 40 | 41 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 42 | { 43 | 44 | if (enumStrPairs.TryGetValue((TEnum)value, out string name)) 45 | { 46 | writer.WriteValue(name); 47 | } 48 | else 49 | { 50 | base.WriteJson(writer, value, serializer); 51 | } 52 | 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Line.Messaging/Json/ToStringJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Line.Messaging 7 | { 8 | 9 | public class ToStringJsonConverter : JsonConverter 10 | { 11 | public override bool CanConvert(Type objectType) 12 | { 13 | return true; 14 | } 15 | 16 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 17 | { 18 | writer.WriteValue(value.ToString()); 19 | } 20 | 21 | public override bool CanRead 22 | { 23 | get { return false; } 24 | } 25 | 26 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Line.Messaging/Liff/LiffApp.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging.Liff 6 | { 7 | public class LiffApp 8 | { 9 | public string LiffId { get; } 10 | public View View { get; } 11 | 12 | public LiffApp(string liffId, View view) 13 | { 14 | LiffId = liffId; 15 | View = view; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Line.Messaging/Liff/View.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging.Liff 6 | { 7 | /// 8 | /// View object which contains the URL and view size of the LIFF app. 9 | /// 10 | public class View 11 | { 12 | /// 13 | /// Size of the LIFF app view. Specify one of the following values 14 | /// 15 | public ViewType Type { get; } 16 | 17 | /// 18 | /// URL of the LIFF app. Must start with HTTPS. 19 | /// 20 | public string Url { get; } 21 | 22 | /// 23 | /// Constructor 24 | /// 25 | /// 26 | /// Size of the LIFF app view. Specify one of the following values 27 | /// 28 | /// 29 | /// URL of the LIFF app. Must start with HTTPS. 30 | /// 31 | public View(ViewType type, string url) 32 | { 33 | Type = type; 34 | Url = url; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Line.Messaging/Liff/ViewType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging.Liff 6 | { 7 | /// 8 | /// Size of the LIFF app view. Specify one of the following values 9 | /// 10 | public enum ViewType 11 | { 12 | /// 13 | /// 50% of the screen height of the device. This size can be specified only for the chat screen. 14 | /// 15 | Compact, 16 | 17 | /// 18 | /// 80% of the screen height of the device. This size can be specified only for the chat screen. 19 | /// 20 | Tall, 21 | 22 | /// 23 | /// 100% of the screen height of the device. This size can be specified for any screens in the LINE app. 24 | /// 25 | Full 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Line.Messaging/Line.Messaging.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard1.3 5 | pierre3, kenamanu 6 | 7 | Line Messaging API 8 | SDK for the LINE Messaging API for C# 9 | 1.4.5 10 | © 2018 pierre3 11 | https://github.com/pierre3/LineMessagingApi/blob/master/LICENSE 12 | true 13 | Line Messaging API;line;bot 14 | https://github.com/pierre3/LineMessagingApi/ 15 | true 16 | https://github.com/pierre3/LineMessagingApi/ 17 | git 18 | 1. Supports the API update at 1/17/2019 19 | https://developers.line.biz/en/news/2019/01/ 20 | - New endpoints added to Messaging API 21 | 22 | 2. We reviewed the implementation of the LineMessagingClient class. 23 | - Added interface ILineMessagingClient. 24 | - Changed methods of LineMessagingClient class to virtual method. 25 | 1.4.5.0 26 | 1.4.5.0 27 | 28 | 29 | 30 | bin\Release\netstandard1.3\Line.Messaging.xml 31 | 1701;1702;1705;1591 32 | 7.3 33 | 34 | 35 | 36 | 7.3 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Line.Messaging/LineObjects/ChannelAccessToken.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Short-lived channel access token that is valid for 30 days. 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#issue-channel-access-token 8 | /// 9 | public class ChannelAccessToken 10 | { 11 | /// 12 | /// Short-lived channel access token. Valid for 30 days. 13 | /// Note: Channel access tokens cannot be refreshed 14 | /// 15 | public string AccessToken { get; set; } 16 | 17 | /// 18 | /// Time until channel access token expires in seconds from time the token is issued 19 | /// 20 | public long ExpiresIn { get; set; } 21 | 22 | /// 23 | /// Bearer 24 | /// 25 | public string TokenType { get; } = "Bearer"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Line.Messaging/LineObjects/ImagemapSize.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Image size. 5 | /// 6 | public class ImagemapSize 7 | { 8 | /// 9 | /// Default rich menu size 10 | /// 11 | public static ImagemapSize RichMenuLong { get; } = new ImagemapSize(2500, 1686); 12 | 13 | /// 14 | /// Half rich menu size. 15 | /// 16 | public static ImagemapSize RichMenuShort { get; } = new ImagemapSize(2500, 843); 17 | 18 | /// 19 | /// Width 20 | /// 21 | public int Width { get; } 22 | 23 | /// 24 | /// Height 25 | /// 26 | public int Height { get; } 27 | 28 | public ImagemapSize(int width, int height) 29 | { 30 | Width = width; 31 | Height = height; 32 | } 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Line.Messaging/LineObjects/MemberIds.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Response from Get group member user IDs API 7 | /// 8 | public class GroupMemberIds 9 | { 10 | /// 11 | /// List of user IDs of the members in the group. 12 | /// Max: 100 user IDs 13 | /// 14 | public IList MemberIds { get; set; } 15 | 16 | /// 17 | /// continuationToken 18 | /// Only returned when there are more user IDs remaining in memberIds 19 | /// 20 | public string Next { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Line.Messaging/LineObjects/NumberOfMessages.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public class NumberOfSentMessages 4 | { 5 | /// 6 | /// Status of the counting process. One of the following values is returned: 7 | /// ready: You can get the number of messages. 8 | /// unready: The message counting process for the date specified in date has not been completed yet.Retry your request later.Normally, the counting process is completed within the next day. 9 | /// out_of_service: The date specified in date is earlier than March 31, 2018, when the operation of the counting system started. 10 | /// 11 | public NumberOfSentMessagesStatus Status { get; set; } 12 | 13 | /// 14 | /// The number of messages sent with the Messaging API on the date specified in date. The response has this property only when the value of status is ready. 15 | /// 16 | public int Success { get; set; } 17 | 18 | /// 19 | /// Default Constructor 20 | /// 21 | public NumberOfSentMessages() 22 | {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Line.Messaging/LineObjects/NumberOfSentMessagesStatus.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum NumberOfSentMessagesStatus 4 | { 5 | Ready, 6 | Unready, 7 | out_of_service 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Line.Messaging/LineObjects/UserProfile.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Response from Get User Profile API. 5 | /// https://developers.line.me/en/docs/messaging-api/reference/#get-profile 6 | /// 7 | public class UserProfile 8 | { 9 | /// 10 | /// Display name 11 | /// 12 | public string DisplayName { get; set; } 13 | 14 | /// 15 | /// User ID 16 | /// 17 | public string UserId { get; set; } 18 | 19 | /// 20 | /// Image URL 21 | /// 22 | public string PictureUrl { get; set; } 23 | 24 | /// 25 | /// Status message 26 | /// 27 | public string StatusMessage { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Action/CameraRollTemplateAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// This action can be configured only with quick reply buttons. When a button associated with this action is tapped, the camera roll screen in the LINE app is opened. 7 | /// https://developers.line.me/en/reference/messaging-api/#camera-roll-action 8 | /// 9 | public class CameraRollTemplateAction : ITemplateAction 10 | { 11 | public TemplateActionType Type { get; } = TemplateActionType.CameraRoll; 12 | 13 | /// 14 | /// Label for the action 15 | /// Max: 20 characters 16 | /// 17 | public string Label { get; } 18 | 19 | public CameraRollTemplateAction(string label) 20 | { 21 | Label = label.Substring(0, Math.Min(label.Length, 20)); 22 | } 23 | 24 | internal static CameraRollTemplateAction CreateFrom(dynamic dynamicObject) 25 | { 26 | return new CameraRollTemplateAction((string)dynamicObject?.label); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Action/CameraTemplateAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// This action can be configured only with quick reply buttons. When a button associated with this action is tapped, the camera screen in the LINE app is opened. 7 | /// https://developers.line.me/en/reference/messaging-api/#camera-action 8 | /// 9 | public class CameraTemplateAction : ITemplateAction 10 | { 11 | public TemplateActionType Type { get; } = TemplateActionType.Camera; 12 | 13 | /// 14 | /// Label for the action 15 | /// Max: 20 characters 16 | /// 17 | public string Label { get; } 18 | 19 | public CameraTemplateAction(string label) 20 | { 21 | Label = label.Substring(0, Math.Min(label.Length, 20)); 22 | } 23 | 24 | internal static CameraTemplateAction CreateFrom(dynamic dynamicObject) 25 | { 26 | return new CameraTemplateAction((string)dynamicObject?.label); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Action/DateTimePickerMode.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum DateTimePickerMode 4 | { 5 | Time, 6 | Date, 7 | Datetime 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Action/LocationTemplateAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// This action can be configured only with quick reply buttons. When a button associated with this action is tapped, the location screen in the LINE app is opened. 7 | /// https://developers.line.me/en/reference/messaging-api/#location-action 8 | /// 9 | public class LocationTemplateAction : ITemplateAction 10 | { 11 | public TemplateActionType Type { get; } = TemplateActionType.Location; 12 | 13 | /// 14 | /// Label for the action 15 | /// Max: 20 characters 16 | /// 17 | public string Label { get; } 18 | 19 | public LocationTemplateAction(string label) 20 | { 21 | Label = label.Substring(0, Math.Min(label.Length, 20)); 22 | } 23 | 24 | internal static LocationTemplateAction CreateFrom(dynamic dynamicObject) 25 | { 26 | return new LocationTemplateAction((string)dynamicObject?.label); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Action/MessageTemplateAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// When a control associated with this action is tapped, the string in the text field is sent as a message from the user. 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#datetime-picker-action 8 | /// 9 | public class MessageTemplateAction : ITemplateAction 10 | { 11 | public TemplateActionType Type { get; } = TemplateActionType.Message; 12 | 13 | /// 14 | /// Label for the action 15 | /// Required for templates other than image carousel.Max: 20 characters 16 | /// Optional for image carousel templates.Max: 12 characters. 17 | /// Optional for rich menus. Spoken when the accessibility feature is enabled on the client device. Max: 20 characters. Supported on LINE iOS version 8.2.0 and later. 18 | /// 19 | public string Label { get; } 20 | 21 | /// 22 | /// Text sent when the action is performed 23 | /// Max: 300 characters 24 | /// 25 | public string Text { get; } 26 | 27 | /// 28 | /// Constructor 29 | /// 30 | /// 31 | /// Label for the action 32 | /// Required for templates other than image carousel.Max: 20 characters 33 | /// Optional for image carousel templates.Max: 12 characters. 34 | /// Optional for rich menus. Spoken when the accessibility feature is enabled on the client device. Max: 20 characters. Supported on LINE iOS version 8.2.0 and later. 35 | /// 36 | /// 37 | /// Text sent when the action is performed 38 | /// Max: 300 characters 39 | /// 40 | public MessageTemplateAction(string label, string text) 41 | { 42 | Label = label?.Substring(0, Math.Min(label.Length, 20)); 43 | Text = text.Substring(0, Math.Min(text.Length, 300)); 44 | } 45 | 46 | internal static MessageTemplateAction CreateFrom(dynamic dynamicObject) 47 | { 48 | return new MessageTemplateAction((string)dynamicObject?.label, (string)dynamicObject?.text); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Action/TemplateActionType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum TemplateActionType 4 | { 5 | Postback, 6 | Message, 7 | Uri, 8 | Datetimepicker, 9 | Camera, 10 | CameraRoll, 11 | Location 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/AudioMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Audio 5 | /// https://developers.line.me/en/docs/messaging-api/reference/#audio 6 | /// 7 | public class AudioMessage : ISendMessage 8 | { 9 | public MessageType Type { get; } = MessageType.Audio; 10 | 11 | /// 12 | /// These properties are used for the quick reply feature 13 | /// 14 | public QuickReply QuickReply { get; set; } 15 | 16 | /// 17 | /// URL of audio file (Max: 1000 characters) 18 | /// HTTPS 19 | /// m4a 20 | /// Less than 1 minute 21 | /// Max 10 MB 22 | /// 23 | public string OriginalContentUrl { get; } 24 | 25 | /// 26 | /// Length of audio file (milliseconds) 27 | /// 28 | public long Duration { get; } 29 | 30 | /// 31 | /// Constructor 32 | /// 33 | /// 34 | /// URL of audio file (Max: 1000 characters) 35 | /// HTTPS 36 | /// m4a 37 | /// Less than 1 minute 38 | /// Max 10 MB 39 | /// 40 | /// 41 | /// Length of audio file (milliseconds) 42 | /// 43 | /// 44 | /// QuickReply 45 | /// 46 | public AudioMessage(string originalContentUrl, long duration, QuickReply quickReply = null) 47 | { 48 | OriginalContentUrl = originalContentUrl; 49 | Duration = duration; 50 | QuickReply = quickReply; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/BubbleContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public class BubbleContainer : IFlexContainer 8 | { 9 | public FlexContainerType Type => FlexContainerType.Bubble; 10 | 11 | /// 12 | /// Text directionality and the order of components in horizontal boxes in the container. 13 | /// Specify one of the following values: 14 | /// / ltr: Left to right 15 | /// / rtl: Right to left 16 | /// , The default value is ltr. 17 | /// (Optional) 18 | /// 19 | public ComponentDirection Direction { get; set; } 20 | 21 | /// 22 | /// Header block. Specify a box component. 23 | /// (Optional) 24 | /// 25 | public BoxComponent Header { get; set; } 26 | 27 | /// 28 | /// Hero block. Specify an image component. 29 | /// (Optional) 30 | /// 31 | public ImageComponent Hero { get; set; } 32 | 33 | /// 34 | /// Body block. Specify a box component. 35 | /// (Optional) 36 | /// 37 | public BoxComponent Body { get; set; } 38 | 39 | /// 40 | /// Footer block. Specify a box component. 41 | /// (Optional) 42 | /// 43 | public BoxComponent Footer { get; set; } 44 | 45 | /// 46 | /// Style of each block. Specify a bubble style object. For more information, see Objects for the block style. 47 | /// (Optional) 48 | /// 49 | public BubbleStyles Styles { get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/CarouselContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public class CarouselContainer : IFlexContainer 8 | { 9 | public FlexContainerType Type => FlexContainerType.Carousel; 10 | 11 | /// 12 | /// Array of bubble containers. Max: 10 bubbles 13 | /// (Required) 14 | /// 15 | public IList Contents { get; set; } = new List(); 16 | 17 | public CarouselContainer() 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Component/FillerComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | /// 8 | /// This is an invisible component to fill extra space between components. 9 | /// 10 | public class FillerComponent : IFlexComponent 11 | { 12 | 13 | public FlexComponentType Type => FlexComponentType.Filler; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Component/FlexComponentType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum FlexComponentType 8 | { 9 | Box, 10 | Button, 11 | Filler, 12 | Icon, 13 | Image, 14 | Separator, 15 | Spacer, 16 | Text, 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Component/IFlexComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public interface IFlexComponent 8 | { 9 | FlexComponentType Type { get; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Component/SeparatorComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | /// 8 | /// This component draws a separator between components in the parent box. 9 | /// 10 | public class SeparatorComponent : IFlexComponent 11 | { 12 | public FlexComponentType Type => FlexComponentType.Separator; 13 | 14 | /// 15 | /// Minimum space between this component and the previous component in the parent box. 16 | /// You can specify one of the following values: none, xs, sm, md, lg, xl, or xxl. 17 | /// none does not set a space while the other values set a space whose size increases in the order of listing. 18 | /// The default value is the value of the spacing property of the parent box. 19 | /// If this component is the first component in the parent box, the margin property will be ignored. 20 | /// (Optional) 21 | /// 22 | public Spacing? Margin { get; set; } 23 | 24 | /// 25 | /// Color of the separator. Use a hexadecimal color code. 26 | /// (Optional) 27 | /// 28 | public string Color { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Component/SpacerComponent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public class SpacerComponent : IFlexComponent 8 | { 9 | public FlexComponentType Type => FlexComponentType.Spacer; 10 | 11 | /// 12 | /// Size of the space.(Required) 13 | /// You can specify one of the following values: xs, sm, md, lg, xl, or xxl. 14 | /// The size increases in the order of listing. The default value is md. 15 | /// (Required) 16 | /// 17 | public ComponentSize Size { get; set; } 18 | 19 | /// 20 | /// Constructor 21 | /// 22 | /// 23 | /// /// Size of the space.(Required) 24 | /// You can specify one of the following values: xs, sm, md, lg, xl, or xxl. 25 | /// The size increases in the order of listing. The default value is md. 26 | /// 27 | public SpacerComponent(ComponentSize size) 28 | { 29 | Size = size; 30 | } 31 | 32 | /// 33 | /// Constructor 34 | /// 35 | public SpacerComponent() 36 | { 37 | 38 | } 39 | 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Extensions/BoxComponentEntensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public static class BoxComponentExtensions 8 | { 9 | /// 10 | /// Add a flex component to the Box component. 11 | /// 12 | /// BoxComponent 13 | /// Flex Component 14 | /// BoxComponent 15 | public static BoxComponent AddContents(this BoxComponent self, IFlexComponent component) 16 | { 17 | self.Contents.Add(component); 18 | return self; 19 | } 20 | 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Extensions/BubbleContainerFlexMessages.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public class BubbleContainerFlexMessage : FlexMessage 8 | { 9 | /// 10 | /// Sets a Bubble container to the FlexMessage object. 11 | /// 12 | /// 13 | /// Flex Message 14 | public BubbleContainerFlexMessage SetBubbleContainer(BubbleContainer bubbleContainer) 15 | { 16 | Contents = bubbleContainer ?? throw new ArgumentNullException(nameof(bubbleContainer)); 17 | return this; 18 | } 19 | 20 | /// 21 | /// Constructor 22 | /// 23 | /// alt text 24 | public BubbleContainerFlexMessage(string altText) : base(altText) 25 | { 26 | 27 | } 28 | 29 | /// 30 | /// Sets a QuickReply object to the FlexMessage objecy. 31 | /// 32 | /// 33 | /// Flex Message 34 | public BubbleContainerFlexMessage SetQuickReply(QuickReply quickReply) 35 | { 36 | QuickReply = quickReply; 37 | return this; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Extensions/CarouselContainerFlexMessges.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public class CarouselContainerFlexMessage : FlexMessage 8 | { 9 | /// 10 | /// Constructor 11 | /// 12 | /// alt text 13 | public CarouselContainerFlexMessage(string altText) : base(altText) 14 | { 15 | } 16 | 17 | /// 18 | /// Add a bubble container to the FlexMessage object. 19 | /// 20 | /// Bubble Container 21 | /// Flex Message 22 | public CarouselContainerFlexMessage AddBubbleContainer(BubbleContainer bubbleContainer) 23 | { 24 | if (bubbleContainer == null) { throw new ArgumentNullException(nameof(bubbleContainer)); } 25 | var contents = (Contents as CarouselContainer).Contents; 26 | contents.Add(bubbleContainer); 27 | return this; 28 | } 29 | 30 | /// 31 | /// Sets a QuickReply object to the QuickReply object. 32 | /// 33 | /// 34 | /// Flex Message 35 | public CarouselContainerFlexMessage SetQuickReply(QuickReply quickReply) 36 | { 37 | QuickReply = quickReply; 38 | return this; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/IFlexContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public interface IFlexContainer 8 | { 9 | FlexContainerType Type { get; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/Align.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum Align 8 | { 9 | Start, 10 | End, 11 | Center 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/AltUri.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public class AltUri 8 | { 9 | public string Desktop { get; } 10 | public AltUri(string desktop) 11 | { 12 | Desktop = desktop; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/AspectMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum AspectMode 8 | { 9 | Cover, 10 | Fit, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/BoxLayout.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | /// 8 | /// The placement style of components in this box. Specify one of the following values 9 | /// 10 | public enum BoxLayout 11 | { 12 | /// 13 | /// Components are placed horizontally. The direction property of the bubble container specifies the order. 14 | /// 15 | Horizontal, 16 | /// 17 | /// Components are placed vertically from top to bottom. 18 | /// 19 | Vertical, 20 | /// 21 | /// Components are placed in the same way as horizontal is specified except the baselines of the components are aligned. 22 | /// 23 | Baseline, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/ButtonHeight.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum ButtonHeight 8 | { 9 | Sm, 10 | Md, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/ButtonStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum ButtonStyle 8 | { 9 | Link, 10 | Primary, 11 | Secondary, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/ComponentDirection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum ComponentDirection 8 | { 9 | Ltr, 10 | Rtl, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/ComponentSize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace Line.Messaging 5 | { 6 | [JsonConverter(typeof(ComponentSizeEnumConverter))] 7 | public enum ComponentSize 8 | { 9 | Xxs, 10 | Xs, 11 | Sm, 12 | Md, 13 | Lg, 14 | Xl, 15 | Xxl, 16 | _3xl, 17 | _4xl, 18 | _5xl, 19 | Full 20 | } 21 | 22 | internal class ComponentSizeEnumConverter : CustomStringEnumConverter 23 | { 24 | public ComponentSizeEnumConverter() : base(new Dictionary 25 | { 26 | [ComponentSize._3xl] = "3xl", 27 | [ComponentSize._4xl] = "4xl", 28 | [ComponentSize._5xl] = "5xl", 29 | }) 30 | { 31 | CamelCaseText = true; 32 | } 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/FlexContainerType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum FlexContainerType 8 | { 9 | Bubble, 10 | Carousel 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/Gravity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum Gravity 8 | { 9 | Top, 10 | Bottom, 11 | Center 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/Spacing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum Spacing 8 | { 9 | None, 10 | Xs, 11 | Sm, 12 | Md, 13 | Lg, 14 | Xl, 15 | Xxl, 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/ParameterTypes/Weight.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | public enum Weight 8 | { 9 | Regular, 10 | Bold 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Style/BoxStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | /// 8 | /// Block Style 9 | /// 10 | public class BlockStyle 11 | { 12 | /// 13 | /// Background color of the block. Use a hexadecimal color code. 14 | /// (Optional) 15 | /// 16 | public string BackgroundColor { get; set; } 17 | 18 | /// 19 | /// true to place a separator above the block. 20 | /// true will be ignored for the first block in a container because you cannot place a separator above the first block. 21 | /// The default value is false. 22 | /// (Optional) 23 | /// 24 | 25 | public bool Separator { get; set; } 26 | 27 | /// 28 | /// Color of the separator. Use a hexadecimal color code. 29 | /// (Optional) 30 | /// 31 | public string SeparatorColor { get; set; } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Flex/Style/BubbleStyles.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Line.Messaging 6 | { 7 | /// 8 | /// Use the following two objects to define the style of blocks in a bubble. 9 | /// 10 | public class BubbleStyles 11 | { 12 | /// 13 | /// Style of the header block 14 | /// (Optional) 15 | /// 16 | public BlockStyle Header { get; set; } 17 | 18 | /// 19 | /// Style of the hero block 20 | /// (Optional) 21 | /// 22 | public BlockStyle Hero { get; set; } 23 | 24 | /// 25 | /// Style of the body block 26 | /// (Optional) 27 | /// 28 | public BlockStyle Body { get; set; } 29 | 30 | /// 31 | /// Style of the footer block 32 | /// (Optional) 33 | /// 34 | public BlockStyle Footer { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/FlexMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Line.Messaging 5 | { 6 | /// 7 | /// Template messages are messages with predefined layouts which you can customize. There are four types of templates available that can be used to interact with users through your bot. 8 | /// 9 | public class FlexMessage : ISendMessage 10 | { 11 | public MessageType Type { get; } = MessageType.Flex; 12 | 13 | /// 14 | /// These properties are used for the quick reply feature 15 | /// 16 | public QuickReply QuickReply { get; set; } 17 | 18 | /// 19 | /// Flex Message container object 20 | /// 21 | public IFlexContainer Contents { get; set; } 22 | 23 | /// 24 | /// Alternative text. 25 | /// Max: 400 characters 26 | /// 27 | public string AltText { get; set; } 28 | 29 | /// 30 | /// Constructor 31 | /// 32 | /// 33 | /// Alternative text. 34 | /// Max: 400 characters 35 | /// 36 | public FlexMessage(string altText) 37 | { 38 | AltText = altText.Substring(0, Math.Min(altText.Length, 400)); 39 | } 40 | 41 | public static BubbleContainerFlexMessage CreateBubbleMessage(string altText) 42 | { 43 | return new BubbleContainerFlexMessage(altText) 44 | { 45 | Contents = new BubbleContainer() 46 | }; 47 | } 48 | 49 | public static CarouselContainerFlexMessage CreateCarouselMessage(string altText) 50 | { 51 | return new CarouselContainerFlexMessage(altText) 52 | { 53 | Contents = new CarouselContainer() 54 | }; 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/ISendMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public interface ISendMessage 4 | { 5 | MessageType Type { get; } 6 | 7 | /// 8 | /// These properties are used for the quick reply feature. Supported on LINE 8.11.0 and later for iOS and Android. For more information, see Using quick replies. 9 | /// 10 | QuickReply QuickReply { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/ImageMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Image 5 | /// https://developers.line.me/en/docs/messaging-api/reference/#image 6 | /// 7 | public class ImageMessage : ISendMessage 8 | { 9 | public MessageType Type { get; } = MessageType.Image; 10 | 11 | /// 12 | /// These properties are used for the quick reply feature 13 | /// 14 | public QuickReply QuickReply { get; set; } 15 | 16 | /// 17 | /// Image URL (Max: 1000 characters) 18 | /// HTTPS 19 | /// JPEG 20 | /// Max: 1024 x 1024 21 | /// Max: 1 MB 22 | /// 23 | public string OriginalContentUrl { get; } 24 | 25 | /// 26 | /// Preview image URL (Max: 1000 characters) 27 | /// HTTPS 28 | /// JPEG 29 | /// Max: 240 x 240 30 | /// Max: 1 MB 31 | /// 32 | public string PreviewImageUrl { get; } 33 | 34 | /// 35 | /// Constructor 36 | /// 37 | /// 38 | /// Image URL (Max: 1000 characters) 39 | /// HTTPS 40 | /// JPEG 41 | /// Max: 1024 x 1024 42 | /// Max: 1 MB 43 | /// 44 | /// 45 | /// Preview image URL (Max: 1000 characters) 46 | /// HTTPS 47 | /// JPEG 48 | /// Max: 240 x 240 49 | /// Max: 1 MB 50 | /// 51 | /// 52 | /// QuickReply 53 | /// 54 | public ImageMessage(string originalContentUrl, string previerImageUrl, QuickReply quickReply = null) 55 | { 56 | OriginalContentUrl = originalContentUrl; 57 | PreviewImageUrl = previerImageUrl; 58 | QuickReply = quickReply; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/ExternalLink.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public class ExternalLink 4 | { 5 | /// 6 | /// Webpage URL. Called when the label displayed after the video is tapped. 7 | /// / Max: 1000 characters 8 | /// 9 | public string LinkUri { get; } 10 | 11 | /// 12 | /// Label.Displayed after the video is finished. 13 | /// / Max: 30 characters 14 | /// 15 | public string Label { get; } 16 | 17 | /// 18 | /// Constructor 19 | /// 20 | /// 21 | /// Webpage URL. Called when the label displayed after the video is tapped. 22 | /// / Max: 1000 characters 23 | /// 24 | /// 25 | /// Label.Displayed after the video is finished. 26 | /// / Max: 30 characters 27 | /// 28 | public ExternalLink(string linkUri, string label) 29 | { 30 | LinkUri = linkUri; 31 | Label = label; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/IImagemapAction.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public interface IImagemapAction 4 | { 5 | ImagemapActionType Type { get; } 6 | ImagemapArea Area { get; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/ImagemapActionType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum ImagemapActionType 4 | { 5 | Uri, 6 | Message 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/ImagemapArea.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Defines the size of a tappable area. The top left is used as the origin of the area. 5 | /// https://developers.line.me/en/docs/messaging-api/reference/#imagemap-area-object 6 | /// 7 | public class ImagemapArea 8 | { 9 | /// 10 | /// Horizontal position relative to the top-left corner of the area. 11 | /// 12 | public int X { get; } 13 | /// 14 | /// Vertical position relative to the top-left corner of the area. 15 | /// 16 | public int Y { get; } 17 | /// 18 | /// Width of the tappable area 19 | /// 20 | public int Width { get; } 21 | /// 22 | /// Height of the tappable area 23 | /// 24 | public int Height { get; } 25 | 26 | /// 27 | /// Constructor 28 | /// 29 | /// 30 | /// Horizontal position relative to the top-left corner of the area. 31 | /// 32 | /// 33 | /// Vertical position relative to the top-left corner of the area. 34 | /// 35 | /// 36 | /// Width of the tappable area 37 | /// 38 | /// 39 | /// Height of the tappable area 40 | /// 41 | public ImagemapArea(int x, int y, int width, int height) 42 | { 43 | X = x; 44 | Y = y; 45 | Width = width; 46 | Height = height; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/MessageImagemapAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Object which specifies the actions and tappable regions of an imagemap. 7 | /// When a region is tapped, the message specified in message is sent. 8 | /// https://developers.line.me/en/docs/messaging-api/reference/#imagemap-action-objects 9 | /// 10 | public class MessageImagemapAction : IImagemapAction 11 | { 12 | public ImagemapActionType Type { get; } = ImagemapActionType.Message; 13 | 14 | /// 15 | /// Defined tappable area 16 | /// 17 | public ImagemapArea Area { get; } 18 | 19 | /// 20 | /// Message to send 21 | /// Max: 400 characters 22 | /// 23 | public string Text { get; } 24 | 25 | /// 26 | /// Label for the action. Spoken when the accessibility feature is enabled on the client device. 27 | /// Max: 50 characters 28 | /// Supported on LINE iOS version 8.2.0 and later. 29 | /// 30 | public string Label { get; } 31 | 32 | /// 33 | /// Constructor 34 | /// 35 | /// 36 | /// Defined tappable area 37 | /// 38 | /// 39 | /// Message to send 40 | /// Max: 400 characters 41 | /// 42 | /// 43 | /// Label for the action. Spoken when the accessibility feature is enabled on the client device. 44 | /// Max: 50 characters 45 | /// Supported on LINE iOS version 8.2.0 and later. 46 | /// 47 | public MessageImagemapAction(ImagemapArea area, string text, string label = null) 48 | { 49 | Area = area; 50 | Text = text.Substring(0, Math.Min(text.Length, 400)); 51 | Label = label?.Substring(0, Math.Min(label.Length, 50)); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/UriImagemapAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Object which specifies the actions and tappable regions of an imagemap. 7 | /// When a region is tapped, the user is redirected to the URI specified in uri. 8 | /// https://developers.line.me/en/docs/messaging-api/reference/#imagemap-action-objects 9 | /// 10 | public class UriImagemapAction : IImagemapAction 11 | { 12 | public ImagemapActionType Type { get; } = ImagemapActionType.Uri; 13 | 14 | /// 15 | /// Defined tappable area 16 | /// 17 | public ImagemapArea Area { get; } 18 | 19 | /// 20 | /// Webpage URL 21 | /// Max: 1000 characters 22 | /// 23 | public string LinkUri { get; } 24 | 25 | /// 26 | /// Label for the action. Spoken when the accessibility feature is enabled on the client device. 27 | /// Max: 50 characters 28 | /// Supported on LINE iOS version 8.2.0 and later. 29 | /// 30 | public string Label { get; } 31 | 32 | /// 33 | /// Constructor 34 | /// 35 | /// 36 | /// Defined tappable area 37 | /// 38 | /// 39 | /// Label for the action. Spoken when the accessibility feature is enabled on the client device. 40 | /// Max: 50 characters 41 | /// Supported on LINE iOS version 8.2.0 and later. 42 | /// 43 | /// 44 | /// Label for the action. Spoken when the accessibility feature is enabled on the client device. 45 | /// Max: 50 characters 46 | /// Supported on LINE iOS version 8.2.0 and later. 47 | /// 48 | public UriImagemapAction(ImagemapArea area, string linkUri, string label = null) 49 | { 50 | Area = area; 51 | LinkUri = linkUri; 52 | Label = label?.Substring(Math.Min(label.Length, 50)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Imagemap/Video.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public class Video 4 | { 5 | /// 6 | /// URL of the video file (Max: 1000 characters) 7 | /// HTTPS, mp4 8 | /// / Max: 1 minute 9 | /// / Max: 10 MB 10 | /// / Note: A very wide or tall video may be cropped when played in some environments. 11 | /// 12 | public string OriginalContentUrl { get; } 13 | 14 | /// 15 | /// URL of the preview image (Max: 1000 characters) 16 | /// HTTP, JPEG 17 | /// / Max: 240 x 240 pixels 18 | /// / Max: 1 MB 19 | /// 20 | public string PreviewImageUrl { get; } 21 | 22 | /// 23 | /// Imagemap Area 24 | /// 25 | public ImagemapArea Area { get; } 26 | 27 | /// 28 | /// Label. Displayed after the video is finished. 29 | /// And Webpage URL. Called when the label displayed after the video is tapped. 30 | /// 31 | public ExternalLink ExternalLink { get; } 32 | 33 | /// 34 | /// Constructor 35 | /// 36 | /// 37 | /// URL of the video file (Max: 1000 characters) 38 | /// HTTPS, mp4 39 | /// / Max: 1 minute 40 | /// / Max: 10 MB 41 | /// / Note: A very wide or tall video may be cropped when played in some environments. 42 | /// 43 | /// 44 | /// URL of the preview image (Max: 1000 characters) 45 | /// HTTP, JPEG 46 | /// / Max: 240 x 240 pixels 47 | /// / Max: 1 MB 48 | /// 49 | /// 50 | /// Imagemap Area 51 | /// 52 | /// 53 | /// Label. Displayed after the video is finished. 54 | /// And Webpage URL. Called when the label displayed after the video is tapped. 55 | /// 56 | public Video(string originalContentUrl, string previewImageUrl, ImagemapArea area, ExternalLink externalLink) 57 | { 58 | OriginalContentUrl = originalContentUrl; 59 | PreviewImageUrl = previewImageUrl; 60 | Area = area; 61 | ExternalLink = externalLink; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/LocationMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Location 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#location 8 | /// 9 | public class LocationMessage : ISendMessage 10 | { 11 | public MessageType Type { get; } = MessageType.Location; 12 | 13 | /// 14 | /// These properties are used for the quick reply feature 15 | /// 16 | public QuickReply QuickReply { get; set; } 17 | 18 | /// 19 | /// Title 20 | /// Max: 100 characters 21 | /// 22 | public string Title { get; } 23 | 24 | /// 25 | /// Address 26 | /// Max: 100 characters 27 | /// 28 | public string Address { get; } 29 | 30 | /// 31 | /// Latitude 32 | /// 33 | public decimal Latitude { get; } 34 | 35 | /// 36 | /// Longitude 37 | /// 38 | public decimal Longitude { get; } 39 | 40 | /// 41 | /// Constructor 42 | /// 43 | /// 44 | /// Title 45 | /// Max: 100 characters 46 | /// 47 | /// 48 | /// Address 49 | /// Max: 100 characters 50 | /// 51 | /// 52 | /// Latitude 53 | /// 54 | /// 55 | /// Longitude 56 | /// 57 | /// 58 | /// QuickReply 59 | /// 60 | public LocationMessage(string title, string address, decimal latitude, decimal longitude, QuickReply quickReply = null) 61 | { 62 | Title = title.Substring(0, Math.Min(title.Length, 100)); 63 | Address = address.Substring(0, Math.Min(address.Length, 100)); 64 | Latitude = latitude; 65 | Longitude = longitude; 66 | QuickReply = quickReply; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/MessageType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum MessageType 4 | { 5 | Text, 6 | Image, 7 | Video, 8 | Audio, 9 | Location, 10 | Sticker, 11 | Imagemap, 12 | Template, 13 | File, 14 | Flex, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/QuickReply/QuickItem.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// This is a quick reply option that is displayed as a button. 5 | /// https://developers.line.me/en/reference/messaging-api/#quick-reply-button-object 6 | /// 7 | public class QuickReplyButtonObject 8 | { 9 | public string Type = "action"; 10 | 11 | /// 12 | /// URL of the icon that is displayed at the beginning of the button 13 | /// Max: 1000 characters 14 | /// URL scheme: https 15 | /// Image format: PNG 16 | /// Aspect ratio: 1:1 17 | /// Data size: Up to 1 MB 18 | /// There is no limit on the image size. 19 | /// If the action property has a camera action, camera roll action, or location action, and the imageUrl property is not set, the default icon is displayed. 20 | /// 21 | public string ImageUrl { get; set; } 22 | 23 | public ITemplateAction Action { get; set; } 24 | 25 | public QuickReplyButtonObject(ITemplateAction action, string imageUrl = null) 26 | { 27 | Action = action; 28 | ImageUrl = imageUrl; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Line.Messaging/Messages/QuickReply/QuickReply.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// https://developers.line.me/en/reference/messaging-api/#quick-reply 7 | /// These properties are used for the quick reply feature. Supported on LINE 8.11.0 and later for iOS and Android. For more information, see Using quick replies. 8 | /// 9 | public class QuickReply 10 | { 11 | /// 12 | /// Quick reply button objects. Max: 13 objects 13 | /// 14 | public IList Items { get; set; } 15 | 16 | public QuickReply(IList items = null) 17 | { 18 | Items = items ?? new List(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Line.Messaging/Messages/RichMenu/ActionArea.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Rich menu Area 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#area-object 8 | /// 9 | public class ActionArea 10 | { 11 | /// 12 | /// Object describing the boundaries of the area in pixels. See bounds object. 13 | /// 14 | public ImagemapArea Bounds { get; set; } 15 | 16 | /// 17 | /// Action performed when the area is tapped. See action objects. Note: The label field is not supported for actions in rich menus. 18 | /// 19 | public ITemplateAction Action { get; set; } 20 | 21 | internal static ActionArea CreateFrom(dynamic dynamicObject) 22 | { 23 | return new ActionArea() 24 | { 25 | Bounds = new ImagemapArea( 26 | (int)(dynamicObject?.bounds?.x ?? 0), 27 | (int)(dynamicObject?.bounds?.y ?? 0), 28 | (int)(dynamicObject?.bounds?.width ?? 0), 29 | (int)(dynamicObject?.bounds?.height ?? 0)), 30 | Action = ParseTemplateAction(dynamicObject?.action) 31 | }; 32 | } 33 | 34 | public static ITemplateAction ParseTemplateAction(dynamic dynamicObject) 35 | { 36 | var type = (TemplateActionType)System.Enum.Parse(typeof(TemplateActionType), (string)dynamicObject?.type, true); 37 | switch (type) 38 | { 39 | case TemplateActionType.Message: 40 | return MessageTemplateAction.CreateFrom(dynamicObject); 41 | case TemplateActionType.Uri: 42 | return UriTemplateAction.CreateFrom(dynamicObject); 43 | case TemplateActionType.Postback: 44 | return PostbackTemplateAction.CreateFrom(dynamicObject); 45 | case TemplateActionType.Datetimepicker: 46 | return DateTimePickerTemplateAction.CreateFrom(dynamicObject); 47 | default: 48 | return null; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/RichMenu/ResponseRichMenu.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | namespace Line.Messaging 5 | { 6 | /// 7 | /// Rich menu response object. 8 | /// https://developers.line.me/en/docs/messaging-api/reference/#rich-menu-response-object 9 | /// 10 | public class ResponseRichMenu : RichMenu 11 | { 12 | /// 13 | /// Rich menu ID 14 | /// 15 | public string RichMenuId { get; set; } 16 | 17 | /// 18 | /// Constructor 19 | /// 20 | /// 21 | /// Rich menu ID 22 | /// 23 | /// 24 | /// Rich menu object 25 | /// 26 | public ResponseRichMenu(string richMenuId, RichMenu source) 27 | { 28 | RichMenuId = richMenuId; 29 | Size = source.Size; 30 | Selected = source.Selected; 31 | Name = source.Name; 32 | ChatBarText = source.ChatBarText; 33 | Areas = source.Areas; 34 | } 35 | 36 | internal static ResponseRichMenu CreateFrom(dynamic dynamicObject) 37 | { 38 | 39 | var areas = new List(); 40 | foreach (var area in dynamicObject?.areas ?? Enumerable.Empty()) 41 | { 42 | areas.Add(ActionArea.CreateFrom(area)); 43 | } 44 | 45 | var menu = new RichMenu() 46 | { 47 | Name = (string)dynamicObject?.name, 48 | Size = new ImagemapSize((int)(dynamicObject?.size?.width ?? 0), (int)(dynamicObject?.size?.height ?? 0)), 49 | Selected = (bool)(dynamicObject?.selected ?? false), 50 | ChatBarText = (string)dynamicObject?.chatBarText, 51 | Areas = areas 52 | }; 53 | return new ResponseRichMenu((string)dynamicObject?.richMenuId, menu); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/RichMenu/RichMenu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Line.Messaging 5 | { 6 | /// 7 | /// Rich menu object 8 | /// https://developers.line.me/en/docs/messaging-api/reference/#rich-menu-object 9 | /// 10 | public class RichMenu 11 | { 12 | private string _name; 13 | private string _chatBarText; 14 | 15 | /// 16 | /// size object which contains the width and height of the rich menu displayed in the chat. Rich menu images must be one of the following sizes: 2500x1686, 2500x843. 17 | /// 18 | public ImagemapSize Size { get; set; } 19 | 20 | /// 21 | /// true to display the rich menu by default. Otherwise, false. 22 | /// 23 | public bool Selected { set; get; } 24 | 25 | /// 26 | /// Name of the rich menu. This value can be used to help manage your rich menus and is not displayed to users. Maximum of 300 characters. 27 | /// 28 | public string Name 29 | { 30 | get => _name; 31 | set 32 | { 33 | _name = value?.Substring(0, Math.Min(value.Length, 300)); 34 | } 35 | } 36 | 37 | /// 38 | /// Text displayed in the chat bar. Maximum of 14 characters. 39 | /// 40 | public string ChatBarText 41 | { 42 | get => _chatBarText; 43 | set 44 | { 45 | _chatBarText = value?.Substring(0, Math.Min(value.Length, 14)); 46 | } 47 | } 48 | 49 | /// 50 | /// Array of area objects which define the coordinates and size of tappable areas. Maximum of 20 area objects. 51 | /// 52 | public IList Areas { set; get; } 53 | 54 | /// 55 | /// Converts from RichMenu to ResponseRichMenu 56 | /// 57 | /// 58 | /// Rich menu ID 59 | /// 60 | /// ResponseRichMenu object 61 | public ResponseRichMenu ToResponseRichMenu(string richMenuId = "") 62 | { 63 | return new ResponseRichMenu(richMenuId, this); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/StickerMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Sticker. For a list of the sticker IDs for stickers that can be sent with the Messaging API, see Sticker list. 5 | /// 6 | public class StickerMessage : ISendMessage 7 | { 8 | public MessageType Type { get; } = MessageType.Sticker; 9 | 10 | /// 11 | /// These properties are used for the quick reply feature 12 | /// 13 | public QuickReply QuickReply { get; set; } 14 | 15 | /// 16 | /// Package ID for a set of stickers. For information on package IDs, see the Sticker list. 17 | /// 18 | public string PackageId { get; } 19 | 20 | /// 21 | /// Sticker ID. For a list of sticker IDs for stickers that can be sent with the Messaging API, see the Sticker list. 22 | /// 23 | public string StickerId { get; } 24 | 25 | /// 26 | /// Constructor 27 | /// 28 | /// 29 | /// Package ID for a set of stickers. For information on package IDs, see the Sticker list. 30 | /// 31 | /// 32 | /// Sticker ID. For a list of sticker IDs for stickers that can be sent with the Messaging API, see the Sticker list. 33 | /// 34 | /// 35 | /// QuickReply 36 | /// 37 | public StickerMessage(string packageId, string stickerId, QuickReply quickReply = null) 38 | { 39 | PackageId = packageId; 40 | StickerId = stickerId; 41 | QuickReply = quickReply; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/CarouselTemplate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Template message with multiple columns which can be cycled like a carousel. 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#carousel 8 | /// 9 | public class CarouselTemplate : ITemplate 10 | { 11 | public TemplateType Type { get; } = TemplateType.Carousel; 12 | 13 | /// 14 | /// Array of columns 15 | /// Max: 10 16 | /// 17 | public IList Columns { get; } 18 | 19 | /// 20 | /// Aspect ratio of the image. Specify one of the following values: 21 | /// rectangle: 1.51:1 22 | /// square: 1:1 23 | /// The default value is rectangle. 24 | /// 25 | public ImageAspectRatioType ImageAspectRatio { get; } 26 | 27 | /// 28 | /// Size of the image. Specify one of the following values: 29 | /// cover: The image fills the entire image area.Parts of the image that do not fit in the area are not displayed. 30 | /// contain: The entire image is displayed in the image area.A background is displayed in the unused areas to the left and right of vertical images and in the areas above and below horizontal images. 31 | /// The default value is cover. 32 | /// 33 | public ImageSizeType ImageSize { get; } 34 | 35 | /// 36 | /// Constructor 37 | /// 38 | /// 39 | /// Array of columns 40 | /// Max: 10 41 | /// 42 | /// 43 | /// Aspect ratio of the image. Specify one of the following values: 44 | /// rectangle: 1.51:1 45 | /// square: 1:1 46 | /// The default value is rectangle. 47 | /// 48 | /// 49 | /// Size of the image. Specify one of the following values: 50 | /// cover: The image fills the entire image area.Parts of the image that do not fit in the area are not displayed. 51 | /// contain: The entire image is displayed in the image area.A background is displayed in the unused areas to the left and right of vertical images and in the areas above and below horizontal images. 52 | /// The default value is cover. 53 | /// 54 | public CarouselTemplate(IList columns = null, 55 | ImageAspectRatioType imageAspectRatio = ImageAspectRatioType.Rectangle, ImageSizeType imageSize = ImageSizeType.Cover) 56 | { 57 | Columns = columns ?? new List(); 58 | ImageAspectRatio = imageAspectRatio; 59 | ImageSize = imageSize; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ConfirmTemplate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Line.Messaging 5 | { 6 | /// 7 | /// Template message with two action buttons. 8 | /// 9 | public class ConfirmTemplate : ITemplate 10 | { 11 | public TemplateType Type { get; } = TemplateType.Confirm; 12 | 13 | /// 14 | /// Message text 15 | /// Max: 240 characters 16 | /// 17 | public string Text { get; } 18 | 19 | /// 20 | /// Action when tapped 21 | /// Set 2 actions for the 2 buttons 22 | /// 23 | public IList Actions { get; } 24 | 25 | 26 | /// 27 | /// Constructor 28 | /// 29 | /// 30 | /// Message text 31 | /// Max: 240 characters 32 | /// 33 | /// 34 | /// Action when tapped 35 | /// Set 2 actions for the 2 buttons 36 | /// 37 | public ConfirmTemplate(string text, IList actions = null) 38 | { 39 | Text = text.Substring(0, Math.Min(text.Length, 240)); 40 | Actions = actions ?? new List(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ITemplate.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public interface ITemplate 4 | { 5 | TemplateType Type { get; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ITemplateAction.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public interface ITemplateAction 4 | { 5 | TemplateActionType Type { get; } 6 | string Label { get; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ImageAspectRatioType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum ImageAspectRatioType 4 | { 5 | /// 6 | /// 1.51:1 7 | /// 8 | Rectangle, 9 | 10 | /// 11 | /// 1:1 12 | /// 13 | Square 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ImageCarouselColumn.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Column object for image carousel 5 | /// 6 | public class ImageCarouselColumn 7 | { 8 | /// 9 | /// Image URL (Max: 1000 characters) 10 | /// HTTPS 11 | /// JPEG or PNG 12 | /// Aspect ratio: 1:1 13 | /// Max width: 1024px 14 | /// Max: 1 MB 15 | /// 16 | public string ImageUrl { get; } 17 | 18 | /// 19 | /// Action when image is tapped 20 | /// 21 | public ITemplateAction Action { get; } 22 | 23 | /// 24 | /// Constructor 25 | /// 26 | /// 27 | /// Image URL (Max: 1000 characters) 28 | /// HTTPS 29 | /// JPEG or PNG 30 | /// Aspect ratio: 1:1 31 | /// Max width: 1024px 32 | /// Max: 1 MB 33 | /// 34 | /// 35 | /// Action when image is tapped 36 | /// 37 | public ImageCarouselColumn(string imageUrl, ITemplateAction action) 38 | { 39 | ImageUrl = imageUrl; 40 | Action = action; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ImageCarouselTemplate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Template with multiple images which can be cycled like a carousel. 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#image-carousel 8 | /// 9 | public class ImageCarouselTemplate : ITemplate 10 | { 11 | public TemplateType Type { get; } = TemplateType.Image_carousel; 12 | 13 | /// 14 | /// Array of columns 15 | /// Max: 10 16 | /// 17 | public IList Columns { get; } 18 | 19 | /// 20 | /// Constructor 21 | /// 22 | /// 23 | /// Array of columns 24 | /// Max: 10 25 | /// 26 | public ImageCarouselTemplate(IList columns = null) 27 | { 28 | Columns = columns ?? new List(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/ImageSizeType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum ImageSizeType 4 | { 5 | /// 6 | /// The image fills the entire image area. Parts of the image that do not fit in the area are not displayed. 7 | /// 8 | Cover, 9 | 10 | /// 11 | /// The entire image is displayed in the image area. 12 | /// A background is displayed in the unused areas to the left and right of vertical images and in the areas above and below horizontal images. 13 | /// 14 | Contain 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/Template/TemplateType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | public enum TemplateType 4 | { 5 | Buttons, 6 | Confirm, 7 | Carousel, 8 | Image_carousel 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/TemplateMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Template messages are messages with predefined layouts which you can customize. There are four types of templates available that can be used to interact with users through your bot. 7 | /// 8 | public class TemplateMessage : ISendMessage 9 | { 10 | public MessageType Type { get; } = MessageType.Template; 11 | 12 | 13 | /// 14 | /// These properties are used for the quick reply feature 15 | /// 16 | public QuickReply QuickReply { get; set; } 17 | 18 | 19 | /// 20 | /// A Buttons, Confirm, Carousel, or Image Carousel object. 21 | /// 22 | public ITemplate Template { get; } 23 | 24 | /// 25 | /// Alternative text. 26 | /// Max: 400 characters 27 | /// 28 | public string AltText { get; } 29 | 30 | /// 31 | /// Constructor 32 | /// 33 | /// 34 | /// Alternative text. 35 | /// Max: 400 characters 36 | /// 37 | /// 38 | /// A Buttons, Confirm, Carousel, or Image Carousel object. 39 | /// 40 | /// 41 | /// QuickRepy 42 | /// 43 | public TemplateMessage(string altText, ITemplate template, QuickReply quickReply = null) 44 | { 45 | AltText = altText.Substring(0, Math.Min(altText.Length, 400)); 46 | Template = template; 47 | QuickReply = quickReply; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/TextMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging 4 | { 5 | /// 6 | /// Text 7 | /// https://developers.line.me/en/docs/messaging-api/reference/#text 8 | /// 9 | public class TextMessage : ISendMessage 10 | { 11 | public MessageType Type { get; } = MessageType.Text; 12 | 13 | /// 14 | /// These properties are used for the quick reply feature 15 | /// 16 | public QuickReply QuickReply { get; set; } 17 | 18 | /// 19 | /// Message text 20 | /// Max: 2000 characters 21 | /// 22 | public string Text { get; set; } 23 | 24 | /// 25 | /// Constructor 26 | /// 27 | /// 28 | /// Message text 29 | /// Max: 2000 characters 30 | /// 31 | /// 32 | /// QuickReply 33 | /// 34 | public TextMessage(string text, QuickReply quickReply = null) 35 | { 36 | Text = text.Substring(0, Math.Min(text.Length, 2000)); 37 | QuickReply = quickReply; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Line.Messaging/Messages/VideoMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging 2 | { 3 | /// 4 | /// Video 5 | /// https://developers.line.me/en/docs/messaging-api/reference/#video 6 | /// 7 | public class VideoMessage : ISendMessage 8 | { 9 | public MessageType Type { get; } = MessageType.Video; 10 | 11 | /// 12 | /// These properties are used for the quick reply feature 13 | /// 14 | public QuickReply QuickReply { get; set; } 15 | 16 | /// 17 | /// URL of video file (Max: 1000 characters) 18 | /// HTTPS 19 | /// mp4 20 | /// Less than 1 minute 21 | /// Max: 10 MB 22 | /// 23 | public string OriginalContentUrl { get; } 24 | 25 | /// 26 | /// URL of preview image (Max: 1000 characters) 27 | /// HTTPS 28 | /// JPEG 29 | /// Max: 240 x 240 30 | /// Max: 1 MB 31 | /// 32 | public string PreviewImageUrl { get; set; } 33 | 34 | /// 35 | /// Constructor 36 | /// 37 | /// 38 | /// URL of video file (Max: 1000 characters) 39 | /// HTTPS 40 | /// mp4 41 | /// Less than 1 minute 42 | /// Max: 10 MB 43 | /// 44 | /// 45 | /// URL of preview image (Max: 1000 characters) 46 | /// HTTPS 47 | /// JPEG 48 | /// Max: 240 x 240 49 | /// Max: 1 MB 50 | /// 51 | /// 52 | /// QuickReply 53 | /// 54 | public VideoMessage(string originalContentUrl, string previerImageUrl, QuickReply quickReply = null) 55 | { 56 | OriginalContentUrl = originalContentUrl; 57 | PreviewImageUrl = previerImageUrl; 58 | QuickReply = quickReply; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/AccountLinkEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when a user has linked his/her LINE account with a provider's service account. You can reply to account link events. 5 | /// If the link token has expired or has already been used, no webhook event will be sent and the user will be shown an error. 6 | /// 7 | public class AccountLinkEvent : ReplyableEvent 8 | { 9 | /// 10 | /// Link Object 11 | /// 12 | public Link Link { get; } 13 | 14 | public AccountLinkEvent(WebhookEventSource source, long timestamp, string replyToken, Link link) 15 | : base(WebhookEventType.AccountLink, source, timestamp, replyToken) 16 | { 17 | Link = link; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/Beacon.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Line Beacon 5 | /// 6 | public class Beacon 7 | { 8 | /// 9 | /// Hardware ID of the beacon that was detected 10 | /// 11 | public string Hwid { get; } 12 | 13 | /// 14 | /// Type of beacon event 15 | /// 16 | public BeaconType Type { get; } 17 | 18 | /// 19 | /// Optional. Device message of beacon that was detected 20 | /// The "device message" consists of data generated by the beacon to send notifications to bots. The beacon.dm property is only included in webhooks from devices that support the "device message" property. You can use beacon.dm with the LINE Simple Beacon specification. For more information, see the LINE Simple Beacon specification. 21 | /// 22 | public string Dm { get; } 23 | 24 | public Beacon(string hwid, BeaconType type, string dm) 25 | { 26 | Hwid = hwid; 27 | Type = type; 28 | Dm = dm; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/BeaconEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when a user enters or leaves the range of a LINE Beacon. You can reply to beacon events. 5 | /// https://developers.line.me/en/docs/messaging-api/reference/#beacon-event 6 | /// 7 | public class BeaconEvent : ReplyableEvent 8 | { 9 | public Beacon Beacon { get; } 10 | 11 | public BeaconEvent(WebhookEventSource source, long timestamp, string replyToken, string hwid, BeaconType beaconType, string dm) 12 | : base(WebhookEventType.Beacon, source, timestamp, replyToken) 13 | { 14 | Beacon = new Beacon(hwid, beaconType, dm); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/BeaconType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | public enum BeaconType 4 | { 5 | /// 6 | /// Entered beacon's reception range 7 | /// 8 | Enter, 9 | /// 10 | /// Left beacon's reception range 11 | /// 12 | Leave, 13 | /// 14 | /// Tapped beacon banner 15 | /// 16 | Banner 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/ContentProvider.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Content provider of media message 5 | /// 6 | public class ContentProvider 7 | { 8 | /// 9 | /// Content Provider Type 10 | /// 11 | public ContentProviderType Type { get; } 12 | 13 | /// 14 | /// URL of the media file. Only included when contentProvider.type is external. 15 | /// 16 | public string OriginalContentUrl { get; } 17 | 18 | 19 | /// 20 | /// URL of the preview image. Only included when contentProvider.type is external. 21 | /// 22 | public string PreviewImageUrl { get; } 23 | 24 | /// 25 | /// Constructor 26 | /// 27 | /// 28 | /// Provider of the media file. 29 | /// / line: LINE.The binary media data can be retrieved from the content endpoint. 30 | /// / external: Provider other than LINE 31 | /// 32 | /// 33 | /// URL of the media file. Only included when contentProvider.type is external. 34 | /// 35 | /// 36 | /// URL of the preview image. Only included when contentProvider.type is external. 37 | /// 38 | public ContentProvider(ContentProviderType type, string originalContentUrl, string previewImageUrl) 39 | { 40 | Type = type; 41 | OriginalContentUrl = originalContentUrl; 42 | PreviewImageUrl = previewImageUrl; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/ContentProviderType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Provider of the media file. 5 | /// 6 | public enum ContentProviderType 7 | { 8 | /// 9 | /// LINE. The binary media data can be retrieved from the content endpoint. 10 | /// 11 | Line, 12 | /// 13 | /// Provider other than LINE 14 | /// 15 | External 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/DeviceEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | public abstract class DeviceEvent : WebhookEvent 4 | { 5 | public Things Things { get; } 6 | public DeviceEvent(WebhookEventSource source, long timestamp, Things things) 7 | : base(WebhookEventType.Things, source, timestamp) 8 | { 9 | Things = things; 10 | } 11 | 12 | public static DeviceEvent Create(WebhookEventSource source, long timestamp, Things things) 13 | { 14 | return (things.Type == ThingsType.Link) 15 | ? new DeviceLinkEvent(source, timestamp, things) as DeviceEvent 16 | : new DeviceUnlinkEvent(source, timestamp, things) as DeviceEvent; 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/DeviceLinkEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Indicates that a LINE Things-compatible device has been linked with LINE by a user operation. For more information, see Receiving device link events via webhook. 5 | /// 6 | public class DeviceLinkEvent : DeviceEvent 7 | { 8 | public DeviceLinkEvent(WebhookEventSource source, long timestamp, Things things) : base(source, timestamp, things) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/DeviceUnLinkEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Indicates that a LINE Things-compatible device has been unlinked from LINE by a user operation. For more information, see Receiving device unlink events via webhook. 5 | /// 6 | public class DeviceUnlinkEvent : DeviceEvent 7 | { 8 | public DeviceUnlinkEvent(WebhookEventSource source, long timestamp, Things things) : base(source, timestamp, things) 9 | { 10 | } 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/EventMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging.Webhooks 4 | { 5 | /// 6 | /// Contents of the message 7 | /// 8 | public class EventMessage 9 | { 10 | /// 11 | /// Message ID 12 | /// 13 | public string Id { get; } 14 | 15 | /// 16 | /// EventMessageType 17 | /// 18 | public EventMessageType Type { get; } 19 | 20 | public EventMessage(EventMessageType type, string id) 21 | { 22 | Type = type; 23 | Id = id; 24 | } 25 | 26 | internal static EventMessage CreateFrom(dynamic dynamicObject) 27 | { 28 | var message = dynamicObject?.message; 29 | if (message == null) { return null; } 30 | if (!Enum.TryParse((string)message.type, true, out EventMessageType messageType)) 31 | { 32 | return null; 33 | } 34 | switch (messageType) 35 | { 36 | case EventMessageType.Text: 37 | return new TextEventMessage((string)message.id, (string)message.text); 38 | case EventMessageType.Image: 39 | case EventMessageType.Audio: 40 | case EventMessageType.Video: 41 | ContentProvider contentProvider = null; 42 | if (Enum.TryParse((string)message.contentProvider?.type,true, out ContentProviderType providerType)) 43 | { 44 | contentProvider = new ContentProvider(providerType, 45 | (string)message.contentProvider?.originalContentUrl, 46 | (string)message.contentProvider?.previewContentUrl); 47 | } 48 | return new MediaEventMessage(messageType, (string)message.id, contentProvider, (int?)message.duration); 49 | case EventMessageType.Location: 50 | return new LocationEventMessage((string)message.id, (string)message.title, (string)message.address, 51 | (decimal)message.latitude, (decimal)message.longitude); 52 | case EventMessageType.Sticker: 53 | return new StickerEventMessage((string)message.id, (string)message.packageId, (string)message.stickerId); 54 | case EventMessageType.File: 55 | return new FileEventMessage((string)message.id, (string)message.fileName, (long)message.fileSize); 56 | default: 57 | return null; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/EventMessageType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Webhook event message types. 5 | /// 6 | public enum EventMessageType 7 | { 8 | Text, 9 | Image, 10 | Video, 11 | Audio, 12 | Location, 13 | Sticker, 14 | File 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/EventSourceType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Webhook Event Source Type. 5 | /// 6 | public enum EventSourceType 7 | { 8 | User, 9 | Group, 10 | Room 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/FileEventMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Message object which contains the file sent from the source. The binary data can be retrieved from the content endpoint. 5 | /// 6 | public class FileEventMessage : EventMessage 7 | { 8 | /// 9 | /// file name 10 | /// 11 | public string FileName { get; } 12 | 13 | /// 14 | /// File size in bytes 15 | /// 16 | public long FileSize { get; } 17 | 18 | public FileEventMessage(string id, string fileName, long fileSize) : base(EventMessageType.File, id) 19 | { 20 | FileName = fileName; 21 | FileSize = fileSize; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/FollowEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when your account is added as a friend (or unblocked). You can reply to follow events. 5 | /// 6 | public class FollowEvent : ReplyableEvent 7 | { 8 | public FollowEvent(WebhookEventSource source, long timestamp, string replyToken) 9 | : base(WebhookEventType.Follow, source, timestamp, replyToken) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/JoinEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when your account joins a group or talk room. You can reply to join events. 5 | /// 6 | public class JoinEvent : ReplyableEvent 7 | { 8 | public JoinEvent(WebhookEventSource source, long timestamp, string replyToken) 9 | : base(WebhookEventType.Join, source, timestamp, replyToken) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/LeaveEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when your account leaves a group. 5 | /// No event is generated when your account leaves a room. 6 | /// Leave events are not generated if you leave a group or room using leave group or leave room. 7 | /// 8 | public class LeaveEvent : WebhookEvent 9 | { 10 | public LeaveEvent(WebhookEventSource source, long timestamp) 11 | : base(WebhookEventType.Leave, source, timestamp) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/Link.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Link Object 5 | /// 6 | public class Link 7 | { 8 | /// 9 | /// One of the following values to indicate whether the link was successful or not. 10 | /// 11 | /// 12 | /// ok: Indicates the link was successful. 13 | /// 14 | /// 15 | /// failed: Indicates the link failed for any reason, such as due to a user impersonation. 16 | /// 17 | /// 18 | /// 19 | public LinkResult Result { get; } 20 | 21 | /// 22 | /// Specified nonce when verifying the user ID 23 | /// https://developers.line.me/en/docs/messaging-api/linking-accounts#verifying-user-id 24 | /// 25 | public string Nonce { get; } 26 | 27 | /// 28 | /// Constructor 29 | /// 30 | /// 31 | /// One of the following values to indicate whether the link was successful or not. 32 | /// 33 | /// 34 | /// ok: Indicates the link was successful. 35 | /// 36 | /// 37 | /// failed: Indicates the link failed for any reason, such as due to a user impersonation. 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// Specified nonce when verifying the user ID 43 | /// https://developers.line.me/en/docs/messaging-api/linking-accounts#verifying-user-id 44 | /// 45 | public Link(string result, string nonce) 46 | { 47 | Result = (result == "ok") ? LinkResult.OK : LinkResult.Failed; 48 | Nonce = nonce; 49 | } 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/LinkResult.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | 4 | public enum LinkResult 5 | { 6 | OK, 7 | Failed 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/LocationEventMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Message object which contains the location data sent from the source. 5 | /// 6 | public class LocationEventMessage : EventMessage 7 | { 8 | /// 9 | /// Title 10 | /// 11 | public string Title { get; } 12 | 13 | /// 14 | /// Address 15 | /// 16 | public string Address { get; } 17 | 18 | /// 19 | /// Latitude 20 | /// 21 | public decimal Latitude { get; } 22 | 23 | /// 24 | /// Longitude 25 | /// 26 | public decimal Longitude { get; } 27 | 28 | public LocationEventMessage(string id, string title, string address, decimal latitude, decimal longitude) : base(EventMessageType.Location, id) 29 | { 30 | Title = title; 31 | Address = address; 32 | Latitude = latitude; 33 | Longitude = longitude; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/MemberJoinEvent.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging.Webhooks 4 | { 5 | /// 6 | /// Event object for when a user joins a group or room that the bot is in. 7 | /// 8 | public class MemberJoinEvent : ReplyableEvent 9 | { 10 | /// 11 | /// User ID of users who joined 12 | /// 13 | public Moved Joined { get; } 14 | 15 | public MemberJoinEvent(WebhookEventSource source, long timestamp, string replyToken, IList members) 16 | : base(WebhookEventType.MemberJoined, source, timestamp, replyToken) 17 | { 18 | Joined = new Moved(members); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/MemberLeaveEvent.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging.Webhooks 4 | { 5 | /// 6 | /// Event object for when a user leaves a group or room that the bot is in. 7 | /// 8 | public class MemberLeaveEvent : WebhookEvent 9 | { 10 | /// 11 | /// User ID of users who left 12 | /// 13 | public Moved Left { get; } 14 | 15 | public MemberLeaveEvent(WebhookEventSource source, long timestamp, IList members) 16 | : base(WebhookEventType.MemberLeft, source, timestamp) 17 | { 18 | Left = new Moved(members); 19 | } 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/MessageEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object which contains the sent message. The message field contains a message object which corresponds with the message type. You can reply to message events. 5 | /// 6 | public class MessageEvent : ReplyableEvent 7 | { 8 | /// 9 | /// Contents of the message 10 | /// 11 | public EventMessage Message { get; } 12 | 13 | public MessageEvent(WebhookEventSource source, long timestamp, EventMessage message, string replyToken) 14 | : base(WebhookEventType.Message, source, timestamp, replyToken) 15 | { 16 | Message = message; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/MidiaEventMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Media event message (Image, Video or Audio) 5 | /// 6 | public class MediaEventMessage : EventMessage 7 | { 8 | /// 9 | /// ContentProvider 10 | /// 11 | public ContentProvider ContentProvider { get; } 12 | 13 | /// 14 | /// Length of media file (milliseconds) 15 | /// 16 | public int? Duration { get; } 17 | 18 | /// 19 | /// Constructor 20 | /// 21 | /// Event Message Type 22 | /// Message ID 23 | /// ContentProvider Object 24 | /// Duration 25 | public MediaEventMessage(EventMessageType type, string id, ContentProvider contentProvider = null, int? duration = null) : base(type, id) 26 | { 27 | ContentProvider = contentProvider; 28 | Duration = duration; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/Moved.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Line.Messaging.Webhooks 4 | { 5 | /// 6 | /// Joined or left Members 7 | /// 8 | public class Moved 9 | { 10 | /// 11 | /// Joined or left Members 12 | /// 13 | public IList Members { get; } 14 | 15 | /// 16 | /// Constructor 17 | /// 18 | /// 19 | /// Joined or left Members 20 | /// 21 | public Moved(IList members) 22 | { 23 | Members = members; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/Postback.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Postback 5 | /// 6 | public class Postback 7 | { 8 | /// 9 | /// Postback data 10 | /// 11 | public string Data { get; } 12 | 13 | /// 14 | /// date and time selected by a user through a datetime picker action. 15 | /// Only returned for postback actions via the datetime picker. 16 | /// 17 | public PostbackParams Params { get; } 18 | 19 | public Postback(string data, string date, string time, string datetime) 20 | { 21 | Data = data; 22 | Params = new PostbackParams(date, time, datetime); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/PostbackEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when a user performs an action on a template message which initiates a postback. You can reply to postback events. 5 | /// 6 | public class PostbackEvent : ReplyableEvent 7 | { 8 | /// 9 | /// Postback 10 | /// 11 | public Postback Postback { get; } 12 | 13 | public PostbackEvent(WebhookEventSource source, long timestamp, string replyToken, Postback postback) 14 | : base(WebhookEventType.Postback, source, timestamp, replyToken) 15 | { 16 | Postback = postback; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/PostbackParams.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace Line.Messaging.Webhooks 5 | { 6 | /// 7 | /// Object with the date and time selected by a user through a datetime picker action. The full-date, time-hour, and time-minute formats follow the RFC3339 protocol. 8 | /// 9 | public class PostbackParams 10 | { 11 | /// 12 | /// Date selected by user. Only included in the date mode. Format: full-date 13 | /// 14 | public string Date { get; } 15 | 16 | /// 17 | /// Time selected by the user. Only included in the time mode. Format: time-hour ":" time-minute 18 | /// 19 | public string Time { get; } 20 | 21 | /// 22 | /// Date and time selected by the user. Only included in the datetime mode. Format: full-date "T" time-hour ":" time-minute 23 | /// 24 | public string DateTime { get; } 25 | 26 | public PostbackParams(string date, string time, string datetime) 27 | { 28 | if (date != null && !Regex.Match(date, @"^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$").Success) 29 | { 30 | throw new ArgumentException($"Date format must be \"yyyy-MM-dd\".", nameof(date)); 31 | } 32 | if (time != null && !Regex.Match(time, @"^([01][0-9]|2[0-3]):([0-5][0-9])$").Success) 33 | { 34 | throw new ArgumentException($"Time format must be \"HH:mm\".", nameof(time)); 35 | } 36 | if (datetime != null && !Regex.Match(datetime, @"^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):([0-5][0-9])$").Success) 37 | { 38 | throw new ArgumentException("Date-Time format must be \"yyyy-MM-ddTHH:mm\".", nameof(datetime)); 39 | } 40 | 41 | Date = date; 42 | Time = time; 43 | DateTime = datetime; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/ReplyableEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | public abstract class ReplyableEvent : WebhookEvent 4 | { 5 | public string ReplyToken { get; } 6 | 7 | public ReplyableEvent(WebhookEventType eventType, WebhookEventSource source, long timestamp, string replyToken) 8 | : base(eventType, source, timestamp) 9 | { 10 | ReplyToken = replyToken; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/StickerEventMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Message object which contains the sticker data sent from the source. For a list of basic LINE stickers and sticker IDs, see sticker list. 5 | /// 6 | public class StickerEventMessage : EventMessage 7 | { 8 | public string PackageId { get; } 9 | 10 | public string StickerId { get; } 11 | 12 | public StickerEventMessage(string id, string packageId, string stickerId) : base(EventMessageType.Sticker, id) 13 | { 14 | PackageId = packageId; 15 | StickerId = stickerId; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/TextEventMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Message object which contains the text sent from the source. 5 | /// 6 | public class TextEventMessage : EventMessage 7 | { 8 | public string Text { get; } 9 | 10 | public TextEventMessage(string id, string text) : base(EventMessageType.Text, id) 11 | { 12 | Text = text; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/Things.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// LINE Things 5 | /// 6 | public class Things 7 | { 8 | /// 9 | /// Device ID of the LINE Things-compatible device that was linked with LINE 10 | /// 11 | public string DeviceId { get; } 12 | 13 | /// 14 | /// Link or Unlink 15 | /// 16 | public ThingsType Type { get; } 17 | 18 | /// 19 | /// Constructor 20 | /// 21 | /// Device ID of the LINE Things-compatible device that was linked with LINE 22 | /// Link or Unlink 23 | public Things(string deviceId, ThingsType type) 24 | { 25 | DeviceId = deviceId; 26 | Type = type; 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/ThingsType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Things Types 5 | /// 6 | public enum ThingsType 7 | { 8 | Link, 9 | Unlink, 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/UnfollowEvent.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Event object for when your account is blocked. 5 | /// 6 | public class UnfollowEvent : WebhookEvent 7 | { 8 | public UnfollowEvent(WebhookEventSource source, long timestamp) 9 | : base(WebhookEventType.Unfollow, source, timestamp) 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/WebhookEventParser.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace Line.Messaging.Webhooks 5 | { 6 | public static class WebhookEventParser 7 | { 8 | public static IEnumerable Parse(string webhookContent) 9 | { 10 | dynamic dynamicObject = JsonConvert.DeserializeObject(webhookContent); 11 | if (dynamicObject == null) { yield break; } 12 | 13 | foreach (var ev in dynamicObject.events) 14 | { 15 | var webhookEvent = WebhookEvent.CreateFrom(ev); 16 | if (webhookEvent == null) { continue; } 17 | yield return webhookEvent; 18 | } 19 | } 20 | 21 | public static IEnumerable ParseEvents(dynamic events) 22 | { 23 | foreach (var ev in events) 24 | { 25 | var webhookEvent = WebhookEvent.CreateFrom(ev); 26 | if (webhookEvent == null) { continue; } 27 | yield return webhookEvent; 28 | } 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/WebhookEventSource.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Line.Messaging.Webhooks 4 | { 5 | /// 6 | /// Webhook Event Source. Source could be User, Group or Room. 7 | /// 8 | public class WebhookEventSource 9 | { 10 | public EventSourceType Type { get; } 11 | 12 | /// 13 | /// User, Group or Room Id 14 | /// 15 | public string Id { get; } 16 | 17 | /// 18 | /// UserId of the Group or Room 19 | /// 20 | public string UserId { get; } 21 | 22 | public WebhookEventSource(EventSourceType type, string sourceId, string userId) 23 | { 24 | Type = type; 25 | Id = sourceId; 26 | UserId = userId; 27 | } 28 | 29 | internal static WebhookEventSource CreateFrom(dynamic source) 30 | { 31 | if (source == null) { return null; } 32 | if (!Enum.TryParse((string)source.type, true, out EventSourceType sourceType)) 33 | { 34 | return null; 35 | } 36 | var sourceId = ""; 37 | switch (sourceType) 38 | { 39 | case EventSourceType.User: 40 | sourceId = (string)source.userId; 41 | break; 42 | case EventSourceType.Group: 43 | sourceId = (string)source.groupId; 44 | break; 45 | case EventSourceType.Room: 46 | sourceId = (string)source.roomId; 47 | break; 48 | default: 49 | return null; 50 | } 51 | return new WebhookEventSource(sourceType, sourceId, (string)source.userId); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Line.Messaging/Webhooks/WebhookEventType.cs: -------------------------------------------------------------------------------- 1 | namespace Line.Messaging.Webhooks 2 | { 3 | /// 4 | /// Webhook Event Type 5 | /// 6 | public enum WebhookEventType 7 | { 8 | Message, 9 | Follow, 10 | Unfollow, 11 | Join, 12 | Leave, 13 | Postback, 14 | Beacon, 15 | AccountLink, 16 | MemberJoined, 17 | MemberLeft, 18 | Things 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Line.MessagingTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | [assembly: AssemblyTitle("Line.MessagingTest")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("Line.MessagingTest")] 10 | [assembly: AssemblyCopyright("Copyright © 2017")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | 14 | [assembly: ComVisible(false)] 15 | 16 | [assembly: Guid("7062faf3-9d96-4384-a486-a1d2bb68bc16")] 17 | 18 | // [assembly: AssemblyVersion("1.0.*")] 19 | [assembly: AssemblyVersion("1.0.0.0")] 20 | [assembly: AssemblyFileVersion("1.0.0.0")] 21 | -------------------------------------------------------------------------------- /Line.MessagingTest/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ProjectTemplate/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 pierre3 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ProjectTemplate/ProjectTemplates/CSharp/Cloud/LINEBotApplication.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ProjectTemplate/ProjectTemplates/CSharp/Cloud/LINEBotApplication.zip -------------------------------------------------------------------------------- /ProjectTemplate/ProjectTemplates/CSharp/Cloud/LineBotFunction.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ProjectTemplate/ProjectTemplates/CSharp/Cloud/LineBotFunction.zip -------------------------------------------------------------------------------- /ProjectTemplate/ProjectTemplates/CSharp/Cloud/LineWithBotFrameworkApplication.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ProjectTemplate/ProjectTemplates/CSharp/Cloud/LineWithBotFrameworkApplication.zip -------------------------------------------------------------------------------- /ProjectTemplate/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("VsixLineBotFunction")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("VsixLineBotFunction")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // Version information for an assembly consists of the following four values: 23 | // 24 | // Major Version 25 | // Minor Version 26 | // Build Number 27 | // Revision 28 | // 29 | // You can specify all the values or you can default the Build and Revision Numbers 30 | // by using the '*' as shown below: 31 | // [assembly: AssemblyVersion("1.0.*")] 32 | [assembly: AssemblyVersion("1.0.0.0")] 33 | [assembly: AssemblyFileVersion("1.0.0.0")] 34 | -------------------------------------------------------------------------------- /ProjectTemplate/README.md: -------------------------------------------------------------------------------- 1 | # C# LINE Messaging API Visual Studio Templates 2 | 3 | [日本語の説明はこちら](./README_JP.md) 4 | 5 | This folder contains Visual Studio Extension project for C# Project templates. The compiled vsix is on [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=pierre3.LINEBotCSharpTemplate) as Visual Studio Extension. 6 | 7 | In this README, you see how to import the extension to Visual Studio and use it. 8 | 9 | # How to use the extension 10 | 11 | ## Install the extension 12 | 1. Open Visual Studio and go to Tools | Extensions and Updates. 13 | 1. Select "Online" on the left pane and search for "LINE Bot C# Template", and click "Download".
14 | ![ExtensionSearch.PNG](../ImagesForREADME/ExtensionSearch.PNG) 15 | 1. Restart Visual Studio and it will be installed. 16 | 17 | ## Use the project templates 18 | Once you installed the extension, it's straight forward. 19 | 20 | 1. Open Visual Studio and "Create new project". 21 | 1. Search "LINE Bot" and you see several projcts comes up.
22 | ![LINEBotTemplates.PNG](../ImagesForREADME/LINEBotTemplates.PNG) 23 | 1. Select any project to start. 24 | 25 | For detail, checkout each directory in this repository. 26 | -------------------------------------------------------------------------------- /ProjectTemplate/README_JP.md: -------------------------------------------------------------------------------- 1 | # C# LINE Messaging API Visual Studio テンプレート 2 | 3 | このディレクトリでは C# 版 LINE Messaging API プロジェクトテンプレート用の Visual Studio 拡張プロジェクトのソースを公開しています。コンパイル済みの VSIX は [Visual Studio マーケットプレース](https://marketplace.visualstudio.com/items?itemName=pierre3.LINEBotCSharpTemplate) に公開済です。 4 | 5 | # 拡張機能の使い方 6 | 7 | ## 拡張のインストール 8 | 1. Visual Studio を開いて、ツール | 拡張機能と更新プログラムを選択。 9 | 1. 左ペインの "オンライン" を選択して、"LINE Bot C# Template" を検索し、"ダウンロード" をクリック。
10 | ![ExtensionSearch_ja.PNG](../ImagesForREADME/ExtensionSearch_ja.PNG) 11 | 1. Visual Studio を再起動するとインストールが完了。 12 | 13 | ## テンプレートを使う 14 | インストールが終われば後は簡単です。 15 | 16 | 1. Visual Studio を開いて、新しいプロジェクトを作成。 17 | 1. "LINE Bot" で検索すると複数のプロジェクトテンプレートが表示される。
18 | ![LINEBotTemplates_ja.PNG](../ImagesForREADME/LINEBotTemplates_ja.PNG) 19 | 1. 利用したいプロジェクトを選択。 20 | 21 | 各テンプレートの詳細はそれぞれのフォルダをご覧ください。 -------------------------------------------------------------------------------- /ProjectTemplate/__TemplateIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/ProjectTemplate/__TemplateIcon.ico -------------------------------------------------------------------------------- /ProjectTemplate/ja-JP/Extension.vsixlangpack: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LINE Bot C# テンプレート 5 | LINE Messaging API を利用したLINE Bot アプリケーションを簡単に作成できるテンプレートです。このパッケージには以下のテンプレートが含まれます。 6 | - Azure Function 用テンプレート 7 | - Web App 用テンプレート 8 | 9 | 10 | -------------------------------------------------------------------------------- /ProjectTemplate/source.extension.vsixmanifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LINE Bot C# Template 6 | This package enables C# developer to imeplement LINE Bot by using LINE Messaging API. This contanis: 7 | - Azure Function template for LINE Bot 8 | - Web app templates for LINE Bot 9 | https://github.com/pierre3/LineMessagingApi 10 | LICENSE.txt 11 | Azure Function;LINE Bot 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ProjectTemplate/stylesheet.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | border: 0; 5 | color: #1E1E1E; 6 | font-size: 13px; 7 | font-family: "Segoe UI", Helvetica, Arial, sans-serif; 8 | line-height: 1.45; 9 | word-wrap: break-word; 10 | } 11 | 12 | /* General & 'Reset' Stuff */ 13 | 14 | 15 | .container { 16 | width: 980px; 17 | margin: 0 auto; 18 | } 19 | 20 | section { 21 | display: block; 22 | margin: 0; 23 | } 24 | 25 | h1, h2, h3, h4, h5, h6 { 26 | margin: 0; 27 | } 28 | 29 | /* Header,
30 | header - container 31 | h1 - project name 32 | h2 - project description 33 | */ 34 | 35 | #header { 36 | color: #FFF; 37 | background: #68217a; 38 | position:relative; 39 | } 40 | #hangcloud { 41 | width: 190px; 42 | height: 160px; 43 | background: url("../images/bannerart03.png"); 44 | position: absolute; 45 | top: 0; 46 | right: -30px; 47 | } 48 | h1, h2 { 49 | font-family: "Segoe UI Light", "Segoe UI", Helvetica, Arial, sans-serif; 50 | line-height: 1; 51 | margin: 0 18px; 52 | padding: 0; 53 | } 54 | #header h1 { 55 | font-size: 3.4em; 56 | padding-top: 18px; 57 | font-weight: normal; 58 | margin-left: 15px; 59 | } 60 | 61 | #header h2 { 62 | font-size: 1.5em; 63 | margin-top: 10px; 64 | padding-bottom: 18px; 65 | font-weight: normal; 66 | } 67 | 68 | 69 | #main_content { 70 | width: 100%; 71 | display: flex; 72 | flex-direction: row; 73 | } 74 | 75 | 76 | h1, h2, h3, h4, h5, h6 { 77 | font-weight: bolder; 78 | } 79 | 80 | #main_content h1 { 81 | font-size: 1.8em; 82 | margin-top: 34px; 83 | } 84 | 85 | #main_content h1:first-child { 86 | margin-top: 30px; 87 | } 88 | 89 | #main_content h2 { 90 | font-size: 1.4em; 91 | font-weight: bold; 92 | } 93 | p, ul { 94 | margin: 11px 18px; 95 | } 96 | 97 | #main_content a { 98 | color: #06C; 99 | text-decoration: none; 100 | } 101 | ul { 102 | margin-top: 13px; 103 | margin-left: 18px; 104 | padding-left: 0; 105 | } 106 | ul li { 107 | margin-left: 18px; 108 | padding-left: 0; 109 | } 110 | #lpanel { 111 | width: 620px; 112 | float: left; 113 | } 114 | #rpanel ul { 115 | list-style-type: none; 116 | width: 300px; 117 | } 118 | #rpanel ul li { 119 | line-height: 1.8em; 120 | } 121 | #rpanel { 122 | background: #e7e7e7; 123 | width: 360px; 124 | float: right; 125 | } 126 | 127 | #rpanel div { 128 | width: 300px; 129 | } 130 | -------------------------------------------------------------------------------- /WebAppSample/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace WebAppSample 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | // Web API configuration and services 13 | 14 | // Web API routes 15 | config.MapHttpAttributeRoutes(); 16 | 17 | config.Routes.MapHttpRoute( 18 | name: "ImagesController", 19 | routeTemplate: "images/{file}/{size}", 20 | defaults: new { controller = "Images", size = 1040 } 21 | ); 22 | 23 | config.Routes.MapHttpRoute( 24 | name: "DefaultApi", 25 | routeTemplate: "api/{controller}/{id}", 26 | defaults: new { id = RouteParameter.Optional } 27 | ); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /WebAppSample/CloudStorage/BlobStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Blob; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace WebAppSample.CloudStorage 10 | { 11 | public class BlobStorage 12 | { 13 | private CloudBlobClient _blobClient; 14 | private CloudBlobContainer _blobContainer; 15 | 16 | public BlobStorage(string connectionString) 17 | { 18 | var strageAccount = CloudStorageAccount.Parse(connectionString); 19 | _blobClient = strageAccount.CreateCloudBlobClient(); 20 | } 21 | 22 | public static async Task CreateAsync(string connectionString, string containerName) 23 | { 24 | var instance = new BlobStorage(connectionString); 25 | await instance.InitializeAsync(containerName); 26 | return instance; 27 | } 28 | 29 | public async Task InitializeAsync(string containerName) 30 | { 31 | _blobContainer = _blobClient.GetContainerReference(containerName); 32 | await _blobContainer.CreateIfNotExistsAsync(); 33 | await _blobContainer.SetPermissionsAsync( 34 | new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }); 35 | } 36 | 37 | public async Task UploadFromStreamAsync(Stream stream, string directoryName, string blobName) 38 | { 39 | var directory = _blobContainer.GetDirectoryReference(directoryName); 40 | var blob = directory.GetBlockBlobReference(blobName); 41 | await blob.UploadFromStreamAsync(stream); 42 | return blob.Uri; 43 | } 44 | 45 | public async Task DeleteImageAsync(string directoryName, string blobName) 46 | { 47 | var directory = _blobContainer.GetDirectoryReference(directoryName); 48 | var blob = directory.GetBlockBlobReference(blobName); 49 | await blob.DeleteIfExistsAsync(); 50 | } 51 | 52 | public async Task DeleteDirectoryAsync(string directoryName) 53 | { 54 | var directory = _blobContainer.GetDirectoryReference(directoryName); 55 | foreach (CloudBlob blob in (await directory.ListBlobsSegmentedAsync(new BlobContinuationToken())).Results) 56 | { 57 | await blob.DeleteIfExistsAsync(); 58 | } 59 | } 60 | 61 | public async Task> ListBlobUri(string directoryName) 62 | { 63 | var directory = _blobContainer.GetDirectoryReference(directoryName); 64 | return (await directory.ListBlobsSegmentedAsync(new BlobContinuationToken())).Results.Select(blob => blob.Uri); 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /WebAppSample/CloudStorage/TableStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Table; 3 | using System.Threading.Tasks; 4 | 5 | namespace WebAppSample.CloudStorage 6 | { 7 | 8 | public class TableStorage where T : TableEntity, new() 9 | { 10 | private CloudTableClient _tableClient; 11 | private CloudTable _table; 12 | 13 | protected TableStorage(string connectionString) 14 | { 15 | var strageAccount = CloudStorageAccount.Parse(connectionString); 16 | _tableClient = strageAccount.CreateCloudTableClient(); 17 | } 18 | 19 | protected async Task InitializeAsync(string tableName) 20 | { 21 | _table = _tableClient.GetTableReference(tableName); 22 | await _table.CreateIfNotExistsAsync(); 23 | } 24 | 25 | public static async Task> CreateAsync(string connectionString,string tableName) 26 | { 27 | var result = new TableStorage(connectionString); 28 | await result.InitializeAsync(tableName); 29 | return result; 30 | } 31 | 32 | public async Task AddAsync(string partitionKey, string rowKey) 33 | { 34 | if ((await FindAsync(partitionKey, rowKey)) != null) { return; } 35 | 36 | var newItem = new T() { PartitionKey = partitionKey, RowKey = rowKey }; 37 | await _table.ExecuteAsync(TableOperation.Insert(newItem)); 38 | } 39 | 40 | public async Task UpdateAsync(T item) 41 | { 42 | await _table.ExecuteAsync(TableOperation.InsertOrReplace(item)); 43 | } 44 | 45 | public async Task FindAsync(string partitionKey, string rowKey) 46 | { 47 | var ope = TableOperation.Retrieve(partitionKey, rowKey); 48 | var retrieveResult = await _table.ExecuteAsync(ope); 49 | if (retrieveResult.Result == null) { return null; } 50 | return (T)(retrieveResult.Result); 51 | } 52 | 53 | public async Task DeleteAsync(string partitionKey, string rowKey) 54 | { 55 | var item = await FindAsync(partitionKey, rowKey); 56 | if (item == null) { return; } 57 | 58 | var ope = TableOperation.Delete(item); 59 | await _table.ExecuteAsync(ope); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /WebAppSample/Controllers/ImagesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net; 4 | using System.Net.Http; 5 | using System.Threading.Tasks; 6 | using System.Web.Http; 7 | 8 | namespace WebAppSample.Controllers 9 | { 10 | public class ImagesController : ApiController 11 | { 12 | [HttpGet] 13 | public HttpResponseMessage Get(string file, string size) 14 | { 15 | var root = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; 16 | var path = Path.Combine(root, "Images", file, size + ".png"); 17 | 18 | var response = Request.CreateResponse(HttpStatusCode.OK); 19 | response.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read)); 20 | response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); 21 | response.Content.Headers.ContentDisposition.FileName = $"{size}.png"; 22 | response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); 23 | 24 | return response; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /WebAppSample/Controllers/LineBotController.cs: -------------------------------------------------------------------------------- 1 | using Line.Messaging.Webhooks; 2 | using Line.Messaging; 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Configuration; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Net.Http; 11 | using System.Security.Cryptography; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | using System.Web; 15 | using System.Web.Http; 16 | using WebAppSample.CloudStorage; 17 | using WebAppSample.Models; 18 | 19 | namespace WebAppSample.Controllers 20 | { 21 | public class LineBotController : ApiController 22 | { 23 | 24 | private static LineMessagingClient lineMessagingClient; 25 | private string accessToken = ConfigurationManager.AppSettings["ChannelAccessToken"]; 26 | private string channelSecret = ConfigurationManager.AppSettings["ChannelSecret"]; 27 | public LineBotController() 28 | { 29 | lineMessagingClient = new LineMessagingClient(accessToken); 30 | } 31 | 32 | /// 33 | /// POST: api/Messages 34 | /// Receive a message from a user and reply to it 35 | /// 36 | [HttpPost] 37 | public async Task Post(HttpRequestMessage request) 38 | { 39 | var events = await request.GetWebhookEventsAsync(channelSecret); 40 | var connectionString = ConfigurationManager.AppSettings["StorageConnectionString"]; 41 | var blobStorage = await BlobStorage.CreateAsync(connectionString, "linebotcontainer"); 42 | var eventSourceState = await TableStorage.CreateAsync(connectionString, "eventsourcestate"); 43 | 44 | var app = new LineBotApp(lineMessagingClient, eventSourceState, blobStorage); 45 | await app.RunAsync(events); 46 | 47 | return Request.CreateResponse(HttpStatusCode.OK); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /WebAppSample/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="WebAppSample.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /WebAppSample/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Routing; 7 | 8 | namespace WebAppSample 9 | { 10 | public class WebApiApplication : System.Web.HttpApplication 11 | { 12 | protected void Application_Start() 13 | { 14 | GlobalConfiguration.Configure(WebApiConfig.Register); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /WebAppSample/Images/GitHubIcon/1040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/WebAppSample/Images/GitHubIcon/1040.png -------------------------------------------------------------------------------- /WebAppSample/Images/GitHubIcon/240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/WebAppSample/Images/GitHubIcon/240.png -------------------------------------------------------------------------------- /WebAppSample/Images/GitHubIcon/300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/WebAppSample/Images/GitHubIcon/300.png -------------------------------------------------------------------------------- /WebAppSample/Images/GitHubIcon/460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/WebAppSample/Images/GitHubIcon/460.png -------------------------------------------------------------------------------- /WebAppSample/Images/GitHubIcon/700.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/WebAppSample/Images/GitHubIcon/700.png -------------------------------------------------------------------------------- /WebAppSample/Images/richmenu.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pierre3/LineMessagingApi/4d5c461cafadf417b54e21f98f826d1d8e8042d0/WebAppSample/Images/richmenu.PNG -------------------------------------------------------------------------------- /WebAppSample/Models/EventSourceLocation.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace WebAppSample.Models 4 | { 5 | public class EventSourceLocation : EventSourceState 6 | { 7 | public string Location { get; set; } 8 | 9 | public EventSourceLocation() { } 10 | } 11 | } -------------------------------------------------------------------------------- /WebAppSample/Models/EventSourceState.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace WebAppSample.Models 4 | { 5 | public class EventSourceState : TableEntity 6 | { 7 | [IgnoreProperty] 8 | public string SourceType { get { return PartitionKey; } set { PartitionKey = value; } } 9 | [IgnoreProperty] 10 | public string SourceId { get { return RowKey; } set { RowKey = value; } } 11 | 12 | public EventSourceState() { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /WebAppSample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebAppSample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebAppSample")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f0bd615e-05ef-490b-ae54-bff53fcd0a13")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /WebAppSample/README_JP.md: -------------------------------------------------------------------------------- 1 | # LINE Messaging API 用 C# Web App (API) サンプル 2 | 3 | このフォルダには、LINE Messaging API 用 C# Web App (API) サンプルが含まれています。ソリューションは .NET Framework 4.6.2 ベースです。Visual Studio テンプレートより同様のプロジェクトを作成することも可能です。[Visual Studio マーケットプレース](https://marketplace.visualstudio.com/items?itemName=pierre3.LINEBotCSharpTemplate). 4 | 5 | # セットアップ 6 | ## [前提条件] 7 | 以下のモジュールが必要です。 8 | 9 | - [Azure サブスクリプション](https://azure.microsoft.com) 10 | - [Visual Studio および ASP.NET と Web 開発ワークロード](https://www.visualstudio.com/vs/) 11 | - [git](https://git-scm.com/downloads) 12 | - [.NET Framework 4.6.2](https://www.microsoft.com/net/download/visual-studio-sdks) 13 | - [LINE 開発者アカウントおよび Messaging API アプリケーション](https://developers.line.me/en/) 14 | - [ngrok (ローカルテスト用)](https://ngrok.com/) 15 | 16 | ## [ソースコードの取得] 17 | zip ファイルをダウンロードして解凍するか、git clone コマンドでレポジトリをコピーします。テンプレートからも同様のプロジェクトを作成できます。 18 | 19 | ## [構成の更新] 20 | Web.config の設定を更新します。 21 | 22 | - StorageConnectionString: Azure ストレージの接続文字列 23 | - ChannelSecret: LINE Messaging API チャネルシークレット 24 | - ChannelAccessToken: LINE Messaging API アクセストークン 25 | 26 | # コンパイル、テストおよび公開 27 | ## [コンパイル] 28 | Visual Studio でコンパイルします。 29 | 1. Visual Studio でソリューションを開く。 30 | 1. ビルドメニューより ”ソリューションのビルド” を実行します。必要に応じてデバッグやリリース構成を切り替え。 31 | 32 | ## [ローカルでのテスト] 33 | ローカルでデバッグテストをしたい場合は、以下の手順を行います。 34 | 1. Visual Studio で Web App を右クリックし ”スタートアップ プロジェクトに設定” をクリック。 35 | ![SetWebAppStartUpProject_JA.PNG](../ImagesForREADME/SetWebAppStartUpProject_JA.PNG) 36 | 1. F5 を押下してデバッグを開始。ブラウザが開くのでポートを確認。(既定: 1590) 37 | 1. マンドプロンプトやターミナルを開いて、>ngrok http --host-header=localhost:1590 1590 を実行。ポートは環境に合わせて変更。出力された ngrok のアドレスをコピー。
38 | ![ngrok.PNG](../ImagesForREADME/ngrok.PNG) 39 | 1. [Line 開発者コンソール](https://developers.line.me/console/) を開き、Messaging API アプリケーションを開く。 40 | 1. "Webhook URL Requires SSL" 設定を ngrok URL に変更。/api/LineBot をつけ忘れないように注意。
41 | ![LINEWebhookUrl](../ImagesForREADME/LINEWebhookUrl.PNG) 42 | 43 | この状態で LINE アプリケーションよりボットにメッセージを送ると、ローカルのデバッグ環境に送信されます。コードを変更したい場合は Visual Studio のデバッグ実行を停止するだけで、ngrok のセッションは止めないでください。セッションが有効な限り、LINE 側の設定変更は不要です。 44 | 45 | ## [Web App の公開] 46 | Visual Studio から直接 Azure に公開できます。 47 | 1. プロジェクトを右クリックして、”発行” を選択。 48 | 1. ウィザードに従ってアプリケーションを公開。 49 | 1. ブラウザが開くので、URL を確認。 50 | 1. [Line 開発者コンソール](https://developers.line.me/console/) Messaging API アプリケーションを開く。 51 | 1. "Webhook URL Requires SSL" 設定を行更新。 52 | 1. LINE アプリケーションよりボットにメッセージを送信して動作確認。 -------------------------------------------------------------------------------- /WebAppSample/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /WebAppSample/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace WebAppWithBotFrameworkSample 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | // Web API configuration and services 13 | 14 | // Web API routes 15 | config.MapHttpAttributeRoutes(); 16 | 17 | config.Routes.MapHttpRoute( 18 | name: "DefaultApi", 19 | routeTemplate: "api/{controller}/{id}", 20 | defaults: new { id = RouteParameter.Optional } 21 | ); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/CloudStorage/BlobStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Blob; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | 9 | namespace WebAppWithBotFrameworkSample.CloudStorage 10 | { 11 | public class BlobStorage 12 | { 13 | private CloudBlobClient _blobClient; 14 | private CloudBlobContainer _blobContainer; 15 | 16 | public BlobStorage(string connectionString) 17 | { 18 | var strageAccount = CloudStorageAccount.Parse(connectionString); 19 | _blobClient = strageAccount.CreateCloudBlobClient(); 20 | } 21 | 22 | public static async Task CreateAsync(string connectionString, string containerName) 23 | { 24 | var instance = new BlobStorage(connectionString); 25 | await instance.InitializeAsync(containerName); 26 | return instance; 27 | } 28 | 29 | public async Task InitializeAsync(string containerName) 30 | { 31 | _blobContainer = _blobClient.GetContainerReference(containerName); 32 | await _blobContainer.CreateIfNotExistsAsync(); 33 | await _blobContainer.SetPermissionsAsync( 34 | new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }); 35 | } 36 | 37 | public async Task UploadFromStreamAsync(Stream stream, string directoryName, string blobName) 38 | { 39 | var directory = _blobContainer.GetDirectoryReference(directoryName); 40 | var blob = directory.GetBlockBlobReference(blobName); 41 | await blob.UploadFromStreamAsync(stream); 42 | return blob.Uri; 43 | } 44 | 45 | public async Task DeleteImageAsync(string directoryName, string blobName) 46 | { 47 | var directory = _blobContainer.GetDirectoryReference(directoryName); 48 | var blob = directory.GetBlockBlobReference(blobName); 49 | await blob.DeleteIfExistsAsync(); 50 | } 51 | 52 | public async Task DeleteDirectoryAsync(string directoryName) 53 | { 54 | var directory = _blobContainer.GetDirectoryReference(directoryName); 55 | foreach (CloudBlob blob in (await directory.ListBlobsSegmentedAsync(new BlobContinuationToken())).Results) 56 | { 57 | await blob.DeleteIfExistsAsync(); 58 | } 59 | } 60 | 61 | public async Task> ListBlobUri(string directoryName) 62 | { 63 | var directory = _blobContainer.GetDirectoryReference(directoryName); 64 | return (await directory.ListBlobsSegmentedAsync(new BlobContinuationToken())).Results.Select(blob => blob.Uri); 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/CloudStorage/TableStorage.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage; 2 | using Microsoft.WindowsAzure.Storage.Table; 3 | using System.Threading.Tasks; 4 | 5 | namespace WebAppWithBotFrameworkSample.CloudStorage 6 | { 7 | 8 | public class TableStorage where T : TableEntity, new() 9 | { 10 | private CloudTableClient _tableClient; 11 | private CloudTable _table; 12 | 13 | protected TableStorage(string connectionString) 14 | { 15 | var strageAccount = CloudStorageAccount.Parse(connectionString); 16 | _tableClient = strageAccount.CreateCloudTableClient(); 17 | } 18 | 19 | protected async Task InitializeAsync(string tableName) 20 | { 21 | _table = _tableClient.GetTableReference(tableName); 22 | await _table.CreateIfNotExistsAsync(); 23 | } 24 | 25 | public static async Task> CreateAsync(string connectionString,string tableName) 26 | { 27 | var result = new TableStorage(connectionString); 28 | await result.InitializeAsync(tableName); 29 | return result; 30 | } 31 | 32 | public async Task AddAsync(string partitionKey, string rowKey) 33 | { 34 | if ((await FindAsync(partitionKey, rowKey)) != null) { return; } 35 | 36 | var newItem = new T() { PartitionKey = partitionKey, RowKey = rowKey }; 37 | await _table.ExecuteAsync(TableOperation.Insert(newItem)); 38 | } 39 | 40 | public async Task UpdateAsync(T item) 41 | { 42 | await _table.ExecuteAsync(TableOperation.InsertOrReplace(item)); 43 | } 44 | 45 | public async Task FindAsync(string partitionKey, string rowKey) 46 | { 47 | var ope = TableOperation.Retrieve(partitionKey, rowKey); 48 | var retrieveResult = await _table.ExecuteAsync(ope); 49 | if (retrieveResult.Result == null) { return null; } 50 | return (T)(retrieveResult.Result); 51 | } 52 | 53 | public async Task DeleteAsync(string partitionKey, string rowKey) 54 | { 55 | var item = await FindAsync(partitionKey, rowKey); 56 | if (item == null) { return; } 57 | 58 | var ope = TableOperation.Delete(item); 59 | await _table.ExecuteAsync(ope); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Controllers/LineBotController.cs: -------------------------------------------------------------------------------- 1 | using Line.Messaging; 2 | using Line.Messaging.Webhooks; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Configuration; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.Http; 9 | using System.Threading.Tasks; 10 | using System.Web.Http; 11 | using WebAppWithBotFrameworkSample.CloudStorage; 12 | using WebAppWithBotFrameworkSample.Models; 13 | 14 | namespace WebAppWithBotFrameworkSample.Controllers 15 | { 16 | public class LineBotController : ApiController 17 | { 18 | private static LineMessagingClient lineMessagingClient; 19 | private string accessToken = ConfigurationManager.AppSettings["ChannelAccessToken"]; 20 | private string channelSecret = ConfigurationManager.AppSettings["ChannelSecret"]; 21 | public LineBotController() 22 | { 23 | lineMessagingClient = new LineMessagingClient(accessToken); 24 | } 25 | 26 | /// 27 | /// POST: api/Messages 28 | /// Receive a message from a user and reply to it 29 | /// 30 | [HttpPost] 31 | public async Task Post(HttpRequestMessage request) 32 | { 33 | var events = await request.GetWebhookEventsAsync(channelSecret); 34 | var connectionString = ConfigurationManager.AppSettings["StorageConnectionString"]; 35 | var blobStorage = await BlobStorage.CreateAsync(connectionString, "linebotcontainer"); 36 | var eventSourceState = await TableStorage.CreateAsync(connectionString, "eventsourcestate"); 37 | 38 | var app = new LineBotApp(lineMessagingClient, eventSourceState, blobStorage); 39 | 40 | await app.RunAsync(events); 41 | 42 | return Request.CreateResponse(HttpStatusCode.OK); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="WebAppWithBotFrameworkSample.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Http; 6 | using System.Web.Security; 7 | using System.Web.SessionState; 8 | 9 | namespace WebAppWithBotFrameworkSample 10 | { 11 | public class WebApiApplication : System.Web.HttpApplication 12 | { 13 | protected void Application_Start() 14 | { 15 | GlobalConfiguration.Configure(WebApiConfig.Register); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Models/EventSourceLocation.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace WebAppWithBotFrameworkSample.Models 4 | { 5 | public class EventSourceLocation : EventSourceState 6 | { 7 | public string Location { get; set; } 8 | 9 | public EventSourceLocation() { } 10 | } 11 | } -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Models/EventSourceState.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.WindowsAzure.Storage.Table; 2 | 3 | namespace WebAppWithBotFrameworkSample.Models 4 | { 5 | public class EventSourceState : TableEntity 6 | { 7 | [IgnoreProperty] 8 | public string SourceType { get { return PartitionKey; } set { PartitionKey = value; } } 9 | [IgnoreProperty] 10 | public string SourceId { get { return RowKey; } set { RowKey = value; } } 11 | 12 | public EventSourceState() { } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WebAppWithBotFrameworkSample")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WebAppWithBotFrameworkSample")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e6ab02a3-0b99-4529-8195-f8aaad8c0cdb")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/README_JP.md: -------------------------------------------------------------------------------- 1 | # LINE Messaging API 用 Microsoft Bot Framework コネクター 2 | 3 | 4 | # Microsoft Bot Framework 5 | Microsoft Bot Framework はボット開発者に、柔軟で強力なフレームワークを提供します。また開発したボットは、Skype や Facebook、Slack などの多くのチャネルに公開が可能です。 6 | 7 | 詳細は [こちら](https://dev.botframework.com/). 8 | 9 | # LINE 用 Microsoft Bot Framework コネクター 10 | 残念ながら現時点で LINE 用のネイティブコネクターが Bot Framework で提供されていません。このプロジェクトはその問題を解決するもので、外部からアクセスできる場所に公開するだけでコネクターとして機能します。 11 | 12 | ## 対象者 13 | 主に以下の方を対象としています。 14 | 15 | - Bot Framework でボットを既に開発していて、LINE にも公開したい方。 16 | - LINE ボットの開発者で Bot Framework を活用したい方。 17 | 18 | # どのように機能するか 19 | 考え方はシンプルです。 20 | 1. ユーザーが LINE でメッセージをボットに送信すると、コネクターがそのメッセージを受信。 21 | 1. 受信したメッセージをパースし、Bot Framework 用のメッセージに変換。 22 | 1. 変換したメッセージをダイレクトライン経由で Bot Connector に送信。 23 | 1. 処理された結果をコネクターで受信。 24 | 1. ダイレクトラインからの返信をパースして、LINE 用のメッセージに変更。 25 | 1. LINE に返信。 26 | 27 | # セットアップ 28 | ## [前提条件] 29 | 以下のモジュールが必要です。 30 | 31 | - [Azure サブスクリプション](https://azure.microsoft.com) 32 | - [Visual Studio および ASP.NET と Web 開発ワークロード](https://www.visualstudio.com/vs/) 33 | - [Microsoft Bot Framework account](https://dev.botframework.com/) 34 | - [git](https://git-scm.com/downloads) 35 | - [LINE 開発者アカウントおよび Messaging API アプリケーション](https://developers.line.me/en/) 36 | - [ngrok (ローカルテスト用)](https://ngrok.com/) 37 | 38 | ## [ソースコードの取得] 39 | zip ファイルをダウンロードして解凍するか、git clone コマンドでレポジトリをコピーします。テンプレートからも同様のプロジェクトを作成できます。 40 | 41 | ## [構成の更新] 42 | Web.config の設定を更新します。 43 | 44 | - StorageConnectionString: Azure ストレージの接続文字列 45 | - DirectLineSecret: Bot Framework ダイレクトラインシークレット 46 | - ChannelSecret: LINE Messaging API チャネルシークレット 47 | - ChannelAccessToken: LINE Messaging API アクセストークン 48 | 49 | # コンパイル、テストおよび公開 50 | ## [コンパイル] 51 | Visual Studio でコンパイルします。 52 | 1. Visual Studio でソリューションを開く。 53 | 1. ビルドメニューより ”ソリューションのビルド” を実行します。必要に応じてデバッグやリリース構成を切り替え。 54 | 55 | ## [ローカルでのテスト] 56 | ローカルでデバッグテストをしたい場合は、以下の手順を行います。 57 | 1. Visual Studio で Web App を右クリックし ”スタートアップ プロジェクトに設定” をクリック。 58 | ![SetWebAppStartUpProject_JA.PNG](../ImagesForREADME/SetWebAppStartUpProject_JA.PNG) 59 | 1. F5 を押下してデバッグを開始。ブラウザが開くのでポートを確認。(既定: 1590) 60 | 1. マンドプロンプトやターミナルを開いて、>ngrok http --host-header=localhost:1590 1590 を実行。ポートは環境に合わせて変更。出力された ngrok のアドレスをコピー。
61 | ![ngrok.PNG](../ImagesForREADME/ngrok.PNG) 62 | 1. [Line 開発者コンソール](https://developers.line.me/console/) を開き、Messaging API アプリケーションを開く。 63 | 1. "Webhook URL Requires SSL" 設定を ngrok URL に変更。/api/LineBot をつけ忘れないように注意。
64 | ![LINEWebhookUrl](../ImagesForREADME/LINEWebhookUrl.PNG) 65 | 66 | この状態で LINE アプリケーションよりボットにメッセージを送ると、ローカルのデバッグ環境に送信されます。コードを変更したい場合は Visual Studio のデバッグ実行を停止するだけで、ngrok のセッションは止めないでください。セッションが有効な限り、LINE 側の設定変更は不要です。 67 | 68 | ## [Web App の公開] 69 | Visual Studio から直接 Azure に公開できます。 70 | 1. プロジェクトを右クリックして、”発行” を選択。 71 | 1. ウィザードに従ってアプリケーションを公開。 72 | 1. ブラウザが開くので、URL を確認。 73 | 1. [Line 開発者コンソール](https://developers.line.me/console/) Messaging API アプリケーションを開く。 74 | 1. "Webhook URL Requires SSL" 設定を行更新。 75 | 1. LINE アプリケーションよりボットにメッセージを送信して動作確認。 -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Services/CacheService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | 6 | namespace WebAppWithBotFrameworkSample.Services 7 | { 8 | public static class CacheService 9 | { 10 | public static Dictionary caches; 11 | 12 | static CacheService() 13 | { 14 | caches = new Dictionary(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /WebAppWithBotFrameworkSample/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | --------------------------------------------------------------------------------