├── .gitattributes
├── .github
└── workflows
│ ├── main.yml
│ ├── pr.yml
│ └── release.yml
├── .gitignore
├── Abp.Push.sln
├── LICENSE
├── NuGet.Config
├── build.cake
├── build.ps1
├── common.props
├── nupkg
└── pack.ps1
├── readme.md
├── src
├── Abp.Push.Common
│ ├── Abp.Push.Common.csproj
│ ├── Abp.Push.Common.nuspec
│ └── Push
│ │ ├── AbpPushCommonModule.cs
│ │ ├── AbpPushConsts.cs
│ │ ├── AbpPushSettingNames.cs
│ │ ├── AbpPushSettingProvider.cs
│ │ ├── Configuration
│ │ ├── AbpPushConfiguration.cs
│ │ ├── AbpPushDeviceStoreConfiguration.cs
│ │ ├── AbpPushModuleConfigurationExtensions.cs
│ │ ├── AbpPushRequestStoreConfiguration.cs
│ │ ├── AbpPushStoreConfiguration.cs
│ │ ├── IAbpPushConfiguration.cs
│ │ ├── IAbpPushDeviceStoreConfiguration.cs
│ │ ├── IAbpPushRequestStoreConfiguration.cs
│ │ └── IAbpPushStoreConfiguration.cs
│ │ ├── Devices
│ │ ├── AbpPushDevice.cs
│ │ ├── AbpPushDeviceManager.cs
│ │ ├── AbpPushDeviceManagerExtensions.cs
│ │ ├── DeviceIdentifier.cs
│ │ ├── DeviceIdentifierExtensions.cs
│ │ ├── DevicePlatformInfo.cs
│ │ ├── IDeviceIdentifier.cs
│ │ ├── IHasDeviceInfo.cs
│ │ ├── IPushDeviceStore.cs
│ │ ├── PushDeviceData.cs
│ │ ├── PushDeviceExtensions.cs
│ │ └── PushDeviceInfo.cs
│ │ ├── IPushDefinition.cs
│ │ ├── IPushDefinitionContext.cs
│ │ ├── IPushDefinitionManager.cs
│ │ ├── Localization
│ │ ├── AbpPush.xml
│ │ └── AbpPushLocalizationConfigurer.cs
│ │ ├── Providers
│ │ ├── AbpPushProviderManager.cs
│ │ ├── IPushApiClient.cs
│ │ ├── IPushProviderManager.cs
│ │ ├── IPushServiceProvider.cs
│ │ ├── PushApiClientBase.cs
│ │ ├── PushPayload.cs
│ │ ├── PushServiceProviderBase.cs
│ │ └── ServiceProviderInfo.cs
│ │ ├── PushDefinition.cs
│ │ ├── PushDefinitionContext.cs
│ │ ├── PushDefinitionManager.cs
│ │ ├── PushDefinitionManagerExtensions.cs
│ │ ├── PushDefinitionProvider.cs
│ │ └── Requests
│ │ ├── AbpPushRequestDistributor.cs
│ │ ├── AbpPushRequestPublisher.cs
│ │ ├── AbpPushRequestSubscriptionManager.cs
│ │ ├── IPushRequestDistributor.cs
│ │ ├── IPushRequestPublisher.cs
│ │ ├── IPushRequestStore.cs
│ │ ├── IPushRequestSubscriptionManager.cs
│ │ ├── NullPushRequestStore.cs
│ │ ├── PushRequest.cs
│ │ ├── PushRequestData.cs
│ │ ├── PushRequestDistributionJob.cs
│ │ ├── PushRequestDistributionJobArgs.cs
│ │ ├── PushRequestEntityData.cs
│ │ ├── PushRequestPriority.cs
│ │ ├── PushRequestPublisherExtensions.cs
│ │ ├── PushRequestSubscription.cs
│ │ └── PushRequestSubscriptionManagerExtensions.cs
├── Abp.Push.EntityFrameworkCore
│ ├── Abp.Push.EntityFrameworkCore.csproj
│ ├── Abp.Push.EntityFrameworkCore.nuspec
│ └── Push
│ │ └── EntityFrameworkCore
│ │ ├── AbpPushEntityFrameworkCoreConfigurationExtensions.cs
│ │ ├── AbpPushEntityFrameworkCoreModule.cs
│ │ └── IAbpPushDbContext.cs
└── Abp.Push
│ ├── Abp.Push.csproj
│ ├── Abp.Push.nuspec
│ └── Push
│ ├── AbpPushModule.cs
│ ├── Configuration
│ └── AbpPushModuleConfigurationExtensions.cs
│ ├── Devices
│ └── AbpPersistentPushDeviceStore.cs
│ └── Requests
│ ├── AbpInMemoryPushRequestStore.cs
│ └── AbpPersistentPushRequestStore.cs
├── test
└── Abp.Push.Tests
│ ├── Abp.Push.Tests.csproj
│ ├── Push
│ ├── PushRequestDistributor_Tests.cs
│ └── PushRequestPublisher_Tests.cs
│ └── TestBaseWithLocalIocManager.cs
└── tools
├── gitlink
└── GitLink.exe
└── nuget
└── nuget.exe
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Main tests
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 15
11 | steps:
12 | - uses: actions/checkout@v2
13 | - name: Setup .NET
14 | uses: actions/setup-dotnet@v1
15 | with:
16 | dotnet-version: 5.0.x
17 | - name: Restore dependencies
18 | run: dotnet restore
19 | - name: Build
20 | run: dotnet build --no-restore
21 | - name: Test
22 | run: dotnet test --no-build --verbosity normal
23 |
--------------------------------------------------------------------------------
/.github/workflows/pr.yml:
--------------------------------------------------------------------------------
1 | name: PR Tests
2 |
3 | on:
4 | pull_request:
5 | branches: [ main ]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | timeout-minutes: 15
11 | steps:
12 | - uses: actions/checkout@v2
13 | - name: Setup .NET
14 | uses: actions/setup-dotnet@v1
15 | with:
16 | dotnet-version: 5.0.x
17 | - name: Restore dependencies
18 | run: dotnet restore
19 | - name: Build
20 | run: dotnet build --no-restore
21 | - name: Test
22 | run: dotnet test --no-build --verbosity normal
23 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Nuget Releases
2 |
3 | on:
4 | push:
5 | tags:
6 | - "v[0-9]+.[0-9]+.[0-9]+"
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | timeout-minutes: 15
12 | steps:
13 | - name: Checkout from git
14 | uses: actions/checkout@v2
15 | - name: Verify commit exists in origin/main
16 | run: |
17 | git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/*
18 | git branch --remote --contains | grep origin/main
19 | - name: Set VERSION variable from tag
20 | run: echo "VERSION=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_ENV
21 | - name: Setup .NET
22 | uses: actions/setup-dotnet@v1
23 | with:
24 | dotnet-version: 5.0.x
25 | - name: Restore dependencies
26 | run: dotnet restore
27 | - name: Build
28 | run: dotnet build --configuration Release /p:Version=${VERSION}
29 | - name: Test
30 | run: dotnet test --configuration Release /p:Version=${VERSION} --no-build
31 | - name: Pack
32 | run: dotnet pack --configuration Release /p:Version=${VERSION} --no-build --output .
33 | - name: Push
34 | run: |
35 | dotnet nuget push src/Abp.Push.Common/Abp.Push.Common.nupkg --source https://nuget.pkg.github.com/acraven/index.json --api-key ${GITHUB_TOKEN}
36 | dotnet nuget push src/Abp.Push/Abp.Push.nupkg --source https://nuget.pkg.github.com/acraven/index.json --api-key ${GITHUB_TOKEN}
37 | dotnet nuget push src/Abp.Push.EntityFrameworkCore/Abp.Push.EntityFrameworkCore.nupkg --source https://nuget.pkg.github.com/acraven/index.json --api-key ${GITHUB_TOKEN}
38 | env:
39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # Logs
6 | Logs/
7 |
8 | # Generated files
9 | project.lock.json
10 | .vs/
11 |
12 | # Nuget packages
13 | nupkg/*.nupkg
14 | nupkg/push.bat
15 |
16 | # Profile images
17 | ProfileImages/
18 |
19 | # mstest test results
20 | TestResults
21 |
22 | ## Ignore Visual Studio temporary files, build results, and
23 | ## files generated by popular Visual Studio add-ons.
24 |
25 | # User-specific files
26 | *.suo
27 | *.user
28 | *.sln.docstates
29 |
30 | # Build results
31 | [Dd]ebug/
32 | [Rr]elease/
33 | x64/
34 | *_i.c
35 | *_p.c
36 | *.ilk
37 | *.meta
38 | *.obj
39 | *.pch
40 | *.pdb
41 | *.pgc
42 | *.pgd
43 | *.rsp
44 | *.sbr
45 | *.tlb
46 | *.tli
47 | *.tlh
48 | *.tmp
49 | *.log
50 | *.vspscc
51 | *.vssscc
52 | .builds
53 |
54 | # Visual C++ cache files
55 | ipch/
56 | *.aps
57 | *.ncb
58 | *.opensdf
59 | *.sdf
60 |
61 | # Visual Studio profiler
62 | *.psess
63 | *.vsp
64 | *.vspx
65 |
66 | # JetBrain
67 | .idea/
68 |
69 | # Guidance Automation Toolkit
70 | *.gpState
71 |
72 | # ReSharper is a .NET coding add-in
73 | _ReSharper*
74 |
75 | # NCrunch
76 | *.ncrunch*
77 | .*crunch*.local.xml
78 |
79 | # Installshield output folder
80 | [Ee]xpress
81 |
82 | # DocProject is a documentation generator add-in
83 | DocProject/buildhelp/
84 | DocProject/Help/*.HxT
85 | DocProject/Help/*.HxC
86 | DocProject/Help/*.hhc
87 | DocProject/Help/*.hhk
88 | DocProject/Help/*.hhp
89 | DocProject/Help/Html2
90 | DocProject/Help/html
91 |
92 | # Click-Once directory
93 | publish
94 |
95 | # Publish Web Output
96 | *.Publish.xml
97 |
98 | # NuGet Packages Directory
99 | packages
100 |
101 | # Windows Azure Build Output
102 | csx
103 | *.build.csdef
104 |
105 | # Windows Store app package directory
106 | AppPackages/
107 |
108 | # Others
109 | [Bb]in
110 | [Oo]bj
111 | sql
112 | TestResults
113 | [Tt]est[Rr]esult*
114 | *.Cache
115 | ClientBin
116 | [Ss]tyle[Cc]op.*
117 | ~$*
118 | *.dbmdl
119 | Generated_Code #added for RIA/Silverlight projects
120 |
121 | # Backup & report files from converting an old project file to a newer
122 | # Visual Studio version. Backup files are not needed, because we have git ;-)
123 | _UpgradeReport_Files/
124 | Backup*/
125 | UpgradeLog*.XML
126 | src/.vs/config/applicationhost.config
127 |
128 | # GitLink
129 | !GitLink.exe
130 | !nuget.exe
131 | !SQLite.Interop.dll
132 |
--------------------------------------------------------------------------------
/Abp.Push.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27130.2010
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{CDCAEAFD-A61C-4525-98F5-E8F7227FE7B3}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0ACDB552-6577-497F-8DC5-F38941B5D395}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abp.Push.Common", "src\Abp.Push.Common\Abp.Push.Common.csproj", "{B4F6E73F-D573-461C-A4A6-8F838C50859F}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abp.Push", "src\Abp.Push\Abp.Push.csproj", "{62081BD6-0FAF-4EF1-BCE4-619AC948C7AF}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution-items", "solution-items", "{0A8896A1-EC2E-44D8-BD7E-34D2E46A16CF}"
15 | ProjectSection(SolutionItems) = preProject
16 | .gitattributes = .gitattributes
17 | .gitignore = .gitignore
18 | appveyor.yml = appveyor.yml
19 | build.cake = build.cake
20 | build.ps1 = build.ps1
21 | common.props = common.props
22 | LICENSE = LICENSE
23 | README.md = README.md
24 | EndProjectSection
25 | EndProject
26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abp.Push.Tests", "test\Abp.Push.Tests\Abp.Push.Tests.csproj", "{935CBB37-42F7-4100-91BD-425FC2E1A72B}"
27 | EndProject
28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Abp.Push.EntityFrameworkCore", "src\Abp.Push.EntityFrameworkCore\Abp.Push.EntityFrameworkCore.csproj", "{ADBFFA10-DF24-41DA-BC78-25F9F10942F3}"
29 | EndProject
30 | Global
31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
32 | Debug|Any CPU = Debug|Any CPU
33 | Release|Any CPU = Release|Any CPU
34 | EndGlobalSection
35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
36 | {B4F6E73F-D573-461C-A4A6-8F838C50859F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {B4F6E73F-D573-461C-A4A6-8F838C50859F}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {B4F6E73F-D573-461C-A4A6-8F838C50859F}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {B4F6E73F-D573-461C-A4A6-8F838C50859F}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {62081BD6-0FAF-4EF1-BCE4-619AC948C7AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {62081BD6-0FAF-4EF1-BCE4-619AC948C7AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {62081BD6-0FAF-4EF1-BCE4-619AC948C7AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {62081BD6-0FAF-4EF1-BCE4-619AC948C7AF}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {935CBB37-42F7-4100-91BD-425FC2E1A72B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {935CBB37-42F7-4100-91BD-425FC2E1A72B}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {935CBB37-42F7-4100-91BD-425FC2E1A72B}.Release|Any CPU.ActiveCfg = Release|Any CPU
47 | {935CBB37-42F7-4100-91BD-425FC2E1A72B}.Release|Any CPU.Build.0 = Release|Any CPU
48 | {ADBFFA10-DF24-41DA-BC78-25F9F10942F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {ADBFFA10-DF24-41DA-BC78-25F9F10942F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {ADBFFA10-DF24-41DA-BC78-25F9F10942F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
51 | {ADBFFA10-DF24-41DA-BC78-25F9F10942F3}.Release|Any CPU.Build.0 = Release|Any CPU
52 | EndGlobalSection
53 | GlobalSection(SolutionProperties) = preSolution
54 | HideSolutionNode = FALSE
55 | EndGlobalSection
56 | GlobalSection(NestedProjects) = preSolution
57 | {B4F6E73F-D573-461C-A4A6-8F838C50859F} = {CDCAEAFD-A61C-4525-98F5-E8F7227FE7B3}
58 | {62081BD6-0FAF-4EF1-BCE4-619AC948C7AF} = {CDCAEAFD-A61C-4525-98F5-E8F7227FE7B3}
59 | {935CBB37-42F7-4100-91BD-425FC2E1A72B} = {0ACDB552-6577-497F-8DC5-F38941B5D395}
60 | {ADBFFA10-DF24-41DA-BC78-25F9F10942F3} = {CDCAEAFD-A61C-4525-98F5-E8F7227FE7B3}
61 | EndGlobalSection
62 | GlobalSection(ExtensibilityGlobals) = postSolution
63 | SolutionGuid = {B2C237ED-C779-4CDF-96E9-CFD415CF820E}
64 | EndGlobalSection
65 | GlobalSection(MonoDevelopProperties) = preSolution
66 | Policies = $0
67 | $0.TextStylePolicy = $1
68 | $1.FileWidth = 80
69 | $1.TabsToSpaces = True
70 | $1.scope = text/x-csharp
71 | $0.CSharpFormattingPolicy = $2
72 | $2.scope = text/x-csharp
73 | EndGlobalSection
74 | EndGlobal
75 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018-2019 ryancyq
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/build.cake:
--------------------------------------------------------------------------------
1 | #tool nuget:?package=vswhere
2 | #tool "nuget:?package=xunit.runner.console&version=2.3.0-beta5-build3769"
3 |
4 | //////////////////////////////////////////////////////////////////////
5 | // ARGUMENTS
6 | //////////////////////////////////////////////////////////////////////
7 |
8 | var projectName = "Abp.Push";
9 | var solution = "./" + projectName + ".sln";
10 |
11 | var target = Argument("target", "Default");
12 | var configuration = Argument("configuration", "Release");
13 | var toolpath = Argument("toolpath", @"tools");
14 | var branch = Argument("branch", EnvironmentVariable("APPVEYOR_REPO_BRANCH"));
15 |
16 | var vsLatest = VSWhereLatest();
17 | var msBuildPathX64 = (vsLatest==null)
18 | ? null
19 | : vsLatest.CombineWithFilePath("./MSBuild/15.0/Bin/amd64/MSBuild.exe");
20 |
21 | var testProjects = new List>
22 | {
23 | new Tuple("Abp.Push.Tests", new[] { "net461", "netcoreapp2.1" })
24 | };
25 |
26 |
27 |
28 | var nugetPath = toolpath + "/nuget.exe";
29 |
30 | //////////////////////////////////////////////////////////////////////
31 | // TASKS
32 | //////////////////////////////////////////////////////////////////////
33 |
34 | Task("Clean")
35 | .Does(() =>
36 | {
37 | Information("Current Branch is:" + branch);
38 | CleanDirectories("./src/**/bin");
39 | CleanDirectories("./src/**/obj");
40 | CleanDirectories("./test/**/bin");
41 | CleanDirectories("./test/**/obj");
42 | });
43 |
44 | Task("Restore-NuGet-Packages")
45 | .IsDependentOn("Clean")
46 | .Does(() =>
47 | {
48 | NuGetRestore(solution);
49 | DotNetCoreRestore(solution);
50 | });
51 |
52 | Task("Build")
53 | .IsDependentOn("Restore-NuGet-Packages")
54 | .Does(() =>
55 | {
56 | MSBuild(solution, new MSBuildSettings(){Configuration = configuration, ToolPath = msBuildPathX64}
57 | .WithProperty("SourceLinkCreate","true"));
58 | });
59 |
60 | Task("Run-Unit-Tests")
61 | .IsDependentOn("Build")
62 | .DoesForEach(testProjects, testProject =>
63 | {
64 | foreach (string targetFramework in testProject.Item2)
65 | {
66 | Information($"Test execution started for target frameowork: {targetFramework}...");
67 | var testProj = GetFiles($"./test/**/*{testProject.Item1}.csproj").First();
68 | DotNetCoreTest(testProj.FullPath, new DotNetCoreTestSettings { Configuration = "Release", Framework = targetFramework });
69 | }
70 | })
71 | .DeferOnError();
72 |
73 |
74 | //////////////////////////////////////////////////////////////////////
75 | // TASK TARGETS
76 | //////////////////////////////////////////////////////////////////////
77 |
78 | Task("Default")
79 | .IsDependentOn("Build")
80 | .IsDependentOn("Run-Unit-Tests");
81 |
82 | //////////////////////////////////////////////////////////////////////
83 | // EXECUTION
84 | //////////////////////////////////////////////////////////////////////
85 |
86 | RunTarget(target);
87 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | This is a Powershell script to bootstrap a Cake build.
4 | .DESCRIPTION
5 | This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
6 | and execute your Cake build script with the parameters you provide.
7 | .PARAMETER Target
8 | The build script target to run.
9 | .PARAMETER Configuration
10 | The build configuration to use.
11 | .PARAMETER Verbosity
12 | Specifies the amount of information to be displayed.
13 | .PARAMETER WhatIf
14 | Performs a dry run of the build script.
15 | No tasks will be executed.
16 | .PARAMETER ScriptArgs
17 | Remaining arguments are added here.
18 | .LINK
19 | https://cakebuild.net
20 | #>
21 |
22 | [CmdletBinding()]
23 | Param(
24 | [string]$Target = "Default",
25 | [ValidateSet("Release", "Debug")]
26 | [string]$Configuration = "Release",
27 | [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
28 | [string]$Verbosity = "Verbose",
29 | [switch]$WhatIf,
30 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
31 | [string[]]$ScriptArgs
32 | )
33 |
34 | $CakeVersion = "0.23.0"
35 | $DotNetChannel = "Current";
36 | $DotNetVersion = "2.1.302";
37 | $DotNetInstallerUri = "https://dot.net/v1/dotnet-install.ps1";
38 | $NugetUrl = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
39 |
40 | # Temporarily skip verification and opt-in to new in-proc NuGet
41 | $ENV:CAKE_SETTINGS_SKIPVERIFICATION='true'
42 | $ENV:CAKE_NUGET_USEINPROCESSCLIENT='true'
43 |
44 | # Make sure tools folder exists
45 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
46 | $ToolPath = Join-Path $PSScriptRoot "tools"
47 | if (!(Test-Path $ToolPath)) {
48 | Write-Verbose "Creating tools directory..."
49 | New-Item -Path $ToolPath -Type directory | out-null
50 | }
51 |
52 | ###########################################################################
53 | # INSTALL .NET CORE CLI
54 | ###########################################################################
55 |
56 | Function Remove-PathVariable([string]$VariableToRemove)
57 | {
58 | $path = [Environment]::GetEnvironmentVariable("PATH", "User")
59 | if ($path -ne $null)
60 | {
61 | $newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove }
62 | [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "User")
63 | }
64 |
65 | $path = [Environment]::GetEnvironmentVariable("PATH", "Process")
66 | if ($path -ne $null)
67 | {
68 | $newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove }
69 | [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "Process")
70 | }
71 | }
72 |
73 | # Get .NET Core CLI path if installed.
74 | $FoundDotNetCliVersion = $null;
75 | if (Get-Command dotnet -ErrorAction SilentlyContinue) {
76 | $FoundDotNetCliVersion = dotnet --version;
77 | }
78 |
79 | if($FoundDotNetCliVersion -ne $DotNetVersion) {
80 | $InstallPath = Join-Path $PSScriptRoot ".dotnet"
81 | if (!(Test-Path $InstallPath)) {
82 | mkdir -Force $InstallPath | Out-Null;
83 | }
84 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, "$InstallPath\dotnet-install.ps1");
85 | & $InstallPath\dotnet-install.ps1 -Channel $DotNetChannel -Version $DotNetVersion -InstallDir $InstallPath;
86 |
87 | Remove-PathVariable "$InstallPath"
88 | $env:PATH = "$InstallPath;$env:PATH"
89 | }
90 |
91 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
92 | $env:DOTNET_CLI_TELEMETRY_OPTOUT=1
93 |
94 | ###########################################################################
95 | # INSTALL NUGET
96 | ###########################################################################
97 |
98 | # Make sure nuget.exe exists.
99 | $NugetPath = Join-Path $ToolPath "nuget.exe"
100 | if (!(Test-Path $NugetPath)) {
101 | Write-Host "Downloading NuGet.exe..."
102 | (New-Object System.Net.WebClient).DownloadFile($NugetUrl, $NugetPath);
103 | }
104 |
105 | ###########################################################################
106 | # INSTALL CAKE
107 | ###########################################################################
108 |
109 | # Make sure Cake has been installed.
110 | $CakePath = Join-Path $ToolPath "Cake.$CakeVersion/Cake.exe"
111 | if (!(Test-Path $CakePath)) {
112 | Write-Host "Installing Cake..."
113 | Invoke-Expression "&`"$NugetPath`" install Cake -Version $CakeVersion -OutputDirectory `"$ToolPath`"" | Out-Null;
114 | if ($LASTEXITCODE -ne 0) {
115 | Throw "An error occured while restoring Cake from NuGet."
116 | }
117 | }
118 |
119 | ###########################################################################
120 | # RUN BUILD SCRIPT
121 | ###########################################################################
122 |
123 | # Build the argument list.
124 | $Arguments = @{
125 | target=$Target;
126 | configuration=$Configuration;
127 | verbosity=$Verbosity;
128 | dryrun=$WhatIf;
129 | }.GetEnumerator() | %{"--{0}=`"{1}`"" -f $_.key, $_.value };
130 |
131 | # Start Cake
132 | Write-Host "Running build script..."
133 | Invoke-Expression "& `"$CakePath`" `"build.cake`" $Arguments $ScriptArgs"
134 | exit $LASTEXITCODE
--------------------------------------------------------------------------------
/common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | $(NoWarn);CS1591
5 |
6 | https://github.com/ryancyq/abp-push
7 | MIT
8 | git
9 | https://github.com/ryancyq/abp-push
10 |
11 |
12 |
13 | bin\$(Platform)\$(Configuration)\
14 | ..\..\nupkg\
15 |
16 |
17 |
18 | True
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | true
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/nupkg/pack.ps1:
--------------------------------------------------------------------------------
1 | # Paths
2 | $packFolder = (Get-Item -Path "./" -Verbose).FullName
3 | $slnPath = Join-Path $packFolder "../"
4 | $srcPath = Join-Path $slnPath "src"
5 |
6 | # List of projects
7 | $projects = (
8 | "Abp.Push.Common",
9 | "Abp.Push",
10 | "Abp.Push.EntityFrameworkCore"
11 | )
12 |
13 | # Rebuild solution
14 | Set-Location $slnPath
15 | & dotnet restore
16 |
17 | # Copy all nuget packages to the pack folder
18 | foreach($project in $projects) {
19 |
20 | $projectFolder = Join-Path $srcPath $project
21 |
22 | # Create nuget pack
23 | Set-Location $projectFolder
24 | Remove-Item -Recurse (Join-Path $projectFolder "bin/Release")
25 | & dotnet msbuild /p:Configuration=Release /p:SourceLinkCreate=true
26 | & dotnet msbuild /t:pack /p:Configuration=Release /p:SourceLinkCreate=true /p:IncludeReferencedProjects=true
27 |
28 | # Copy nuget package
29 | $projectPackPath = Join-Path $projectFolder ("/bin/Release/" + $project + ".*.nupkg")
30 | Move-Item $projectPackPath $packFolder
31 |
32 | }
33 |
34 | # Go back to the pack folder
35 | Set-Location $packFolder
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | ## Abp Push Notification
2 | A push notification system built base on Abp Framework.
3 |
4 | 
5 |
6 | ## Nuget Packages
7 | |Package|Status|
8 | |---|---|
9 | |Abp.Push.Common|[](https://www.nuget.org/packages/Abp.Push.Common)|
10 | |Abp.Push|[](https://www.nuget.org/packages/Abp.Push)|
11 | |Abp.Push.EntityFrameworkCore|[](https://www.nuget.org/packages/Abp.Push.EntityFrameworkCore)|
12 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Abp.Push.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | netstandard2.0
7 | Abp Push.Common
8 | Abp.Push.Common
9 | Abp.Push.Common
10 | Abp
11 | false
12 | false
13 | false
14 | false
15 | false
16 | false
17 | true
18 | False
19 | Library
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Abp.Push.Common.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Abp.Push.Common
5 | $version$
6 | $title$
7 | Ryancyq
8 | Ryancyq
9 | true
10 | Abp Push Common Module
11 | Summary of changes made in this release of the package.
12 | Copyright 2019
13 | netstandard2.0 asp.net mvc abp aspnetboilerplate
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/AbpPushCommonModule.cs:
--------------------------------------------------------------------------------
1 | using Abp.Dependency;
2 | using Abp.Modules;
3 | using Abp.Push.Localization;
4 | using Abp.Push.Requests;
5 | using Abp.Reflection.Extensions;
6 |
7 | namespace Abp.Push
8 | {
9 | [DependsOn(typeof(AbpKernelModule))]
10 | public class AbpPushCommonModule : AbpModule
11 | {
12 | ///
13 | public override void PreInitialize()
14 | {
15 | //Configure settings
16 | Configuration.Settings.Providers.Add();
17 |
18 | //Configure localizations
19 | AbpPushLocalizationConfigurer.Configure(Configuration.Localization);
20 | }
21 |
22 | ///
23 | public override void Initialize()
24 | {
25 | IocManager.RegisterAssemblyByConvention(typeof(AbpPushCommonModule).GetAssembly());
26 | }
27 |
28 | public override void PostInitialize()
29 | {
30 | IocManager.RegisterIfNot(DependencyLifeStyle.Singleton);
31 |
32 | IocManager.Resolve().Initialize();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/AbpPushConsts.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push
2 | {
3 | public static class AbpPushConsts
4 | {
5 | public const string LocalizationSourceName = "AbpPush";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/AbpPushSettingNames.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push
2 | {
3 | ///
4 | /// Pre-defined setting names for push system.
5 | ///
6 | public static class AbpPushSettingNames
7 | {
8 | ///
9 | /// A top-level switch to enable/disable receiving push for a user.
10 | ///
11 | public const string Receive = "Abp.Push.Receive";
12 | }
13 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/AbpPushSettingProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Abp.Configuration;
3 | using Abp.Localization;
4 |
5 | namespace Abp.Push
6 | {
7 | internal class AbpPushSettingProvider : SettingProvider
8 | {
9 | public override IEnumerable GetSettingDefinitions(SettingDefinitionProviderContext context)
10 | {
11 | return new[]
12 | {
13 | new SettingDefinition(
14 | AbpPushSettingNames.Receive,
15 | "true",
16 | L("AbpPushSettingNames.Receive"),
17 | scopes: SettingScopes.User,
18 | isVisibleToClients: true)
19 | };
20 | }
21 |
22 | protected virtual LocalizableString L(string name)
23 | {
24 | return new LocalizableString(name, AbpPushConsts.LocalizationSourceName);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/AbpPushConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Abp.Collections;
3 | using Abp.Configuration.Startup;
4 | using Abp.Dependency;
5 | using Abp.Push.Devices;
6 | using Abp.Push.Providers;
7 |
8 | namespace Abp.Push.Configuration
9 | {
10 | internal class AbpPushConfiguration : IAbpPushConfiguration, ISingletonDependency
11 | {
12 | public IAbpStartupConfiguration AbpConfiguration { get; private set; }
13 |
14 | public IAbpPushStoreConfiguration StoreConfiguration { get; private set; }
15 |
16 | public ITypeList Providers { get; private set; }
17 |
18 | public List ServiceProviders { get; private set; }
19 |
20 | public List DevicePlatforms { get; private set; }
21 |
22 | public int MaxUserCountForForegroundDistribution { get; set; }
23 |
24 | public AbpPushConfiguration(
25 | IAbpStartupConfiguration abpConfiguration,
26 | AbpPushStoreConfiguration pushStoreConfiguration
27 | )
28 | {
29 | AbpConfiguration = abpConfiguration;
30 | StoreConfiguration = pushStoreConfiguration;
31 | Providers = new TypeList();
32 | ServiceProviders = new List();
33 | DevicePlatforms = new List();
34 | MaxUserCountForForegroundDistribution = 5;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/AbpPushDeviceStoreConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 | using Abp.Dependency;
3 |
4 | namespace Abp.Push.Configuration
5 | {
6 | internal class AbpPushDeviceStoreConfiguration : IAbpPushDeviceStoreConfiguration, ISingletonDependency
7 | {
8 | public IAbpStartupConfiguration AbpConfiguration { get; private set; }
9 |
10 | public AbpPushDeviceStoreConfiguration(IAbpStartupConfiguration abpConfiguration)
11 | {
12 | AbpConfiguration = abpConfiguration;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/AbpPushModuleConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 |
3 | namespace Abp.Push.Configuration
4 | {
5 | public static class AbpPushConfigurationExtensions
6 | {
7 | ///
8 | /// Used to configure ABP Push module.
9 | ///
10 | public static IAbpPushConfiguration AbpPush(this IModuleConfigurations configurations)
11 | {
12 | return configurations.AbpConfiguration.Get();
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/AbpPushRequestStoreConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 | using Abp.Dependency;
3 |
4 | namespace Abp.Push.Configuration
5 | {
6 | internal class AbpPushRequestStoreConfiguration : IAbpPushRequestStoreConfiguration, ISingletonDependency
7 | {
8 | public IAbpStartupConfiguration AbpConfiguration { get; private set; }
9 |
10 | public AbpPushRequestStoreConfiguration(IAbpStartupConfiguration abpConfiguration)
11 | {
12 | AbpConfiguration = abpConfiguration;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/AbpPushStoreConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Abp.Dependency;
2 |
3 | namespace Abp.Push.Configuration
4 | {
5 | internal class AbpPushStoreConfiguration : IAbpPushStoreConfiguration, ISingletonDependency
6 | {
7 | public IAbpPushDeviceStoreConfiguration DeviceStore { get; private set; }
8 |
9 | public IAbpPushRequestStoreConfiguration RequestStore { get; private set; }
10 |
11 | public AbpPushStoreConfiguration(
12 | IAbpPushDeviceStoreConfiguration deviceStoreConfiguration,
13 | IAbpPushRequestStoreConfiguration requestStoreConfiguration
14 | )
15 | {
16 | DeviceStore = deviceStoreConfiguration;
17 | RequestStore = requestStoreConfiguration;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/IAbpPushConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Abp.Collections;
3 | using Abp.Configuration.Startup;
4 | using Abp.Push.Devices;
5 | using Abp.Push.Providers;
6 |
7 | namespace Abp.Push.Configuration
8 | {
9 | ///
10 | /// Used to configure push system.
11 | ///
12 | public interface IAbpPushConfiguration
13 | {
14 | ///
15 | /// Gets the ABP configuration object.
16 | ///
17 | IAbpStartupConfiguration AbpConfiguration { get; }
18 |
19 | ///
20 | /// Gets the push store configuration.
21 | ///
22 | IAbpPushStoreConfiguration StoreConfiguration { get; }
23 |
24 | ///
25 | /// Gets the list of push definition providers.
26 | ///
27 | ITypeList Providers { get; }
28 |
29 | ///
30 | /// Gets the list of push service providers.
31 | ///
32 | List ServiceProviders { get; }
33 |
34 | ///
35 | /// Gets the list of device platforms.
36 | ///
37 | List DevicePlatforms { get; }
38 |
39 | int MaxUserCountForForegroundDistribution { get; }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/IAbpPushDeviceStoreConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 |
3 | namespace Abp.Push.Configuration
4 | {
5 | ///
6 | /// Used to configure push device store.
7 | ///
8 | public interface IAbpPushDeviceStoreConfiguration
9 | {
10 | ///
11 | /// Gets the ABP configuration object.
12 | ///
13 | IAbpStartupConfiguration AbpConfiguration { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/IAbpPushRequestStoreConfiguration.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 |
3 | namespace Abp.Push.Configuration
4 | {
5 | ///
6 | /// Used to configure push reequest store.
7 | ///
8 | public interface IAbpPushRequestStoreConfiguration
9 | {
10 | ///
11 | /// Gets the ABP configuration object.
12 | ///
13 | IAbpStartupConfiguration AbpConfiguration { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Configuration/IAbpPushStoreConfiguration.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push.Configuration
2 | {
3 | ///
4 | /// Used to configure push system.
5 | ///
6 | public interface IAbpPushStoreConfiguration
7 | {
8 | IAbpPushDeviceStoreConfiguration DeviceStore { get; }
9 |
10 | IAbpPushRequestStoreConfiguration RequestStore { get; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/AbpPushDevice.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using Abp.Domain.Entities;
5 | using Abp.Domain.Entities.Auditing;
6 |
7 | namespace Abp.Push.Devices
8 | {
9 | [Table("AbpPushDevices")]
10 | public abstract class AbpPushDevice : CreationAuditedEntity, IHasDeviceInfo, IMayHaveTenant
11 | {
12 | ///
13 | /// Maximum length of property.
14 | /// Value: 512.
15 | ///
16 | public const int MaxDeviceNameLength = 512;
17 |
18 | ///
19 | /// Maximum length of property.
20 | /// Value: 512.
21 | ///
22 | public const int MaxDevicePlatformLength = 256;
23 |
24 | ///
25 | /// Maximum length of property.
26 | /// Value: 1024 (1 kB).
27 | ///
28 | public const int MaxDeviceIdentifierLength = 1024;
29 |
30 | ///
31 | /// Maximum length of property.
32 | /// Value: 1024 (1 kB).
33 | ///
34 | public const int MaxProviderLength = 512;
35 |
36 | ///
37 | /// Maximum length of property.
38 | /// Value: 1024 (1 kB).
39 | ///
40 | public const int MaxProviderKeyLength = 1024;
41 |
42 | ///
43 | /// Maximum length of property.
44 | /// Value: 1048576 (1 MB).
45 | ///
46 | public const int MaxDataLength = 1024 * 1024;
47 |
48 | ///
49 | /// Maximum length of property.
50 | /// Value: 512.
51 | ///
52 | public const int MaxDataTypeNameLength = 512;
53 |
54 | ///
55 | /// Tenant Id.
56 | ///
57 | public virtual int? TenantId { get; set; }
58 |
59 | ///
60 | /// User Id.
61 | ///
62 | public virtual long? UserId { get; set; }
63 |
64 | ///
65 | /// Device Platform.
66 | ///
67 | [MaxLength(MaxDevicePlatformLength)]
68 | public virtual string DevicePlatform { get; set; }
69 |
70 | ///
71 | /// Device name.
72 | ///
73 | [MaxLength(MaxDeviceNameLength)]
74 | public virtual string DeviceName { get; set; }
75 |
76 | ///
77 | /// Normalized device name.
78 | ///
79 | [MaxLength(MaxDeviceNameLength)]
80 | public virtual string NormalizedDeviceName { get; private set; }
81 |
82 | ///
83 | /// Device identifier.
84 | ///
85 | public virtual Guid DeviceIdentifier { get; set; }
86 |
87 | ///
88 | /// Service Provider type.
89 | ///
90 | [MaxLength(MaxProviderLength)]
91 | public virtual string ServiceProvider { get; set; }
92 |
93 | ///
94 | /// Service Provider key.
95 | /// Follows convention in
96 | ///
97 | [MaxLength(MaxProviderKeyLength)]
98 | public virtual string ServiceProviderKey { get; set; }
99 |
100 | ///
101 | /// data payload as JSON string. (optional)
102 | ///
103 | [MaxLength(MaxDataLength)]
104 | public virtual PushDeviceData Data { get; set; }
105 |
106 | ///
107 | /// Expiration time.
108 | ///
109 | public virtual DateTime? ExpirationTime { get; set; }
110 |
111 | ///
112 | /// Type of the JSON serialized .
113 | /// It's AssemblyQualifiedName of the type.
114 | ///
115 | public virtual string DataTypeName { get; set; }
116 |
117 | public virtual void SetNormalizedNames()
118 | {
119 | NormalizedDeviceName = DeviceName?.ToUpperInvariant();
120 | }
121 |
122 | public override string ToString()
123 | {
124 | return $"tenantId: { TenantId } , userId: { UserId }, platform: { DevicePlatform } , identifier: { DeviceIdentifier } , serviceProvider: { ServiceProvider } , serviceProviderKey: { ServiceProviderKey }";
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/AbpPushDeviceManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.Immutable;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using System.Transactions;
7 | using Abp.Domain.Services;
8 | using Abp.Push.Configuration;
9 | using Abp.Runtime.Session;
10 | using Abp.UI;
11 |
12 | namespace Abp.Push.Devices
13 | {
14 | public abstract class AbpPushDeviceManager : DomainService where TDevice : AbpPushDevice, new()
15 | {
16 | public IAbpSession AbpSession { get; set; }
17 | protected readonly IPushDeviceStore DeviceStore;
18 | protected readonly IAbpPushConfiguration Configuration;
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | protected AbpPushDeviceManager(
24 | IPushDeviceStore deviceStore,
25 | IAbpPushConfiguration pushConfiguration
26 | )
27 | {
28 | DeviceStore = deviceStore;
29 | Configuration = pushConfiguration;
30 |
31 | AbpSession = NullAbpSession.Instance;
32 |
33 | LocalizationSourceName = AbpPushConsts.LocalizationSourceName;
34 | }
35 |
36 | ///
37 | /// Adds a push device.
38 | ///
39 | /// The device.
40 | public virtual async Task AddAsync(TDevice device)
41 | {
42 | try
43 | {
44 | Check.NotNull(device, nameof(device));
45 |
46 | ValidateServiceProvider(device);
47 | ValidateDevicePlatform(device);
48 |
49 | using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
50 | {
51 | await CreateOrUpdateAsync(device);
52 | await uow.CompleteAsync();
53 | }
54 | return true;
55 | }
56 | catch (Exception ex)
57 | {
58 | Logger.Error("AddAsync failed, device: " + device?.ToString(), ex);
59 | }
60 | return false;
61 | }
62 |
63 | protected virtual async Task CreateOrUpdateAsync(TDevice entity)
64 | {
65 | var existingDevice = await FindAsync(entity.ServiceProvider, entity.ServiceProviderKey);
66 | if (existingDevice == null)
67 | {
68 | Logger.Debug("Device push existed " + entity.ToString());
69 | existingDevice = MapToPushDevice(existingDevice, entity);
70 | await DeviceStore.UpdateDeviceAsync(existingDevice);
71 | }
72 | else
73 | {
74 | var newDevice = MapToPushDevice(entity);
75 | await DeviceStore.InsertDeviceAsync(newDevice);
76 | }
77 | }
78 |
79 | ///
80 | /// Find a push device by provider and provider key.
81 | ///
82 | /// The service provider.
83 | /// The service provider key.
84 | /// The push device, if it is found
85 | public virtual async Task FindAsync(string serviceProvider, string serviceProviderKey)
86 | {
87 | return await DeviceStore.GetDeviceOrNullAsync(AbpSession.TenantId, serviceProvider, serviceProviderKey);
88 | }
89 |
90 | protected virtual TDevice MapToPushDevice(TDevice entity)
91 | {
92 | entity.SetNormalizedNames();
93 | return entity;
94 | }
95 |
96 | protected virtual TDevice MapToPushDevice(TDevice existingEntity, TDevice entity)
97 | {
98 | existingEntity.ServiceProviderKey = entity.ServiceProviderKey;
99 | existingEntity.DevicePlatform = entity.DevicePlatform;
100 | existingEntity.DeviceIdentifier = entity.DeviceIdentifier;
101 | existingEntity.DeviceName = entity.DeviceName;
102 | existingEntity.SetNormalizedNames();
103 | return existingEntity;
104 | }
105 |
106 | protected virtual void ValidateServiceProvider(TDevice entity)
107 | {
108 | var serviceProvider = Configuration.ServiceProviders
109 | .FirstOrDefault(p => p.Name == entity.ServiceProvider);
110 | if (serviceProvider == null)
111 | {
112 | throw new UserFriendlyException(L("Push.ServiceProvider.Invalid"));
113 | }
114 | }
115 |
116 | protected virtual void ValidateDevicePlatform(TDevice entity)
117 | {
118 | var devicePlatform = Configuration.DevicePlatforms
119 | .FirstOrDefault(p => p.Name == entity.DevicePlatform);
120 | if (devicePlatform == null)
121 | {
122 | throw new UserFriendlyException(L("Push.DevicePlatform.Invalid"));
123 | }
124 | }
125 |
126 | ///
127 | /// Removes a push device
128 | ///
129 | /// The device.
130 | public virtual async Task RemoveAsync(TDevice device)
131 | {
132 | try
133 | {
134 | Check.NotNull(device, nameof(device));
135 |
136 | using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
137 | {
138 | await DeviceStore.DeleteDeviceAsync(device);
139 | await uow.CompleteAsync();
140 | }
141 | }
142 | catch (Exception ex)
143 | {
144 | Logger.Error("RemoveAsync failed, device: " + device?.ToString(), ex);
145 | }
146 | }
147 |
148 | ///
149 | /// Removes a push device by device identifier.
150 | ///
151 | /// The device identifier.
152 | public virtual async Task RemoveAsync(IDeviceIdentifier deviceIdentifier)
153 | {
154 | try
155 | {
156 | using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
157 | {
158 | await DeviceStore.DeleteDeviceAsync(deviceIdentifier);
159 | await uow.CompleteAsync();
160 | }
161 | }
162 | catch (Exception ex)
163 | {
164 | Logger.Error("RemoveAsync failed, device identifier: " + deviceIdentifier?.ToString(), ex);
165 | }
166 | }
167 |
168 | ///
169 | /// Removes a push device by provider and provider key.
170 | ///
171 | /// The service provider.
172 | /// The service provider key.
173 | public virtual async Task RemoveAsync(string serviceProvider, string serviceProviderKey)
174 | {
175 | try
176 | {
177 | using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
178 | {
179 | await DeviceStore.DeleteDevicesByProviderAsync(AbpSession.TenantId, serviceProvider, serviceProviderKey);
180 | await uow.CompleteAsync();
181 | }
182 | }
183 | catch (Exception ex)
184 | {
185 | Logger.Error("RemoveAsync failed, service provider: " + serviceProvider + ", service provider key: " + serviceProviderKey, ex);
186 | }
187 | }
188 |
189 | ///
190 | /// Removes all push devices by user identifier.
191 | ///
192 | /// The user identifier.
193 | public virtual async Task RemoveAllByUserIdAsync(IUserIdentifier userIdentifier)
194 | {
195 | await DeviceStore.DeleteDevicesByUserAsync(userIdentifier);
196 | }
197 |
198 | ///
199 | /// Gets all push devices.
200 | ///
201 | public virtual async Task> GetAllAsync(int? skipCount = null, int? maxResultCount = null)
202 | {
203 | var devices = await DeviceStore.GetDevicesAsync(skipCount, maxResultCount);
204 | return devices.ToImmutableList();
205 | }
206 |
207 | ///
208 | /// Gets all push device by user identifier.
209 | ///
210 | public virtual async Task> GetAllByUserAsync(IUserIdentifier userIdentifier, int? skipCount = null, int? maxResultCount = null)
211 | {
212 | var devices = await DeviceStore.GetDevicesByUserAsync(userIdentifier, skipCount, maxResultCount);
213 | return devices.ToImmutableList();
214 | }
215 |
216 | ///
217 | /// Gets all push devices by user identifier and provider.
218 | ///
219 | public virtual async Task> GetAllByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider, int? skipCount = null, int? maxResultCount = null)
220 | {
221 | var devices = await DeviceStore.GetDevicesByUserPlatformAsync(userIdentifier, serviceProvider, skipCount, maxResultCount);
222 | return devices.ToImmutableList();
223 | }
224 |
225 | ///
226 | /// Gets total count of push devices by user identifier.
227 | ///
228 | public virtual Task GetCountByUserAsync(IUserIdentifier userIdentifier)
229 | {
230 | return DeviceStore.GetDeviceCountByUserAsync(userIdentifier);
231 | }
232 |
233 | ///
234 | /// Gets total count of push devices by user identifier and provider.
235 | ///
236 | public virtual Task GetCountByUserIdProviderAsync(IUserIdentifier userIdentifier, string serviceProvider)
237 | {
238 | return DeviceStore.GetDeviceCountByUserProviderAsync(userIdentifier, serviceProvider);
239 | }
240 |
241 | ///
242 | /// Gets total count of push devices by user identifier and platform.
243 | ///
244 | public virtual Task GetCountByUserIdPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform)
245 | {
246 | return DeviceStore.GetDeviceCountByUserPlatformAsync(userIdentifier, devicePlatform);
247 | }
248 | }
249 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/AbpPushDeviceManagerExtensions.cs:
--------------------------------------------------------------------------------
1 | using Abp.Threading;
2 |
3 | namespace Abp.Push.Devices
4 | {
5 | ///
6 | /// Extension methods for .
7 | ///
8 | public static class AbpPushDeviceManagerExtensions
9 | {
10 | ///
11 | /// Determines whether the specified user has any devices can be pushed to.
12 | ///
13 | /// The push device manager.
14 | /// The user.
15 | public static bool HasAny(this AbpPushDeviceManager manager, IUserIdentifier user)
16 | where TDevice : AbpPushDevice, new()
17 | {
18 | return AsyncHelper.RunSync(() => manager.GetCountByUserAsync(user)) > 0;
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/DeviceIdentifier.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using Abp.Extensions;
4 |
5 | namespace Abp.Push.Devices
6 | {
7 | ///
8 | /// Used to identify a device.
9 | ///
10 | [Serializable]
11 | public class DeviceIdentifier : IDeviceIdentifier
12 | {
13 | ///
14 | /// Tenant Id of the device.
15 | /// Can be null for host devices in a multi tenant application.
16 | ///
17 | public int? TenantId { get; protected set; }
18 |
19 | ///
20 | /// Id of the device.
21 | ///
22 | public long DeviceId { get; protected set; }
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | protected DeviceIdentifier()
28 | {
29 |
30 | }
31 |
32 | ///
33 | /// Initializes a new instance of the class.
34 | ///
35 | /// Tenant Id of the device.
36 | /// Id of the device.
37 | public DeviceIdentifier(int? tenantId, long deviceId)
38 | {
39 | TenantId = tenantId;
40 | DeviceId = deviceId;
41 | }
42 |
43 | ///
44 | /// Parses given string and creates a new object.
45 | ///
46 | ///
47 | /// Should be formatted one of the followings:
48 | ///
49 | /// - "deviceId@tenantId". Ex: "42@3" (for tenant devices).
50 | /// - "deviceId". Ex: 1 (for host devices)
51 | ///
52 | public static DeviceIdentifier Parse(string deviceIdentifierString)
53 | {
54 | if (deviceIdentifierString.IsNullOrEmpty())
55 | {
56 | throw new ArgumentNullException(nameof(deviceIdentifierString), "deviceAtTenant can not be null or empty!");
57 | }
58 |
59 | var splitted = deviceIdentifierString.Split('@');
60 | if (splitted.Length == 1)
61 | {
62 | return new DeviceIdentifier(null, splitted[0].To());
63 |
64 | }
65 |
66 | if (splitted.Length == 2)
67 | {
68 | return new DeviceIdentifier(splitted[1].To(), splitted[0].To());
69 | }
70 |
71 | throw new ArgumentException("deviceAtTenant is not properly formatted", nameof(deviceIdentifierString));
72 | }
73 |
74 | ///
75 | /// Creates a string represents this instance.
76 | /// Formatted one of the followings:
77 | ///
78 | /// - "deviceId@tenantId". Ex: "42@3" (for tenant devices).
79 | /// - "deviceId". Ex: 1 (for host devices)
80 | ///
81 | /// Returning string can be used in method to re-create identical object.
82 | ///
83 | public string ToDeviceIdentifierString()
84 | {
85 | if (TenantId == null)
86 | {
87 | return DeviceId.ToString();
88 | }
89 |
90 | return DeviceId + "@" + TenantId;
91 | }
92 |
93 | public override bool Equals(object obj)
94 | {
95 | if (obj == null || !(obj is DeviceIdentifier))
96 | {
97 | return false;
98 | }
99 |
100 | //Same instances must be considered as equal
101 | if (ReferenceEquals(this, obj))
102 | {
103 | return true;
104 | }
105 |
106 | //Transient objects are not considered as equal
107 | var other = (DeviceIdentifier)obj;
108 |
109 | //Must have a IS-A relation of types or must be same type
110 | var typeOfThis = GetType();
111 | var typeOfOther = other.GetType();
112 | if (!typeOfThis.GetTypeInfo().IsAssignableFrom(typeOfOther) && !typeOfOther.GetTypeInfo().IsAssignableFrom(typeOfThis))
113 | {
114 | return false;
115 | }
116 |
117 | return TenantId == other.TenantId && DeviceId == other.DeviceId;
118 | }
119 |
120 | ///
121 | public override int GetHashCode()
122 | {
123 | return TenantId == null ? (int)DeviceId : (int)(TenantId.Value ^ DeviceId);
124 | }
125 |
126 | ///
127 | public static bool operator ==(DeviceIdentifier left, DeviceIdentifier right)
128 | {
129 | if (Equals(left, null))
130 | {
131 | return Equals(right, null);
132 | }
133 |
134 | return left.Equals(right);
135 | }
136 |
137 | ///
138 | public static bool operator !=(DeviceIdentifier left, DeviceIdentifier right)
139 | {
140 | return !(left == right);
141 | }
142 |
143 | public override string ToString()
144 | {
145 | return ToDeviceIdentifierString();
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/DeviceIdentifierExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push.Devices
2 | {
3 | ///
4 | /// Extension methods for and .
5 | ///
6 | public static class DeviceIdentifierExtensions
7 | {
8 | ///
9 | /// Creates a new object from any object implements .
10 | ///
11 | /// Device identifier.
12 | public static DeviceIdentifier ToDeviceIdentifier(this IDeviceIdentifier deviceIdentifier)
13 | {
14 | return new DeviceIdentifier(deviceIdentifier.TenantId, deviceIdentifier.DeviceId);
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/DevicePlatformInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Abp.Push.Devices
4 | {
5 | public class DevicePlatformInfo
6 | {
7 | public string Name { get; set; }
8 |
9 | public Type PlatformResolverType { get; set; }
10 |
11 | public DevicePlatformInfo(string name, Type platformResolverType)
12 | {
13 | Name = name;
14 | PlatformResolverType = platformResolverType;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/IDeviceIdentifier.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Abp.Push.Devices
4 | {
5 | ///
6 | /// Interface to get a device identifier.
7 | ///
8 | public interface IDeviceIdentifier
9 | {
10 | ///
11 | /// Tenant Id. Can be null for host device.
12 | ///
13 | int? TenantId { get; }
14 |
15 | ///
16 | /// Id of the device.
17 | ///
18 | long DeviceId { get; }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/IHasDeviceInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push.Devices
2 | {
3 | ///
4 | /// Represents information of a device
5 | ///
6 | public interface IHasDeviceInfo
7 | {
8 | string DevicePlatform { get; }
9 |
10 | ///
11 | /// Device name
12 | ///
13 | string DeviceName { get; }
14 |
15 | ///
16 | /// Normalized device name
17 | ///
18 | string NormalizedDeviceName { get; }
19 |
20 | ///
21 | /// Device identifier
22 | ///
23 | TIdentifier DeviceIdentifier { get; }
24 |
25 |
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/IPushDeviceStore.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace Abp.Push.Devices
5 | {
6 | ///
7 | /// Used to store (persist) push devices.
8 | ///
9 | public interface IPushDeviceStore where TDevice : AbpPushDevice
10 | {
11 | ///
12 | /// Inserts a push device.
13 | ///
14 | Task InsertDeviceAsync(TDevice device);
15 |
16 | ///
17 | /// Updates a push device.
18 | ///
19 | Task UpdateDeviceAsync(TDevice device);
20 |
21 | ///
22 | /// Inserts or updates a push device.
23 | ///
24 | Task InsertOrUpdateDeviceAsync(TDevice device);
25 |
26 | ///
27 | /// Delete a push device.
28 | ///
29 | Task DeleteDeviceAsync(TDevice device);
30 |
31 | ///
32 | /// Delete a push device by device identifier.
33 | ///
34 | Task DeleteDeviceAsync(IDeviceIdentifier deviceIdentifier);
35 |
36 | ///
37 | /// Delete all push devices by service provider.
38 | /// The tenant id.
39 | /// The service provider.
40 | ///
41 | Task DeleteDevicesByProviderAsync(int? tenantId, string serviceProvider);
42 |
43 | ///
44 | /// Delete all push devices by service provider and service provider key.
45 | /// The tenant id.
46 | /// The service provider.
47 | /// The service provider key.
48 | ///
49 | Task DeleteDevicesByProviderAsync(int? tenantId, string serviceProvider, string serviceProviderKey);
50 |
51 | ///
52 | /// Delete all push devices by device platform.
53 | /// The tenant id.
54 | /// The device platform.
55 | ///
56 | Task DeleteDevicesByPlatformAsync(int? tenantId, string devicePlatform);
57 |
58 | ///
59 | /// Delete a push device by user identifier.
60 | ///
61 | /// The user identifier.
62 | Task DeleteDevicesByUserAsync(IUserIdentifier userIdentifier);
63 |
64 | ///
65 | /// Delete all push devices by user identifier and service provider.
66 | /// The user identifier.
67 | /// The service provider.
68 | ///
69 | Task DeleteDevicesByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider);
70 |
71 | ///
72 | /// Delete all push devices by user identifier and device platform.
73 | /// The user identifier.
74 | /// The device platform.
75 | ///
76 | Task DeleteDevicesByUserPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform);
77 |
78 | ///
79 | /// Get a push device by service provider and service provider key.
80 | ///
81 | /// The tenant id.
82 | /// The service provider.
83 | /// The service provider key.
84 | /// The push device, if it is found
85 | Task GetDeviceOrNullAsync(int? tenantId, string serviceProvider, string serviceProviderKey);
86 |
87 | ///
88 | /// Gets all push devices.
89 | ///
90 | /// The tenant id.
91 | Task> GetDevicesAsync(int? tenantId, int? skipCount = null, int? maxResultCount = null);
92 |
93 | ///
94 | /// Gets all push devices by service provider.
95 | /// The tenant id.
96 | /// The service provider.
97 | ///
98 | Task> GetDevicesByProviderAsync(int? tenantId, string serviceProvider, int? skipCount = null, int? maxResultCount = null);
99 |
100 | ///
101 | /// Gets all push devices by device platform.
102 | /// The tenant id.
103 | /// The device platform.
104 | ///
105 | Task> GetDevicesByPlatformAsync(int? tenantId, string devicePlatform, int? skipCount = null, int? maxResultCount = null);
106 |
107 | ///
108 | /// Get a push device by user identifier and service provider and service provider key.
109 | ///
110 | /// The user identifier.
111 | /// The service provider.
112 | /// The service provider key.
113 | /// The push device, if it is found
114 | Task GetUserDeviceOrNullAsync(IUserIdentifier userIdentifier, string serviceProvider, string serviceProviderKey);
115 |
116 | ///
117 | /// Gets all push devices by user identifier.
118 | /// The user identifier.
119 | ///
120 | Task> GetDevicesByUserAsync(IUserIdentifier userIdentifier, int? skipCount = null, int? maxResultCount = null);
121 |
122 | ///
123 | /// Gets all push devices by user identifier and service provider.
124 | /// The user identifier.
125 | /// The service provider.
126 | ///
127 | Task> GetDevicesByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider, int? skipCount = null, int? maxResultCount = null);
128 |
129 | ///
130 | /// Gets all push devices by user identifier and device platform.
131 | /// The user identifier.
132 | /// The device platform.
133 | ///
134 | Task> GetDevicesByUserPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform, int? skipCount = null, int? maxResultCount = null);
135 |
136 | ///
137 | /// Gets push devices count by user identifier.
138 | /// The user identifier.
139 | ///
140 | Task GetDeviceCountByUserAsync(IUserIdentifier userIdentifier);
141 |
142 | ///
143 | /// Gets push device count by user identifier and service provider.
144 | /// The user identifier.
145 | /// The service provider.
146 | ///
147 | Task GetDeviceCountByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider);
148 |
149 | ///
150 | /// Gets push device count by user identifier and device platform.
151 | /// The user identifier.
152 | /// The device platform.
153 | ///
154 | Task GetDeviceCountByUserPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform);
155 | }
156 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/PushDeviceData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Abp.Collections.Extensions;
4 | using Abp.Json;
5 |
6 | namespace Abp.Push.Devices
7 | {
8 | ///
9 | /// Used to store info for a push device.
10 | /// It can be directly used or can be derived.
11 | ///
12 | [Serializable]
13 | public class PushDeviceData
14 | {
15 | ///
16 | /// Gets push device info data type name.
17 | /// It returns the full class name by default.
18 | ///
19 | public virtual string Type => GetType().FullName;
20 |
21 | ///
22 | /// Shortcut to set/get .
23 | ///
24 | public object this[string key]
25 | {
26 | get { return Properties.GetOrDefault(key); }
27 | set { Properties[key] = value; }
28 | }
29 |
30 | ///
31 | /// Can be used to add custom properties to this push device.
32 | ///
33 | public Dictionary Properties
34 | {
35 | get { return _properties; }
36 | set
37 | {
38 | if (value == null)
39 | {
40 | throw new ArgumentNullException(nameof(value));
41 | }
42 |
43 | /* Not assign value, but add dictionary items. This is required for backward compability. */
44 | foreach (var keyValue in value)
45 | {
46 | if (!_properties.ContainsKey(keyValue.Key))
47 | {
48 | _properties[keyValue.Key] = keyValue.Value;
49 | }
50 | }
51 | }
52 | }
53 | private readonly Dictionary _properties;
54 |
55 | ///
56 | /// Createa a new PushDeviceData object.
57 | ///
58 | public PushDeviceData()
59 | {
60 | _properties = new Dictionary();
61 | }
62 |
63 | public override string ToString()
64 | {
65 | return this.ToJsonString();
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/PushDeviceExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push.Devices
2 | {
3 | public static class PushDeviceExtensions
4 | {
5 | public static UserIdentifier ToUserIdentifierOrNull(this AbpPushDevice device)
6 | {
7 | return device.UserId.HasValue ? new UserIdentifier(device.TenantId, device.UserId.Value) : null;
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Devices/PushDeviceInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push.Devices
2 | {
3 | public class PushDeviceInfo
4 | {
5 | public static PushDeviceInfo Empty = new PushDeviceInfo();
6 |
7 | public string ProviderKey { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/IPushDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Abp.Application.Features;
4 | using Abp.Authorization;
5 | using Abp.Localization;
6 |
7 | namespace Abp.Push
8 | {
9 | ///
10 | /// Interface of a push definition
11 | ///
12 | public interface IPushDefinition
13 | {
14 | ///
15 | /// Unique name of the push.
16 | ///
17 | string Name { get; }
18 |
19 | ///
20 | /// Related entity type with this push (optional).
21 | ///
22 | Type EntityType { get; }
23 |
24 | ///
25 | /// Display name of the push.
26 | /// Optional.
27 | ///
28 | ILocalizableString DisplayName { get; }
29 |
30 | ///
31 | /// Description for the push.
32 | /// Optional.
33 | ///
34 | ILocalizableString Description { get; }
35 |
36 | ///
37 | /// A permission dependency. This push will be available to a user if this dependency is satisfied.
38 | /// Optional.
39 | ///
40 | IPermissionDependency PermissionDependency { get; }
41 |
42 | ///
43 | /// A feature dependency. This push will be available to a tenant if this feature is enabled.
44 | /// Optional.
45 | ///
46 | IFeatureDependency FeatureDependency { get; }
47 |
48 | ///
49 | /// Gets/sets arbitrary objects related to this object.
50 | /// Gets null if given key does not exists.
51 | /// This is a shortcut for dictionary.
52 | ///
53 | /// Key
54 | object this[string key] { get; set; }
55 |
56 | ///
57 | /// Arbitrary objects related to this object.
58 | /// These objects must be serializable.
59 | ///
60 | IDictionary Attributes { get; }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/IPushDefinitionContext.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push
2 | {
3 | ///
4 | /// Used as a context while defining pushes.
5 | ///
6 | public interface IPushDefinitionContext
7 | {
8 | ///
9 | /// Gets the push definition manager.
10 | ///
11 | IPushDefinitionManager Manager { get; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/IPushDefinitionManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 |
4 | namespace Abp.Push
5 | {
6 | public interface IPushDefinitionManager : IPushDefinitionManager
7 | {
8 | }
9 |
10 | ///
11 | /// Used to manage push definitions.
12 | ///
13 | public interface IPushDefinitionManager
14 | where TDefinition : IPushDefinition
15 | {
16 | ///
17 | /// Adds the specified push definition.
18 | ///
19 | void Add(TDefinition pushDefinition);
20 |
21 | ///
22 | /// Gets a push definition by name.
23 | /// Throws exception if there is no push definition with given name.
24 | ///
25 | TDefinition Get(string name);
26 |
27 | ///
28 | /// Gets a push definition by name.
29 | /// Returns null if there is no push definition with given name.
30 | ///
31 | TDefinition GetOrNull(string name);
32 |
33 | ///
34 | /// Gets all push definitions.
35 | ///
36 | IReadOnlyList GetAll();
37 |
38 | ///
39 | /// Checks if given push definition by name is available for given user.
40 | ///
41 | /// Definition Name.
42 | /// User.
43 | Task IsAvailableAsync(string name, IUserIdentifier user);
44 |
45 | ///
46 | /// Gets all available push definitions for given user.
47 | ///
48 | /// User.
49 | Task> GetAllAvailableAsync(IUserIdentifier user);
50 | }
51 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Localization/AbpPush.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Localization/AbpPushLocalizationConfigurer.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 | using Abp.Localization.Dictionaries;
3 | using Abp.Localization.Dictionaries.Xml;
4 | using Abp.Reflection.Extensions;
5 |
6 | namespace Abp.Push.Localization
7 | {
8 | internal static class AbpPushLocalizationConfigurer
9 | {
10 | public static void Configure(ILocalizationConfiguration localizationConfiguration)
11 | {
12 | localizationConfiguration.Sources.Add(
13 | new DictionaryBasedLocalizationSource(
14 | AbpPushConsts.LocalizationSourceName,
15 | new XmlEmbeddedFileLocalizationDictionaryProvider(
16 | typeof(AbpPushCommonModule).GetAssembly(), "Abp.Push.Localization"
17 | )
18 | )
19 | );
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/AbpPushProviderManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Abp.Dependency;
5 | using Abp.Domain.Services;
6 | using Abp.Push.Configuration;
7 | using Abp.Push.Devices;
8 |
9 | namespace Abp.Push.Providers
10 | {
11 | public class AbpPushProviderManager : DomainService, IPushProviderManager, ITransientDependency
12 | {
13 | protected readonly IIocResolver IocResolver;
14 | protected readonly IAbpPushConfiguration Configuration;
15 |
16 | public AbpPushProviderManager(
17 | IIocResolver iocResolver,
18 | IAbpPushConfiguration pushConfiguration
19 | )
20 | {
21 | IocResolver = iocResolver;
22 | Configuration = pushConfiguration;
23 | }
24 |
25 | public virtual Task IsValidDeviceAsync(string provider, string providerKey)
26 | {
27 | using (var apiClient = CreateApiClient(provider))
28 | {
29 | return apiClient.Object.IsValidDeviceAsync(providerKey);
30 | }
31 | }
32 |
33 | public virtual Task GetDeviceInfoAsync(string provider, string providerKey)
34 | where TDeviceInfo : PushDeviceInfo
35 | {
36 | using (var apiClient = CreateApiClient(provider))
37 | {
38 | return apiClient.Object.GetDeviceInfoAsync(providerKey);
39 | }
40 | }
41 |
42 | public virtual Task PushAsync(string provider, TPayload payload)
43 | where TPayload : PushPayload
44 | {
45 | using (var providerApi = CreateApiClient(provider))
46 | {
47 | return providerApi.Object.PushAsync(payload);
48 | }
49 | }
50 |
51 | protected virtual IDisposableDependencyObjectWrapper CreateApiClient(string provider)
52 | {
53 | var providerInfo = Configuration.ServiceProviders.FirstOrDefault(p => p.Name == provider);
54 | if (providerInfo == null)
55 | {
56 | throw new ArgumentException("Unknown push service provider: " + provider);
57 | }
58 |
59 | var providerApi = IocResolver.ResolveAsDisposable(providerInfo.ApiClientType);
60 | providerApi.Object.Initialize(providerInfo);
61 | return providerApi;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/IPushApiClient.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Abp.Push.Devices;
3 |
4 | namespace Abp.Push.Providers
5 | {
6 | public interface IPushApiClient
7 | {
8 | ServiceProviderInfo ProviderInfo { get; }
9 |
10 | void Initialize(ServiceProviderInfo providerInfo);
11 |
12 | Task IsValidDeviceAsync(string providerKey);
13 |
14 | Task GetDeviceInfoAsync(string providerKey) where TDeviceInfo : PushDeviceInfo;
15 |
16 | Task PushAsync(TPayload payload) where TPayload : PushPayload;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/IPushProviderManager.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Abp.Push.Devices;
3 |
4 | namespace Abp.Push.Providers
5 | {
6 | public interface IPushProviderManager
7 | {
8 | Task IsValidDeviceAsync(string provider, string providerKey);
9 |
10 | Task GetDeviceInfoAsync(string provider, string providerKey) where TDeviceInfo : PushDeviceInfo;
11 |
12 | Task PushAsync(string provider, TPayload payload) where TPayload : PushPayload;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/IPushServiceProvider.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Abp.Push.Devices;
3 | using Abp.Push.Requests;
4 |
5 | namespace Abp.Push.Providers
6 | {
7 | ///
8 | /// Interface of push service provider
9 | ///
10 | public interface IPushServiceProvider
11 | {
12 | ServiceProviderInfo ProviderInfo { get; }
13 |
14 | void Initialize(ServiceProviderInfo providerInfo);
15 |
16 | ///
17 | /// This method tries to deliver a single push to specified users.
18 | /// If a user does not have any registered device, it should ignore him.
19 | ///
20 | Task PushAsync(IUserIdentifier[] userIdentifiers, PushRequest pushRequest);
21 |
22 | ///
23 | /// This method tries to deliver a single push to specified devices.
24 | ///
25 | Task PushAsync(IDeviceIdentifier[] deviceIdentifiers, PushRequest pushRequest);
26 | }
27 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/PushApiClientBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 | using Abp.Dependency;
5 | using Abp.Push.Devices;
6 |
7 | namespace Abp.Push.Providers
8 | {
9 | public abstract class PushApiClientBase : AbpServiceBase, IPushApiClient, ITransientDependency
10 | {
11 | public ServiceProviderInfo ProviderInfo { get; set; }
12 |
13 | public void Initialize(ServiceProviderInfo providerInfo)
14 | {
15 | ProviderInfo = providerInfo;
16 | }
17 |
18 | public virtual async Task IsValidDeviceAsync(string providerKey)
19 | {
20 | if (string.IsNullOrWhiteSpace(providerKey))
21 | {
22 | return false;
23 | }
24 | var deviceInfo = await GetDeviceInfoAsync(providerKey);
25 | return deviceInfo.ProviderKey == providerKey;
26 | }
27 |
28 | public abstract Task GetDeviceInfoAsync(string providerKey) where TDeviceInfo : PushDeviceInfo;
29 |
30 | public abstract Task PushAsync(TPayload payload) where TPayload : PushPayload;
31 |
32 | protected virtual string ToBase64Utf8(string source)
33 | {
34 | return ToBase64(source, Encoding.UTF8);
35 | }
36 |
37 | protected virtual string ToBase64(string source, Encoding encoding)
38 | {
39 | return Convert.ToBase64String(encoding.GetBytes(source));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/PushPayload.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Abp.Push.Providers
4 | {
5 | [Serializable]
6 | public class PushPayload
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/PushServiceProviderBase.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Abp.Dependency;
3 | using Abp.Push.Devices;
4 | using Abp.Push.Requests;
5 |
6 | namespace Abp.Push.Providers
7 | {
8 | public abstract class PushServiceProviderBase : AbpServiceBase, IPushServiceProvider, ITransientDependency
9 | {
10 | public ServiceProviderInfo ProviderInfo { get; set; }
11 |
12 | public void Initialize(ServiceProviderInfo providerInfo)
13 | {
14 | ProviderInfo = providerInfo;
15 | }
16 |
17 | public abstract Task PushAsync(IUserIdentifier[] userIdentifiers, PushRequest pushRequest);
18 |
19 | public abstract Task PushAsync(IDeviceIdentifier[] deviceIdentifiers, PushRequest pushRequest);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Providers/ServiceProviderInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Abp.Push.Providers
4 | {
5 | public class ServiceProviderInfo
6 | {
7 | public string Name { get; set; }
8 |
9 | public string ClientId { get; set; }
10 |
11 | public string ClientSecret { get; set; }
12 |
13 | public Type ProviderType { get; set; }
14 |
15 | public Type ApiClientType { get; set; }
16 |
17 | public ServiceProviderInfo(string name, Type providerType, Type apiClientType, string clientId, string clientSecret)
18 | {
19 | Name = name;
20 | ProviderType = providerType;
21 | ApiClientType = apiClientType;
22 | ClientId = clientId;
23 | ClientSecret = clientSecret;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/PushDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Abp.Application.Features;
4 | using Abp.Authorization;
5 | using Abp.Collections.Extensions;
6 | using Abp.Localization;
7 |
8 | namespace Abp.Push
9 | {
10 | ///
11 | /// Definition for a push.
12 | ///
13 | public class PushDefinition : IPushDefinition
14 | {
15 | ///
16 | /// Unique name of the push.
17 | ///
18 | public string Name { get; private set; }
19 |
20 | ///
21 | /// Related entity type with this push (optional).
22 | ///
23 | public Type EntityType { get; private set; }
24 |
25 | ///
26 | /// Display name of the push.
27 | /// Optional.
28 | ///
29 | public ILocalizableString DisplayName { get; set; }
30 |
31 | ///
32 | /// Description for the push.
33 | /// Optional.
34 | ///
35 | public ILocalizableString Description { get; set; }
36 |
37 | ///
38 | /// A permission dependency. This push will be available to a user if this dependency is satisfied.
39 | /// Optional.
40 | ///
41 | public IPermissionDependency PermissionDependency { get; set; }
42 |
43 | ///
44 | /// A feature dependency. This push will be available to a tenant if this feature is enabled.
45 | /// Optional.
46 | ///
47 | public IFeatureDependency FeatureDependency { get; set; }
48 |
49 | ///
50 | /// Gets/sets arbitrary objects related to this object.
51 | /// Gets null if given key does not exists.
52 | /// This is a shortcut for dictionary.
53 | ///
54 | /// Key
55 | public object this[string key]
56 | {
57 | get { return Attributes.GetOrDefault(key); }
58 | set { Attributes[key] = value; }
59 | }
60 |
61 | ///
62 | /// Arbitrary objects related to this object.
63 | /// These objects must be serializable.
64 | ///
65 | public IDictionary Attributes { get; private set; }
66 |
67 | ///
68 | /// Initializes a new instance of the class.
69 | ///
70 | /// Unique name of the push.
71 | /// Related entity type with this push (optional).
72 | /// Display name of the push.
73 | /// Description for the push
74 | /// A permission dependency. This push will be available to a user if this dependency is satisfied.
75 | /// A feature dependency. This push will be available to a tenant if this feature is enabled.
76 | public PushDefinition(string name, Type entityType = null, ILocalizableString displayName = null, ILocalizableString description = null, IPermissionDependency permissionDependency = null, IFeatureDependency featureDependency = null)
77 | {
78 | if (string.IsNullOrWhiteSpace(name))
79 | {
80 | throw new ArgumentNullException(nameof(name), "name can not be null, empty or whitespace!");
81 | }
82 |
83 | Name = name;
84 | EntityType = entityType;
85 | DisplayName = displayName;
86 | Description = description;
87 | PermissionDependency = permissionDependency;
88 | FeatureDependency = featureDependency;
89 |
90 | Attributes = new Dictionary();
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/PushDefinitionContext.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push
2 | {
3 | internal class PushDefinitionContext : IPushDefinitionContext
4 | {
5 | public IPushDefinitionManager Manager { get; private set; }
6 |
7 | public PushDefinitionContext(IPushDefinitionManager manager)
8 | {
9 | Manager = manager;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/PushDefinitionManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Collections.Immutable;
3 | using System.Threading.Tasks;
4 | using Abp.Application.Features;
5 | using Abp.Authorization;
6 | using Abp.Collections.Extensions;
7 | using Abp.Dependency;
8 | using Abp.Push.Configuration;
9 |
10 | namespace Abp.Push
11 | {
12 | ///
13 | /// Implements .
14 | ///
15 | public class PushDefinitionManager : AbpServiceBase, IPushDefinitionManager, ISingletonDependency
16 | {
17 | protected readonly IAbpPushConfiguration Configuration;
18 | protected readonly IIocResolver IocResolver;
19 |
20 | private readonly IDictionary _pushDefinitions;
21 |
22 | public PushDefinitionManager(
23 | IIocResolver iocResolver,
24 | IAbpPushConfiguration configuration)
25 | {
26 | Configuration = configuration;
27 | IocResolver = iocResolver;
28 |
29 | _pushDefinitions = new Dictionary();
30 | }
31 |
32 | public virtual void Initialize()
33 | {
34 | var context = new PushDefinitionContext(this);
35 |
36 | foreach (var providerType in Configuration.Providers)
37 | {
38 | using (var provider = IocResolver.ResolveAsDisposable(providerType))
39 | {
40 | provider.Object.SetDefinitions(context);
41 | }
42 | }
43 | }
44 |
45 | public virtual void Add(PushDefinition pushDefinition)
46 | {
47 | if (_pushDefinitions.ContainsKey(pushDefinition.Name))
48 | {
49 | throw new AbpInitializationException("There is already a push definition with given name: " + pushDefinition.Name + ". Push names must be unique!");
50 | }
51 |
52 | _pushDefinitions[pushDefinition.Name] = pushDefinition;
53 | }
54 |
55 | public virtual PushDefinition Get(string name)
56 | {
57 | var definition = GetOrNull(name);
58 | if (definition == null)
59 | {
60 | throw new AbpException("There is no push definition with given name: " + name);
61 | }
62 |
63 | return definition;
64 | }
65 |
66 | public virtual PushDefinition GetOrNull(string name)
67 | {
68 | return _pushDefinitions.GetOrDefault(name);
69 | }
70 |
71 | public virtual IReadOnlyList GetAll()
72 | {
73 | return _pushDefinitions.Values.ToImmutableList();
74 | }
75 |
76 | public virtual async Task IsAvailableAsync(string name, IUserIdentifier user)
77 | {
78 | var pushDefinition = GetOrNull(name);
79 | if (pushDefinition == null)
80 | {
81 | return true;
82 | }
83 |
84 | if (pushDefinition.FeatureDependency != null)
85 | {
86 | using (var featureDependencyContext = IocResolver.ResolveAsDisposable())
87 | {
88 | featureDependencyContext.Object.TenantId = user.TenantId;
89 |
90 | if (!await pushDefinition.FeatureDependency.IsSatisfiedAsync(featureDependencyContext.Object))
91 | {
92 | return false;
93 | }
94 | }
95 | }
96 |
97 | if (pushDefinition.PermissionDependency != null)
98 | {
99 | using (var permissionDependencyContext = IocResolver.ResolveAsDisposable())
100 | {
101 | permissionDependencyContext.Object.User = user.ToUserIdentifier();
102 |
103 | if (!await pushDefinition.PermissionDependency.IsSatisfiedAsync(permissionDependencyContext.Object))
104 | {
105 | return false;
106 | }
107 | }
108 | }
109 |
110 | return true;
111 | }
112 |
113 | public virtual async Task> GetAllAvailableAsync(IUserIdentifier user)
114 | {
115 | var availableDefinitions = new List();
116 |
117 | using (var permissionDependencyContext = IocResolver.ResolveAsDisposable())
118 | {
119 | permissionDependencyContext.Object.User = user.ToUserIdentifier();
120 |
121 | using (var featureDependencyContext = IocResolver.ResolveAsDisposable())
122 | {
123 | featureDependencyContext.Object.TenantId = user.TenantId;
124 |
125 | foreach (var pushDefinition in GetAll())
126 | {
127 | if (pushDefinition.PermissionDependency != null &&
128 | !await pushDefinition.PermissionDependency.IsSatisfiedAsync(permissionDependencyContext.Object))
129 | {
130 | continue;
131 | }
132 |
133 | if (user.TenantId.HasValue &&
134 | pushDefinition.FeatureDependency != null &&
135 | !await pushDefinition.FeatureDependency.IsSatisfiedAsync(featureDependencyContext.Object))
136 | {
137 | continue;
138 | }
139 |
140 | availableDefinitions.Add(pushDefinition);
141 | }
142 | }
143 | }
144 |
145 | return availableDefinitions.ToImmutableList();
146 | }
147 | }
148 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/PushDefinitionManagerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Abp.Threading;
3 |
4 | namespace Abp.Push
5 | {
6 | ///
7 | /// Extension methods for .
8 | ///
9 | public static class PushDefinitionManagerExtensions
10 | {
11 | ///
12 | /// Gets all available push definitions for given user.
13 | ///
14 | /// Push definition manager
15 | /// User
16 | public static IReadOnlyList GetAllAvailable(this IPushDefinitionManager pushDefinitionManager, UserIdentifier user)
17 | {
18 | return AsyncHelper.RunSync(() => pushDefinitionManager.GetAllAvailableAsync(user));
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/PushDefinitionProvider.cs:
--------------------------------------------------------------------------------
1 | using Abp.Dependency;
2 |
3 | namespace Abp.Push
4 | {
5 | ///
6 | /// This class should be implemented in order to define pushes.
7 | ///
8 | public abstract class PushDefinitionProvider : ITransientDependency
9 | {
10 | ///
11 | /// Used to add/manipulate push definitions.
12 | ///
13 | /// Context
14 | public abstract void SetDefinitions(IPushDefinitionContext context);
15 | }
16 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/AbpPushRequestDistributor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Abp.Collections.Extensions;
6 | using Abp.Configuration;
7 | using Abp.Dependency;
8 | using Abp.Domain.Uow;
9 | using Abp.Extensions;
10 | using Abp.Push.Configuration;
11 | using Abp.Push.Providers;
12 |
13 | namespace Abp.Push.Requests
14 | {
15 | ///
16 | /// Used to distribute push requests to users.
17 | ///
18 | public class AbpPushRequestDistributor : AbpServiceBase, IPushRequestDistributor, ITransientDependency
19 | {
20 | protected readonly IPushRequestStore RequestStore;
21 | protected readonly IPushDefinitionManager DefinitionManager;
22 | protected readonly IAbpPushConfiguration Configuration;
23 | protected readonly IIocResolver IocResolver;
24 | protected readonly IGuidGenerator GuidGenerator;
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | public AbpPushRequestDistributor(
30 | IPushRequestStore pushRequestStore,
31 | IPushDefinitionManager pushDefinitionManager,
32 | IAbpPushConfiguration pushConfiguration,
33 | IIocResolver iocResolver,
34 | IGuidGenerator guidGenerator)
35 | {
36 | RequestStore = pushRequestStore;
37 | DefinitionManager = pushDefinitionManager;
38 | Configuration = pushConfiguration;
39 | IocResolver = iocResolver;
40 | GuidGenerator = guidGenerator;
41 | }
42 |
43 | [UnitOfWork]
44 | public virtual async Task DistributeAsync(Guid pushRequestId)
45 | {
46 | PushRequest pushRequest = null;
47 | // set tenantId = null, because push request only store in host side
48 | using (UnitOfWorkManager.Current.SetTenantId(null))
49 | {
50 | pushRequest = await RequestStore.GetRequestOrNullAsync(pushRequestId);
51 | if (pushRequest == null)
52 | {
53 | Logger.WarnFormat("PushRequestDistributionJob can not continue since could not found push request by id: {0} ", pushRequestId);
54 | return;
55 | }
56 | }
57 |
58 | // TODO: change GetUsers() to GetDevices()
59 | var users = await GetUsers(pushRequest);
60 | if (users.IsNullOrEmpty())
61 | {
62 | Logger.WarnFormat("Push Request with id: {0} does not have any target user", pushRequest.Id);
63 | }
64 |
65 | try
66 | {
67 | foreach (var providerInfo in Configuration.ServiceProviders)
68 | {
69 | // TODO: allow PushRequest to store target providers
70 | using (var provider = CreateProvider(providerInfo.Name))
71 | {
72 | await provider.Object.PushAsync(users, pushRequest);
73 | }
74 | }
75 |
76 | await RequestStore.DeleteRequestAsync(pushRequest.Id);
77 | }
78 | catch (Exception ex)
79 | {
80 | Logger.Warn(ex.ToString(), ex);
81 | }
82 | }
83 |
84 | [UnitOfWork]
85 | protected virtual async Task GetUsers(PushRequest request)
86 | {
87 | var userIds = new List();
88 |
89 | if (request.UserIds.IsNullOrEmpty())
90 | {
91 | //Get subscribed users
92 |
93 | List subscriptions;
94 |
95 | if (request.TenantIds.IsNullOrWhiteSpace() ||
96 | request.TenantIds.Trim() == PushRequest.AllTenantIdsString)
97 | {
98 | //Get all subscribed users of all tenants
99 | subscriptions = await RequestStore.GetSubscriptionsAsync(
100 | request.Name,
101 | request.EntityTypeName,
102 | request.EntityId
103 | );
104 | }
105 | else
106 | {
107 | var tenantIds = PushRequest.GetTenantIds(request.TenantIds);
108 |
109 | //Get all subscribed users of specified tenant(s)
110 | subscriptions = await RequestStore.GetSubscriptionsAsync(
111 | tenantIds,
112 | request.Name,
113 | request.EntityTypeName,
114 | request.EntityId
115 | );
116 | }
117 |
118 | //Remove invalid subscriptions
119 | var invalidSubscriptions = new Dictionary();
120 |
121 | var subscriptionGroups = subscriptions.GroupBy(s => s.TenantId);
122 | foreach (var subscriptionGroup in subscriptionGroups)
123 | {
124 | using (CurrentUnitOfWork.SetTenantId(subscriptionGroup.Key))
125 | {
126 | foreach (var subscription in subscriptionGroup)
127 | {
128 | if (!await DefinitionManager.IsAvailableAsync(request.Name, new UserIdentifier(subscription.TenantId, subscription.UserId)) ||
129 | // TODO: exclude system push request from checking user setting
130 | !SettingManager.GetSettingValueForUser(AbpPushSettingNames.Receive, subscription.TenantId, subscription.UserId))
131 | {
132 | invalidSubscriptions[subscription.Id] = subscription;
133 | }
134 | }
135 | }
136 | }
137 |
138 | subscriptions.RemoveAll(s => invalidSubscriptions.ContainsKey(s.Id));
139 |
140 | //Get user ids
141 | userIds = subscriptions
142 | .Select(s => new UserIdentifier(s.TenantId, s.UserId))
143 | .ToList();
144 | }
145 | else
146 | {
147 | //Directly get from UserIds
148 | userIds = request
149 | .UserIds
150 | .Split(",")
151 | .Select(uidAsStr => UserIdentifier.Parse(uidAsStr))
152 | // TODO: exclude system push request from checking user setting
153 | .Where(uid => SettingManager.GetSettingValueForUser(AbpPushSettingNames.Receive, uid.TenantId, uid.UserId))
154 | .ToList();
155 | }
156 |
157 | if (!request.ExcludedUserIds.IsNullOrEmpty())
158 | {
159 | //Exclude specified users.
160 | var excludedUserIds = request
161 | .ExcludedUserIds
162 | .Split(",")
163 | .Select(uidAsStr => UserIdentifier.Parse(uidAsStr))
164 | .ToList();
165 |
166 | userIds.RemoveAll(uid => excludedUserIds.Any(euid => euid.Equals(uid)));
167 | }
168 |
169 | return userIds.ToArray();
170 | }
171 |
172 | public virtual IDisposableDependencyObjectWrapper CreateProvider(string provider)
173 | {
174 | var providerInfo = Configuration.ServiceProviders.FirstOrDefault(s => s.Name == provider);
175 | if (providerInfo == null)
176 | {
177 | throw new Exception("Unknown push provider: " + provider);
178 | }
179 |
180 | var pushProvider = IocResolver.ResolveAsDisposable(providerInfo.ProviderType);
181 | pushProvider.Object.Initialize(providerInfo);
182 | return pushProvider;
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/AbpPushRequestPublisher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Abp.BackgroundJobs;
5 | using Abp.Collections.Extensions;
6 | using Abp.Dependency;
7 | using Abp.Domain.Entities;
8 | using Abp.Domain.Uow;
9 | using Abp.Extensions;
10 | using Abp.Json;
11 | using Abp.Push.Configuration;
12 | using Abp.Runtime.Session;
13 |
14 | namespace Abp.Push.Requests
15 | {
16 | ///
17 | /// Implements .
18 | ///
19 | public class AbpPushRequestPublisher : AbpServiceBase, IPushRequestPublisher, ITransientDependency
20 | {
21 | public int MaxUserCountToDirectlyDistributeARequest { get; protected set; } = 5;
22 |
23 | ///
24 | /// Reference to ABP session.
25 | ///
26 | public IAbpSession AbpSession { get; set; }
27 |
28 | protected readonly IPushRequestStore RequestStore;
29 | protected readonly IBackgroundJobManager BackgroundJobManager;
30 | protected readonly IPushRequestDistributor RequestDistributor;
31 | protected readonly IAbpPushConfiguration Configuration;
32 | protected readonly IGuidGenerator GuidGenerator;
33 |
34 | ///
35 | /// Initializes a new instance of the class.
36 | ///
37 | public AbpPushRequestPublisher(
38 | IPushRequestStore pushRequestStore,
39 | IBackgroundJobManager backgroundJobManager,
40 | IPushRequestDistributor pushRequestDistributor,
41 | IAbpPushConfiguration pushConfiguration,
42 | IGuidGenerator guidGenerator
43 | )
44 | {
45 | RequestStore = pushRequestStore;
46 | BackgroundJobManager = backgroundJobManager;
47 | RequestDistributor = pushRequestDistributor;
48 | Configuration = pushConfiguration;
49 | GuidGenerator = guidGenerator;
50 |
51 | AbpSession = NullAbpSession.Instance;
52 | }
53 |
54 | [UnitOfWork]
55 | public virtual async Task PublishAsync(
56 | string pushRequestName,
57 | PushRequestData data = null,
58 | EntityIdentifier entityIdentifier = null,
59 | PushRequestPriority priority = PushRequestPriority.Normal,
60 | IUserIdentifier[] userIds = null,
61 | IUserIdentifier[] excludedUserIds = null,
62 | int?[] tenantIds = null)
63 | {
64 | if (pushRequestName.IsNullOrEmpty())
65 | {
66 | throw new ArgumentException("PushRequestName can not be null or whitespace!", nameof(pushRequestName));
67 | }
68 |
69 | if (!tenantIds.IsNullOrEmpty() && !userIds.IsNullOrEmpty())
70 | {
71 | throw new ArgumentException("tenantIds can be set only if userIds is not set!", nameof(tenantIds));
72 | }
73 |
74 | if (tenantIds.IsNullOrEmpty() && userIds.IsNullOrEmpty())
75 | {
76 | tenantIds = new[] { AbpSession.TenantId };
77 | }
78 |
79 | var pushRequest = new PushRequest(GuidGenerator.Create())
80 | {
81 | Name = pushRequestName,
82 | EntityTypeName = entityIdentifier?.Type.FullName,
83 | EntityTypeAssemblyQualifiedName = entityIdentifier?.Type.AssemblyQualifiedName,
84 | EntityId = entityIdentifier?.Id.ToJsonString(),
85 | Priority = priority,
86 | UserIds = userIds.IsNullOrEmpty() ? null : userIds.Select(uid => uid.ToUserIdentifier().ToUserIdentifierString()).JoinAsString(","),
87 | ExcludedUserIds = excludedUserIds.IsNullOrEmpty() ? null : excludedUserIds.Select(uid => uid.ToUserIdentifier().ToUserIdentifierString()).JoinAsString(","),
88 | TenantIds = PushRequest.ToTenantIds(tenantIds),
89 | Data = data?.ToJsonString(),
90 | DataTypeName = data?.GetType().AssemblyQualifiedName
91 | };
92 |
93 | await RequestStore.InsertRequestAsync(pushRequest);
94 |
95 | await CurrentUnitOfWork.SaveChangesAsync(); //To get Id of the push request
96 |
97 | if (userIds != null && userIds.Length <= Configuration.MaxUserCountForForegroundDistribution)
98 | {
99 | //We can directly distribute the push request since there are not much receivers
100 | await RequestDistributor.DistributeAsync(pushRequest.Id);
101 | }
102 | else
103 | {
104 | //We enqueue a background job since distributing may get a long time
105 | await BackgroundJobManager.EnqueueAsync(
106 | new PushRequestDistributionJobArgs(
107 | pushRequest.Id
108 | )
109 | );
110 | }
111 | }
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/AbpPushRequestSubscriptionManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Abp.Dependency;
5 | using Abp.Domain.Entities;
6 | using Abp.Json;
7 |
8 | namespace Abp.Push.Requests
9 | {
10 | ///
11 | /// Implements .
12 | ///
13 | public class AbpPushRequestSubscriptionManager : IPushRequestSubscriptionManager, ITransientDependency
14 | {
15 | protected readonly IPushRequestStore RequestStore;
16 | protected readonly IPushDefinitionManager DefinitionManager;
17 | protected readonly IGuidGenerator GuidGenerator;
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | public AbpPushRequestSubscriptionManager(
23 | IPushRequestStore pushRequestStore,
24 | IPushDefinitionManager pushDefinitionManager,
25 | IGuidGenerator guidGenerator)
26 | {
27 | RequestStore = pushRequestStore;
28 | DefinitionManager = pushDefinitionManager;
29 | GuidGenerator = guidGenerator;
30 | }
31 |
32 | public virtual async Task SubscribeAsync(IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null)
33 | {
34 | if (await IsSubscribedAsync(user, pushRequestName, entityIdentifier))
35 | {
36 | return;
37 | }
38 |
39 | await RequestStore.InsertSubscriptionAsync(
40 | new PushRequestSubscription(
41 | GuidGenerator.Create(),
42 | user.TenantId,
43 | user.UserId,
44 | pushRequestName,
45 | entityIdentifier
46 | )
47 | );
48 | }
49 |
50 | public virtual async Task SubscribeToAllAvailablePushRequestsAsync(IUserIdentifier user)
51 | {
52 | var pushRequestDefinitions = (await DefinitionManager
53 | .GetAllAvailableAsync(user))
54 | .Where(nd => nd.EntityType == null)
55 | .ToList();
56 |
57 | foreach (var notificationDefinition in pushRequestDefinitions)
58 | {
59 | await SubscribeAsync(user, notificationDefinition.Name);
60 | }
61 | }
62 |
63 | public virtual async Task UnsubscribeAsync(IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null)
64 | {
65 | await RequestStore.DeleteSubscriptionAsync(
66 | user,
67 | pushRequestName,
68 | entityIdentifier?.Type.FullName,
69 | entityIdentifier?.Id.ToJsonString()
70 | );
71 | }
72 |
73 | // Can work only for single database approach
74 | public virtual async Task> GetSubscriptionsAsync(string pushRequestName, EntityIdentifier entityIdentifier = null, int skipCount = 0, int maxResultCount = int.MaxValue)
75 | {
76 | return await RequestStore.GetSubscriptionsAsync(pushRequestName,
77 | entityIdentifier?.Type.FullName,
78 | entityIdentifier?.Id.ToJsonString(),
79 | skipCount: skipCount,
80 | maxResultCount: maxResultCount
81 | );
82 | }
83 |
84 | public virtual async Task> GetSubscriptionsAsync(int? tenantId, string pushRequestName, EntityIdentifier entityIdentifier = null, int skipCount = 0, int maxResultCount = int.MaxValue)
85 | {
86 | return await RequestStore.GetSubscriptionsAsync(new[] { tenantId },
87 | pushRequestName,
88 | entityIdentifier?.Type.FullName,
89 | entityIdentifier?.Id.ToJsonString(),
90 | skipCount: skipCount,
91 | maxResultCount: maxResultCount
92 | );
93 | }
94 |
95 | public virtual async Task> GetSubscribedPushRequestsAsync(IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue)
96 | {
97 | return await RequestStore.GetSubscriptionsAsync(user,
98 | skipCount: skipCount,
99 | maxResultCount: maxResultCount);
100 | }
101 |
102 | public virtual Task IsSubscribedAsync(IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null)
103 | {
104 | return RequestStore.IsSubscribedAsync(
105 | user,
106 | pushRequestName,
107 | entityIdentifier?.Type.FullName,
108 | entityIdentifier?.Id.ToJsonString()
109 | );
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/IPushRequestDistributor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace Abp.Push.Requests
5 | {
6 | ///
7 | /// Used to distribute push requests.
8 | ///
9 | public interface IPushRequestDistributor
10 | {
11 | ///
12 | /// Distributes given push request.
13 | ///
14 | /// The push request id.
15 | Task DistributeAsync(Guid pushRequestId);
16 | }
17 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/IPushRequestPublisher.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Abp.Domain.Entities;
3 |
4 | namespace Abp.Push.Requests
5 | {
6 | ///
7 | /// Used to publish push request.
8 | ///
9 | public interface IPushRequestPublisher
10 | {
11 | ///
12 | /// Publishes a new push request.
13 | ///
14 | /// Unique push request name
15 | /// Push Request data (optional)
16 | /// The entity identifier if this request is related to an entity
17 | /// The push request priority
18 | ///
19 | /// Target user id(s).
20 | /// Used to send push request to specific user(s) (without checking the subscription).
21 | /// If this is null/empty, the request is sent to subscribed users.
22 | ///
23 | ///
24 | /// Excluded user id(s).
25 | /// This can be set to exclude some users while publishing requests to subscribed users.
26 | /// It's normally not set if is set.
27 | ///
28 | ///
29 | /// Target tenant id(s).
30 | /// Used to send push request to subscribed users of specific tenant(s).
31 | /// This should not be set if is set.
32 | /// can be passed to indicate all tenants.
33 | /// But this can only work in a single database approach (all tenants are stored in host database).
34 | /// If this is null, then it's automatically set to the current tenant on .
35 | ///
36 | Task PublishAsync(
37 | string pushRequestName,
38 | PushRequestData data = null,
39 | EntityIdentifier entityIdentifier = null,
40 | PushRequestPriority priority = PushRequestPriority.Normal,
41 | IUserIdentifier[] userIds = null,
42 | IUserIdentifier[] excludedUserIds = null,
43 | int?[] tenantIds = null);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/IPushRequestStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace Abp.Push.Requests
6 | {
7 | public interface IPushRequestStore
8 | {
9 | #region Subscriptions
10 |
11 | ///
12 | /// Inserts a push request subscription.
13 | ///
14 | Task InsertSubscriptionAsync(PushRequestSubscription subscription);
15 |
16 | ///
17 | /// Deletes a push request subscription.
18 | ///
19 | Task DeleteSubscriptionAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId);
20 |
21 | ///
22 | /// Gets subscriptions for a push request.
23 | ///
24 | Task> GetSubscriptionsAsync(string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue);
25 |
26 | ///
27 | /// Gets subscriptions for a push request for specified tenant(s).
28 | ///
29 | Task> GetSubscriptionsAsync(int?[] tenantIds, string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue);
30 |
31 | ///
32 | /// Gets subscriptions for a user.
33 | ///
34 | Task> GetSubscriptionsAsync(IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue);
35 |
36 | ///
37 | /// Checks if a user subscribed for a push request
38 | ///
39 | Task IsSubscribedAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId);
40 |
41 | #endregion
42 |
43 | ///
44 | /// Inserts a push request.
45 | ///
46 | /// The push request.
47 | Task InsertRequestAsync(PushRequest request);
48 |
49 | ///
50 | /// Gets a push request.
51 | ///
52 | /// The push request id.
53 | Task GetRequestOrNullAsync(Guid requestId);
54 |
55 | ///
56 | /// Gets push requests.
57 | ///
58 | /// Push request priority
59 | Task> GetRequestsAsync(PushRequestPriority? priority = null, int skipCount = 0, int maxResultCount = int.MaxValue);
60 |
61 | ///
62 | /// Gets push request count.
63 | ///
64 | /// Push request priority
65 | Task GethRequestCountAsync(PushRequestPriority? priority = null);
66 |
67 | ///
68 | /// Deletes a push request.
69 | ///
70 | /// The push request id.
71 | Task DeleteRequestAsync(Guid requestId);
72 |
73 | ///
74 | /// Updates a push request priority.
75 | ///
76 | Task UpdateRequestPriorityAsync(Guid requestId, PushRequestPriority priority);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/IPushRequestSubscriptionManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using Abp.Domain.Entities;
4 |
5 | namespace Abp.Push.Requests
6 | {
7 | ///
8 | /// Used to manage subscriptions for push requests.
9 | ///
10 | public interface IPushRequestSubscriptionManager
11 | {
12 | ///
13 | /// Subscribes to a push request for given user and push request informations.
14 | ///
15 | /// User
16 | /// Name of the push request.
17 | /// entity identifier
18 | Task SubscribeAsync(IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null);
19 |
20 | ///
21 | /// Subscribes to all available push request for given user.
22 | /// It does not subscribe entity related push request.
23 | ///
24 | /// User.
25 | Task SubscribeToAllAvailablePushRequestsAsync(IUserIdentifier user);
26 |
27 | ///
28 | /// Unsubscribes from a push request.
29 | ///
30 | /// User.
31 | /// Name of the push request.
32 | /// entity identifier
33 | Task UnsubscribeAsync(IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null);
34 |
35 | ///
36 | /// Gets all subscribtions for given push request (including all tenants).
37 | /// This only works for single database approach in a multitenant application!
38 | ///
39 | /// Name of the push request.
40 | /// entity identifier
41 | Task> GetSubscriptionsAsync(string pushRequestName, EntityIdentifier entityIdentifier = null, int skipCount = 0, int maxResultCount = int.MaxValue);
42 |
43 | ///
44 | /// Gets all subscribtions for given push request.
45 | ///
46 | /// Tenant id. Null for the host.
47 | /// Name of the push request.
48 | /// entity identifier
49 | Task> GetSubscriptionsAsync(int? tenantId, string pushRequestName, EntityIdentifier entityIdentifier = null, int skipCount = 0, int maxResultCount = int.MaxValue);
50 |
51 | ///
52 | /// Gets subscribed push requests for a user.
53 | ///
54 | /// User.
55 | Task> GetSubscribedPushRequestsAsync(IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue);
56 |
57 | ///
58 | /// Checks if a user subscribed for a push request.
59 | ///
60 | /// User.
61 | /// Name of the push request.
62 | /// entity identifier
63 | Task IsSubscribedAsync(IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/NullPushRequestStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 |
5 | namespace Abp.Push.Requests
6 | {
7 | ///
8 | /// Null pattern implementation of .
9 | ///
10 | public class NullPushRequestStore : IPushRequestStore
11 | {
12 | public Task InsertSubscriptionAsync(PushRequestSubscription subscription)
13 | {
14 | return Task.FromResult(0);
15 | }
16 |
17 | public Task DeleteSubscriptionAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId)
18 | {
19 | return Task.FromResult(0);
20 | }
21 |
22 | public Task> GetSubscriptionsAsync(string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue)
23 | {
24 | return Task.FromResult(new List());
25 | }
26 |
27 | public Task> GetSubscriptionsAsync(int?[] tenantIds, string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue)
28 | {
29 | return Task.FromResult(new List());
30 | }
31 |
32 | public Task> GetSubscriptionsAsync(IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue)
33 | {
34 | return Task.FromResult(new List());
35 | }
36 |
37 | public Task IsSubscribedAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId)
38 | {
39 | return Task.FromResult(false);
40 | }
41 |
42 | public Task DeleteRequestAsync(Guid requestId)
43 | {
44 | return Task.FromResult(0);
45 | }
46 |
47 | public Task InsertRequestAsync(PushRequest request)
48 | {
49 | return Task.FromResult(0);
50 | }
51 |
52 | public Task GetRequestOrNullAsync(Guid requestId)
53 | {
54 | return Task.FromResult(null as PushRequest);
55 | }
56 |
57 | public Task> GetRequestsAsync(PushRequestPriority? priority = null, int skipCount = 0, int maxResultCount = int.MaxValue)
58 | {
59 | return Task.FromResult(new List());
60 | }
61 |
62 | public Task GethRequestCountAsync(PushRequestPriority? priority = null)
63 | {
64 | return Task.FromResult(0);
65 | }
66 |
67 | public Task UpdateRequestPriorityAsync(Guid pushRequestId, PushRequestPriority priority)
68 | {
69 | return Task.FromResult(0);
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using System.Linq;
5 | using Abp.Collections.Extensions;
6 | using Abp.Domain.Entities.Auditing;
7 | using Abp.Extensions;
8 | using Abp.MultiTenancy;
9 |
10 | namespace Abp.Push.Requests
11 | {
12 | ///
13 | /// Used to store a push request.
14 | /// This push request is distributed to tenants and users by .
15 | ///
16 | [Serializable]
17 | [Table("AbpPushRequests")]
18 | [MultiTenancySide(MultiTenancySides.Host)]
19 | public class PushRequest : CreationAuditedEntity
20 | {
21 | ///
22 | /// Maximum length of property.
23 | /// Value: 512.
24 | ///
25 | public const int MaxNameLength = 512;
26 |
27 | ///
28 | /// Maximum length of property.
29 | /// Value: 4,194,304 (4 MB).
30 | ///
31 | public const int MaxDataLength = 4 * 1024 * 1024;
32 |
33 | ///
34 | /// Maximum length of property.
35 | /// Value: 512.
36 | ///
37 | public const int MaxDataTypeNameLength = 512;
38 |
39 | ///
40 | /// Maximum length of property.
41 | /// Value: 512.
42 | ///
43 | public const int MaxEntityTypeNameLength = 512;
44 |
45 | ///
46 | /// Maximum length of property.
47 | /// Value: 512.
48 | ///
49 | public const int MaxEntityTypeAssemblyQualifiedNameLength = 512;
50 |
51 | ///
52 | /// Maximum length of property.
53 | /// Value: 256.
54 | ///
55 | public const int MaxEntityIdLength = 256;
56 |
57 | ///
58 | /// Maximum length of property.
59 | /// Value: 2,097,152 (2 MB).
60 | ///
61 | public const int MaxUserIdsLength = 2 * 1024 * 1024;
62 |
63 | ///
64 | /// Maximum length of property.
65 | /// Value: 1,048,576 (1 MB).
66 | ///
67 | public const int MaxTenantIdsLength = 1024 * 1024;
68 |
69 | ///
70 | /// Maximum length of property.
71 | /// Value: 4,194,304 (4 MB).
72 | ///
73 | public const int MaxLastExecutionResultLength = 4 * 1024 * 1024;
74 |
75 | ///
76 | /// Unique push request name.
77 | ///
78 | [Required]
79 | [MaxLength(MaxNameLength)]
80 | public virtual string Name { get; set; }
81 |
82 | ///
83 | /// Request data as JSON string.
84 | ///
85 | [MaxLength(MaxDataLength)]
86 | public virtual string Data { get; set; }
87 |
88 | ///
89 | /// Type of the JSON serialized .
90 | /// It's AssemblyQualifiedName of the type.
91 | ///
92 | [MaxLength(MaxDataTypeNameLength)]
93 | public virtual string DataTypeName { get; set; }
94 |
95 | ///
96 | /// Gets/sets entity type name, if this is an entity level push request.
97 | /// It's FullName of the entity type.
98 | ///
99 | [MaxLength(MaxEntityTypeNameLength)]
100 | public virtual string EntityTypeName { get; set; }
101 |
102 | ///
103 | /// AssemblyQualifiedName of the entity type.
104 | ///
105 | [MaxLength(MaxEntityTypeAssemblyQualifiedNameLength)]
106 | public virtual string EntityTypeAssemblyQualifiedName { get; set; }
107 |
108 | ///
109 | /// Gets/sets primary key of the entity, if this is an entity level push request.
110 | ///
111 | [MaxLength(MaxEntityIdLength)]
112 | public virtual string EntityId { get; set; }
113 |
114 | ///
115 | /// Target users of the request.
116 | /// If this is set, it overrides subscribed users.
117 | /// If this is null/empty, then push request is sent to all subscribed users.
118 | ///
119 | [MaxLength(MaxUserIdsLength)]
120 | public virtual string UserIds { get; set; }
121 |
122 | ///
123 | /// Excluded users.
124 | /// This can be set to exclude some users while publishing requests to subscribed users.
125 | /// It's not normally used if is not null.
126 | ///
127 | [MaxLength(MaxUserIdsLength)]
128 | public virtual string ExcludedUserIds { get; set; }
129 |
130 | ///
131 | /// Target tenants of the request.
132 | /// Used to send request to subscribed users of specific tenant(s).
133 | /// This is valid only if UserIds is null.
134 | /// If it's "0", then indicates to all tenants.
135 | ///
136 | [MaxLength(MaxTenantIdsLength)]
137 | public virtual string TenantIds { get; set; }
138 |
139 | ///
140 | /// Gets or sets the priority.
141 | ///
142 | /// The priority.
143 | public virtual PushRequestPriority Priority { get; set; }
144 |
145 | ///
146 | /// Gets or sets the expiration time.
147 | ///
148 | /// The expiration time.
149 | public virtual DateTime? ExpirationTime { get; set; }
150 |
151 | ///
152 | /// Gets or sets the max failed count.
153 | ///
154 | /// The max failed count.
155 | public virtual int? MaxFailedCount { get; set; }
156 |
157 | ///
158 | /// Gets or sets the failed count.
159 | ///
160 | /// The failed count.
161 | public virtual int FailedCount { get; set; }
162 |
163 | ///
164 | /// Gets or sets the last execution time.
165 | ///
166 | /// The last execution time.
167 | public virtual DateTime? LastExecutionTime { get; set; }
168 |
169 | ///
170 | /// Gets or sets the last execution result.
171 | ///
172 | /// The last execution result.
173 | [MaxLength(MaxLastExecutionResultLength)]
174 | public virtual string LastExecutionResult { get; set; }
175 |
176 | public PushRequest()
177 | {
178 | }
179 |
180 | ///
181 | /// Initializes a new instance of the class.
182 | ///
183 | public PushRequest(Guid id)
184 | {
185 | Id = id;
186 | Priority = PushRequestPriority.Normal;
187 | }
188 |
189 | ///
190 | /// Indicates all tenant ids for property.
191 | /// Value: "0".
192 | ///
193 | public const string AllTenantIdsString = "0";
194 |
195 | ///
196 | /// Indicates all tenants.
197 | ///
198 | public static int AllTenantIds = 0;
199 |
200 | public static string ToTenantIds(int?[] tenantIds)
201 | {
202 | if (tenantIds.IsNullOrEmpty())
203 | {
204 | return null;
205 | }
206 | return tenantIds.JoinAsString(",");
207 | }
208 |
209 | public static int?[] GetTenantIds(string tenantIdsString)
210 | {
211 | if (tenantIdsString.IsNullOrWhiteSpace())
212 | {
213 | return new int?[] { };
214 | }
215 |
216 | return tenantIdsString
217 | .Split(",")
218 | .Select(tenantIdAsStr => tenantIdAsStr == "null" ? (int?)null : (int?)tenantIdAsStr.To())
219 | .ToArray();
220 | }
221 | }
222 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Abp.Collections.Extensions;
4 | using Abp.Json;
5 |
6 | namespace Abp.Push.Requests
7 | {
8 | ///
9 | /// Used to store data for a push request.
10 | /// It can be directly used or can be derived.
11 | ///
12 | [Serializable]
13 | public class PushRequestData
14 | {
15 | ///
16 | /// Gets push request data type name.
17 | /// It returns the full class name by default.
18 | ///
19 | public virtual string Type => GetType().FullName;
20 |
21 | ///
22 | /// Shortcut to set/get .
23 | ///
24 | public object this[string key]
25 | {
26 | get { return Properties.GetOrDefault(key); }
27 | set { Properties[key] = value; }
28 | }
29 |
30 | ///
31 | /// Can be used to add custom properties to this request.
32 | ///
33 | public Dictionary Properties
34 | {
35 | get { return _properties; }
36 | set
37 | {
38 | if (value == null)
39 | {
40 | throw new ArgumentNullException(nameof(value));
41 | }
42 |
43 | /* Not assign value, but add dictionary items. This is required for backward compability. */
44 | foreach (var keyValue in value)
45 | {
46 | if (!_properties.ContainsKey(keyValue.Key))
47 | {
48 | _properties[keyValue.Key] = keyValue.Value;
49 | }
50 | }
51 | }
52 | }
53 | private readonly Dictionary _properties;
54 |
55 | ///
56 | /// Createa a new RequestData object.
57 | ///
58 | public PushRequestData()
59 | {
60 | _properties = new Dictionary();
61 | }
62 |
63 | public override string ToString()
64 | {
65 | // TODO: loop reference during serialization
66 | return this.ToJsonString();
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestDistributionJob.cs:
--------------------------------------------------------------------------------
1 | using Abp.BackgroundJobs;
2 | using Abp.Dependency;
3 | using Abp.Threading;
4 |
5 | namespace Abp.Push.Requests
6 | {
7 | ///
8 | /// This background job distributes push requests to users.
9 | ///
10 | public class PushRequestDistributionJob : BackgroundJob, ITransientDependency
11 | {
12 | private readonly IPushRequestDistributor _pushRequestDistributor;
13 |
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | public PushRequestDistributionJob(IPushRequestDistributor pushRequestDistributer)
18 | {
19 | _pushRequestDistributor = pushRequestDistributer;
20 | }
21 |
22 | public override void Execute(PushRequestDistributionJobArgs args)
23 | {
24 | AsyncHelper.RunSync(() => _pushRequestDistributor.DistributeAsync(args.PushRequestId));
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestDistributionJobArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Abp.Push.Requests
4 | {
5 | ///
6 | /// Arguments for .
7 | ///
8 | [Serializable]
9 | public class PushRequestDistributionJobArgs
10 | {
11 | ///
12 | /// Push Request Id.
13 | ///
14 | public Guid PushRequestId { get; set; }
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | public PushRequestDistributionJobArgs(Guid pushRequestId)
20 | {
21 | PushRequestId = pushRequestId;
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestEntityData.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace Abp.Push.Requests
5 | {
6 | [Serializable]
7 | public class PushRequestEntityData : PushRequestData
8 | {
9 | ///
10 | /// Converted from EntityTypeName
11 | ///
12 | [JsonProperty(PropertyName = "name", NullValueHandling = NullValueHandling.Ignore)]
13 | public string EntityName { get; set; }
14 |
15 | [JsonProperty(PropertyName = "id", NullValueHandling = NullValueHandling.Ignore)]
16 | public string EntityId { get; set; }
17 |
18 | [JsonProperty(PropertyName = "event", NullValueHandling = NullValueHandling.Ignore)]
19 | public string EntityEvent { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestPriority.cs:
--------------------------------------------------------------------------------
1 | namespace Abp.Push.Requests
2 | {
3 | public enum PushRequestPriority
4 | {
5 | RealTime,
6 | High,
7 | AboveNormal,
8 | Normal,
9 | BelowNormal,
10 | Low,
11 | Idle
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestPublisherExtensions.cs:
--------------------------------------------------------------------------------
1 | using Abp.Domain.Entities;
2 | using Abp.Threading;
3 |
4 | namespace Abp.Push.Requests
5 | {
6 | public static class PushRequestPublisherExtensions
7 | {
8 | ///
9 | /// Publishes a new push request.
10 | ///
11 | /// Push Request publisher
12 | /// Unique push request name
13 | /// Push request data (optional)
14 | /// The entity identifier if this push request is related to an entity
15 | /// Push request priority
16 | /// Target user id(s). Used to send push request to specific user(s). If this is null/empty, the notification is sent to all subscribed users
17 | public static void Publish(this IPushRequestPublisher pushRequestPublisher, string pushRequestName, PushRequestData data = null, EntityIdentifier entityIdentifier = null, PushRequestPriority priority = PushRequestPriority.Normal, IUserIdentifier[] userIds = null)
18 | {
19 | AsyncHelper.RunSync(() => pushRequestPublisher.PublishAsync(pushRequestName, data, entityIdentifier, priority, userIds));
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestSubscription.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel.DataAnnotations;
3 | using System.ComponentModel.DataAnnotations.Schema;
4 | using Abp.Domain.Entities;
5 | using Abp.Domain.Entities.Auditing;
6 | using Abp.Json;
7 |
8 | namespace Abp.Push.Requests
9 | {
10 | ///
11 | /// Used to store a push request subscription.
12 | ///
13 | [Table("AbpPushRequestSubscriptions")]
14 | public class PushRequestSubscription : CreationAuditedEntity, IMayHaveTenant
15 | {
16 | ///
17 | /// Tenant id of the subscribed user.
18 | ///
19 | public virtual int? TenantId { get; set; }
20 |
21 | ///
22 | /// User Id.
23 | ///
24 | public virtual long UserId { get; set; }
25 |
26 | ///
27 | /// Push request unique name.
28 | ///
29 | [MaxLength(PushRequest.MaxNameLength)]
30 | public virtual string PushRequestName { get; set; }
31 |
32 | ///
33 | /// Gets/sets entity type name, if this is an entity level push request.
34 | /// It's FullName of the entity type.
35 | ///
36 | [MaxLength(PushRequest.MaxEntityTypeNameLength)]
37 | public virtual string EntityTypeName { get; set; }
38 |
39 | ///
40 | /// AssemblyQualifiedName of the entity type.
41 | ///
42 | [MaxLength(PushRequest.MaxEntityTypeAssemblyQualifiedNameLength)]
43 | public virtual string EntityTypeAssemblyQualifiedName { get; set; }
44 |
45 | ///
46 | /// Gets/sets primary key of the entity, if this is an entity level push request.
47 | ///
48 | [MaxLength(PushRequest.MaxEntityIdLength)]
49 | public virtual string EntityId { get; set; }
50 |
51 | ///
52 | /// Initializes a new instance of the class.
53 | ///
54 | public PushRequestSubscription()
55 | {
56 | }
57 |
58 | ///
59 | /// Initializes a new instance of the class.
60 | ///
61 | public PushRequestSubscription(Guid id, int? tenantId, long userId, string pushRequestName, EntityIdentifier entityIdentifier = null)
62 | {
63 | Id = id;
64 | TenantId = tenantId;
65 | PushRequestName = pushRequestName;
66 | UserId = userId;
67 | EntityTypeName = entityIdentifier == null ? null : entityIdentifier.Type.FullName;
68 | EntityTypeAssemblyQualifiedName = entityIdentifier == null ? null : entityIdentifier.Type.AssemblyQualifiedName;
69 | EntityId = entityIdentifier == null ? null : entityIdentifier.Id.ToJsonString();
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/src/Abp.Push.Common/Push/Requests/PushRequestSubscriptionManagerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Abp.Domain.Entities;
3 | using Abp.Threading;
4 |
5 | namespace Abp.Push.Requests
6 | {
7 | public static class PushRequestSubscriptionManagerExtensions
8 | {
9 | ///
10 | /// Subscribes to a push request.
11 | ///
12 | /// Push request subscription manager
13 | /// User.
14 | /// Name of the push request.
15 | /// entity identifier
16 | public static void Subscribe(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null)
17 | {
18 | AsyncHelper.RunSync(() => pushRequestSubscriptionManager.SubscribeAsync(user, pushRequestName, entityIdentifier));
19 | }
20 |
21 | ///
22 | /// Subscribes to all available push requests for given user.
23 | /// It does not subscribe entity related push requests.
24 | ///
25 | /// Push request subscription manager
26 | /// User.
27 | public static void SubscribeToAllAvailablePushRequests(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, IUserIdentifier user)
28 | {
29 | AsyncHelper.RunSync(() => pushRequestSubscriptionManager.SubscribeToAllAvailablePushRequestsAsync(user));
30 | }
31 |
32 | ///
33 | /// Unsubscribes from a push request.
34 | ///
35 | /// Push request subscription manager
36 | /// User.
37 | /// Name of the push request.
38 | /// entity identifier
39 | public static void Unsubscribe(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, UserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null)
40 | {
41 | AsyncHelper.RunSync(() => pushRequestSubscriptionManager.UnsubscribeAsync(user, pushRequestName, entityIdentifier));
42 | }
43 |
44 | ///
45 | /// Gets all subscribtions for given push request.
46 | /// Can work only for single database approach
47 | ///
48 | /// Push request subscription manager
49 | /// Name of the push request.
50 | /// entity identifier
51 | public static List GetSubscriptions(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, string pushRequestName, EntityIdentifier entityIdentifier = null, int skipCount = 0, int maxResultCount = int.MaxValue)
52 | {
53 | return AsyncHelper.RunSync(() => pushRequestSubscriptionManager.GetSubscriptionsAsync(pushRequestName, entityIdentifier, skipCount, maxResultCount));
54 | }
55 |
56 | ///
57 | /// Gets all subscribtions for given push request.
58 | ///
59 | /// Push request subscription manager
60 | /// Tenant id. Null for the host.
61 | /// Name of the push request.
62 | /// entity identifier
63 | public static List GetSubscriptions(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, int? tenantId, string pushRequestName, EntityIdentifier entityIdentifier = null, int skipCount = 0, int maxResultCount = int.MaxValue)
64 | {
65 | return AsyncHelper.RunSync(() => pushRequestSubscriptionManager.GetSubscriptionsAsync(tenantId, pushRequestName, entityIdentifier, skipCount, maxResultCount));
66 | }
67 |
68 | ///
69 | /// Gets subscribed push requests for a user.
70 | ///
71 | /// Push request subscription manager
72 | /// User.
73 | public static List GetSubscribedPushRequests(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue)
74 | {
75 | return AsyncHelper.RunSync(() => pushRequestSubscriptionManager.GetSubscribedPushRequestsAsync(user, skipCount, maxResultCount));
76 | }
77 |
78 | ///
79 | /// Checks if a user subscribed for a push request.
80 | ///
81 | /// Push request subscription manager
82 | /// User.
83 | /// Name of the push request.
84 | /// entity identifier
85 | public static bool IsSubscribed(this IPushRequestSubscriptionManager pushRequestSubscriptionManager, IUserIdentifier user, string pushRequestName, EntityIdentifier entityIdentifier = null)
86 | {
87 | return AsyncHelper.RunSync(() => pushRequestSubscriptionManager.IsSubscribedAsync(user, pushRequestName, entityIdentifier));
88 | }
89 | }
90 | }
--------------------------------------------------------------------------------
/src/Abp.Push.EntityFrameworkCore/Abp.Push.EntityFrameworkCore.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | netstandard2.0
7 | Abp.Push.EntityFrameworkCore
8 | Abp.Push.EntityFrameworkCore
9 | Abp.Push.EntityFrameworkCore
10 | Abp
11 | false
12 | false
13 | false
14 | false
15 | false
16 | false
17 | true
18 | False
19 | Library
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/Abp.Push.EntityFrameworkCore/Abp.Push.EntityFrameworkCore.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Abp.Push.EntityFrameworkCore
5 | $version$
6 | $title$
7 | Ryancyq
8 | Ryancyq
9 | true
10 | Abp Push EntityFrameworkCore Module
11 | Summary of changes made in this release of the package.
12 | Copyright 2019
13 | netstandard2.0 asp.net mvc abp aspnetboilerplate
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Abp.Push.EntityFrameworkCore/Push/EntityFrameworkCore/AbpPushEntityFrameworkCoreConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Abp.Push.Devices;
3 | using Abp.Push.Requests;
4 |
5 | namespace Abp.Push.EntityFrameworkCore
6 | {
7 | public static class AbpPushEntityFrameworkCoreConfigurationExtensions
8 | {
9 | public static void ConfigurePushEntities(this ModelBuilder modelBuilder, string prefix = null, string schemaName = null)
10 | where TDevice : AbpPushDevice, new()
11 | {
12 | prefix = prefix ?? "Abp";
13 | modelBuilder.Entity(device =>
14 | {
15 | var tableName = prefix + "PushDevices";
16 | if (schemaName == null)
17 | {
18 | device.ToTable(tableName);
19 | }
20 | else
21 | {
22 | device.ToTable(tableName, schemaName);
23 | }
24 |
25 | device.HasIndex(e => new { e.TenantId, e.UserId });
26 | device.HasIndex(e => new { e.TenantId, e.DeviceIdentifier });
27 | device.HasIndex(e => new { e.TenantId, e.NormalizedDeviceName });
28 | device.HasIndex(e => new { e.TenantId, e.DevicePlatform });
29 | device.HasIndex(e => new { e.TenantId, e.ServiceProvider });
30 | });
31 |
32 | modelBuilder.Entity(request =>
33 | {
34 | var tableName = prefix + "PushRequests";
35 | if (schemaName == null)
36 | {
37 | request.ToTable(tableName);
38 | }
39 | else
40 | {
41 | request.ToTable(tableName, schemaName);
42 | }
43 |
44 | request.HasIndex(e => new { e.Name });
45 | request.HasIndex(e => new { e.CreationTime });
46 | request.HasIndex(e => new { e.ExpirationTime });
47 | });
48 |
49 | modelBuilder.Entity(subscription =>
50 | {
51 | var tableName = prefix + "PushRequestSubscriptions";
52 | if (schemaName == null)
53 | {
54 | subscription.ToTable(tableName);
55 | }
56 | else
57 | {
58 | subscription.ToTable(tableName, schemaName);
59 | }
60 |
61 | subscription.HasIndex(e => new { e.PushRequestName, e.EntityTypeName, e.EntityId, e.UserId });
62 | subscription.HasIndex(e => new { e.TenantId, e.PushRequestName, e.EntityTypeName, e.EntityId, e.UserId });
63 | });
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Abp.Push.EntityFrameworkCore/Push/EntityFrameworkCore/AbpPushEntityFrameworkCoreModule.cs:
--------------------------------------------------------------------------------
1 | using Abp.Modules;
2 | using Abp.Reflection.Extensions;
3 |
4 | namespace Abp.Push
5 | {
6 | [DependsOn(typeof(AbpPushModule))]
7 | public class AbpPushEntityFrameworkCoreModule : AbpModule
8 | {
9 | ///
10 | public override void PreInitialize()
11 | {
12 | }
13 |
14 | ///
15 | public override void Initialize()
16 | {
17 | IocManager.RegisterAssemblyByConvention(typeof(AbpPushEntityFrameworkCoreModule).GetAssembly());
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Abp.Push.EntityFrameworkCore/Push/EntityFrameworkCore/IAbpPushDbContext.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Abp.Push.Devices;
3 | using Abp.Push.Requests;
4 |
5 | namespace Abp.Push.EntityFrameworkCore
6 | {
7 | public interface IAbpPushDbContext where TDevice : AbpPushDevice, new()
8 | {
9 | DbSet PushDevices { get; set; }
10 |
11 | DbSet PushRequests { get; set; }
12 |
13 | DbSet PushRequestSubscriptions { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/Abp.Push/Abp.Push.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | netstandard2.0
7 | Abp Push
8 | Abp.Push
9 | Abp.Push
10 | Abp
11 | false
12 | false
13 | false
14 | false
15 | false
16 | false
17 | true
18 | False
19 | Library
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Abp.Push/Abp.Push.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Abp.Push
5 | $version$
6 | $title$
7 | Ryancyq
8 | Ryancyq
9 | true
10 | Abp Push Module
11 | Summary of changes made in this release of the package.
12 | Copyright 2019
13 | netstandard2.0 asp.net mvc abp aspnetboilerplate
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Abp.Push/Push/AbpPushModule.cs:
--------------------------------------------------------------------------------
1 | using Abp.Configuration.Startup;
2 | using Abp.Dependency;
3 | using Abp.Modules;
4 | using Abp.Push.Requests;
5 | using Abp.Reflection.Extensions;
6 |
7 | namespace Abp.Push
8 | {
9 | [DependsOn(typeof(AbpPushCommonModule))]
10 | public class AbpPushModule : AbpModule
11 | {
12 | ///
13 | public override void PreInitialize()
14 | {
15 | Configuration.ReplaceService(DependencyLifeStyle.Transient);
16 | }
17 |
18 | ///
19 | public override void Initialize()
20 | {
21 | IocManager.RegisterAssemblyByConvention(typeof(AbpPushModule).GetAssembly());
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Abp.Push/Push/Configuration/AbpPushModuleConfigurationExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Abp.Configuration.Startup;
3 | using Abp.Push.Requests;
4 | using Abp.Push.Devices;
5 |
6 | namespace Abp.Push.Configuration
7 | {
8 | public static class AbpPushModuleConfigurationExtensions
9 | {
10 | ///
11 | /// Configures persistent push request store.
12 | ///
13 | public static void ConfigStore(this IAbpPushConfiguration configuration, Action configureAction)
14 | {
15 | configureAction(configuration.AbpConfiguration.Modules.AbpPush().StoreConfiguration);
16 | }
17 |
18 | ///
19 | /// Configures persistent push store.
20 | ///
21 | public static void UsePersistentStore(this IAbpPushStoreConfiguration configuration)
22 | where TDevice : AbpPushDevice, new()
23 | {
24 | configuration.DeviceStore.UsePersistentStore();
25 | configuration.RequestStore.UsePersistentStore();
26 | }
27 |
28 | ///
29 | /// Configures persistent push device store.
30 | ///
31 | public static void UsePersistentStore(this IAbpPushRequestStoreConfiguration configuration)
32 | {
33 | configuration.AbpConfiguration.ReplaceService();
34 | }
35 |
36 | ///
37 | /// Configures persistent push device store.
38 | ///
39 | public static void UsePersistentStore(this IAbpPushDeviceStoreConfiguration configuration)
40 | where TDevice : AbpPushDevice, new()
41 | {
42 | configuration.AbpConfiguration.ReplaceService, AbpPersistentPushDeviceStore>();
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Abp.Push/Push/Devices/AbpPersistentPushDeviceStore.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using Abp.Domain.Repositories;
5 | using Abp.Domain.Uow;
6 | using Abp.Linq;
7 |
8 | namespace Abp.Push.Devices
9 | {
10 | ///
11 | /// Implements using repositories.
12 | ///
13 | public abstract class AbpPersistentPushDeviceStore : AbpServiceBase, IPushDeviceStore
14 | where TDevice : AbpPushDevice, new()
15 | {
16 | public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }
17 |
18 | protected readonly IRepository DeviceRepository;
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | protected AbpPersistentPushDeviceStore(
24 | IRepository deviceRepository)
25 | {
26 | DeviceRepository = deviceRepository;
27 | }
28 |
29 | [UnitOfWork]
30 | public virtual async Task DeleteDeviceAsync(TDevice device)
31 | {
32 | using (UnitOfWorkManager.Current.SetTenantId(device.TenantId))
33 | {
34 | await DeviceRepository.DeleteAsync(device);
35 | await UnitOfWorkManager.Current.SaveChangesAsync();
36 | }
37 | }
38 |
39 | [UnitOfWork]
40 | public virtual async Task DeleteDeviceAsync(IDeviceIdentifier deviceIdentifier)
41 | {
42 | using (UnitOfWorkManager.Current.SetTenantId(deviceIdentifier.TenantId))
43 | {
44 | await DeviceRepository.DeleteAsync(d => d.TenantId == deviceIdentifier.TenantId &&
45 | d.Id == deviceIdentifier.DeviceId);
46 | await UnitOfWorkManager.Current.SaveChangesAsync();
47 | }
48 | }
49 |
50 | [UnitOfWork]
51 | public virtual async Task DeleteDevicesByPlatformAsync(int? tenantId, string devicePlatform)
52 | {
53 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
54 | {
55 | await DeviceRepository.DeleteAsync(d => d.DevicePlatform == devicePlatform);
56 | await UnitOfWorkManager.Current.SaveChangesAsync();
57 | }
58 | }
59 |
60 | [UnitOfWork]
61 | public virtual async Task DeleteDevicesByProviderAsync(int? tenantId, string serviceProvider)
62 | {
63 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
64 | {
65 | await DeviceRepository.DeleteAsync(d => d.ServiceProvider == serviceProvider);
66 | await UnitOfWorkManager.Current.SaveChangesAsync();
67 | }
68 | }
69 |
70 | [UnitOfWork]
71 | public virtual async Task DeleteDevicesByProviderAsync(int? tenantId, string serviceProvider, string serviceProviderKey)
72 | {
73 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
74 | {
75 | await DeviceRepository.DeleteAsync(d => d.ServiceProvider == serviceProvider &&
76 | d.ServiceProviderKey == serviceProviderKey);
77 | await UnitOfWorkManager.Current.SaveChangesAsync();
78 | }
79 | }
80 |
81 | [UnitOfWork]
82 | public virtual async Task DeleteDevicesByUserAsync(IUserIdentifier userIdentifier)
83 | {
84 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
85 | {
86 | await DeviceRepository.DeleteAsync(d => d.UserId == userIdentifier.UserId);
87 | await UnitOfWorkManager.Current.SaveChangesAsync();
88 | }
89 | }
90 |
91 | [UnitOfWork]
92 | public virtual async Task DeleteDevicesByUserPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform)
93 | {
94 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
95 | {
96 | await DeviceRepository.DeleteAsync(d => d.UserId == userIdentifier.UserId &&
97 | d.DevicePlatform == devicePlatform);
98 | await UnitOfWorkManager.Current.SaveChangesAsync();
99 | }
100 | }
101 |
102 | [UnitOfWork]
103 | public virtual async Task DeleteDevicesByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider)
104 | {
105 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
106 | {
107 | await DeviceRepository.DeleteAsync(d => d.UserId == userIdentifier.UserId &&
108 | d.ServiceProvider == serviceProvider);
109 | await UnitOfWorkManager.Current.SaveChangesAsync();
110 | }
111 | }
112 |
113 | [UnitOfWork]
114 | public virtual async Task GetDeviceOrNullAsync(int? tenantId, string serviceProvider, string serviceProviderKey)
115 | {
116 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
117 | {
118 | return await DeviceRepository.FirstOrDefaultAsync(d => d.ServiceProvider == serviceProvider &&
119 | d.ServiceProviderKey == serviceProviderKey);
120 | }
121 | }
122 |
123 | [UnitOfWork]
124 | public virtual async Task GetUserDeviceOrNullAsync(IUserIdentifier userIdentifier, string serviceProvider, string serviceProviderKey)
125 | {
126 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
127 | {
128 | return await DeviceRepository.FirstOrDefaultAsync(d => d.UserId == userIdentifier.UserId &&
129 | d.ServiceProvider == serviceProvider &&
130 | d.ServiceProviderKey == serviceProviderKey);
131 | }
132 |
133 | }
134 |
135 | [UnitOfWork]
136 | public virtual async Task> GetDevicesAsync(int? tenantId, int? skipCount = null, int? maxResultCount = null)
137 | {
138 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
139 | {
140 | var query = DeviceRepository.GetAll();
141 | query = ApplySkipTake(query, skipCount, maxResultCount);
142 |
143 | return await AsyncQueryableExecuter.ToListAsync(query);
144 | }
145 | }
146 |
147 | [UnitOfWork]
148 | public virtual async Task> GetDevicesByPlatformAsync(int? tenantId, string devicePlatform, int? skipCount = null, int? maxResultCount = null)
149 | {
150 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
151 | {
152 | var query = DeviceRepository.GetAll();
153 | query = ApplyPlatform(query, devicePlatform);
154 | query = ApplySkipTake(query, skipCount, maxResultCount);
155 |
156 | return await AsyncQueryableExecuter.ToListAsync(query);
157 | }
158 | }
159 |
160 | [UnitOfWork]
161 | public virtual async Task> GetDevicesByProviderAsync(int? tenantId, string serviceProvider, int? skipCount = null, int? maxResultCount = null)
162 | {
163 | using (UnitOfWorkManager.Current.SetTenantId(tenantId))
164 | {
165 | var query = DeviceRepository.GetAll();
166 | query = ApplyProvider(query, serviceProvider);
167 | query = ApplySkipTake(query, skipCount, maxResultCount);
168 |
169 | return await AsyncQueryableExecuter.ToListAsync(query);
170 | }
171 | }
172 |
173 | [UnitOfWork]
174 | public virtual async Task> GetDevicesByUserAsync(IUserIdentifier userIdentifier, int? skipCount = null, int? maxResultCount = null)
175 | {
176 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
177 | {
178 | var query = DeviceRepository.GetAll();
179 | query = ApplyUser(query, userIdentifier);
180 | query = ApplySkipTake(query, skipCount, maxResultCount);
181 |
182 | return await AsyncQueryableExecuter.ToListAsync(query);
183 | }
184 | }
185 |
186 | [UnitOfWork]
187 | public virtual async Task> GetDevicesByUserPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform, int? skipCount = null, int? maxResultCount = null)
188 | {
189 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
190 | {
191 | var query = DeviceRepository.GetAll();
192 | query = ApplyPlatform(query, devicePlatform);
193 | query = ApplyUser(query, userIdentifier);
194 | query = ApplySkipTake(query, skipCount, maxResultCount);
195 |
196 | return await AsyncQueryableExecuter.ToListAsync(query);
197 | }
198 | }
199 |
200 | [UnitOfWork]
201 | public virtual async Task> GetDevicesByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider, int? skipCount = null, int? maxResultCount = null)
202 | {
203 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
204 | {
205 | var query = DeviceRepository.GetAll();
206 | query = ApplyProvider(query, serviceProvider);
207 | query = ApplyUser(query, userIdentifier);
208 | query = ApplySkipTake(query, skipCount, maxResultCount);
209 |
210 | return await AsyncQueryableExecuter.ToListAsync(query);
211 | }
212 | }
213 |
214 | [UnitOfWork]
215 | public virtual async Task GetDeviceCountByUserAsync(IUserIdentifier userIdentifier)
216 | {
217 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
218 | {
219 | var query = DeviceRepository.GetAll();
220 | query = ApplyUser(query, userIdentifier);
221 |
222 | return await AsyncQueryableExecuter.CountAsync(query);
223 | }
224 | }
225 |
226 | [UnitOfWork]
227 | public virtual async Task GetDeviceCountByUserPlatformAsync(IUserIdentifier userIdentifier, string devicePlatform)
228 | {
229 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
230 | {
231 | var query = DeviceRepository.GetAll();
232 | query = ApplyPlatform(query, devicePlatform);
233 | query = ApplyUser(query, userIdentifier);
234 |
235 | return await AsyncQueryableExecuter.CountAsync(query);
236 | }
237 | }
238 |
239 | [UnitOfWork]
240 | public virtual async Task GetDeviceCountByUserProviderAsync(IUserIdentifier userIdentifier, string serviceProvider)
241 | {
242 | using (UnitOfWorkManager.Current.SetTenantId(userIdentifier.TenantId))
243 | {
244 | var query = DeviceRepository.GetAll();
245 | query = ApplyProvider(query, serviceProvider);
246 | query = ApplyUser(query, userIdentifier);
247 |
248 | return await AsyncQueryableExecuter.CountAsync(query);
249 | }
250 | }
251 |
252 | [UnitOfWork]
253 | public virtual async Task InsertDeviceAsync(TDevice device)
254 | {
255 | using (UnitOfWorkManager.Current.SetTenantId(device.TenantId))
256 | {
257 | await DeviceRepository.InsertAsync(device);
258 | await UnitOfWorkManager.Current.SaveChangesAsync();
259 | }
260 | }
261 |
262 | [UnitOfWork]
263 | public virtual async Task InsertOrUpdateDeviceAsync(TDevice device)
264 | {
265 | using (UnitOfWorkManager.Current.SetTenantId(device.TenantId))
266 | {
267 | await DeviceRepository.InsertOrUpdateAsync(device);
268 | await UnitOfWorkManager.Current.SaveChangesAsync();
269 | }
270 | }
271 |
272 | [UnitOfWork]
273 | public virtual async Task UpdateDeviceAsync(TDevice device)
274 | {
275 | using (UnitOfWorkManager.Current.SetTenantId(device.TenantId))
276 | {
277 | await DeviceRepository.UpdateAsync(device);
278 | await UnitOfWorkManager.Current.SaveChangesAsync();
279 | }
280 | }
281 |
282 | protected virtual IQueryable ApplyUser(IQueryable query, IUserIdentifier userIdentifier)
283 | {
284 | return query.Where(d => d.UserId == userIdentifier.UserId);
285 | }
286 |
287 | protected virtual IQueryable ApplyPlatform(IQueryable query, string devicePlatform)
288 | {
289 | return query.Where(d => d.DevicePlatform == devicePlatform);
290 | }
291 |
292 | protected virtual IQueryable ApplyProvider(IQueryable query, string serviceProvider)
293 | {
294 | return query.Where(d => d.ServiceProvider == serviceProvider);
295 | }
296 |
297 | protected virtual IQueryable ApplyProviderIdentity(IQueryable query, string serviceProvider, string serviceProviderKey)
298 | {
299 | return ApplyProvider(query, serviceProvider).Where(pl => pl.ServiceProviderKey == serviceProviderKey);
300 | }
301 |
302 | protected virtual IQueryable ApplySkipTake(IQueryable query, int? skipCount, int? maxResultCount)
303 | {
304 | if (skipCount.HasValue)
305 | {
306 | query = query.Skip(skipCount.Value);
307 | }
308 |
309 | if (maxResultCount.HasValue)
310 | {
311 | query = query.Take(maxResultCount.Value);
312 | }
313 |
314 | return query;
315 | }
316 | }
317 | }
--------------------------------------------------------------------------------
/src/Abp.Push/Push/Requests/AbpInMemoryPushRequestStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Abp.Collections.Extensions;
7 | using Abp.Linq.Extensions;
8 |
9 | namespace Abp.Push.Requests
10 | {
11 | ///
12 | /// Implements using in memory storage (thread-safe).
13 | ///
14 | public class AbpInMemoryPushRequestStore : AbpServiceBase, IPushRequestStore
15 | {
16 | protected readonly ConcurrentDictionary> MultiTenantSubscriptions;
17 | // push request only defined on Host side
18 | protected readonly ConcurrentDictionary Requests;
19 | protected readonly IGuidGenerator GuidGenerator;
20 |
21 | // Set the initial capacity to some prime number above that, to ensure that
22 | // the ConcurrentDictionary does not need to be resized while initializing it.
23 | protected readonly int MultiTenancyInitialCapacity = 101;
24 | protected readonly int RequestInitialCapacity = 257;
25 | protected readonly int SubscriptionInitialCapacity = 1009;
26 |
27 | protected int TimeoutMiliseconds = 5000;
28 | protected readonly int ConcurrencyLevel;
29 |
30 | private readonly object _syncObj = new object();
31 |
32 | public AbpInMemoryPushRequestStore(IGuidGenerator guidGenerator)
33 | {
34 | GuidGenerator = guidGenerator;
35 |
36 | // The higher the concurrencyLevel, the higher the theoretical number of operations
37 | // that could be performed concurrently on the ConcurrentDictionary. However, global
38 | // operations like resizing the dictionary take longer as the concurrencyLevel rises.
39 | // For the purposes of this example, we'll compromise at numCores * 2.
40 | int numProcs = Environment.ProcessorCount;
41 | ConcurrencyLevel = numProcs * 2;
42 |
43 | // above is copied from https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=netcore-2.0
44 |
45 | Requests = new ConcurrentDictionary(ConcurrencyLevel, RequestInitialCapacity);
46 | MultiTenantSubscriptions = new ConcurrentDictionary>(ConcurrencyLevel, MultiTenancyInitialCapacity);
47 | }
48 |
49 | private ConcurrentDictionary CreateSubscriptionCollection()
50 | {
51 | return new ConcurrentDictionary(ConcurrencyLevel, SubscriptionInitialCapacity);
52 | }
53 |
54 | #region Subscriptions
55 |
56 | public virtual Task InsertSubscriptionAsync(PushRequestSubscription subscription)
57 | {
58 | var pushSubscriptions = MultiTenantSubscriptions.GetOrAdd(subscription.TenantId, CreateSubscriptionCollection());
59 | if (pushSubscriptions.ContainsKey(subscription.Id))
60 | {
61 | throw new AbpException(string.Format("Subscription {0} already exists", subscription.Id));
62 | }
63 |
64 | subscription.Id = GuidGenerator.Create();
65 | if (!pushSubscriptions.TryAdd(subscription.Id, subscription)){
66 | throw new AbpException(string.Format("Failed to insert subscription {0}:{1}", subscription.PushRequestName, subscription.Id));
67 | }
68 | return Task.CompletedTask;
69 | }
70 |
71 | public virtual Task DeleteSubscriptionAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId)
72 | {
73 | var pushSubscriptions = MultiTenantSubscriptions.GetOrAdd(user.TenantId, CreateSubscriptionCollection());
74 | var deleteSubscriptions = pushSubscriptions.Where(ps =>
75 | {
76 | var subscription = ps.Value;
77 | return ps.Value.TenantId == user.TenantId &&
78 | ps.Value.UserId == user.UserId &&
79 | ps.Value.PushRequestName == pushRequestName &&
80 | ps.Value.EntityTypeName == entityTypeName &&
81 | ps.Value.EntityId == entityId;
82 | }).Select(ps => ps.Key);
83 |
84 | foreach(var key in deleteSubscriptions){
85 | pushSubscriptions.TryRemove(key, out PushRequestSubscription subscription);
86 | }
87 | return Task.CompletedTask;
88 | }
89 |
90 | public virtual Task> GetSubscriptionsAsync(string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue)
91 | {
92 | var allPushSubscriptions = MultiTenantSubscriptions.Values;
93 | var subscriptions = allPushSubscriptions.SelectMany(dict =>
94 | {
95 | return dict.Values.Where(ps => ps.PushRequestName == pushRequestName &&
96 | ps.EntityTypeName == entityTypeName &&
97 | ps.EntityId == entityId);
98 | })
99 | .Skip(skipCount)
100 | .Take(maxResultCount)
101 | .ToList();
102 | return Task.FromResult(subscriptions);
103 | }
104 |
105 | public virtual Task> GetSubscriptionsAsync(int?[] tenantIds, string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue)
106 | {
107 | var tenantIdsList = new List();
108 | if (tenantIds != null && tenantIds.Length > 0)
109 | {
110 | tenantIdsList.AddRange(tenantIds);
111 | }
112 |
113 | var allPushSubscriptions = MultiTenantSubscriptions
114 | .Where(ms => tenantIdsList.Contains(ms.Key))
115 | .Select(ms => ms.Value);
116 | var subscriptions = allPushSubscriptions.SelectMany(dict =>
117 | {
118 | return dict.Values.Where(ps => ps.PushRequestName == pushRequestName &&
119 | ps.EntityTypeName == entityTypeName &&
120 | ps.EntityId == entityId);
121 | })
122 | .Skip(skipCount)
123 | .Take(maxResultCount)
124 | .ToList();
125 | return Task.FromResult(subscriptions);
126 | }
127 |
128 | public virtual Task> GetSubscriptionsAsync(IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue)
129 | {
130 | var pushSubscriptions = MultiTenantSubscriptions.GetOrAdd(user.TenantId, CreateSubscriptionCollection());
131 | var subscriptions = pushSubscriptions.Values
132 | .Skip(skipCount)
133 | .Take(maxResultCount)
134 | .ToList();
135 | return Task.FromResult(subscriptions);
136 | }
137 |
138 | public virtual Task IsSubscribedAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId)
139 | {
140 | var pushSubscriptions = MultiTenantSubscriptions.GetOrAdd(user.TenantId, CreateSubscriptionCollection());
141 | var hasSubscription = pushSubscriptions.Values
142 | .Any(ps => ps.UserId == user.UserId &&
143 | ps.PushRequestName == pushRequestName &&
144 | ps.EntityTypeName == entityTypeName &&
145 | ps.EntityId == entityId
146 | );
147 | return Task.FromResult(hasSubscription);
148 | }
149 |
150 | #endregion
151 |
152 | public virtual Task DeleteRequestAsync(Guid requestId)
153 | {
154 | Requests.TryRemove(requestId, out PushRequest request);
155 | return Task.CompletedTask;
156 | }
157 |
158 | public virtual Task InsertRequestAsync(PushRequest request)
159 | {
160 | if (Requests.ContainsKey(request.Id))
161 | {
162 | throw new AbpException(string.Format("Request {0} already exists", request.Id));
163 | }
164 |
165 | request.Id = GuidGenerator.Create();
166 | if (!Requests.TryAdd(request.Id, request))
167 | {
168 | throw new AbpException(string.Format("Failed to insert request {0}:{1}", request.Name, request.Id));
169 | }
170 | return Task.CompletedTask;
171 | }
172 |
173 | public virtual Task GetRequestOrNullAsync(Guid requestId)
174 | {
175 | if(Requests.TryGetValue(requestId, out PushRequest request)){
176 | return Task.FromResult(request);
177 | }
178 | return Task.FromResult(null as PushRequest);
179 | }
180 |
181 | public virtual Task> GetRequestsAsync(PushRequestPriority? priority = null, int skipCount = 0, int maxResultCount = int.MaxValue)
182 | {
183 | var requests = Requests.Values
184 | .WhereIf(priority.HasValue, pr => pr.Priority == priority.Value)
185 | .Skip(skipCount)
186 | .Take(maxResultCount)
187 | .ToList();
188 | return Task.FromResult(requests);
189 | }
190 |
191 | public virtual Task GethRequestCountAsync(PushRequestPriority? priority = null)
192 | {
193 | var requestCount = Requests.Values
194 | .WhereIf(priority.HasValue, pr => pr.Priority == priority.Value)
195 | .Count();
196 | return Task.FromResult(requestCount);
197 | }
198 |
199 | public virtual Task UpdateRequestPriorityAsync(Guid requestId, PushRequestPriority priority)
200 | {
201 | if (Requests.TryGetValue(requestId, out PushRequest request))
202 | {
203 | request.Priority = priority;
204 | Requests.AddOrUpdate(requestId, request, (key, oldValue) =>
205 | {
206 | oldValue.Priority = request.Priority;
207 | return oldValue;
208 | });
209 | }
210 | return Task.CompletedTask;
211 | }
212 | }
213 | }
--------------------------------------------------------------------------------
/src/Abp.Push/Push/Requests/AbpPersistentPushRequestStore.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Abp.Domain.Repositories;
6 | using Abp.Domain.Uow;
7 | using Abp.Linq;
8 | using Abp.Linq.Extensions;
9 |
10 | namespace Abp.Push.Requests
11 | {
12 | ///
13 | /// Implements using repositories.
14 | ///
15 | public class AbpPersistentPushRequestStore : AbpServiceBase, IPushRequestStore
16 | {
17 | public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }
18 |
19 | protected readonly IRepository RequestRepository;
20 | protected readonly IRepository SubscriptionRepository;
21 |
22 | public AbpPersistentPushRequestStore(
23 | IRepository pushRequestRepository,
24 | IRepository pushSubscriptionRepository
25 | )
26 | {
27 | RequestRepository = pushRequestRepository;
28 | SubscriptionRepository = pushSubscriptionRepository;
29 |
30 | AsyncQueryableExecuter = NullAsyncQueryableExecuter.Instance;
31 | }
32 |
33 | #region Subscriptions
34 |
35 | [UnitOfWork]
36 | public virtual async Task InsertSubscriptionAsync(PushRequestSubscription subscription)
37 | {
38 | using (UnitOfWorkManager.Current.SetTenantId(subscription.TenantId))
39 | {
40 | await SubscriptionRepository.InsertAsync(subscription);
41 | await UnitOfWorkManager.Current.SaveChangesAsync();
42 | }
43 | }
44 |
45 | [UnitOfWork]
46 | public virtual async Task DeleteSubscriptionAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId)
47 | {
48 | using (UnitOfWorkManager.Current.SetTenantId(user.TenantId))
49 | {
50 | await SubscriptionRepository.DeleteAsync(s =>
51 | s.UserId == user.UserId &&
52 | s.PushRequestName == pushRequestName &&
53 | s.EntityTypeName == entityTypeName &&
54 | s.EntityId == entityId
55 | );
56 | await UnitOfWorkManager.Current.SaveChangesAsync();
57 | }
58 | }
59 |
60 | [UnitOfWork]
61 | public virtual async Task> GetSubscriptionsAsync(string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue)
62 | {
63 | using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
64 | {
65 | var query = SubscriptionRepository.GetAll()
66 | .Where(s =>
67 | s.PushRequestName == pushRequestName &&
68 | s.EntityTypeName == entityTypeName &&
69 | s.EntityId == entityId
70 | );
71 | query = query.PageBy(skipCount, maxResultCount);
72 |
73 | return await AsyncQueryableExecuter.ToListAsync(query);
74 | }
75 | }
76 |
77 | [UnitOfWork]
78 | public virtual async Task> GetSubscriptionsAsync(int?[] tenantIds, string pushRequestName, string entityTypeName, string entityId, int skipCount = 0, int maxResultCount = int.MaxValue)
79 | {
80 | var tenantIdsList = new List();
81 | if (tenantIds != null && tenantIds.Length > 0)
82 | {
83 | tenantIdsList.AddRange(tenantIds);
84 | }
85 |
86 | using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
87 | {
88 | var query = SubscriptionRepository.GetAll()
89 | .Where(s =>
90 | tenantIdsList.Contains(s.TenantId) &&
91 | s.PushRequestName == pushRequestName &&
92 | s.EntityTypeName == entityTypeName &&
93 | s.EntityId == entityId
94 | );
95 | query = query.PageBy(skipCount, maxResultCount);
96 |
97 | return await AsyncQueryableExecuter.ToListAsync(query);
98 | }
99 | }
100 |
101 | [UnitOfWork]
102 | public virtual async Task> GetSubscriptionsAsync(IUserIdentifier user, int skipCount = 0, int maxResultCount = int.MaxValue)
103 | {
104 | using (UnitOfWorkManager.Current.SetTenantId(user.TenantId))
105 | {
106 | var query = SubscriptionRepository.GetAll()
107 | .Where(s => s.UserId == user.UserId);
108 | query = query.PageBy(skipCount, maxResultCount);
109 |
110 | return await AsyncQueryableExecuter.ToListAsync(query);
111 | }
112 | }
113 |
114 | [UnitOfWork]
115 | public virtual async Task IsSubscribedAsync(IUserIdentifier user, string pushRequestName, string entityTypeName, string entityId)
116 | {
117 | using (UnitOfWorkManager.Current.SetTenantId(user.TenantId))
118 | {
119 | return await SubscriptionRepository.CountAsync(s =>
120 | s.UserId == user.UserId &&
121 | s.PushRequestName == pushRequestName &&
122 | s.EntityTypeName == entityTypeName &&
123 | s.EntityId == entityId
124 | ) > 0;
125 | }
126 | }
127 |
128 | #endregion
129 |
130 | [UnitOfWork]
131 | public virtual async Task DeleteRequestAsync(Guid requestId)
132 | {
133 | // push request only defined on Host side
134 | using (UnitOfWorkManager.Current.SetTenantId(null))
135 | {
136 | await RequestRepository.DeleteAsync(requestId);
137 | await UnitOfWorkManager.Current.SaveChangesAsync();
138 | }
139 | }
140 |
141 | [UnitOfWork]
142 | public virtual async Task InsertRequestAsync(PushRequest request)
143 | {
144 | // push request only defined on Host side
145 | using (UnitOfWorkManager.Current.SetTenantId(null))
146 | {
147 | await RequestRepository.DeleteAsync(request);
148 | await UnitOfWorkManager.Current.SaveChangesAsync();
149 | }
150 | }
151 |
152 | [UnitOfWork]
153 | public virtual async Task GetRequestOrNullAsync(Guid requestId)
154 | {
155 | // push request only defined on Host side
156 | using (UnitOfWorkManager.Current.SetTenantId(null))
157 | {
158 | return await RequestRepository.FirstOrDefaultAsync(requestId);
159 | }
160 | }
161 |
162 | public virtual async Task> GetRequestsAsync(PushRequestPriority? priority = null, int skipCount = 0, int maxResultCount = int.MaxValue)
163 | {
164 | // push request only defined on Host side
165 | using (UnitOfWorkManager.Current.SetTenantId(null))
166 | {
167 | var query = RequestRepository.GetAll()
168 | .WhereIf(priority.HasValue, pr => pr.Priority == priority.Value);
169 | query = query.PageBy(skipCount, maxResultCount);
170 |
171 | return await AsyncQueryableExecuter.ToListAsync(query);
172 | }
173 | }
174 |
175 | public virtual async Task GethRequestCountAsync(PushRequestPriority? priority = null)
176 | {
177 | // push request only defined on Host side
178 | using (UnitOfWorkManager.Current.SetTenantId(null))
179 | {
180 | var query = RequestRepository.GetAll()
181 | .WhereIf(priority.HasValue, pr => pr.Priority == priority.Value);
182 |
183 | return await AsyncQueryableExecuter.CountAsync(query);
184 | }
185 | }
186 |
187 | [UnitOfWork]
188 | public virtual async Task UpdateRequestPriorityAsync(Guid requestId, PushRequestPriority priority)
189 | {
190 | // push request only defined on Host side
191 | using (UnitOfWorkManager.Current.SetTenantId(null))
192 | {
193 | var pushRequest = await RequestRepository.FirstOrDefaultAsync(requestId);
194 | if (pushRequest == null)
195 | {
196 | return;
197 | }
198 |
199 | pushRequest.Priority = priority;
200 | await UnitOfWorkManager.Current.SaveChangesAsync();
201 | }
202 | }
203 | }
204 | }
--------------------------------------------------------------------------------
/test/Abp.Push.Tests/Abp.Push.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net461;net5.0
4 | net5.0
5 | Abp.Push.Tests
6 | Abp.Push.Tests
7 | true
8 | false
9 | false
10 | false
11 | false
12 | false
13 | false
14 | true
15 | true
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | all
27 | runtime; build; native; contentfiles; analyzers
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/test/Abp.Push.Tests/Push/PushRequestDistributor_Tests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Abp.Configuration;
5 | using Abp.Dependency;
6 | using Abp.Domain.Uow;
7 | using Abp.Push;
8 | using Abp.Push.Configuration;
9 | using Abp.Push.Providers;
10 | using Abp.Push.Requests;
11 | using NSubstitute;
12 | using Xunit;
13 |
14 | namespace Abp.Tests.Push
15 | {
16 | public class PushRequestDistributor_Tests : TestBaseWithLocalIocManager
17 | {
18 | private readonly IPushRequestStore _store;
19 | private readonly IPushDefinitionManager _definitionManager;
20 | private readonly IAbpPushConfiguration _configuration;
21 | private readonly IIocResolver _iocResolver;
22 | private readonly IGuidGenerator _generator;
23 | private readonly AbpPushRequestDistributor _distributor;
24 |
25 | public PushRequestDistributor_Tests()
26 | {
27 | _store = Substitute.For();
28 | _definitionManager = Substitute.For();
29 | _configuration = Substitute.For();
30 | _configuration.ServiceProviders.Returns(new List());
31 | _iocResolver = Substitute.For();
32 | _generator = Substitute.For();
33 | _distributor = new AbpPushRequestDistributor(
34 | _store,
35 | _definitionManager,
36 | _configuration,
37 | _iocResolver,
38 | _generator
39 | );
40 | _distributor.UnitOfWorkManager = Substitute.For();
41 | _distributor.UnitOfWorkManager.Current.Returns(Substitute.For());
42 |
43 | var _settingManager = Substitute.For();
44 | _settingManager.GetSettingValueForUser(Arg.Any(), Arg.Any(), Arg.Any())
45 | .Returns("true");
46 | _distributor.SettingManager = _settingManager;
47 | }
48 |
49 | [Fact]
50 | public async Task Should_Distribute_Push_Request()
51 | {
52 | //Arrange
53 | var guid = _generator.Create();
54 | _store.GetRequestOrNullAsync(Arg.Any()).ReturnsForAnyArgs(CreatePushRequest());
55 | _store.GetSubscriptionsAsync(Arg.Any(), Arg.Any(), Arg.Any())
56 | .ReturnsForAnyArgs(new List { CreatePushRequestSubscription() });
57 |
58 | //Act
59 | await _distributor.DistributeAsync(guid);
60 |
61 | //Assert
62 | await _store.Received().GetRequestOrNullAsync(Arg.Any());
63 | await _store.Received().DeleteRequestAsync(Arg.Is(n => n.Equals(guid)));
64 | }
65 |
66 | private static PushRequest CreatePushRequest()
67 | {
68 | return new PushRequest
69 | {
70 | UserIds = "1,2,3"
71 | };
72 | }
73 |
74 | private static PushRequestSubscription CreatePushRequestSubscription()
75 | {
76 | return new PushRequestSubscription();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/test/Abp.Push.Tests/Push/PushRequestPublisher_Tests.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Abp.BackgroundJobs;
3 | using Abp.Domain.Uow;
4 | using Abp.Push.Configuration;
5 | using Abp.Push.Requests;
6 | using NSubstitute;
7 | using Xunit;
8 |
9 | namespace Abp.Tests.Push
10 | {
11 | public class PushRequestPublisher_Tests : TestBaseWithLocalIocManager
12 | {
13 | private readonly IPushRequestStore _store;
14 | private readonly IBackgroundJobManager _backgroundJobManager;
15 | private readonly IPushRequestDistributor _distributor;
16 | private readonly IAbpPushConfiguration _configuration;
17 | private readonly IGuidGenerator _generator;
18 | private readonly AbpPushRequestPublisher _publisher;
19 |
20 | public PushRequestPublisher_Tests()
21 | {
22 | _store = Substitute.For();
23 | _backgroundJobManager = Substitute.For();
24 | _distributor = Substitute.For();
25 | _configuration = Substitute.For();
26 | _generator = Substitute.For();
27 | _publisher = new AbpPushRequestPublisher(
28 | _store,
29 | _backgroundJobManager,
30 | _distributor,
31 | _configuration,
32 | _generator
33 | );
34 | _publisher.UnitOfWorkManager = Substitute.For();
35 | _publisher.UnitOfWorkManager.Current.Returns(Substitute.For());
36 | }
37 |
38 | [Fact]
39 | public async Task Should_Publish_Push_Request()
40 | {
41 | //Arrange
42 | var pushRequestData = CreatePushRequestData();
43 |
44 | //Act
45 | await _publisher.PublishAsync("TestPushRequest", pushRequestData, priority: PushRequestPriority.AboveNormal);
46 |
47 | //Assert
48 | await _store.Received()
49 | .InsertRequestAsync(
50 | Arg.Is(n =>
51 | n.Name == "TestPushRequest" &&
52 | n.Priority == PushRequestPriority.AboveNormal &&
53 | n.DataTypeName == pushRequestData.GetType().AssemblyQualifiedName &&
54 | n.Data.Contains("42")
55 | )
56 | );
57 |
58 | await _backgroundJobManager.Received()
59 | .EnqueueAsync(
60 | Arg.Any()
61 | );
62 | }
63 |
64 | private static PushRequestData CreatePushRequestData()
65 | {
66 | var pushRequestData = new PushRequestData();
67 | pushRequestData["TestValue"] = 42;
68 | return pushRequestData;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/test/Abp.Push.Tests/TestBaseWithLocalIocManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Abp.Dependency;
3 |
4 | namespace Abp.Tests
5 | {
6 | public abstract class TestBaseWithLocalIocManager : IDisposable
7 | {
8 | protected IIocManager LocalIocManager;
9 |
10 | protected TestBaseWithLocalIocManager()
11 | {
12 | LocalIocManager = new IocManager();
13 | }
14 |
15 | public virtual void Dispose()
16 | {
17 | LocalIocManager.Dispose();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/tools/gitlink/GitLink.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryancyq/abp-push/50edc82781ae750a9ebdcfd3b033114edada58c4/tools/gitlink/GitLink.exe
--------------------------------------------------------------------------------
/tools/nuget/nuget.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryancyq/abp-push/50edc82781ae750a9ebdcfd3b033114edada58c4/tools/nuget/nuget.exe
--------------------------------------------------------------------------------