From c22718282444dfe8aee1edb463cb0db1a695ff5f Mon Sep 17 00:00:00 2001 From: anna lizunova Date: Mon, 18 May 2020 16:58:16 +0300 Subject: [PATCH] Create service by tamplate --- .editorconfig | 84 +++++++++++++ .gitattributes | 21 ++++ .github/workflows/release.yml | 104 ++++++++++++++++ .github/workflows/test.yml | 31 +++++ .gitignore | 63 ++++++++++ CONTRIBUTING.md | 67 +++++++++++ MAVN.Service.Kyc.sln | 83 +++++++++++++ .../AutofacExtension.cs | 43 +++++++ client/MAVN.Service.Kyc.Client/IKycApi.cs | 16 +++ client/MAVN.Service.Kyc.Client/IKycClient.cs | 18 +++ client/MAVN.Service.Kyc.Client/KycClient.cs | 21 ++++ .../KycServiceClientSettings.cs | 14 +++ .../MAVN.Service.Kyc.Client.csproj | 34 ++++++ .../MAVN.Service.Kyc.Contract.csproj | 35 ++++++ .../MyPublishedMessage.cs | 7 ++ contract/MAVN.Service.Kyc.Contract/Readme.md | 3 + settings.yaml | 24 ++++ .../MAVN.Service.Kyc.Domain.csproj | 9 ++ src/MAVN.Service.Kyc.Domain/Readme.md | 1 + .../Services/Readme.md | 1 + .../MAVN.Service.Kyc.DomainServices.csproj | 14 +++ src/MAVN.Service.Kyc.DomainServices/Readme.md | 1 + src/MAVN.Service.Kyc/AutoMapperProfile.cs | 12 ++ .../Controllers/KycController.cs | 17 +++ src/MAVN.Service.Kyc/Dockerfile | 4 + src/MAVN.Service.Kyc/MAVN.Service.Kyc.csproj | 36 ++++++ .../Modules/RabbitMqModule.cs | 37 ++++++ src/MAVN.Service.Kyc/Modules/ServiceModule.cs | 41 +++++++ src/MAVN.Service.Kyc/Program.cs | 17 +++ src/MAVN.Service.Kyc/Services/Readme.md | 1 + .../Services/ShutdownManager.cs | 43 +++++++ .../Services/StartupManager.cs | 27 +++++ src/MAVN.Service.Kyc/Settings/AppSettings.cs | 11 ++ src/MAVN.Service.Kyc/Settings/DbSettings.cs | 10 ++ src/MAVN.Service.Kyc/Settings/KycSettings.cs | 13 ++ .../Settings/RabbitMqSettings.cs | 15 +++ src/MAVN.Service.Kyc/Startup.cs | 113 ++++++++++++++++++ .../AutoMapperProfileTests.cs | 25 ++++ ...entHttpPathsAreMatchedInControllersTest.cs | 101 ++++++++++++++++ .../MAVN.Service.Kyc.Tests.csproj | 17 +++ .../SensitiveDataTests.cs | 56 +++++++++ 41 files changed, 1290 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 MAVN.Service.Kyc.sln create mode 100644 client/MAVN.Service.Kyc.Client/AutofacExtension.cs create mode 100644 client/MAVN.Service.Kyc.Client/IKycApi.cs create mode 100644 client/MAVN.Service.Kyc.Client/IKycClient.cs create mode 100644 client/MAVN.Service.Kyc.Client/KycClient.cs create mode 100644 client/MAVN.Service.Kyc.Client/KycServiceClientSettings.cs create mode 100644 client/MAVN.Service.Kyc.Client/MAVN.Service.Kyc.Client.csproj create mode 100644 contract/MAVN.Service.Kyc.Contract/MAVN.Service.Kyc.Contract.csproj create mode 100644 contract/MAVN.Service.Kyc.Contract/MyPublishedMessage.cs create mode 100644 contract/MAVN.Service.Kyc.Contract/Readme.md create mode 100644 settings.yaml create mode 100644 src/MAVN.Service.Kyc.Domain/MAVN.Service.Kyc.Domain.csproj create mode 100644 src/MAVN.Service.Kyc.Domain/Readme.md create mode 100644 src/MAVN.Service.Kyc.Domain/Services/Readme.md create mode 100644 src/MAVN.Service.Kyc.DomainServices/MAVN.Service.Kyc.DomainServices.csproj create mode 100644 src/MAVN.Service.Kyc.DomainServices/Readme.md create mode 100644 src/MAVN.Service.Kyc/AutoMapperProfile.cs create mode 100644 src/MAVN.Service.Kyc/Controllers/KycController.cs create mode 100644 src/MAVN.Service.Kyc/Dockerfile create mode 100644 src/MAVN.Service.Kyc/MAVN.Service.Kyc.csproj create mode 100644 src/MAVN.Service.Kyc/Modules/RabbitMqModule.cs create mode 100644 src/MAVN.Service.Kyc/Modules/ServiceModule.cs create mode 100644 src/MAVN.Service.Kyc/Program.cs create mode 100644 src/MAVN.Service.Kyc/Services/Readme.md create mode 100644 src/MAVN.Service.Kyc/Services/ShutdownManager.cs create mode 100644 src/MAVN.Service.Kyc/Services/StartupManager.cs create mode 100644 src/MAVN.Service.Kyc/Settings/AppSettings.cs create mode 100644 src/MAVN.Service.Kyc/Settings/DbSettings.cs create mode 100644 src/MAVN.Service.Kyc/Settings/KycSettings.cs create mode 100644 src/MAVN.Service.Kyc/Settings/RabbitMqSettings.cs create mode 100644 src/MAVN.Service.Kyc/Startup.cs create mode 100644 tests/MAVN.Service.Kyc.Tests/AutoMapperProfileTests.cs create mode 100644 tests/MAVN.Service.Kyc.Tests/ClientHttpPathsAreMatchedInControllersTest.cs create mode 100644 tests/MAVN.Service.Kyc.Tests/MAVN.Service.Kyc.Tests.csproj create mode 100644 tests/MAVN.Service.Kyc.Tests/SensitiveDataTests.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..2dc0806 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,84 @@ +# EditorConfig is awesome:http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space +end_of_line = lf +# (Please don't specify an indent_size here; that has too many unintended consequences.) + +# Code files +[*.{cs,csx}] +indent_size = 4 +insert_final_newline = true +charset = utf-8-bom + +[*.{sln,csproj}] +end_of_line = crlf + +# Xml project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# Xml config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs}] +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# CSharp code style settings: +[*.cs] +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..88a128f --- /dev/null +++ b/.gitattributes @@ -0,0 +1,21 @@ +# Auto normalize line-endings + +* text eol=lf encoding=UTF-8 + +# Always LF line-endings + +*.sh text eol=lf + +# Always CRLF line-endings + +*.sln text eol=crlf +*.csproj text eol=crlf + +# Diff settings + +*.cs diff=csharp text +*.vb text +*.ttf -text diff +*.eot -text diff +*.woff -text diff +*.woff2 -text diff \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..bc4024c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,104 @@ +name: release + +on: + release: + types: + - published + +env: + RELEASE_CLIENT: true + RELEASE_CONTRACT: true + RELEASE_JOB: false + RELEASE_SERVICE: true + + CLIENT_PROJECT: ./client/MAVN.Service.Kyc.Client/MAVN.Service.Kyc.Client.csproj + CONTRACT_PROJECT: ./contract/MAVN.Service.Kyc.Contract/MAVN.Service.Kyc.Contract.csproj + JOB_DOCKER_IMAGE: Kyc-job + JOB_PROJECT: ./src/MAVN.Job.Kyc/MAVN.Job.Kyc.csproj + SERVICE_DOCKER_IMAGE: Kyc-service # this template value must be fixed in most cases + SERVICE_PROJECT: ./src/MAVN.Service.Kyc/MAVN.Service.Kyc.csproj + + + +jobs: + publish-release: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + # Set release version + - name: Get release version from tag + id: version + uses: LykkeBusiness/get-semver-from-tag-action@v1.0.2 + with: + tag: ${{ github.ref }} + - name: Set version for release + uses: allenevans/set-env@v1.0.0 + with: + VERSION: ${{ steps.version.outputs.non-prefixed }} + + # Login to Docker Hub + - name: Login to docker hub + if: env.RELEASE_JOB == 'true' || env.RELEASE_SERVICE == 'true' + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: docker login --username $DOCKER_USERNAME --password $DOCKER_PASSWORD + + # Build solution + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.201 + - name: Install dependencies + run: dotnet restore + - name: Build solution + run: dotnet build --configuration Release --no-restore /p:Version=$VERSION + + # Build Docker images + - name: Build docker image for a job + if: env.RELEASE_JOB == 'true' + run: | + dotnet publish $JOB_PROJECT --configuration Release --output ./docker/job --no-build /p:Version=$VERSION + docker build --tag openmavn/$JOB_DOCKER_IMAGE:$VERSION ./docker/job + - name: Build docker image for a service + if: env.RELEASE_SERVICE == 'true' + run: | + dotnet publish $SERVICE_PROJECT --configuration Release --output ./docker/service --no-build /p:Version=$VERSION + docker build --tag openmavn/$SERVICE_DOCKER_IMAGE:$VERSION ./docker/service + + # Pack NuGet packages + - name: Pack client NuGet package + if: env.RELEASE_CLIENT == 'true' + run: dotnet pack $CLIENT_PROJECT --configuration Release --output ./packages --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg /p:Version=$VERSION + - name: Pack contract NuGet package + if: env.RELEASE_CONTRACT == 'true' + run: dotnet pack $CONTRACT_PROJECT --configuration Release --output ./packages --no-build --include-symbols --include-source /p:SymbolPackageFormat=snupkg /p:Version=$VERSION + + # Push Docker Images + - name: Push job docker image + if: env.RELEASE_JOB == 'true' + run: docker push openmavn/$JOB_DOCKER_IMAGE:$VERSION + - name: Push service docker image + if: env.RELEASE_SERVICE == 'true' + run: docker push openmavn/$SERVICE_DOCKER_IMAGE:$VERSION + + # Push NuGet packages + - name: Push NuGet packages + if: env.RELEASE_CLIENT == 'true' || env.RELEASE_CONTRACT == 'true' + env: + API_KEY: ${{ secrets.NUGET_ORG_API_KEY }} + run: dotnet nuget push ./packages/**/*.nupkg --source https://api.nuget.org/v3/index.json --api-key $API_KEY + + # Create next release draft + - name: Create next release draft + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: next + release_name: next + body: + draft: true \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..23d1d01 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,31 @@ +name: test + +on: + pull_request: + branches: [ master ] + push: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.201 + - name: Install dependencies + run: dotnet restore + - name: Build + run: dotnet build --configuration Release --no-restore + - name: Test + run: dotnet test --no-restore --verbosity normal /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov + - name: Publish coverage report + if: github.event_name == 'push' + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./tests/MAVN.Service.Kyc.Tests/TestResults/coverage.info diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1504ae4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# Global wildcards +*.aps +*.bak +*.dll +*.log +*.ncb +*.obj +*.old +*.opensdf +*.orig +*.pdb +*.Publish.xml +*.sdf +*.sln.cache +*.suo +*.tmp +*.user +*.lock.json + +# Well-known infrastructure folders +/packages/ +/target/ +**/aspnet_client/ + +# IDEs +*[Rr]e[Ss]harper* +**/.idea/ +**/.metadata/ +**/.settings/ +/[Tt]est[Rr]esults/ +[Bb]in/ +[Oo]bj/ +[Dd]ebug/ +[Rr]elease/ +ipch/ + +# Visual Studio project upgrade +[Bb]ackup/ +UpgradeLog* +_UpgradeReport_Files/ + +# Operating Systems generated +.DS_Store +[Dd]esktop.ini +[Tt]humbs.db + +#ncrunch +*.*crunch* +_NCrunch_* + +#publish profiles +*publish.ps1 +*.pubxml +*.psm1 + +#some test +.vs +node_modules +**/launchSettings.json +**/appsettings.json +**/appsettings.*.json +**/*sonar* +/client/**/*.xml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4d5ef54 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# How to contribute + +First of all, thank you for wanting to contribute! We really appreciate all the awesome support we get from our community. We want to keep it as easy as possible to contribute changes that get things working in your environment. There are a few guidelines we need contributors to follow to keep the project flowing smoothly. + +These guidelines are for code changes but we are always very grateful to receive other forms of contribution. + +## Preparation + +Before starting work on a *functional* change, i.e. a new feature, a change to an existing feature or a fixing a bug, please ensure an [issue has been raised](https://github.com/OpenMAVN/MAVN.Service.Kyc/issues/). Indicate your intention to do the work by writing a comment on the issue. This will prevent duplication of effort. If the change is non-trivial, it's usually best to propose a design in the issue comments before making a significant effort on the implementation. + +It is **not** necessary to raise an issue for non-functional changes, e.g. refactoring, adding tests, reformatting code, documentation, updating packages, etc. + +## Tests + +All new features must be covered by feature tests. + +## Branches + +There is a single mainline branches `master` which is used for trunk-based development work. All new features, changes, etc. must be applied to `master`. + +## Making changes + +1. [Fork](http://help.github.com/forking/) on GitHub +1. Clone your fork locally +1. Configure the `upstream` repo (`git remote add upstream git://github.com/OpenMAVN/MAVN.Service.Kyc.git`) +1. Checkout `master` (`git checkout master`) +1. Create a local branch (`git checkout -b my-branch`). The branch name should be descriptive, or it can just be the GitHub issue number which the work relates to, e.g. `123`. +1. Work on your change +1. Rebase if required (see 'Handling updates from `upstream`' below) +1. Test the build locally +1. Push the branch up to GitHub (`git push origin my-branch`) +1. Send a pull request on GitHub (see 'Sending a Pull Request' below) + +You should **never** work on a clone of `master`, and you should **never** send a pull request from `master`. Always use a feature/patch branch. The reasons for this are detailed below. + +## Handling updates from `upstream` + +While you're working away in your branch it's quite possible that your `upstream` `master` may be updated. If this happens you should: + +1. [Stash](https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning) any un-committed changes you need to +1. `git checkout master` +1. `git pull upstream master --ff-only` +1. `git checkout my-branch` +1. `git rebase master my-branch` +1. `git push origin master` (optional) this keeps `master` in your fork up to date + +These steps ensure your history is "clean" i.e. you have one branch from `master` followed by your changes in a straight line. Failing to do this ends up with several "messy" merges in your history, which we don't want. This is the reason why you should always work in a branch and you should never be working in or sending pull requests from `master`. + +If you're working on a long running feature you may want to do this quite often to reduce the risk of tricky merges later on. + +## Sending a pull request + +While working on your feature you may well create several branches, which is fine, but before you send a pull request you should ensure that you have rebased back to a single "feature/patch branch". We care about your commits, and we care about your feature/patch branch, but we don't care about how many or which branches you created while you were working on it. :smile: + +When you're ready to go you should confirm that you are up to date and rebased with `upstream` `master` (see "Handling updates from `upstream`" above) and then: + +1. `git push origin my-branch` +1. Send a descriptive [pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) on GitHub. + - Make sure the pull request is **from** the branch on your fork **to** the `OpenMAVN/MAVN.Service.Kyc` `master`. + - If your changes relate to a GitHub issue, add the issue number to the pull request description in the format `#123`. +1. If GitHub determines that the pull request can be merged automatically, a test build will commence shortly after you raise the pull request. The build status will be reported on the pull request. + - If the build fails, there may be a problem with your changes which you will have to fix before the pull request can be merged. Follow the link to the build server and inspect the build logs to see what caused the failure. + - Occasionally, build failures may be due to problems on the build server rather than problems in your changes. If you determine this to be the case, please add a comment on the pull request and one of the maintainers will address the problem. + +## What happens next? + +The maintainers will review your pull request and provide any feedback required. \ No newline at end of file diff --git a/MAVN.Service.Kyc.sln b/MAVN.Service.Kyc.sln new file mode 100644 index 0000000..0980ca5 --- /dev/null +++ b/MAVN.Service.Kyc.sln @@ -0,0 +1,83 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26430.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "0. Solution items", "0. Solution items", "{7664A776-FBC4-4DB1-BE35-29E9664E24B4}" + ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore + LICENSE = LICENSE + README.md = README.md + settings.yaml = settings.yaml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "1. Domain", "1. Domain", "{CC2067D7-1971-47BB-B491-5649EA3C18B2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.Kyc.Domain", "src\MAVN.Service.Kyc.Domain\MAVN.Service.Kyc.Domain.csproj", "{F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.Kyc.DomainServices", "src\MAVN.Service.Kyc.DomainServices\MAVN.Service.Kyc.DomainServices.csproj", "{2D5F52EC-2A27-4045-81ED-72355E2A6325}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2. Repositories", "2. Repositories", "{BF745453-B940-470E-81BC-43FB67703D4E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3. Contract", "3. Contract", "{14B5AF15-F733-4EF0-9FB9-3E61C4C83ADD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.Kyc.Contract", "contract\MAVN.Service.Kyc.Contract\MAVN.Service.Kyc.Contract.csproj", "{931B95E3-AF9F-4A4C-9C6A-5959C2FBCAC9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "4. Client", "4. Client", "{C9A2CFDE-EA32-4946-B679-7CE6EFA816B8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.Kyc.Client", "client\MAVN.Service.Kyc.Client\MAVN.Service.Kyc.Client.csproj", "{3C300C31-97D3-41E8-A627-C53491BDA28B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "5. Tests", "5. Tests", "{8F9036B1-5106-4C69-B2D2-B78EE52687A0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.Kyc.Tests", "tests\MAVN.Service.Kyc.Tests\MAVN.Service.Kyc.Tests.csproj", "{A61FFDEE-5725-4650-A788-6E55EE5EFD5B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "6. Hosts", "6. Hosts", "{EE7F3159-E06C-497F-96D4-DB2A6B03A6AB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.Kyc", "src\MAVN.Service.Kyc\MAVN.Service.Kyc.csproj", "{E414FDB9-FEEA-4CD0-9BBA-D1541601DF29}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E414FDB9-FEEA-4CD0-9BBA-D1541601DF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E414FDB9-FEEA-4CD0-9BBA-D1541601DF29}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E414FDB9-FEEA-4CD0-9BBA-D1541601DF29}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E414FDB9-FEEA-4CD0-9BBA-D1541601DF29}.Release|Any CPU.Build.0 = Release|Any CPU + {3C300C31-97D3-41E8-A627-C53491BDA28B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C300C31-97D3-41E8-A627-C53491BDA28B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C300C31-97D3-41E8-A627-C53491BDA28B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C300C31-97D3-41E8-A627-C53491BDA28B}.Release|Any CPU.Build.0 = Release|Any CPU + {931B95E3-AF9F-4A4C-9C6A-5959C2FBCAC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {931B95E3-AF9F-4A4C-9C6A-5959C2FBCAC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {931B95E3-AF9F-4A4C-9C6A-5959C2FBCAC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {931B95E3-AF9F-4A4C-9C6A-5959C2FBCAC9}.Release|Any CPU.Build.0 = Release|Any CPU + {F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955}.Release|Any CPU.Build.0 = Release|Any CPU + {2D5F52EC-2A27-4045-81ED-72355E2A6325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D5F52EC-2A27-4045-81ED-72355E2A6325}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D5F52EC-2A27-4045-81ED-72355E2A6325}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D5F52EC-2A27-4045-81ED-72355E2A6325}.Release|Any CPU.Build.0 = Release|Any CPU + {A61FFDEE-5725-4650-A788-6E55EE5EFD5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A61FFDEE-5725-4650-A788-6E55EE5EFD5B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A61FFDEE-5725-4650-A788-6E55EE5EFD5B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A61FFDEE-5725-4650-A788-6E55EE5EFD5B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E414FDB9-FEEA-4CD0-9BBA-D1541601DF29} = {EE7F3159-E06C-497F-96D4-DB2A6B03A6AB} + {3C300C31-97D3-41E8-A627-C53491BDA28B} = {C9A2CFDE-EA32-4946-B679-7CE6EFA816B8} + {931B95E3-AF9F-4A4C-9C6A-5959C2FBCAC9} = {14B5AF15-F733-4EF0-9FB9-3E61C4C83ADD} + {F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955} = {CC2067D7-1971-47BB-B491-5649EA3C18B2} + {2D5F52EC-2A27-4045-81ED-72355E2A6325} = {CC2067D7-1971-47BB-B491-5649EA3C18B2} + {A61FFDEE-5725-4650-A788-6E55EE5EFD5B} = {8F9036B1-5106-4C69-B2D2-B78EE52687A0} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EB6C0EF4-AA6A-444D-8603-3669F73A58BC} + EndGlobalSection +EndGlobal diff --git a/client/MAVN.Service.Kyc.Client/AutofacExtension.cs b/client/MAVN.Service.Kyc.Client/AutofacExtension.cs new file mode 100644 index 0000000..16491c0 --- /dev/null +++ b/client/MAVN.Service.Kyc.Client/AutofacExtension.cs @@ -0,0 +1,43 @@ +using System; +using Autofac; +using JetBrains.Annotations; +using Lykke.HttpClientGenerator; +using Lykke.HttpClientGenerator.Infrastructure; + +namespace MAVN.Service.Kyc.Client +{ + /// + /// Extension for client registration + /// + [PublicAPI] + public static class AutofacExtension + { + /// + /// Registers in Autofac container using . + /// + /// Autofac container builder. + /// Kyc client settings. + /// Optional configure handler. + public static void RegisterKycClient( + [NotNull] this ContainerBuilder builder, + [NotNull] KycServiceClientSettings settings, + [CanBeNull] Func builderConfigure) + { + if (builder == null) + throw new ArgumentNullException(nameof(builder)); + if (settings == null) + throw new ArgumentNullException(nameof(settings)); + if (string.IsNullOrWhiteSpace(settings.ServiceUrl)) + throw new ArgumentException("Value cannot be null or whitespace.", nameof(KycServiceClientSettings.ServiceUrl)); + + var clientBuilder = HttpClientGenerator.BuildForUrl(settings.ServiceUrl) + .WithAdditionalCallsWrapper(new ExceptionHandlerCallsWrapper()); + + clientBuilder = builderConfigure?.Invoke(clientBuilder) ?? clientBuilder.WithoutRetries(); + + builder.RegisterInstance(new KycClient(clientBuilder.Create())) + .As() + .SingleInstance(); + } + } +} diff --git a/client/MAVN.Service.Kyc.Client/IKycApi.cs b/client/MAVN.Service.Kyc.Client/IKycApi.cs new file mode 100644 index 0000000..c3cc7f3 --- /dev/null +++ b/client/MAVN.Service.Kyc.Client/IKycApi.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using Refit; + +namespace MAVN.Service.Kyc.Client +{ + // This is an example of service controller interfaces. + // Actual interface methods must be placed here (not in IKycClient interface). + + /// + /// Kyc client API interface. + /// + [PublicAPI] + public interface IKycApi + { + } +} diff --git a/client/MAVN.Service.Kyc.Client/IKycClient.cs b/client/MAVN.Service.Kyc.Client/IKycClient.cs new file mode 100644 index 0000000..d8fe011 --- /dev/null +++ b/client/MAVN.Service.Kyc.Client/IKycClient.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; + +namespace MAVN.Service.Kyc.Client +{ + /// + /// Kyc client interface. + /// + [PublicAPI] + public interface IKycClient + { + // Make your app's controller interfaces visible by adding corresponding properties here. + // NO actual methods should be placed here (these go to controller interfaces, for example - IKycApi). + // ONLY properties for accessing controller interfaces are allowed. + + /// Application Api interface + IKycApi Api { get; } + } +} diff --git a/client/MAVN.Service.Kyc.Client/KycClient.cs b/client/MAVN.Service.Kyc.Client/KycClient.cs new file mode 100644 index 0000000..6a12824 --- /dev/null +++ b/client/MAVN.Service.Kyc.Client/KycClient.cs @@ -0,0 +1,21 @@ +using Lykke.HttpClientGenerator; + +namespace MAVN.Service.Kyc.Client +{ + /// + /// Kyc API aggregating interface. + /// + public class KycClient : IKycClient + { + // Note: Add similar Api properties for each new service controller + + /// Inerface to Kyc Api. + public IKycApi Api { get; private set; } + + /// C-tor + public KycClient(IHttpClientGenerator httpClientGenerator) + { + Api = httpClientGenerator.Generate(); + } + } +} diff --git a/client/MAVN.Service.Kyc.Client/KycServiceClientSettings.cs b/client/MAVN.Service.Kyc.Client/KycServiceClientSettings.cs new file mode 100644 index 0000000..968f125 --- /dev/null +++ b/client/MAVN.Service.Kyc.Client/KycServiceClientSettings.cs @@ -0,0 +1,14 @@ +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.Kyc.Client +{ + /// + /// Kyc client settings. + /// + public class KycServiceClientSettings + { + /// Service url. + [HttpCheck("api/isalive")] + public string ServiceUrl {get; set;} + } +} diff --git a/client/MAVN.Service.Kyc.Client/MAVN.Service.Kyc.Client.csproj b/client/MAVN.Service.Kyc.Client/MAVN.Service.Kyc.Client.csproj new file mode 100644 index 0000000..ccdd366 --- /dev/null +++ b/client/MAVN.Service.Kyc.Client/MAVN.Service.Kyc.Client.csproj @@ -0,0 +1,34 @@ + + + netstandard2.0 + 1.0.1 + LykkeBisiness + LykkeBisiness + MAVN.Service.Kyc + Client for MAVN.Service.Kyc API + https://github.com/OpenMAVN/MAVN.Service.Kyc/blob/master/LICENSE + https://github.com/OpenMAVN/MAVN.Service.Kyc + https://avatars3.githubusercontent.com/u/14153330?v=3&s=200 + https://github.com/OpenMAVN/MAVN.Service.Kyc.git + git + MAVN;Kyc + MAVN.Service.Kyc.Client + + + $(OutputPath)$(AssemblyName).xml + + + $(OutputPath)$(AssemblyName).xml + + + + + + + + + + + + + \ No newline at end of file diff --git a/contract/MAVN.Service.Kyc.Contract/MAVN.Service.Kyc.Contract.csproj b/contract/MAVN.Service.Kyc.Contract/MAVN.Service.Kyc.Contract.csproj new file mode 100644 index 0000000..f3b1d18 --- /dev/null +++ b/contract/MAVN.Service.Kyc.Contract/MAVN.Service.Kyc.Contract.csproj @@ -0,0 +1,35 @@ + + + + netstandard2.0 + 1.0.1 + LykkeBisiness + LykkeBisiness + Contract for the MAVN.Service.Kyc + https://github.com/OpenMAVN/MAVN.Service.Kyc/blob/master/LICENSE + https://github.com/OpenMAVN/MAVN.Service.Kyc + https://avatars3.githubusercontent.com/u/14153330?v=3&s=200 + https://github.com/OpenMAVN/MAVN.Service.Kyc.git + git + MAVN;Kyc + MAVN.Service.Kyc.Contract + + + + bin\Debug\netstandard2.0\MAVN.Service.Kyc.Contract.xml + 1701;1702;1705;1591 + + + + bin\Release\netstandard2.0\MAVN.Service.Kyc.Contract.xml + 1701;1702;1705;1591 + + + + + true + lib/netstandard2.0 + + + + diff --git a/contract/MAVN.Service.Kyc.Contract/MyPublishedMessage.cs b/contract/MAVN.Service.Kyc.Contract/MyPublishedMessage.cs new file mode 100644 index 0000000..ddf55e2 --- /dev/null +++ b/contract/MAVN.Service.Kyc.Contract/MyPublishedMessage.cs @@ -0,0 +1,7 @@ +namespace MAVN.Service.Kyc.Contract +{ + // NOTE: This is outgiong message example + public class MyPublishedMessage + { + } +} \ No newline at end of file diff --git a/contract/MAVN.Service.Kyc.Contract/Readme.md b/contract/MAVN.Service.Kyc.Contract/Readme.md new file mode 100644 index 0000000..0e00bef --- /dev/null +++ b/contract/MAVN.Service.Kyc.Contract/Readme.md @@ -0,0 +1,3 @@ +# Place outgoing message's models here +# Deploy this assembly as nuget package Lykke.Service.Kyc.Contract +# Use published nuget package in service's clients diff --git a/settings.yaml b/settings.yaml new file mode 100644 index 0000000..d31b8c6 --- /dev/null +++ b/settings.yaml @@ -0,0 +1,24 @@ +KycService: + Db: + LogsConnString: + settings-key: KycService-LogsConnString + types: + - AzureTableStorage + Rabbit: + Publishers: + ConnectionString: + settings-key: Pub-ConnectionString + types: + - RabbitMq +SlackNotifications: + AzureQueue: + ConnectionString: + settings-key: SlackNotificationsConnString + types: + - AzureTableStorage + QueueName: + settings-key: SlackQueueName +MonitoringServiceClient: + MonitoringServiceUrl: + settings-key: MonitoringServiceUrl + diff --git a/src/MAVN.Service.Kyc.Domain/MAVN.Service.Kyc.Domain.csproj b/src/MAVN.Service.Kyc.Domain/MAVN.Service.Kyc.Domain.csproj new file mode 100644 index 0000000..3ea3310 --- /dev/null +++ b/src/MAVN.Service.Kyc.Domain/MAVN.Service.Kyc.Domain.csproj @@ -0,0 +1,9 @@ + + + netcoreapp3.1 + 1.0.0 + + + + + diff --git a/src/MAVN.Service.Kyc.Domain/Readme.md b/src/MAVN.Service.Kyc.Domain/Readme.md new file mode 100644 index 0000000..6d38761 --- /dev/null +++ b/src/MAVN.Service.Kyc.Domain/Readme.md @@ -0,0 +1 @@ +Place domain objects here, at the root of the project \ No newline at end of file diff --git a/src/MAVN.Service.Kyc.Domain/Services/Readme.md b/src/MAVN.Service.Kyc.Domain/Services/Readme.md new file mode 100644 index 0000000..ac13c02 --- /dev/null +++ b/src/MAVN.Service.Kyc.Domain/Services/Readme.md @@ -0,0 +1 @@ +Place interfaces of your services in this folder. Group them in subfolders by business functions \ No newline at end of file diff --git a/src/MAVN.Service.Kyc.DomainServices/MAVN.Service.Kyc.DomainServices.csproj b/src/MAVN.Service.Kyc.DomainServices/MAVN.Service.Kyc.DomainServices.csproj new file mode 100644 index 0000000..a868a13 --- /dev/null +++ b/src/MAVN.Service.Kyc.DomainServices/MAVN.Service.Kyc.DomainServices.csproj @@ -0,0 +1,14 @@ + + + netcoreapp3.1 + 1.0.0 + + + + + + + + + + diff --git a/src/MAVN.Service.Kyc.DomainServices/Readme.md b/src/MAVN.Service.Kyc.DomainServices/Readme.md new file mode 100644 index 0000000..77cdada --- /dev/null +++ b/src/MAVN.Service.Kyc.DomainServices/Readme.md @@ -0,0 +1 @@ +Place implementations of your services in this folder. Group them in subfolders by business functions \ No newline at end of file diff --git a/src/MAVN.Service.Kyc/AutoMapperProfile.cs b/src/MAVN.Service.Kyc/AutoMapperProfile.cs new file mode 100644 index 0000000..9386a0b --- /dev/null +++ b/src/MAVN.Service.Kyc/AutoMapperProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace MAVN.Service.Kyc +{ + public class AutoMapperProfile : Profile + { + public AutoMapperProfile() + { + // TODO - add mappings here... + } + } +} diff --git a/src/MAVN.Service.Kyc/Controllers/KycController.cs b/src/MAVN.Service.Kyc/Controllers/KycController.cs new file mode 100644 index 0000000..c274016 --- /dev/null +++ b/src/MAVN.Service.Kyc/Controllers/KycController.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using MAVN.Service.Kyc.Client; +using Microsoft.AspNetCore.Mvc; + +namespace MAVN.Service.Kyc.Controllers +{ + [Route("api/Kyc")] // TODO fix route + public class KycController : Controller, IKycApi + { + private readonly IMapper _mapper; + + public KycController(IMapper mapper) + { + _mapper = mapper; + } + } +} diff --git a/src/MAVN.Service.Kyc/Dockerfile b/src/MAVN.Service.Kyc/Dockerfile new file mode 100644 index 0000000..a5c9916 --- /dev/null +++ b/src/MAVN.Service.Kyc/Dockerfile @@ -0,0 +1,4 @@ +FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 +WORKDIR /app +COPY . . +ENTRYPOINT ["dotnet", "MAVN.Service.Kyc.dll"] diff --git a/src/MAVN.Service.Kyc/MAVN.Service.Kyc.csproj b/src/MAVN.Service.Kyc/MAVN.Service.Kyc.csproj new file mode 100644 index 0000000..b196aba --- /dev/null +++ b/src/MAVN.Service.Kyc/MAVN.Service.Kyc.csproj @@ -0,0 +1,36 @@ + + + netcoreapp3.1 + Exe + 1.0.1 + OutOfProcess + AspNetCoreModuleV2 + latest + + + 1701;1702;1705;1591 + + + 1701;1702;1705;1591 + + + + + + + PreserveNewest + + + + + + + + + + + + + + + diff --git a/src/MAVN.Service.Kyc/Modules/RabbitMqModule.cs b/src/MAVN.Service.Kyc/Modules/RabbitMqModule.cs new file mode 100644 index 0000000..60d7bbb --- /dev/null +++ b/src/MAVN.Service.Kyc/Modules/RabbitMqModule.cs @@ -0,0 +1,37 @@ +using Autofac; +using JetBrains.Annotations; +using Lykke.RabbitMqBroker.Publisher; +using Lykke.SettingsReader; +using MAVN.Service.Kyc.Contract; +using MAVN.Service.Kyc.Settings; + +namespace MAVN.Service.Kyc.Modules +{ + [UsedImplicitly] + public class RabbitMqModule : Module + { + private const string PubExchangeName = "REPLACE THIS WITH PROPER EXCHANGE NAME"; // TODO pass proper exchange name + + private readonly RabbitMqSettings _settings; + + public RabbitMqModule(IReloadingManager settingsManager) + { + _settings = settingsManager.CurrentValue.KycService.Rabbit; + } + + protected override void Load(ContainerBuilder builder) + { + // NOTE: Do not register entire settings in container, pass necessary settings to services which requires them + + RegisterRabbitMqPublishers(builder); + } + + // registered publishers could be esolved by IRabbitPublisher interface + private void RegisterRabbitMqPublishers(ContainerBuilder builder) + { + builder.RegisterJsonRabbitPublisher( + _settings.Publishers.ConnectionString, + PubExchangeName); + } + } +} diff --git a/src/MAVN.Service.Kyc/Modules/ServiceModule.cs b/src/MAVN.Service.Kyc/Modules/ServiceModule.cs new file mode 100644 index 0000000..98fa46e --- /dev/null +++ b/src/MAVN.Service.Kyc/Modules/ServiceModule.cs @@ -0,0 +1,41 @@ +using Autofac; +using JetBrains.Annotations; +using Lykke.Sdk; +using Lykke.Sdk.Health; +using Lykke.SettingsReader; +using MAVN.Service.Kyc.Services; +using MAVN.Service.Kyc.Settings; + +namespace MAVN.Service.Kyc.Modules +{ + [UsedImplicitly] + public class ServiceModule : Module + { + private readonly IReloadingManager _appSettings; + + public ServiceModule(IReloadingManager appSettings) + { + _appSettings = appSettings; + } + + protected override void Load(ContainerBuilder builder) + { + // NOTE: Do not register entire settings in container, pass necessary settings to services which requires them + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .AutoActivate() + .SingleInstance(); + + // TODO: Add your dependencies here + } + } +} diff --git a/src/MAVN.Service.Kyc/Program.cs b/src/MAVN.Service.Kyc/Program.cs new file mode 100644 index 0000000..e204849 --- /dev/null +++ b/src/MAVN.Service.Kyc/Program.cs @@ -0,0 +1,17 @@ +using Lykke.Sdk; +using System.Threading.Tasks; + +namespace MAVN.Service.Kyc +{ + internal sealed class Program + { + public static async Task Main(string[] args) + { +#if DEBUG + await LykkeStarter.Start(true); +#else + await LykkeStarter.Start(false); +#endif + } + } +} diff --git a/src/MAVN.Service.Kyc/Services/Readme.md b/src/MAVN.Service.Kyc/Services/Readme.md new file mode 100644 index 0000000..fdd3f09 --- /dev/null +++ b/src/MAVN.Service.Kyc/Services/Readme.md @@ -0,0 +1 @@ +Place application services here diff --git a/src/MAVN.Service.Kyc/Services/ShutdownManager.cs b/src/MAVN.Service.Kyc/Services/ShutdownManager.cs new file mode 100644 index 0000000..fd344c9 --- /dev/null +++ b/src/MAVN.Service.Kyc/Services/ShutdownManager.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Common; +using Common.Log; +using Lykke.Common; +using Lykke.Common.Log; +using Lykke.Sdk; + +namespace MAVN.Service.Kyc.Services +{ + public class ShutdownManager : IShutdownManager + { + private readonly IEnumerable _stoppables; + private readonly IEnumerable _items; + private readonly ILog _log; + + public ShutdownManager( + IEnumerable stoppables, + IEnumerable items, + ILogFactory logFactory) + { + _stoppables = stoppables; + _items = items; + _log = logFactory.CreateLog(this); + } + + public async Task StopAsync() + { + try + { + await Task.WhenAll(_stoppables.Select(i => Task.Run(() => i.Stop()))); + + await Task.WhenAll(_items.Select(i => Task.Run(() => i.Stop()))); + } + catch (Exception ex) + { + _log.Warning($"Unable to stop a component", ex); + } + } + } +} diff --git a/src/MAVN.Service.Kyc/Services/StartupManager.cs b/src/MAVN.Service.Kyc/Services/StartupManager.cs new file mode 100644 index 0000000..ed3459d --- /dev/null +++ b/src/MAVN.Service.Kyc/Services/StartupManager.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Lykke.Common; +using Lykke.Sdk; + +namespace MAVN.Service.Kyc.Services +{ + public class StartupManager : IStartupManager + { + private readonly IEnumerable _startables; + + public StartupManager(IEnumerable startables) + { + _startables = startables; + } + + public Task StartAsync() + { + foreach (var startable in _startables) + { + startable.Start(); + } + + return Task.CompletedTask; + } + } +} diff --git a/src/MAVN.Service.Kyc/Settings/AppSettings.cs b/src/MAVN.Service.Kyc/Settings/AppSettings.cs new file mode 100644 index 0000000..4b3c8c8 --- /dev/null +++ b/src/MAVN.Service.Kyc/Settings/AppSettings.cs @@ -0,0 +1,11 @@ +using JetBrains.Annotations; +using Lykke.Sdk.Settings; + +namespace MAVN.Service.Kyc.Settings +{ + [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] + public class AppSettings : BaseAppSettings + { + public KycSettings KycService { get; set; } + } +} diff --git a/src/MAVN.Service.Kyc/Settings/DbSettings.cs b/src/MAVN.Service.Kyc/Settings/DbSettings.cs new file mode 100644 index 0000000..e31f78a --- /dev/null +++ b/src/MAVN.Service.Kyc/Settings/DbSettings.cs @@ -0,0 +1,10 @@ +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.Kyc.Settings +{ + public class DbSettings + { + [AzureTableCheck] + public string LogsConnString { get; set; } + } +} diff --git a/src/MAVN.Service.Kyc/Settings/KycSettings.cs b/src/MAVN.Service.Kyc/Settings/KycSettings.cs new file mode 100644 index 0000000..e89232d --- /dev/null +++ b/src/MAVN.Service.Kyc/Settings/KycSettings.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.Kyc.Settings +{ + [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] + public class KycSettings + { + public DbSettings Db { get; set; } + + public RabbitMqSettings Rabbit { get; set; } + } +} diff --git a/src/MAVN.Service.Kyc/Settings/RabbitMqSettings.cs b/src/MAVN.Service.Kyc/Settings/RabbitMqSettings.cs new file mode 100644 index 0000000..2e6b70c --- /dev/null +++ b/src/MAVN.Service.Kyc/Settings/RabbitMqSettings.cs @@ -0,0 +1,15 @@ +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.Kyc.Settings +{ + public class RabbitMqSettings + { + public RabbitMqExchangeSettings Publishers { get; set; } + } + + public class RabbitMqExchangeSettings + { + [AmqpCheck] + public string ConnectionString { get; set; } + } +} diff --git a/src/MAVN.Service.Kyc/Startup.cs b/src/MAVN.Service.Kyc/Startup.cs new file mode 100644 index 0000000..1f39d86 --- /dev/null +++ b/src/MAVN.Service.Kyc/Startup.cs @@ -0,0 +1,113 @@ +using System; +using Autofac; +using AutoMapper; +using JetBrains.Annotations; +using Lykke.Logs.Loggers.LykkeSlack; +using Lykke.Sdk; +using Lykke.Sdk.Health; +using Lykke.Sdk.Middleware; +using Lykke.SettingsReader; +using MAVN.Service.Kyc.Settings; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.ApplicationInsights.Extensibility; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace MAVN.Service.Kyc +{ + [UsedImplicitly] + public class Startup + { + private IConfigurationRoot _configurationRoot; + private IReloadingManager _settingsManager; + + private readonly LykkeSwaggerOptions _swaggerOptions = new LykkeSwaggerOptions + { + ApiTitle = "Kyc API", + ApiVersion = "v1" + }; + + [UsedImplicitly] + public void ConfigureServices(IServiceCollection services) + { + (_configurationRoot, _settingsManager) = services.BuildServiceProvider(options => + { + options.SwaggerOptions = _swaggerOptions; + + options.Logs = logs => + { + logs.AzureTableName = "KycLog"; + logs.AzureTableConnectionStringResolver = settings => settings.KycService.Db.LogsConnString; + + // TODO: You could add extended logging configuration here: + /* + logs.Extended = extendedLogs => + { + // For example, you could add additional slack channel like this: + extendedLogs.AddAdditionalSlackChannel("Kyc", channelOptions => + { + channelOptions.MinLogLevel = LogLevel.Information; + }); + }; + */ + }; + + options.Extend = (sc, settings) => + { + sc.AddAutoMapper(typeof(AutoMapperProfile)); + /* + sc + .AddOptions() + .AddAuthentication(MyAuthOptions.AuthenticationScheme) + .AddScheme(MyAuthOptions.AuthenticationScheme, null); + */ + }; + + // TODO: You could add extended Swagger configuration here: + /* + options.Swagger = swagger => + { + swagger.IgnoreObsoleteActions(); + }; + */ + }); + } + + [UsedImplicitly] + public void ConfigureContainer(ContainerBuilder builder) + { + builder.ConfigureLykkeContainer( + _configurationRoot, + _settingsManager); + } + + [UsedImplicitly] + public void Configure( + IApplicationBuilder app, + IMapper mapper, + IApplicationLifetime appLifetime) + { + mapper.ConfigurationProvider.AssertConfigurationIsValid(); + + app.UseLykkeConfiguration(appLifetime, options => + { + options.SwaggerOptions = _swaggerOptions; + + // TODO: Configure additional middleware for eg authentication or maintenancemode checks + /* + options.WithMiddleware = x => + { + x.UseMaintenanceMode(settings => new MaintenanceMode + { + Enabled = settings.MaintenanceMode?.Enabled ?? false, + Reason = settings.MaintenanceMode?.Reason + }); + x.UseAuthentication(); + }; + */ + }); + } + } +} diff --git a/tests/MAVN.Service.Kyc.Tests/AutoMapperProfileTests.cs b/tests/MAVN.Service.Kyc.Tests/AutoMapperProfileTests.cs new file mode 100644 index 0000000..191c101 --- /dev/null +++ b/tests/MAVN.Service.Kyc.Tests/AutoMapperProfileTests.cs @@ -0,0 +1,25 @@ +using AutoMapper; +using Xunit; + +namespace MAVN.Service.Kyc.Tests +{ + public class AutoMapperProfileTests + { + [Fact] + public void Mapping_Configuration_Is_Correct() + { + // arrange + + var mockMapper = new MapperConfiguration(cfg => { cfg.AddProfile(new AutoMapperProfile()); }); + var mapper = mockMapper.CreateMapper(); + + // act + + mapper.ConfigurationProvider.AssertConfigurationIsValid(); + + // assert + + Assert.True(true); + } + } +} diff --git a/tests/MAVN.Service.Kyc.Tests/ClientHttpPathsAreMatchedInControllersTest.cs b/tests/MAVN.Service.Kyc.Tests/ClientHttpPathsAreMatchedInControllersTest.cs new file mode 100644 index 0000000..a0ec7e5 --- /dev/null +++ b/tests/MAVN.Service.Kyc.Tests/ClientHttpPathsAreMatchedInControllersTest.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using MAVN.Service.Kyc; +using MAVN.Service.Kyc.Client; +using Microsoft.AspNetCore.Mvc; +using Refit; +using Xunit; + +namespace MAVN.Service.Kyc.Tests +{ + public class ClientHttpPathsAreMatchedInControllersTest + { + private readonly Type _routeAttrType = typeof(RouteAttribute); + private readonly List _refitAttrs = new List + { + typeof(GetAttribute), typeof(PostAttribute), typeof(PutAttribute), typeof(DeleteAttribute), typeof(PatchAttribute) + }; + private readonly List _httpAttrs = new List + { + typeof(HttpGetAttribute), typeof(HttpPostAttribute), typeof(HttpPutAttribute), typeof(HttpDeleteAttribute), typeof(HttpPatchAttribute) + }; + + [Fact] + public void CheckRoutesInControllersTest() + { + var clientInterface = typeof(IKycClient); + + var apiInterfaces = clientInterface + .GetProperties() + .Where(p => p.CanRead && p.PropertyType.IsInterface) + .Select(p => p.PropertyType) + .ToHashSet(); + var controllers = Assembly.GetAssembly(typeof(Startup)) + .GetTypes() + .Where(t => t.IsSubclassOf(typeof(ControllerBase))) + .ToList(); + + var apiErrors = new List(); + + foreach (var apiInterface in apiInterfaces) + { + var implementingController = controllers.FirstOrDefault(c => c.GetInterfaces().Any(i => i == apiInterface)); + var interfaceMethods = apiInterface.GetMethods(); + if (implementingController == null) + { + if (interfaceMethods.Length > 0) + apiErrors.Add($"Api interface '{apiInterface.Name}' is not implemented"); + continue; + } + + foreach (var apiMethod in interfaceMethods) + { + var refitAttr = apiMethod.CustomAttributes.FirstOrDefault(a => _refitAttrs.Any(i => i == a.AttributeType)); + if (refitAttr == null) + { + apiErrors.Add($"Refit attribute is missing on {apiInterface.Name}.{apiMethod.Name}"); + continue; + } + + var apiRoute = refitAttr.ConstructorArguments[0].Value.ToString(); + if (apiRoute.StartsWith('/')) + apiRoute = apiRoute.TrimStart('/'); + else + apiErrors.Add( + $"Route '{apiRoute}' on {apiInterface.Name}.{apiMethod.Name} is missing leading slash"); + + var implMethod = implementingController.GetMethod( + apiMethod.Name, + apiMethod.GetParameters().Select(p => p.ParameterType).ToArray()); + + var routeAttr = implMethod.CustomAttributes.FirstOrDefault(a => a.AttributeType == _routeAttrType); + var httpAttr = implMethod.CustomAttributes.First(a => _httpAttrs.Any(i => i == a.AttributeType)); + var implRoute = string.Empty; + if ((routeAttr ?? httpAttr).ConstructorArguments.Count > 0) + implRoute = (routeAttr ?? httpAttr).ConstructorArguments[0].Value.ToString(); + + var controllerRouteAttr = implementingController.CustomAttributes.FirstOrDefault(a => a.AttributeType == _routeAttrType); + if (controllerRouteAttr != null) + { + var controllerRoute = controllerRouteAttr.ConstructorArguments[0].Value.ToString(); + implRoute = string.IsNullOrWhiteSpace(implRoute) + ? controllerRoute.Trim('/') + : $"{controllerRoute.Trim('/')}/{implRoute}"; + } + + if (apiRoute != implRoute) + apiErrors.Add( + $"Route '{apiRoute}' on {apiInterface.Name}.{apiMethod.Name} is not matched in controller - '{implRoute}'"); + + if (_refitAttrs.IndexOf(refitAttr.AttributeType) != _httpAttrs.IndexOf(httpAttr.AttributeType)) + apiErrors.Add( + $"Refit '{refitAttr.AttributeType.Name}' on {apiInterface.Name}.{apiMethod.Name} is not matched in controller - '{httpAttr.AttributeType.Name}'"); + } + } + + Assert.True(apiErrors.Count == 0, string.Join(",\t", apiErrors)); + } + } +} diff --git a/tests/MAVN.Service.Kyc.Tests/MAVN.Service.Kyc.Tests.csproj b/tests/MAVN.Service.Kyc.Tests/MAVN.Service.Kyc.Tests.csproj new file mode 100644 index 0000000..204d68b --- /dev/null +++ b/tests/MAVN.Service.Kyc.Tests/MAVN.Service.Kyc.Tests.csproj @@ -0,0 +1,17 @@ + + + netcoreapp3.1 + 1.0.0 + + + + + + + + + + + + + diff --git a/tests/MAVN.Service.Kyc.Tests/SensitiveDataTests.cs b/tests/MAVN.Service.Kyc.Tests/SensitiveDataTests.cs new file mode 100644 index 0000000..c5aefe0 --- /dev/null +++ b/tests/MAVN.Service.Kyc.Tests/SensitiveDataTests.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using MAVN.Service.Kyc.Client; +using Refit; +using Xunit; + +namespace MAVN.Service.Kyc.Tests +{ + public class SensitiveDataTests + { + private readonly Type _refitGetAttrType = typeof(GetAttribute); + + private readonly List _sensitiveParamsNames = new List + { + "name", "email", "phone", "login" + }; + + [Fact] + public void CheckSensitiveParamsTest() + { + var clientInterface = typeof(IKycClient); + + var apiInterfaces = clientInterface + .GetProperties() + .Where(p => p.CanRead && p.PropertyType.IsInterface) + .Select(p => p.PropertyType) + .ToHashSet(); + + var sensitiveDataParams = new List(); + + foreach (var apiInterface in apiInterfaces) + { + var interfaceMethods = apiInterface.GetMethods( + BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.DeclaredOnly); + + foreach (var apiMethod in interfaceMethods) + { + var refitGetAttr = apiMethod.CustomAttributes.FirstOrDefault(a => _refitGetAttrType == a.AttributeType); + if (refitGetAttr == null) + continue; + + var methodParams = apiMethod.GetParameters(); + var paramsWithSensitiveData = methodParams.Where(p => _sensitiveParamsNames.Any(s => p.Name.ToLower().Contains(s))); + sensitiveDataParams.AddRange( + paramsWithSensitiveData.Select(i => $"{i.Name} from {apiInterface.Name}.{apiMethod.Name}")); + } + } + + Assert.True( + sensitiveDataParams.Count == 0, + "These parameters might lead to exposing sensitive data when building url via refit: " + string.Join(", ", sensitiveDataParams)); + } + } +}