From e41b92af7b137f8c12f6f0da99568887e4048604 Mon Sep 17 00:00:00 2001 From: Sergey Nesterov Date: Mon, 6 Apr 2020 17:18:22 +0300 Subject: [PATCH] Initial version --- .editorconfig | 84 ++++ .gitattributes | 21 + .github/workflows/build-and-test.yml | 23 ++ .github/workflows/coverage-report.yml | 28 ++ .gitignore | 391 +++--------------- CONTRIBUTING.md | 67 +++ LICENSE | 2 +- MAVN.Service.SmartVouchers.sln | 90 ++++ README.md | 7 +- .../AutofacExtension.cs | 43 ++ .../ISmartVouchersApi.cs | 16 + .../ISmartVouchersClient.cs | 18 + .../MAVN.Service.SmartVouchers.Client.csproj | 34 ++ .../SmartVouchersClient.cs | 21 + .../SmartVouchersServiceClientSettings.cs | 14 + ...MAVN.Service.SmartVouchers.Contract.csproj | 35 ++ .../Readme.md | 3 + settings.yaml | 31 ++ .../MAVN.Service.SmartVouchers.Domain.csproj | 9 + .../Readme.md | 1 + .../Repositories/ISmartVouchersRepository.cs | 12 + .../Repositories/Readme.md | 1 + .../Services/Readme.md | 1 + ...ervice.SmartVouchers.DomainServices.csproj | 14 + .../RabbitSubscribers/RabbitSubscriber.cs | 30 ++ .../RabbitSubscribers/Readme.md | 1 + .../Readme.md | 1 + ...ice.SmartVouchers.MsSqlRepositories.csproj | 21 + .../Repositories/SmartVouchersRepository.cs | 22 + .../SmartVouchersContext.cs | 40 ++ .../AutoMapperProfile.cs | 12 + .../Controllers/SmartVouchersController.cs | 17 + src/MAVN.Service.SmartVouchers/Dockerfile | 4 + .../MAVN.Service.SmartVouchers.csproj | 40 ++ .../Modules/DbModule.cs | 34 ++ .../Modules/RabbitMqModule.cs | 49 +++ .../Modules/ServiceModule.cs | 41 ++ src/MAVN.Service.SmartVouchers/Program.cs | 17 + .../Services/Readme.md | 1 + .../Services/ShutdownManager.cs | 43 ++ .../Services/StartupManager.cs | 27 ++ .../Settings/AppSettings.cs | 11 + .../Settings/DbSettings.cs | 13 + .../Settings/RabbitMqSettings.cs | 16 + .../Settings/SmartVouchersSettings.cs | 13 + src/MAVN.Service.SmartVouchers/Startup.cs | 113 +++++ .../AutoMapperProfileTests.cs | 25 ++ ...entHttpPathsAreMatchedInControllersTest.cs | 101 +++++ .../MAVN.Service.SmartVouchers.Tests.csproj | 20 + .../SensitiveDataTests.cs | 56 +++ 50 files changed, 1393 insertions(+), 341 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/workflows/build-and-test.yml create mode 100644 .github/workflows/coverage-report.yml create mode 100644 CONTRIBUTING.md create mode 100644 MAVN.Service.SmartVouchers.sln create mode 100644 client/MAVN.Service.SmartVouchers.Client/AutofacExtension.cs create mode 100644 client/MAVN.Service.SmartVouchers.Client/ISmartVouchersApi.cs create mode 100644 client/MAVN.Service.SmartVouchers.Client/ISmartVouchersClient.cs create mode 100644 client/MAVN.Service.SmartVouchers.Client/MAVN.Service.SmartVouchers.Client.csproj create mode 100644 client/MAVN.Service.SmartVouchers.Client/SmartVouchersClient.cs create mode 100644 client/MAVN.Service.SmartVouchers.Client/SmartVouchersServiceClientSettings.cs create mode 100644 contract/MAVN.Service.SmartVouchers.Contract/MAVN.Service.SmartVouchers.Contract.csproj create mode 100644 contract/MAVN.Service.SmartVouchers.Contract/Readme.md create mode 100644 settings.yaml create mode 100644 src/MAVN.Service.SmartVouchers.Domain/MAVN.Service.SmartVouchers.Domain.csproj create mode 100644 src/MAVN.Service.SmartVouchers.Domain/Readme.md create mode 100644 src/MAVN.Service.SmartVouchers.Domain/Repositories/ISmartVouchersRepository.cs create mode 100644 src/MAVN.Service.SmartVouchers.Domain/Repositories/Readme.md create mode 100644 src/MAVN.Service.SmartVouchers.Domain/Services/Readme.md create mode 100644 src/MAVN.Service.SmartVouchers.DomainServices/MAVN.Service.SmartVouchers.DomainServices.csproj create mode 100644 src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/RabbitSubscriber.cs create mode 100644 src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/Readme.md create mode 100644 src/MAVN.Service.SmartVouchers.DomainServices/Readme.md create mode 100644 src/MAVN.Service.SmartVouchers.MsSqlRepositories/MAVN.Service.SmartVouchers.MsSqlRepositories.csproj create mode 100644 src/MAVN.Service.SmartVouchers.MsSqlRepositories/Repositories/SmartVouchersRepository.cs create mode 100644 src/MAVN.Service.SmartVouchers.MsSqlRepositories/SmartVouchersContext.cs create mode 100644 src/MAVN.Service.SmartVouchers/AutoMapperProfile.cs create mode 100644 src/MAVN.Service.SmartVouchers/Controllers/SmartVouchersController.cs create mode 100644 src/MAVN.Service.SmartVouchers/Dockerfile create mode 100644 src/MAVN.Service.SmartVouchers/MAVN.Service.SmartVouchers.csproj create mode 100644 src/MAVN.Service.SmartVouchers/Modules/DbModule.cs create mode 100644 src/MAVN.Service.SmartVouchers/Modules/RabbitMqModule.cs create mode 100644 src/MAVN.Service.SmartVouchers/Modules/ServiceModule.cs create mode 100644 src/MAVN.Service.SmartVouchers/Program.cs create mode 100644 src/MAVN.Service.SmartVouchers/Services/Readme.md create mode 100644 src/MAVN.Service.SmartVouchers/Services/ShutdownManager.cs create mode 100644 src/MAVN.Service.SmartVouchers/Services/StartupManager.cs create mode 100644 src/MAVN.Service.SmartVouchers/Settings/AppSettings.cs create mode 100644 src/MAVN.Service.SmartVouchers/Settings/DbSettings.cs create mode 100644 src/MAVN.Service.SmartVouchers/Settings/RabbitMqSettings.cs create mode 100644 src/MAVN.Service.SmartVouchers/Settings/SmartVouchersSettings.cs create mode 100644 src/MAVN.Service.SmartVouchers/Startup.cs create mode 100644 tests/MAVN.Service.SmartVouchers.Tests/AutoMapperProfileTests.cs create mode 100644 tests/MAVN.Service.SmartVouchers.Tests/ClientHttpPathsAreMatchedInControllersTest.cs create mode 100644 tests/MAVN.Service.SmartVouchers.Tests/MAVN.Service.SmartVouchers.Tests.csproj create mode 100644 tests/MAVN.Service.SmartVouchers.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/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000..a8cf5d3 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,23 @@ +name: build and test + +on: + pull_request: + 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: 2.2.207 + - name: Install dependencies + run: dotnet restore + - name: Build + run: dotnet build --configuration Release --no-restore + - name: Test + run: dotnet test --no-restore --verbosity normal diff --git a/.github/workflows/coverage-report.yml b/.github/workflows/coverage-report.yml new file mode 100644 index 0000000..fb8171a --- /dev/null +++ b/.github/workflows/coverage-report.yml @@ -0,0 +1,28 @@ +name: calculate coverage + +on: + 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: 2.2.207 + - 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 + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./tests/MAVN.Service.SmartVouchers.Tests/TestResults/coverage.info diff --git a/.gitignore b/.gitignore index dfcfd56..1504ae4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,350 +1,63 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser +# Global wildcards +*.aps +*.bak +*.dll +*.log +*.ncb +*.obj +*.old +*.opensdf +*.orig +*.pdb +*.Publish.xml +*.sdf +*.sln.cache *.suo +*.tmp *.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ +*.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/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files +[Dd]ebug/ +[Rr]elease/ ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json +# Visual Studio project upgrade +[Bb]ackup/ +UpgradeLog* +_UpgradeReport_Files/ -# Visual Studio code coverage results -*.coverage -*.coveragexml +# Operating Systems generated +.DS_Store +[Dd]esktop.ini +[Tt]humbs.db -# NCrunch +#ncrunch +*.*crunch* _NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted +#publish profiles +*publish.ps1 *.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ +*.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..cfa38bc --- /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.SmartVouchers/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.SmartVouchers.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.SmartVouchers` `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/LICENSE b/LICENSE index 1ea017d..8864d4a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 OpenMAVN +Copyright (c) 2017 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MAVN.Service.SmartVouchers.sln b/MAVN.Service.SmartVouchers.sln new file mode 100644 index 0000000..70867ba --- /dev/null +++ b/MAVN.Service.SmartVouchers.sln @@ -0,0 +1,90 @@ + +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.SmartVouchers.Domain", "src\MAVN.Service.SmartVouchers.Domain\MAVN.Service.SmartVouchers.Domain.csproj", "{F5B2F6B8-A8CC-4612-8F1D-C063EB8C8955}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.SmartVouchers.DomainServices", "src\MAVN.Service.SmartVouchers.DomainServices\MAVN.Service.SmartVouchers.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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MAVN.Service.SmartVouchers.MsSqlRepositories", "src\MAVN.Service.SmartVouchers.MsSqlRepositories\MAVN.Service.SmartVouchers.MsSqlRepositories.csproj", "{D9F540C8-8E7B-47C9-AF5C-E844910FED0A}" +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.SmartVouchers.Contract", "contract\MAVN.Service.SmartVouchers.Contract\MAVN.Service.SmartVouchers.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.SmartVouchers.Client", "client\MAVN.Service.SmartVouchers.Client\MAVN.Service.SmartVouchers.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.SmartVouchers.Tests", "tests\MAVN.Service.SmartVouchers.Tests\MAVN.Service.SmartVouchers.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.SmartVouchers", "src\MAVN.Service.SmartVouchers\MAVN.Service.SmartVouchers.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 + {D9F540C8-8E7B-47C9-AF5C-E844910FED0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9F540C8-8E7B-47C9-AF5C-E844910FED0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9F540C8-8E7B-47C9-AF5C-E844910FED0A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9F540C8-8E7B-47C9-AF5C-E844910FED0A}.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} + {D9F540C8-8E7B-47C9-AF5C-E844910FED0A} = {BF745453-B940-470E-81BC-43FB67703D4E} + {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/README.md b/README.md index f77c76c..df01776 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -# MAVN.Service.SmartVouchers \ No newline at end of file +# MAVN.Service.SmartVouchers + +![calculate coverage](https://github.com/OpenMAVN/MAVN.Service.SmartVouchers/workflows/calculate%20coverage/badge.svg) +[![Coverage Status](https://coveralls.io/repos/github/OpenMAVN/MAVN.Service.SmartVouchers/badge.svg?branch=master)](https://coveralls.io/github/OpenMAVN/MAVN.Service.SmartVouchers?branch=master) + +This service is responsible for the storage and processing of vouchers campaigns. \ No newline at end of file diff --git a/client/MAVN.Service.SmartVouchers.Client/AutofacExtension.cs b/client/MAVN.Service.SmartVouchers.Client/AutofacExtension.cs new file mode 100644 index 0000000..04d4825 --- /dev/null +++ b/client/MAVN.Service.SmartVouchers.Client/AutofacExtension.cs @@ -0,0 +1,43 @@ +using System; +using Autofac; +using JetBrains.Annotations; +using Lykke.HttpClientGenerator; +using Lykke.HttpClientGenerator.Infrastructure; + +namespace MAVN.Service.SmartVouchers.Client +{ + /// + /// Extension for client registration + /// + [PublicAPI] + public static class AutofacExtension + { + /// + /// Registers in Autofac container using . + /// + /// Autofac container builder. + /// SmartVouchers client settings. + /// Optional configure handler. + public static void RegisterSmartVouchersClient( + [NotNull] this ContainerBuilder builder, + [NotNull] SmartVouchersServiceClientSettings 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(SmartVouchersServiceClientSettings.ServiceUrl)); + + var clientBuilder = HttpClientGenerator.BuildForUrl(settings.ServiceUrl) + .WithAdditionalCallsWrapper(new ExceptionHandlerCallsWrapper()); + + clientBuilder = builderConfigure?.Invoke(clientBuilder) ?? clientBuilder.WithoutRetries(); + + builder.RegisterInstance(new SmartVouchersClient(clientBuilder.Create())) + .As() + .SingleInstance(); + } + } +} diff --git a/client/MAVN.Service.SmartVouchers.Client/ISmartVouchersApi.cs b/client/MAVN.Service.SmartVouchers.Client/ISmartVouchersApi.cs new file mode 100644 index 0000000..1acdf40 --- /dev/null +++ b/client/MAVN.Service.SmartVouchers.Client/ISmartVouchersApi.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using Refit; + +namespace MAVN.Service.SmartVouchers.Client +{ + // This is an example of service controller interfaces. + // Actual interface methods must be placed here (not in ISmartVouchersClient interface). + + /// + /// SmartVouchers client API interface. + /// + [PublicAPI] + public interface ISmartVouchersApi + { + } +} diff --git a/client/MAVN.Service.SmartVouchers.Client/ISmartVouchersClient.cs b/client/MAVN.Service.SmartVouchers.Client/ISmartVouchersClient.cs new file mode 100644 index 0000000..69b076d --- /dev/null +++ b/client/MAVN.Service.SmartVouchers.Client/ISmartVouchersClient.cs @@ -0,0 +1,18 @@ +using JetBrains.Annotations; + +namespace MAVN.Service.SmartVouchers.Client +{ + /// + /// SmartVouchers client interface. + /// + [PublicAPI] + public interface ISmartVouchersClient + { + // 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 - ISmartVouchersApi). + // ONLY properties for accessing controller interfaces are allowed. + + /// Application Api interface + ISmartVouchersApi Api { get; } + } +} diff --git a/client/MAVN.Service.SmartVouchers.Client/MAVN.Service.SmartVouchers.Client.csproj b/client/MAVN.Service.SmartVouchers.Client/MAVN.Service.SmartVouchers.Client.csproj new file mode 100644 index 0000000..a8ca0a5 --- /dev/null +++ b/client/MAVN.Service.SmartVouchers.Client/MAVN.Service.SmartVouchers.Client.csproj @@ -0,0 +1,34 @@ + + + netstandard2.0 + 1.0.1 + Lykke + LykkeBisiness + Lykke.Service.SmartVouchers + Client for Lykke.Service.SmartVouchers API + https://github.com/LykkeBusinessPlatform/Lykke.Service.SmartVouchers/blob/master/LICENSE + https://github.com/LykkeBusinessPlatform/Lykke.Service.SmartVouchers + https://avatars3.githubusercontent.com/u/14153330?v=3&s=200 + https://github.com/LykkeBusinessPlatform/Lykke.Service.SmartVouchers.git + git + LykkeBiz;SmartVouchers + LykkeBiz.Service.SmartVouchers + + + $(OutputPath)$(AssemblyName).xml + + + $(OutputPath)$(AssemblyName).xml + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/MAVN.Service.SmartVouchers.Client/SmartVouchersClient.cs b/client/MAVN.Service.SmartVouchers.Client/SmartVouchersClient.cs new file mode 100644 index 0000000..8638712 --- /dev/null +++ b/client/MAVN.Service.SmartVouchers.Client/SmartVouchersClient.cs @@ -0,0 +1,21 @@ +using Lykke.HttpClientGenerator; + +namespace MAVN.Service.SmartVouchers.Client +{ + /// + /// SmartVouchers API aggregating interface. + /// + public class SmartVouchersClient : ISmartVouchersClient + { + // Note: Add similar Api properties for each new service controller + + /// Inerface to SmartVouchers Api. + public ISmartVouchersApi Api { get; private set; } + + /// C-tor + public SmartVouchersClient(IHttpClientGenerator httpClientGenerator) + { + Api = httpClientGenerator.Generate(); + } + } +} diff --git a/client/MAVN.Service.SmartVouchers.Client/SmartVouchersServiceClientSettings.cs b/client/MAVN.Service.SmartVouchers.Client/SmartVouchersServiceClientSettings.cs new file mode 100644 index 0000000..574a2c4 --- /dev/null +++ b/client/MAVN.Service.SmartVouchers.Client/SmartVouchersServiceClientSettings.cs @@ -0,0 +1,14 @@ +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.SmartVouchers.Client +{ + /// + /// SmartVouchers client settings. + /// + public class SmartVouchersServiceClientSettings + { + /// Service url. + [HttpCheck("api/isalive")] + public string ServiceUrl {get; set;} + } +} diff --git a/contract/MAVN.Service.SmartVouchers.Contract/MAVN.Service.SmartVouchers.Contract.csproj b/contract/MAVN.Service.SmartVouchers.Contract/MAVN.Service.SmartVouchers.Contract.csproj new file mode 100644 index 0000000..db5c50c --- /dev/null +++ b/contract/MAVN.Service.SmartVouchers.Contract/MAVN.Service.SmartVouchers.Contract.csproj @@ -0,0 +1,35 @@ + + + + netstandard2.0 + 1.0.1 + Lykke + LykkeBisiness + Contract for the Lykke.Service.SmartVouchers + https://github.com/LykkeBusinessPlatform/Lykke.Service.SmartVouchers/blob/master/LICENSE + https://github.com/LykkeBusinessPlatform/Lykke.Service.SmartVouchers + https://avatars3.githubusercontent.com/u/14153330?v=3&s=200 + https://github.com/LykkeBusinessPlatform/Lykke.Service.SmartVouchers.git + git + LykkeBiz;SmartVouchers + LykkeBiz.Service.SmartVouchers.Contract + + + + bin\Debug\netstandard2.0\Lykke.Service.SmartVouchers.Contract.xml + 1701;1702;1705;1591 + + + + bin\Release\netstandard2.0\Lykke.Service.SmartVouchers.Contract.xml + 1701;1702;1705;1591 + + + + + true + lib/netstandard2.0 + + + + diff --git a/contract/MAVN.Service.SmartVouchers.Contract/Readme.md b/contract/MAVN.Service.SmartVouchers.Contract/Readme.md new file mode 100644 index 0000000..3557f2b --- /dev/null +++ b/contract/MAVN.Service.SmartVouchers.Contract/Readme.md @@ -0,0 +1,3 @@ +# Place outgoing message's models here +# Deploy this assembly as nuget package Lykke.Service.SmartVouchers.Contract +# Use published nuget package in service's clients diff --git a/settings.yaml b/settings.yaml new file mode 100644 index 0000000..10ee243 --- /dev/null +++ b/settings.yaml @@ -0,0 +1,31 @@ +SmartVouchersService: + Db: + LogsConnString: + settings-key: SmartVouchersService-LogsConnString + types: + - AzureTableStorage + SqlDbConnString: + settings-key: SmartVouchersService-SqlDbConnString + Rabbit: + Publishers: + ConnectionString: + settings-key: Pub-ConnectionString + types: + - RabbitMq + Subscribers: + ConnectionString: + settings-key: Sub-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.SmartVouchers.Domain/MAVN.Service.SmartVouchers.Domain.csproj b/src/MAVN.Service.SmartVouchers.Domain/MAVN.Service.SmartVouchers.Domain.csproj new file mode 100644 index 0000000..3ea3310 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.Domain/MAVN.Service.SmartVouchers.Domain.csproj @@ -0,0 +1,9 @@ + + + netcoreapp3.1 + 1.0.0 + + + + + diff --git a/src/MAVN.Service.SmartVouchers.Domain/Readme.md b/src/MAVN.Service.SmartVouchers.Domain/Readme.md new file mode 100644 index 0000000..6d38761 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.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.SmartVouchers.Domain/Repositories/ISmartVouchersRepository.cs b/src/MAVN.Service.SmartVouchers.Domain/Repositories/ISmartVouchersRepository.cs new file mode 100644 index 0000000..278f8f4 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.Domain/Repositories/ISmartVouchersRepository.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using MAVN.Service.SmartVouchers.Domain; + +namespace MAVN.Service.SmartVouchers.Domain.Repositories +{ + public interface ISmartVouchersRepository + { + + } +} diff --git a/src/MAVN.Service.SmartVouchers.Domain/Repositories/Readme.md b/src/MAVN.Service.SmartVouchers.Domain/Repositories/Readme.md new file mode 100644 index 0000000..2b35371 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.Domain/Repositories/Readme.md @@ -0,0 +1 @@ +Place repository interfaces here \ No newline at end of file diff --git a/src/MAVN.Service.SmartVouchers.Domain/Services/Readme.md b/src/MAVN.Service.SmartVouchers.Domain/Services/Readme.md new file mode 100644 index 0000000..ac13c02 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.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.SmartVouchers.DomainServices/MAVN.Service.SmartVouchers.DomainServices.csproj b/src/MAVN.Service.SmartVouchers.DomainServices/MAVN.Service.SmartVouchers.DomainServices.csproj new file mode 100644 index 0000000..e2f3a8f --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.DomainServices/MAVN.Service.SmartVouchers.DomainServices.csproj @@ -0,0 +1,14 @@ + + + netcoreapp3.1 + 1.0.0 + + + + + + + + + + diff --git a/src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/RabbitSubscriber.cs b/src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/RabbitSubscriber.cs new file mode 100644 index 0000000..a4ec14f --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/RabbitSubscriber.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Common.Log; +using Lykke.Common.Log; +using Lykke.RabbitMqBroker.Subscriber; + +namespace MAVN.Service.SmartVouchers.DomainServices.RabbitSubscribers +{ + // TODO replace object with required message type + public class RabbitSubscriber : JsonRabbitSubscriber + { + private readonly ILog _log; + + public RabbitSubscriber( + string connectionString, + string exchangeName, + string queueName, + ILogFactory logFactory) + : base(connectionString, exchangeName, queueName, logFactory) + { + _log = logFactory.CreateLog(this); + } + + protected override async Task ProcessMessageAsync(object message) + { + await Task.CompletedTask; // TODO replace this with proper message handling + + _log.Info($"Handled {typeof(object).Name}", message); + } + } +} diff --git a/src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/Readme.md b/src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/Readme.md new file mode 100644 index 0000000..fa85912 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.DomainServices/RabbitSubscribers/Readme.md @@ -0,0 +1 @@ +Place your rabbitmq subscribers here \ No newline at end of file diff --git a/src/MAVN.Service.SmartVouchers.DomainServices/Readme.md b/src/MAVN.Service.SmartVouchers.DomainServices/Readme.md new file mode 100644 index 0000000..77cdada --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.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.SmartVouchers.MsSqlRepositories/MAVN.Service.SmartVouchers.MsSqlRepositories.csproj b/src/MAVN.Service.SmartVouchers.MsSqlRepositories/MAVN.Service.SmartVouchers.MsSqlRepositories.csproj new file mode 100644 index 0000000..d7342a0 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.MsSqlRepositories/MAVN.Service.SmartVouchers.MsSqlRepositories.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.1 + 1.0.0 + + + + + + + + + + + + + + + + diff --git a/src/MAVN.Service.SmartVouchers.MsSqlRepositories/Repositories/SmartVouchersRepository.cs b/src/MAVN.Service.SmartVouchers.MsSqlRepositories/Repositories/SmartVouchersRepository.cs new file mode 100644 index 0000000..82c7194 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.MsSqlRepositories/Repositories/SmartVouchersRepository.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Lykke.Common.MsSql; +using MAVN.Service.SmartVouchers.Domain.Repositories; +using Microsoft.EntityFrameworkCore; + +namespace MAVN.Service.SmartVouchers.MsSqlRepositories.Repositories +{ + public class SmartVouchersRepository : ISmartVouchersRepository + { + private readonly IDbContextFactory _contextFactory; + + public SmartVouchersRepository(IDbContextFactory contextFactory) + { + _contextFactory = contextFactory; + } + + + } +} diff --git a/src/MAVN.Service.SmartVouchers.MsSqlRepositories/SmartVouchersContext.cs b/src/MAVN.Service.SmartVouchers.MsSqlRepositories/SmartVouchersContext.cs new file mode 100644 index 0000000..590f570 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers.MsSqlRepositories/SmartVouchersContext.cs @@ -0,0 +1,40 @@ +using System.Data.Common; +using JetBrains.Annotations; +using Lykke.Common.MsSql; +using Microsoft.EntityFrameworkCore; + +namespace MAVN.Service.SmartVouchers.MsSqlRepositories +{ + public class SmartVouchersContext : MsSqlContext + { + private const string Schema = "smart_vouchers"; + + // empty constructor needed for EF migrations + [UsedImplicitly] + public SmartVouchersContext() + : base(Schema) + { + } + + public SmartVouchersContext(string connectionString, bool isTraceEnabled) + : base(Schema, connectionString, isTraceEnabled) + { + } + + //Needed constructor for using InMemoryDatabase for tests + public SmartVouchersContext(DbContextOptions options) + : base(Schema, options) + { + } + + public SmartVouchersContext(DbConnection dbConnection) + : base(Schema, dbConnection) + { + } + + protected override void OnLykkeModelCreating(ModelBuilder modelBuilder) + { + // TODO put db entities models building code here + } + } +} diff --git a/src/MAVN.Service.SmartVouchers/AutoMapperProfile.cs b/src/MAVN.Service.SmartVouchers/AutoMapperProfile.cs new file mode 100644 index 0000000..2a1ceed --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/AutoMapperProfile.cs @@ -0,0 +1,12 @@ +using AutoMapper; + +namespace MAVN.Service.SmartVouchers +{ + public class AutoMapperProfile : Profile + { + public AutoMapperProfile() + { + // TODO - add mappings here... + } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Controllers/SmartVouchersController.cs b/src/MAVN.Service.SmartVouchers/Controllers/SmartVouchersController.cs new file mode 100644 index 0000000..b5291ba --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Controllers/SmartVouchersController.cs @@ -0,0 +1,17 @@ +using AutoMapper; +using MAVN.Service.SmartVouchers.Client; +using Microsoft.AspNetCore.Mvc; + +namespace MAVN.Service.SmartVouchers.Controllers +{ + [Route("api/SmartVouchers")] // TODO fix route + public class SmartVouchersController : Controller, ISmartVouchersApi + { + private readonly IMapper _mapper; + + public SmartVouchersController(IMapper mapper) + { + _mapper = mapper; + } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Dockerfile b/src/MAVN.Service.SmartVouchers/Dockerfile new file mode 100644 index 0000000..7840f5c --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Dockerfile @@ -0,0 +1,4 @@ +FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 +WORKDIR /app +COPY . . +ENTRYPOINT ["dotnet", "Lykke.Service.SmartVouchers.dll"] diff --git a/src/MAVN.Service.SmartVouchers/MAVN.Service.SmartVouchers.csproj b/src/MAVN.Service.SmartVouchers/MAVN.Service.SmartVouchers.csproj new file mode 100644 index 0000000..7e7cd85 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/MAVN.Service.SmartVouchers.csproj @@ -0,0 +1,40 @@ + + + netcoreapp3.1 + Exe + 1.0.1 + OutOfProcess + AspNetCoreModuleV2 + latest + + + 1701;1702;1705;1591 + + + 1701;1702;1705;1591 + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + diff --git a/src/MAVN.Service.SmartVouchers/Modules/DbModule.cs b/src/MAVN.Service.SmartVouchers/Modules/DbModule.cs new file mode 100644 index 0000000..bddd33c --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Modules/DbModule.cs @@ -0,0 +1,34 @@ +using Autofac; +using JetBrains.Annotations; +using Lykke.Common.MsSql; +using MAVN.Service.SmartVouchers.Domain.Repositories; +using MAVN.Service.SmartVouchers.MsSqlRepositories; +using MAVN.Service.SmartVouchers.MsSqlRepositories.Repositories; +using MAVN.Service.SmartVouchers.Settings; +using Lykke.SettingsReader; + +namespace MAVN.Service.SmartVouchers.Modules +{ + [UsedImplicitly] + public class DbModule : Module + { + private readonly string _connectionString; + + public DbModule(IReloadingManager appSettings) + { + _connectionString = appSettings.CurrentValue.SmartVouchersService.Db.SqlDbConnString; + } + + protected override void Load(ContainerBuilder builder) + { + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterMsSql( + _connectionString, + connString => new SmartVouchersContext(connString, false), + dbConn => new SmartVouchersContext(dbConn)); + } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Modules/RabbitMqModule.cs b/src/MAVN.Service.SmartVouchers/Modules/RabbitMqModule.cs new file mode 100644 index 0000000..8763447 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Modules/RabbitMqModule.cs @@ -0,0 +1,49 @@ +using Autofac; +using JetBrains.Annotations; +using MAVN.Service.SmartVouchers.DomainServices.RabbitSubscribers; +using MAVN.Service.SmartVouchers.Settings; +using Lykke.RabbitMqBroker.Publisher; +using Lykke.RabbitMqBroker.Subscriber; +using Lykke.SettingsReader; + +namespace MAVN.Service.SmartVouchers.Modules +{ + [UsedImplicitly] + public class RabbitMqModule : Module + { + private const string PubExchangeName = "REPLACE THIS WITH PROPER EXCHANGE NAME"; // TODO pass proper exchange name + private const string SubExchangeName = "REPLACE THIS WITH PROPER EXCHANGE NAME"; // TODO pass proper exchange name + + private readonly RabbitMqSettings _settings; + + public RabbitMqModule(IReloadingManager settingsManager) + { + _settings = settingsManager.CurrentValue.SmartVouchersService.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); + + RegisterRabbitMqSubscribers(builder); + } + + // registered publishers could be esolved by IRabbitPublisher interface + private void RegisterRabbitMqPublishers(ContainerBuilder builder) + { + //builder.RegisterJsonRabbitPublisher( + // _settings.Publishers.ConnectionString, + // PubExchangeName); + } + + private void RegisterRabbitMqSubscribers(ContainerBuilder builder) + { + //builder.RegisterJsonRabbitSubscriber( // TODO replace object with proper message type + // _settings.Subscribers.ConnectionString, + // SubExchangeName, + // nameof(SmartVouchers).ToLower()); // this could be changed if needed + } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Modules/ServiceModule.cs b/src/MAVN.Service.SmartVouchers/Modules/ServiceModule.cs new file mode 100644 index 0000000..570a257 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Modules/ServiceModule.cs @@ -0,0 +1,41 @@ +using Autofac; +using JetBrains.Annotations; +using Lykke.Sdk; +using Lykke.Sdk.Health; +using MAVN.Service.SmartVouchers.Services; +using MAVN.Service.SmartVouchers.Settings; +using Lykke.SettingsReader; + +namespace MAVN.Service.SmartVouchers.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.SmartVouchers/Program.cs b/src/MAVN.Service.SmartVouchers/Program.cs new file mode 100644 index 0000000..138be82 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Program.cs @@ -0,0 +1,17 @@ +using Lykke.Sdk; +using System.Threading.Tasks; + +namespace MAVN.Service.SmartVouchers +{ + 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.SmartVouchers/Services/Readme.md b/src/MAVN.Service.SmartVouchers/Services/Readme.md new file mode 100644 index 0000000..fdd3f09 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Services/Readme.md @@ -0,0 +1 @@ +Place application services here diff --git a/src/MAVN.Service.SmartVouchers/Services/ShutdownManager.cs b/src/MAVN.Service.SmartVouchers/Services/ShutdownManager.cs new file mode 100644 index 0000000..baaa2b7 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/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.SmartVouchers.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.SmartVouchers/Services/StartupManager.cs b/src/MAVN.Service.SmartVouchers/Services/StartupManager.cs new file mode 100644 index 0000000..e791874 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Services/StartupManager.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Lykke.Common; +using Lykke.Sdk; + +namespace MAVN.Service.SmartVouchers.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.SmartVouchers/Settings/AppSettings.cs b/src/MAVN.Service.SmartVouchers/Settings/AppSettings.cs new file mode 100644 index 0000000..adff36e --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Settings/AppSettings.cs @@ -0,0 +1,11 @@ +using JetBrains.Annotations; +using Lykke.Sdk.Settings; + +namespace MAVN.Service.SmartVouchers.Settings +{ + [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] + public class AppSettings : BaseAppSettings + { + public SmartVouchersSettings SmartVouchersService { get; set; } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Settings/DbSettings.cs b/src/MAVN.Service.SmartVouchers/Settings/DbSettings.cs new file mode 100644 index 0000000..5da8c70 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Settings/DbSettings.cs @@ -0,0 +1,13 @@ +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.SmartVouchers.Settings +{ + public class DbSettings + { + [AzureTableCheck] + public string LogsConnString { get; set; } + + [SqlCheck] + public string SqlDbConnString { get; set; } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Settings/RabbitMqSettings.cs b/src/MAVN.Service.SmartVouchers/Settings/RabbitMqSettings.cs new file mode 100644 index 0000000..4070cd7 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Settings/RabbitMqSettings.cs @@ -0,0 +1,16 @@ +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.SmartVouchers.Settings +{ + public class RabbitMqSettings + { + public RabbitMqExchangeSettings Subscribers { get; set; } + public RabbitMqExchangeSettings Publishers { get; set; } + } + + public class RabbitMqExchangeSettings + { + [AmqpCheck] + public string ConnectionString { get; set; } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Settings/SmartVouchersSettings.cs b/src/MAVN.Service.SmartVouchers/Settings/SmartVouchersSettings.cs new file mode 100644 index 0000000..7af3789 --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/Settings/SmartVouchersSettings.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using Lykke.SettingsReader.Attributes; + +namespace MAVN.Service.SmartVouchers.Settings +{ + [UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] + public class SmartVouchersSettings + { + public DbSettings Db { get; set; } + + public RabbitMqSettings Rabbit { get; set; } + } +} diff --git a/src/MAVN.Service.SmartVouchers/Startup.cs b/src/MAVN.Service.SmartVouchers/Startup.cs new file mode 100644 index 0000000..626bafb --- /dev/null +++ b/src/MAVN.Service.SmartVouchers/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 MAVN.Service.SmartVouchers.Settings; +using Lykke.SettingsReader; +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.SmartVouchers +{ + [UsedImplicitly] + public class Startup + { + private IConfigurationRoot _configurationRoot; + private IReloadingManager _settingsManager; + + private readonly LykkeSwaggerOptions _swaggerOptions = new LykkeSwaggerOptions + { + ApiTitle = "SmartVouchers API", + ApiVersion = "v1" + }; + + [UsedImplicitly] + public void ConfigureServices(IServiceCollection services) + { + (_configurationRoot, _settingsManager) = services.BuildServiceProvider(options => + { + options.SwaggerOptions = _swaggerOptions; + + options.Logs = logs => + { + logs.AzureTableName = "SmartVouchersLog"; + logs.AzureTableConnectionStringResolver = settings => settings.SmartVouchersService.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("SmartVouchers", 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.SmartVouchers.Tests/AutoMapperProfileTests.cs b/tests/MAVN.Service.SmartVouchers.Tests/AutoMapperProfileTests.cs new file mode 100644 index 0000000..e227f65 --- /dev/null +++ b/tests/MAVN.Service.SmartVouchers.Tests/AutoMapperProfileTests.cs @@ -0,0 +1,25 @@ +using AutoMapper; +using Xunit; + +namespace MAVN.Service.SmartVouchers.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.SmartVouchers.Tests/ClientHttpPathsAreMatchedInControllersTest.cs b/tests/MAVN.Service.SmartVouchers.Tests/ClientHttpPathsAreMatchedInControllersTest.cs new file mode 100644 index 0000000..644f327 --- /dev/null +++ b/tests/MAVN.Service.SmartVouchers.Tests/ClientHttpPathsAreMatchedInControllersTest.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using MAVN.Service.SmartVouchers; +using MAVN.Service.SmartVouchers.Client; +using Microsoft.AspNetCore.Mvc; +using Refit; +using Xunit; + +namespace MAVN.Service.SmartVouchers.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(ISmartVouchersClient); + + 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.TrimStart('/')}"; + } + + 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.SmartVouchers.Tests/MAVN.Service.SmartVouchers.Tests.csproj b/tests/MAVN.Service.SmartVouchers.Tests/MAVN.Service.SmartVouchers.Tests.csproj new file mode 100644 index 0000000..b7f5157 --- /dev/null +++ b/tests/MAVN.Service.SmartVouchers.Tests/MAVN.Service.SmartVouchers.Tests.csproj @@ -0,0 +1,20 @@ + + + netcoreapp3.1 + 1.0.0 + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + diff --git a/tests/MAVN.Service.SmartVouchers.Tests/SensitiveDataTests.cs b/tests/MAVN.Service.SmartVouchers.Tests/SensitiveDataTests.cs new file mode 100644 index 0000000..dc5cd37 --- /dev/null +++ b/tests/MAVN.Service.SmartVouchers.Tests/SensitiveDataTests.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using MAVN.Service.SmartVouchers.Client; +using Refit; +using Xunit; + +namespace MAVN.Service.SmartVouchers.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(ISmartVouchersClient); + + 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)); + } + } +}