├── .github └── workflows │ └── Adapter CI.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── build ├── ExtractCompressNuGet.ps1 ├── botframework-wechat-dotnet-daily.yml ├── botframework-wechat-dotnet.yml ├── botframework-wechat-js.yml ├── dotnet-build-steps.yml └── dotnet-sign-steps.yml ├── doc ├── README.md └── media │ ├── change_language.png │ ├── chat.png │ ├── register_account.png │ ├── sandbox_account.png │ ├── sandbox_account2.png │ ├── sandbox_console.png │ ├── serviceaccount_console.png │ └── subscribe.png ├── libraries ├── csharp_dotnetcore │ ├── .editorconfig │ ├── BotBuilder-DotNet.ruleset │ ├── Directory.Build.props │ ├── Microsoft.Bot.Builder.Adapters.WeChat │ │ ├── AttachmentHash.cs │ │ ├── BackgroundTaskQueue.cs │ │ ├── Directory.Build.props │ │ ├── Extensions │ │ │ └── AttachmentExtensions.cs │ │ ├── Helpers │ │ │ ├── AttachmentHelper.cs │ │ │ ├── EntityHelper.cs │ │ │ └── VerificationHelper.cs │ │ ├── IAttachmentHash.cs │ │ ├── IBackgroundTaskQueue.cs │ │ ├── MessageCryptography.cs │ │ ├── Microsoft.Bot.Builder.Adapters.WeChat.csproj │ │ ├── QueuedHostedService.cs │ │ ├── Schema │ │ │ ├── Article.cs │ │ │ ├── Image.cs │ │ │ ├── JsonResults │ │ │ │ ├── AccessTokenResult.cs │ │ │ │ ├── UploadMediaResult.cs │ │ │ │ ├── UploadPersistentMediaResult.cs │ │ │ │ ├── UploadTemporaryMediaResult.cs │ │ │ │ └── WeChatJsonResult.cs │ │ │ ├── MediaTypes.cs │ │ │ ├── MenuItem.cs │ │ │ ├── MessageMenu.cs │ │ │ ├── MimeTypesMap.cs │ │ │ ├── Music.cs │ │ │ ├── News.cs │ │ │ ├── Requests │ │ │ │ ├── Events │ │ │ │ │ ├── CameraEvent.cs │ │ │ │ │ ├── CameraOrAlbumEvent.cs │ │ │ │ │ ├── ClickEvent.cs │ │ │ │ │ ├── CopyrightCheckResult.cs │ │ │ │ │ ├── EnterEvent.cs │ │ │ │ │ ├── EventTypes.cs │ │ │ │ │ ├── IRequestMessageEventBase.cs │ │ │ │ │ ├── LocationEvent.cs │ │ │ │ │ ├── MD5Sum.cs │ │ │ │ │ ├── MassSendJobFinishedEvent.cs │ │ │ │ │ ├── PicItem.cs │ │ │ │ │ ├── RequestEvent.cs │ │ │ │ │ ├── RequestEventWithEventKey.cs │ │ │ │ │ ├── ResultList.cs │ │ │ │ │ ├── ResultListItem.cs │ │ │ │ │ ├── ScanCodeInfo.cs │ │ │ │ │ ├── ScanEvent.cs │ │ │ │ │ ├── ScanPushEvent.cs │ │ │ │ │ ├── SelectLocationEvent.cs │ │ │ │ │ ├── SendLocationInfo.cs │ │ │ │ │ ├── SendPicsInfo.cs │ │ │ │ │ ├── SubscribeEvent.cs │ │ │ │ │ ├── TemplateSendFinishedEvent.cs │ │ │ │ │ ├── UnsunscribeEvent.cs │ │ │ │ │ ├── ViewEvent.cs │ │ │ │ │ ├── ViewMiniProgramEvent.cs │ │ │ │ │ ├── WaitScanPushEvent.cs │ │ │ │ │ └── WeChatAlbumEvent.cs │ │ │ │ ├── IRequestMessageBase.cs │ │ │ │ ├── ImageRequest.cs │ │ │ │ ├── LinkRequest.cs │ │ │ │ ├── LocationRequest.cs │ │ │ │ ├── RequestMessage.cs │ │ │ │ ├── RequestMessageTypes.cs │ │ │ │ ├── ShortVideoRequest.cs │ │ │ │ ├── TextRequest.cs │ │ │ │ ├── UnknowRequest.cs │ │ │ │ ├── VideoRequest.cs │ │ │ │ └── VoiceRequest.cs │ │ │ ├── Responses │ │ │ │ ├── IResponseMessageBase.cs │ │ │ │ ├── ImageResponse.cs │ │ │ │ ├── MPNewsResponse.cs │ │ │ │ ├── MessageMenuResponse.cs │ │ │ │ ├── MusicResponse.cs │ │ │ │ ├── NewsResponse.cs │ │ │ │ ├── ResponseMessage.cs │ │ │ │ ├── ResponseMessageTypes.cs │ │ │ │ ├── TextResponse.cs │ │ │ │ ├── VideoResponse.cs │ │ │ │ └── VoiceResponse.cs │ │ │ ├── SecretInfo.cs │ │ │ ├── Video.cs │ │ │ ├── Voice.cs │ │ │ ├── WeChatAccessToken.cs │ │ │ └── WeChatMessageFactory.cs │ │ ├── Storage │ │ │ ├── AccessTokenStorage.cs │ │ │ ├── IWeChatStorage.cs │ │ │ └── WeChatAttachmentStorage.cs │ │ ├── WeChatClient.cs │ │ ├── WeChatHttpAdapter.cs │ │ ├── WeChatMessageMapper.cs │ │ └── WeChatSettings.cs │ ├── build │ │ └── 35MSSharedLib1024.snk │ ├── csharp_dotnetcore.sln │ └── tests │ │ └── Microsoft.Bot.Builder.Adapters.WeChat.Tests │ │ ├── AdapterTest.cs │ │ ├── AttachmentHashTest.cs │ │ ├── BackgroundTaskTest.cs │ │ ├── Cards.cs │ │ ├── EchoBot.cs │ │ ├── MessageCryptographyTest.cs │ │ ├── MessageFactoryTest.cs │ │ ├── MessageMapperTest.cs │ │ ├── Microsoft.Bot.Builder.Adapters.WeChat.Tests.csproj │ │ ├── MockWeChatClient.cs │ │ ├── Resources │ │ └── adaptiveCard.json │ │ ├── TestUtilities │ │ └── MockDataUtility.cs │ │ └── WeChatClientTest.cs └── typescript │ └── Microsoft.Bot.Builder.Adapters.WeChat │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.json │ ├── .gitattributes │ ├── .gitignore │ ├── .nycrc │ ├── README.md │ ├── package.json │ ├── src │ ├── accessTokenStorage.ts │ ├── attachmentHash.ts │ ├── attachmentHelper.ts │ ├── index.ts │ ├── messageCryptography.ts │ ├── verificationHelper.ts │ ├── weChatAdapter.ts │ ├── weChatAttachmentStorage.ts │ ├── weChatClient.ts │ ├── weChatMessageMapper.ts │ └── weChatSchema.ts │ ├── tests │ ├── accessTokenStorage.test.js │ ├── attachmentHash.test.js │ ├── bot.js │ ├── messageCryptography.test.js │ ├── mocha.opts │ ├── verificationHelper.test.js │ ├── weChatAdapter.test.js │ ├── weChatClient.test.js │ └── weChatMessageMapper.test.js │ └── tsconfig.json └── samples ├── csharp_dotnetcore └── Microsoft.Bot.Builder.Adapters.WeChat.TestBot │ ├── Bots │ ├── DialogBot.cs │ └── RichCardsBot.cs │ ├── Cards.cs │ ├── Controllers │ └── BotController.cs │ ├── DialogExtensions.cs │ ├── Dialogs │ └── MainDialog.cs │ ├── Microsoft.Bot.Builder.Adapters.WeChat.TestBot.csproj │ ├── Microsoft.Bot.Builder.Adapters.WeChat.TestBot.sln │ ├── Program.cs │ ├── README.md │ ├── Resources │ ├── MessageMenu.json │ └── adaptiveCard.json │ ├── Startup.cs │ ├── WeChatAdapterWithErrorHandler.cs │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ └── default.htm └── typescript └── Microsoft.Bot.Builder.Adapters.WeChat.TestBot ├── .env ├── .gitignore ├── README.md ├── deploymentScripts └── webConfigPrep.js ├── deploymentTemplates ├── new-rg-parameters.json ├── preexisting-rg-parameters.json ├── template-with-new-rg.json └── template-with-preexisting-rg.json ├── package-lock.json ├── package.json ├── src ├── bots │ ├── dialogBot.ts │ └── richCardsBot.ts ├── dialogs │ └── mainDialog.ts ├── index.ts └── resources │ ├── MessageMenu.json │ └── adaptiveCard.json ├── tsconfig.json └── tslint.json /.github/workflows/Adapter CI.yml: -------------------------------------------------------------------------------- 1 | name: Adapter CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | job_dotnet: 13 | name: DotNet CI 14 | runs-on: windows-latest 15 | timeout-minutes: 20 16 | 17 | steps: 18 | - uses: actions/checkout@v1 19 | - name: Setup .NET Core 20 | uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: 3.1 23 | - name: Build Adapter 24 | run: dotnet build 25 | working-directory: libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat 26 | - name: Build Test Project 27 | run: dotnet build 28 | working-directory: libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests 29 | - name: Run Tests 30 | run: dotnet test /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov 31 | working-directory: libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests 32 | - name: Publish Coverage Result 33 | uses: coverallsapp/github-action@master 34 | with: 35 | github-token: ${{ secrets.GITHUB_TOKEN }} 36 | path-to-lcov: libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/TestResults/coverage.info 37 | 38 | job_typescript: 39 | name: TypeScript CI 40 | runs-on: ubuntu-latest 41 | timeout-minutes: 20 42 | 43 | steps: 44 | - uses: actions/checkout@v1 45 | - name: Use Node.js 46 | uses: actions/setup-node@v1 47 | with: 48 | node-version: 12.13.1 49 | - name: npm install 50 | run: npm install 51 | working-directory: libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat 52 | - name: Run Tests 53 | run: npm run test 54 | working-directory: libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat 55 | - name: Coveralls 56 | uses: coverallsapp/github-action@master 57 | with: 58 | github-token: ${{ secrets.GITHUB_TOKEN }} 59 | path-to-lcov: libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/coverage/lcov.info -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Guidelines for contributing to BotFramework-WeChat 2 | 3 | - Nothing gets pushed to the `master` branch. Use github pull-request's to submit new code. 4 | - Use the "Description" field of the new Pull Request form to describe the change in detail. Assume reviewers are taking on a context switch to review your code and need a refresher on context. Reference & link to any pertinent tickets in project tracking software. This will also act as a paper trail of changes and it should be logical for one to use `git blame` to look up the commit and understand why the change was made. 5 | - Keep your pull-requests small and concise. If you are working on a substantially large change in lines of code, it is OK to open a pull-request that is a partial implementation; please make it clear in the description and keep the boundaries between diffs logical. 6 | - At least one approver is required on a pull-request prior to merging it. 7 | - Programatic testing for each change is a requirement. Comprehensive unit tests for every change is not. _"Write tests, not too many, mostly integration"_. We should be using [Xunit](https://xunit.net/) for this. 8 | - Use `rebase` when merging changes into to the master branch. This can be done using the _“Squash and Merge”_ technique in the GitHub UI. Local branches will need to be updated using rebase as well. This will keep a clean commit history. Reach out to me if you need help understanding rebase. 9 | 10 | ### Forking 11 | 12 | In order to keep a clean tree on our Github repository we use a forking strategy. Follow the steps below to work with forks. 13 | 14 | #### Creating a fork 15 | 16 | To create a fork, click on the the `Fork` button at the top of the repository page in Github. 17 | 18 | This creates a copy of the repository in your Github account in which you can develop against. Read more about working with forks [here](https://help.github.com/en/articles/working-with-forks). 19 | 20 | #### Developing on your fork 21 | 22 | - clone your fork to your machine 23 | - create a branch 24 | - make changes and commit 25 | - push your branch to your fork 26 | - create a pull request against the main repository [docs](https://help.github.com/en/articles/creating-a-pull-request-from-a-fork) 27 | 28 | #### Keeping your fork up-to-date 29 | 30 | - add a new remote to your local repository 31 | 32 | ```bash 33 | git remote add upstream git@github.com:microsoft/BotFramework-WeChat.git 34 | ``` 35 | 36 | - update your upstream remote 37 | - merge upstream changes into your local master branch 38 | 39 | ```bash 40 | git fetch upstream 41 | git checkout master 42 | git pull upstream master 43 | ``` 44 | 45 | #### Updating your feature branch with latest master 46 | 47 | - update your local master by following the previous section 48 | - merge/rebase master into your feature branch 49 | 50 | ```bash 51 | git checkout 52 | git merge master # git rebase master 53 | git push origin 54 | ``` 55 | 56 | #### Checking out a pull request from a fork 57 | 58 | ```bash 59 | git checkout -b pull-request-branch master 60 | git pull git://github.com//BotFramework-WeChat.git 61 | ``` 62 | 63 | For example, if there were a PR from the user AwesomeDev's branch my-awesome-feature: 64 | 65 | ```bash 66 | git checkout -b AwesomeDev/my-awesome-feature master 67 | git pull git://github.com/AwesomeDev/BotFramework-WeChat.git my-awesome-feature 68 | ``` 69 | 70 | #### Things to keep in mind 71 | 72 | - Always work off of branches; don't commit directly to your master branch. This will help avoid conflicts and keep your master branch pristine. 73 | - When creating pull requests check the `Allow edits from maintainers` option so that others can make changes if necessary. 74 | 75 | **** 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BotFramework-WeChat 2 | | Branch | Description | Build Status | Coverage Status | 3 | |----|---------------|--------------|-----------------| 4 | |Master | WeChat Adapter Builds |[![Build Status](https://github.com/microsoft/BotFramework-WeChat/workflows/Adapter%20CI/badge.svg?branch=master)](https://github.com/microsoft/BotFramework-WeChat/actions?query=branch%3Amaster)|[![Coverage Status](https://coveralls.io/repos/github/microsoft/BotFramework-WeChat/badge.svg?branch=master)](https://coveralls.io/github/microsoft/BotFramework-WeChat?branch=master)| 5 | 6 | 7 | # Contributing 8 | 9 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 10 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 11 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 12 | 13 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 14 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 15 | provided by the bot. You will only need to do this once across all repos using our CLA. 16 | 17 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 18 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 19 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /build/ExtractCompressNuGet.ps1: -------------------------------------------------------------------------------- 1 | # 2 | # This extracts contents from or recompresses them back into NuGet .nupkg files. 3 | # Run this to extract before, then recompress after signing assemblies in the packages. 4 | # 5 | param 6 | ( 7 | [string]$path, 8 | [switch]$extract, 9 | [switch]$compress 10 | ) 11 | pushd $path 12 | 13 | # Download temporary version of Archive module that fixes issue on macOS/Linux with path separator 14 | #Invoke-WebRequest -Uri "https://raw.githubusercontent.com/PowerShell/Microsoft.PowerShell.Archive/master/Microsoft.PowerShell.Archive/Microsoft.PowerShell.Archive.psm1" -OutFile .\archive.psm1 15 | #Import-Module .\archive.psm1 16 | 17 | # Ensure Powershell.Archive minimum version 1.2.3.0 is installed. That fixes a path separator issue on macOS/Linux. 18 | $ver = (Get-Command -Module Microsoft.PowerShell.Archive | Select-Object -Property version -First 1).Version.ToString() 19 | if ($ver -lt '1.2.3.0') { 20 | Write-Host "Installing Microsoft.Powershell.Archive 1.2.3.0 (fix for Linux path separator bug)" 21 | Install-Module -Name Microsoft.PowerShell.Archive -MinimumVersion '1.2.3.0' -AllowClobber -Force -AcceptLicense 22 | } else { 23 | Write-Host "Already installed: Microsoft.Powershell.Archive $ver" 24 | } 25 | 26 | [int]$itemsProcessed = 0 27 | if ($extract) { 28 | # Extract .nupkg packages in the path. 29 | Get-ChildItem . -Filter *.nupkg | 30 | Foreach-Object { 31 | Write-Host $_.Name 32 | Rename-Item -Path $_.Name -NewName ($_.BaseName + ".zip") 33 | Expand-Archive ($_.BaseName + '.zip') -DestinationPath ($_.BaseName) 34 | Remove-Item -Path ($_.DirectoryName + '\' + $_.BaseName + '.zip') 35 | $itemsProcessed++ 36 | } 37 | } elseif ($compress) { 38 | # Compress folders in the path. Name them *.nupkg. 39 | Get-ChildItem | ?{ $_.PSIsContainer } | 40 | Foreach-Object { 41 | Write-Host $_.Name 42 | Compress-Archive ($_.Name + '\**') -DestinationPath ($_.Name + '.zip') 43 | Rename-Item -Path ($_.Name + '.zip') -NewName ($_.BaseName + ".nupkg") 44 | Remove-Item -Path ($_.FullName) -Recurse 45 | $itemsProcessed++ 46 | } 47 | } else { 48 | throw 'Error: Missing argument "-Extract" or "-Compress".' 49 | } 50 | if ($itemsProcessed -eq 0) { 51 | Write-Host "No items found to process in path '$path'." 52 | } 53 | 54 | popd -------------------------------------------------------------------------------- /build/botframework-wechat-dotnet-daily.yml: -------------------------------------------------------------------------------- 1 | name: $(Build.BuildId) 2 | variables: 3 | BuildConfiguration: Release 4 | BuildPlatform: Any CPU 5 | CoverallsToken: define this in Azure 6 | Parameters.solution: libraries/csharp_dotnetcore/csharp_dotnetcore.sln 7 | MSBuildArguments: -p:PublishRepositoryUrl=true -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg 8 | ReleasePackageVersion: 4.0.0-preview-$(Build.BuildNumber) 9 | pool: 10 | name: Hosted Windows 2019 with VS2019 11 | demands: 12 | - msbuild 13 | - visualstudio 14 | 15 | trigger: 16 | branches: 17 | include: 18 | - master 19 | paths: 20 | include: 21 | - '*' 22 | exclude: 23 | - doc/* 24 | - libraries/typescript/* 25 | - samples/* 26 | - CODE_OF_CONDUCT.md 27 | - CONTRIBUTING.md 28 | - LICENSE 29 | - README.md 30 | - SECURITY.md 31 | 32 | pr: none 33 | 34 | jobs: 35 | - job: Build_and_Sign 36 | steps: 37 | - template: dotnet-build-steps.yml 38 | - template: dotnet-sign-steps.yml -------------------------------------------------------------------------------- /build/botframework-wechat-dotnet.yml: -------------------------------------------------------------------------------- 1 | # Starter pipeline 2 | # Start with a minimal pipeline that you can customize to build and deploy your code. 3 | # Add steps that build, run tests, deploy, and more: 4 | # https://aka.ms/yaml 5 | 6 | name: $(Build.BuildId) 7 | variables: 8 | BuildConfiguration: Debug 9 | BuildPlatform: Any CPU 10 | CoverallsToken: define this in Azure 11 | Parameters.solution: libraries/csharp_dotnetcore/csharp_dotnetcore.sln 12 | pool: 13 | name: Hosted Windows 2019 with VS2019 14 | demands: 15 | - msbuild 16 | - visualstudio 17 | 18 | trigger: 19 | branches: 20 | include: 21 | - master 22 | paths: 23 | include: 24 | - '*' 25 | exclude: 26 | - doc/* 27 | - libraries/typescript/* 28 | - samples/* 29 | - CODE_OF_CONDUCT.md 30 | - CONTRIBUTING.md 31 | - LICENSE 32 | - README.md 33 | - SECURITY.md 34 | 35 | pr: 36 | branches: 37 | include: 38 | - master 39 | paths: 40 | include: 41 | - '*' 42 | exclude: 43 | - doc/* 44 | - libraries/typescript/* 45 | - samples/* 46 | - CODE_OF_CONDUCT.md 47 | - CONTRIBUTING.md 48 | - LICENSE 49 | - README.md 50 | - SECURITY.md 51 | 52 | steps: 53 | - powershell: 'gci env:* | sort-object name | Format-Table -AutoSize -Wrap' 54 | displayName: 'Display env vars' 55 | 56 | - task: NuGetToolInstaller@1 57 | displayName: 'Use NuGet' 58 | 59 | - task: NuGetCommand@2 60 | displayName: 'NuGet restore' 61 | inputs: 62 | restoreSolution: '$(Parameters.solution)' 63 | 64 | - task: DotNetCoreCLI@2 65 | displayName: 'dotnet restore' 66 | inputs: 67 | command: restore 68 | projects: | 69 | libraries/csharp_dotnetcore/csharp_dotnetcore.sln 70 | 71 | - task: VSBuild@1 72 | displayName: 'Build solution libraries/csharp_dotnetcore/csharp_dotnetcore.sln' 73 | inputs: 74 | solution: '$(Parameters.solution)' 75 | vsVersion: "latest" 76 | msbuildArgs: '-p:SignAssembly=false -p:delaySign=false' 77 | platform: '$(BuildPlatform)' 78 | configuration: '$(BuildConfiguration)' 79 | 80 | - task: DotNetCoreCLI@2 81 | displayName: 'dotnet test (release)' 82 | inputs: 83 | command: test 84 | projects: | 85 | libraries/csharp_dotnetcore/Tests/**/*Tests.csproj 86 | 87 | arguments: '-v n --configuration release --no-build --no-restore --filter TestCategory!=IgnoreInAutomatedBuild --collect:"Code Coverage"' 88 | condition: eq(variables['BuildConfiguration'],'Release') 89 | 90 | - task: DotNetCoreCLI@2 91 | displayName: 'dotnet test (debug)' 92 | inputs: 93 | command: test 94 | projects: | 95 | libraries/csharp_dotnetcore/Tests/**/*Tests.csproj 96 | 97 | arguments: '-v n --configuration debug --no-build --no-restore --filter TestCategory!=IgnoreInAutomatedBuild --collect:"Code Coverage"' 98 | condition: eq(variables['BuildConfiguration'],'Debug') 99 | 100 | - script: | 101 | cd .. 102 | dir *.* /s 103 | displayName: 'Dir workspace' 104 | 105 | - task: PublishBuildArtifacts@1 106 | displayName: 'Publish Artifact: build folder' 107 | inputs: 108 | PathtoPublish: build 109 | ArtifactName: build 110 | 111 | - script: | 112 | cd .. 113 | dir *.* /s 114 | displayName: 'Dir workspace' -------------------------------------------------------------------------------- /build/botframework-wechat-js.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Build Botframework-WeChat on Windows agent 3 | # 4 | 5 | # "name" here defines the build number format. Build number is accessed via $(Build.BuildNumber) 6 | name: $(Build.BuildId) 7 | 8 | pool: 9 | name: Hosted Windows 2019 with VS2019 10 | 11 | pr: 12 | branches: 13 | include: 14 | - master 15 | paths: 16 | include: 17 | - '*' 18 | exclude: 19 | - doc/* 20 | - libraries/csharp_dotnetcore/* 21 | - samples/* 22 | - CODE_OF_CONDUCT.md 23 | - CONTRIBUTING.md 24 | - LICENSE 25 | - README.md 26 | - SECURITY.md 27 | 28 | jobs: 29 | - job: WeChat 30 | variables: 31 | buildVersion: '4.0.0-preview.$(Build.BuildId)' 32 | _version: ${{coalesce(variables.version, variables.buildVersion)}} 33 | 34 | steps: 35 | - task: colinsalmcorner.colinsalmcorner-buildtasks.tag-build-task.tagBuildOrRelease@0 36 | displayName: 'Tag Build with version number' 37 | inputs: 38 | tags: 'Version=$(_version)' 39 | 40 | - task: NodeTool@0 41 | displayName: 'Use Node 10.x' 42 | inputs: 43 | versionSpec: '10.15.1' 44 | 45 | - task: Npm@1 46 | displayName: 'npm install' 47 | inputs: 48 | command: 'install' 49 | workingDir: 'libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat' 50 | 51 | - task: Npm@1 52 | displayName: 'npm run build' 53 | inputs: 54 | command: 'custom' 55 | workingDir: 'libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat' 56 | customCommand: 'run build' 57 | 58 | - task: Npm@1 59 | displayName: 'npm run test' 60 | inputs: 61 | command: 'custom' 62 | workingDir: 'libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat' 63 | customCommand: 'run test' 64 | 65 | - task: Npm@1 66 | displayName: 'Replace version number in package.json file' 67 | inputs: 68 | command: 'custom' 69 | workingDir: 'libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat' 70 | customCommand: 'version --allow-same-version $(_version)' 71 | 72 | - task: Npm@1 73 | displayName: 'npm pack botframework-wechat' 74 | inputs: 75 | command: 'custom' 76 | workingDir: 'libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat' 77 | verbose: false 78 | customCommand: 'pack' 79 | 80 | - task: CopyFiles@2 81 | displayName: 'Copy Files to: $(Build.ArtifactStagingDirectory)' 82 | inputs: 83 | SourceFolder: libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat 84 | Contents: '**/*.tgz' 85 | TargetFolder: '$(Build.ArtifactStagingDirectory)' 86 | flattenFolders: true 87 | 88 | - task: PublishBuildArtifacts@1 89 | displayName: 'Publish Artifact: drop' 90 | inputs: 91 | ArtifactName: 'drop' 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /build/dotnet-build-steps.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - powershell: 'gci env:* | sort-object name | Format-Table -AutoSize -Wrap' 3 | displayName: 'Display env vars' 4 | 5 | - task: colinsalmcorner.colinsalmcorner-buildtasks.tag-build-task.tagBuildOrRelease@0 6 | displayName: 'Tag build with package version' 7 | inputs: 8 | tags: 'Version=$(ReleasePackageVersion)' 9 | continueOnError: true 10 | 11 | - task: NuGetToolInstaller@1 12 | displayName: 'Use NuGet' 13 | 14 | - task: NuGetCommand@2 15 | displayName: 'NuGet restore' 16 | inputs: 17 | restoreSolution: '$(Parameters.solution)' 18 | 19 | - task: DotNetCoreCLI@2 20 | displayName: 'DotNet restore' 21 | inputs: 22 | command: restore 23 | projects: | 24 | libraries/csharp_dotnetcore/csharp_dotnetcore.sln 25 | 26 | - task: VSBuild@1 27 | displayName: 'Build solution libraries/csharp_dotnetcore/csharp_dotnetcore.sln' 28 | inputs: 29 | solution: '$(Parameters.solution)' 30 | vsVersion: "latest" 31 | msbuildArgs: '$(MSBuildArguments)' 32 | platform: '$(BuildPlatform)' 33 | configuration: '$(BuildConfiguration)' 34 | 35 | - script: | 36 | cd .. 37 | dir *.* /s 38 | displayName: 'Dir workspace' 39 | continueOnError: true 40 | condition: succeededOrFailed() -------------------------------------------------------------------------------- /doc/media/change_language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/change_language.png -------------------------------------------------------------------------------- /doc/media/chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/chat.png -------------------------------------------------------------------------------- /doc/media/register_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/register_account.png -------------------------------------------------------------------------------- /doc/media/sandbox_account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/sandbox_account.png -------------------------------------------------------------------------------- /doc/media/sandbox_account2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/sandbox_account2.png -------------------------------------------------------------------------------- /doc/media/sandbox_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/sandbox_console.png -------------------------------------------------------------------------------- /doc/media/serviceaccount_console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/serviceaccount_console.png -------------------------------------------------------------------------------- /doc/media/subscribe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/doc/media/subscribe.png -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(MSBuildThisFileDirectory)outputpackages\ 4 | 5 | 6 | 7 | latest 8 | 9 | 10 | 11 | $(SolutionDir)BotBuilder-DotNet.ruleset 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Microsoft 20 | 21 | 22 | 23 | 24 | Microsoft 25 | Microsoft Bot Builder SDK 26 | © Microsoft Corporation. All rights reserved. 27 | 28 | 29 | 30 | $(SolutionDir)\build\35MSSharedLib1024.snk 31 | true 32 | $(NoWarn),1573,1591,1712 33 | true 34 | true 35 | 36 | 37 | 38 | SIGNASSEMBLY 39 | 40 | 41 | 42 | full 43 | true 44 | 45 | 46 | 47 | 48 | https://github.com/microsoft/BotFramework-WeChat 49 | https://raw.githubusercontent.com/microsoft/botframework-sdk/master/icon.png 50 | https://github.com/Microsoft/BotBuilder/blob/master/LICENSE 51 | true 52 | https://github.com/microsoft/BotFramework-WeChat 53 | >https://github.com/microsoft/BotFramework-WeChat/blob/master/LICENSE 54 | bots;ai;botframework;botbuilder 55 | 56 | en-US 57 | 61 | $(NoWarn);NU5125 62 | true 63 | snupkg 64 | 65 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/AttachmentHash.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Globalization; 5 | using System.Security.Cryptography; 6 | using System.Text; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat 9 | { 10 | internal class AttachmentHash : IAttachmentHash 11 | { 12 | /// 13 | /// Calculates the hash value, used to ignore same file when upload media. 14 | /// 15 | /// Bytes content need to be hashed. 16 | /// Hash value. 17 | public string ComputeHash(byte[] inputBytes) 18 | { 19 | // step 1, calculate MD5 hash from input 20 | #pragma warning disable CA5351 // Only used to get a unique hash value 21 | using (var md5 = MD5.Create()) 22 | #pragma warning restore CA5351 // Only used to get a unique hash value 23 | { 24 | var hash = md5.ComputeHash(inputBytes); 25 | 26 | // step 2, convert byte array to hex string 27 | var sb = new StringBuilder(); 28 | for (var i = 0; i < hash.Length; i++) 29 | { 30 | sb.Append(hash[i].ToString("X2", CultureInfo.InvariantCulture)); 31 | } 32 | 33 | return sb.ToString(); 34 | } 35 | } 36 | 37 | /// 38 | /// Calculates the hash value, used to ignore same file when upload media. 39 | /// 40 | /// String content need to be hashed. 41 | /// Hash value. 42 | public string ComputeHash(string content) 43 | { 44 | var inputBytes = Encoding.UTF8.GetBytes(content); 45 | return ComputeHash(inputBytes); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/BackgroundTaskQueue.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Concurrent; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace Microsoft.Bot.Builder.Adapters.WeChat 10 | { 11 | public class BackgroundTaskQueue : IBackgroundTaskQueue, IDisposable 12 | { 13 | private readonly ConcurrentQueue> _workItems = new ConcurrentQueue>(); 14 | private SemaphoreSlim _signal = new SemaphoreSlim(0); 15 | 16 | /// 17 | /// Queue a Task to background task queue. 18 | /// 19 | /// The work func need to be queued. 20 | public void QueueBackgroundWorkItem(Func workItem) 21 | { 22 | if (workItem == null) 23 | { 24 | throw new ArgumentNullException(nameof(workItem)); 25 | } 26 | 27 | _workItems.Enqueue(workItem); 28 | _signal.Release(); 29 | } 30 | 31 | /// 32 | /// Dequeue a Task in background task queue. 33 | /// 34 | /// The work func need to be queued. 35 | /// A representing the dequeue operation. 36 | public async Task> DequeueAsync(CancellationToken token) 37 | { 38 | await _signal.WaitAsync(token).ConfigureAwait(false); 39 | 40 | _workItems.TryDequeue(out var workItem); 41 | 42 | return workItem; 43 | } 44 | 45 | public void Dispose() 46 | { 47 | Dispose(true); 48 | GC.SuppressFinalize(this); 49 | } 50 | 51 | protected virtual void Dispose(bool disposing) 52 | { 53 | if (disposing) 54 | { 55 | // free managed resources 56 | if (_signal != null) 57 | { 58 | _signal.Dispose(); 59 | _signal = null; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | all 5 | runtime; build; native; contentfiles; analyzers; buildtransitive 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Extensions/AttachmentExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Globalization; 6 | using Microsoft.Bot.Schema; 7 | using Newtonsoft.Json; 8 | using Newtonsoft.Json.Linq; 9 | 10 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Extensions 11 | { 12 | /// 13 | /// Attachment Extensions to easily convert attachment type to card, etc. 14 | /// 15 | internal static class AttachmentExtensions 16 | { 17 | public static T ContentAs(this Attachment attachment) 18 | { 19 | if (attachment.Content == null) 20 | { 21 | return default(T); 22 | } 23 | else if (typeof(T).IsValueType) 24 | { 25 | return (T)Convert.ChangeType(attachment.Content, typeof(T), CultureInfo.InvariantCulture); 26 | } 27 | else if (attachment.Content is T) 28 | { 29 | return (T)attachment.Content; 30 | } 31 | else if (typeof(T) == typeof(byte[])) 32 | { 33 | return (T)(object)Convert.FromBase64String(attachment.Content.ToString()); 34 | } 35 | else if (attachment.Content is string) 36 | { 37 | return JsonConvert.DeserializeObject((string)attachment.Content); 38 | } 39 | 40 | return (T)((JObject)attachment.Content).ToObject(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Helpers/AttachmentHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Helpers 8 | { 9 | /// 10 | /// Helper methods for storing attachments in the channel. 11 | /// 12 | internal static class AttachmentHelper 13 | { 14 | /// 15 | /// Determines if the content param can be turned into an Uri with http or https scheme. 16 | /// 17 | /// Content object to check if it is an URL. 18 | /// Ture or False. 19 | public static bool IsUrl(object content) 20 | { 21 | return Uri.TryCreate(content as string, UriKind.Absolute, out var uriResult) 22 | && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); 23 | } 24 | 25 | public static byte[] DecodeBase64String(string base64Encoded, out string contentType) 26 | { 27 | contentType = null; 28 | 29 | // ContentUrl may contain base64 encoded string of form: "data:[][;charset=][;base64]," 30 | if (base64Encoded?.TrimStart().StartsWith("data:", StringComparison.OrdinalIgnoreCase) == true) 31 | { 32 | var start = base64Encoded.IndexOf("data:", StringComparison.InvariantCulture) + 5; 33 | var end = base64Encoded.IndexOfAny(";,".ToArray(), start); 34 | if (end > start) 35 | { 36 | contentType = base64Encoded.Substring(start, end - start).Trim(); 37 | } 38 | } 39 | 40 | // string off header 41 | var headerIndex = base64Encoded.IndexOf("base64,", StringComparison.InvariantCulture); 42 | if (headerIndex >= 0) 43 | { 44 | base64Encoded = base64Encoded.Substring(headerIndex + 7).Trim(); 45 | } 46 | 47 | return Convert.FromBase64String(base64Encoded); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Helpers/EntityHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.IO; 6 | using System.Text; 7 | using System.Xml; 8 | using System.Xml.Linq; 9 | using System.Xml.Serialization; 10 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests; 11 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses; 12 | 13 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Helpers 14 | { 15 | /// 16 | /// Entity related helper class. 17 | /// 18 | internal static class EntityHelper 19 | { 20 | /// 21 | /// Get the request message entity from XML. 22 | /// 23 | /// Type of IRequestMessageBase. 24 | /// The XDocument. 25 | /// Request Message Entity. 26 | public static IRequestMessageBase FillEntityWithXml(XDocument doc) 27 | where T : IRequestMessageBase, new() 28 | { 29 | try 30 | { 31 | var requestMessage = new T(); 32 | var serializer = new XmlSerializer(typeof(T)); 33 | using (var reader = doc.CreateReader()) 34 | { 35 | requestMessage = (T)serializer.Deserialize(reader); 36 | } 37 | 38 | return requestMessage; 39 | } 40 | catch (Exception e) 41 | { 42 | throw new Exception("Deserialize XDocument failed.", e); 43 | } 44 | } 45 | 46 | /// 47 | /// Convert Entity to XML string. 48 | /// 49 | /// Type of Entity class. 50 | /// Request Message Interface. 51 | /// XML String. 52 | public static string ConvertEntityToXmlString(IResponseMessageBase responseMessage) 53 | where T : class 54 | { 55 | try 56 | { 57 | var entity = responseMessage as T; 58 | 59 | var serializer = new XmlSerializer(typeof(T)); 60 | 61 | var settings = new XmlWriterSettings 62 | { 63 | Encoding = new UnicodeEncoding(false, false), 64 | Indent = true, 65 | OmitXmlDeclaration = true, 66 | }; 67 | var nameSpace = new XmlSerializerNamespaces(); 68 | nameSpace.Add(string.Empty, string.Empty); 69 | 70 | using (var textWriter = new StringWriter()) 71 | { 72 | using (var xmlWriter = XmlWriter.Create(textWriter, settings)) 73 | { 74 | serializer.Serialize(xmlWriter, entity, nameSpace); 75 | return textWriter.ToString(); 76 | } 77 | } 78 | } 79 | catch (Exception e) 80 | { 81 | throw new Exception("Serialize WeChat response message failed.", e); 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/IAttachmentHash.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat 5 | { 6 | /// 7 | /// Hash interface to calculate the attachment hash. 8 | /// User can inject there only hash method to replace the attachment hash. 9 | /// 10 | public interface IAttachmentHash 11 | { 12 | /// 13 | /// Calculate the hash of the byte array. 14 | /// 15 | /// The byte array need to be hashed. 16 | /// The hash string. 17 | string ComputeHash(byte[] bytes); 18 | 19 | /// 20 | /// Calculate the hash of the string content. 21 | /// 22 | /// The string content need to be hashed. 23 | /// The hash string. 24 | string ComputeHash(string content); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/IBackgroundTaskQueue.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat 9 | { 10 | public interface IBackgroundTaskQueue 11 | { 12 | void QueueBackgroundWorkItem(Func workItem); 13 | 14 | Task> DequeueAsync(CancellationToken token); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Microsoft.Bot.Builder.Adapters.WeChat.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4.0.0-local 4 | $(ReleasePackageVersion) 5 | 4.0.0-local 6 | $(ReleasePackageVersion) 7 | Debug;Release 8 | true 9 | 10 | 11 | 12 | netstandard2.0 13 | 14 | 15 | 16 | bin\$(Configuration)\netstandard2.0\Microsoft.Bot.Builder.Adapters.WeChat.xml 17 | 18 | 19 | 20 | Full 21 | true 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/QueuedHostedService.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.Extensions.Hosting; 8 | using Microsoft.Extensions.Logging; 9 | using Microsoft.Extensions.Logging.Abstractions; 10 | 11 | namespace Microsoft.Bot.Builder.Adapters.WeChat 12 | { 13 | public class QueuedHostedService : BackgroundService 14 | { 15 | private readonly ILogger _logger; 16 | 17 | public QueuedHostedService(IBackgroundTaskQueue backgroundTaskQueue, ILogger logger = null) 18 | { 19 | TaskQueue = backgroundTaskQueue; 20 | _logger = logger ?? NullLogger.Instance; 21 | } 22 | 23 | public IBackgroundTaskQueue TaskQueue { get; } 24 | 25 | protected override async Task ExecuteAsync(CancellationToken stoppingToken) 26 | { 27 | while (!stoppingToken.IsCancellationRequested) 28 | { 29 | var workItem = await TaskQueue.DequeueAsync(stoppingToken).ConfigureAwait(false); 30 | 31 | try 32 | { 33 | await workItem(stoppingToken).ConfigureAwait(false); 34 | } 35 | #pragma warning disable CA1031 // Do not throw exception, you will always need the hosted service. 36 | catch (Exception e) 37 | #pragma warning restore CA1031 38 | { 39 | // Execute work item in adapter background service. 40 | // Typically work item is about convert activity to WeChat message and send it. 41 | // Log and rethrow the exception to developer. 42 | _logger.LogError(e, "Execute Background Queued Task Failed."); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Article.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 8 | { 9 | [XmlRoot("item")] 10 | public class Article 11 | { 12 | [XmlIgnore] 13 | public string Title { get; set; } 14 | 15 | [XmlElement(ElementName = "Title")] 16 | public XmlCDataSection TitleCData 17 | { 18 | get 19 | { 20 | return new XmlDocument().CreateCDataSection(Title); 21 | } 22 | 23 | set 24 | { 25 | Title = value.Value; 26 | } 27 | } 28 | 29 | [XmlIgnore] 30 | public string Description { get; set; } 31 | 32 | [XmlElement(ElementName = "Description")] 33 | public XmlCDataSection DescriptionCData 34 | { 35 | get 36 | { 37 | return new XmlDocument().CreateCDataSection(Description); 38 | } 39 | 40 | set 41 | { 42 | Description = value.Value; 43 | } 44 | } 45 | 46 | [XmlIgnore] 47 | public string Url { get; set; } 48 | 49 | [XmlElement(ElementName = "Url")] 50 | public XmlCDataSection UrlCData 51 | { 52 | get 53 | { 54 | return new XmlDocument().CreateCDataSection(Url); 55 | } 56 | 57 | set 58 | { 59 | Url = value.Value; 60 | } 61 | } 62 | 63 | /// 64 | /// Gets or sets PicUrl. 65 | /// 66 | /// 67 | /// Should be JPG or PNG type. 68 | /// 69 | [XmlIgnore] 70 | public string PicUrl { get; set; } 71 | 72 | [XmlElement(ElementName = "PicUrl")] 73 | public XmlCDataSection PicUrlCData 74 | { 75 | get 76 | { 77 | return new XmlDocument().CreateCDataSection(PicUrl); 78 | } 79 | 80 | set 81 | { 82 | PicUrl = value.Value; 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Image.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 8 | { 9 | [XmlRoot("Image")] 10 | public class Image 11 | { 12 | public Image() 13 | { 14 | } 15 | 16 | public Image(string mediaId) 17 | { 18 | MediaId = mediaId; 19 | } 20 | 21 | [XmlIgnore] 22 | public string MediaId { get; set; } 23 | 24 | [XmlElement(ElementName = "MediaId")] 25 | public XmlCDataSection MediaIdCData 26 | { 27 | get 28 | { 29 | return new XmlDocument().CreateCDataSection(MediaId); 30 | } 31 | 32 | set 33 | { 34 | MediaId = value.Value; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/JsonResults/AccessTokenResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults 8 | { 9 | public class AccessTokenResult : WeChatJsonResult 10 | { 11 | [JsonProperty("access_token")] 12 | public string Token { get; set; } 13 | 14 | [JsonProperty("expires_in")] 15 | public int ExpireIn { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/JsonResults/UploadMediaResult.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults 4 | { 5 | public class UploadMediaResult : WeChatJsonResult, IStoreItem 6 | { 7 | [JsonProperty("media_id")] 8 | public string MediaId { get; set; } 9 | 10 | public string ETag { get; set; } 11 | 12 | public virtual bool Expired() => false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/JsonResults/UploadPersistentMediaResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Newtonsoft.Json; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults 7 | { 8 | public class UploadPersistentMediaResult : UploadMediaResult 9 | { 10 | [JsonProperty("url")] 11 | public string Url { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/JsonResults/UploadTemporaryMediaResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Newtonsoft.Json; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults 8 | { 9 | public class UploadTemporaryMediaResult : UploadMediaResult 10 | { 11 | [JsonProperty("type")] 12 | public string Type { get; set; } 13 | 14 | [JsonProperty("thumb_media_id")] 15 | public string ThumbMediaId { get; set; } 16 | 17 | [JsonProperty("created_at")] 18 | public long CreatedAt { get; set; } 19 | 20 | // By wechat description temporary media will expired in 3 days 21 | public override bool Expired() 22 | { 23 | var expiredTime = CreatedAt + (3 * 24 * 60 * 60); 24 | return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() >= expiredTime; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/JsonResults/WeChatJsonResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Globalization; 5 | using Newtonsoft.Json; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults 8 | { 9 | public class WeChatJsonResult 10 | { 11 | /// 12 | /// Gets or sets ErrorCode. 13 | /// 14 | /// 15 | /// Error code from WeChat, default is 0. 16 | /// 17 | [JsonProperty("errcode")] 18 | public int ErrorCode { get; set; } 19 | 20 | /// 21 | /// Gets or sets ErrorMessage. 22 | /// 23 | /// 24 | /// Error message from WeChat, default is 'ok'. 25 | /// 26 | [JsonProperty("errmsg")] 27 | public virtual string ErrorMessage { get; set; } 28 | 29 | public override string ToString() => string.Format(CultureInfo.InvariantCulture, "WeChatJsonResult: {{ErrorCode:'{0}', ErrorMessage:'{1}'}}", ErrorCode, ErrorMessage); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/MediaTypes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 5 | { 6 | public static class MediaTypes 7 | { 8 | /// 9 | /// Image: 2M, support PNG/JEPG/JPG/GIF. 10 | /// 11 | public const string Image = "image"; 12 | 13 | /// 14 | /// Voice: 2M, no longer than 60s, support AMR/MP3. 15 | /// 16 | public const string Voice = "voice"; 17 | 18 | /// 19 | /// Video: 10M, support MP4. 20 | /// 21 | public const string Video = "video"; 22 | 23 | /// 24 | /// General audio type. 25 | /// 26 | public const string Audio = "audio"; 27 | 28 | /// 29 | /// Thumb:64KB,support JPG. 30 | /// 31 | public const string Thumb = "thumb"; 32 | 33 | /// 34 | /// News type. 35 | /// 36 | public const string News = "news"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/MenuItem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Newtonsoft.Json; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 7 | { 8 | public class MenuItem 9 | { 10 | /// 11 | /// Gets or sets Id. 12 | /// 13 | /// 14 | /// Id of the menu item. 15 | /// 16 | [JsonProperty("id")] 17 | public string Id { get; set; } 18 | 19 | /// 20 | /// Gets or sets Content. 21 | /// 22 | /// 23 | /// Content of the menu item. 24 | /// 25 | [JsonProperty("content")] 26 | public string Content { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/MessageMenu.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using Newtonsoft.Json; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 8 | { 9 | public class MessageMenu 10 | { 11 | /// 12 | /// Gets or sets HeaderContent. 13 | /// 14 | /// 15 | /// HeaderContent of the menu. 16 | /// 17 | [JsonProperty("head_content")] 18 | public string HeaderContent { get; set; } 19 | 20 | /// 21 | /// Gets or sets MenuItems. 22 | /// 23 | /// 24 | /// Items in message menu. 25 | /// 26 | [JsonProperty("list")] 27 | public List MenuItems { get; set; } 28 | 29 | /// 30 | /// Gets or sets TailContent. 31 | /// 32 | /// 33 | /// Footer of the menu. 34 | /// 35 | [JsonProperty("tail_content")] 36 | public string TailContent { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Music.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | using Newtonsoft.Json; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 9 | { 10 | [XmlRoot("Music")] 11 | public class Music 12 | { 13 | /// 14 | /// Gets or sets Title. 15 | /// 16 | /// 17 | /// Title of music. 18 | /// 19 | [XmlIgnore] 20 | public string Title { get; set; } 21 | 22 | [XmlElement(ElementName = "Title")] 23 | public XmlCDataSection TitleCData 24 | { 25 | get 26 | { 27 | return new XmlDocument().CreateCDataSection(Title); 28 | } 29 | 30 | set 31 | { 32 | Title = value.Value; 33 | } 34 | } 35 | 36 | /// 37 | /// Gets or sets Description. 38 | /// 39 | /// 40 | /// Description of music. 41 | /// 42 | [XmlIgnore] 43 | public string Description { get; set; } 44 | 45 | [XmlElement(ElementName = "Description")] 46 | public XmlCDataSection DescriptionCData 47 | { 48 | get 49 | { 50 | return new XmlDocument().CreateCDataSection(Description); 51 | } 52 | 53 | set 54 | { 55 | Description = value.Value; 56 | } 57 | } 58 | 59 | /// 60 | /// Gets or sets MusicUrl. 61 | /// 62 | /// 63 | /// Url of music. 64 | /// 65 | [XmlIgnore] 66 | public string MusicUrl { get; set; } 67 | 68 | [XmlElement(ElementName = "MusicUrl")] 69 | public XmlCDataSection MusicUrlCData 70 | { 71 | get 72 | { 73 | return new XmlDocument().CreateCDataSection(MusicUrl); 74 | } 75 | 76 | set 77 | { 78 | MusicUrl = value.Value; 79 | } 80 | } 81 | 82 | /// 83 | /// Gets or sets HQMusicUrl. 84 | /// 85 | /// 86 | /// High quality music Url. 87 | /// 88 | [XmlIgnore] 89 | public string HQMusicUrl { get; set; } 90 | 91 | [XmlElement(ElementName = "HQMusicUrl")] 92 | public XmlCDataSection HQMusicUrlCData 93 | { 94 | get 95 | { 96 | return new XmlDocument().CreateCDataSection(HQMusicUrl); 97 | } 98 | 99 | set 100 | { 101 | HQMusicUrl = value.Value; 102 | } 103 | } 104 | 105 | /// 106 | /// Gets or sets ThumbMediaId. 107 | /// 108 | /// 109 | /// Thumbnail image id of the music. 110 | /// 111 | [XmlIgnore] 112 | public string ThumbMediaId { get; set; } 113 | 114 | [XmlElement(ElementName = "ThumbMediaId")] 115 | public XmlCDataSection ThumbMediaIdCData 116 | { 117 | get 118 | { 119 | return new XmlDocument().CreateCDataSection(ThumbMediaId); 120 | } 121 | 122 | set 123 | { 124 | ThumbMediaId = value.Value; 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/News.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Newtonsoft.Json; 5 | 6 | /// 7 | /// Model for News message. 8 | /// 9 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 10 | { 11 | public class News 12 | { 13 | /// 14 | /// Gets or sets ThumbMediaId. 15 | /// 16 | /// 17 | /// Thumbnail image id. 18 | /// 19 | [JsonProperty("thumb_media_id")] 20 | public string ThumbMediaId { get; set; } 21 | 22 | /// 23 | /// Gets or sets Author. 24 | /// 25 | /// 26 | /// Author of the news. 27 | /// 28 | [JsonProperty("author")] 29 | public string Author { get; set; } 30 | 31 | /// 32 | /// Gets or sets Title. 33 | /// 34 | /// 35 | /// News title. 36 | /// 37 | [JsonProperty("title")] 38 | public string Title { get; set; } 39 | 40 | /// 41 | /// Gets or sets ContentSourceUrl. 42 | /// 43 | /// 44 | /// Link to open when user click open original article. 45 | /// 46 | [JsonProperty("content_source_url")] 47 | public string ContentSourceUrl { get; set; } 48 | 49 | /// 50 | /// Gets or sets Content. 51 | /// 52 | /// 53 | /// News content, support HTML. 54 | /// 55 | [JsonProperty("content")] 56 | public string Content { get; set; } 57 | 58 | /// 59 | /// Gets or sets Description. 60 | /// 61 | /// 62 | /// News description. 63 | /// 64 | [JsonProperty("digest")] 65 | public string Description { get; set; } 66 | 67 | /// 68 | /// Gets or sets ShowCoverPicture. 69 | /// 70 | /// 71 | /// Show cover picture in news detail, 1 is ture, 0 is false. 72 | /// Must be a string. 73 | /// 74 | [JsonProperty("show_cover_pic")] 75 | public string ShowCoverPicture { get; set; } 76 | 77 | /// 78 | /// Gets or sets ThumbUrl. 79 | /// 80 | /// 81 | /// Thumbnail image url. 82 | /// 83 | [JsonProperty("thumb_url")] 84 | public string ThumbUrl { get; set; } 85 | 86 | /// 87 | /// Gets or sets NeedOpenComment. 88 | /// 89 | /// 90 | /// Flag if open comment for news, 1 is true, 0 is false. 91 | /// 92 | [JsonProperty("need_open_comment")] 93 | public int NeedOpenComment { get; set; } 94 | 95 | /// 96 | /// Gets or sets OnlyFansCanComment. 97 | /// 98 | /// 99 | /// Flag only fans can comment, 1 is true, 0 is false. 100 | /// 101 | [JsonProperty("only_fans_can_comment")] 102 | public int OnlyFansCanComment { get; set; } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/CameraEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class CameraEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.Camera; 12 | 13 | [XmlElement(ElementName = "SendPicsInfo")] 14 | public SendPicsInfo SendPicsInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/CameraOrAlbumEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class CameraOrAlbumEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.CameraOrAlbum; 12 | 13 | [XmlElement(ElementName = "SendPicsInfo")] 14 | public SendPicsInfo SendPicsInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ClickEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Click. 10 | /// 11 | [XmlRoot("xml")] 12 | public class ClickEvent : RequestEventWithEventKey 13 | { 14 | /// 15 | /// Gets Event, eventType: CLICK. 16 | /// 17 | /// 18 | /// Event type click. 19 | /// 20 | public override string EventType => EventTypes.Click; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/CopyrightCheckResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("CopyrightCheckResult")] 9 | public class CopyrightCheckResult 10 | { 11 | /// 12 | /// Gets or sets Count. 13 | /// 14 | /// 15 | /// Number of artiles.< 16 | /// 17 | [XmlElement(ElementName = "Count")] 18 | public int Count { get; set; } 19 | 20 | /// 21 | /// Gets or sets ResultList. 22 | /// 23 | /// 24 | /// Single artile check result. 25 | /// 26 | public ResultList ResultList { get; set; } 27 | 28 | /// 29 | /// Gets or sets CheckState. 30 | /// 31 | /// 32 | /// Overall check result 33 | /// 1: not reprint, could be group sending 34 | /// 2: repirnt, could be group sending 35 | /// 3: reprint, could not send. 36 | /// 37 | [XmlElement(ElementName = "CheckState")] 38 | public int CheckState { get; set; } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/EnterEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Enter a conversation. 10 | /// 11 | [XmlRoot("xml")] 12 | public class EnterEvent : RequestEvent 13 | { 14 | /// 15 | /// Gets event, EventType: ENTER. 16 | /// 17 | /// 18 | /// EventType: ENTER. 19 | /// 20 | public override string EventType => EventTypes.Enter; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/IRequestMessageEventBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 5 | { 6 | public interface IRequestMessageEventBase : IRequestMessageBase 7 | { 8 | string EventType { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/LocationEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Get user's location 10 | /// Two method to get location: 11 | /// 1. submit location when user enter the conversation 12 | /// 2. submit location every 5 seconds after user enter the conversation. 13 | /// 14 | [XmlRoot("xml")] 15 | public class LocationEvent : RequestEvent 16 | { 17 | /// 18 | /// Gets event, EventType: LOCATION. 19 | /// 20 | /// 21 | /// EventType: LOCATION. 22 | /// 23 | public override string EventType => EventTypes.Location; 24 | 25 | /// 26 | /// Gets or sets latitude. 27 | /// 28 | /// 29 | /// Latitude, exist when EventType is Location. 30 | /// 31 | [XmlElement(ElementName = "Latitude")] 32 | public double Latitude { get; set; } 33 | 34 | /// 35 | /// Gets or sets longitude. 36 | /// 37 | /// 38 | /// Longitude, exist when EventType is Location. 39 | /// 40 | [XmlElement(ElementName = "Longitude")] 41 | public double Longitude { get; set; } 42 | 43 | /// 44 | /// Gets or sets precision. 45 | /// 46 | /// 47 | /// Precision, exist when EventType is Location. 48 | /// 49 | [XmlElement(ElementName = "Precision")] 50 | public double Precision { get; set; } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/MD5Sum.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | public class MD5Sum 9 | { 10 | [XmlElement(ElementName = "PicMd5Sum")] 11 | public string PicMD5Sum { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/MassSendJobFinishedEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Group message send finish event. 10 | /// 11 | [XmlRoot("xml")] 12 | public class MassSendJobFinishedEvent : RequestEvent 13 | { 14 | /// 15 | /// Gets event EventType: MASSSENDJOBFINISH. 16 | /// 17 | /// 18 | /// EventType: MASSSENDJOBFINISH. 19 | /// 20 | public override string EventType => EventTypes.MassSendJobFinished; 21 | 22 | /// 23 | /// Gets or sets status code. 24 | /// 25 | /// 26 | /// Status code. 27 | /// 28 | [XmlElement(ElementName = "Status")] 29 | public string Status { get; set; } 30 | 31 | /// 32 | /// Gets or sets TotalCount. 33 | /// 34 | /// 35 | /// Number of subscribers under group_id or openid_list. 36 | /// 37 | [XmlElement(ElementName = "TotalCount")] 38 | public int TotalCount { get; set; } 39 | 40 | /// 41 | /// Gets or sets FilterCount. 42 | /// 43 | /// 44 | /// Number of subscribers that message is going to be sent 45 | /// FilterCount = SentCount + ErrorCount. 46 | /// 47 | [XmlElement(ElementName = "FilterCount")] 48 | public int FilterCount { get; set; } 49 | 50 | /// 51 | /// Gets or sets SentCount. 52 | /// 53 | /// 54 | /// Number of subscribers that message is successfully sent. 55 | /// 56 | [XmlElement(ElementName = "SentCount")] 57 | public int SentCount { get; set; } 58 | 59 | /// 60 | /// Gets or sets ErrorCount. 61 | /// 62 | /// 63 | /// Number of subscribers that message is not sent. 64 | /// 65 | [XmlElement(ElementName = "ErrorCount")] 66 | public int ErrorCount { get; set; } 67 | 68 | /// 69 | /// Gets or sets MsgID. 70 | /// 71 | /// 72 | /// Group message id. 73 | /// 74 | [XmlElement(ElementName = "MsgID")] 75 | public long MsgID { get; set; } 76 | 77 | // [XmlElement(ElementName = "CopyrightCheckResult")] 78 | public CopyrightCheckResult CopyrightCheckResult { get; set; } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/PicItem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | public class PicItem 9 | { 10 | [XmlElement(ElementName = "item")] 11 | public MD5Sum Item { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/RequestEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | public abstract class RequestEvent : IRequestMessageEventBase 9 | { 10 | /// 11 | /// Gets the event type. 12 | /// 13 | /// 14 | /// The event type, should be one of EventType. 15 | /// 16 | [XmlElement(ElementName = "Event")] 17 | public virtual string EventType { get; } 18 | 19 | [XmlElement(ElementName = "Encrypt")] 20 | public string Encrypt { get; set; } 21 | 22 | /// 23 | /// Gets event message type. 24 | /// 25 | /// 26 | /// Event message type, should be a static value. 27 | /// 28 | public string MsgType => RequestMessageTypes.Event; 29 | 30 | /// 31 | /// Gets or sets ToUserName. 32 | /// 33 | /// 34 | /// Recipient openId. 35 | /// 36 | [XmlElement(ElementName = "ToUserName")] 37 | public string ToUserName { get; set; } 38 | 39 | /// 40 | /// Gets or sets FromUserName. 41 | /// 42 | /// 43 | /// Sender openId. 44 | /// 45 | [XmlElement(ElementName = "FromUserName")] 46 | public string FromUserName { get; set; } 47 | 48 | /// 49 | /// Gets or sets CreateTime. 50 | /// 51 | /// 52 | /// Message creation time. 53 | /// 54 | [XmlElement(ElementName = "CreateTime")] 55 | public long CreateTime { get; set; } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/RequestEventWithEventKey.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Request Event with event key, most likly comming from static menu event. 10 | /// 11 | public abstract class RequestEventWithEventKey : RequestEvent 12 | { 13 | [XmlElement(ElementName = "EventKey")] 14 | public string EventKey { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ResultList.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 8 | { 9 | [XmlRoot("ResultList")] 10 | public class ResultList 11 | { 12 | [XmlElement(ElementName = "item")] 13 | public List Items { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ResultListItem.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("item")] 9 | public class ResultListItem 10 | { 11 | /// 12 | /// Gets or sets ArticleIdx. 13 | /// 14 | /// 15 | /// Index of group sending artiles, start from 1. 16 | /// 17 | [XmlElement(ElementName = "ArticleIdx")] 18 | public int ArticleIdx { get; set; } 19 | 20 | /// 21 | /// Gets or sets UserDeclareState. 22 | /// 23 | /// 24 | /// User declares state of artile. 25 | /// 26 | [XmlElement(ElementName = "UserDeclareState")] 27 | public int UserDeclareState { get; set; } 28 | 29 | /// 30 | /// Gets or sets AuditState. 31 | /// 32 | /// 33 | /// State of system check. 34 | /// 35 | [XmlElement(ElementName = "AuditState")] 36 | public int AuditState { get; set; } 37 | 38 | /// 39 | /// Gets or sets OriginalArticleUrl. 40 | /// 41 | /// 42 | /// Url of Similar orginal artile. 43 | /// 44 | [XmlElement(ElementName = "OriginalArticleUrl")] 45 | public string OriginalArticleUrl { get; set; } 46 | 47 | /// 48 | /// Gets or sets OriginalArticleType. 49 | /// 50 | /// 51 | /// Type of Similar original artile. 52 | /// 53 | [XmlElement(ElementName = "OriginalArticleType")] 54 | public int OriginalArticleType { get; set; } 55 | 56 | /// 57 | /// Gets or sets CanReprint. 58 | /// 59 | /// 60 | /// Reprint or not. 61 | /// 62 | [XmlElement(ElementName = "CanReprint")] 63 | public int CanReprint { get; set; } 64 | 65 | /// 66 | /// Gets or sets NeedReplaceContent. 67 | /// 68 | /// 69 | /// Replace by original content or not. 70 | /// 71 | [XmlElement(ElementName = "NeedReplaceContent")] 72 | public int NeedReplaceContent { get; set; } 73 | 74 | /// 75 | /// Gets or sets NeedShowReprintSource. 76 | /// 77 | /// 78 | /// Show reprint source or not. 79 | /// 80 | [XmlElement(ElementName = "NeedShowReprintSource")] 81 | public int NeedShowReprintSource { get; set; } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ScanCodeInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | public class ScanCodeInfo 9 | { 10 | [XmlElement(ElementName = "ScanType")] 11 | public string ScanType { get; set; } 12 | 13 | [XmlElement(ElementName = "ScanResult")] 14 | public string ScanResult { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ScanEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Scan QR code. 10 | /// 11 | [XmlRoot("xml")] 12 | public class ScanEvent : RequestEventWithEventKey 13 | { 14 | /// 15 | /// Gets event, EventType: scan. 16 | /// 17 | /// 18 | /// EventType: scan. 19 | /// 20 | public override string EventType => EventTypes.Scan; 21 | 22 | /// 23 | /// Gets or sets Ticket. 24 | /// 25 | /// 26 | /// Use to get QR code picture. 27 | /// 28 | [XmlElement(ElementName = "Ticket")] 29 | public string Ticket { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ScanPushEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class ScanPushEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.ScanPush; 12 | 13 | [XmlElement(ElementName = "ScanCodeInfo")] 14 | public ScanCodeInfo ScanCodeInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/SelectLocationEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class SelectLocationEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.SelectLocation; 12 | 13 | [XmlElement(ElementName = "SendLocationInfo")] 14 | public SendLocationInfo SendLocationInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/SendLocationInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | public class SendLocationInfo 9 | { 10 | /// 11 | /// Gets or sets Latitude. 12 | /// 13 | /// 14 | /// The latitude infomation. 15 | /// 16 | [XmlElement(ElementName = "Location_X")] 17 | public string Latitude { get; set; } 18 | 19 | /// 20 | /// Gets or sets Longtitude. 21 | /// 22 | /// 23 | /// The longtitude information. 24 | /// 25 | [XmlElement(ElementName = "Location_Y")] 26 | public string Longtitude { get; set; } 27 | 28 | /// 29 | /// Gets or sets scale. 30 | /// 31 | /// 32 | /// Map zoom size information. 33 | /// 34 | [XmlElement(ElementName = "Scale")] 35 | public string Scale { get; set; } 36 | 37 | /// 38 | /// Gets or sets Label. 39 | /// 40 | /// 41 | /// Geolocation information in text. 42 | /// 43 | [XmlElement(ElementName = "Label")] 44 | public string Label { get; set; } 45 | 46 | /// 47 | /// Gets or sets PoiName. 48 | /// 49 | /// 50 | /// POI name at Friend Zone. 51 | /// 52 | [XmlElement(ElementName = "Poiname")] 53 | public string PoiName { get; set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/SendPicsInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 8 | { 9 | public class SendPicsInfo 10 | { 11 | [XmlElement(ElementName = "Count")] 12 | public int Count { get; set; } 13 | 14 | [XmlElement(ElementName = "PicList")] 15 | public List PicList { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/SubscribeEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Subscribe. 10 | /// 11 | [XmlRoot("xml")] 12 | public class SubscribeEvent : RequestEventWithEventKey 13 | { 14 | /// 15 | /// Gets event, EventType: subscribe. 16 | /// 17 | /// 18 | /// EventType: subscribe. 19 | /// 20 | public override string EventType => EventTypes.Subscribe; 21 | 22 | /// 23 | /// Gets or sets Ticket. 24 | /// 25 | /// 26 | /// Use to get QR code picture. 27 | /// 28 | [XmlElement(ElementName = "Ticket")] 29 | public string Ticket { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/TemplateSendFinishedEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class TemplateSendFinishedEvent : RequestEvent 10 | { 11 | public override string EventType => EventTypes.TemplateSendFinished; 12 | 13 | [XmlElement(ElementName = "Status")] 14 | public string Status { get; set; } 15 | 16 | [XmlElement(ElementName = "MsgID")] 17 | public long MsgID { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/UnsunscribeEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// unsubscribe. 10 | /// 11 | [XmlRoot("xml")] 12 | public class UnsunscribeEvent : RequestEvent 13 | { 14 | /// 15 | /// Gets event, EventType: unsubscribe. 16 | /// 17 | /// 18 | /// EventType: unsubscribe. 19 | /// 20 | public override string EventType => EventTypes.Unsubscribe; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ViewEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | /// 9 | /// Url jump to view. 10 | /// 11 | [XmlRoot("xml")] 12 | public class ViewEvent : RequestEventWithEventKey 13 | { 14 | /// 15 | /// Gets event, EventType: VIEW. 16 | /// 17 | /// 18 | /// EventType: VIEW. 19 | /// 20 | public override string EventType => EventTypes.View; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/ViewMiniProgramEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class ViewMiniProgramEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.ViewMiniProgram; 12 | 13 | [XmlElement(ElementName = "MenuId")] 14 | public string MenuId { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/WaitScanPushEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class WaitScanPushEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.WaitScanPush; 12 | 13 | [XmlElement(ElementName = "ScanCodeInfo")] 14 | public ScanCodeInfo ScanCodeInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/Events/WeChatAlbumEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events 7 | { 8 | [XmlRoot("xml")] 9 | public class WeChatAlbumEvent : RequestEventWithEventKey 10 | { 11 | public override string EventType => EventTypes.WeChatAlbum; 12 | 13 | [XmlElement(ElementName = "SendPicsInfo")] 14 | public SendPicsInfo SendPicsInfo { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/IRequestMessageBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 5 | { 6 | public interface IRequestMessageBase 7 | { 8 | /// 9 | /// Gets MsgType. 10 | /// 11 | /// 12 | /// Message type of the request. 13 | /// 14 | string MsgType { get; } 15 | 16 | string Encrypt { get; set; } 17 | 18 | /// 19 | /// Gets or sets ToUserName. 20 | /// 21 | /// 22 | /// Recipient OpenId from WeChat. 23 | /// 24 | string ToUserName { get; set; } 25 | 26 | /// 27 | /// Gets or sets FromUserName. 28 | /// 29 | /// 30 | /// Sender OpenId from WeChat. 31 | /// 32 | string FromUserName { get; set; } 33 | 34 | /// 35 | /// Gets or sets CreateTime. 36 | /// 37 | /// 38 | /// Message Created time. 39 | /// 40 | long CreateTime { get; set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/ImageRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | [XmlRoot("xml")] 9 | public class ImageRequest : RequestMessage 10 | { 11 | public override string MsgType => RequestMessageTypes.Image; 12 | 13 | /// 14 | /// Gets or sets MediaId. 15 | /// 16 | /// 17 | /// Media id of the image. 18 | /// 19 | [XmlElement(ElementName = "MediaId")] 20 | public string MediaId { get; set; } 21 | 22 | /// 23 | /// Gets or sets PicUrl. 24 | /// 25 | /// 26 | /// Image's link. 27 | /// 28 | [XmlElement(ElementName = "PicUrl")] 29 | public string PicUrl { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/LinkRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | /// 9 | /// Link request is used to share some online aritclies. 10 | /// 11 | [XmlRoot("xml")] 12 | public class LinkRequest : RequestMessage 13 | { 14 | public override string MsgType => RequestMessageTypes.Link; 15 | 16 | [XmlElement(ElementName = "Title")] 17 | public string Title { get; set; } 18 | 19 | [XmlElement(ElementName = "Description")] 20 | public string Description { get; set; } 21 | 22 | [XmlElement(ElementName = "Url")] 23 | public string Url { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/LocationRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | [XmlRoot("xml")] 9 | public class LocationRequest : RequestMessage 10 | { 11 | public override string MsgType => RequestMessageTypes.Location; 12 | 13 | /// 14 | /// Gets or sets Latitude. 15 | /// 16 | /// 17 | /// The latitude infomation. 18 | /// 19 | [XmlElement(ElementName = "Location_X")] 20 | public double Latitude { get; set; } 21 | 22 | /// 23 | /// Gets or sets Longtitude. 24 | /// 25 | /// 26 | /// The longtitude infomation. 27 | /// 28 | [XmlElement(ElementName = "Location_Y")] 29 | public double Longtitude { get; set; } 30 | 31 | /// 32 | /// Gets or sets Scale. 33 | /// 34 | /// 35 | /// Map zoom size. 36 | /// 37 | [XmlElement(ElementName = "Scale")] 38 | public int Scale { get; set; } 39 | 40 | /// 41 | /// Gets or sets Label. 42 | /// 43 | /// 44 | /// Geolocation information in text. 45 | /// 46 | [XmlElement(ElementName = "Label")] 47 | public string Label { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/RequestMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | /// 9 | /// Base class of the request from wechat. 10 | /// TODO: may need to be an abstract class, force user to implement MsgType. 11 | /// 12 | [XmlRoot("xml")] 13 | public abstract class RequestMessage : IRequestMessageBase 14 | { 15 | /// 16 | /// Gets or sets MsgId. 17 | /// 18 | /// 19 | /// Message id, required except event message. 20 | /// 21 | [XmlElement(ElementName = "MsgId")] 22 | public long MsgId { get; set; } 23 | 24 | [XmlElement(ElementName = "Encrypt")] 25 | public string Encrypt { get; set; } 26 | 27 | /// 28 | /// Gets MsgType. 29 | /// 30 | /// 31 | /// Message type of the request message, override it if needed. 32 | /// 33 | [XmlElement(ElementName = "MsgType")] 34 | public abstract string MsgType { get; } 35 | 36 | /// 37 | /// Gets or sets ToUserName. 38 | /// 39 | /// 40 | /// Recipient openId. 41 | /// 42 | [XmlElement(ElementName = "ToUserName")] 43 | public string ToUserName { get; set; } 44 | 45 | /// 46 | /// Gets or sets FromUserName. 47 | /// 48 | /// 49 | /// Sender openId. 50 | /// 51 | [XmlElement(ElementName = "FromUserName")] 52 | public string FromUserName { get; set; } 53 | 54 | /// 55 | /// Gets or sets CreateTime. 56 | /// 57 | /// 58 | /// Message creation time. 59 | /// 60 | [XmlElement(ElementName = "CreateTime")] 61 | public long CreateTime { get; set; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/RequestMessageTypes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 5 | { 6 | /// 7 | /// Request Message types. 8 | /// 9 | public static class RequestMessageTypes 10 | { 11 | /// 12 | /// Request message type: Unknown. 13 | /// 14 | public const string Unknown = "unknown"; 15 | 16 | /// 17 | /// Request message type: Text. 18 | /// 19 | public const string Text = "text"; 20 | 21 | /// 22 | /// Request message type: Location. 23 | /// 24 | public const string Location = "location"; 25 | 26 | /// 27 | /// Request message type: Image. 28 | /// 29 | public const string Image = "image"; 30 | 31 | /// 32 | /// Request message type: Voice. 33 | /// 34 | public const string Voice = "voice"; 35 | 36 | /// 37 | /// Request message type: Video. 38 | /// 39 | public const string Video = "video"; 40 | 41 | /// 42 | /// Request message type: Link. 43 | /// 44 | public const string Link = "link"; 45 | 46 | /// 47 | /// Request message type: ShortVideo. 48 | /// 49 | public const string ShortVideo = "shortvideo"; 50 | 51 | /// 52 | /// Request message type: Event. 53 | /// 54 | public const string Event = "event"; 55 | 56 | /// 57 | /// Request message type: File. 58 | /// 59 | public const string File = "file"; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/ShortVideoRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | [XmlRoot("xml")] 9 | public class ShortVideoRequest : RequestMessage 10 | { 11 | public override string MsgType => RequestMessageTypes.ShortVideo; 12 | 13 | [XmlElement(ElementName = "MediaId")] 14 | public string MediaId { get; set; } 15 | 16 | [XmlElement(ElementName = "ThumbMediaId")] 17 | public string ThumbMediaId { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/TextRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | [XmlRoot("xml")] 9 | public class TextRequest : RequestMessage 10 | { 11 | public override string MsgType => RequestMessageTypes.Text; 12 | 13 | [XmlElement(ElementName = "Content")] 14 | public string Content { get; set; } 15 | 16 | [XmlElement(ElementName = "bizmsgmenuid")] 17 | public string Bizmsgmenuid { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/UnknowRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Linq; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 8 | { 9 | [XmlRoot("xml")] 10 | public class UnknowRequest : RequestMessage 11 | { 12 | public override string MsgType => RequestMessageTypes.Unknown; 13 | 14 | /// 15 | /// Gets or sets Content. 16 | /// 17 | /// 18 | /// Original request body of the unknow type, should be xml format. 19 | /// 20 | [XmlElement(ElementName = "Content")] 21 | public XDocument Content { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/VideoRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | [XmlRoot("xml")] 9 | public class VideoRequest : RequestMessage 10 | { 11 | public override string MsgType => RequestMessageTypes.Video; 12 | 13 | [XmlElement(ElementName = "MediaId")] 14 | public string MediaId { get; set; } 15 | 16 | [XmlElement(ElementName = "ThumbMediaId")] 17 | public string ThumbMediaId { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Requests/VoiceRequest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml.Serialization; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests 7 | { 8 | [XmlRoot("xml")] 9 | public class VoiceRequest : RequestMessage 10 | { 11 | public override string MsgType => RequestMessageTypes.Voice; 12 | 13 | [XmlElement(ElementName = "MediaId")] 14 | public string MediaId { get; set; } 15 | 16 | [XmlElement(ElementName = "Format")] 17 | public string Format { get; set; } 18 | 19 | [XmlElement(ElementName = "Recognition")] 20 | public string Recognition { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/IResponseMessageBase.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 5 | { 6 | public interface IResponseMessageBase 7 | { 8 | string MsgType { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/ImageResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 8 | { 9 | [XmlRoot("xml")] 10 | public class ImageResponse : ResponseMessage 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public ImageResponse() 16 | : base() 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The sender's id. 24 | /// The recipient id. 25 | /// The media id of the image. 26 | public ImageResponse(string senderId, string recipientId, string mediaId) 27 | : base(senderId, recipientId) 28 | { 29 | Image = new Image(mediaId); 30 | } 31 | 32 | [XmlIgnore] 33 | public override string MsgType => ResponseMessageTypes.Image; 34 | 35 | [XmlElement(ElementName = "MsgType")] 36 | public XmlCDataSection MsgTypeCData 37 | { 38 | get 39 | { 40 | return new XmlDocument().CreateCDataSection(MsgType); 41 | } 42 | 43 | set 44 | { 45 | MsgType = value.Value; 46 | } 47 | } 48 | 49 | [XmlElement(ElementName = "Image")] 50 | public Image Image { get; set; } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/MPNewsResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 5 | { 6 | public class MPNewsResponse : ResponseMessage 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | public MPNewsResponse() 12 | : base() 13 | { 14 | } 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The sender's id. 20 | /// The recipient id. 21 | /// The media id of the mpnews. 22 | public MPNewsResponse(string senderId, string recipientId, string mediaId) 23 | : base(senderId, recipientId) 24 | { 25 | MediaId = mediaId; 26 | } 27 | 28 | public override string MsgType => ResponseMessageTypes.MPNews; 29 | 30 | public string MediaId { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/MessageMenuResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 5 | { 6 | public class MessageMenuResponse : ResponseMessage 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | public MessageMenuResponse() 12 | : base() 13 | { 14 | } 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The sender's id. 20 | /// The recipient id. 21 | public MessageMenuResponse(string senderId, string recipientId) 22 | : base(senderId, recipientId) 23 | { 24 | } 25 | 26 | public MessageMenu MessageMenu { get; set; } 27 | 28 | public override string MsgType => ResponseMessageTypes.MessageMenu; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/MusicResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 8 | { 9 | [XmlRoot("xml")] 10 | public class MusicResponse : ResponseMessage 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public MusicResponse() 16 | : base() 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The sender's id. 24 | /// The recipient id. 25 | /// The of the music resposne. 26 | public MusicResponse(string senderId, string recipientId, Music music) 27 | : base(senderId, recipientId) 28 | { 29 | Music = music; 30 | } 31 | 32 | [XmlIgnore] 33 | public override string MsgType => ResponseMessageTypes.Music; 34 | 35 | [XmlElement(ElementName = "MsgType")] 36 | public XmlCDataSection MsgTypeCData 37 | { 38 | get 39 | { 40 | return new XmlDocument().CreateCDataSection(MsgType); 41 | } 42 | 43 | set 44 | { 45 | MsgType = value.Value; 46 | } 47 | } 48 | 49 | [XmlElement(ElementName = "Music")] 50 | public Music Music { get; set; } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/NewsResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.Xml; 6 | using System.Xml.Serialization; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 9 | { 10 | [XmlRoot("xml")] 11 | public class NewsResponse : ResponseMessage 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | public NewsResponse() 17 | : base() 18 | { 19 | Articles = new List
(); 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The sender's id. 26 | /// The recipient id. 27 | /// The article list in news response. 28 | public NewsResponse(string senderId, string recipientId, List
articles) 29 | : base(senderId, recipientId) 30 | { 31 | Articles = articles; 32 | } 33 | 34 | [XmlIgnore] 35 | public override string MsgType => ResponseMessageTypes.News; 36 | 37 | [XmlElement(ElementName = "MsgType")] 38 | public XmlCDataSection MsgTypeCData 39 | { 40 | get 41 | { 42 | return new XmlDocument().CreateCDataSection(MsgType); 43 | } 44 | 45 | set 46 | { 47 | MsgType = value.Value; 48 | } 49 | } 50 | 51 | [XmlElement(ElementName = "ArticleCount")] 52 | public int ArticleCount 53 | { 54 | get 55 | { 56 | return Articles == null ? 0 : Articles.Count; 57 | } 58 | 59 | set 60 | { 61 | } 62 | } 63 | 64 | /// 65 | /// Gets or sets Articles. 66 | /// 67 | /// 68 | /// Article list, can only show up to 10 article. 69 | /// 70 | [XmlElement(ElementName = "item")] 71 | public List
Articles { get; set; } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/ResponseMessage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Xml; 6 | using System.Xml.Serialization; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 9 | { 10 | /// 11 | /// Base class for all WeChat response message. 12 | /// 13 | public abstract class ResponseMessage : IResponseMessageBase 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public ResponseMessage() 19 | { 20 | CreateTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The sender's id. 27 | /// The recipient id. 28 | public ResponseMessage(string senderId, string recipientId) 29 | { 30 | ToUserName = senderId; 31 | FromUserName = recipientId; 32 | CreateTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); 33 | } 34 | 35 | /// 36 | /// Gets or sets ToUserName. 37 | /// 38 | /// 39 | /// Recipient openId. 40 | /// 41 | [XmlIgnore] 42 | public string ToUserName { get; set; } 43 | 44 | [XmlElement(ElementName = "ToUserName")] 45 | public XmlCDataSection ToUserNameCData 46 | { 47 | get 48 | { 49 | return new XmlDocument().CreateCDataSection(ToUserName); 50 | } 51 | 52 | set 53 | { 54 | ToUserName = value.Value; 55 | } 56 | } 57 | 58 | /// 59 | /// Gets or sets FromUserName. 60 | /// 61 | /// 62 | /// Sender openId. 63 | /// 64 | [XmlIgnore] 65 | public string FromUserName { get; set; } 66 | 67 | [XmlElement(ElementName = "FromUserName")] 68 | public XmlCDataSection FromUserNameCData 69 | { 70 | get 71 | { 72 | return new XmlDocument().CreateCDataSection(FromUserName); 73 | } 74 | 75 | set 76 | { 77 | FromUserName = value.Value; 78 | } 79 | } 80 | 81 | /// 82 | /// Gets or sets creation time. 83 | /// 84 | /// 85 | /// Message creation time. 86 | /// 87 | [XmlElement(ElementName = "CreateTime")] 88 | public long CreateTime { get; set; } 89 | 90 | /// 91 | /// Gets or sets message type. 92 | /// 93 | /// /// 94 | /// Response message type. 95 | /// 96 | [XmlIgnore] 97 | public virtual string MsgType { get; set; } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/ResponseMessageTypes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 5 | { 6 | public static class ResponseMessageTypes 7 | { 8 | /// 9 | /// Text message. 10 | /// 11 | public const string Text = "text"; 12 | 13 | /// 14 | /// News message. 15 | /// 16 | public const string News = "news"; 17 | 18 | /// 19 | /// Music message. 20 | /// 21 | public const string Music = "music"; 22 | 23 | /// 24 | /// Image message. 25 | /// 26 | public const string Image = "image"; 27 | 28 | /// 29 | /// Voice message. 30 | /// 31 | public const string Voice = "voice"; 32 | 33 | /// 34 | /// Video message. 35 | /// 36 | public const string Video = "video"; 37 | 38 | /// 39 | /// MPNews message. 40 | /// 41 | public const string MPNews = "mpnews"; 42 | 43 | /// 44 | /// MultipleNews message. 45 | /// 46 | public const string MultipleNews = "mutiplenews"; 47 | 48 | /// 49 | /// MessageMenu message. 50 | /// 51 | public const string MessageMenu = "msgmenu"; 52 | 53 | /// 54 | /// Location message. 55 | /// 56 | public const string LocationMessage = "location"; 57 | 58 | /// 59 | /// No responese message. 60 | /// 61 | public const string NoResponse = "noresponse"; 62 | 63 | /// 64 | /// Success response message. 65 | /// 66 | public const string SuccessResponse = "successresponse"; 67 | 68 | /// 69 | /// Unknown message. 70 | /// 71 | public const string Unknown = "unknown"; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/TextResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 8 | { 9 | [XmlRoot("xml")] 10 | public class TextResponse : ResponseMessage 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public TextResponse() 16 | : base() 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The sender's id. 24 | /// The recipient id. 25 | /// The content of the text response. 26 | public TextResponse(string senderId, string recipientId, string content) 27 | : base(senderId, recipientId) 28 | { 29 | Content = content; 30 | } 31 | 32 | [XmlIgnore] 33 | public override string MsgType => ResponseMessageTypes.Text; 34 | 35 | [XmlElement(ElementName = "MsgType")] 36 | public XmlCDataSection MsgTypeCData 37 | { 38 | get 39 | { 40 | return new XmlDocument().CreateCDataSection(MsgType); 41 | } 42 | 43 | set 44 | { 45 | MsgType = value.Value; 46 | } 47 | } 48 | 49 | [XmlIgnore] 50 | public string Content { get; set; } 51 | 52 | [XmlElement(ElementName = "Content")] 53 | public XmlCDataSection ContentCData 54 | { 55 | get 56 | { 57 | return new XmlDocument().CreateCDataSection(Content); 58 | } 59 | 60 | set 61 | { 62 | Content = value.Value; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/VideoResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 8 | { 9 | [XmlRoot("xml")] 10 | public class VideoResponse : ResponseMessage 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public VideoResponse() 16 | : base() 17 | { 18 | } 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | /// The sender's id. 24 | /// The recipient id. 25 | /// The of the video resposne. 26 | public VideoResponse(string senderId, string recipientId, Video video) 27 | : base(senderId, recipientId) 28 | { 29 | Video = video; 30 | } 31 | 32 | [XmlIgnore] 33 | public override string MsgType => ResponseMessageTypes.Video; 34 | 35 | [XmlElement(ElementName = "MsgType")] 36 | public XmlCDataSection MsgTypeCData 37 | { 38 | get 39 | { 40 | return new XmlDocument().CreateCDataSection(MsgType); 41 | } 42 | 43 | set 44 | { 45 | MsgType = value.Value; 46 | } 47 | } 48 | 49 | [XmlElement(ElementName = "Video")] 50 | public Video Video { get; set; } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Responses/VoiceResponse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema.Responses 8 | { 9 | [XmlRoot("xml")] 10 | public class VoiceResponse : ResponseMessage 11 | { 12 | public VoiceResponse() 13 | : base() 14 | { 15 | } 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The sender's id. 21 | /// The recipient id. 22 | /// The media id of the voice. 23 | public VoiceResponse(string senderId, string recipientId, string mediaId) 24 | : base(senderId, recipientId) 25 | { 26 | Voice = new Voice(mediaId); 27 | } 28 | 29 | [XmlIgnore] 30 | public override string MsgType => ResponseMessageTypes.Voice; 31 | 32 | [XmlElement(ElementName = "MsgType")] 33 | public XmlCDataSection MsgTypeCData 34 | { 35 | get 36 | { 37 | return new XmlDocument().CreateCDataSection(MsgType); 38 | } 39 | 40 | set 41 | { 42 | MsgType = value.Value; 43 | } 44 | } 45 | 46 | [XmlElement(ElementName = "Voice")] 47 | public Voice Voice { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/SecretInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.AspNetCore.Mvc; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 7 | { 8 | /// 9 | /// Secret info store the parameter used to verify the message from WeChat and decrypt message content. 10 | /// 11 | public class SecretInfo 12 | { 13 | /// 14 | /// Gets or Sets signature from WeChat update webhook request. 15 | /// 16 | /// 17 | /// signature from WeChat update webhook request. 18 | /// 19 | [FromQuery(Name = "signature")] 20 | public string WebhookSignature { get; set; } 21 | 22 | /// 23 | /// Gets or Sets signature from WeChat message request. 24 | /// 25 | /// 26 | /// Signature from WeChat message request. 27 | /// 28 | [FromQuery(Name = "msg_signature")] 29 | public string MessageSignature { get; set; } 30 | 31 | /// 32 | /// Gets or Sets echo string from WeChat message request. 33 | /// 34 | /// 35 | /// Echo string from WeChat message request. 36 | /// 37 | [FromQuery(Name = "echostr")] 38 | public string EchoString { get; set; } 39 | 40 | /// 41 | /// Gets or Sets timestamp. 42 | /// 43 | /// 44 | /// Timestamp of the request parameter. 45 | /// 46 | [FromQuery(Name = "timestamp")] 47 | public string Timestamp { get; set; } 48 | 49 | /// 50 | /// Gets or Sets nonce. 51 | /// 52 | /// 53 | /// Nonce of the request parameter. 54 | /// 55 | [FromQuery(Name = "nonce")] 56 | public string Nonce { get; set; } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Video.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 8 | { 9 | [XmlRoot("Video")] 10 | public class Video 11 | { 12 | public Video() 13 | { 14 | } 15 | 16 | public Video(string mediaId, string title = null, string description = null) 17 | { 18 | MediaId = mediaId; 19 | Title = title; 20 | Description = description; 21 | } 22 | 23 | [XmlIgnore] 24 | public string MediaId { get; set; } 25 | 26 | [XmlElement(ElementName = "MediaId")] 27 | public XmlCDataSection MediaIdCData 28 | { 29 | get 30 | { 31 | return new XmlDocument().CreateCDataSection(MediaId); 32 | } 33 | 34 | set 35 | { 36 | MediaId = value.Value; 37 | } 38 | } 39 | 40 | [XmlIgnore] 41 | public string Title { get; set; } 42 | 43 | [XmlElement(ElementName = "Title")] 44 | public XmlCDataSection TitleCData 45 | { 46 | get 47 | { 48 | return new XmlDocument().CreateCDataSection(Title); 49 | } 50 | 51 | set 52 | { 53 | Title = value.Value; 54 | } 55 | } 56 | 57 | [XmlIgnore] 58 | public string Description { get; set; } 59 | 60 | [XmlElement(ElementName = "Description")] 61 | public XmlCDataSection DescriptionCData 62 | { 63 | get 64 | { 65 | return new XmlDocument().CreateCDataSection(Description); 66 | } 67 | 68 | set 69 | { 70 | Description = value.Value; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/Voice.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Xml; 5 | using System.Xml.Serialization; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 8 | { 9 | [XmlRoot("Voice")] 10 | public class Voice 11 | { 12 | public Voice() 13 | { 14 | } 15 | 16 | public Voice(string mediaId) 17 | { 18 | MediaId = mediaId; 19 | } 20 | 21 | [XmlIgnore] 22 | public string MediaId { get; set; } 23 | 24 | [XmlElement(ElementName = "MediaId")] 25 | public XmlCDataSection MediaIdCData 26 | { 27 | get 28 | { 29 | return new XmlDocument().CreateCDataSection(MediaId); 30 | } 31 | 32 | set 33 | { 34 | MediaId = value.Value; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Schema/WeChatAccessToken.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Schema 7 | { 8 | public class WeChatAccessToken : IStoreItem 9 | { 10 | public WeChatAccessToken() 11 | { 12 | ExpireTime = DateTimeOffset.MinValue; 13 | } 14 | 15 | public string AppId { get; set; } 16 | 17 | public string Token { get; set; } 18 | 19 | public string Secret { get; set; } 20 | 21 | public DateTimeOffset ExpireTime { get; set; } 22 | 23 | public string ETag { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Storage/AccessTokenStorage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema; 9 | 10 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Storage 11 | { 12 | internal class AccessTokenStorage : IWeChatStorage, IDisposable 13 | { 14 | private readonly IStorage _storage; 15 | private SemaphoreSlim _semaphore; 16 | 17 | public AccessTokenStorage(IStorage storage) 18 | { 19 | _storage = storage; 20 | _semaphore = new SemaphoreSlim(1); 21 | } 22 | 23 | public async Task SaveAsync(string key, WeChatAccessToken value, CancellationToken cancellationToken = default(CancellationToken)) 24 | { 25 | try 26 | { 27 | await _semaphore.WaitAsync().ConfigureAwait(false); 28 | var dict = new Dictionary 29 | { 30 | { key, value }, 31 | }; 32 | await _storage.WriteAsync(dict, cancellationToken).ConfigureAwait(false); 33 | } 34 | finally 35 | { 36 | _semaphore.Release(); 37 | } 38 | } 39 | 40 | public async Task GetAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) 41 | { 42 | try 43 | { 44 | await _semaphore.WaitAsync().ConfigureAwait(false); 45 | var keys = new string[] { key }; 46 | var result = await _storage.ReadAsync(keys, cancellationToken).ConfigureAwait(false); 47 | result.TryGetValue(key, out var wechatResult); 48 | 49 | if (IfTokenExpired(wechatResult)) 50 | { 51 | return null; 52 | } 53 | 54 | return wechatResult; 55 | } 56 | finally 57 | { 58 | _semaphore.Release(); 59 | } 60 | } 61 | 62 | public async Task DeleteAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) 63 | { 64 | try 65 | { 66 | await _semaphore.WaitAsync().ConfigureAwait(false); 67 | var keys = new string[] { key }; 68 | await _storage.DeleteAsync(keys, cancellationToken).ConfigureAwait(false); 69 | } 70 | finally 71 | { 72 | _semaphore.Release(); 73 | } 74 | } 75 | 76 | public void Dispose() 77 | { 78 | Dispose(true); 79 | GC.SuppressFinalize(this); 80 | } 81 | 82 | protected virtual void Dispose(bool disposing) 83 | { 84 | if (disposing) 85 | { 86 | // free managed resources 87 | if (_semaphore != null) 88 | { 89 | _semaphore.Dispose(); 90 | _semaphore = null; 91 | } 92 | } 93 | } 94 | 95 | private bool IfTokenExpired(WeChatAccessToken tokenResult) 96 | { 97 | if (tokenResult == null) 98 | { 99 | return true; 100 | } 101 | 102 | // Return true when token is nearly expired. 103 | if (tokenResult.ExpireTime.ToUnixTimeSeconds() - DateTimeOffset.UtcNow.ToUnixTimeSeconds() <= 10) 104 | { 105 | return true; 106 | } 107 | 108 | return false; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Storage/IWeChatStorage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Storage 8 | { 9 | public interface IWeChatStorage 10 | { 11 | Task SaveAsync(string key, T value, CancellationToken cancellationToken = default(CancellationToken)); 12 | 13 | Task GetAsync(string key, CancellationToken cancellationToken = default(CancellationToken)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/Storage/WeChatAttachmentStorage.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults; 9 | 10 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Storage 11 | { 12 | internal class WeChatAttachmentStorage : IWeChatStorage, IDisposable 13 | { 14 | private readonly IStorage _storage; 15 | private SemaphoreSlim _semaphore; 16 | 17 | public WeChatAttachmentStorage(IStorage storage) 18 | { 19 | _storage = storage; 20 | _semaphore = new SemaphoreSlim(1); 21 | } 22 | 23 | public async Task SaveAsync(string key, UploadMediaResult value, CancellationToken cancellationToken = default(CancellationToken)) 24 | { 25 | try 26 | { 27 | await _semaphore.WaitAsync().ConfigureAwait(false); 28 | var dict = new Dictionary 29 | { 30 | { key, value }, 31 | }; 32 | await _storage.WriteAsync(dict, cancellationToken).ConfigureAwait(false); 33 | } 34 | finally 35 | { 36 | _semaphore.Release(); 37 | } 38 | } 39 | 40 | public async Task GetAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) 41 | { 42 | try 43 | { 44 | await _semaphore.WaitAsync().ConfigureAwait(false); 45 | var keys = new string[] { key }; 46 | var result = await _storage.ReadAsync(keys, cancellationToken).ConfigureAwait(false); 47 | result.TryGetValue(key, out var mediaResult); 48 | if (mediaResult == null || mediaResult.Expired()) 49 | { 50 | return null; 51 | } 52 | 53 | return mediaResult; 54 | } 55 | finally 56 | { 57 | _semaphore.Release(); 58 | } 59 | } 60 | 61 | public async Task DeleteAsync(string key, CancellationToken cancellationToken = default(CancellationToken)) 62 | { 63 | try 64 | { 65 | await _semaphore.WaitAsync().ConfigureAwait(false); 66 | var keys = new string[] { key }; 67 | await _storage.DeleteAsync(keys, cancellationToken).ConfigureAwait(false); 68 | } 69 | finally 70 | { 71 | _semaphore.Release(); 72 | } 73 | } 74 | 75 | public void Dispose() 76 | { 77 | Dispose(true); 78 | GC.SuppressFinalize(this); 79 | } 80 | 81 | protected virtual void Dispose(bool disposing) 82 | { 83 | if (disposing) 84 | { 85 | // free managed resources 86 | if (_semaphore != null) 87 | { 88 | _semaphore.Dispose(); 89 | _semaphore = null; 90 | } 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat/WeChatSettings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.Bot.Builder.Adapters.WeChat 5 | { 6 | /// 7 | /// Settings value required by WeChat. 8 | /// 9 | public class WeChatSettings 10 | { 11 | /// 12 | /// Gets or sets a value indicating whether upload media as temporary media. 13 | /// 14 | /// 15 | /// If upload all media as temporary media, will expired in 3 days. 16 | /// 17 | public bool UploadTemporaryMedia { get; set; } 18 | 19 | /// 20 | /// Gets or sets a value indicating whether response WeChat request passively. 21 | /// 22 | /// 23 | /// Response WeChat request in passive response mode. 24 | /// 25 | public bool PassiveResponseMode { get; set; } 26 | 27 | /// 28 | /// Gets or Sets token. 29 | /// 30 | /// 31 | /// Token from the request parameter. 32 | /// 33 | public string Token { get; set; } 34 | 35 | /// 36 | /// Gets or Sets endcoding aes key. 37 | /// 38 | /// 39 | /// EncodingAESKey from appsetings. 40 | /// EncodingAESKey fixed length of 43 characters, a-z, A-Z, 0-9 a total of 62 characters selected 41 | /// https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318479&token=&lang=en_US. 42 | /// 43 | public string EncodingAesKey { get; set; } 44 | 45 | /// 46 | /// Gets or Sets WeChat app id. 47 | /// 48 | /// 49 | /// WeChat app id. 50 | /// 51 | public string AppId { get; set; } 52 | 53 | /// 54 | /// Gets or Sets AppSecret. 55 | /// 56 | /// 57 | /// WeChat app secret. 58 | /// 59 | public string AppSecret { get; set; } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/build/35MSSharedLib1024.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/libraries/csharp_dotnetcore/build/35MSSharedLib1024.snk -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/csharp_dotnetcore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29326.143 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Adapters.WeChat", "Microsoft.Bot.Builder.Adapters.WeChat\Microsoft.Bot.Builder.Adapters.WeChat.csproj", "{D5D41DA1-02EB-4586-BD99-5547D8DED496}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Adapters.WeChat.Tests", "tests\Microsoft.Bot.Builder.Adapters.WeChat.Tests\Microsoft.Bot.Builder.Adapters.WeChat.Tests.csproj", "{F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {D5D41DA1-02EB-4586-BD99-5547D8DED496}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU 18 | {D5D41DA1-02EB-4586-BD99-5547D8DED496}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU 19 | {D5D41DA1-02EB-4586-BD99-5547D8DED496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {D5D41DA1-02EB-4586-BD99-5547D8DED496}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {D5D41DA1-02EB-4586-BD99-5547D8DED496}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {D5D41DA1-02EB-4586-BD99-5547D8DED496}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU 24 | {F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU 25 | {F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {F6B0326D-61C9-4A62-A8C0-B1AB0E4F166E}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {12DC1128-5FE9-413D-9C11-D2F8885F8219} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/AttachmentHashTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Text; 5 | using Xunit; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Tests 8 | { 9 | public class AttachmentHashTest 10 | { 11 | [Fact] 12 | public void Md5HashTest() 13 | { 14 | var md5Hash = new AttachmentHash(); 15 | var testString = "test string to get hash"; 16 | var stringHashed = md5Hash.ComputeHash(testString); 17 | var bytesHashed = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(testString)); 18 | Assert.Equal("E16B52D76AD74BB8D4B507515CD9ADB8", stringHashed); 19 | Assert.Equal(bytesHashed, stringHashed); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/BackgroundTaskTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.Bot.Builder.Adapters.WeChat.Extensions; 7 | using Xunit; 8 | 9 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Tests 10 | { 11 | public class BackgroundTaskTest 12 | { 13 | [Fact] 14 | public async Task BackgroundTaskQueueTest() 15 | { 16 | var queue = new BackgroundTaskQueue(); 17 | var hostService = new QueuedHostedService(queue); 18 | var result = string.Empty; 19 | queue.QueueBackgroundWorkItem(ct => 20 | { 21 | result = "executed"; 22 | return Task.CompletedTask; 23 | }); 24 | await hostService.StartAsync(default(CancellationToken)); 25 | queue.Dispose(); 26 | Assert.Equal("executed", result); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/EchoBot.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.Bot.Schema; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Tests 9 | { 10 | public class EchoBot : ActivityHandler 11 | { 12 | protected override async Task OnMessageActivityAsync(ITurnContext turnContext, CancellationToken cancellationToken) 13 | { 14 | await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/MessageCryptographyTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Xunit; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Tests 8 | { 9 | public class MessageCryptographyTest 10 | { 11 | [Fact] 12 | public void DecryptMsgTest() 13 | { 14 | var postData = MockDataUtility.XmlEncrypt; 15 | var result = MockDataUtility.TestDecryptMsg.DecryptMessage(postData); 16 | 17 | // Need to remove "/r" created by editor 18 | var decryptString = MockDataUtility.XmlDecrypt.Replace("\r", string.Empty); 19 | Assert.Equal(decryptString, result); 20 | } 21 | 22 | [Fact] 23 | public void EncodingAESKeyTest() 24 | { 25 | var result = Assert.Throws(() => new MessageCryptography(MockDataUtility.SecretInfoAesKeyError, MockDataUtility.WeChatSettingsAesKeyError)); 26 | Assert.Equal("Invalid EncodingAESKey. (Parameter 'secretInfo')", result.Message); 27 | } 28 | 29 | [Fact] 30 | public void VerifySignatureTest() 31 | { 32 | var postData = MockDataUtility.XmlEncrypt; 33 | var result = Assert.Throws(() => MockDataUtility.TestSignature.DecryptMessage(postData)); 34 | Assert.Equal("Signature verification failed.", result.Message); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/MessageMapperTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Threading.Tasks; 5 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests; 6 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema.Requests.Events; 7 | using Microsoft.Bot.Schema; 8 | using Xunit; 9 | 10 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Tests 11 | { 12 | public class MessageMapperTest 13 | { 14 | private readonly WeChatMessageMapper wechatMessageMapper; 15 | private readonly WeChatMessageMapper wechatMessageMapper2; 16 | 17 | public MessageMapperTest() 18 | { 19 | var wechatClient = MockDataUtility.GetMockWeChatClient(); 20 | this.wechatMessageMapper = new WeChatMessageMapper(wechatClient, true); 21 | this.wechatMessageMapper2 = new WeChatMessageMapper(wechatClient, false); 22 | } 23 | 24 | [Fact] 25 | public async Task ToConnectorMessageTest_TestRequest() 26 | { 27 | var mockRequestList = MockDataUtility.GetMockRequestMessageList(); 28 | foreach (var mockRequest in mockRequestList) 29 | { 30 | var activity = await wechatMessageMapper.ToConnectorMessage(mockRequest); 31 | AssertGeneralParameters(mockRequest, activity); 32 | } 33 | } 34 | 35 | [Fact] 36 | public async Task ToWeChatMessagesTest_MessageActivity() 37 | { 38 | var activityList = MockDataUtility.GetMockMessageActivityList(); 39 | foreach (var messageActivity in activityList) 40 | { 41 | var wechatResponses = await wechatMessageMapper.ToWeChatMessages(messageActivity); 42 | var wechatResponses2 = await wechatMessageMapper2.ToWeChatMessages(messageActivity); 43 | Assert.True(wechatResponses.Count > 0); 44 | Assert.True(wechatResponses2.Count > 0); 45 | } 46 | } 47 | 48 | [Fact] 49 | public async Task ToWeChatMessagesTest_MessageActivityWithAttachment() 50 | { 51 | var messageActivity = MockDataUtility.GetMockMessageActivity(); 52 | var attachments = await MockDataUtility.GetGeneralAttachmentList(true); 53 | foreach (var att in attachments) 54 | { 55 | messageActivity.Attachments.Add(att); 56 | } 57 | 58 | var wechatResponses = await wechatMessageMapper.ToWeChatMessages(messageActivity); 59 | var wechatResponses2 = await wechatMessageMapper2.ToWeChatMessages(messageActivity); 60 | Assert.True(wechatResponses2.Count > 0); 61 | Assert.True(wechatResponses.Count > 0); 62 | } 63 | 64 | [Fact] 65 | public async Task ToWeChatMessagesTest_EventActivity() 66 | { 67 | var activityList = MockDataUtility.GetMockEventActivityList(); 68 | foreach (var activity in activityList) 69 | { 70 | var wechatResponses = await wechatMessageMapper.ToWeChatMessages(activity); 71 | } 72 | } 73 | 74 | private void AssertGeneralParameters(IRequestMessageBase requestMessage, IActivity activity) 75 | { 76 | Assert.Equal(requestMessage.ToUserName, activity.Recipient.Id); 77 | Assert.Equal("Bot", activity.Recipient.Name); 78 | Assert.Equal(requestMessage.FromUserName, activity.From.Id); 79 | Assert.Equal("User", activity.From.Name); 80 | if (requestMessage is RequestMessage message) 81 | { 82 | Assert.Equal(message.MsgId.ToString(), activity.Id); 83 | } 84 | else 85 | { 86 | Assert.True(requestMessage is IRequestMessageEventBase); 87 | } 88 | 89 | Assert.Equal("wechat", activity.ChannelId); 90 | Assert.Equal(requestMessage.FromUserName, activity.Conversation.Id); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | netcoreapp3.1 6 | false 7 | 8 | 9 | 10 | true 11 | true 12 | ..\..\build\35MSSharedLib1024.snk 13 | 14 | 15 | 16 | AnyCPU 17 | 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | Always 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /libraries/csharp_dotnetcore/tests/Microsoft.Bot.Builder.Adapters.WeChat.Tests/MockWeChatClient.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema; 8 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema.JsonResults; 9 | using Microsoft.Extensions.Logging; 10 | using Newtonsoft.Json; 11 | 12 | namespace Microsoft.Bot.Builder.Adapters.WeChat.Tests 13 | { 14 | internal class MockWeChatClient : WeChatClient 15 | { 16 | public MockWeChatClient( 17 | WeChatSettings settings, 18 | IStorage storage, 19 | ILogger logger = null) 20 | : base(settings, storage, logger) 21 | { 22 | } 23 | 24 | public override Task SendHttpRequestAsync(HttpMethod method, string url, object data = null, string token = null, int timeout = 10000) 25 | { 26 | var result = JsonConvert.SerializeObject(MockDataUtility.WeChatJsonResult); 27 | var byteResult = Encoding.UTF8.GetBytes(result); 28 | 29 | if (url.Contains("cgi-bin/token")) 30 | { 31 | var tokenResult = new AccessTokenResult() 32 | { 33 | ExpireIn = 7200, 34 | Token = "testToken", 35 | }; 36 | result = JsonConvert.SerializeObject(tokenResult); 37 | byteResult = Encoding.UTF8.GetBytes(result); 38 | } 39 | else if (url.Contains("upload?access_token")) 40 | { 41 | result = JsonConvert.SerializeObject(MockDataUtility.MockTempMediaResult(MediaTypes.Image)); 42 | byteResult = Encoding.UTF8.GetBytes(result); 43 | } 44 | else if (url.Contains("add_material")) 45 | { 46 | result = JsonConvert.SerializeObject(MockDataUtility.MockForeverMediaResult("foreverMedia")); 47 | byteResult = Encoding.UTF8.GetBytes(result); 48 | } 49 | else if (url.Contains("uploadnews")) 50 | { 51 | result = JsonConvert.SerializeObject(MockDataUtility.MockTempMediaResult(MediaTypes.News)); 52 | byteResult = Encoding.UTF8.GetBytes(result); 53 | } 54 | else if (url.Contains("add_news")) 55 | { 56 | result = JsonConvert.SerializeObject(MockDataUtility.MockForeverMediaResult("foreverNews")); 57 | byteResult = Encoding.UTF8.GetBytes(result); 58 | } 59 | else if (url.Contains("uploadimg")) 60 | { 61 | result = JsonConvert.SerializeObject(MockDataUtility.MockForeverMediaResult("foreverImage")); 62 | byteResult = Encoding.UTF8.GetBytes(result); 63 | } 64 | 65 | return Task.FromResult(byteResult); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # File take from the VSCode repo at: 3 | # https://github.com/Microsoft/vscode/blob/master/.editorconfig 4 | 5 | # top-most EditorConfig file 6 | root = true 7 | 8 | # Tab indentation 9 | [*] 10 | indent_style = space 11 | indent_size = 4 12 | trim_trailing_whitespace = true 13 | 14 | # The indent size used in the `package.json` file cannot be changed 15 | # https://github.com/npm/npm/pull/3180#issuecomment-16336516 16 | [{*.yml,*.yaml,package.json}] 17 | indent_style = space 18 | indent_size = 2 -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/.eslintignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/BotFramework-WeChat/36b6863357bf120fbece708ddf4564242f476691/libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/.eslintignore -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "plugins": [ 4 | "@typescript-eslint", 5 | "only-warn" 6 | ], 7 | "extends": ["plugin:@typescript-eslint/recommended"], 8 | "parserOptions": { 9 | "ecmaVersion": 9, 10 | "sourceType": "module", 11 | "ecmaFeatures": { 12 | "impliedStrict": true 13 | } 14 | }, 15 | "rules": { 16 | "semi": ["error", "always"], 17 | "no-return-await": 0, 18 | "space-before-function-paren": ["error", { 19 | "named": "never", 20 | "anonymous": "never", 21 | "asyncArrow": "always" 22 | }], 23 | "quotes": ["error", "single", {"allowTemplateLiterals": true}], 24 | "template-curly-spacing": ["error", "always"], 25 | "@typescript-eslint/indent": ["error", 4], 26 | "@typescript-eslint/interface-name-prefix": 0, 27 | "@typescript-eslint/no-explicit-any": 0, 28 | "@typescript-eslint/no-object-literal-type-assertion": ["error", { 29 | "allowAsParameter": true 30 | }], 31 | "@typescript-eslint/no-use-before-define": ["error", { "functions": false, "classes": true }] 32 | } 33 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/.gitattributes: -------------------------------------------------------------------------------- 1 | # .gitattributes in project root 2 | package.json text eol=lf 3 | package-lock.json text eol=lf -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "extension": [ 3 | ".js" 4 | ], 5 | "include": [ 6 | "lib/**/*.js" 7 | ], 8 | "exclude": [ 9 | "**/node_modules/**", 10 | "**/tests/**", 11 | "**/coverage/**", 12 | "**/*.d.ts" 13 | ], 14 | "reporter": [ 15 | "lcov" 16 | ], 17 | "all": true, 18 | "cache": true 19 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/README.md: -------------------------------------------------------------------------------- 1 | ## WeChat Adapter for BotFramework ***_[PREVIEW]_*** 2 | 3 | This is the Node.js version of WeChat Adapter for BotFramework. 4 | 5 | - [Installing](#installing) 6 | - [Documentation](https://github.com/microsoft/BotFramework-WeChat/blob/6fd1d212e47fd9ff1b9e6865beac1c6fac242047/doc/README.md) 7 | - [GitHub Repo](https://github.com/microsoft/BotFramework-WeChat) 8 | - [Report Issues](https://github.com/microsoft/BotFramework-WeChat/issues) 9 | 10 | ### Installing 11 | As we are the preview version, please configure npm to use the MyGet feed before installing. 12 | ```bash 13 | npm config set registry https://botbuilder.myget.org/F/botframework-wechat/npm/ 14 | ``` 15 | 16 | Then add the published version of this package to your bot: 17 | ```bash 18 | npm install --save botframework-wechat 19 | ``` 20 | 21 | To reset the registry, run: 22 | ```bash 23 | npm config set registry https://registry.npmjs.org/ 24 | ``` -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "botframework-wechat", 3 | "author": "Microsoft Corp.", 4 | "license": "MIT", 5 | "version": "4.0.0", 6 | "description": "botframework wechat adapter", 7 | "keywords": [ 8 | "botframework", 9 | "bots", 10 | "wechat" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/microsoft/BotFramework-WeChat.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/microsoft/BotFramework-WeChat/issues" 18 | }, 19 | "main": "./lib/index.js", 20 | "typings": "./lib/index.d.ts", 21 | "dependencies": { 22 | "@azure/ms-rest-js": "1.2.6", 23 | "adaptivecards": "1.1.0", 24 | "botbuilder-core": "^4.7.0", 25 | "form-data": "^3.0.0", 26 | "node-fetch": "2.6.0", 27 | "xml2js": "^0.4.23" 28 | }, 29 | "devDependencies": { 30 | "@types/node": "^10.12.18", 31 | "@types/mocha": "^2.2.47", 32 | "@types/form-data": "2.5.0", 33 | "@types/node-fetch": "1.6.9", 34 | "dotenv": "^5.0.1", 35 | "mocha": "^5.2.0", 36 | "nyc": "^11.4.1", 37 | "ts-node": "^4.1.0", 38 | "@typescript-eslint/eslint-plugin": "^1.10.2", 39 | "@typescript-eslint/parser": "^1.10.2", 40 | "eslint-plugin-only-warn": "^1.0.1", 41 | "eslint": "^5.16.0", 42 | "coveralls": "^3.0.4", 43 | "typescript": "^3.7.3" 44 | }, 45 | "scripts": { 46 | "test": "tsc && nyc mocha tests/", 47 | "clean": "erase /q /s .\\lib", 48 | "build": "tsc" 49 | }, 50 | "files": [ 51 | "/lib", 52 | "/src" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/accessTokenStorage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | import { Storage, StoreItems } from 'botbuilder-core'; 10 | import { WeChatAccessToken } from './weChatSchema'; 11 | 12 | /** 13 | * Storage provider for access token. 14 | * @private 15 | */ 16 | export class AccessTokenStorage { 17 | private storage: Storage; 18 | 19 | /** 20 | * Creates an instance of access token storage. 21 | * @param storage 22 | */ 23 | constructor(storage: Storage) { 24 | this.storage = storage; 25 | } 26 | 27 | /** 28 | * Saves store items to storage. 29 | * @param key Item key to write to the storage. 30 | * @param value Item value to write to the storage. 31 | */ 32 | public async saveAsync(key: string, value: WeChatAccessToken): Promise { 33 | const dict: StoreItems = { 34 | [key]: value 35 | }; 36 | await this.storage.write(dict); 37 | } 38 | 39 | /** 40 | * Loads store items from storage. 41 | * @param key Item key to read from the store. 42 | */ 43 | public async getAsync(key: string): Promise { 44 | const result: StoreItems = await this.storage.read([key]); 45 | return result[key] as WeChatAccessToken; 46 | } 47 | 48 | /** 49 | * Removes store items from storage. 50 | * @param key Item key to remove from the store. 51 | */ 52 | public async deleteAsync(key: string): Promise { 53 | await this.storage.delete([key]); 54 | } 55 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/attachmentHash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | import * as crypto from 'crypto'; 10 | import * as util from 'util'; 11 | 12 | /** 13 | * Attachment hash 14 | * @private 15 | */ 16 | export class AttachmentHash { 17 | 18 | /** 19 | * Calculates the hash value, used to ignore same file when upload media. 20 | * @param bytes Bytes content need to be hashed. 21 | * @returns Hash value. 22 | */ 23 | computeBytesHash(bytes: Uint8Array): string { 24 | const result = crypto.createHash('md5').update(bytes).digest('hex'); 25 | return result; 26 | } 27 | 28 | /** 29 | * Calculates the hash value, used to ignore same file when upload media. 30 | * @param content String content need to be hashed. 31 | * @returns Hash value. 32 | */ 33 | computeStringHash(content: string): string { 34 | const encoder = new util.TextEncoder(); 35 | const bytes = encoder.encode(content); 36 | return this.computeBytesHash(bytes); 37 | } 38 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/attachmentHelper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | import * as util from 'util'; 10 | 11 | /** 12 | * Helper methods for storing attachments in the channel. 13 | * @private 14 | */ 15 | export class AttachmentHelper { 16 | /** 17 | * Determines if the content param can be turned into an Uri with http or https scheme. 18 | * @param content Content object to check if it is an URL. 19 | * @returns Ture or False. 20 | */ 21 | public static isUrl(content: any): boolean { 22 | if (typeof content === 'string') { 23 | if (content.startsWith('data:')){ 24 | return false; 25 | } 26 | try { 27 | new URL(content); 28 | return true; 29 | } catch (_) { 30 | return false; 31 | } 32 | } 33 | return false; 34 | } 35 | 36 | public static decodeBase64String(base64Encoded: string): any { 37 | let contentType: string; 38 | if (base64Encoded.startsWith('data:')) { 39 | const start = base64Encoded.indexOf('data:') + 5; 40 | const end = base64Encoded.indexOf(';', start); 41 | if (end > start) { 42 | contentType = base64Encoded.substring(start, end).trim(); 43 | } 44 | } 45 | 46 | const headerIndex = base64Encoded.indexOf('base64,'); 47 | if (headerIndex >= 0) { 48 | base64Encoded = base64Encoded.substring(headerIndex + 7).trim(); 49 | } 50 | 51 | const base64 = new util.TextEncoder().encode(base64Encoded); 52 | 53 | return {base64, contentType}; 54 | } 55 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | export * from './weChatAdapter'; 10 | export * from './weChatClient'; 11 | export * from './weChatSchema'; 12 | export * from './weChatMessageMapper'; 13 | export * from './verificationHelper'; 14 | -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/messageCryptography.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | import { SecretInfo } from './weChatSchema'; 10 | import { VerificationHelper } from './verificationHelper'; 11 | import * as crypto from 'crypto'; 12 | 13 | /** 14 | * A cryptography class to decrypt the message content from WeChat. 15 | * @private 16 | */ 17 | export class MessageCryptography { 18 | 19 | /** 20 | * Verify the authenticity of the message and get the decrypted plaintext. 21 | * @param requestData Cipher message. 22 | * @param secretInfo The secret info provide by WeChat. 23 | * @returns message 24 | */ 25 | public static decryptMessage(requestData: any, secretInfo: SecretInfo): string { 26 | if (secretInfo.EncodingAesKey.length !== 43) { 27 | throw new Error('Invalid EncodingAESKey.'); 28 | } 29 | if (!VerificationHelper.verifySignature(secretInfo.Msg_signature, secretInfo.Timestamp, secretInfo.Nonce, secretInfo.Token, requestData.Encrypt)) { 30 | throw new Error('Signature verification failed.'); 31 | } 32 | const message = aesDecrypt(requestData.Encrypt, secretInfo.EncodingAesKey, secretInfo.AppId); 33 | return message; 34 | } 35 | } 36 | 37 | /** 38 | * Decrypt the message. 39 | * @private 40 | * @param encryptString Encrypted string. 41 | * @param encodingAesKey Encoding AES key for decrypt message. 42 | * @param appId The WeChat app id. 43 | * @returns Decrypted string. 44 | */ 45 | function aesDecrypt(encryptString: string, encodingAesKey: string, appId: string): string { 46 | const aesKey = Buffer.from(encodingAesKey + '=', 'base64'); 47 | const iv = aesKey.slice(0, 16); 48 | const decipher = crypto.createDecipheriv('aes-256-cbc', aesKey, iv); 49 | decipher.setAutoPadding(false); 50 | let decipherBuff = Buffer.concat([decipher.update(encryptString, 'base64'), decipher.final()]); 51 | decipherBuff = pkcs7Decoder(decipherBuff); 52 | const len = decipherBuff.slice(16); 53 | const msgLen = len.slice(0, 4).readUInt32BE(0); 54 | const result = len.slice(4, msgLen + 4).toString(); 55 | const appid = len.slice(msgLen + 4).toString(); 56 | if (appId !== appid) { 57 | throw new Error('AppId is invalid.'); 58 | } 59 | return result; 60 | } 61 | 62 | /** 63 | * @private 64 | */ 65 | function pkcs7Decoder(buff: any) { 66 | let pad = buff[buff.length - 1]; 67 | if (pad < 1 || pad > 32) { 68 | pad = 0; 69 | } 70 | return buff.slice(0, buff.length - pad); 71 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/verificationHelper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | import * as crypto from 'crypto'; 10 | 11 | export class VerificationHelper { 12 | 13 | /** 14 | * Verify WeChat request message signature. 15 | * @param signature WeChat message signature in query params. 16 | * @param timestamp WeChat message timestamp in query params. 17 | * @param nonce WeChat message nonce in query params. 18 | * @param [token] Validation token from WeChat. 19 | * @param [postBody] Request body as string. 20 | * @returns Signature verification result. 21 | */ 22 | public static verifySignature(signature: string, timestamp: string, nonce: string, token: string = undefined, postBody: string = undefined): boolean { 23 | if (!signature) { 24 | throw new Error('ArgumentError - Request validation failed - invalid Signature.'); 25 | } 26 | if (!timestamp) { 27 | throw new Error('ArgumentError - Request validation failed - invalid Timestamp.'); 28 | } 29 | if (!nonce) { 30 | throw new Error('ArgumentError - Request validation failed - invalid Nonce.'); 31 | } 32 | return signature === generateSignature(token, timestamp, nonce, postBody); 33 | } 34 | } 35 | 36 | /** 37 | * Generate signature use the encrypted message. 38 | * @private 39 | * @param token Token in provided by WeChat. 40 | * @param timestamp WeChat message timestamp in query params. 41 | * @param nonce WeChat message nonce in query params. 42 | * @param [encryptedMessage] The encrypted message content from WeChat request. 43 | * @returns Generated signature. 44 | */ 45 | function generateSignature(token: string, timestamp: string, nonce: string, encryptedMessage: string = undefined): string { 46 | const sortlist = [token, timestamp, nonce, encryptedMessage]; 47 | sortlist.sort(); 48 | const raw = sortlist.join(''); 49 | const hash = crypto.createHash('sha1').update(raw).digest('hex'); 50 | return hash; 51 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/src/weChatAttachmentStorage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @module botframework-wechat 3 | */ 4 | /** 5 | * Copyright (c) Microsoft Corporation. All rights reserved. 6 | * Licensed under the MIT License. 7 | */ 8 | 9 | import { Storage, StoreItems } from 'botbuilder-core'; 10 | import { UploadMediaResult } from './weChatSchema'; 11 | 12 | /** 13 | * We chat attachment storage 14 | * @private 15 | */ 16 | export class WeChatAttachmentStorage { 17 | private storage: Storage; 18 | 19 | /** 20 | * Creates an instance of we chat attachment storage. 21 | * @param storage 22 | */ 23 | constructor(storage: Storage) { 24 | this.storage = storage; 25 | } 26 | 27 | /** 28 | * Saves store items to storage. 29 | * @param key Item key to write to the storage. 30 | * @param value Item value to write to the storage. 31 | */ 32 | async saveAsync(key: string, value: UploadMediaResult): Promise { 33 | const dict: StoreItems = { 34 | [key]: value, 35 | }; 36 | await this.storage.write(dict); 37 | } 38 | 39 | /** 40 | * Loads store items from storage. 41 | * @param key Item key to read from the store. 42 | */ 43 | async getAsync(key: string): Promise { 44 | const keys: string[] = [key]; 45 | const result: StoreItems = await this.storage.read(keys); 46 | const weChatResult: UploadMediaResult = result[key]; 47 | return weChatResult; 48 | } 49 | 50 | /** 51 | * Removes store items from storage. 52 | * @param key Item key to remove from the store. 53 | */ 54 | async deleteAsync(key: string): Promise { 55 | await this.storage.delete([key]); 56 | } 57 | } -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tests/accessTokenStorage.test.js: -------------------------------------------------------------------------------- 1 | const { AccessTokenStorage } = require('../lib/accessTokenStorage'); 2 | const { MemoryStorage } = require('botbuilder-core'); 3 | const assert = require('assert'); 4 | const accessTokenStorage = new AccessTokenStorage(new MemoryStorage()); 5 | const key = 'accesstokenkey'; 6 | const date = new Date('1995-12-17T03:24:00'); 7 | const result = { 8 | AppId: 'appid', 9 | Secret: 'secret', 10 | Token: 'token', 11 | ExpireTime: date.valueOf() 12 | }; 13 | 14 | describe('My access token storage', async () => { 15 | assert(accessTokenStorage.saveAsync(key, result), 'Save failed.'); 16 | it('shoule be reload the corret stored value', async () => { 17 | const weChatAccessToken = await accessTokenStorage.getAsync(key); 18 | assert.equal(weChatAccessToken.AppId, result.AppId); 19 | assert.equal(weChatAccessToken.Secret, result.Secret); 20 | assert.equal(weChatAccessToken.Token, result.Token); 21 | assert.equal(weChatAccessToken.ExpireTime, result.ExpireTime); 22 | }); 23 | }); -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tests/attachmentHash.test.js: -------------------------------------------------------------------------------- 1 | const { AttachmentHash } = require('../lib/attachmentHash'); 2 | const { TextEncoder } = require('util'); 3 | const assert = require('assert'); 4 | const testString = 'test string to get hash'; 5 | const bytes = new TextEncoder().encode(testString); 6 | const attachmentHash = new AttachmentHash(); 7 | 8 | describe('My hash library', () => { 9 | it('should be able to computer hash correctly', () => { 10 | assert.equal(attachmentHash.computeStringHash(testString), 'e16b52d76ad74bb8d4b507515cd9adb8'); 11 | }); 12 | it('shoule be same result', () => { 13 | assert.equal(attachmentHash.computeBytesHash(bytes), attachmentHash.computeStringHash(testString)); 14 | }); 15 | }); -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tests/bot.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | const { ActivityHandler } = require('botbuilder-core'); 5 | 6 | class EchoBot extends ActivityHandler { 7 | constructor() { 8 | super(); 9 | // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. 10 | this.onMessage(async (context, next) => { 11 | await context.sendActivity(`You said '${ context.activity.text }'`); 12 | 13 | // By calling next() you ensure that the next BotHandler is run. 14 | await next(); 15 | }); 16 | 17 | this.onMembersAdded(async (context, next) => { 18 | const membersAdded = context.activity.membersAdded; 19 | for (let cnt = 0; cnt < membersAdded.length; ++cnt) { 20 | if (membersAdded[cnt].id !== context.activity.recipient.id) { 21 | await context.sendActivity('Hello and welcome!'); 22 | } 23 | } 24 | // By calling next() you ensure that the next BotHandler is run. 25 | await next(); 26 | }); 27 | } 28 | } 29 | 30 | module.exports.EchoBot = EchoBot; -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tests/messageCryptography.test.js: -------------------------------------------------------------------------------- 1 | const { MessageCryptography } = require('../lib/messageCryptography'); 2 | const assert = require('assert'); 3 | const secretInfo = { 4 | Token: 'bmwipabotwx', 5 | EncodingAesKey: 'P7PIjIGpA7axbjbffRoWYq7G0BsIaEpqdawIir4KqCt', 6 | AppId: 'wx77f941c869071d99', 7 | Signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7d', 8 | Timestamp: '1562066088', 9 | Nonce: '236161902', 10 | Msg_signature: 'f3187a0efd9709c8f6550190147f43c279e9bc43', 11 | }; 12 | const secretInfoAESKeyError = { 13 | Token: 'bmwipabotwx', 14 | EncodingAesKey: 'bmwipabotwx', 15 | AppId: 'wx77f941c869071d99', 16 | Signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7', 17 | Timestamp: '1562066088', 18 | Nonce: '236161902', 19 | Msg_signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7', 20 | }; 21 | const secretInfoMsgSignatureError = { 22 | Token: 'bmwipabotwx', 23 | EncodingAesKey: 'P7PIjIGpA7axbjbffRoWYq7G0BsIaEpqdawIir4KqCt', 24 | AppId: 'wx77f941c869071d99', 25 | Signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7d', 26 | Timestamp: '1562066088', 27 | Nonce: '236161902', 28 | Msg_signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7d', 29 | }; 30 | const secretInfoAppIdError = { 31 | Token: 'bmwipabotwx', 32 | EncodingAesKey: 'P7PIjIGpA7axbjbffRoWYq7G0BsIaEpqdawIir4KqCt', 33 | AppId: 'wx77f941c8', 34 | Signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7d', 35 | Timestamp: '1562066088', 36 | Nonce: '236161902', 37 | Msg_signature: 'f3187a0efd9709c8f6550190147f43c279e9bc43', 38 | }; 39 | const requestRaw = { 40 | Encrypt: '8VfmSJqZFzMlnaDohVD7I0T+9LIG1fT8kl221jOyL9TwkTJ38AZ9A6kMxvADvvxfg+azCEOEXtdVElhLs/roYyf25YfGH4kZp0O2t6XngOzwClG9HAhUV29OomouAqVpZ1ySqV60THKQ8E25N+fYF8RnXboae0r/ZTGnUJPuPwPVtbBj1dIGuFjpls+mnaSyg6Ag04FF5GcqO7exfEugQtNS44yQbmel/EKmxtvzz9CClJ3QnsHUODCMj5e6lYNSM7b84s+OBtKKsD0ObRnrAN5IfFLbDqK6twKlwTqHM0O1icSmfFo2MHT2+iizTcJfpbFnQeIj1zlSQdexvQ8fH9JwoSaHjQad/CyQ4D/PSxYi2Thu2ZFt5C2/NJ0ixL++GlOZpdaL/SQvxsVPrqsNhp7tteT69EVbpZux7c+eib4=' 41 | }; 42 | const xmlDecryptString = '156206608822363405356629000'; 43 | 44 | describe('My Message Cryptography', () => { 45 | it('should be able to decrypt the message correctly', () => { 46 | assert.equal(MessageCryptography.decryptMessage(requestRaw, secretInfo).replace(/(\r\n|\n|\r)/gm,''), xmlDecryptString); 47 | }); 48 | it('should throw error if the encodingAesKey is invalid', () => { 49 | assert.throws( 50 | () => { 51 | MessageCryptography.decryptMessage(requestRaw, secretInfoAESKeyError); 52 | }, 53 | /^Error: Invalid EncodingAESKey.$/ 54 | ); 55 | }); 56 | it('should throw error if signature information is invalid', () => { 57 | assert.throws( 58 | () => { 59 | MessageCryptography.decryptMessage(requestRaw, secretInfoMsgSignatureError); 60 | }, 61 | /^Error: Signature verification failed.$/ 62 | ); 63 | }); 64 | it('should throw error if the AppId is invalid', () => { 65 | assert.throws( 66 | () => { 67 | MessageCryptography.decryptMessage(requestRaw, secretInfoAppIdError); 68 | }, 69 | /^Error: AppId is invalid.$/ 70 | ); 71 | }); 72 | }); -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tests/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ts-node/register 2 | --require source-map-support/register 3 | --recursive 4 | **/*.js -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tests/verificationHelper.test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const { VerificationHelper } = require('../lib/verificationHelper'); 3 | const secretInfo = { 4 | Token: 'bmwipabotwx', 5 | EncodingAesKey: 'P7PIjIGpA7axbjbffRoWYq7G0BsIaEpqdawIir4KqCt', 6 | AppId: 'wx77f941c869071d99', 7 | Signature: '4e17212123b3ce5a6b11643dc658af83fdb54c7d', 8 | Timestamp: '1562066088', 9 | Nonce: '236161902', 10 | Msg_signature: 'f3187a0efd9709c8f6550190147f43c279e9bc43', 11 | }; 12 | 13 | describe('Verify secret information', () => { 14 | it('should throw error if the Signature is invalid', () => { 15 | assert.throws( 16 | () => { 17 | VerificationHelper.verifySignature(undefined, secretInfo.Timestamp, secretInfo.Nonce); 18 | }, 19 | /^Error: ArgumentError - Request validation failed - invalid Signature.$/ 20 | ); 21 | }); 22 | it('should throw error if the Timestamp is invalid', () => { 23 | assert.throws( 24 | () => { 25 | VerificationHelper.verifySignature(secretInfo.Signature, undefined, secretInfo.Nonce); 26 | }, 27 | /^Error: ArgumentError - Request validation failed - invalid Timestamp.$/ 28 | ); 29 | }); 30 | it('should throw error if the Nonce is invalid', () => { 31 | assert.throws( 32 | () => { 33 | VerificationHelper.verifySignature(secretInfo.Signature, secretInfo.Timestamp, undefined); 34 | }, 35 | /^Error: ArgumentError - Request validation failed - invalid Nonce.$/ 36 | ); 37 | }); 38 | }); -------------------------------------------------------------------------------- /libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "commonjs", 5 | "strict": false, 6 | "declaration": true, 7 | "sourceMap": true, 8 | "outDir": "./lib", 9 | "rootDir": "./src", 10 | "types" : ["node"] 11 | }, 12 | "include": [ 13 | "src/**/*" 14 | ] 15 | } -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Bots/RichCardsBot.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.Bot.Schema; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace Microsoft.Bot.Builder.Adapters.WeChat.TestBot 11 | { 12 | // RichCardsBot prompts a user to select a Rich Card and then returns the card 13 | // that matches the user's selection. 14 | public class RichCardsBot : DialogBot 15 | { 16 | public RichCardsBot(ConversationState conversationState, UserState userState, MainDialog dialog, ILogger> logger) 17 | : base(conversationState, userState, dialog, logger) 18 | { 19 | } 20 | 21 | protected override async Task OnMembersAddedAsync(IList membersAdded, ITurnContext turnContext, CancellationToken cancellationToken) 22 | { 23 | foreach (var member in membersAdded) 24 | { 25 | // Greet anyone that was not the target (recipient) of this message. 26 | // To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details. 27 | if (member.Id != turnContext.Activity.Recipient.Id) 28 | { 29 | var reply = MessageFactory.Text("Welcome to CardBot." 30 | + " This bot will show you different types of Rich Cards." 31 | + " Please type anything to get started."); 32 | 33 | await turnContext.SendActivityAsync(reply, cancellationToken); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Controllers/BotController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Bot.Builder.Adapters.WeChat.Schema; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.TestBot 9 | { 10 | // This ASP Controller is created to handle a request. Dependency Injection will provide the Adapter and IBot 11 | // implementation at runtime. Multiple different IBot implementations running at different endpoints can be 12 | // achieved by specifying a more specific type for the bot constructor argument. 13 | [Route("api/messages")] 14 | [ApiController] 15 | public class BotController : ControllerBase 16 | { 17 | private readonly IBot _bot; 18 | private readonly WeChatAdapterWithErrorHandler _wechatAdapter; 19 | 20 | public BotController(IBot bot, WeChatAdapterWithErrorHandler wechatAdapter) 21 | { 22 | _bot = bot; 23 | _wechatAdapter = wechatAdapter; 24 | } 25 | 26 | [HttpGet("/WeChat")] 27 | [HttpPost("/WeChat")] 28 | public async Task PostWeChatAsync([FromQuery] SecretInfo postModel) 29 | { 30 | // Delegate the processing of the HTTP POST to the adapter. 31 | // The adapter will invoke the bot. 32 | await _wechatAdapter.ProcessAsync(Request, Response, _bot, postModel); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/DialogExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.Bot.Builder.Dialogs; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.TestBot 9 | { 10 | public static class DialogExtensions 11 | { 12 | public static async Task Run(this Dialog dialog, ITurnContext turnContext, IStatePropertyAccessor accessor, CancellationToken cancellationToken = default(CancellationToken)) 13 | { 14 | var dialogSet = new DialogSet(accessor); 15 | dialogSet.Add(dialog); 16 | 17 | var dialogContext = await dialogSet.CreateContextAsync(turnContext, cancellationToken); 18 | var results = await dialogContext.ContinueDialogAsync(cancellationToken); 19 | if (results.Status == DialogTurnStatus.Empty) 20 | { 21 | await dialogContext.BeginDialogAsync(dialog.Id, null, cancellationToken); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Microsoft.Bot.Builder.Adapters.WeChat.TestBot.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | InProcess 6 | 7 | 8 | 9 | true 10 | true 11 | ..\..\build\35MSSharedLib1024.snk 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Always 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Microsoft.Bot.Builder.Adapters.WeChat.TestBot.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29709.97 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Builder.Adapters.WeChat.TestBot", "Microsoft.Bot.Builder.Adapters.WeChat.TestBot.csproj", "{0FE2726A-72B4-4109-A719-FC422A2E58DC}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {0FE2726A-72B4-4109-A719-FC422A2E58DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {0FE2726A-72B4-4109-A719-FC422A2E58DC}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {0FE2726A-72B4-4109-A719-FC422A2E58DC}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {0FE2726A-72B4-4109-A719-FC422A2E58DC}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {7B4EC8F5-3A70-442C-B431-4793A597A1B5} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.AspNetCore; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Microsoft.Bot.Builder.Adapters.WeChat.TestBot 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | CreateWebHostBuilder(args).Build().Run(); 15 | } 16 | 17 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 18 | WebHost.CreateDefaultBuilder(args) 19 | .ConfigureLogging((logging) => 20 | { 21 | logging.AddDebug(); 22 | logging.AddConsole(); 23 | }) 24 | .UseStartup(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/README.md: -------------------------------------------------------------------------------- 1 | # Microsoft.Bot.Builder.Adapters.WeChat.TestBot 2 | 3 | Bot Framework v4 echo bot sample. 4 | 5 | This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back. 6 | 7 | ## Prerequisites 8 | 9 | - [.NET Core SDK](https://dotnet.microsoft.com/download) version 2.1 10 | 11 | ```bash 12 | # determine dotnet version 13 | dotnet --version 14 | ``` 15 | 16 | ## To try this sample 17 | 18 | - In a terminal, navigate to `Microsoft.Bot.Builder.Adapters.WeChat.TestBot` 19 | 20 | ```bash 21 | # change into project folder 22 | cd # Microsoft.Bot.Builder.Adapters.WeChat.TestBot 23 | ``` 24 | 25 | - Run the bot from a terminal or from Visual Studio, choose option A or B. 26 | 27 | A) From a terminal 28 | 29 | ```bash 30 | # run the bot 31 | dotnet run 32 | ``` 33 | 34 | B) Or from Visual Studio 35 | 36 | - Launch Visual Studio 37 | - File -> Open -> Project/Solution 38 | - Navigate to `Microsoft.Bot.Builder.Adapters.WeChat.TestBot` folder 39 | - Select `Microsoft.Bot.Builder.Adapters.WeChat.TestBot.csproj` file 40 | - Press `F5` to run the project 41 | 42 | ## Testing the bot using Bot Framework Emulator 43 | 44 | [Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel. 45 | 46 | - Install the Bot Framework Emulator version 4.5.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases) 47 | 48 | ### Connect to the bot using Bot Framework Emulator 49 | 50 | - Launch Bot Framework Emulator 51 | - File -> Open Bot 52 | - Enter a Bot URL of `http://localhost:3978/api/messages` 53 | 54 | ## Deploy the bot to Azure 55 | 56 | To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](https://aka.ms/azuredeployment) for a complete list of deployment instructions. 57 | 58 | ## Further reading 59 | 60 | - [Bot Framework Documentation](https://docs.botframework.com) 61 | - [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0) 62 | - [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0) 63 | - [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0) 64 | - [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0) 65 | - [.NET Core CLI tools](https://docs.microsoft.com/en-us/dotnet/core/tools/?tabs=netcore2x) 66 | - [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest) 67 | - [Azure Portal](https://portal.azure.com) 68 | - [Language Understanding using LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/) 69 | - [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0) 70 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Resources/MessageMenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "head_content": "Are you satisfied with this service?", 3 | "list": [{ 4 | "id": 101, 5 | "content": "Satisfied" 6 | }, 7 | { 8 | "id": 102, 9 | "content": "NotSatisfied" 10 | } 11 | ], 12 | "tail_content": "You are welcome to come back again." 13 | } -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/Startup.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.Bot.Builder.Adapters.WeChat.Extensions; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Microsoft.Extensions.Hosting; 11 | using IHostingEnvironment = Microsoft.AspNetCore.Hosting.IHostingEnvironment; 12 | 13 | namespace Microsoft.Bot.Builder.Adapters.WeChat.TestBot 14 | { 15 | public class Startup 16 | { 17 | public Startup(IConfiguration configuration) 18 | { 19 | Configuration = configuration; 20 | } 21 | 22 | public IConfiguration Configuration { get; } 23 | 24 | // This method gets called by the runtime. Use this method to add services to the container. 25 | public void ConfigureServices(IServiceCollection services) 26 | { 27 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 28 | 29 | // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.) 30 | services.AddSingleton(); 31 | 32 | // Create the User state. (Used in this bot's Dialog implementation.) 33 | services.AddSingleton(); 34 | 35 | // Create the Conversation state. (Used by the Dialog system itself.) 36 | services.AddSingleton(); 37 | 38 | // Load WeChat settings. 39 | var wechatSettings = new WeChatSettings(); 40 | Configuration.Bind("WeChatSettings", wechatSettings); 41 | services.AddSingleton(wechatSettings); 42 | 43 | // Configure hosted serivce. 44 | services.AddSingleton(); 45 | services.AddHostedService(); 46 | services.AddSingleton(); 47 | 48 | // The Dialog that will be run by the bot. 49 | services.AddSingleton(); 50 | 51 | // Create the bot as a transient. In this case the ASP Controller is expecting an IBot. 52 | services.AddTransient(); 53 | } 54 | 55 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 56 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 57 | { 58 | if (env.IsDevelopment()) 59 | { 60 | app.UseDeveloperExceptionPage(); 61 | } 62 | else 63 | { 64 | app.UseHsts(); 65 | } 66 | 67 | app.UseDefaultFiles(); 68 | app.UseStaticFiles(); 69 | app.UseMvc(); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/WeChatAdapterWithErrorHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace Microsoft.Bot.Builder.Adapters.WeChat.TestBot 8 | { 9 | public class WeChatAdapterWithErrorHandler : WeChatHttpAdapter 10 | { 11 | public WeChatAdapterWithErrorHandler(WeChatSettings settings, IStorage storage, IBackgroundTaskQueue taskQueue, ILogger logger = null, ConversationState conversationState = null, UserState userState = null) 12 | : base(settings, storage, taskQueue, logger) 13 | { 14 | OnTurnError = async (turnContext, exception) => 15 | { 16 | // Log any leaked exception from the application. 17 | logger.LogError($"Exception caught : {exception.Message}"); 18 | 19 | // Send a catch-all apology to the user. 20 | await turnContext.SendActivityAsync("Sorry, it looks like something went wrong."); 21 | 22 | if (conversationState != null) 23 | { 24 | try 25 | { 26 | // Delete the conversationState for the current conversation to prevent the 27 | // bot from getting stuck in a error-loop caused by being in a bad state. 28 | // ConversationState should be thought of as similar to "cookie-state" in a Web pages. 29 | await conversationState.DeleteAsync(turnContext); 30 | } 31 | catch (Exception e) 32 | { 33 | logger.LogError($"Exception caught on attempting to Delete ConversationState : {e.Message}"); 34 | } 35 | } 36 | }; 37 | 38 | this.Use(new AutoSaveStateMiddleware(conversationState, userState)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/csharp_dotnetcore/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "MicrosoftAppId": "", 3 | "MicrosoftAppPassword": "", 4 | "WeChatSettings": { 5 | "UploadTemporaryMedia": true, 6 | "PassiveResponseMode": false, 7 | "Token": "", 8 | "EncodingAESKey": "", 9 | "AppId": "", 10 | "AppSecret": "" 11 | }, 12 | "AllowedHosts": "*" 13 | } 14 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/.env: -------------------------------------------------------------------------------- 1 | AppId= 2 | AppSecret= 3 | Token= 4 | EncodingAESKey= 5 | UploadTemporaryMedia=true 6 | passiveResponse=false 7 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | lib 3 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/README.md: -------------------------------------------------------------------------------- 1 | # wechat-testbot 2 | 3 | test 4 | 5 | This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to create a simple bot that accepts input from the user and echoes it back. 6 | 7 | ## Prerequisites 8 | 9 | - [Node.js](https://nodejs.org) version 10.14.1 or higher 10 | 11 | ```bash 12 | # determine node version 13 | node --version 14 | ``` 15 | 16 | ## To run the bot 17 | 18 | - Install modules 19 | 20 | ```bash 21 | npm install 22 | ``` 23 | - Start the bot 24 | 25 | ```bash 26 | npm start 27 | ``` 28 | 29 | ## Testing the bot using Bot Framework Emulator 30 | 31 | [Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel. 32 | 33 | - Install the Bot Framework Emulator version 4.3.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases) 34 | 35 | ### Connect to the bot using Bot Framework Emulator 36 | 37 | - Launch Bot Framework Emulator 38 | - File -> Open Bot 39 | - Enter a Bot URL of `http://localhost:3978/api/messages` 40 | 41 | ## Deploy the bot to Azure 42 | 43 | ### Publishing Changes to Azure Bot Service 44 | 45 | ```bash 46 | # build the TypeScript bot before you publish 47 | npm run build 48 | ``` 49 | 50 | To learn more about deploying a bot to Azure, see [Deploy your bot to Azure](https://aka.ms/azuredeployment) for a complete list of deployment instructions. 51 | 52 | ## Further reading 53 | 54 | - [Bot Framework Documentation](https://docs.botframework.com) 55 | - [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0) 56 | - [Dialogs](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0) 57 | - [Gathering Input Using Prompts](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-prompts?view=azure-bot-service-4.0) 58 | - [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0) 59 | - [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0) 60 | - [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0) 61 | - [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest) 62 | - [Azure Portal](https://portal.azure.com) 63 | - [Language Understanding using LUIS](https://docs.microsoft.com/en-us/azure/cognitive-services/luis/) 64 | - [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0) 65 | - [TypeScript](https://www.typescriptlang.org) 66 | - [Restify](https://www.npmjs.com/package/restify) 67 | - [dotenv](https://www.npmjs.com/package/dotenv) 68 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/deploymentScripts/webConfigPrep.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | // DO NOT MODIFY THIS CODE 5 | // This script is run as part of the Post Deploy step when 6 | // deploying the bot to Azure. It ensures the Azure Web App 7 | // is configured correctly to host a TypeScript authored bot. 8 | const fs = require('fs'); 9 | const path = require('path'); 10 | const replace = require('replace'); 11 | const WEB_CONFIG_FILE = './web.config'; 12 | 13 | if (fs.existsSync(path.resolve(WEB_CONFIG_FILE))) { 14 | replace({ 15 | regex: "url=\"index.js\"", 16 | replacement: "url=\"lib/index.js\"", 17 | paths: ['./web.config'], 18 | recursive: false, 19 | silent: true, 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/deploymentTemplates/new-rg-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "groupLocation": { 6 | "value": "" 7 | }, 8 | "groupName": { 9 | "value": "" 10 | }, 11 | "appId": { 12 | "value": "" 13 | }, 14 | "appSecret": { 15 | "value": "" 16 | }, 17 | "botId": { 18 | "value": "" 19 | }, 20 | "botSku": { 21 | "value": "" 22 | }, 23 | "newAppServicePlanName": { 24 | "value": "" 25 | }, 26 | "newAppServicePlanSku": { 27 | "value": { 28 | "name": "S1", 29 | "tier": "Standard", 30 | "size": "S1", 31 | "family": "S", 32 | "capacity": 1 33 | } 34 | }, 35 | "newAppServicePlanLocation": { 36 | "value": "" 37 | }, 38 | "newWebAppName": { 39 | "value": "" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/deploymentTemplates/preexisting-rg-parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "appId": { 6 | "value": "" 7 | }, 8 | "appSecret": { 9 | "value": "" 10 | }, 11 | "botId": { 12 | "value": "" 13 | }, 14 | "botSku": { 15 | "value": "" 16 | }, 17 | "newAppServicePlanName": { 18 | "value": "" 19 | }, 20 | "newAppServicePlanSku": { 21 | "value": { 22 | "name": "S1", 23 | "tier": "Standard", 24 | "size": "S1", 25 | "family": "S", 26 | "capacity": 1 27 | } 28 | }, 29 | "appServicePlanLocation": { 30 | "value": "" 31 | }, 32 | "existingAppServicePlan": { 33 | "value": "" 34 | }, 35 | "newWebAppName": { 36 | "value": "" 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "botframework-wechat-testbot", 3 | "version": "4.1.6", 4 | "description": "test", 5 | "author": "Generated using Microsoft Bot Builder Yeoman generator v4.5.0", 6 | "license": "MIT", 7 | "main": "./lib/index.js", 8 | "typings": "./lib/index.d.ts", 9 | "scripts": { 10 | "build": "tsc", 11 | "lint": "tslint -c tslint.json 'src/**/*.ts'", 12 | "start": "tsc --build && node ./lib/index.js", 13 | "clean": "erase /q /s .\\lib", 14 | "test": "echo \"Error: no test specified\" && exit 1", 15 | "watch": "nodemon --watch ./src -e ts --exec \"npm run start\"" 16 | }, 17 | "dependencies": { 18 | "botbuilder": "^4.5.3", 19 | "botbuilder-dialogs": "^4.5.3", 20 | "botframework-wechat": "file:../../../libraries/typescript/Microsoft.Bot.Builder.Adapters.WeChat", 21 | "dotenv": "^8.2.0", 22 | "restify": "^8.3.0" 23 | }, 24 | "devDependencies": { 25 | "@types/dotenv": "6.1.1", 26 | "@types/restify": "7.2.12", 27 | "nodemon": "~1.19.1", 28 | "tslint": "^5.18.0", 29 | "typescript": "^3.5.2" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/src/bots/dialogBot.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | import { ActivityHandler, BotState, ConversationState, StatePropertyAccessor, UserState } from 'botbuilder'; 5 | import { Dialog, DialogState } from 'botbuilder-dialogs'; 6 | import { MainDialog } from '../dialogs/mainDialog'; 7 | 8 | export class DialogBot extends ActivityHandler { 9 | private conversationState: BotState; 10 | private userState: BotState; 11 | private dialog: Dialog; 12 | private dialogState: StatePropertyAccessor; 13 | 14 | /** 15 | * 16 | * @param {BotState} conversationState 17 | * @param {BotState} userState 18 | * @param {Dialog} dialog 19 | */ 20 | constructor(conversationState: BotState, userState: BotState, dialog: Dialog) { 21 | super(); 22 | if (!conversationState) { 23 | throw new Error('[DialogBot]: Missing parameter. conversationState is required'); 24 | } 25 | if (!userState) { 26 | throw new Error('[DialogBot]: Missing parameter. userState is required'); 27 | } 28 | if (!dialog) { 29 | throw new Error('[DialogBot]: Missing parameter. dialog is required'); 30 | } 31 | 32 | this.conversationState = conversationState as ConversationState; 33 | this.userState = userState as UserState; 34 | this.dialog = dialog; 35 | this.dialogState = this.conversationState.createProperty('DialogState'); 36 | 37 | this.onMessage(async (context, next) => { 38 | console.log('Running dialog with Message Activity.'); 39 | 40 | // Run the Dialog with the new message Activity. 41 | await (this.dialog as MainDialog).run(context, this.dialogState); 42 | 43 | // Save any state changes. The load happened during the execution of the Dialog. 44 | await this.conversationState.saveChanges(context, false); 45 | await this.userState.saveChanges(context, false); 46 | 47 | // By calling next() you ensure that the next BotHandler is run. 48 | await next(); 49 | }); 50 | 51 | this.onDialog(async (context, next) => { 52 | // Save any state changes. The load happened during the execution of the Dialog. 53 | await this.conversationState.saveChanges(context, false); 54 | await this.userState.saveChanges(context, false); 55 | 56 | // By calling next() you ensure that the next BotHandler is run. 57 | await next(); 58 | }); 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/src/bots/richCardsBot.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | 4 | import { MessageFactory, BotState } from 'botbuilder'; 5 | import { DialogBot } from './dialogBot'; 6 | import { Dialog } from 'botbuilder-dialogs'; 7 | 8 | /** 9 | * RichCardsBot prompts a user to select a Rich Card and then returns the card 10 | * that matches the user's selection. 11 | */ 12 | export class RichCardsBot extends DialogBot { 13 | constructor(conversationState: BotState, userState: BotState, dialog: Dialog) { 14 | super(conversationState, userState, dialog); 15 | 16 | this.onMembersAdded(async (context, next) => { 17 | const membersAdded = context.activity.membersAdded; 18 | for (let cnt = 0; cnt < membersAdded.length; cnt++) { 19 | if (membersAdded[cnt].id !== context.activity.recipient.id) { 20 | const reply = MessageFactory.text('Welcome to CardBot. ' + 21 | 'This bot will show you different types of Rich Cards. ' + 22 | 'Please type anything to get started.'); 23 | await context.sendActivity(reply); 24 | } 25 | } 26 | 27 | // By calling next() you ensure that the next BotHandler is run. 28 | await next(); 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/src/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT License. 3 | import { config } from 'dotenv'; 4 | import * as path from 'path'; 5 | import * as restify from 'restify'; 6 | 7 | // Import required bot services. 8 | // See https://aka.ms/bot-services to learn more about the different parts of a bot. 9 | import { ConversationState, MemoryStorage, UserState } from 'botbuilder'; 10 | import { SecretInfo, VerificationHelper, WeChatAdapter } from 'botframework-wechat'; 11 | import { RichCardsBot } from './bots/richCardsBot'; 12 | 13 | import { MainDialog } from './dialogs/mainDialog'; 14 | const ENV_FILE = path.join(__dirname, '..', '.env'); 15 | config({ path: ENV_FILE }); 16 | 17 | // Create HTTP server. 18 | const server = restify.createServer(); 19 | server.listen(process.env.port || process.env.PORT || 3978, () => { 20 | console.log(`\n${server.name} listening to ${server.url}`); 21 | console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`); 22 | console.log(`\nTo test your bot, see: https://aka.ms/debug-with-emulator`); 23 | }); 24 | 25 | const storage = new MemoryStorage(); 26 | 27 | // Create adapter. 28 | // See https://aka.ms/about-bot-adapter to learn more about adapters. 29 | const wechatAdapter = new WeChatAdapter(storage, { 30 | AppId: process.env.AppId, 31 | AppSecret: process.env.AppSecret, 32 | Token: process.env.Token, 33 | EncodingAESKey: process.env.EncodingAESKey, 34 | UploadTemporaryMedia: process.env.UploadTemporaryMedia === 'true', 35 | PassiveResponse: process.env.passiveResponse === 'true' 36 | }); 37 | 38 | // Catch-all for errors. 39 | wechatAdapter.onTurnError = async (context, error) => { 40 | // This check writes out errors to console log .vs. app insights. 41 | console.error(`\n [onTurnError]: ${error}`); 42 | // Send a message to the user 43 | await context.sendActivity(`Oops. Something went wrong!`); 44 | }; 45 | 46 | // Define a state store for your bot. See https://aka.ms/about-bot-state to learn more about using MemoryStorage. 47 | // A bot requires a state store to persist the dialog and user state between messages. 48 | let conversationState, userState; 49 | 50 | // For local development, in-memory storage is used. 51 | // CAUTION: The Memory Storage used here is for local bot debugging only. When the bot 52 | // is restarted, anything stored in memory will be gone. 53 | const memoryStorage = new MemoryStorage(); 54 | conversationState = new ConversationState(memoryStorage); 55 | userState = new UserState(memoryStorage); 56 | 57 | // Create the main dialog. 58 | const dialog = new MainDialog(); 59 | const bot = new RichCardsBot(conversationState, userState, dialog); 60 | 61 | server.use(restify.plugins.queryParser()); 62 | server.use(restify.plugins.bodyParser()); 63 | // Listen for incoming requests. 64 | server.post('/WeChat', (req, res) => { 65 | const secretInfo: SecretInfo = { 66 | AppId: req.query.appId || undefined, 67 | Signature: req.query.signature || undefined, 68 | Msg_signature: req.query.msg_signature || undefined, 69 | Timestamp: req.query.timestamp || undefined, 70 | Token: req.query.token || undefined, 71 | Nonce: req.query.nonce || undefined, 72 | EncodingAesKey: req.query.encodingAesKey || undefined 73 | }; 74 | wechatAdapter.processActivity(req, res, async (context) => { 75 | // Route to main dialog. 76 | await bot.run(context); 77 | }, 78 | secretInfo); 79 | }); 80 | 81 | server.get('/WeChat', (req, res) => { 82 | const echostr: string = req.query.echostr; 83 | if (VerificationHelper.verifySignature(req.query.signature, req.query.timestamp, req.query.nonce, process.env.Token)) { 84 | res.statusCode = 200; 85 | res.contentType = 'text/plain; charset=utf-8'; 86 | res.send(echostr); 87 | } 88 | }); 89 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/src/resources/MessageMenu.json: -------------------------------------------------------------------------------- 1 | { 2 | "head_content": "Are you satisfied with this service?", 3 | "list": [ 4 | { 5 | "id": "101", 6 | "content": "Satisfied" 7 | }, 8 | { 9 | "id": "102", 10 | "content": "NotSatisfied" 11 | } 12 | ], 13 | "tail_content": "You are welcome to come back again." 14 | } -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "target": "es2016", 5 | "module": "commonjs", 6 | "outDir": "./lib", 7 | "rootDir": "./src", 8 | "sourceMap": true, 9 | "incremental": true, 10 | "tsBuildInfoFile": "./lib/.tsbuildinfo", 11 | "resolveJsonModule": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/typescript/Microsoft.Bot.Builder.Adapters.WeChat.TestBot/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "interface-name" : [true, "never-prefix"], 9 | "max-line-length": [false], 10 | "no-console": [false, "log", "error"], 11 | "no-var-requires": false, 12 | "quotemark": [true, "single"], 13 | "one-variable-per-declaration": false, 14 | "curly": [true, "ignore-same-line"], 15 | "trailing-comma": [true, {"multiline": "never", "singleline": "never"}] 16 | }, 17 | "rulesDirectory": [] 18 | } 19 | --------------------------------------------------------------------------------