Compare commits
523 Commits
v1.2.0725.2249
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d1aee95d35 | |||
| 72a709c11d | |||
| 4f7f6db804 | |||
| 892299a791 | |||
| 48512fa9d1 | |||
| 204d57a4a5 | |||
| f807d75162 | |||
| e809c63e37 | |||
| e1f1973520 | |||
| 71fa53bfb2 | |||
| 834d2f8fae | |||
| 2ab765f2d7 | |||
| 04be92a1df | |||
| 4e7c7c117b | |||
| f975c55b8a | |||
| 9e0d832aa1 | |||
| 94a31282eb | |||
| 529bba5c72 | |||
| 8424a9a9a2 | |||
| 202bbb163b | |||
| 0e15d2a880 | |||
| 89c14084f5 | |||
| e2c07f019c | |||
| 7603cac01a | |||
| 356762c811 | |||
| deaac0f073 | |||
| de10f92c02 | |||
| 3e514fdf9a | |||
| 36c24542e1 | |||
| ca7193a8fc | |||
| 676ff82e4b | |||
| 53fdea5325 | |||
| 0c0a7bf297 | |||
| 57aeaa3eaa | |||
| d291ad464f | |||
| be7ee4cae8 | |||
| 7deead494b | |||
| fd43d85778 | |||
| 4c27b0ff3c | |||
| 58546ed16d | |||
| 9656c15c4b | |||
| 1add4ee0f5 | |||
| 5792771ea1 | |||
| 49da389c2c | |||
| 7faebe56a8 | |||
| 4e518d6684 | |||
| b4e54c9edf | |||
| 3aeb9374a9 | |||
| 0905a02aea | |||
| f8fd1a58a3 | |||
| 2184c9e22e | |||
| 42e9045d5e | |||
| 092c6249ee | |||
| b56e82d5c4 | |||
| 54a578f4a1 | |||
| 3f1fa3d7de | |||
| caa0bedc93 | |||
| 6e99b4503b | |||
| 583552ffdd | |||
| 4660425ccc | |||
| 8b8b26116e | |||
| 57ae665070 | |||
| f06a37ebb4 | |||
| ee273ffe03 | |||
| 0672bdb7c0 | |||
| 662e1ed231 | |||
| cc1f224456 | |||
| 6e2c36d4ae | |||
| bccbb20b84 | |||
| fd3eb80648 | |||
| 9a171a8417 | |||
| eb1ffae212 | |||
| d31c2db43b | |||
| 62a5da7513 | |||
| eb3ed7f819 | |||
| a9687b5f25 | |||
| 539503133a | |||
| d2b5e7ab6a | |||
| 04430bba50 | |||
| 162ca20046 | |||
| 786d4809b5 | |||
| d3cef11796 | |||
| 2c215e4856 | |||
| eec8ba438c | |||
| 59dc0b9d5a | |||
| ac24055365 | |||
| 2fce645066 | |||
| 67f1c2a5d1 | |||
| f946f3250c | |||
| 0853bcee50 | |||
| 408e1c4c14 | |||
| dee54bb6d7 | |||
| 50603210b0 | |||
| b640e51874 | |||
| 7a336e699a | |||
| a3e1e1d030 | |||
| 963970feeb | |||
| 296f7a13fd | |||
| 4006bdbcc6 | |||
| 26bac92e5a | |||
| b6dfaa3445 | |||
| 39ba206831 | |||
| 7550e0e45d | |||
| 9f10eeeb70 | |||
| 77acf0bfdb | |||
| f0dfe45cd4 | |||
| fb6432a5c8 | |||
| b15917254f | |||
| 8abe31f430 | |||
| a6b9cd1af2 | |||
| 90c709c4c1 | |||
| 25e3a8e1f1 | |||
| 343f20980d | |||
| f36871abe2 | |||
| cb354cd13e | |||
| 09f9f2d427 | |||
| 390857e065 | |||
| e0d620bf67 | |||
| 78b7b059ea | |||
| bb846d14c5 | |||
| 565e1707ce | |||
| a675e4a6e9 | |||
| d8eb8fec83 | |||
| f90eda4101 | |||
| 37e2e5a08c | |||
| 6af83cbdb2 | |||
| 5f4cb20900 | |||
| aee467cb53 | |||
| 6ce6e2cccf | |||
| cd858c2215 | |||
| 7e07c07171 | |||
| 15e2806731 | |||
| 53baf4eb78 | |||
| 8c48ab6ecd | |||
| 8afe4195a9 | |||
| dcc4fcb984 | |||
| 4631903019 | |||
| 85d51c0e45 | |||
| 974a07f3bb | |||
| b576aec641 | |||
| a2aaa4c913 | |||
| 318a70d9a3 | |||
| 53e57d4017 | |||
| 143dc1b3e6 | |||
| a4f18d1d49 | |||
| 46222f2a78 | |||
| 2e091383ec | |||
| 7ace4d1c7e | |||
| f901d45d78 | |||
| 028d1ccc64 | |||
| 7b6a44921d | |||
| 23406e5e39 | |||
| 83557e6f0c | |||
| 1c90c89158 | |||
| 9924153e82 | |||
| 3ec2ea7d37 | |||
| b6945d9bbd | |||
| 6740a7479a | |||
| a3fb09440d | |||
| 7353405b16 | |||
| 6fcb1a1eae | |||
| e204ea4d5f | |||
| 0a4a2816a0 | |||
| 473b02f718 | |||
| 5a2c29ea0b | |||
| 1a8ec32f0f | |||
| 9e7daf2043 | |||
| 0c690cff5a | |||
| b55b77de9f | |||
| 937508c440 | |||
| cfe4c4b912 | |||
| d75663a219 | |||
| 1e24844e88 | |||
| 273b67c422 | |||
| 13549e7ec4 | |||
| bbb40bd5c4 | |||
| 22dad072b9 | |||
| 215e9863a2 | |||
| 190abc72dd | |||
| af75a55d44 | |||
| e05206d405 | |||
| 53eed02a4f | |||
| 57a7f67c3a | |||
| 47e11c0fd6 | |||
| 708ca16de8 | |||
| 535a3f2967 | |||
| ebd1c79f64 | |||
| 7194dd612d | |||
| 584bc07824 | |||
| 2bd9238090 | |||
| b11fa5b1d6 | |||
| 7667eaa49e | |||
| 9f7c0f965e | |||
| a274a33cf6 | |||
| 4acfd54319 | |||
| 941f1cf13e | |||
| f225edd2d4 | |||
| 5824680e2a | |||
| ed4ec890da | |||
| 56453fa081 | |||
| 11c824518f | |||
| d720303a83 | |||
| 02b29948ce | |||
| a152365312 | |||
| dba6c383f6 | |||
| ba32b3b717 | |||
| 51cebd0706 | |||
| 983bdbefb9 | |||
| be99083d6a | |||
| 4c19a1ef63 | |||
| 4f9f0fd0a8 | |||
| 05593a1466 | |||
| 2873b4be8a | |||
| 7a1ff211a0 | |||
| fcf70f724e | |||
| 99be87ed9c | |||
| 261baf669e | |||
| b0fddd491b | |||
| dff47c0e8b | |||
| ed58619919 | |||
| 2a2731b9f3 | |||
| 13e666d95a | |||
| 96cccab958 | |||
| e463a7361e | |||
| 58e467b6d6 | |||
| 81bd6ccd83 | |||
| 3e7db6b552 | |||
| 09a6369693 | |||
| 9bfeff8c42 | |||
| 3e57af394d | |||
| e11d0871c4 | |||
| f7fdfb0c8a | |||
| 806aadd161 | |||
| af4a94870e | |||
| 486ce17857 | |||
| f82b47dd46 | |||
| f1d27732c7 | |||
| 28e5901929 | |||
| e531ffe2b7 | |||
| 4fca015afa | |||
| a80ed14038 | |||
| f3e0939a06 | |||
| 2cd6ddfa24 | |||
| b4a30061e3 | |||
| cb033c0b70 | |||
| 3c197e7b2f | |||
| 9f62da9ccd | |||
| df721d7d6e | |||
| 8278efb9a6 | |||
| d477ad5d9c | |||
| 0755b6fc8a | |||
| 78dd494304 | |||
| 0497e145ea | |||
| 4d6aa18095 | |||
| fdf1bd4bc6 | |||
| 82183f6508 | |||
| d6ee70b860 | |||
| 5ce9e51ae7 | |||
| ed66f4f285 | |||
| 526f8547f7 | |||
| d8e93cb31b | |||
| 5fa74a8cc0 | |||
| a0d643eda1 | |||
| 0887eb447e | |||
| d9cade74b6 | |||
| 67261cd5b8 | |||
| aca037ecf8 | |||
| ef8df08e29 | |||
| 4c91d03385 | |||
| b52cbcb94a | |||
| 065b14b158 | |||
| cbf16a41a6 | |||
| f74d49b96e | |||
| afa548fb70 | |||
| c72c18e825 | |||
| 6df2e16a7f | |||
| 3e4dda683d | |||
| dc8a5ab806 | |||
| 0f20b16f41 | |||
| 23975f8fc3 | |||
| 062769a7e3 | |||
| 1dfa3f4f15 | |||
| e082c22983 | |||
| b286f8473a | |||
| 0a67e9544d | |||
| 687713428b | |||
| aeb9eb4d3a | |||
| 9baca7f633 | |||
| 5fcb81e9e8 | |||
| 3c521541fd | |||
| 669de7e46b | |||
| a15f3daad5 | |||
| 86faf02cf0 | |||
| 27c21175d7 | |||
| 489a5df7cc | |||
| 85425d2a1f | |||
| 4b866c9486 | |||
| acfa0e5094 | |||
| 5ea9a814d6 | |||
| 44f6d325db | |||
| 4e6093702d | |||
| d955addc26 | |||
| dee347128e | |||
| d6de5e5958 | |||
| 80f7cd0275 | |||
| 538fd2e394 | |||
| ad5aea6df2 | |||
| b070283270 | |||
| 6a017c7be9 | |||
| 6fe8d9c8e0 | |||
| 7eb17a91c9 | |||
| d2acf31b81 | |||
| 50399f4f48 | |||
| 23db0b6111 | |||
| a7b3f045d6 | |||
| 76318d8d00 | |||
| f2ac35a7fa | |||
| b1575fa321 | |||
| 4283b62803 | |||
| 7551b39b8e | |||
| 3ae99f45bb | |||
| c846fa053a | |||
| 57c2e062fc | |||
| e940c24522 | |||
| 73d6160db6 | |||
| 13c5efe5d6 | |||
| bbe4cccc91 | |||
| 41e061df54 | |||
| 35a07344cc | |||
| 4b6604df5b | |||
| 0de162fce3 | |||
| f26474fa4d | |||
| 8e2a17cfc5 | |||
| 3b0286fe11 | |||
| 12fc071786 | |||
| 1d931463a8 | |||
| f01bc940f6 | |||
| ea80876286 | |||
| 7062a40dfb | |||
| 2d8dcb6900 | |||
| 3358d9e320 | |||
| 1cc7e94646 | |||
| c528a2be26 | |||
| a43db01b96 | |||
| b78ce003a7 | |||
| 81d024618a | |||
| 4d8fec2ced | |||
| 7cbed23a74 | |||
| 6700d092b3 | |||
| 4b3905b4fc | |||
| 09b1c93bf0 | |||
| 5c5e5a23a2 | |||
| 9bfa95e263 | |||
| 2274e2201d | |||
| f4394fe2a0 | |||
| 5ba9fde10f | |||
| 67a624d5b5 | |||
| 0b79140290 | |||
| 5013fa27bd | |||
| 83e9b7a832 | |||
| a3a92245ae | |||
| 045fb0b65d | |||
| 304ffd7ee1 | |||
| 8b74dbabf5 | |||
| 7f8ed7e752 | |||
| 84a4ba281f | |||
| 34842012b7 | |||
| a819d2722a | |||
| ebf78dd08d | |||
| 6186237028 | |||
| 513397779d | |||
| 815216fd73 | |||
| 8254e7ec5a | |||
| 4c3a68da30 | |||
| b64ac3b16f | |||
| d040ab094c | |||
| a0e18ef963 | |||
| 830a9c8d05 | |||
| ea51ba1f88 | |||
| 5510d34885 | |||
| be25569245 | |||
| 7af6a2220c | |||
| 4cd57f4a90 | |||
| f6fae26bc7 | |||
| 7cad69598f | |||
| 4e69253852 | |||
| 825627e345 | |||
| e9042f7666 | |||
| 6a45348bdb | |||
| f3351af9e8 | |||
| a5e38406d1 | |||
| 3c759ac4d7 | |||
| f70261aa25 | |||
| 3fdb4f1053 | |||
| 53ca13c7f4 | |||
| 185c4682f0 | |||
| 39c3bf9fc7 | |||
| c87ee6a0e7 | |||
| 4a08c8c275 | |||
| fb6067afc3 | |||
| 6b2cd47610 | |||
| 392de396df | |||
| 3cf6d5475d | |||
| 74df073b29 | |||
| 09c2a24222 | |||
| 43fc622121 | |||
| b8ec44293f | |||
| 36100bfef5 | |||
| b77bdf16f5 | |||
| 5aede7153c | |||
| 4fc6c3ca9f | |||
| d86280ae3e | |||
| 2281313966 | |||
| 740e806ef0 | |||
| f35f9d3661 | |||
| 201acc1976 | |||
| a4f4b7d0b3 | |||
| 41dc002ef8 | |||
| e984221c95 | |||
| 3238a916a2 | |||
| db73cc1a12 | |||
| b841c6b2c0 | |||
| 69091e0785 | |||
| 3d5f71aba9 | |||
| da166e5cd2 | |||
| 74775e9e3d | |||
| 96c5860080 | |||
| 6ac87633ac | |||
| 0db43d9200 | |||
| a82e039140 | |||
| bfa3bf1e94 | |||
| 5be747afbc | |||
| ed7caf8b4a | |||
| 7027b33fe2 | |||
| 68256d7abd | |||
| 2ac3a9bdd3 | |||
| a6a65c54c7 | |||
| 7bdbeb6a82 | |||
| c4cc54d316 | |||
| 3ae657f2ba | |||
| 2e7b66ee5b | |||
| 6d54f3f972 | |||
| cd31ba4a6c | |||
| 9ea0273936 | |||
| 7748f15d76 | |||
| eea71e6eb0 | |||
| 3bc8b63700 | |||
| 6bacf6e3a5 | |||
| cc4682875b | |||
| bfcbcf9da2 | |||
| ad28729a85 | |||
| 3f63281dc4 | |||
| bdb3e1e6b4 | |||
| 10394c4e39 | |||
| 2ddf4b7bd9 | |||
| 35391ad1a1 | |||
| ab553a05cb | |||
| 20263905f9 | |||
| f1ee2937cd | |||
| ec118a3395 | |||
| 551b1d3a41 | |||
| 214ecf6212 | |||
| fad8eae9f4 | |||
| 2dd3f5f9ab | |||
| 8ace60f10d | |||
| 136c371b01 | |||
| a5c051916e | |||
| 4f4dbabf8b | |||
| e4c86f1cc1 | |||
| eabd9671f0 | |||
| 9b34abfa29 | |||
| d1007266c9 | |||
| 230b1af9f7 | |||
| fe00963cb0 | |||
| b1048588e7 | |||
| 9ac487e7e0 | |||
| 404d5c9120 | |||
| 1cbbf1dde4 | |||
| a63041abf2 | |||
| bd4f0bd9a7 | |||
| bc08bd7dc2 | |||
| d8fc45ee6f | |||
| fce371231c | |||
| 76aead2011 | |||
| df633b3591 | |||
| 94c7cae443 | |||
| 10a38af08b | |||
| c13d13c91c | |||
| 7096a511c3 | |||
| 233d62442c | |||
| 723eeec91e | |||
| 0d60fb422c | |||
| cc218a08e4 | |||
| 401ae029f1 | |||
| 4dfe9ad086 | |||
| 5f9a49bca3 | |||
| faee1e724e | |||
| d6859dcde4 | |||
| fdb5d37ec8 | |||
| 51ebc673e7 | |||
| 017b1435d8 | |||
| 7b62eabeee | |||
| d8c4d13def | |||
| 9784c5d282 | |||
| 4b822d3ae3 | |||
| 24751780cc | |||
| 4d19e381fd | |||
| ec74039400 | |||
| a099d68915 | |||
| 172ce5524a | |||
| 2ad4cd2080 | |||
| 2e820cd720 | |||
| 75ebfdaa80 | |||
| 122f719e3b | |||
| 60f7384c97 | |||
| 02b91f1ea4 | |||
| d0aea2401b | |||
| 29a6057443 | |||
| f3efa56750 | |||
| 090322126a | |||
| d8538d2792 | |||
| 37810656fd | |||
| 3596d325eb |
@@ -0,0 +1,4 @@
|
|||||||
|
[*.cs]
|
||||||
|
|
||||||
|
# VSSpell001: Spell Check
|
||||||
|
dotnet_diagnostic.VSSpell001.severity = suggestion
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<solution>
|
|
||||||
<add key="disableSourceControlIntegration" value="true" />
|
|
||||||
</solution>
|
|
||||||
</configuration>
|
|
||||||
Binary file not shown.
@@ -1,153 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
|
|
||||||
|
|
||||||
<!-- Enable the restore command to run before builds -->
|
|
||||||
<RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
|
|
||||||
|
|
||||||
<!-- Property that enables building a package from a project -->
|
|
||||||
<BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
|
|
||||||
|
|
||||||
<!-- Determines if package restore consent is required to restore packages -->
|
|
||||||
<RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
|
|
||||||
|
|
||||||
<!-- Download NuGet.exe if it does not already exist -->
|
|
||||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition=" '$(PackageSources)' == '' ">
|
|
||||||
<!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
|
|
||||||
<!-- The official NuGet package source (https://nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
|
|
||||||
<!--
|
|
||||||
<PackageSource Include="https://nuget.org/api/v2/" />
|
|
||||||
<PackageSource Include="https://my-nuget-source/nuget/" />
|
|
||||||
-->
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
|
|
||||||
<!-- Windows specific commands -->
|
|
||||||
<NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
|
|
||||||
<PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
|
|
||||||
<PackagesDir>$([System.IO.Path]::Combine($(SolutionDir), "packages"))</PackagesDir>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
|
|
||||||
<!-- We need to launch nuget.exe with the mono command if we're not on windows -->
|
|
||||||
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
|
|
||||||
<PackagesConfig>packages.config</PackagesConfig>
|
|
||||||
<PackagesDir>$(SolutionDir)packages</PackagesDir>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- NuGet command -->
|
|
||||||
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\nuget.exe</NuGetExePath>
|
|
||||||
<PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
|
|
||||||
|
|
||||||
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
|
|
||||||
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
|
|
||||||
|
|
||||||
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
|
|
||||||
|
|
||||||
<RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
|
|
||||||
<!-- Commands -->
|
|
||||||
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(RequireConsentSwitch) -o "$(PackagesDir)"</RestoreCommand>
|
|
||||||
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols</BuildCommand>
|
|
||||||
|
|
||||||
<!-- We need to ensure packages are restored prior to assembly resolve -->
|
|
||||||
<ResolveReferencesDependsOn Condition="$(RestorePackages) == 'true'">
|
|
||||||
RestorePackages;
|
|
||||||
$(ResolveReferencesDependsOn);
|
|
||||||
</ResolveReferencesDependsOn>
|
|
||||||
|
|
||||||
<!-- Make the build depend on restore packages -->
|
|
||||||
<BuildDependsOn Condition="$(BuildPackage) == 'true'">
|
|
||||||
$(BuildDependsOn);
|
|
||||||
BuildPackage;
|
|
||||||
</BuildDependsOn>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<Target Name="CheckPrerequisites">
|
|
||||||
<!-- Raise an error if we're unable to locate nuget.exe -->
|
|
||||||
<Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
|
|
||||||
<SetEnvironmentVariable EnvKey="VisualStudioVersion" EnvValue="$(VisualStudioVersion)" Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' " />
|
|
||||||
<!--
|
|
||||||
Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
|
|
||||||
This effectively acts as a lock that makes sure that the download operation will only happen once and all
|
|
||||||
parallel builds will have to wait for it to complete.
|
|
||||||
-->
|
|
||||||
<MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="_DownloadNuGet">
|
|
||||||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
|
|
||||||
<Exec Command="$(RestoreCommand)"
|
|
||||||
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
|
||||||
|
|
||||||
<Exec Command="$(RestoreCommand)"
|
|
||||||
LogStandardErrorAsError="true"
|
|
||||||
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
|
|
||||||
<Exec Command="$(BuildCommand)"
|
|
||||||
Condition=" '$(OS)' != 'Windows_NT' " />
|
|
||||||
|
|
||||||
<Exec Command="$(BuildCommand)"
|
|
||||||
LogStandardErrorAsError="true"
|
|
||||||
Condition=" '$(OS)' == 'Windows_NT' " />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
|
||||||
<ParameterGroup>
|
|
||||||
<OutputFilename ParameterType="System.String" Required="true" />
|
|
||||||
</ParameterGroup>
|
|
||||||
<Task>
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Using Namespace="System" />
|
|
||||||
<Using Namespace="System.IO" />
|
|
||||||
<Using Namespace="System.Net" />
|
|
||||||
<Using Namespace="Microsoft.Build.Framework" />
|
|
||||||
<Using Namespace="Microsoft.Build.Utilities" />
|
|
||||||
<Code Type="Fragment" Language="cs">
|
|
||||||
<![CDATA[
|
|
||||||
try {
|
|
||||||
OutputFilename = Path.GetFullPath(OutputFilename);
|
|
||||||
|
|
||||||
Log.LogMessage("Downloading latest version of NuGet.exe...");
|
|
||||||
WebClient webClient = new WebClient();
|
|
||||||
webClient.DownloadFile("https://nuget.org/nuget.exe", OutputFilename);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
Log.LogErrorFromException(ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</Code>
|
|
||||||
</Task>
|
|
||||||
</UsingTask>
|
|
||||||
|
|
||||||
<UsingTask TaskName="SetEnvironmentVariable" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
|
||||||
<ParameterGroup>
|
|
||||||
<EnvKey ParameterType="System.String" Required="true" />
|
|
||||||
<EnvValue ParameterType="System.String" Required="true" />
|
|
||||||
</ParameterGroup>
|
|
||||||
<Task>
|
|
||||||
<Using Namespace="System" />
|
|
||||||
<Code Type="Fragment" Language="cs">
|
|
||||||
<![CDATA[
|
|
||||||
try {
|
|
||||||
Environment.SetEnvironmentVariable(EnvKey, EnvValue, System.EnvironmentVariableTarget.Process);
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</Code>
|
|
||||||
</Task>
|
|
||||||
</UsingTask>
|
|
||||||
</Project>
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
|
|
||||||
namespace Disco.BI.AttachmentBI
|
|
||||||
{
|
|
||||||
public static class Utilities
|
|
||||||
{
|
|
||||||
|
|
||||||
public static bool GenerateThumbnail(Stream Source, string SourceMimeType, Stream OutStream)
|
|
||||||
{
|
|
||||||
if (Source != null)
|
|
||||||
{
|
|
||||||
// GDI+ (jpg, png, gif, bmp)
|
|
||||||
if (SourceMimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
|
||||||
SourceMimeType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("png") ||
|
|
||||||
SourceMimeType.Equals("image/gif", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("gif") ||
|
|
||||||
SourceMimeType.Equals("image/bmp", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("bmp"))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (Image sourceImage = Image.FromStream(Source))
|
|
||||||
{
|
|
||||||
using (Image thumbImage = sourceImage.ResizeImage(48, 48))
|
|
||||||
{
|
|
||||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_img16)
|
|
||||||
thumbImage.EmbedIconOverlay(mimeTypeIcon);
|
|
||||||
thumbImage.SaveJpg(90, OutStream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// Ignore Thumbnail Generation exceptions for images
|
|
||||||
//throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// PDF
|
|
||||||
if (SourceMimeType.Equals("application/pdf", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("pdf"))
|
|
||||||
{
|
|
||||||
PdfReader pdfReader = new PdfReader(Source);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (DisposableImageCollection pdfPageImages = pdfReader.PdfPageImages(1))
|
|
||||||
{
|
|
||||||
if (pdfPageImages.Count() > 0)
|
|
||||||
{
|
|
||||||
// Find Biggest Image on Page
|
|
||||||
Image biggestImage = pdfPageImages.OrderByDescending(i => i.Height * i.Width).First();
|
|
||||||
using (Image thumbImage = biggestImage.ResizeImage(48, 48, Brushes.White))
|
|
||||||
{
|
|
||||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_pdf16)
|
|
||||||
thumbImage.EmbedIconOverlay(mimeTypeIcon);
|
|
||||||
thumbImage.SaveJpg(90, OutStream);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (pdfReader != null)
|
|
||||||
pdfReader.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public static bool GenerateThumbnail(string SourceFilename, string SourceMimeType, string DestinationFilename)
|
|
||||||
{
|
|
||||||
using (FileStream sourceStream = new FileStream(SourceFilename, FileMode.Open, FileAccess.Read))
|
|
||||||
{
|
|
||||||
return GenerateThumbnail(sourceStream, SourceMimeType, DestinationFilename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static bool GenerateThumbnail(Stream Source, string SourceMimeType, string DestinationFilename)
|
|
||||||
{
|
|
||||||
bool result;
|
|
||||||
using (FileStream destinationStream = new FileStream(DestinationFilename, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
result = GenerateThumbnail(Source, SourceMimeType, destinationStream);
|
|
||||||
}
|
|
||||||
if (!result && File.Exists(DestinationFilename))
|
|
||||||
File.Delete(DestinationFilename);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Data.Configuration;
|
|
||||||
|
|
||||||
namespace Disco.BI
|
|
||||||
{
|
|
||||||
public static class DataStore
|
|
||||||
{
|
|
||||||
|
|
||||||
public static string CreateLocation(DiscoDataContext dbContext, string SubLocation, DateTime? SubSubLocationTimestamp = null)
|
|
||||||
{
|
|
||||||
return CreateLocation(dbContext.DiscoConfiguration, SubLocation, SubSubLocationTimestamp);
|
|
||||||
}
|
|
||||||
public static string CreateLocation(SystemConfiguration DiscoConfiguration, string SubLocation, DateTime? SubSubLocationTimestamp = null)
|
|
||||||
{
|
|
||||||
string SubSubLocation = string.Empty;
|
|
||||||
if (SubSubLocationTimestamp.HasValue)
|
|
||||||
SubSubLocation = SubSubLocationTimestamp.Value.ToString(@"yyyy\\MM");
|
|
||||||
|
|
||||||
string storeDirectory = System.IO.Path.Combine(DiscoConfiguration.DataStoreLocation, SubLocation, SubSubLocation);
|
|
||||||
if (!System.IO.Directory.Exists(storeDirectory))
|
|
||||||
System.IO.Directory.CreateDirectory(storeDirectory);
|
|
||||||
|
|
||||||
return storeDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data.Entity;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI
|
|
||||||
{
|
|
||||||
public static class DeviceModelBI
|
|
||||||
{
|
|
||||||
|
|
||||||
// Added: 2013-02-07 G#
|
|
||||||
// Ensure Duplicate Device Models are not created by creating only one Device Model at a time
|
|
||||||
// http://www.discoict.com.au/forum/support/2013/2/duplicate-device-models.aspx
|
|
||||||
// Thanks to Michael Vorster for reporting this problem.
|
|
||||||
private static object _CreateDeviceModelLock = new object();
|
|
||||||
public static Tuple<DeviceModel, bool> GetOrCreateDeviceModel(this DbSet<DeviceModel> DeviceModelsSet, string Manufacturer, string Model, string ModelType)
|
|
||||||
{
|
|
||||||
// Already Exists?
|
|
||||||
var deviceModel = DeviceModelsSet.FirstOrDefault(dm => dm.Manufacturer == Manufacturer && dm.Model == Model);
|
|
||||||
if (deviceModel == null)
|
|
||||||
{
|
|
||||||
// Ensure only one thread/request at a time
|
|
||||||
lock (_CreateDeviceModelLock)
|
|
||||||
{
|
|
||||||
// Check again now that lock is enforced
|
|
||||||
deviceModel = DeviceModelsSet.FirstOrDefault(dm => dm.Manufacturer == Manufacturer && dm.Model == Model);
|
|
||||||
|
|
||||||
if (deviceModel == null)
|
|
||||||
{
|
|
||||||
// Create the Device Model in a different DataContext so we don't have to commit unrelated changes
|
|
||||||
using (DiscoDataContext dbContext = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
var addDeviceModel = new DeviceModel
|
|
||||||
{
|
|
||||||
Manufacturer = Manufacturer,
|
|
||||||
Model = Model,
|
|
||||||
ModelType = ModelType,
|
|
||||||
Description = string.Format("{0} {1}", Manufacturer, Model)
|
|
||||||
};
|
|
||||||
dbContext.DeviceModels.Add(addDeviceModel);
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the Device Model with the in-scope DataContext
|
|
||||||
// - Overhead acknowledged, but reasonable given the infrequency of occurrence
|
|
||||||
deviceModel = DeviceModelsSet.FirstOrDefault(dm => dm.Manufacturer == Manufacturer && dm.Model == Model);
|
|
||||||
return new Tuple<DeviceModel, bool>(deviceModel, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Tuple<DeviceModel,bool>(deviceModel, false);
|
|
||||||
}
|
|
||||||
// Added: 2013-02-07 G#
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,578 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Disco.BI.Interop.ActiveDirectory;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Data.Configuration.Modules;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.ClientServices;
|
|
||||||
using Disco.Models.Interop.ActiveDirectory;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Tamir.SharpSsh;
|
|
||||||
using Disco.Services.Plugins;
|
|
||||||
using Disco.Services.Plugins.Features.CertificateProvider;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI
|
|
||||||
{
|
|
||||||
public class DeviceEnrol
|
|
||||||
{
|
|
||||||
public enum EnrolmentTypes
|
|
||||||
{
|
|
||||||
Normal,
|
|
||||||
Mac = 5,
|
|
||||||
MacSecure
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Regex SshPromptRegEx = new Regex("[\\$,\\#]", RegexOptions.Multiline);
|
|
||||||
public static MacSecureEnrolResponse MacSecureEnrol(DiscoDataContext dbContext, string Host)
|
|
||||||
{
|
|
||||||
MacEnrol trustedRequest = new MacEnrol();
|
|
||||||
string sessionId = System.Guid.NewGuid().ToString("B");
|
|
||||||
MacSecureEnrolResponse MacSecureEnrol;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionStarting(sessionId, Host, EnrolmentTypes.MacSecure);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 0, string.Format("Connecting to '{0}' as '{1}'", Host, dbContext.DiscoConfiguration.Bootstrapper.MacSshUsername));
|
|
||||||
SshShell shell = new SshShell(Host, dbContext.DiscoConfiguration.Bootstrapper.MacSshUsername, dbContext.DiscoConfiguration.Bootstrapper.MacSshPassword);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
shell.ExpectPattern = "#";
|
|
||||||
shell.Connect();
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 10, "Connected, Authenticating");
|
|
||||||
var output = shell.Expect(SshPromptRegEx);
|
|
||||||
bool sessionElevated = false;
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, output);
|
|
||||||
if (!output.TrimEnd(new char[0]).EndsWith("#"))
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 22, "Connected, Elevating Credentials");
|
|
||||||
shell.WriteLine("sudo -k");
|
|
||||||
System.Threading.Thread.Sleep(250);
|
|
||||||
output = shell.Expect(SshPromptRegEx);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 25, "Connected, Elevating Credentials");
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, output);
|
|
||||||
shell.WriteLine("sudo -s -S");
|
|
||||||
System.Threading.Thread.Sleep(250);
|
|
||||||
output = shell.Expect(":");
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 27, "Connected, Elevating Credentials");
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, output);
|
|
||||||
shell.WriteLine(dbContext.DiscoConfiguration.Bootstrapper.MacSshPassword);
|
|
||||||
System.Threading.Thread.Sleep(250);
|
|
||||||
output = shell.Expect(SshPromptRegEx);
|
|
||||||
sessionElevated = true;
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, output);
|
|
||||||
}
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 20, "Retrieving Serial Number");
|
|
||||||
trustedRequest.DeviceSerialNumber = ParseMacShellCommand(shell, "system_profiler SPHardwareDataType | grep \"Serial Number\" | cut -d \":\" -f 2-", sessionId);
|
|
||||||
EnrolmentLog.LogSessionDevice(sessionId, trustedRequest.DeviceSerialNumber, null);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "Retrieving Hardware UUID");
|
|
||||||
trustedRequest.DeviceUUID = ParseMacShellCommand(shell, "system_profiler SPHardwareDataType | grep \"Hardware UUID:\" | cut -d \":\" -f 2-", sessionId);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 40, "Retrieving Computer Name");
|
|
||||||
trustedRequest.DeviceComputerName = ParseMacShellCommand(shell, "scutil --get ComputerName", sessionId);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Retrieving Ethernet MAC Address");
|
|
||||||
string lanNicId = ParseMacShellCommand(shell, "system_profiler SPEthernetDataType | egrep -o \"en0|en1|en2|en3|en4|en5|en6\"", sessionId);
|
|
||||||
if (!string.IsNullOrWhiteSpace(lanNicId))
|
|
||||||
{
|
|
||||||
trustedRequest.DeviceLanMacAddress = ParseMacShellCommand(shell, string.Format("ifconfig {0} | grep ether | cut -d \" \" -f 2-", lanNicId), sessionId);
|
|
||||||
}
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 65, "Retrieving Wireless MAC Address");
|
|
||||||
string wlanNicId = ParseMacShellCommand(shell, "system_profiler SPAirPortDataType | egrep -o \"en0|en1|en2|en3|en4|en5|en6\"", sessionId);
|
|
||||||
if (!string.IsNullOrWhiteSpace(wlanNicId))
|
|
||||||
{
|
|
||||||
trustedRequest.DeviceWlanMacAddress = ParseMacShellCommand(shell, string.Format("ifconfig {0} | grep ether | cut -d \" \" -f 2-", wlanNicId), sessionId);
|
|
||||||
}
|
|
||||||
trustedRequest.DeviceManufacturer = "Apple Inc.";
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Model");
|
|
||||||
trustedRequest.DeviceModel = ParseMacShellCommand(shell, "system_profiler SPHardwareDataType | grep \"Model Identifier:\" | cut -d \":\" -f 2-", sessionId);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 90, "Retrieving Model Type");
|
|
||||||
trustedRequest.DeviceModelType = ParseMacModelType(ParseMacShellCommand(shell, "system_profiler SPHardwareDataType | grep \"Model Name:\" | cut -d \":\" -f 2-", sessionId));
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 99, "Disconnecting");
|
|
||||||
output = ParseMacModelType(ParseMacShellCommand(shell, "exit", sessionId));
|
|
||||||
if (sessionElevated)
|
|
||||||
{
|
|
||||||
output = ParseMacModelType(ParseMacShellCommand(shell, "exit", sessionId));
|
|
||||||
}
|
|
||||||
if (shell.Connected)
|
|
||||||
{
|
|
||||||
shell.Close();
|
|
||||||
}
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Disconnected, Starting Disco Enrolment");
|
|
||||||
MacSecureEnrolResponse response = MacSecureEnrolResponse.FromMacEnrolResponse(MacEnrol(dbContext, trustedRequest, true, sessionId));
|
|
||||||
EnrolmentLog.LogSessionFinished(sessionId);
|
|
||||||
MacSecureEnrol = response;
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (shell != null)
|
|
||||||
{
|
|
||||||
bool connected = shell.Connected;
|
|
||||||
if (connected)
|
|
||||||
{
|
|
||||||
shell.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionError(sessionId, ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
return MacSecureEnrol;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region "Mac Enrol Helpers"
|
|
||||||
|
|
||||||
private static string ParseMacModelType(string ModelName)
|
|
||||||
{
|
|
||||||
string ParseMacModelType;
|
|
||||||
if (!string.IsNullOrWhiteSpace(ModelName))
|
|
||||||
{
|
|
||||||
string mn = ModelName.ToLower();
|
|
||||||
if (mn.Contains("imac") || mn.Contains("mini"))
|
|
||||||
{
|
|
||||||
ParseMacModelType = "Desktop";
|
|
||||||
return ParseMacModelType;
|
|
||||||
}
|
|
||||||
if (mn.Contains("macbook"))
|
|
||||||
{
|
|
||||||
ParseMacModelType = "Mobile";
|
|
||||||
return ParseMacModelType;
|
|
||||||
}
|
|
||||||
if (mn.Contains("xserve"))
|
|
||||||
{
|
|
||||||
ParseMacModelType = "Server";
|
|
||||||
return ParseMacModelType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseMacModelType = "Unknown";
|
|
||||||
return ParseMacModelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ParseMacShellCommand(SshShell Shell, string Command, string LogSessionId)
|
|
||||||
{
|
|
||||||
Shell.WriteLine(Command);
|
|
||||||
System.Threading.Thread.Sleep(250);
|
|
||||||
string Response = Shell.Expect(SshPromptRegEx);
|
|
||||||
Response = Response.Replace("\r", string.Empty);
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(LogSessionId, Response);
|
|
||||||
bool flag = Response.Contains("\n");
|
|
||||||
string ParseMacShellCommand;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
string[] ResponseLines = Response.Split(new char[]
|
|
||||||
{
|
|
||||||
'\n'
|
|
||||||
});
|
|
||||||
switch (ResponseLines.Length)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
ParseMacShellCommand = string.Empty;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
ParseMacShellCommand = ResponseLines[1].Trim();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
System.Text.StringBuilder ResponseBuilder = new System.Text.StringBuilder();
|
|
||||||
int num = ResponseLines.Length - 2;
|
|
||||||
int lineIndex = 1;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int arg_111_0 = lineIndex;
|
|
||||||
int num2 = num;
|
|
||||||
if (arg_111_0 > num2)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ResponseBuilder.AppendLine(ResponseLines[lineIndex]);
|
|
||||||
lineIndex++;
|
|
||||||
}
|
|
||||||
ParseMacShellCommand = ResponseBuilder.ToString().Trim();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ParseMacShellCommand = Response;
|
|
||||||
}
|
|
||||||
return ParseMacShellCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public static MacEnrolResponse MacEnrol(DiscoDataContext dbContext, MacEnrol Request, bool Trusted, string OpenSessionId = null)
|
|
||||||
{
|
|
||||||
string sessionId;
|
|
||||||
if (OpenSessionId == null)
|
|
||||||
{
|
|
||||||
sessionId = System.Guid.NewGuid().ToString("B");
|
|
||||||
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Mac);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sessionId = OpenSessionId;
|
|
||||||
}
|
|
||||||
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
|
|
||||||
MacEnrolResponse response = new MacEnrolResponse();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 10, "Querying Database");
|
|
||||||
Device RepoDevice = dbContext.Devices.Include("AssignedUser").Include("DeviceProfile").Include("DeviceProfile").Where(d => d.SerialNumber == Request.DeviceSerialNumber).FirstOrDefault();
|
|
||||||
if (!Trusted)
|
|
||||||
{
|
|
||||||
if (RepoDevice == null)
|
|
||||||
throw new EnrolSafeException(string.Format("Unknown Device Serial Number (SN: '{0}')", Request.DeviceSerialNumber));
|
|
||||||
if (!RepoDevice.AllowUnauthenticatedEnrol)
|
|
||||||
throw new EnrolSafeException(string.Format("Device isn't allowed an Unauthenticated Enrolment (SN: '{0}')", Request.DeviceSerialNumber));
|
|
||||||
}
|
|
||||||
if (RepoDevice == null)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "New Device, Building Disco Instance");
|
|
||||||
EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.DeviceSerialNumber);
|
|
||||||
DeviceProfile deviceProfile = dbContext.DeviceProfiles.Find(dbContext.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
|
|
||||||
|
|
||||||
var deviceModelResult = dbContext.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
|
||||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
|
||||||
if (deviceModelResult.Item2)
|
|
||||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
|
||||||
else
|
|
||||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
|
||||||
|
|
||||||
RepoDevice = new Device
|
|
||||||
{
|
|
||||||
SerialNumber = Request.DeviceSerialNumber,
|
|
||||||
ComputerName = Request.DeviceComputerName,
|
|
||||||
DeviceProfile = deviceProfile,
|
|
||||||
DeviceModel = deviceModel,
|
|
||||||
AllowUnauthenticatedEnrol = false,
|
|
||||||
CreatedDate = DateTime.Now,
|
|
||||||
EnrolledDate = DateTime.Now
|
|
||||||
};
|
|
||||||
dbContext.Devices.Add(RepoDevice);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Existing Device, Updating Disco Instance");
|
|
||||||
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
|
|
||||||
if (!RepoDevice.DeviceModelId.HasValue || RepoDevice.DeviceModelId.Value == 1)
|
|
||||||
{
|
|
||||||
var deviceModelResult = dbContext.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
|
||||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
|
||||||
if (deviceModelResult.Item2)
|
|
||||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
|
||||||
else
|
|
||||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
|
||||||
|
|
||||||
RepoDevice.DeviceModel = deviceModel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, RepoDevice.DeviceModelId);
|
|
||||||
}
|
|
||||||
RepoDevice.ComputerName = Request.DeviceComputerName;
|
|
||||||
if (!RepoDevice.EnrolledDate.HasValue)
|
|
||||||
{
|
|
||||||
RepoDevice.EnrolledDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RepoDevice.LastEnrolDate = DateTime.Now;
|
|
||||||
RepoDevice.AllowUnauthenticatedEnrol = false;
|
|
||||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
|
||||||
//DeviceProfileConfiguration RepoDeviceProfileContext = RepoDevice.DeviceProfile.Configuration(Context);
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 90, "Building Response");
|
|
||||||
//if (RepoDeviceProfileContext.DistributionType == DeviceProfileConfiguration.DeviceProfileDistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
|
||||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
|
||||||
{
|
|
||||||
ActiveDirectoryUserAccount AssignedUserInfo = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id);
|
|
||||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.sAMAccountName, AssignedUserInfo.Domain, AssignedUserInfo.ObjectSid);
|
|
||||||
response.DeviceAssignedUserUsername = AssignedUserInfo.sAMAccountName;
|
|
||||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
|
|
||||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
|
||||||
response.DeviceAssignedUserSID = AssignedUserInfo.ObjectSid;
|
|
||||||
}
|
|
||||||
response.DeviceComputerName = RepoDevice.ComputerName;
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
|
|
||||||
}
|
|
||||||
catch (EnrolSafeException ex)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionError(sessionId, ex);
|
|
||||||
return new MacEnrolResponse { ErrorMessage = ex.Message };
|
|
||||||
}
|
|
||||||
catch (System.Exception ex2)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionError(sessionId, ex2);
|
|
||||||
throw ex2;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (OpenSessionId == null)
|
|
||||||
EnrolmentLog.LogSessionFinished(sessionId);
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
public static EnrolResponse Enrol(DiscoDataContext dbContext, string Username, Models.ClientServices.Enrol Request)
|
|
||||||
{
|
|
||||||
ActiveDirectoryMachineAccount MachineInfo = null;
|
|
||||||
EnrolResponse response = new EnrolResponse();
|
|
||||||
User authenticatedUser = null;
|
|
||||||
bool isAuthenticated = false;
|
|
||||||
string sessionId = System.Guid.NewGuid().ToString("B");
|
|
||||||
response.SessionId = sessionId;
|
|
||||||
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Normal);
|
|
||||||
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 10, "Loading User Data");
|
|
||||||
if (!string.IsNullOrWhiteSpace(Username))
|
|
||||||
{
|
|
||||||
authenticatedUser = UserBI.UserCache.GetUser(Username, dbContext);
|
|
||||||
isAuthenticated = (authenticatedUser != null);
|
|
||||||
}
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 13, "Loading Device Data");
|
|
||||||
|
|
||||||
Device RepoDevice = dbContext.Devices.Include("AssignedUser").Include("DeviceModel").Include("DeviceProfile").Where(d => d.SerialNumber == Request.DeviceSerialNumber).FirstOrDefault();
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 15, "Discovering User/Device Disco Permissions");
|
|
||||||
if (isAuthenticated)
|
|
||||||
{
|
|
||||||
if (authenticatedUser.Type != "Admin")
|
|
||||||
{
|
|
||||||
if (authenticatedUser.Type != "Computer")
|
|
||||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1}; User Type: {2})", Request.DeviceSerialNumber, authenticatedUser.Id, authenticatedUser.Type));
|
|
||||||
if (!authenticatedUser.Id.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1}; User Type: {2})", Request.DeviceSerialNumber, authenticatedUser.Id, authenticatedUser.Type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (RepoDevice == null)
|
|
||||||
throw new EnrolSafeException(string.Format("Unknown Device Serial Number (SN: '{0}')", Request.DeviceSerialNumber));
|
|
||||||
if (!RepoDevice.AllowUnauthenticatedEnrol)
|
|
||||||
throw new EnrolSafeException(string.Format("Device isn't allowed an Unauthenticated Enrolment (SN: '{0}')", Request.DeviceSerialNumber));
|
|
||||||
}
|
|
||||||
if (Request.DeviceIsPartOfDomain && !string.IsNullOrWhiteSpace(Request.DeviceComputerName))
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 20, "Loading Active Directory Computer Account");
|
|
||||||
System.Guid? uuidGuid = null;
|
|
||||||
System.Guid? macAddressGuid = null;
|
|
||||||
if (!string.IsNullOrEmpty(Request.DeviceUUID))
|
|
||||||
uuidGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(Request.DeviceUUID);
|
|
||||||
if (!string.IsNullOrEmpty(Request.DeviceLanMacAddress))
|
|
||||||
macAddressGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
|
|
||||||
MachineInfo = ActiveDirectory.GetMachineAccount(Request.DeviceComputerName, uuidGuid, macAddressGuid);
|
|
||||||
}
|
|
||||||
if (RepoDevice == null)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "New Device, Creating Disco Instance");
|
|
||||||
EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.DeviceSerialNumber);
|
|
||||||
DeviceProfile deviceProfile = dbContext.DeviceProfiles.Find(dbContext.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
|
|
||||||
|
|
||||||
|
|
||||||
var deviceModelResult = dbContext.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
|
||||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
|
||||||
if (deviceModelResult.Item2)
|
|
||||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
|
||||||
else
|
|
||||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
|
||||||
|
|
||||||
RepoDevice = new Device
|
|
||||||
{
|
|
||||||
SerialNumber = Request.DeviceSerialNumber,
|
|
||||||
ComputerName = Request.DeviceComputerName,
|
|
||||||
DeviceProfile = deviceProfile,
|
|
||||||
DeviceModel = deviceModel,
|
|
||||||
AllowUnauthenticatedEnrol = false,
|
|
||||||
CreatedDate = DateTime.Now,
|
|
||||||
EnrolledDate = DateTime.Now,
|
|
||||||
LastEnrolDate = DateTime.Now
|
|
||||||
};
|
|
||||||
dbContext.Devices.Add(RepoDevice);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "Existing Device, Updating Disco Instance");
|
|
||||||
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
|
|
||||||
|
|
||||||
var deviceModelResult = dbContext.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
|
||||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
|
||||||
if (deviceModelResult.Item2)
|
|
||||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
|
||||||
else
|
|
||||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
|
||||||
|
|
||||||
RepoDevice.DeviceModel = deviceModel;
|
|
||||||
|
|
||||||
if (!RepoDevice.EnrolledDate.HasValue)
|
|
||||||
RepoDevice.EnrolledDate = DateTime.Now;
|
|
||||||
RepoDevice.LastEnrolDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MachineInfo == null)
|
|
||||||
{
|
|
||||||
if (isAuthenticated || RepoDevice.AllowUnauthenticatedEnrol)
|
|
||||||
{
|
|
||||||
if (RepoDevice.DeviceProfile.ProvisionADAccount)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Provisioning an Active Directory Computer Account");
|
|
||||||
if (string.IsNullOrEmpty(RepoDevice.ComputerName) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
|
||||||
RepoDevice.ComputerName = RepoDevice.ComputerNameRender(dbContext);
|
|
||||||
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.ComputerName);
|
|
||||||
MachineInfo = ActiveDirectory.GetMachineAccount(RepoDevice.ComputerName);
|
|
||||||
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId);
|
|
||||||
response.RequireReboot = true;
|
|
||||||
}
|
|
||||||
if (MachineInfo != null)
|
|
||||||
{
|
|
||||||
response.DeviceComputerName = MachineInfo.Name;
|
|
||||||
response.DeviceDomainName = MachineInfo.Domain;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.DeviceComputerName = RepoDevice.ComputerName;
|
|
||||||
response.DeviceDomainName = RepoDevice.ComputerName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RepoDevice.ComputerName = Request.DeviceComputerName;
|
|
||||||
response.DeviceComputerName = Request.DeviceComputerName;
|
|
||||||
response.DeviceDomainName = RepoDevice.ComputerName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RepoDevice.ComputerName = MachineInfo.Name;
|
|
||||||
response.DeviceComputerName = MachineInfo.Name;
|
|
||||||
response.DeviceDomainName = MachineInfo.Domain;
|
|
||||||
|
|
||||||
// Enforce Computer Name Convention
|
|
||||||
if (RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
|
||||||
{
|
|
||||||
var calculatedComputerName = RepoDevice.ComputerNameRender(dbContext);
|
|
||||||
if (!Request.DeviceComputerName.Equals(calculatedComputerName, StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.DeviceComputerName, calculatedComputerName));
|
|
||||||
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.DeviceComputerName, calculatedComputerName);
|
|
||||||
|
|
||||||
RepoDevice.ComputerName = calculatedComputerName;
|
|
||||||
response.DeviceComputerName = calculatedComputerName;
|
|
||||||
|
|
||||||
// Create New Account
|
|
||||||
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId);
|
|
||||||
response.RequireReboot = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enforce Organisation Unit
|
|
||||||
if (response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
|
|
||||||
{
|
|
||||||
if ((RepoDevice.DeviceProfile.OrganisationalUnit == null && MachineInfo.ParentDistinguishedName.Equals("CN=Computers", StringComparison.InvariantCultureIgnoreCase)) // Null (Default) OU
|
|
||||||
|| !MachineInfo.ParentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.InvariantCultureIgnoreCase)) // Custom OU
|
|
||||||
{
|
|
||||||
string newOU = RepoDevice.DeviceProfile.OrganisationalUnit ?? "CN=Computers";
|
|
||||||
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 65, string.Format("Moving Device Organisation Unit: {0} -> {1}", MachineInfo.ParentDistinguishedName, newOU));
|
|
||||||
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, MachineInfo.ParentDistinguishedName, newOU);
|
|
||||||
MachineInfo.MoveOrganisationUnit(RepoDevice.DeviceProfile.OrganisationalUnit);
|
|
||||||
MachineInfo = ActiveDirectory.GetMachineAccount(MachineInfo.sAMAccountName);
|
|
||||||
response.RequireReboot = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (MachineInfo != null)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 75, "Updating Active Directory Computer Account Properties");
|
|
||||||
MachineInfo.UpdateNetbootGUID(Request.DeviceUUID, Request.DeviceLanMacAddress);
|
|
||||||
if (RepoDevice.AssignedUser != null)
|
|
||||||
MachineInfo.SetDescription(RepoDevice);
|
|
||||||
}
|
|
||||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne)
|
|
||||||
{
|
|
||||||
if (RepoDevice.AssignedUser == null)
|
|
||||||
{
|
|
||||||
response.AllowBootstrapperUninstall = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account");
|
|
||||||
ActiveDirectoryUserAccount AssignedUserInfo = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id);
|
|
||||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.sAMAccountName, AssignedUserInfo.Domain, AssignedUserInfo.ObjectSid);
|
|
||||||
response.AllowBootstrapperUninstall = true;
|
|
||||||
response.DeviceAssignedUserUsername = AssignedUserInfo.sAMAccountName;
|
|
||||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
|
|
||||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
|
||||||
response.DeviceAssignedUserSID = AssignedUserInfo.ObjectSid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.AllowBootstrapperUninstall = true;
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(Request.DeviceWlanMacAddress) && !string.IsNullOrEmpty(RepoDevice.DeviceProfile.CertificateProviderId))
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 90, "Provisioning a Wireless Certificate");
|
|
||||||
|
|
||||||
var allocationResult = RepoDevice.AllocateCertificate(dbContext);
|
|
||||||
var deviceCertificate = allocationResult.Item1;
|
|
||||||
if (deviceCertificate != null)
|
|
||||||
{
|
|
||||||
bool certAlreadyInstalled = false;
|
|
||||||
if (Request.DeviceCertificates != null && Request.DeviceCertificates.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (string existingCertName in Request.DeviceCertificates)
|
|
||||||
{
|
|
||||||
if (existingCertName.Contains(deviceCertificate.Name))
|
|
||||||
{
|
|
||||||
certAlreadyInstalled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!certAlreadyInstalled)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionTaskProvisioningWirelessCertificate(sessionId, RepoDevice.SerialNumber, deviceCertificate.Name);
|
|
||||||
response.DeviceCertificate = System.Convert.ToBase64String(deviceCertificate.Content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response.DeviceCertificateRemoveExisting = allocationResult.Item2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset 'AllowUnauthenticatedEnrol'
|
|
||||||
if (RepoDevice.AllowUnauthenticatedEnrol)
|
|
||||||
RepoDevice.AllowUnauthenticatedEnrol = false;
|
|
||||||
|
|
||||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
|
|
||||||
}
|
|
||||||
catch (EnrolSafeException ex)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionError(sessionId, ex);
|
|
||||||
return new EnrolResponse
|
|
||||||
{
|
|
||||||
SessionId = sessionId,
|
|
||||||
ErrorMessage = ex.Message
|
|
||||||
};
|
|
||||||
}
|
|
||||||
catch (System.Exception ex2)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionError(sessionId, ex2);
|
|
||||||
throw ex2;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionFinished(sessionId);
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
namespace Disco.BI
|
|
||||||
{
|
|
||||||
public class EnrolSafeException : System.Exception
|
|
||||||
{
|
|
||||||
public EnrolSafeException(string Message) : base(Message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,482 +0,0 @@
|
|||||||
using Disco.Services.Logging;
|
|
||||||
using Disco.Services.Logging.Models;
|
|
||||||
using Disco.Models.ClientServices;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
namespace Disco.BI.DeviceBI
|
|
||||||
{
|
|
||||||
public class EnrolmentLog : LogBase
|
|
||||||
{
|
|
||||||
public enum EventTypeIds
|
|
||||||
{
|
|
||||||
SessionStarting = 10,
|
|
||||||
SessionProgress,
|
|
||||||
SessionDevice,
|
|
||||||
SessionDeviceInfo,
|
|
||||||
SessionFinished = 20,
|
|
||||||
SessionDiagnosticInformation,
|
|
||||||
SessionWarning,
|
|
||||||
SessionError,
|
|
||||||
SessionErrorWithInner,
|
|
||||||
SessionClientError,
|
|
||||||
SessionTaskAddedDevice = 50,
|
|
||||||
SessionTaskUpdatingDevice,
|
|
||||||
SessionTaskCreatedDeviceModel = 56,
|
|
||||||
SessionTaskProvisioningADAccount = 58,
|
|
||||||
SessionTaskAssigningUser = 60,
|
|
||||||
SessionTaskProvisioningWirelessCertificate = 62,
|
|
||||||
SessionTaskRenamingDevice = 64,
|
|
||||||
SessionTaskMovingDeviceOrganisationUnit = 66,
|
|
||||||
ClientError = 400
|
|
||||||
}
|
|
||||||
private const int _ModuleId = 50;
|
|
||||||
public static EnrolmentLog Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (EnrolmentLog)LogContext.LogModules[50];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Device Enrolment";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override int ModuleId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "DeviceEnrolment";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[System.Diagnostics.DebuggerNonUserCode]
|
|
||||||
public EnrolmentLog()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
private static void Log(EnrolmentLog.EventTypeIds EventTypeId, params object[] Args)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Current.Log((int)EventTypeId, Args);
|
|
||||||
}
|
|
||||||
public static void LogSessionStarting(string SessionId, string HostId, DeviceEnrol.EnrolmentTypes EnrolmentType)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionStarting, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
HostId,
|
|
||||||
System.Enum.GetName(EnrolmentType.GetType(), EnrolmentType)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionDevice(string SessionId, string DeviceSerialNumber, int? DeviceModelId)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionDevice, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber,
|
|
||||||
DeviceModelId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionDeviceInfo(string SessionId, string SerialNumber, string UUID, string ComputerName, string LanMacAddress, string WlanMacAddress, string Manufacturer, string Model, string ModelType)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionDeviceInfo, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
SerialNumber,
|
|
||||||
UUID,
|
|
||||||
ComputerName,
|
|
||||||
LanMacAddress,
|
|
||||||
WlanMacAddress,
|
|
||||||
Manufacturer,
|
|
||||||
Model,
|
|
||||||
ModelType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionDeviceInfo(string SessionId, MacEnrol Request)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionDeviceInfo(SessionId, Request.DeviceSerialNumber, Request.DeviceUUID, Request.DeviceComputerName, Request.DeviceLanMacAddress, Request.DeviceWlanMacAddress, Request.DeviceManufacturer, Request.DeviceModel, Request.DeviceModelType);
|
|
||||||
}
|
|
||||||
public static void LogSessionDeviceInfo(string SessionId, Models.ClientServices.Enrol Request)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionDeviceInfo(SessionId, Request.DeviceSerialNumber, Request.DeviceUUID, Request.DeviceComputerName, Request.DeviceLanMacAddress, Request.DeviceWlanMacAddress, Request.DeviceManufacturer, Request.DeviceModel, Request.DeviceModelType);
|
|
||||||
}
|
|
||||||
public static void LogSessionProgress(string SessionId, int Progress, string Status)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionProgress, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Progress,
|
|
||||||
Status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionFinished(string SessionId)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionFinished, new object[]
|
|
||||||
{
|
|
||||||
SessionId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionDiagnosticInformation(string SessionId, string Message)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionDiagnosticInformation, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionWarning(string SessionId, string Message)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionWarning, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionError(string SessionId, System.Exception Ex)
|
|
||||||
{
|
|
||||||
if (Ex.InnerException == null)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionError, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Ex.GetType().Name,
|
|
||||||
Ex.Message,
|
|
||||||
Ex.StackTrace
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionErrorWithInner, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Ex.GetType().Name,
|
|
||||||
Ex.Message,
|
|
||||||
Ex.InnerException.GetType().Name,
|
|
||||||
Ex.InnerException.Message,
|
|
||||||
Ex.StackTrace,
|
|
||||||
Ex.InnerException.StackTrace
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void LogSessionClientError(string SessionId, string ClientIP, string ClientIdentifier, string ClientVersion, string Error, string RawError)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionClientError, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
ClientIP,
|
|
||||||
ClientIdentifier,
|
|
||||||
ClientVersion,
|
|
||||||
Error,
|
|
||||||
RawError
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskAddedDevice(string SessionId, string DeviceSerialNumber)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskAddedDevice, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskUpdatingDevice(string SessionId, string DeviceSerialNumber)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskUpdatingDevice, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskCreatedDeviceModel(string SessionId, string DeviceSerialNumber, string Manufacturer, string Model)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskCreatedDeviceModel, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber,
|
|
||||||
Manufacturer,
|
|
||||||
Model
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskProvisioningADAccount(string SessionId, string DeviceSerialNumber, string ADAccountName)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskProvisioningADAccount, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber,
|
|
||||||
ADAccountName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskAssigningUser(string SessionId, string DeviceSerialNumber, string UserDisplayName, string UserUsername, string UserDomain, string UserSID)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskAssigningUser, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber,
|
|
||||||
UserDisplayName,
|
|
||||||
UserUsername,
|
|
||||||
UserDomain,
|
|
||||||
UserSID
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskProvisioningWirelessCertificate(string SessionId, string DeviceSerialNumber, string CertificateName)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskProvisioningWirelessCertificate, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DeviceSerialNumber,
|
|
||||||
CertificateName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskRenamingDevice(string SessionId, string OldComputerName, string NewComputerName)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskRenamingDevice, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
OldComputerName,
|
|
||||||
NewComputerName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogSessionTaskMovingDeviceOrganisationUnit(string SessionId, string OldOrganisationUnit, string NewOrganisationUnit)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.SessionTaskMovingDeviceOrganisationUnit, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
OldOrganisationUnit,
|
|
||||||
NewOrganisationUnit
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogClientError(string ClientIP, string ClientIdentifier, string ClientVersion, string Error, string RawError)
|
|
||||||
{
|
|
||||||
EnrolmentLog.Log(EnrolmentLog.EventTypeIds.ClientError, new object[]
|
|
||||||
{
|
|
||||||
ClientIP,
|
|
||||||
ClientIdentifier,
|
|
||||||
ClientVersion,
|
|
||||||
Error,
|
|
||||||
RawError
|
|
||||||
});
|
|
||||||
}
|
|
||||||
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<LogEventType>
|
|
||||||
{
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 10,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Starting",
|
|
||||||
Format = "Starting '{2}' Enrolment for {1} (Session# {0})",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 12,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Device",
|
|
||||||
Format = null,
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 11,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Progress",
|
|
||||||
Format = "Processing Session# {0}; {1}% Complete; Status: {2}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 13,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Device Info",
|
|
||||||
Format = null,
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 20,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Finished",
|
|
||||||
Format = "Finished Session# {0}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 21,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Diagnostic Information",
|
|
||||||
Format = null,
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 22,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Warning",
|
|
||||||
Format = null,
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 23,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Error",
|
|
||||||
Format = "An Error Occurred: [{1}] {2}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 24,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Session Error with Internal",
|
|
||||||
Format = "An Error Occurred: [{1}] {2}; Internal Error: [{3}] {4}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.SessionClientError,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Client Error",
|
|
||||||
Format = "IP: {1}; Device ID: {2}; Version: {3} Error: {4}; Session# {0}",
|
|
||||||
Severity = (int)LogEventType.Severities.Error,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 50,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Added Device",
|
|
||||||
Format = "Creating Disco Device {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 51,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Updating Device",
|
|
||||||
Format = "Updating Disco Device {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 56,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Creating Device Model",
|
|
||||||
Format = "Creating Device Model '{2} {3}' for Device {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 58,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Provisioning Active Directory Account",
|
|
||||||
Format = "Provisioning Active Directory Account '{2}' for Device {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 60,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Assigning User",
|
|
||||||
Format = "Assigning User '{2}' ({4}\\{3} {{{5}}}) for Device {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 62,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Provisioning Wireless Certificate",
|
|
||||||
Format = "Provisioning Wireless Certificate '{2}' for Device {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 64,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Renaming Device",
|
|
||||||
Format = "Renaming Device '{1}' to '{2}'",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 66,
|
|
||||||
ModuleId = 50,
|
|
||||||
Name = "Task - Moving Device Organisation Unit",
|
|
||||||
Format = "Moving Device Organisation Unit '{1}' to '{2}'",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = (int)EventTypeIds.ClientError,
|
|
||||||
ModuleId = _ModuleId,
|
|
||||||
Name = "Client Error",
|
|
||||||
Format = "IP: {0}; Device ID: {1}; Version: {2} Error: {3}",
|
|
||||||
Severity = (int)LogEventType.Severities.Error,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public static class Export
|
|
||||||
{
|
|
||||||
private const string ExportHeader = "Serial Number,Device Model,Device Profile,Device Batch,Assigned User,Location,Asset Number";
|
|
||||||
|
|
||||||
public static MemoryStream GenerateExport(IQueryable<Device> Devices)
|
|
||||||
{
|
|
||||||
var devices = Devices.Select(d => new ImportDevice()
|
|
||||||
{
|
|
||||||
SerialNumber = d.SerialNumber,
|
|
||||||
DeviceModelId = d.DeviceModelId,
|
|
||||||
DeviceProfileId = d.DeviceProfileId,
|
|
||||||
DeviceBatchId = d.DeviceBatchId,
|
|
||||||
AssignedUserId = d.AssignedUserId,
|
|
||||||
Location = d.Location,
|
|
||||||
AssetNumber = d.AssetNumber
|
|
||||||
});
|
|
||||||
|
|
||||||
MemoryStream exportStream = new MemoryStream();
|
|
||||||
|
|
||||||
StreamWriter exportWriter = new StreamWriter(exportStream);
|
|
||||||
// Write Header
|
|
||||||
exportWriter.WriteLine(ExportHeader);
|
|
||||||
|
|
||||||
foreach (var device in devices)
|
|
||||||
device.ExportCsv(exportWriter);
|
|
||||||
|
|
||||||
exportWriter.Flush();
|
|
||||||
|
|
||||||
exportStream.Position = 0;
|
|
||||||
return exportStream;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ExportCsv(this ImportDevice device, StreamWriter writer)
|
|
||||||
{
|
|
||||||
// SERIAL NUMBER
|
|
||||||
writer.Write('"');
|
|
||||||
writer.Write(device.SerialNumber.Replace("\"", "\"\""));
|
|
||||||
writer.Write('"');
|
|
||||||
|
|
||||||
writer.Write(',');
|
|
||||||
|
|
||||||
// DEVICE MODEL
|
|
||||||
if (device.DeviceModelId.HasValue)
|
|
||||||
writer.Write(device.DeviceModelId.Value);
|
|
||||||
|
|
||||||
writer.Write(',');
|
|
||||||
|
|
||||||
// DEVICE PROFILE
|
|
||||||
writer.Write(device.DeviceProfileId);
|
|
||||||
|
|
||||||
writer.Write(',');
|
|
||||||
|
|
||||||
// DEVICE BATCH
|
|
||||||
if (device.DeviceBatchId.HasValue)
|
|
||||||
writer.Write(device.DeviceBatchId.Value);
|
|
||||||
|
|
||||||
writer.Write(',');
|
|
||||||
|
|
||||||
// ASSIGNED USER
|
|
||||||
if (device.AssignedUserId != null)
|
|
||||||
{
|
|
||||||
writer.Write('"');
|
|
||||||
writer.Write(device.AssignedUserId.Replace("\"", "\"\""));
|
|
||||||
writer.Write('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(',');
|
|
||||||
|
|
||||||
// LOCATION
|
|
||||||
if (!string.IsNullOrWhiteSpace(device.Location))
|
|
||||||
{
|
|
||||||
writer.Write('"');
|
|
||||||
writer.Write(device.Location.Replace("\"", "\"\""));
|
|
||||||
writer.Write('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(',');
|
|
||||||
|
|
||||||
// ASSET NUMBER
|
|
||||||
if (!string.IsNullOrWhiteSpace(device.AssetNumber))
|
|
||||||
{
|
|
||||||
writer.Write('"');
|
|
||||||
writer.Write(device.AssetNumber.Replace("\"", "\"\""));
|
|
||||||
writer.Write('"');
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using PopulateRecordReferences = System.Tuple<System.Collections.Generic.Dictionary<int, Disco.Models.Repository.DeviceModel>, System.Collections.Generic.Dictionary<int, Disco.Models.Repository.DeviceProfile>, System.Collections.Generic.Dictionary<int, Disco.Models.Repository.DeviceBatch>>;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public static class Import
|
|
||||||
{
|
|
||||||
internal const string ImportParseCacheKey = "ImportParseResults_{0}";
|
|
||||||
|
|
||||||
public static ImportDeviceSession GetSession(string ImportParseTaskId)
|
|
||||||
{
|
|
||||||
string parseKey = string.Format(ImportParseCacheKey, ImportParseTaskId);
|
|
||||||
|
|
||||||
return (ImportDeviceSession)HttpRuntime.Cache.Get(parseKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool ImportRecord(this ImportDevice device, DiscoDataContext dbContext, PopulateRecordReferences references)
|
|
||||||
{
|
|
||||||
// Skips If Errors
|
|
||||||
if (device.Errors == null || device.Errors.Count == 0)
|
|
||||||
{
|
|
||||||
// Re-Populate & Skip If Errors
|
|
||||||
device.PopulateRecord(dbContext, references);
|
|
||||||
if (device.Errors == null || device.Errors.Count == 0)
|
|
||||||
{
|
|
||||||
Device discoDevice = device.Device;
|
|
||||||
|
|
||||||
if (discoDevice == null)
|
|
||||||
{
|
|
||||||
// New Device
|
|
||||||
discoDevice = new Device()
|
|
||||||
{
|
|
||||||
SerialNumber = device.SerialNumber.ToUpper(),
|
|
||||||
CreatedDate = DateTime.Now,
|
|
||||||
AllowUnauthenticatedEnrol = true,
|
|
||||||
};
|
|
||||||
dbContext.Devices.Add(discoDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discoDevice.DeviceModelId != device.DeviceModelId)
|
|
||||||
discoDevice.DeviceModelId = device.DeviceModelId;
|
|
||||||
if (discoDevice.DeviceProfileId != device.DeviceProfileId)
|
|
||||||
discoDevice.DeviceProfileId = device.DeviceProfileId;
|
|
||||||
if (discoDevice.DeviceBatchId != device.DeviceBatchId)
|
|
||||||
discoDevice.DeviceBatchId = device.DeviceBatchId;
|
|
||||||
if (discoDevice.Location != device.Location)
|
|
||||||
discoDevice.Location = device.Location;
|
|
||||||
if (discoDevice.AssetNumber != device.AssetNumber)
|
|
||||||
discoDevice.AssetNumber = device.AssetNumber;
|
|
||||||
|
|
||||||
if (discoDevice.AssignedUserId != device.AssignedUserId)
|
|
||||||
{
|
|
||||||
discoDevice.AssignDevice(dbContext, device.AssignedUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static PopulateRecordReferences GetPopulateRecordReferences(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return new PopulateRecordReferences(
|
|
||||||
dbContext.DeviceModels.ToDictionary(dm => dm.Id),
|
|
||||||
dbContext.DeviceProfiles.ToDictionary(dp => dp.Id),
|
|
||||||
dbContext.DeviceBatches.ToDictionary(db => db.Id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void PopulateRecord(this ImportDevice device, DiscoDataContext dbContext, PopulateRecordReferences references)
|
|
||||||
{
|
|
||||||
|
|
||||||
var deviceModels = references.Item1;
|
|
||||||
var deviceProfiles = references.Item2;
|
|
||||||
var deviceBatches = references.Item3;
|
|
||||||
|
|
||||||
// SERIAL NUMBER - Existing Device
|
|
||||||
if (!device.Errors.ContainsKey("SerialNumber"))
|
|
||||||
{
|
|
||||||
device.Device = dbContext.Devices.Find(device.SerialNumber);
|
|
||||||
if (device.Device != null && device.Device.DecommissionedDate.HasValue)
|
|
||||||
device.Errors.Add("SerialNumber", "The device is decommissioned");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// DEVICE MODEL
|
|
||||||
if (!device.Errors.ContainsKey("DeviceModelId"))
|
|
||||||
{
|
|
||||||
DeviceModel deviceModel;
|
|
||||||
|
|
||||||
if (!device.DeviceModelId.HasValue)
|
|
||||||
device.DeviceModelId = 1; // Default 'Unknown Device Model'
|
|
||||||
|
|
||||||
if (!deviceModels.TryGetValue(device.DeviceModelId.Value, out deviceModel))
|
|
||||||
device.Errors.Add("DeviceModelId", string.Format("Unknown device model id: {0}", device.DeviceModelId));
|
|
||||||
else
|
|
||||||
device.DeviceModel = deviceModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEVICE PROFILE
|
|
||||||
if (!device.Errors.ContainsKey("DeviceProfileId"))
|
|
||||||
{
|
|
||||||
DeviceProfile deviceProfile;
|
|
||||||
if (!deviceProfiles.TryGetValue(device.DeviceProfileId, out deviceProfile))
|
|
||||||
device.Errors.Add("DeviceProfileId", string.Format("Unknown device profile id: {0}", device.DeviceProfileId));
|
|
||||||
else
|
|
||||||
device.DeviceProfile = deviceProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEVICE BATCH
|
|
||||||
if (!device.Errors.ContainsKey("DeviceBatchId") && device.DeviceBatchId.HasValue)
|
|
||||||
{
|
|
||||||
DeviceBatch deviceBatch;
|
|
||||||
if (!deviceBatches.TryGetValue(device.DeviceBatchId.Value, out deviceBatch))
|
|
||||||
device.Errors.Add("DeviceBatchId", string.Format("Unknown device Batch id: {0}", device.DeviceBatchId));
|
|
||||||
else
|
|
||||||
device.DeviceBatch = deviceBatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ASSIGNED USER
|
|
||||||
if (!device.Errors.ContainsKey("AssignedUserId") && device.AssignedUserId != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
device.AssignedUser = UserBI.UserCache.GetUser(device.AssignedUserId, dbContext, true);
|
|
||||||
}
|
|
||||||
catch (ArgumentException)
|
|
||||||
{
|
|
||||||
device.Errors.Add("AssignedUserId", string.Format("Unknown user id: {0}", device.AssignedUserId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ImportDevice ParseRecord(this string[] record)
|
|
||||||
{
|
|
||||||
int csvFieldCount = record.Length;
|
|
||||||
if (csvFieldCount < 1)
|
|
||||||
throw new ArgumentException("At least one CSV field is required (Serial Number)");
|
|
||||||
|
|
||||||
string csvSerialNumber;
|
|
||||||
string csvDeviceModelId;
|
|
||||||
int deviceModelId = 1; // Default 'Unknown Device Model'
|
|
||||||
string csvDeviceProfileId;
|
|
||||||
int deviceProfileId = 1; // 'Default' Profile
|
|
||||||
string csvDeviceBatchId;
|
|
||||||
int deviceBatchId = 0; // No Batch
|
|
||||||
string csvAssignedUserId = null;
|
|
||||||
string csvLocation = null;
|
|
||||||
string csvAssetNumber = null;
|
|
||||||
Dictionary<string, string> errors = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
// SERIAL NUMBER
|
|
||||||
csvSerialNumber = record[0];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvSerialNumber))
|
|
||||||
errors.Add("SerialNumber", "The serial number is required");
|
|
||||||
else if (csvSerialNumber.Trim().Length > 60)
|
|
||||||
errors.Add("SerialNumber", "The serial number must be less than or equal to 60 characters");
|
|
||||||
|
|
||||||
if (csvFieldCount > 1)
|
|
||||||
{
|
|
||||||
// DEVICE MODEL
|
|
||||||
csvDeviceModelId = record[1];
|
|
||||||
if (!string.IsNullOrWhiteSpace(csvDeviceModelId))
|
|
||||||
if (!int.TryParse(csvDeviceModelId, out deviceModelId))
|
|
||||||
errors.Add("DeviceModelId", "The device model is optional, but when supplied must be a number");
|
|
||||||
else if (deviceModelId < 1)
|
|
||||||
errors.Add("DeviceModelId", "The device model is optional, but when supplied must be greater than 0");
|
|
||||||
|
|
||||||
if (csvFieldCount > 2)
|
|
||||||
{
|
|
||||||
// DEVICE PROFILE
|
|
||||||
csvDeviceProfileId = record[2];
|
|
||||||
if (!string.IsNullOrWhiteSpace(csvDeviceProfileId))
|
|
||||||
if (!int.TryParse(csvDeviceProfileId, out deviceProfileId))
|
|
||||||
errors.Add("DeviceProfileId", "The device profile is optional, but when supplied must be a number");
|
|
||||||
else if (deviceProfileId < 1)
|
|
||||||
errors.Add("DeviceProfileId", "The device profile is optional, but when supplied must be greater than 0");
|
|
||||||
|
|
||||||
if (csvFieldCount > 3)
|
|
||||||
{
|
|
||||||
// DEVICE BATCH
|
|
||||||
csvDeviceBatchId = record[3];
|
|
||||||
if (!string.IsNullOrWhiteSpace(csvDeviceBatchId))
|
|
||||||
if (!int.TryParse(csvDeviceBatchId, out deviceBatchId))
|
|
||||||
errors.Add("DeviceBatchId", "The device batch is optional, but when supplied must be a number");
|
|
||||||
else if (deviceBatchId < 1)
|
|
||||||
errors.Add("DeviceBatchId", "The device batch is optional, but when supplied must be greater than 0");
|
|
||||||
|
|
||||||
if (csvFieldCount > 4)
|
|
||||||
{
|
|
||||||
// ASSIGNED USER
|
|
||||||
csvAssignedUserId = record[4];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvAssignedUserId))
|
|
||||||
csvAssignedUserId = null; // Not Assigned
|
|
||||||
else if (csvAssignedUserId.Length > 50)
|
|
||||||
errors.Add("AssignedUserId", "The assigned user must be less than or equal to 50 characters");
|
|
||||||
|
|
||||||
if (csvFieldCount > 5)
|
|
||||||
{
|
|
||||||
// LOCATION
|
|
||||||
csvLocation = record[5];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvLocation))
|
|
||||||
csvLocation = null; // No Location Specified
|
|
||||||
else if (csvLocation.Length > 250)
|
|
||||||
errors.Add("Location", "The location must be less than or equal to 250 characters");
|
|
||||||
|
|
||||||
if (csvFieldCount > 6)
|
|
||||||
{
|
|
||||||
// ASSET NUMBER
|
|
||||||
csvAssetNumber = record[6];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvAssetNumber))
|
|
||||||
csvAssetNumber = null; // No Location Specified
|
|
||||||
else if (csvAssetNumber.Length > 40)
|
|
||||||
errors.Add("AssetNumber", "The asset number must be less than or equal to 40 characters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ImportDevice()
|
|
||||||
{
|
|
||||||
SerialNumber = csvSerialNumber.Trim(),
|
|
||||||
DeviceModelId = deviceModelId,
|
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
DeviceBatchId = deviceBatchId == 0 ? (int?)null : deviceBatchId,
|
|
||||||
AssignedUserId = csvAssignedUserId,
|
|
||||||
Location = csvLocation,
|
|
||||||
AssetNumber = csvAssetNumber,
|
|
||||||
Errors = errors
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#region ImportDevice Extensions
|
|
||||||
|
|
||||||
public static string ImportStatus(this ImportDevice device)
|
|
||||||
{
|
|
||||||
if (device.Errors.Count > 0)
|
|
||||||
return "Error";
|
|
||||||
|
|
||||||
if (device.Device != null)
|
|
||||||
return "Update";
|
|
||||||
|
|
||||||
return "New";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
using LumenWorks.Framework.IO.Csv;
|
|
||||||
using Quartz;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using System.Web.Caching;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public class ImportParseTask : ScheduledTask
|
|
||||||
{
|
|
||||||
public override string TaskName { get { return "Import Devices - Parsing"; } }
|
|
||||||
|
|
||||||
public override bool SingleInstanceTask { get { return false; } }
|
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
|
||||||
|
|
||||||
protected override void ExecuteTask()
|
|
||||||
{
|
|
||||||
string csvFilename = (string)this.ExecutionContext.JobDetail.JobDataMap["CsvFilename"];
|
|
||||||
MemoryStream csvStream = (MemoryStream)this.ExecutionContext.JobDetail.JobDataMap["CsvImport"];
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(0, "Parsing CSV File", "Loading Records");
|
|
||||||
|
|
||||||
List<ImportDevice> records;
|
|
||||||
|
|
||||||
using (TextReader csvTextReader = new StreamReader(csvStream))
|
|
||||||
{
|
|
||||||
using (CsvReader csvReader = new CsvReader(csvTextReader, true))
|
|
||||||
{
|
|
||||||
csvReader.DefaultParseErrorAction = ParseErrorAction.ThrowException;
|
|
||||||
csvReader.MissingFieldAction = MissingFieldAction.ReplaceByNull;
|
|
||||||
|
|
||||||
records = csvReader.Select(record => record.ParseRecord()).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
csvStream.Dispose();
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(20, "Parsing CSV File", string.Format("Linking {0} Records", records.Count));
|
|
||||||
|
|
||||||
using (DiscoDataContext dbContext = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
var populateReferences = Import.GetPopulateRecordReferences(dbContext);
|
|
||||||
|
|
||||||
DateTime lastUpdate = DateTime.Now;
|
|
||||||
foreach (var record in records)
|
|
||||||
{
|
|
||||||
record.PopulateRecord(dbContext, populateReferences);
|
|
||||||
|
|
||||||
if (DateTime.Now.Subtract(lastUpdate).TotalSeconds > 1)
|
|
||||||
{
|
|
||||||
// Update every second
|
|
||||||
this.Status.UpdateStatus((int)Math.Floor((((double)(records.IndexOf(record) + 1) / records.Count) * 80)));
|
|
||||||
lastUpdate = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Session Result
|
|
||||||
ImportDeviceSession session = new ImportDeviceSession()
|
|
||||||
{
|
|
||||||
ImportParseTaskId = this.Status.SessionId,
|
|
||||||
ImportFilename = csvFilename,
|
|
||||||
ImportDevices = records
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set Results to Cache
|
|
||||||
string key = string.Format(Import.ImportParseCacheKey, this.Status.SessionId);
|
|
||||||
HttpRuntime.Cache.Insert(key, session, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60), CacheItemPriority.NotRemovable, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScheduledTaskStatus Run(Stream CsvImport, String CsvFilename)
|
|
||||||
{
|
|
||||||
|
|
||||||
MemoryStream csvStream = new MemoryStream();
|
|
||||||
CsvImport.CopyTo(csvStream);
|
|
||||||
csvStream.Position = 0;
|
|
||||||
|
|
||||||
var task = new ImportParseTask();
|
|
||||||
JobDataMap taskData = new JobDataMap() { { "CsvImport", csvStream }, { "CsvFilename", CsvFilename } };
|
|
||||||
return task.ScheduleTask(taskData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
using Quartz;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public class ImportProcessTask : ScheduledTask
|
|
||||||
{
|
|
||||||
public override string TaskName { get { return "Import Devices - Processing Changes"; } }
|
|
||||||
|
|
||||||
public override bool SingleInstanceTask { get { return false; } }
|
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
|
||||||
|
|
||||||
protected override void ExecuteTask()
|
|
||||||
{
|
|
||||||
string importParseTaskId = (string)this.ExecutionContext.JobDetail.JobDataMap["ImportParseTaskId"];
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(importParseTaskId))
|
|
||||||
throw new ArgumentNullException("ImportParseTaskId");
|
|
||||||
|
|
||||||
ImportDeviceSession session = Import.GetSession(importParseTaskId);
|
|
||||||
|
|
||||||
if (session == null)
|
|
||||||
throw new InvalidOperationException("The session timed out (60 minutes), try importing again");
|
|
||||||
|
|
||||||
List<ImportDevice> records = session.ImportDevices;
|
|
||||||
int recordsImported = 0;
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(0, "Processing Device Import", "Importing Devices");
|
|
||||||
|
|
||||||
using (DiscoDataContext dbContext = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
var populateReferences = Import.GetPopulateRecordReferences(dbContext);
|
|
||||||
|
|
||||||
DateTime lastUpdate = DateTime.Now;
|
|
||||||
foreach (var record in records)
|
|
||||||
{
|
|
||||||
if (record.ImportRecord(dbContext, populateReferences))
|
|
||||||
recordsImported++;
|
|
||||||
|
|
||||||
if (DateTime.Now.Subtract(lastUpdate).TotalSeconds > 1)
|
|
||||||
{
|
|
||||||
// Update every second
|
|
||||||
this.Status.UpdateStatus((int)Math.Floor((((double)(records.IndexOf(record) + 1) / records.Count) * 100)), string.Format("Importing: {0} ({1} of {2})", record.SerialNumber, records.IndexOf(record) + 1, records.Count));
|
|
||||||
lastUpdate = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Status.SetFinishedMessage(string.Format("Imported {0} of {1} Devices", recordsImported, records.Count));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScheduledTaskStatus Run(string ImportParseTaskId)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(ImportParseTaskId))
|
|
||||||
throw new ArgumentNullException("ImportParseTaskId");
|
|
||||||
|
|
||||||
var task = new ImportProcessTask();
|
|
||||||
JobDataMap taskData = new JobDataMap() { { "ImportParseTaskId", ImportParseTaskId } };
|
|
||||||
return task.ScheduleTask(taskData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Search;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI
|
|
||||||
{
|
|
||||||
public static class Searching
|
|
||||||
{
|
|
||||||
private static List<DeviceSearchResultItem> Search_SelectDeviceSearchResultItem(IQueryable<Device> Query, int? LimitCount = null){
|
|
||||||
if (LimitCount.HasValue)
|
|
||||||
Query = Query.Take(LimitCount.Value);
|
|
||||||
|
|
||||||
return Query.Select(d => new DeviceSearchResultItem()
|
|
||||||
{
|
|
||||||
SerialNumber = d.SerialNumber,
|
|
||||||
AssetNumber = d.AssetNumber,
|
|
||||||
ComputerName = d.ComputerName,
|
|
||||||
DeviceModelDescription = d.DeviceModel.Description,
|
|
||||||
DeviceProfileDescription = d.DeviceProfile.Description,
|
|
||||||
DecommissionedDate = d.DecommissionedDate,
|
|
||||||
AssignedUserId = d.AssignedUserId,
|
|
||||||
AssignedUserDisplayName = d.AssignedUser.DisplayName,
|
|
||||||
JobCount = d.Jobs.Count()
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<DeviceSearchResultItem> Search(DiscoDataContext dbContext, string Term, int? LimitCount = null)
|
|
||||||
{
|
|
||||||
return Search_SelectDeviceSearchResultItem(dbContext.Devices.Where(d =>
|
|
||||||
d.AssetNumber.Contains(Term) ||
|
|
||||||
d.ComputerName.Contains(Term) ||
|
|
||||||
d.SerialNumber.Contains(Term) ||
|
|
||||||
d.Location.Contains(Term) ||
|
|
||||||
Term.Contains(d.SerialNumber)
|
|
||||||
), LimitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<DeviceSearchResultItem> SearchDeviceModel(DiscoDataContext dbContext, int DeviceModelId, int? LimitCount = null)
|
|
||||||
{
|
|
||||||
return Search_SelectDeviceSearchResultItem(dbContext.Devices.Where(d => d.DeviceModelId == DeviceModelId), LimitCount);
|
|
||||||
}
|
|
||||||
public static List<DeviceSearchResultItem> SearchDeviceProfile(DiscoDataContext dbContext, int DeviceProfileId, int? LimitCount = null)
|
|
||||||
{
|
|
||||||
return Search_SelectDeviceSearchResultItem(dbContext.Devices.Where(d => d.DeviceProfileId == DeviceProfileId), LimitCount);
|
|
||||||
}
|
|
||||||
public static List<DeviceSearchResultItem> SearchDeviceBatch(DiscoDataContext dbContext, int DeviceBatchId, int? LimitCount = null)
|
|
||||||
{
|
|
||||||
return Search_SelectDeviceSearchResultItem(dbContext.Devices.Where(d => d.DeviceBatchId == DeviceBatchId), LimitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace Disco.BI
|
|
||||||
{
|
|
||||||
public class DisposableImageCollection : List<Bitmap>, IDisposable
|
|
||||||
{
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
foreach (Image i in this)
|
|
||||||
{
|
|
||||||
if (i != null)
|
|
||||||
i.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using System.Web;
|
|
||||||
using System.Drawing;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI
|
|
||||||
{
|
|
||||||
class DocumentTemplateQRCodeLocationCache
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<string, List<RectangleF>> _Cache = new ConcurrentDictionary<string, List<RectangleF>>();
|
|
||||||
|
|
||||||
public static List<RectangleF> GetLocations(DocumentTemplate dt, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Check Cache
|
|
||||||
List<RectangleF> locations;
|
|
||||||
if (_Cache.TryGetValue(dt.Id, out locations))
|
|
||||||
{
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
// Generate Cache
|
|
||||||
return GenerateLocations(dt, dbContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InvalidateLocations(DocumentTemplate dt)
|
|
||||||
{
|
|
||||||
List<RectangleF> locations;
|
|
||||||
return _Cache.TryRemove(dt.Id, out locations);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool SetValue(string DocumentTemplateId, List<RectangleF> Locations)
|
|
||||||
{
|
|
||||||
if (_Cache.ContainsKey(DocumentTemplateId))
|
|
||||||
{
|
|
||||||
List<RectangleF> oldLocations;
|
|
||||||
if (_Cache.TryGetValue(DocumentTemplateId, out oldLocations))
|
|
||||||
{
|
|
||||||
return _Cache.TryUpdate(DocumentTemplateId, Locations, oldLocations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _Cache.TryAdd(DocumentTemplateId, Locations);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static List<RectangleF> GenerateLocations(DocumentTemplate dt, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string templateFilename = dt.RepositoryFilename(dbContext);
|
|
||||||
PdfReader pdfReader = new PdfReader(templateFilename);
|
|
||||||
List<RectangleF> locations = new List<RectangleF>();
|
|
||||||
|
|
||||||
if (pdfReader.AcroFields.Fields.ContainsKey("DiscoAttachmentId"))
|
|
||||||
{
|
|
||||||
foreach (var pdfFieldPosition in pdfReader.AcroFields.GetFieldPositions("DiscoAttachmentId"))
|
|
||||||
{
|
|
||||||
var pdfPageSize = pdfReader.GetPageSize(pdfFieldPosition.page);
|
|
||||||
// Original Position
|
|
||||||
locations.Add(new RectangleF(
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(pdfFieldPosition.position.Left / pdfPageSize.Width) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)((pdfPageSize.Height - pdfFieldPosition.position.Top) / pdfPageSize.Height) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(pdfFieldPosition.position.Width / pdfPageSize.Width) + 0.1)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(pdfFieldPosition.position.Height / pdfPageSize.Height) + 0.1))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pdfReader.Close();
|
|
||||||
|
|
||||||
// Update Cache
|
|
||||||
SetValue(dt.Id, locations);
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
namespace Disco.BI.DocumentTemplateBI
|
|
||||||
{
|
|
||||||
public class DocumentUniqueIdentifier
|
|
||||||
{
|
|
||||||
private bool? _loadedComponentsOk;
|
|
||||||
private DocumentTemplate _documentTemplate;
|
|
||||||
private object _data;
|
|
||||||
private string _dataDescription;
|
|
||||||
public string TemplateTypeId { get; private set; }
|
|
||||||
public string DataId { get; private set; }
|
|
||||||
public string DocumentUniqueId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return string.Format("{0}|{1}", this.TemplateTypeId, this.DataId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string CreatorId { get; private set; }
|
|
||||||
public System.DateTime TimeStamp { get; private set; }
|
|
||||||
public int Page { get; private set; }
|
|
||||||
public string Tag { get; private set; }
|
|
||||||
public DocumentTemplate DocumentTemplate
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this._loadedComponentsOk.HasValue && this._loadedComponentsOk.Value;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return this._documentTemplate;
|
|
||||||
}
|
|
||||||
throw new System.Exception("Document Unique Identifier Components not loaded or invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public object Data
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this._loadedComponentsOk.HasValue && this._loadedComponentsOk.Value;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return this._data;
|
|
||||||
}
|
|
||||||
throw new System.Exception("Document Unique Identifier Components not loaded or invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string DataDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
bool flag = this._loadedComponentsOk.HasValue && this._loadedComponentsOk.Value;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
return this._dataDescription;
|
|
||||||
}
|
|
||||||
throw new System.Exception("Document Unique Identifier Components not loaded or invalid");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string DataScope { get; private set; }
|
|
||||||
public static bool IsDocumentUniqueIdentifier(string UniqueIdentifier)
|
|
||||||
{
|
|
||||||
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.InvariantCultureIgnoreCase);
|
|
||||||
}
|
|
||||||
public DocumentUniqueIdentifier(string TemplateTypeId, string DataId, string CreatorId, DateTime TimeStamp, int? Page = null, string Tag = null)
|
|
||||||
{
|
|
||||||
this.Tag = Tag;
|
|
||||||
this.TemplateTypeId = TemplateTypeId;
|
|
||||||
this.DataId = DataId;
|
|
||||||
this.CreatorId = CreatorId;
|
|
||||||
this.TimeStamp = TimeStamp;
|
|
||||||
this.Page = Page ?? 0;
|
|
||||||
}
|
|
||||||
public DocumentUniqueIdentifier(string UniqueIdentifier, string Tag)
|
|
||||||
{
|
|
||||||
if (!DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(UniqueIdentifier))
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Invalid Document Unique Identifier", "UniqueIdentifier");
|
|
||||||
}
|
|
||||||
this.Tag = Tag;
|
|
||||||
string[] s = UniqueIdentifier.Split(new char[] { '|' });
|
|
||||||
string left = s[1].ToUpper();
|
|
||||||
if (left == "AT" || left == "1")
|
|
||||||
{
|
|
||||||
if (s.Length >= 3)
|
|
||||||
{
|
|
||||||
this.TemplateTypeId = s[2];
|
|
||||||
}
|
|
||||||
if (s.Length >= 4)
|
|
||||||
{
|
|
||||||
this.DataId = s[3];
|
|
||||||
}
|
|
||||||
if (s.Length >= 5)
|
|
||||||
{
|
|
||||||
this.CreatorId = s[4];
|
|
||||||
}
|
|
||||||
if (s.Length >= 6)
|
|
||||||
{
|
|
||||||
System.DateTime timeStamp;
|
|
||||||
if (System.DateTime.TryParse(s[5], out timeStamp))
|
|
||||||
{
|
|
||||||
this.TimeStamp = timeStamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (s.Length >= 7)
|
|
||||||
{
|
|
||||||
int page = 0;
|
|
||||||
if (int.TryParse(s[6], out page))
|
|
||||||
{
|
|
||||||
this.Page = page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new System.ArgumentException(string.Format("Invalid Document Unique Identifier Version ({0})", s[1]), "UniqueIdentifier");
|
|
||||||
}
|
|
||||||
public bool LoadComponents(DiscoDataContext Context)
|
|
||||||
{
|
|
||||||
bool LoadComponents;
|
|
||||||
if (!this._loadedComponentsOk.HasValue)
|
|
||||||
{
|
|
||||||
string scopeType;
|
|
||||||
if (this.TemplateTypeId.StartsWith("--"))
|
|
||||||
{
|
|
||||||
string templateTypeId = this.TemplateTypeId;
|
|
||||||
switch (this.TemplateTypeId)
|
|
||||||
{
|
|
||||||
case "--DEVICE":
|
|
||||||
scopeType = DocumentTemplate.DocumentTemplateScopes.Device;
|
|
||||||
break;
|
|
||||||
case "--JOB":
|
|
||||||
scopeType = DocumentTemplate.DocumentTemplateScopes.Job;
|
|
||||||
break;
|
|
||||||
case "--USER":
|
|
||||||
scopeType = DocumentTemplate.DocumentTemplateScopes.User;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
scopeType = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this._documentTemplate = Context.DocumentTemplates.Find(this.TemplateTypeId);
|
|
||||||
if (this._documentTemplate != null)
|
|
||||||
{
|
|
||||||
scopeType = this._documentTemplate.Scope;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
scopeType = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (scopeType != null)
|
|
||||||
{
|
|
||||||
this.DataScope = scopeType;
|
|
||||||
switch (scopeType)
|
|
||||||
{
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
||||||
Device d = Context.Devices.Find(this.DataId);
|
|
||||||
if (d != null)
|
|
||||||
{
|
|
||||||
this._data = d;
|
|
||||||
this._dataDescription = d.SerialNumber;
|
|
||||||
this._loadedComponentsOk = true;
|
|
||||||
LoadComponents = true;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
||||||
Job i = Context.Jobs.Find(int.Parse(this.DataId));
|
|
||||||
if (i != null)
|
|
||||||
{
|
|
||||||
this._data = i;
|
|
||||||
this._dataDescription = i.Id.ToString();
|
|
||||||
this._loadedComponentsOk = true;
|
|
||||||
LoadComponents = true;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
||||||
User u = Context.Users.Find(this.DataId);
|
|
||||||
if (u != null)
|
|
||||||
{
|
|
||||||
this._data = u;
|
|
||||||
this._dataDescription = u.DisplayName;
|
|
||||||
this._loadedComponentsOk = true;
|
|
||||||
LoadComponents = true;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._loadedComponentsOk = false;
|
|
||||||
}
|
|
||||||
LoadComponents = this._loadedComponentsOk.Value;
|
|
||||||
return LoadComponents;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Web.Caching;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl;
|
|
||||||
using Quartz.Impl.Triggers;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI.Importer
|
|
||||||
{
|
|
||||||
public class DocumentDropBoxMonitor : System.IDisposable
|
|
||||||
{
|
|
||||||
private IScheduler _scheduler;
|
|
||||||
private FileSystemWatcher _fsw;
|
|
||||||
private Cache _httpCache;
|
|
||||||
|
|
||||||
public const string WatcherFilter = "*.pdf";
|
|
||||||
public string DropBoxLocation { get; private set; }
|
|
||||||
|
|
||||||
public DocumentDropBoxMonitor(DiscoDataContext Context, ISchedulerFactory SchedulerFactory, Cache HttpCache)
|
|
||||||
{
|
|
||||||
if (Context == null)
|
|
||||||
throw new System.ArgumentNullException("Context");
|
|
||||||
|
|
||||||
this._httpCache = HttpCache;
|
|
||||||
|
|
||||||
var location = DataStore.CreateLocation(Context, "DocumentDropBox");
|
|
||||||
this.DropBoxLocation = location.EndsWith(@"\") ? location : string.Concat(location, @"\");
|
|
||||||
|
|
||||||
this._scheduler = SchedulerFactory.GetScheduler();
|
|
||||||
this._scheduler.Start();
|
|
||||||
}
|
|
||||||
public void ScheduleCurrentFiles(int Delay)
|
|
||||||
{
|
|
||||||
foreach (var filename in System.IO.Directory.GetFiles(this.DropBoxLocation, "*.pdf"))
|
|
||||||
{
|
|
||||||
this.ScheduleFile(filename, Delay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void StartWatching()
|
|
||||||
{
|
|
||||||
if (this._fsw == null)
|
|
||||||
{
|
|
||||||
this._fsw = new FileSystemWatcher(this.DropBoxLocation, "*.pdf");
|
|
||||||
this._fsw.Created += new FileSystemEventHandler(this.FSW_Created);
|
|
||||||
}
|
|
||||||
this._fsw.EnableRaisingEvents = true;
|
|
||||||
}
|
|
||||||
public void StopWatching()
|
|
||||||
{
|
|
||||||
if (this._fsw != null)
|
|
||||||
{
|
|
||||||
this._fsw.EnableRaisingEvents = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void ScheduleFile(string Filename, int Delay)
|
|
||||||
{
|
|
||||||
System.Guid guid = System.Guid.NewGuid();
|
|
||||||
JobDetailImpl jd = new JobDetailImpl(guid.ToString(), typeof(DocumentImporterJob));
|
|
||||||
jd.JobDataMap.Add("Filename", Filename);
|
|
||||||
jd.JobDataMap.Add("RetryCount", 0);
|
|
||||||
jd.JobDataMap.Add("HttpCache", this._httpCache);
|
|
||||||
guid = System.Guid.NewGuid();
|
|
||||||
|
|
||||||
System.DateTimeOffset startTimeUtc = new System.DateTimeOffset(DateTime.Now.AddSeconds((double)Delay));
|
|
||||||
SimpleTriggerImpl trig = new SimpleTriggerImpl(guid.ToString(), startTimeUtc);
|
|
||||||
|
|
||||||
this._scheduler.ScheduleJob(jd, trig);
|
|
||||||
}
|
|
||||||
private void FSW_Created(object sender, FileSystemEventArgs e)
|
|
||||||
{
|
|
||||||
if ((e.ChangeType & WatcherChangeTypes.Deleted) != WatcherChangeTypes.Deleted)
|
|
||||||
this.ScheduleFile(e.FullPath, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
this.StopWatching();
|
|
||||||
if (this._fsw != null)
|
|
||||||
this._fsw.Dispose();
|
|
||||||
if (this._scheduler != null)
|
|
||||||
this._scheduler.Shutdown(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Web.Caching;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl.Triggers;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI.Importer
|
|
||||||
{
|
|
||||||
[PersistJobDataAfterExecution]
|
|
||||||
public class DocumentImporterJob : IJob
|
|
||||||
{
|
|
||||||
|
|
||||||
void IJob.Execute(IJobExecutionContext context)
|
|
||||||
{
|
|
||||||
string sessionId = context.JobDetail.JobDataMap["SessionId"] as string;
|
|
||||||
if (string.IsNullOrEmpty(sessionId))
|
|
||||||
{
|
|
||||||
sessionId = Guid.NewGuid().ToString();
|
|
||||||
context.JobDetail.JobDataMap["SessionId"] = sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
string filename = context.JobDetail.JobDataMap["Filename"] as string;
|
|
||||||
int retryCount = (int)context.JobDetail.JobDataMap["RetryCount"];
|
|
||||||
Cache httpCache = context.JobDetail.JobDataMap["HttpCache"] as Cache;
|
|
||||||
|
|
||||||
var friendlyFilename = filename;
|
|
||||||
if (!string.IsNullOrEmpty(friendlyFilename))
|
|
||||||
friendlyFilename = System.IO.Path.GetFileName(friendlyFilename);
|
|
||||||
|
|
||||||
DocumentImporterLog.LogImportStarting(sessionId, friendlyFilename);
|
|
||||||
|
|
||||||
if (!File.Exists(filename))
|
|
||||||
{
|
|
||||||
DocumentImporterLog.LogImportWarning(sessionId, string.Format("File not found: {0}", filename));
|
|
||||||
DocumentImporterLog.LogImportFinished(sessionId);
|
|
||||||
context.Scheduler.DeleteJob(context.JobDetail.Key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (DiscoDataContext dbContext = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
if (retryCount < 18)
|
|
||||||
{
|
|
||||||
context.JobDetail.JobDataMap["RetryCount"] = (++retryCount);
|
|
||||||
bool processResult = Interop.Pdf.PdfImporter.ProcessPdfAttachment(filename, dbContext, sessionId, httpCache);
|
|
||||||
|
|
||||||
if (processResult)
|
|
||||||
{
|
|
||||||
// Import Successful - Delete
|
|
||||||
if (File.Exists(filename))
|
|
||||||
File.Delete(filename);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Import Failed - Move to Errors Folder
|
|
||||||
if (File.Exists(filename))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string folderError = DataStore.CreateLocation(dbContext, "DocumentDropBox_Errors");
|
|
||||||
string filenameError = Path.Combine(folderError, Path.GetFileName(filename));
|
|
||||||
int filenameErrorCount = 0;
|
|
||||||
while (File.Exists(filenameError))
|
|
||||||
{
|
|
||||||
filenameError = Path.Combine(folderError, string.Format("{0} ({1}){2}", Path.GetFileNameWithoutExtension(filename), ++filenameErrorCount, Path.GetExtension(filename)));
|
|
||||||
}
|
|
||||||
File.Move(filename, filenameError);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore Errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// To Many Errors
|
|
||||||
DocumentImporterLog.LogImportError(sessionId, string.Format("To many errors occurred trying to import '{1}' (SessionId: {0})", sessionId, friendlyFilename));
|
|
||||||
// Move to Errors Folder
|
|
||||||
if (File.Exists(filename))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string folderError = DataStore.CreateLocation(dbContext, "DocumentDropBox_Errors");
|
|
||||||
string filenameError = Path.Combine(folderError, Path.GetFileName(filename));
|
|
||||||
int filenameErrorCount = 0;
|
|
||||||
while (File.Exists(filenameError))
|
|
||||||
{
|
|
||||||
filenameError = Path.Combine(folderError, string.Format("{0} ({1}){2}", Path.GetFileNameWithoutExtension(filename), ++filenameErrorCount, Path.GetExtension(filename)));
|
|
||||||
}
|
|
||||||
File.Move(filename, filenameError);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore Errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DocumentImporterLog.LogImportFinished(sessionId);
|
|
||||||
|
|
||||||
// All Done
|
|
||||||
context.Scheduler.DeleteJob(context.JobDetail.Key);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.LogImportWarning(sessionId, string.Format("{0}; Will try again in 10 Seconds", ex.Message));
|
|
||||||
// Reschedule Job for 10 seconds
|
|
||||||
SimpleTriggerImpl trig = new SimpleTriggerImpl(Guid.NewGuid().ToString(), new DateTimeOffset(DateTime.Now.AddSeconds(10)));
|
|
||||||
context.Scheduler.RescheduleJob(context.Trigger.Key, trig);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
using Disco.Services.Logging;
|
|
||||||
using Disco.Services.Logging.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
namespace Disco.BI.DocumentTemplateBI.Importer
|
|
||||||
{
|
|
||||||
public class DocumentImporterLog : LogBase
|
|
||||||
{
|
|
||||||
public enum EventTypeIds
|
|
||||||
{
|
|
||||||
ImportStarting = 10,
|
|
||||||
ImportProgress,
|
|
||||||
ImportFinished,
|
|
||||||
ImportWarning = 15,
|
|
||||||
ImportError,
|
|
||||||
ImportPageStarting = 100,
|
|
||||||
ImportPageImageUpdate = 104,
|
|
||||||
ImportPageProgress,
|
|
||||||
ImportPageDetected = 110,
|
|
||||||
ImportPageUndetected = 115,
|
|
||||||
ImportPageError = 120,
|
|
||||||
ImportPageUndetectedStored = 150
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int _ModuleId = 40;
|
|
||||||
|
|
||||||
public static DocumentImporterLog Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (DocumentImporterLog)LogContext.LogModules[_ModuleId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ModuleDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Document Importer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override int ModuleId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _ModuleId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "DocumentImporter";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static void Log(DocumentImporterLog.EventTypeIds EventTypeId, params object[] Args)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Current.Log((int)EventTypeId, Args);
|
|
||||||
}
|
|
||||||
public static void LogImportStarting(string SessionId, string DocumentName)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportStarting, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
DocumentName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportProgress(string SessionId, int? Progress, string Status)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportProgress, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Progress,
|
|
||||||
Status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportFinished(string SessionId)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportFinished, new object[]
|
|
||||||
{
|
|
||||||
SessionId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportWarning(string SessionId, string Message)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportWarning, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportError(string SessionId, string Message)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportError, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageStarting(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageStarting, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageImageUpdate(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageImageUpdate, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageProgress(string SessionId, int PageNumber, int? Progress, string Status)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageProgress, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber,
|
|
||||||
Progress,
|
|
||||||
Status
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageDetected(string SessionId, int PageNumber, string DocumentTypeId, string DocumentTypeName, string TargetType, string AssignedId, string AssignedName)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageDetected, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber,
|
|
||||||
DocumentTypeId,
|
|
||||||
DocumentTypeName,
|
|
||||||
TargetType,
|
|
||||||
AssignedId,
|
|
||||||
AssignedName
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageUndetected(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageUndetected, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageError(string SessionId, int PageNumber, string Message)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageError, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogImportPageUndetectedStored(string SessionId, int PageNumber)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.Log(DocumentImporterLog.EventTypeIds.ImportPageUndetectedStored, new object[]
|
|
||||||
{
|
|
||||||
SessionId,
|
|
||||||
PageNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<LogEventType>
|
|
||||||
{
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 10,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Starting",
|
|
||||||
Format = "Starting import of document: {1} (SessionId: {0})",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 11,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Progress",
|
|
||||||
Format = "Processing: {1}% Complete; Status: {2}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 12,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Finished",
|
|
||||||
Format = "Import of document complete (SessionId: {0})",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 15,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Warning",
|
|
||||||
Format = "Import Warning: {1} (SessionId: {0})",
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 16,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Error",
|
|
||||||
Format = "Import Error: {1} (SessionId: {0})",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 100,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Starting",
|
|
||||||
Format = "Starting import of page: {1} (SessionId: {0})",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 104,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Image Update",
|
|
||||||
Format = null,
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 105,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Progress",
|
|
||||||
Format = "Processing: Page {1}; {2}% Complete; Status: {3}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 110,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Assigned",
|
|
||||||
Format = "Page {1} of type '{3}' assigned to {4}: '{6}'",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 115,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Undetected",
|
|
||||||
Format = "Page {1} not detected",
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 120,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Error",
|
|
||||||
Format = "Page {1}, Import Error: {2}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 150,
|
|
||||||
ModuleId = 40,
|
|
||||||
Name = "Import Page Undetected Stored",
|
|
||||||
Format = null,
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
using iTextSharp.text;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
|
|
||||||
namespace Disco.BI.DocumentTemplateBI
|
|
||||||
{
|
|
||||||
public static class Utilities
|
|
||||||
{
|
|
||||||
public static System.IO.Stream JoinPdfs(params System.IO.Stream[] Pdfs)
|
|
||||||
{
|
|
||||||
if (Pdfs.Length == 0)
|
|
||||||
throw new System.ArgumentNullException("Pdfs");
|
|
||||||
|
|
||||||
// Only One PDF - Possible Reference Bug v's Memory/Speed (Returning Param Memory Stream)
|
|
||||||
if (Pdfs.Length == 1)
|
|
||||||
return Pdfs[0];
|
|
||||||
|
|
||||||
// Join Pdfs
|
|
||||||
System.IO.MemoryStream msBuilder = new System.IO.MemoryStream();
|
|
||||||
|
|
||||||
Document pdfDoc = new Document();
|
|
||||||
PdfCopy pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
|
||||||
pdfDoc.Open();
|
|
||||||
pdfCopy.CloseStream = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < Pdfs.Length; i++)
|
|
||||||
{
|
|
||||||
System.IO.Stream pdf = Pdfs[i];
|
|
||||||
PdfReader pdfReader = new PdfReader(pdf);
|
|
||||||
|
|
||||||
for (int indexPage = 1; indexPage <= pdfReader.NumberOfPages; indexPage++)
|
|
||||||
{
|
|
||||||
iTextSharp.text.Rectangle pageSize = pdfReader.GetPageSizeWithRotation(indexPage);
|
|
||||||
PdfImportedPage page = pdfCopy.GetImportedPage(pdfReader, indexPage);
|
|
||||||
pdfDoc.SetPageSize(pageSize);
|
|
||||||
pdfDoc.NewPage();
|
|
||||||
pdfCopy.AddPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfReader.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfDoc.Close();
|
|
||||||
pdfCopy.Close();
|
|
||||||
msBuilder.Position = 0;
|
|
||||||
|
|
||||||
return msBuilder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Expressions;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
|
||||||
{
|
|
||||||
public sealed class Expression : System.Collections.Generic.List<IExpressionPart>
|
|
||||||
{
|
|
||||||
public string Name { get; private set; }
|
|
||||||
public string Source { get; private set; }
|
|
||||||
public bool IsDynamic { get; private set; }
|
|
||||||
public int Ordinal { get; private set; }
|
|
||||||
|
|
||||||
private Expression(string Name, string Source, int Ordinal)
|
|
||||||
{
|
|
||||||
this.Name = Name;
|
|
||||||
this.Source = Source;
|
|
||||||
this.Ordinal = Ordinal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void InitializeExpressions()
|
|
||||||
{
|
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("DataExt", typeof(Extensions.DataExt));
|
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("UserExt", typeof(Extensions.UserExt));
|
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("DeviceExt", typeof(Extensions.DeviceExt));
|
|
||||||
Spring.Core.TypeResolution.TypeRegistry.RegisterType("ImageExt", typeof(Extensions.ImageExt));
|
|
||||||
}
|
|
||||||
|
|
||||||
public T EvaluateFirst<T>(object ExpressionContext, System.Collections.IDictionary Variables)
|
|
||||||
{
|
|
||||||
T result = default(T);
|
|
||||||
if (this.Count > 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object expressionResult = this[0].Evaluate(ExpressionContext, Variables);
|
|
||||||
if (expressionResult != null)
|
|
||||||
{
|
|
||||||
if (expressionResult is T)
|
|
||||||
{
|
|
||||||
result = (T)expressionResult;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Expression returned an invalid type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Expression evaluation resulted in an error", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Tuple<string, bool, object> Evaluate(object ExpressionContext, System.Collections.IDictionary Variables)
|
|
||||||
{
|
|
||||||
System.Text.StringBuilder resultValue = new System.Text.StringBuilder();
|
|
||||||
object resultObject = null;
|
|
||||||
bool resultError = false;
|
|
||||||
foreach (var expressionPart in this)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object partValue = expressionPart.Evaluate(ExpressionContext, Variables);
|
|
||||||
if (partValue != null)
|
|
||||||
{
|
|
||||||
// Check for Result Objects
|
|
||||||
if (partValue is IImageExpressionResult)
|
|
||||||
resultObject = partValue;
|
|
||||||
else
|
|
||||||
resultValue.Append(partValue.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
if (!expressionPart.ErrorsAllowed)
|
|
||||||
{
|
|
||||||
resultValue.Append("## ERROR # ");
|
|
||||||
resultValue.Append(ex.Message);
|
|
||||||
resultValue.Append(" ##");
|
|
||||||
resultError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Tuple<string, bool, object>(resultValue.ToString(), resultError, resultObject);
|
|
||||||
}
|
|
||||||
public static Expression TokenizeSingleDynamic(string Name, string ExpressionSource, int Ordinal)
|
|
||||||
{
|
|
||||||
Expression e = new Expression(Name, ExpressionSource, Ordinal);
|
|
||||||
if (ExpressionSource != null && !string.IsNullOrWhiteSpace(ExpressionSource))
|
|
||||||
e.Add(new EvaluateExpressionPart(ExpressionSource));
|
|
||||||
e.IsDynamic = true;
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
public static Expression Tokenize(string Name, string ExpressionSource, int Ordinal)
|
|
||||||
{
|
|
||||||
Expression e = new Expression(Name, ExpressionSource, Ordinal);
|
|
||||||
if (!ExpressionSource.Contains("{") || !ExpressionSource.Contains("}"))
|
|
||||||
{
|
|
||||||
e.Add(new TextExpressionPart(ExpressionSource));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
System.Text.StringBuilder token = new System.Text.StringBuilder();
|
|
||||||
bool tokenEval = false;
|
|
||||||
int tokenEvalDepth = 0;
|
|
||||||
foreach (char c in ExpressionSource)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '{':
|
|
||||||
{
|
|
||||||
if (!tokenEval)
|
|
||||||
{
|
|
||||||
if (token.Length > 0)
|
|
||||||
{
|
|
||||||
e.Add(new TextExpressionPart(token.ToString()));
|
|
||||||
token = new System.Text.StringBuilder();
|
|
||||||
}
|
|
||||||
tokenEval = true;
|
|
||||||
tokenEvalDepth = 0;
|
|
||||||
}
|
|
||||||
tokenEvalDepth++;
|
|
||||||
token.Append(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case '}':
|
|
||||||
{
|
|
||||||
token.Append(c);
|
|
||||||
if (tokenEval)
|
|
||||||
{
|
|
||||||
tokenEvalDepth--;
|
|
||||||
if (tokenEvalDepth <= 0)
|
|
||||||
{
|
|
||||||
if (token.Length != 2 && (token.Length != 3 || token[1] != '@'))
|
|
||||||
{
|
|
||||||
e.Add(new EvaluateExpressionPart(token.ToString()));
|
|
||||||
e.IsDynamic = true;
|
|
||||||
token = new System.Text.StringBuilder();
|
|
||||||
}
|
|
||||||
tokenEval = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
token.Append(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (token.Length > 0)
|
|
||||||
{
|
|
||||||
e.Add(new TextExpressionPart(token.ToString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IDictionary StandardVariables(DocumentTemplate AttachmentType, DiscoDataContext DataContext, User User, System.DateTime TimeStamp, DocumentState DocumentState)
|
|
||||||
{
|
|
||||||
return new Hashtable
|
|
||||||
{
|
|
||||||
|
|
||||||
{
|
|
||||||
"DataContext",
|
|
||||||
DataContext
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"User",
|
|
||||||
User
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"TimeStamp",
|
|
||||||
TimeStamp
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"AttachmentType",
|
|
||||||
AttachmentType
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"State",
|
|
||||||
DocumentState
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public static Dictionary<string, string> StandardVariableTypes()
|
|
||||||
{
|
|
||||||
return new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
|
|
||||||
{
|
|
||||||
"#DataContext",
|
|
||||||
typeof(DiscoDataContext).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"#User",
|
|
||||||
typeof(User).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"#TimeStamp",
|
|
||||||
typeof(System.DateTime).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"#AttachmentType",
|
|
||||||
typeof(DocumentTemplate).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"#State",
|
|
||||||
typeof(DocumentState).AssemblyQualifiedName
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public static Dictionary<string, string> ExtensionLibraryTypes()
|
|
||||||
{
|
|
||||||
return new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"DataExt",
|
|
||||||
typeof(Extensions.DataExt).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"DeviceExt",
|
|
||||||
typeof(Extensions.DeviceExt).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"ImageExt",
|
|
||||||
typeof(Extensions.ImageExt).AssemblyQualifiedName
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"UserExt",
|
|
||||||
typeof(Extensions.UserExt).AssemblyQualifiedName
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
|
||||||
{
|
|
||||||
public static class ExpressionCache
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<string, ConcurrentDictionary<string, Expression>> _Cache = new ConcurrentDictionary<string, ConcurrentDictionary<string, Expression>>();
|
|
||||||
|
|
||||||
public delegate Expression CreateValueDelegate();
|
|
||||||
|
|
||||||
public static ConcurrentDictionary<string, Expression> GetModule(string Module, bool Create = false)
|
|
||||||
{
|
|
||||||
ConcurrentDictionary<string, Expression> moduleCache;
|
|
||||||
if (_Cache.TryGetValue(Module, out moduleCache))
|
|
||||||
return moduleCache;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (Create)
|
|
||||||
{
|
|
||||||
moduleCache = new ConcurrentDictionary<string, Expression>();
|
|
||||||
_Cache.TryAdd(Module, moduleCache);
|
|
||||||
return moduleCache;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static Expression GetModuleValue(string Module, string Key, CreateValueDelegate CreateValue)
|
|
||||||
{
|
|
||||||
ConcurrentDictionary<string, Expression> moduleCache = GetModule(Module, (CreateValue != null));
|
|
||||||
if (moduleCache != null)
|
|
||||||
{
|
|
||||||
Expression expression;
|
|
||||||
if (moduleCache.TryGetValue(Key, out expression))
|
|
||||||
{
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
if (CreateValue != null)
|
|
||||||
{
|
|
||||||
expression = CreateValue();
|
|
||||||
Expression oldExpression;
|
|
||||||
if (moduleCache.TryGetValue(Key, out oldExpression))
|
|
||||||
moduleCache.TryUpdate(Key, expression, oldExpression);
|
|
||||||
else
|
|
||||||
moduleCache.TryAdd(Key, expression);
|
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Expression GetValue(string Module, string Key, CreateValueDelegate CreateValue)
|
|
||||||
{
|
|
||||||
return GetModuleValue(Module, Key, CreateValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Expression GetValue(string Module, string Key)
|
|
||||||
{
|
|
||||||
return GetModuleValue(Module, Key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InvalidModule(string Module)
|
|
||||||
{
|
|
||||||
ConcurrentDictionary<string, Expression> moduleCache;
|
|
||||||
return _Cache.TryRemove(Module, out moduleCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InvalidateKey(string Module, string Key)
|
|
||||||
{
|
|
||||||
Expression expression;
|
|
||||||
ConcurrentDictionary<string, Expression> moduleCache = GetModule(Module, false);
|
|
||||||
if (moduleCache != null)
|
|
||||||
{
|
|
||||||
bool removeResult = moduleCache.TryRemove(Key, out expression);
|
|
||||||
if (moduleCache.Count == 0)
|
|
||||||
InvalidModule(Module);
|
|
||||||
return removeResult;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool SetValue(string Module, string Key, Expression Expression)
|
|
||||||
{
|
|
||||||
ConcurrentDictionary<string, Expression> moduleCache = GetModule(Module, true);
|
|
||||||
|
|
||||||
if (moduleCache.ContainsKey(Key))
|
|
||||||
{
|
|
||||||
Expression oldExpression;
|
|
||||||
if (moduleCache.TryGetValue(Key, out oldExpression))
|
|
||||||
{
|
|
||||||
return moduleCache.TryUpdate(Key, Expression, oldExpression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return moduleCache.TryAdd(Key, Expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
|
||||||
{
|
|
||||||
public class ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
public const string FunctionKind = "function";
|
|
||||||
public const string PropertyKind = "property";
|
|
||||||
public const string ParameterKind = "parameter";
|
|
||||||
|
|
||||||
public string Kind {get;set;}
|
|
||||||
public string Name {get;set;}
|
|
||||||
public string ReturnType {get;set;}
|
|
||||||
public string ReturnExpressionType{get;set;}
|
|
||||||
public List<ExpressionTypeMemberDescriptor> Parameters{get;set;}
|
|
||||||
|
|
||||||
public static ExpressionTypeMemberDescriptor Build(System.Reflection.MethodInfo m)
|
|
||||||
{
|
|
||||||
ExpressionTypeMemberDescriptor md = new ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
Kind = "function",
|
|
||||||
Name = m.Name,
|
|
||||||
ReturnType = m.ReturnType.Name,
|
|
||||||
ReturnExpressionType = m.ReturnType.AssemblyQualifiedName
|
|
||||||
};
|
|
||||||
md.Parameters = (
|
|
||||||
from mdp in m.GetParameters()
|
|
||||||
select ExpressionTypeMemberDescriptor.Build(mdp)).ToList<ExpressionTypeMemberDescriptor>();
|
|
||||||
return md;
|
|
||||||
}
|
|
||||||
public static ExpressionTypeMemberDescriptor Build(System.Reflection.PropertyInfo p)
|
|
||||||
{
|
|
||||||
ExpressionTypeMemberDescriptor md = new ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
Kind = "property",
|
|
||||||
Name = p.Name,
|
|
||||||
ReturnType = p.PropertyType.Name,
|
|
||||||
ReturnExpressionType = p.PropertyType.AssemblyQualifiedName
|
|
||||||
};
|
|
||||||
md.Parameters = (
|
|
||||||
from mdp in p.GetIndexParameters()
|
|
||||||
select ExpressionTypeMemberDescriptor.Build(mdp)).ToList<ExpressionTypeMemberDescriptor>();
|
|
||||||
return md;
|
|
||||||
}
|
|
||||||
public static ExpressionTypeMemberDescriptor Build(System.Reflection.ParameterInfo pi)
|
|
||||||
{
|
|
||||||
return new ExpressionTypeMemberDescriptor
|
|
||||||
{
|
|
||||||
Kind = "parameter",
|
|
||||||
Name = pi.Name,
|
|
||||||
ReturnType = pi.ParameterType.Name,
|
|
||||||
ReturnExpressionType = pi.ParameterType.AssemblyQualifiedName
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-70
@@ -1,70 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Expressions;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
|
||||||
{
|
|
||||||
public abstract class BaseImageExpressionResult : IImageExpressionResult
|
|
||||||
{
|
|
||||||
public byte Quality { get; set; }
|
|
||||||
public bool LosslessFormat { get; set; }
|
|
||||||
public bool ShowField { get; set; }
|
|
||||||
public string BackgroundColour { get; set; }
|
|
||||||
public bool BackgroundPreferTransparent { get; set; }
|
|
||||||
|
|
||||||
public BaseImageExpressionResult()
|
|
||||||
{
|
|
||||||
this.LosslessFormat = false;
|
|
||||||
this.Quality = 90;
|
|
||||||
this.ShowField = false;
|
|
||||||
this.BackgroundPreferTransparent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Stream GetImage(int Width, int Height);
|
|
||||||
|
|
||||||
protected Stream RenderImage(Image SourceImage, int Width, int Height)
|
|
||||||
{
|
|
||||||
if (SourceImage == null)
|
|
||||||
throw new ArgumentNullException("SourceImage");
|
|
||||||
if (Width <= 0)
|
|
||||||
throw new ArgumentOutOfRangeException("Width", "Width must be > 0");
|
|
||||||
if (Height <= 0)
|
|
||||||
throw new ArgumentOutOfRangeException("Height", "Height must be > 0");
|
|
||||||
|
|
||||||
Brush backgroundBrush = null;
|
|
||||||
if (!LosslessFormat || !BackgroundPreferTransparent)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(this.BackgroundColour))
|
|
||||||
backgroundBrush = Brushes.White;
|
|
||||||
else
|
|
||||||
backgroundBrush = new SolidBrush(ColorTranslator.FromHtml(this.BackgroundColour));
|
|
||||||
}
|
|
||||||
|
|
||||||
using (Image resizedImage = SourceImage.ResizeImage(Width, Height, backgroundBrush))
|
|
||||||
{
|
|
||||||
return OutputImage(resizedImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Stream OutputImage(Image SourceImage)
|
|
||||||
{
|
|
||||||
MemoryStream imageStream = new MemoryStream();
|
|
||||||
if (LosslessFormat)
|
|
||||||
{ // Lossless Format - PNG
|
|
||||||
SourceImage.SavePng(imageStream);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // Lossy Format - JPG
|
|
||||||
byte quality = Math.Min((byte)100, Math.Max((byte)1, this.Quality));
|
|
||||||
SourceImage.SaveJpg(quality, imageStream);
|
|
||||||
}
|
|
||||||
imageStream.Position = 0;
|
|
||||||
return imageStream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
|
||||||
{
|
|
||||||
public class BitmapImageExpressionResult : BaseImageExpressionResult
|
|
||||||
{
|
|
||||||
public Image Image { get; set; }
|
|
||||||
|
|
||||||
public BitmapImageExpressionResult(Image Image)
|
|
||||||
{
|
|
||||||
if (Image == null)
|
|
||||||
throw new ArgumentNullException("Image");
|
|
||||||
|
|
||||||
this.Image = Image;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Stream GetImage(int Width, int Height)
|
|
||||||
{
|
|
||||||
return this.RenderImage(this.Image, Width, Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions.ImageResultImplementations
|
|
||||||
{
|
|
||||||
public class FileImageExpressionResult : BaseImageExpressionResult
|
|
||||||
{
|
|
||||||
public string AbsoluteFilePath { get; set; }
|
|
||||||
|
|
||||||
public FileImageExpressionResult(string AbsoluteFilePath)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(AbsoluteFilePath))
|
|
||||||
throw new ArgumentNullException("AbsoluteFilePath");
|
|
||||||
if (!File.Exists(AbsoluteFilePath))
|
|
||||||
throw new FileNotFoundException("Image not found", AbsoluteFilePath);
|
|
||||||
|
|
||||||
this.AbsoluteFilePath = AbsoluteFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Stream GetImage(int Width, int Height)
|
|
||||||
{
|
|
||||||
using (Image SourceImage = Bitmap.FromFile(this.AbsoluteFilePath))
|
|
||||||
{
|
|
||||||
return this.RenderImage(SourceImage, Width, Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.BI.Interop.ActiveDirectory;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions.Extensions
|
|
||||||
{
|
|
||||||
public static class UserExt
|
|
||||||
{
|
|
||||||
public static object GetActiveDirectoryObjectValue(User User, string PropertyName, int Index = 0)
|
|
||||||
{
|
|
||||||
var adUserAccount = User.ActiveDirectoryAccount(PropertyName);
|
|
||||||
if (adUserAccount != null)
|
|
||||||
return adUserAccount.GetPropertyValue(PropertyName, Index);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetActiveDirectoryStringValue(User User, string PropertyName, int Index = 0)
|
|
||||||
{
|
|
||||||
var objectValue = GetActiveDirectoryObjectValue(User, PropertyName, Index);
|
|
||||||
string stringValue = objectValue as string;
|
|
||||||
if (stringValue == null && objectValue != null)
|
|
||||||
stringValue = objectValue.ToString();
|
|
||||||
return stringValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetActiveDirectoryIntegerValue(User User, string PropertyName, int Index = 0)
|
|
||||||
{
|
|
||||||
var objectValue = GetActiveDirectoryObjectValue(User, PropertyName, Index);
|
|
||||||
if (objectValue == null)
|
|
||||||
return default(int);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int intValue;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
intValue = (int)Convert.ChangeType(objectValue, typeof(int));
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
return intValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Disco.BI.Expressions
|
|
||||||
{
|
|
||||||
public interface IExpressionPart
|
|
||||||
{
|
|
||||||
string RawSource { get; set; }
|
|
||||||
string Source { get; set; }
|
|
||||||
bool ErrorsAllowed { get; set; }
|
|
||||||
bool ParseError { get; }
|
|
||||||
string ParseErrorMessage { get; }
|
|
||||||
bool IsDynamic { get; set; }
|
|
||||||
object Evaluate(object ExpressionContext, System.Collections.IDictionary Variables);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class AttachmentActionExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
#region Delete
|
|
||||||
public static bool CanDelete(this DeviceAttachment da)
|
|
||||||
{
|
|
||||||
return true; // Placeholder - Currently Can Always Delete;
|
|
||||||
}
|
|
||||||
public static void OnDelete(this DeviceAttachment da, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!da.CanDelete())
|
|
||||||
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
||||||
|
|
||||||
da.RepositoryDelete(dbContext);
|
|
||||||
dbContext.DeviceAttachments.Remove(da);
|
|
||||||
}
|
|
||||||
public static bool CanDelete(this JobAttachment ja)
|
|
||||||
{
|
|
||||||
return true; // Placeholder - Currently Can Always Delete;
|
|
||||||
}
|
|
||||||
public static void OnDelete(this JobAttachment ja, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!ja.CanDelete())
|
|
||||||
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
||||||
|
|
||||||
ja.RepositoryDelete(dbContext);
|
|
||||||
dbContext.JobAttachments.Remove(ja);
|
|
||||||
}
|
|
||||||
public static bool CanDelete(this UserAttachment ua)
|
|
||||||
{
|
|
||||||
return true; // Placeholder - Currently Can Always Delete;
|
|
||||||
}
|
|
||||||
public static void OnDelete(this UserAttachment ua, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!ua.CanDelete())
|
|
||||||
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
|
||||||
|
|
||||||
ua.RepositoryDelete(dbContext);
|
|
||||||
dbContext.UserAttachments.Remove(ua);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.IO;
|
|
||||||
using Disco.BI.DocumentTemplateBI;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class AttachmentExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
public static bool ImportPdfAttachment(this DocumentUniqueIdentifier UniqueIdentifier, DiscoDataContext dbContext, System.IO.Stream PdfContent, byte[] PdfThumbnail)
|
|
||||||
{
|
|
||||||
|
|
||||||
UniqueIdentifier.LoadComponents(dbContext);
|
|
||||||
DocumentTemplate documentTemplate = UniqueIdentifier.DocumentTemplate;
|
|
||||||
string filename;
|
|
||||||
string comments;
|
|
||||||
|
|
||||||
if (documentTemplate == null)
|
|
||||||
{
|
|
||||||
filename = string.Format("{0}_{1:yyyyMMdd-HHmmss}.pdf", UniqueIdentifier.DataId, UniqueIdentifier.TimeStamp);
|
|
||||||
comments = string.Format("Uploaded: {0:s}", UniqueIdentifier.TimeStamp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filename = string.Format("{0}_{1:yyyyMMdd-HHmmss}.pdf", UniqueIdentifier.TemplateTypeId, UniqueIdentifier.TimeStamp);
|
|
||||||
comments = string.Format("Generated: {0:s}", UniqueIdentifier.TimeStamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
User creatorUser = UserBI.UserCache.GetUser(UniqueIdentifier.CreatorId, dbContext);
|
|
||||||
if (creatorUser == null)
|
|
||||||
{
|
|
||||||
// No Creator User (or Username invalid)
|
|
||||||
creatorUser = UserBI.UserCache.CurrentUser;
|
|
||||||
}
|
|
||||||
switch (UniqueIdentifier.DataScope)
|
|
||||||
{
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
||||||
Device d = (Device)UniqueIdentifier.Data;
|
|
||||||
d.CreateAttachment(dbContext, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, documentTemplate, PdfThumbnail);
|
|
||||||
return true;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
||||||
Job j = (Job)UniqueIdentifier.Data;
|
|
||||||
j.CreateAttachment(dbContext, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, documentTemplate, PdfThumbnail);
|
|
||||||
return true;
|
|
||||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
||||||
User u = (User)UniqueIdentifier.Data;
|
|
||||||
u.CreateAttachment(dbContext, creatorUser, filename, DocumentTemplate.PdfMimeType, comments, PdfContent, documentTemplate, PdfThumbnail);
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string RepositoryFilename(this DeviceAttachment da, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return Path.Combine(DataStore.CreateLocation(dbContext, "DeviceAttachments", da.Timestamp), string.Format("{0}_{1}_file", da.DeviceSerialNumber, da.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryFilename(this JobAttachment ja, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return Path.Combine(DataStore.CreateLocation(dbContext, "JobAttachments", ja.Timestamp), string.Format("{0}_{1}_file", ja.JobId, ja.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryFilename(this UserAttachment ua, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return Path.Combine(DataStore.CreateLocation(dbContext, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_file", ua.UserId, ua.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string RepositoryThumbnailFilenameInternal(string DirectoryPath, string Filename)
|
|
||||||
{
|
|
||||||
return Path.Combine(DirectoryPath, Filename);
|
|
||||||
}
|
|
||||||
public static string RepositoryThumbnailFilename(this DeviceAttachment da, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(dbContext, "DeviceAttachments", da.Timestamp), string.Format("{0}_{1}_thumb.jpg", da.DeviceSerialNumber, da.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryThumbnailFilename(this JobAttachment ja, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(dbContext, "JobAttachments", ja.Timestamp), string.Format("{0}_{1}_thumb.jpg", ja.JobId, ja.Id));
|
|
||||||
}
|
|
||||||
public static string RepositoryThumbnailFilename(this UserAttachment ua, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(dbContext, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_thumb.jpg", ua.UserId, ua.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RepositoryDelete(this DeviceAttachment da, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
RepositoryDelete(da.RepositoryFilename(dbContext), da.RepositoryThumbnailFilename(dbContext));
|
|
||||||
}
|
|
||||||
public static void RepositoryDelete(this JobAttachment ja, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
RepositoryDelete(ja.RepositoryFilename(dbContext), ja.RepositoryThumbnailFilename(dbContext));
|
|
||||||
}
|
|
||||||
public static void RepositoryDelete(this UserAttachment ua, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
RepositoryDelete(ua.RepositoryFilename(dbContext), ua.RepositoryThumbnailFilename(dbContext));
|
|
||||||
}
|
|
||||||
private static void RepositoryDelete(params string[] filePaths)
|
|
||||||
{
|
|
||||||
foreach (string filePath in filePaths)
|
|
||||||
{
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
File.Delete(filePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string SaveAttachment(this DeviceAttachment da, DiscoDataContext dbContext, Stream FileContent)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryFilename(dbContext);
|
|
||||||
SaveAttachment(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveAttachment(this JobAttachment ja, DiscoDataContext dbContext, Stream FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryFilename(dbContext);
|
|
||||||
SaveAttachment(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveAttachment(this UserAttachment ua, DiscoDataContext dbContext, Stream FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryFilename(dbContext);
|
|
||||||
SaveAttachment(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveThumbnailAttachment(this DeviceAttachment da, DiscoDataContext dbContext, byte[] FileContent)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryThumbnailFilename(dbContext);
|
|
||||||
File.WriteAllBytes(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveThumbnailAttachment(this JobAttachment ja, DiscoDataContext dbContext, byte[] FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryThumbnailFilename(dbContext);
|
|
||||||
File.WriteAllBytes(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string SaveThumbnailAttachment(this UserAttachment ua, DiscoDataContext dbContext, byte[] FileContent)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryThumbnailFilename(dbContext);
|
|
||||||
File.WriteAllBytes(filePath, FileContent);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
private static void SaveAttachment(string FilePath, Stream FileContent)
|
|
||||||
{
|
|
||||||
using (FileStream sw = new FileStream(FilePath, FileMode.Create, FileAccess.Write, FileShare.None))
|
|
||||||
{
|
|
||||||
FileContent.CopyTo(sw);
|
|
||||||
sw.Flush();
|
|
||||||
sw.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateThumbnail(this DeviceAttachment da, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryThumbnailFilename(dbContext);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(da.RepositoryFilename(dbContext), da.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this JobAttachment ja, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryThumbnailFilename(dbContext);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(ja.RepositoryFilename(dbContext), ja.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this UserAttachment ua, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryThumbnailFilename(dbContext);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(ua.RepositoryFilename(dbContext), ua.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this DeviceAttachment da, DiscoDataContext dbContext, Stream SourceFile)
|
|
||||||
{
|
|
||||||
string filePath = da.RepositoryThumbnailFilename(dbContext);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(SourceFile, da.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this JobAttachment ja, DiscoDataContext dbContext, Stream SourceFile)
|
|
||||||
{
|
|
||||||
string filePath = ja.RepositoryThumbnailFilename(dbContext);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(SourceFile, ja.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
public static string GenerateThumbnail(this UserAttachment ua, DiscoDataContext dbContext, Stream SourceFile)
|
|
||||||
{
|
|
||||||
string filePath = ua.RepositoryThumbnailFilename(dbContext);
|
|
||||||
AttachmentBI.Utilities.GenerateThumbnail(SourceFile, ua.MimeType, filePath);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.BI.Interop.ActiveDirectory;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class DeviceActionExtensions
|
|
||||||
{
|
|
||||||
public static bool IsDecommissioned(this Device d)
|
|
||||||
{
|
|
||||||
return d.DecommissionedDate.HasValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanCreateJob(this Device d)
|
|
||||||
{
|
|
||||||
return !d.IsDecommissioned();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanUpdateAssignment(this Device d)
|
|
||||||
{
|
|
||||||
return !d.IsDecommissioned();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanUpdateDeviceProfile(this Device d)
|
|
||||||
{
|
|
||||||
return !d.IsDecommissioned();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanUpdateDeviceBatch(this Device d)
|
|
||||||
{
|
|
||||||
return !d.IsDecommissioned();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanUpdateTrustEnrol(this Device d)
|
|
||||||
{
|
|
||||||
return !d.IsDecommissioned() && !d.AllowUnauthenticatedEnrol;
|
|
||||||
}
|
|
||||||
public static bool CanUpdateUntrustEnrol(this Device d)
|
|
||||||
{
|
|
||||||
return !d.IsDecommissioned() && d.AllowUnauthenticatedEnrol;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Decommission
|
|
||||||
public static bool CanDecommission(this Device d)
|
|
||||||
{
|
|
||||||
if (d.DecommissionedDate.HasValue)
|
|
||||||
return false; // Already Decommissioned
|
|
||||||
|
|
||||||
if (d.AssignedUserId != null)
|
|
||||||
return false; // User Assigned to Device
|
|
||||||
|
|
||||||
if (d.Jobs.Count(j => !j.ClosedDate.HasValue) > 0)
|
|
||||||
return false; // Device linked to > 0 Open Jobs
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public static void OnDecommission(this Device d)
|
|
||||||
{
|
|
||||||
if (!d.CanDecommission())
|
|
||||||
throw new InvalidOperationException("Decommission of Device is Denied");
|
|
||||||
|
|
||||||
d.DecommissionedDate = DateTime.Now;
|
|
||||||
|
|
||||||
// Disable AD Account
|
|
||||||
if (d.ComputerName != null)
|
|
||||||
{
|
|
||||||
var adAccount = d.ActiveDirectoryAccount();
|
|
||||||
if (adAccount != null)
|
|
||||||
{
|
|
||||||
adAccount.DisableAccount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
#region Recommission
|
|
||||||
public static bool CanRecommission(this Device d)
|
|
||||||
{
|
|
||||||
return d.DecommissionedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnRecommission(this Device d)
|
|
||||||
{
|
|
||||||
if (!d.CanRecommission())
|
|
||||||
throw new InvalidOperationException("Recommission of Device is Denied");
|
|
||||||
|
|
||||||
d.DecommissionedDate = null;
|
|
||||||
|
|
||||||
// Enable AD Account
|
|
||||||
if (d.ComputerName != null)
|
|
||||||
{
|
|
||||||
var adAccount = d.ActiveDirectoryAccount();
|
|
||||||
if (adAccount != null)
|
|
||||||
{
|
|
||||||
adAccount.EnableAccount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Delete
|
|
||||||
public static bool CanDelete(this Device d)
|
|
||||||
{
|
|
||||||
return d.DecommissionedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnDelete(this Device d, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Delete Jobs
|
|
||||||
foreach (Job j in dbContext.Jobs.Where(i => i.DeviceSerialNumber == d.SerialNumber))
|
|
||||||
{
|
|
||||||
if (j.UserId == null)
|
|
||||||
{ // No User associated, thus must Delete whole Job
|
|
||||||
if (j.CanDelete())
|
|
||||||
j.OnDelete(dbContext);
|
|
||||||
else
|
|
||||||
throw new InvalidOperationException(string.Format("Deletion of Device is Denied (See Job# {0})", j.Id));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// User associated to Job, thus just remove Devices' association
|
|
||||||
j.DeviceSerialNumber = null;
|
|
||||||
|
|
||||||
// Write Job Log
|
|
||||||
JobLog jobLog = new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = UserBI.UserCache.CurrentUser.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = string.Format("Device Deleted{0}{0}Serial Number: {1}{0}Computer Name: {2}{0}Model: {3}{0}Profile: {4}",
|
|
||||||
Environment.NewLine, d.SerialNumber, d.ComputerName, d.DeviceModel, d.DeviceProfile)
|
|
||||||
};
|
|
||||||
dbContext.JobLogs.Add(jobLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable Wireless Certificates
|
|
||||||
foreach (var wc in dbContext.DeviceCertificates.Where(i => i.DeviceSerialNumber == d.SerialNumber))
|
|
||||||
{
|
|
||||||
wc.DeviceSerialNumber = null;
|
|
||||||
wc.Enabled = false;
|
|
||||||
}
|
|
||||||
// Delete Device Details
|
|
||||||
foreach (var dd in dbContext.DeviceDetails.Where(i => i.DeviceSerialNumber == d.SerialNumber))
|
|
||||||
dbContext.DeviceDetails.Remove(dd);
|
|
||||||
// Delete Device Attachments
|
|
||||||
foreach (var da in dbContext.DeviceAttachments.Where(i => i.DeviceSerialNumber == d.SerialNumber))
|
|
||||||
{
|
|
||||||
da.RepositoryDelete(dbContext);
|
|
||||||
dbContext.DeviceAttachments.Remove(da);
|
|
||||||
}
|
|
||||||
// Delete Device User Assignments
|
|
||||||
foreach (var dua in dbContext.DeviceUserAssignments.Where(i => i.DeviceSerialNumber == d.SerialNumber))
|
|
||||||
dbContext.DeviceUserAssignments.Remove(dua);
|
|
||||||
|
|
||||||
dbContext.Devices.Remove(d);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class DeviceBatchExtensions
|
|
||||||
{
|
|
||||||
public static bool CanDelete(this DeviceBatch db, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Can't Delete if Contains Devices
|
|
||||||
var deviceCount = dbContext.Devices.Count(d => d.DeviceBatchId == db.Id);
|
|
||||||
if (deviceCount > 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Delete(this DeviceBatch db, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!db.CanDelete(dbContext))
|
|
||||||
throw new InvalidOperationException("The state of this Device Batch doesn't allow it to be deleted");
|
|
||||||
|
|
||||||
// Delete Batch
|
|
||||||
dbContext.DeviceBatches.Remove(db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Plugins;
|
|
||||||
using Disco.Services.Plugins.Features.CertificateProvider;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class DeviceCertificateExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
public static Tuple<DeviceCertificate, List<string>> AllocateCertificate(this Device device, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(device.DeviceProfile.CertificateProviderId))
|
|
||||||
{
|
|
||||||
// REMOVED 2012-07-18 G# - Plugin is responsible for checking
|
|
||||||
//var deviceCertificates = dbContext.DeviceCertificates.Where(c =>
|
|
||||||
// c.DeviceSerialNumber == device.SerialNumber &&
|
|
||||||
// c.ProviderId == device.DeviceProfile.CertificateProviderId &&
|
|
||||||
// c.Enabled == true).ToList();
|
|
||||||
|
|
||||||
// Load Plugin
|
|
||||||
PluginFeatureManifest featureManifest = Plugins.GetPluginFeature(device.DeviceProfile.CertificateProviderId, typeof(CertificateProviderFeature));
|
|
||||||
|
|
||||||
using (CertificateProviderFeature providerFeature = featureManifest.CreateInstance<CertificateProviderFeature>())
|
|
||||||
{
|
|
||||||
// REMOVED 2012-07-18 G# - Plugin is responsible for checking
|
|
||||||
// Already Allocated Certificate
|
|
||||||
//if (deviceCertificates.Count > 0)
|
|
||||||
// return new Tuple<DeviceCertificate, List<string>>(deviceCertificates[0], providerPlugin.RemoveExistingCertificateNames());
|
|
||||||
//else
|
|
||||||
|
|
||||||
return providerFeature.AllocateCertificate(dbContext, device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Device Profile does not allow certificate allocation
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Disco.BI.Interop.ActiveDirectory;
|
|
||||||
using Disco.Data.Configuration;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using Disco.Models.Interop.ActiveDirectory;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class DeviceExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
public static string ComputerNameRender(this Device device, DiscoDataContext context)
|
|
||||||
{
|
|
||||||
DeviceProfile deviceProfile = device.DeviceProfile;
|
|
||||||
Expressions.Expression computerNameTemplateExpression = null;
|
|
||||||
computerNameTemplateExpression = Expressions.ExpressionCache.GetValue(DeviceProfileExtensions.ComputerNameExpressionCacheModule, deviceProfile.Id.ToString(), () =>
|
|
||||||
{
|
|
||||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
|
||||||
//return Expressions.Expression.TokenizeSingleDynamic(null, deviceProfile.Configuration(context).ComputerNameTemplate, 0);
|
|
||||||
return Expressions.Expression.TokenizeSingleDynamic(null, deviceProfile.ComputerNameTemplate, 0);
|
|
||||||
});
|
|
||||||
System.Collections.IDictionary evaluatorVariables = Expressions.Expression.StandardVariables(null, context, UserBI.UserCache.CurrentUser, System.DateTime.Now, null);
|
|
||||||
string rendered;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
rendered = computerNameTemplateExpression.EvaluateFirst<string>(device, evaluatorVariables);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException(string.Format("An error occurred rendering the computer name: [{0}] {1}", ex.GetType().Name, ex.Message), ex.InnerException);
|
|
||||||
}
|
|
||||||
if (rendered == null || rendered.Length > 24)
|
|
||||||
{
|
|
||||||
throw new System.InvalidOperationException("The rendered computer name would be invalid or longer than 24 characters");
|
|
||||||
}
|
|
||||||
return rendered.ToString();
|
|
||||||
}
|
|
||||||
public static System.Collections.Generic.List<DocumentTemplate> AvailableDocumentTemplates(this Device d, DiscoDataContext Context, User User, System.DateTime TimeStamp)
|
|
||||||
{
|
|
||||||
List<DocumentTemplate> ats = Context.DocumentTemplates
|
|
||||||
.Where(at => at.Scope == Disco.Models.Repository.DocumentTemplate.DocumentTemplateScopes.Device).ToList();
|
|
||||||
|
|
||||||
return ats.Where(at => at.FilterExpressionMatches(d, Context, User, TimeStamp, DocumentState.DefaultState())).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UpdateLastNetworkLogonDate(this Device Device)
|
|
||||||
{
|
|
||||||
return ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDate(Device);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext dbContext, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
|
||||||
|
|
||||||
DeviceAttachment da = new DeviceAttachment()
|
|
||||||
{
|
|
||||||
DeviceSerialNumber = Device.SerialNumber,
|
|
||||||
TechUserId = CreatorUser.Id,
|
|
||||||
Filename = Filename,
|
|
||||||
MimeType = MimeType,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = Comments
|
|
||||||
};
|
|
||||||
|
|
||||||
if (DocumentTemplate != null)
|
|
||||||
da.DocumentTemplateId = DocumentTemplate.Id;
|
|
||||||
|
|
||||||
dbContext.DeviceAttachments.Add(da);
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
da.SaveAttachment(dbContext, Content);
|
|
||||||
Content.Position = 0;
|
|
||||||
if (PdfThumbnail == null)
|
|
||||||
da.GenerateThumbnail(dbContext, Content);
|
|
||||||
else
|
|
||||||
da.SaveThumbnailAttachment(dbContext, PdfThumbnail);
|
|
||||||
|
|
||||||
return da;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Device AddOffline(this Device d, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Just Include:
|
|
||||||
// - Serial Number
|
|
||||||
// - Asset Number
|
|
||||||
// - Profile Id
|
|
||||||
// - Assigned User Id
|
|
||||||
// - Batch
|
|
||||||
|
|
||||||
// Batch
|
|
||||||
DeviceBatch db = default(DeviceBatch);
|
|
||||||
if (d.DeviceBatchId.HasValue)
|
|
||||||
db = dbContext.DeviceBatches.Find(d.DeviceBatchId.Value);
|
|
||||||
|
|
||||||
// Default Device Model
|
|
||||||
DeviceModel dm = default(DeviceModel);
|
|
||||||
if (db != null && db.DefaultDeviceModelId.HasValue)
|
|
||||||
dm = dbContext.DeviceModels.Find(db.DefaultDeviceModelId); // From Batch
|
|
||||||
else
|
|
||||||
dm = dbContext.DeviceModels.Find(1); // Default
|
|
||||||
|
|
||||||
Device d2 = new Device()
|
|
||||||
{
|
|
||||||
SerialNumber = d.SerialNumber.ToUpper(),
|
|
||||||
AssetNumber = d.AssetNumber,
|
|
||||||
Location = d.Location,
|
|
||||||
CreatedDate = DateTime.Now,
|
|
||||||
DeviceProfileId = d.DeviceProfileId,
|
|
||||||
DeviceProfile = dbContext.DeviceProfiles.Find(d.DeviceProfileId),
|
|
||||||
AllowUnauthenticatedEnrol = true,
|
|
||||||
DeviceModelId = dm.Id,
|
|
||||||
DeviceModel = dm,
|
|
||||||
DeviceBatchId = d.DeviceBatchId,
|
|
||||||
DeviceBatch = db
|
|
||||||
};
|
|
||||||
|
|
||||||
dbContext.Devices.Add(d2);
|
|
||||||
if (!string.IsNullOrEmpty(d.AssignedUserId))
|
|
||||||
{
|
|
||||||
User u = UserBI.UserCache.GetUser(d.AssignedUserId, dbContext, true);
|
|
||||||
d2.AssignDevice(dbContext, u);
|
|
||||||
}
|
|
||||||
|
|
||||||
return d2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DeviceUserAssignment AssignDevice(this Device d, DiscoDataContext dbContext, User u)
|
|
||||||
{
|
|
||||||
DeviceUserAssignment newDua = default(DeviceUserAssignment);
|
|
||||||
|
|
||||||
// Mark existing assignments as Unassigned
|
|
||||||
foreach (var dua in dbContext.DeviceUserAssignments.Where(m => m.DeviceSerialNumber == d.SerialNumber && !m.UnassignedDate.HasValue))
|
|
||||||
dua.UnassignedDate = DateTime.Now;
|
|
||||||
|
|
||||||
if (u != null)
|
|
||||||
{
|
|
||||||
// Add new Assignment
|
|
||||||
newDua = new DeviceUserAssignment()
|
|
||||||
{
|
|
||||||
DeviceSerialNumber = d.SerialNumber,
|
|
||||||
AssignedUserId = u.Id,
|
|
||||||
AssignedDate = DateTime.Now
|
|
||||||
};
|
|
||||||
dbContext.DeviceUserAssignments.Add(newDua);
|
|
||||||
|
|
||||||
d.AssignedUserId = u.Id;
|
|
||||||
d.AssignedUser = u;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.AssignedUserId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update AD Account
|
|
||||||
if (!string.IsNullOrEmpty(d.ComputerName) && d.ComputerName.Length <= 24)
|
|
||||||
{
|
|
||||||
var adMachineAccount = Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(d.ComputerName);
|
|
||||||
if (adMachineAccount != null)
|
|
||||||
{
|
|
||||||
adMachineAccount.SetDescription(d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return newDua;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ActiveDirectoryMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(Device.ComputerName))
|
|
||||||
return Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(Device.ComputerName, AdditionalProperties: AdditionalProperties);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Status(this Device Device)
|
|
||||||
{
|
|
||||||
if (Device.DecommissionedDate.HasValue)
|
|
||||||
return "Decommissioned";
|
|
||||||
|
|
||||||
if (!Device.EnrolledDate.HasValue)
|
|
||||||
return "Not Enrolled";
|
|
||||||
|
|
||||||
return "Active";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Data.Configuration.Modules;
|
|
||||||
using Disco.Models.BI.Config;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class DeviceProfileExtensions
|
|
||||||
{
|
|
||||||
public const string ComputerNameExpressionCacheModule = "ComputerNameTemplate";
|
|
||||||
|
|
||||||
public static void ComputerNameInvalidateCache(this DeviceProfile deviceProfile)
|
|
||||||
{
|
|
||||||
Expressions.ExpressionCache.InvalidateKey(ComputerNameExpressionCacheModule, deviceProfile.Id.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OrganisationAddress DefaultOrganisationAddressDetails(this DeviceProfile deviceProfile, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (deviceProfile.DefaultOrganisationAddress.HasValue)
|
|
||||||
{
|
|
||||||
return dbContext.DiscoConfiguration.OrganisationAddresses.GetAddress(deviceProfile.DefaultOrganisationAddress.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CanDelete(this DeviceProfile dp, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Can't Delete Default Profile (Id: 1)
|
|
||||||
if (dp.Id == 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Can't Delete if Contains Devices
|
|
||||||
if (dbContext.Devices.Count(d => d.DeviceProfileId == dp.Id) > 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public static void Delete(this DeviceProfile dp, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!dp.CanDelete(dbContext))
|
|
||||||
throw new InvalidOperationException("The state of this Device Profile doesn't allow it to be deleted");
|
|
||||||
|
|
||||||
// Update Defaults
|
|
||||||
if (dbContext.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId == dp.Id)
|
|
||||||
dbContext.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId = 1;
|
|
||||||
if (dbContext.DiscoConfiguration.DeviceProfiles.DefaultAddDeviceOfflineDeviceProfileId == dp.Id)
|
|
||||||
dbContext.DiscoConfiguration.DeviceProfiles.DefaultAddDeviceOfflineDeviceProfileId = 1;
|
|
||||||
|
|
||||||
// Delete Profile
|
|
||||||
dbContext.DeviceProfiles.Remove(dp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
|
||||||
//public static DeviceProfileConfiguration Configuration(this DeviceProfile dp, DiscoDataContext dbContext)
|
|
||||||
//{
|
|
||||||
// return dbContext.DiscoConfiguration.DeviceProfiles.DeviceProfile(dp);
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,220 +1,169 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Web;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
using System.Collections;
|
using Disco.Models.Services.Documents;
|
||||||
using System.Collections.Generic;
|
using Disco.Services;
|
||||||
|
using Disco.Services.Documents;
|
||||||
|
using Disco.Services.Documents.ManagedGroups;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using iTextSharp.text.pdf;
|
using iTextSharp.text.pdf;
|
||||||
using Disco.BI.Expressions;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Disco.BI.DocumentTemplateBI;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
namespace Disco.BI.Extensions
|
||||||
{
|
{
|
||||||
public static class DocumentTemplateExtensions
|
public static class DocumentTemplateExtensions
|
||||||
{
|
{
|
||||||
private const string DocumentTemplateExpressionCacheTemplate = "DocumentTemplate_{0}";
|
public static Tuple<Dictionary<string, Expression>, List<DocumentField>> CreateExpressions(string templateFileName, DiscoDataContext database)
|
||||||
|
{
|
||||||
|
Dictionary<string, Expression> expressions = new Dictionary<string, Expression>();
|
||||||
|
List<DocumentField> fields = new List<DocumentField>();
|
||||||
|
|
||||||
public static string RepositoryFilename(this DocumentTemplate dt, DiscoDataContext dbContext)
|
PdfReader pdfReader = new PdfReader(templateFileName);
|
||||||
{
|
|
||||||
return System.IO.Path.Combine(DataStore.CreateLocation(dbContext, "DocumentTemplates"), string.Format("{0}.pdf", dt.Id));
|
|
||||||
}
|
|
||||||
public static string SavePdfTemplate(this DocumentTemplate dt, DiscoDataContext dbContext, Stream TemplateFile)
|
|
||||||
{
|
|
||||||
string filePath = dt.RepositoryFilename(dbContext);
|
|
||||||
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
|
|
||||||
{
|
|
||||||
TemplateFile.CopyTo(fs);
|
|
||||||
}
|
|
||||||
Expressions.ExpressionCache.InvalidModule(string.Format(DocumentTemplateExpressionCacheTemplate, dt.Id));
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DisposableImageCollection PdfPageImages(this PdfReader pdfReader, int PageNumber)
|
|
||||||
{
|
|
||||||
return Interop.Pdf.PdfImporter.GetPageImages(pdfReader, PageNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ConcurrentDictionary<string, Expression> PdfExpressionsFromCache(this DocumentTemplate dt, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string cacheModuleKey = string.Format(DocumentTemplateExpressionCacheTemplate, dt.Id);
|
|
||||||
var module = Expressions.ExpressionCache.GetModule(cacheModuleKey);
|
|
||||||
if (module == null)
|
|
||||||
{
|
|
||||||
// Cache
|
|
||||||
string templateFilename = dt.RepositoryFilename(dbContext);
|
|
||||||
PdfReader pdfReader = new PdfReader(templateFilename);
|
|
||||||
int pdfFieldOrdinal = 0;
|
int pdfFieldOrdinal = 0;
|
||||||
foreach (string pdfFieldKey in pdfReader.AcroFields.Fields.Keys)
|
foreach (string pdfFieldKey in pdfReader.AcroFields.Fields.Keys)
|
||||||
{
|
{
|
||||||
|
var pdfField = pdfReader.AcroFields.Fields[pdfFieldKey];
|
||||||
|
var pdfFieldPositions = pdfReader.AcroFields.GetFieldPositions(pdfFieldKey);
|
||||||
|
var pdfFieldFlags = pdfField.GetMerged(0).GetAsNumber(PdfName.FF)?.IntValue ?? 0;
|
||||||
|
var isRequired = (pdfFieldFlags & 2) == 2;
|
||||||
|
var isReadOnly = (pdfFieldFlags & 1) == 1;
|
||||||
|
|
||||||
var pdfFieldValue = pdfReader.AcroFields.GetField(pdfFieldKey);
|
var pdfFieldValue = pdfReader.AcroFields.GetField(pdfFieldKey);
|
||||||
Expressions.ExpressionCache.SetValue(cacheModuleKey, pdfFieldKey, Expressions.Expression.Tokenize(pdfFieldKey, pdfFieldValue, pdfFieldOrdinal));
|
var pdfFieldPosition = default(RectangleF?);
|
||||||
|
if (pdfFieldPositions != null && pdfFieldPositions.Count > 0)
|
||||||
|
{
|
||||||
|
var position = pdfFieldPositions.First().position;
|
||||||
|
pdfFieldPosition = new RectangleF(position.Left, position.Top, position.Width, position.Height);
|
||||||
|
}
|
||||||
|
var fieldTypeId = pdfReader.AcroFields.GetFieldType(pdfFieldKey);
|
||||||
|
var fieldType = DocumentFieldType.None;
|
||||||
|
if (fieldTypeId <= 8 && fieldTypeId > 0)
|
||||||
|
fieldType = (DocumentFieldType)fieldTypeId;
|
||||||
|
|
||||||
|
var fixedValues = default(List<string>);
|
||||||
|
|
||||||
|
if (fieldType == DocumentFieldType.RadioButton || fieldType == DocumentFieldType.Checkbox)
|
||||||
|
{
|
||||||
|
fixedValues = pdfReader.AcroFields.GetAppearanceStates(pdfFieldKey).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
expressions[pdfFieldKey] = Expression.Tokenize(pdfFieldKey, pdfFieldValue, pdfFieldOrdinal, isRequired, isReadOnly, pdfFieldPosition);
|
||||||
|
fields.Add(new DocumentField(pdfFieldKey, pdfFieldValue, pdfFieldOrdinal, fieldType, isRequired, isReadOnly, fixedValues));
|
||||||
pdfFieldOrdinal++;
|
pdfFieldOrdinal++;
|
||||||
}
|
}
|
||||||
pdfReader.Close();
|
pdfReader.Close();
|
||||||
module = Expressions.ExpressionCache.GetModule(cacheModuleKey, true);
|
|
||||||
}
|
return Tuple.Create(expressions, fields);
|
||||||
return module;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<BI.Expressions.Expression> ExtractPdfExpressions(this DocumentTemplate dt, DiscoDataContext dbContext)
|
private static Tuple<Dictionary<string, Expression>, List<DocumentField>> CreateExpressions(DocumentTemplate dt, DiscoDataContext database)
|
||||||
{
|
{
|
||||||
return dt.PdfExpressionsFromCache(dbContext).Values.OrderBy(e => e.Ordinal).ToList();
|
string templateFileName = dt.RepositoryFilename(database);
|
||||||
}
|
return CreateExpressions(templateFileName, database);
|
||||||
public static System.IO.Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params string[] DataObjectsIds)
|
|
||||||
{
|
|
||||||
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, dbContext, CreatorUser, Timestamp, DataObjectsIds);
|
|
||||||
}
|
|
||||||
public static System.IO.Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
|
|
||||||
{
|
|
||||||
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, dbContext, CreatorUser, Timestamp, DataObjects);
|
|
||||||
}
|
|
||||||
public static System.IO.Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext dbContext, object Data, User CreatorUser, System.DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
|
||||||
{
|
|
||||||
return Interop.Pdf.PdfGenerator.GenerateFromTemplate(dt, dbContext, Data, CreatorUser, TimeStamp, State, FlattenFields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Expression FilterExpressionFromCache(this DocumentTemplate dt)
|
public static Dictionary<string, Expression> PdfExpressionsFromCache(this DocumentTemplate dt, DiscoDataContext database)
|
||||||
{
|
{
|
||||||
return ExpressionCache.GetValue("DocumentTemplateFilterExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.FilterExpression, 0); });
|
return ExpressionCache.GetOrCreateExpressions(dt, () => CreateExpressions(dt, database));
|
||||||
}
|
}
|
||||||
public static void FilterExpressionInvalidateCache(this DocumentTemplate dt)
|
|
||||||
|
public static List<DocumentField> PdfFieldsFromCache(this DocumentTemplate dt, DiscoDataContext database)
|
||||||
{
|
{
|
||||||
ExpressionCache.InvalidateKey("DocumentTemplateFilterExpression", dt.Id);
|
return ExpressionCache.GetOrCreateFields(dt, () => CreateExpressions(dt, database));
|
||||||
}
|
}
|
||||||
public static bool FilterExpressionMatches(this DocumentTemplate dt, object Data, DiscoDataContext DataContext, User User, System.DateTime TimeStamp, DocumentState State)
|
|
||||||
|
public static List<Expression> ExtractPdfExpressions(this DocumentTemplate dt, DiscoDataContext database)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(dt.FilterExpression))
|
return dt.PdfExpressionsFromCache(database).Values.OrderBy(e => e.Ordinal).ToList();
|
||||||
{
|
|
||||||
Expression compiledExpression = dt.FilterExpressionFromCache();
|
|
||||||
System.Collections.IDictionary evaluatorVariables = Expression.StandardVariables(dt, DataContext, User, TimeStamp, State);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
object er = compiledExpression.EvaluateFirst<object>(Data, evaluatorVariables);
|
|
||||||
if (er is bool)
|
|
||||||
{
|
|
||||||
return (bool)er;
|
|
||||||
}
|
}
|
||||||
bool erBool;
|
|
||||||
if (bool.TryParse(er.ToString(), out erBool))
|
public static Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext database, IAttachmentTarget target, User creatorUser, DateTime timeStamp, DocumentState state, bool flattenFields = false)
|
||||||
{
|
{
|
||||||
return erBool;
|
bool generateExpression = !string.IsNullOrEmpty(dt.OnGenerateExpression);
|
||||||
}
|
string generateExpressionResult = null;
|
||||||
}
|
|
||||||
catch
|
if (generateExpression)
|
||||||
{
|
generateExpressionResult = dt.EvaluateOnGenerateExpression(target, database, creatorUser, timeStamp, state);
|
||||||
return false;
|
|
||||||
}
|
var pdfStream = Interop.Pdf.PdfGenerator.GenerateFromTemplate(dt, database, target, creatorUser, timeStamp, state, flattenFields);
|
||||||
}
|
|
||||||
return true;
|
if (generateExpression)
|
||||||
}
|
DocumentsLog.LogDocumentGenerated(dt, target, creatorUser, generateExpressionResult);
|
||||||
public static string GetDataId(this DocumentTemplate dt, object Data)
|
|
||||||
{
|
|
||||||
if (Data is string)
|
|
||||||
{
|
|
||||||
return (string)Data;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
|
DocumentsLog.LogDocumentGenerated(dt, target, creatorUser);
|
||||||
|
|
||||||
|
return pdfStream;
|
||||||
|
}
|
||||||
|
public static Stream GeneratePdfPackage(this DocumentTemplatePackage package, DiscoDataContext database, IAttachmentTarget target, User creatorUser, DateTime timeStamp, DocumentState state)
|
||||||
{
|
{
|
||||||
switch (dt.Scope)
|
return Interop.Pdf.PdfGenerator.GenerateFromPackage(package, database, target, creatorUser, timeStamp, state);
|
||||||
|
}
|
||||||
|
public static Stream GeneratePdfPackageBulk(this DocumentTemplatePackage package, DiscoDataContext database, User creatorUser, DateTime timestamp, bool? insertBlankPages, List<string> dataObjectsIds)
|
||||||
{
|
{
|
||||||
case Models.Repository.DocumentTemplate.DocumentTemplateScopes.Device:
|
return Interop.Pdf.PdfGenerator.GenerateBulkFromPackage(package, database, creatorUser, timestamp, insertBlankPages, dataObjectsIds);
|
||||||
if (!(Data is Device))
|
|
||||||
throw new ArgumentException("This Document Template is configured for Devices only", "Data");
|
|
||||||
Device d = (Device)Data;
|
|
||||||
return d.SerialNumber;
|
|
||||||
case Models.Repository.DocumentTemplate.DocumentTemplateScopes.Job:
|
|
||||||
if (!(Data is Job))
|
|
||||||
throw new ArgumentException("This Document Template is configured for Jobs only", "Data");
|
|
||||||
Job d2 = (Job)Data;
|
|
||||||
return d2.Id.ToString();
|
|
||||||
case Models.Repository.DocumentTemplate.DocumentTemplateScopes.User:
|
|
||||||
if (!(Data is User))
|
|
||||||
throw new ArgumentException("This Document Template is configured for Users only", "Data");
|
|
||||||
User d3 = (User)Data;
|
|
||||||
return d3.Id;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Invalid Document Template Scope");
|
|
||||||
}
|
}
|
||||||
}
|
public static Stream GeneratePdfPackageBulk(this DocumentTemplatePackage package, DiscoDataContext database, User creatorUser, DateTime timestamp, bool? insertBlankPages, List<IAttachmentTarget> dataObjects)
|
||||||
}
|
|
||||||
public static string UniqueIdentifier(string DocumentTemplateId, string DataId, string CreatorId, System.DateTime Timestamp)
|
|
||||||
{
|
{
|
||||||
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}",
|
return Interop.Pdf.PdfGenerator.GenerateBulkFromPackage(package, database, creatorUser, timestamp, insertBlankPages, dataObjects);
|
||||||
DocumentTemplateId,
|
|
||||||
DataId,
|
|
||||||
CreatorId,
|
|
||||||
Timestamp
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
public static string UniqueIdentifier(this DocumentTemplate dt, object Data, string CreatorId, System.DateTime Timestamp)
|
|
||||||
|
public static List<bool> PdfPageHasAttachmentId(this DocumentTemplate dt, DiscoDataContext database)
|
||||||
{
|
{
|
||||||
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}",
|
string templateFilename = dt.RepositoryFilename(database);
|
||||||
dt.Id,
|
if (!File.Exists(templateFilename))
|
||||||
dt.GetDataId(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Data)),
|
throw new FileNotFoundException("PDF template not found", templateFilename);
|
||||||
CreatorId,
|
|
||||||
Timestamp
|
PdfReader pdfReader = new PdfReader(templateFilename);
|
||||||
);
|
var result = new bool[pdfReader.NumberOfPages];
|
||||||
}
|
var fieldNames = pdfReader.AcroFields.Fields.Keys.Where(key => key.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||||
public static string UniquePageIdentifier(this DocumentTemplate dt, object Data, string CreatorId, System.DateTime Timestamp, int Page)
|
var fieldPositions = fieldNames.SelectMany(name => pdfReader.AcroFields.GetFieldPositions(name));
|
||||||
|
foreach (var fieldPosition in fieldPositions)
|
||||||
{
|
{
|
||||||
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}|{4}",
|
result[fieldPosition.page - 1] = true;
|
||||||
dt.Id,
|
|
||||||
dt.GetDataId(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Data)),
|
|
||||||
CreatorId,
|
|
||||||
Timestamp,
|
|
||||||
Page
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
public static List<RectangleF> QRCodeLocations(this DocumentTemplate dt, DiscoDataContext dbContext)
|
pdfReader.Close();
|
||||||
{
|
return result.ToList();
|
||||||
return DocumentTemplateBI.DocumentTemplateQRCodeLocationCache.GetLocations(dt, dbContext);
|
|
||||||
}
|
}
|
||||||
public static void Delete(this DocumentTemplate dt, DiscoDataContext Context)
|
|
||||||
|
public static void Delete(this DocumentTemplate dt, DiscoDataContext Database)
|
||||||
{
|
{
|
||||||
// Find & Rename all references
|
// Find & Rename all references
|
||||||
foreach (DeviceAttachment a in Context.DeviceAttachments.Where(a => a.DocumentTemplateId == dt.Id))
|
void updateAttachment(IAttachment a)
|
||||||
{
|
{
|
||||||
a.Comments = string.Format("{0} - {1}", dt.Description, a.Comments);
|
var comments = $"{dt.Description} - {a.Comments}";
|
||||||
if (a.Comments.Length > 500)
|
if (comments.Length > 500)
|
||||||
a.Comments = a.Comments.Substring(0, 500);
|
comments = comments.Substring(0, 500);
|
||||||
|
a.Comments = comments;
|
||||||
a.DocumentTemplateId = null;
|
a.DocumentTemplateId = null;
|
||||||
a.DocumentTemplate = null;
|
|
||||||
}
|
|
||||||
foreach (JobAttachment a in Context.JobAttachments.Where(a => a.DocumentTemplateId == dt.Id))
|
|
||||||
{
|
|
||||||
a.Comments = string.Format("{0} - {1}", dt.Description, a.Comments);
|
|
||||||
if (a.Comments.Length > 500)
|
|
||||||
a.Comments = a.Comments.Substring(0, 500);
|
|
||||||
a.DocumentTemplateId = null;
|
|
||||||
a.DocumentTemplate = null;
|
|
||||||
}
|
|
||||||
foreach (UserAttachment a in Context.UserAttachments.Where(a => a.DocumentTemplateId == dt.Id))
|
|
||||||
{
|
|
||||||
a.Comments = string.Format("{0} - {1}", dt.Description, a.Comments);
|
|
||||||
if (a.Comments.Length > 500)
|
|
||||||
a.Comments = a.Comments.Substring(0, 500);
|
|
||||||
a.DocumentTemplateId = null;
|
|
||||||
a.DocumentTemplate = null;
|
|
||||||
}
|
}
|
||||||
|
foreach (var a in Database.DeviceAttachments.Where(a => a.DocumentTemplateId == dt.Id))
|
||||||
|
updateAttachment(a);
|
||||||
|
foreach (var a in Database.JobAttachments.Where(a => a.DocumentTemplateId == dt.Id))
|
||||||
|
updateAttachment(a);
|
||||||
|
foreach (UserAttachment a in Database.UserAttachments.Where(a => a.DocumentTemplateId == dt.Id))
|
||||||
|
updateAttachment(a);
|
||||||
|
|
||||||
|
// Remove Linked Group
|
||||||
|
ActiveDirectory.Context.ManagedGroups.Remove(DocumentTemplateDevicesManagedGroup.GetKey(dt));
|
||||||
|
ActiveDirectory.Context.ManagedGroups.Remove(DocumentTemplateUsersManagedGroup.GetKey(dt));
|
||||||
|
|
||||||
// Delete SubTypes
|
// Delete SubTypes
|
||||||
dt.JobSubTypes.Clear();
|
dt.JobSubTypes.Clear();
|
||||||
|
|
||||||
// Delete Template
|
// Delete Template
|
||||||
string templateRepositoryFilename = dt.RepositoryFilename(Context);
|
string templateRepositoryFilename = dt.RepositoryFilename(Database);
|
||||||
if (System.IO.File.Exists(templateRepositoryFilename))
|
if (File.Exists(templateRepositoryFilename))
|
||||||
System.IO.File.Delete(templateRepositoryFilename);
|
File.Delete(templateRepositoryFilename);
|
||||||
|
|
||||||
// Remove from Cache
|
// Remove from Cache
|
||||||
dt.FilterExpressionInvalidateCache();
|
dt.FilterExpressionInvalidateCache();
|
||||||
|
|
||||||
// Delete Document Template from Repository
|
// Delete Document Template from Repository
|
||||||
Context.DocumentTemplates.Remove(dt);
|
Database.DocumentTemplates.Remove(dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,474 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Config;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Plugins;
|
|
||||||
using Disco.Services.Plugins.Features.WarrantyProvider;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class JobActionExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
#region Device Held
|
|
||||||
public static bool CanDeviceHeld(this Job j)
|
|
||||||
{
|
|
||||||
return (!j.ClosedDate.HasValue) && (j.DeviceSerialNumber != null) &&
|
|
||||||
(!j.DeviceHeld.HasValue || j.DeviceReturnedDate.HasValue);
|
|
||||||
}
|
|
||||||
public static void OnDeviceHeld(this Job j, User Technician)
|
|
||||||
{
|
|
||||||
if (!j.CanDeviceHeld())
|
|
||||||
throw new InvalidOperationException("Holding Device was Denied");
|
|
||||||
|
|
||||||
j.DeviceHeld = DateTime.Now;
|
|
||||||
j.DeviceHeldTechUserId = Technician.Id;
|
|
||||||
j.DeviceReadyForReturn = null;
|
|
||||||
j.DeviceReadyForReturnTechUserId = null;
|
|
||||||
j.DeviceReturnedDate = null;
|
|
||||||
j.DeviceReturnedTechUserId = null;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Device Ready for Return
|
|
||||||
public static bool CanDeviceReadyForReturn(this Job j)
|
|
||||||
{
|
|
||||||
return (!j.ClosedDate.HasValue) && j.DeviceHeld.HasValue &&
|
|
||||||
!j.DeviceReadyForReturn.HasValue && !j.DeviceReturnedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnDeviceReadyForReturn(this Job j, User Technician)
|
|
||||||
{
|
|
||||||
if (!j.CanDeviceReadyForReturn())
|
|
||||||
throw new InvalidOperationException("Device Ready for Return was Denied");
|
|
||||||
|
|
||||||
j.DeviceReadyForReturn = DateTime.Now;
|
|
||||||
j.DeviceReadyForReturnTechUserId = Technician.Id;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Device Returned
|
|
||||||
public static bool CanDeviceReturned(this Job j)
|
|
||||||
{
|
|
||||||
return (!j.ClosedDate.HasValue) && j.DeviceHeld.HasValue &&
|
|
||||||
!j.DeviceReturnedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnDeviceReturned(this Job j, User Technician)
|
|
||||||
{
|
|
||||||
if (!j.CanDeviceReturned())
|
|
||||||
throw new InvalidOperationException("Device Return was Denied");
|
|
||||||
|
|
||||||
j.DeviceReturnedDate = DateTime.Now;
|
|
||||||
j.DeviceReturnedTechUserId = Technician.Id;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Waiting For User Action
|
|
||||||
public static bool CanWaitingForUserAction(this Job j)
|
|
||||||
{
|
|
||||||
return !j.ClosedDate.HasValue && (j.UserId != null) && !j.WaitingForUserAction.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnWaitingForUserAction(this Job j, DiscoDataContext dbContext, User Technician, string Reason)
|
|
||||||
{
|
|
||||||
if (!j.CanWaitingForUserAction())
|
|
||||||
throw new InvalidOperationException("Waiting for User Action was Denied");
|
|
||||||
|
|
||||||
j.WaitingForUserAction = DateTime.Now;
|
|
||||||
|
|
||||||
// Write Log
|
|
||||||
JobLog jobLog = new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = Technician.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = string.Format("Waiting on User Action{0}Reason: {1}", Environment.NewLine, Reason)
|
|
||||||
};
|
|
||||||
dbContext.JobLogs.Add(jobLog);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Not Waiting For User Action
|
|
||||||
public static bool CanNotWaitingForUserAction(this Job j)
|
|
||||||
{
|
|
||||||
return j.WaitingForUserAction.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnNotWaitingForUserAction(this Job j, DiscoDataContext dbContext, User Technician, string Resolution)
|
|
||||||
{
|
|
||||||
if (!j.CanNotWaitingForUserAction())
|
|
||||||
throw new InvalidOperationException("Not Waiting for User Action was Denied");
|
|
||||||
|
|
||||||
j.WaitingForUserAction = null;
|
|
||||||
|
|
||||||
// Write Log
|
|
||||||
JobLog jobLog = new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = Technician.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = string.Format("User Action Resolved{0}Resolution: {1}", Environment.NewLine, Resolution)
|
|
||||||
};
|
|
||||||
dbContext.JobLogs.Add(jobLog);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Log Warranty
|
|
||||||
public static bool CanLogWarranty(this Job j)
|
|
||||||
{
|
|
||||||
return !j.ClosedDate.HasValue &&
|
|
||||||
(j.DeviceSerialNumber != null) &&
|
|
||||||
j.JobTypeId == JobType.JobTypeIds.HWar &&
|
|
||||||
string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference);
|
|
||||||
}
|
|
||||||
public static void OnLogWarranty(this Job j, DiscoDataContext dbContext, string FaultDescription, PluginFeatureManifest WarrantyProviderDefinition, OrganisationAddress Address, User TechUser, Dictionary<string, string> WarrantyProviderProperties)
|
|
||||||
{
|
|
||||||
if (!j.CanLogWarranty())
|
|
||||||
throw new InvalidOperationException("Log Warranty was Denied");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(FaultDescription))
|
|
||||||
FaultDescription = j.GenerateFaultDescriptionFooter(dbContext, WarrantyProviderDefinition);
|
|
||||||
else
|
|
||||||
FaultDescription = string.Concat(FaultDescription, Environment.NewLine, Environment.NewLine, j.GenerateFaultDescriptionFooter(dbContext, WarrantyProviderDefinition));
|
|
||||||
|
|
||||||
using (WarrantyProviderFeature WarrantyProvider = WarrantyProviderDefinition.CreateInstance<WarrantyProviderFeature>())
|
|
||||||
{
|
|
||||||
string providerRef = WarrantyProvider.SubmitJob(dbContext, j, Address, TechUser, FaultDescription, WarrantyProviderProperties);
|
|
||||||
|
|
||||||
j.JobMetaWarranty.ExternalLoggedDate = DateTime.Now;
|
|
||||||
j.JobMetaWarranty.ExternalName = WarrantyProvider.WarrantyProviderId;
|
|
||||||
|
|
||||||
if (providerRef.Length > 100)
|
|
||||||
j.JobMetaWarranty.ExternalReference = providerRef.Substring(0, 100);
|
|
||||||
else
|
|
||||||
j.JobMetaWarranty.ExternalReference = providerRef;
|
|
||||||
|
|
||||||
// Write Log
|
|
||||||
JobLog jobLog = new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = TechUser.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = string.Format("Warranty Claim Submitted{0}{0}Provider: {1}{0}Repair Address: {2}{0}Provider Reference: {3}{0}{0}{4}", Environment.NewLine, WarrantyProvider.Manifest.Name, Address.Name, providerRef, FaultDescription)
|
|
||||||
};
|
|
||||||
dbContext.JobLogs.Add(jobLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Convert HWar to HNWar
|
|
||||||
public static bool CanConvertHWarToHNWar(this Job j)
|
|
||||||
{
|
|
||||||
return !j.ClosedDate.HasValue && (j.DeviceSerialNumber != null) &&
|
|
||||||
j.JobTypeId == JobType.JobTypeIds.HWar && string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference);
|
|
||||||
}
|
|
||||||
public static void OnConvertHWarToHNWar(this Job j, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
if (!j.CanConvertHWarToHNWar())
|
|
||||||
throw new InvalidOperationException("Convert HWar to HNWar was Denied");
|
|
||||||
|
|
||||||
var techUser = UserBI.UserCache.CurrentUser;
|
|
||||||
|
|
||||||
// Remove JobMetaWarranty
|
|
||||||
if (j.JobMetaWarranty != null)
|
|
||||||
dbContext.JobMetaWarranties.Remove(j.JobMetaWarranty);
|
|
||||||
|
|
||||||
// Add JobMetaNonWarranty
|
|
||||||
var metaHNWar = new JobMetaNonWarranty() { Job = j };
|
|
||||||
dbContext.JobMetaNonWarranties.Add(metaHNWar);
|
|
||||||
|
|
||||||
// Swap Job Sub Types
|
|
||||||
List<string> jobSubTypes = j.JobSubTypes.Select(jst => jst.Id).ToList();
|
|
||||||
j.JobSubTypes.Clear();
|
|
||||||
foreach (var jst in dbContext.JobSubTypes.Where(i => i.JobTypeId == JobType.JobTypeIds.HNWar && jobSubTypes.Contains(i.Id)))
|
|
||||||
j.JobSubTypes.Add(jst);
|
|
||||||
|
|
||||||
// Add Components
|
|
||||||
var components = dbContext.DeviceComponents.Include("JobSubTypes").Where(c => !c.DeviceModelId.HasValue || c.DeviceModelId == j.Device.DeviceModelId);
|
|
||||||
var jobComponents = new List<DeviceComponent>();
|
|
||||||
foreach (var component in components)
|
|
||||||
{
|
|
||||||
if (!component.DeviceModelId.HasValue)
|
|
||||||
{
|
|
||||||
jobComponents.Add(component);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var st in component.JobSubTypes)
|
|
||||||
{
|
|
||||||
foreach (var jst in j.JobSubTypes)
|
|
||||||
{
|
|
||||||
if (st.JobTypeId == jst.JobTypeId && st.Id == jst.Id)
|
|
||||||
{
|
|
||||||
jobComponents.Add(component);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (jobComponents.Contains(component))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var component in jobComponents)
|
|
||||||
{
|
|
||||||
dbContext.JobComponents.Add(new JobComponent()
|
|
||||||
{
|
|
||||||
Job = j,
|
|
||||||
TechUserId = techUser.Id,
|
|
||||||
Cost = component.Cost,
|
|
||||||
Description = component.Description
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write Log
|
|
||||||
JobLog jobLog = new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = techUser.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = string.Format("Job Type Converted{0}From: {1}{0}To: {2}", Environment.NewLine, dbContext.JobTypes.Find(JobType.JobTypeIds.HWar), dbContext.JobTypes.Find(JobType.JobTypeIds.HNWar))
|
|
||||||
};
|
|
||||||
dbContext.JobLogs.Add(jobLog);
|
|
||||||
|
|
||||||
j.JobTypeId = JobType.JobTypeIds.HNWar;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Warranty Completed
|
|
||||||
public static bool CanWarrantyCompleted(this Job j)
|
|
||||||
{
|
|
||||||
return (j.JobTypeId == JobType.JobTypeIds.HWar) &&
|
|
||||||
j.JobMetaWarranty.ExternalLoggedDate.HasValue &&
|
|
||||||
!j.JobMetaWarranty.ExternalCompletedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnWarrantyCompleted(this Job j)
|
|
||||||
{
|
|
||||||
if (!j.CanWarrantyCompleted())
|
|
||||||
throw new InvalidOperationException("Warranty Completed was Denied");
|
|
||||||
|
|
||||||
j.JobMetaWarranty.ExternalCompletedDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Insurance Claim Form Sent
|
|
||||||
public static bool CanInsuranceClaimFormSent(this Job j)
|
|
||||||
{
|
|
||||||
return (j.JobTypeId == JobType.JobTypeIds.HNWar) &&
|
|
||||||
j.JobMetaNonWarranty.IsInsuranceClaim &&
|
|
||||||
!j.JobMetaInsurance.ClaimFormSentDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnInsuranceClaimFormSent(this Job j)
|
|
||||||
{
|
|
||||||
if (!j.CanInsuranceClaimFormSent())
|
|
||||||
throw new InvalidOperationException("Insurance Claim Form Sent was Denied");
|
|
||||||
|
|
||||||
var techUser = UserBI.UserCache.CurrentUser;
|
|
||||||
|
|
||||||
j.JobMetaInsurance.ClaimFormSentDate = DateTime.Now;
|
|
||||||
j.JobMetaInsurance.ClaimFormSentUserId = techUser.Id;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Log Repair
|
|
||||||
public static bool CanLogRepair(this Job j)
|
|
||||||
{
|
|
||||||
return (j.JobTypeId == JobType.JobTypeIds.HNWar) &&
|
|
||||||
(j.DeviceSerialNumber != null) &&
|
|
||||||
!j.JobMetaNonWarranty.RepairerLoggedDate.HasValue &&
|
|
||||||
!j.JobMetaNonWarranty.RepairerCompletedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnLogRepair(this Job j, string RepairerName, string RepairerReference)
|
|
||||||
{
|
|
||||||
if (!j.CanLogRepair())
|
|
||||||
throw new InvalidOperationException("Log Repair was Denied");
|
|
||||||
|
|
||||||
if (j.JobMetaNonWarranty.RepairerName != RepairerName)
|
|
||||||
j.JobMetaNonWarranty.RepairerName = RepairerName;
|
|
||||||
if (j.JobMetaNonWarranty.RepairerReference != RepairerReference)
|
|
||||||
j.JobMetaNonWarranty.RepairerReference = RepairerReference;
|
|
||||||
j.JobMetaNonWarranty.RepairerLoggedDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Repair Complete
|
|
||||||
public static bool CanRepairComplete(this Job j)
|
|
||||||
{
|
|
||||||
return (j.JobTypeId == JobType.JobTypeIds.HNWar) &&
|
|
||||||
j.JobMetaNonWarranty.RepairerLoggedDate.HasValue &&
|
|
||||||
!j.JobMetaNonWarranty.RepairerCompletedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnRepairComplete(this Job j)
|
|
||||||
{
|
|
||||||
if (!j.CanRepairComplete())
|
|
||||||
throw new InvalidOperationException("Repair Complete was Denied");
|
|
||||||
|
|
||||||
j.JobMetaNonWarranty.RepairerCompletedDate = DateTime.Now;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Close
|
|
||||||
public static bool CanClose(this Job j)
|
|
||||||
{
|
|
||||||
if (j.ClosedDate.HasValue)
|
|
||||||
return false; // Job already Closed
|
|
||||||
|
|
||||||
if (j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue)
|
|
||||||
return false; // Device not returned to User
|
|
||||||
|
|
||||||
if (j.WaitingForUserAction.HasValue)
|
|
||||||
return false; // Job waiting on User Action
|
|
||||||
|
|
||||||
switch (j.JobTypeId)
|
|
||||||
{
|
|
||||||
case JobType.JobTypeIds.HWar:
|
|
||||||
if (!string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference) && !j.JobMetaWarranty.ExternalCompletedDate.HasValue)
|
|
||||||
return false; // Job Logged (Warranty) but not completed
|
|
||||||
break;
|
|
||||||
case JobType.JobTypeIds.HNWar:
|
|
||||||
if (j.JobMetaNonWarranty.RepairerLoggedDate.HasValue && !j.JobMetaNonWarranty.RepairerCompletedDate.HasValue)
|
|
||||||
return false; // Job Logged (Repair) but not completed
|
|
||||||
if (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue && (!j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue || !j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue))
|
|
||||||
return false; // Accounting Charge Required, but not added or paid
|
|
||||||
|
|
||||||
if (j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue)
|
|
||||||
return false; // Accounting Charge Added, but not paid
|
|
||||||
|
|
||||||
if (j.JobMetaNonWarranty.IsInsuranceClaim && !j.JobMetaInsurance.ClaimFormSentDate.HasValue)
|
|
||||||
return false; // Is Insurance Claim, but claim form not sent
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public static void OnClose(this Job j, User Technician)
|
|
||||||
{
|
|
||||||
if (!j.CanClose())
|
|
||||||
throw new InvalidOperationException("Close was Denied");
|
|
||||||
|
|
||||||
j.ClosedDate = DateTime.Now;
|
|
||||||
j.ClosedTechUserId = Technician.Id;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Force Close
|
|
||||||
public static bool CanForceClose(this Job j)
|
|
||||||
{
|
|
||||||
var canCloseNormally = j.CanClose();
|
|
||||||
|
|
||||||
if (canCloseNormally)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Check for Override
|
|
||||||
if (j.ClosedDate.HasValue)
|
|
||||||
return false; // Job already Closed
|
|
||||||
|
|
||||||
if (j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue)
|
|
||||||
return false; // Device not returned to User
|
|
||||||
|
|
||||||
if (j.WaitingForUserAction.HasValue)
|
|
||||||
return false; // Job waiting on User Action
|
|
||||||
|
|
||||||
switch (j.JobTypeId)
|
|
||||||
{
|
|
||||||
case JobType.JobTypeIds.HWar:
|
|
||||||
if (!string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference) && !j.JobMetaWarranty.ExternalCompletedDate.HasValue)
|
|
||||||
return true; // Job Logged (Warranty) but not completed
|
|
||||||
break;
|
|
||||||
case JobType.JobTypeIds.HNWar:
|
|
||||||
if (j.JobMetaNonWarranty.RepairerLoggedDate.HasValue && !j.JobMetaNonWarranty.RepairerCompletedDate.HasValue)
|
|
||||||
return true; // Job Logged (Repair) but not completed
|
|
||||||
if (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue && (!j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue || !j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue))
|
|
||||||
return true; // Accounting Charge Required, but not added or paid
|
|
||||||
|
|
||||||
if (j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue)
|
|
||||||
return true; // Accounting Charge Added, but not paid
|
|
||||||
|
|
||||||
if (j.JobMetaNonWarranty.IsInsuranceClaim && !j.JobMetaInsurance.ClaimFormSentDate.HasValue)
|
|
||||||
return true; // Is Insurance Claim, but claim form not sent
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public static void OnForceClose(this Job j, DiscoDataContext dbContext, User Technician, string Reason)
|
|
||||||
{
|
|
||||||
if (!j.CanForceClose())
|
|
||||||
throw new InvalidOperationException("Force Close was Denied");
|
|
||||||
|
|
||||||
// Write Log
|
|
||||||
JobLog jobLog = new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = Technician.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = string.Format("Job Forcibly Closed{0}Reason: {1}", Environment.NewLine, Reason)
|
|
||||||
};
|
|
||||||
dbContext.JobLogs.Add(jobLog);
|
|
||||||
|
|
||||||
j.ClosedDate = DateTime.Now;
|
|
||||||
j.ClosedTechUserId = Technician.Id;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Reopen
|
|
||||||
public static bool CanReopen(this Job j)
|
|
||||||
{
|
|
||||||
return j.ClosedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnReopen(this Job j)
|
|
||||||
{
|
|
||||||
if (!j.CanReopen())
|
|
||||||
throw new InvalidOperationException("Reopen was Denied");
|
|
||||||
|
|
||||||
j.ClosedDate = null;
|
|
||||||
j.ClosedTechUserId = null;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Delete
|
|
||||||
public static bool CanDelete(this Job j)
|
|
||||||
{
|
|
||||||
return j.ClosedDate.HasValue;
|
|
||||||
}
|
|
||||||
public static void OnDelete(this Job j, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Job Sub Types
|
|
||||||
j.JobSubTypes.Clear();
|
|
||||||
|
|
||||||
// Job Attachments
|
|
||||||
foreach (var ja in j.JobAttachments.ToArray())
|
|
||||||
ja.OnDelete(dbContext);
|
|
||||||
j.JobAttachments.Clear();
|
|
||||||
|
|
||||||
// Job Components
|
|
||||||
foreach (var jc in j.JobComponents.ToArray())
|
|
||||||
dbContext.JobComponents.Remove(jc);
|
|
||||||
j.JobComponents.Clear();
|
|
||||||
|
|
||||||
// Job Logs
|
|
||||||
foreach (var jl in j.JobLogs.ToArray())
|
|
||||||
dbContext.JobLogs.Remove(jl);
|
|
||||||
j.JobLogs.Clear();
|
|
||||||
|
|
||||||
// Job Meta
|
|
||||||
if (j.JobMetaInsurance != null)
|
|
||||||
{
|
|
||||||
dbContext.JobMetaInsurances.Remove(j.JobMetaInsurance);
|
|
||||||
j.JobMetaInsurance = null;
|
|
||||||
}
|
|
||||||
if (j.JobMetaNonWarranty != null)
|
|
||||||
{
|
|
||||||
dbContext.JobMetaNonWarranties.Remove(j.JobMetaNonWarranty);
|
|
||||||
j.JobMetaNonWarranty = null;
|
|
||||||
}
|
|
||||||
if (j.JobMetaWarranty != null)
|
|
||||||
{
|
|
||||||
dbContext.JobMetaWarranties.Remove(j.JobMetaWarranty);
|
|
||||||
j.JobMetaWarranty = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Job
|
|
||||||
dbContext.Jobs.Remove(j);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.IO;
|
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Services.Plugins;
|
|
||||||
using Disco.Models.BI.Job;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class JobExtensions
|
|
||||||
{
|
|
||||||
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext dbContext, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
|
||||||
|
|
||||||
JobAttachment ja = new JobAttachment()
|
|
||||||
{
|
|
||||||
JobId = Job.Id,
|
|
||||||
TechUserId = CreatorUser.Id,
|
|
||||||
Filename = Filename,
|
|
||||||
MimeType = MimeType,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = Comments
|
|
||||||
};
|
|
||||||
|
|
||||||
if (DocumentTemplate != null)
|
|
||||||
ja.DocumentTemplateId = DocumentTemplate.Id;
|
|
||||||
|
|
||||||
dbContext.JobAttachments.Add(ja);
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
ja.SaveAttachment(dbContext, Content);
|
|
||||||
Content.Position = 0;
|
|
||||||
if (PdfThumbnail == null)
|
|
||||||
ja.GenerateThumbnail(dbContext, Content);
|
|
||||||
else
|
|
||||||
ja.SaveThumbnailAttachment(dbContext, PdfThumbnail);
|
|
||||||
|
|
||||||
return ja;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Tuple<string, string> Status(this Job j)
|
|
||||||
{
|
|
||||||
var statusId = j.CalculateStatusId();
|
|
||||||
return new Tuple<string, string>(statusId, JobBI.Utilities.JobStatusDescription(statusId, j));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JobTableModel.JobTableItemModelIncludeStatus ToJobTableItemModelIncludeStatus(this Job j)
|
|
||||||
{
|
|
||||||
var i = new JobTableModel.JobTableItemModelIncludeStatus()
|
|
||||||
{
|
|
||||||
Id = j.Id,
|
|
||||||
OpenedDate = j.OpenedDate,
|
|
||||||
ClosedDate = j.ClosedDate,
|
|
||||||
TypeId = j.JobTypeId,
|
|
||||||
TypeDescription = j.JobType.Description,
|
|
||||||
Location = j.DeviceHeldLocation,
|
|
||||||
|
|
||||||
WaitingForUserAction = j.WaitingForUserAction,
|
|
||||||
DeviceReadyForReturn = j.DeviceReadyForReturn,
|
|
||||||
DeviceHeld = j.DeviceHeld,
|
|
||||||
DeviceReturnedDate = j.DeviceReturnedDate
|
|
||||||
};
|
|
||||||
|
|
||||||
if (j.Device != null)
|
|
||||||
{
|
|
||||||
i.DeviceSerialNumber = j.DeviceSerialNumber;
|
|
||||||
i.DeviceModelDescription = j.Device.DeviceModel.Description;
|
|
||||||
i.DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress;
|
|
||||||
|
|
||||||
if (j.JobMetaWarranty != null)
|
|
||||||
{
|
|
||||||
i.JobMetaWarranty_ExternalReference = j.JobMetaWarranty.ExternalReference;
|
|
||||||
i.JobMetaWarranty_ExternalCompletedDate = j.JobMetaWarranty.ExternalCompletedDate;
|
|
||||||
i.JobMetaWarranty_ExternalName = j.JobMetaWarranty.ExternalName;
|
|
||||||
}
|
|
||||||
if (j.JobMetaNonWarranty != null)
|
|
||||||
{
|
|
||||||
i.JobMetaNonWarranty_RepairerLoggedDate = j.JobMetaNonWarranty.RepairerLoggedDate;
|
|
||||||
i.JobMetaNonWarranty_RepairerCompletedDate = j.JobMetaNonWarranty.RepairerCompletedDate;
|
|
||||||
i.JobMetaNonWarranty_AccountingChargeAddedDate = j.JobMetaNonWarranty.AccountingChargeAddedDate;
|
|
||||||
i.JobMetaNonWarranty_AccountingChargePaidDate = j.JobMetaNonWarranty.AccountingChargePaidDate;
|
|
||||||
i.JobMetaNonWarranty_AccountingChargeRequiredDate = j.JobMetaNonWarranty.AccountingChargeRequiredDate;
|
|
||||||
i.JobMetaNonWarranty_IsInsuranceClaim = j.JobMetaNonWarranty.IsInsuranceClaim;
|
|
||||||
i.JobMetaNonWarranty_RepairerName = j.JobMetaNonWarranty.RepairerName;
|
|
||||||
if (j.JobMetaInsurance != null)
|
|
||||||
{
|
|
||||||
i.JobMetaInsurance_ClaimFormSentDate = j.JobMetaInsurance.ClaimFormSentDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (j.User != null)
|
|
||||||
{
|
|
||||||
i.UserId = j.UserId;
|
|
||||||
i.UserDisplayName = j.User.DisplayName;
|
|
||||||
}
|
|
||||||
if (j.OpenedTechUser != null)
|
|
||||||
{
|
|
||||||
i.OpenedTechUserId = j.OpenedTechUserId;
|
|
||||||
i.OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string CalculateStatusId(this Job j)
|
|
||||||
{
|
|
||||||
return j.ToJobTableItemModelIncludeStatus().CalculateStatusId();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string CalculateStatusId(this JobTableModel.JobTableItemModelIncludeStatus j)
|
|
||||||
{
|
|
||||||
if (j.ClosedDate.HasValue)
|
|
||||||
return Job.JobStatusIds.Closed;
|
|
||||||
|
|
||||||
if (j.TypeId == JobType.JobTypeIds.HWar)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(j.JobMetaWarranty_ExternalReference) && !j.JobMetaWarranty_ExternalCompletedDate.HasValue)
|
|
||||||
return Job.JobStatusIds.AwaitingWarrantyRepair; // Job Logged - but not marked as completed
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j.TypeId == JobType.JobTypeIds.HNWar)
|
|
||||||
{
|
|
||||||
if (j.JobMetaNonWarranty_RepairerLoggedDate.HasValue && !j.JobMetaNonWarranty_RepairerCompletedDate.HasValue)
|
|
||||||
return Job.JobStatusIds.AwaitingRepairs; // Repairs logged - but not complete
|
|
||||||
if (j.JobMetaNonWarranty_AccountingChargeAddedDate.HasValue && !j.JobMetaNonWarranty_AccountingChargePaidDate.HasValue)
|
|
||||||
return Job.JobStatusIds.AwaitingAccountingPayment; // Accounting Charge Added, but not paid
|
|
||||||
if (j.JobMetaNonWarranty_AccountingChargeRequiredDate.HasValue && (!j.JobMetaNonWarranty_AccountingChargePaidDate.HasValue || !j.JobMetaNonWarranty_AccountingChargeAddedDate.HasValue))
|
|
||||||
return Job.JobStatusIds.AwaitingAccountingCharge; // Accounting Charge Required, but not added or paid
|
|
||||||
if (j.JobMetaNonWarranty_RepairerLoggedDate.HasValue && j.JobMetaNonWarranty_IsInsuranceClaim.Value && !j.JobMetaInsurance_ClaimFormSentDate.HasValue)
|
|
||||||
return Job.JobStatusIds.AwaitingInsuranceProcessing; // Is insurance claim, but no Claim Form Sent
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j.WaitingForUserAction.HasValue)
|
|
||||||
return Job.JobStatusIds.AwaitingUserAction; // Awaiting for User
|
|
||||||
|
|
||||||
if (j.DeviceReadyForReturn.HasValue && !j.DeviceReturnedDate.HasValue)
|
|
||||||
return Job.JobStatusIds.AwaitingDeviceReturn; // Device not returned to User
|
|
||||||
|
|
||||||
return Job.JobStatusIds.Open;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<DocumentTemplate> AvailableDocumentTemplates(this Job j, DiscoDataContext dbContext, User User, DateTime TimeStamp)
|
|
||||||
{
|
|
||||||
var dts = dbContext.DocumentTemplates.Include("JobSubTypes")
|
|
||||||
.Where(dt => dt.Scope == DocumentTemplate.DocumentTemplateScopes.Job)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var dt in dts.ToArray())
|
|
||||||
{
|
|
||||||
if (dt.JobSubTypes.Count != 0)
|
|
||||||
{ // Filter Applied
|
|
||||||
bool match = false;
|
|
||||||
foreach (var st in j.JobSubTypes)
|
|
||||||
{
|
|
||||||
if (dt.JobSubTypes.Contains(st))
|
|
||||||
{
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!match)
|
|
||||||
dts.Remove(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evaluate Filters
|
|
||||||
dts = dts.Where(dt => dt.FilterExpressionMatches(j, dbContext, User, TimeStamp, DocumentState.DefaultState())).ToList();
|
|
||||||
|
|
||||||
return dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DateTime ValidateDateAfterOpened(this Job j, DateTime d)
|
|
||||||
{
|
|
||||||
if (d < j.OpenedDate)
|
|
||||||
{
|
|
||||||
if (d > j.OpenedDate.AddMinutes(-1))
|
|
||||||
return j.OpenedDate;
|
|
||||||
else
|
|
||||||
throw new ArgumentException("The Date must be >= the Open Date.", "d");
|
|
||||||
}
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateFaultDescription(this Job j, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.AppendLine("Faulty Components:");
|
|
||||||
foreach (var jst in j.JobSubTypes)
|
|
||||||
sb.Append("- ").AppendLine(jst.Description).AppendLine(" - ");
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateFaultDescriptionFooter(this Job j, DiscoDataContext dbContext, PluginFeatureManifest WarrantyProviderDefinition)
|
|
||||||
{
|
|
||||||
var versionDisco = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
|
||||||
return string.Format("Automation by Disco v{0}.{1}.{2:0000}.{3:0000} (Provider: {4} v{5})",
|
|
||||||
versionDisco.Major, versionDisco.Minor, versionDisco.Build, versionDisco.Revision, WarrantyProviderDefinition.Id, WarrantyProviderDefinition.PluginManifest.Version.ToString(4));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UpdateSubTypes(this Job j, DiscoDataContext dbContext, List<JobSubType> SubTypes, bool AddComponents, User TechUser)
|
|
||||||
{
|
|
||||||
if (SubTypes == null || SubTypes.Count == 0)
|
|
||||||
throw new ArgumentException("The Job must contain at least one Sub Type");
|
|
||||||
|
|
||||||
List<JobSubType> addedSubTypes = new List<JobSubType>();
|
|
||||||
List<JobSubType> removedSubTypes = new List<JobSubType>();
|
|
||||||
|
|
||||||
// Removed Sub Types
|
|
||||||
foreach (var t in j.JobSubTypes.ToArray())
|
|
||||||
if (!SubTypes.Contains(t))
|
|
||||||
{
|
|
||||||
removedSubTypes.Add(t);
|
|
||||||
j.JobSubTypes.Remove(t);
|
|
||||||
}
|
|
||||||
// Added Sub Types
|
|
||||||
foreach (var t in SubTypes)
|
|
||||||
if (!j.JobSubTypes.Contains(t))
|
|
||||||
{
|
|
||||||
addedSubTypes.Add(t);
|
|
||||||
j.JobSubTypes.Add(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write Log
|
|
||||||
if (addedSubTypes.Count > 0 || removedSubTypes.Count > 0)
|
|
||||||
{
|
|
||||||
StringBuilder logBuilder = new StringBuilder();
|
|
||||||
logBuilder.AppendLine("Updated Job Sub Types");
|
|
||||||
if (removedSubTypes.Count > 0)
|
|
||||||
{
|
|
||||||
logBuilder.AppendLine("Removed:");
|
|
||||||
foreach (var t in removedSubTypes)
|
|
||||||
logBuilder.Append("- ").AppendLine(t.ToString());
|
|
||||||
}
|
|
||||||
if (addedSubTypes.Count > 0)
|
|
||||||
{
|
|
||||||
logBuilder.AppendLine("Added:");
|
|
||||||
foreach (var t in addedSubTypes)
|
|
||||||
logBuilder.Append("- ").AppendLine(t.ToString());
|
|
||||||
}
|
|
||||||
dbContext.JobLogs.Add(new JobLog()
|
|
||||||
{
|
|
||||||
JobId = j.Id,
|
|
||||||
TechUserId = TechUser.Id,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = logBuilder.ToString()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Components
|
|
||||||
if (AddComponents && addedSubTypes.Count > 0 && j.DeviceSerialNumber != null)
|
|
||||||
{
|
|
||||||
var components = dbContext.DeviceComponents.Include("JobSubTypes").Where(c => !c.DeviceModelId.HasValue || c.DeviceModelId == j.Device.DeviceModelId);
|
|
||||||
var addedComponents = new List<DeviceComponent>();
|
|
||||||
foreach (var c in components)
|
|
||||||
{
|
|
||||||
foreach (var st in c.JobSubTypes)
|
|
||||||
{
|
|
||||||
foreach (var jst in addedSubTypes)
|
|
||||||
{
|
|
||||||
if (st.JobTypeId == jst.JobTypeId && st.Id == jst.Id)
|
|
||||||
{
|
|
||||||
addedComponents.Add(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addedComponents.Contains(c))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var c in addedComponents)
|
|
||||||
{
|
|
||||||
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.InvariantCultureIgnoreCase)))
|
|
||||||
{ // Job Component with matching Description doesn't exist.
|
|
||||||
dbContext.JobComponents.Add(new JobComponent()
|
|
||||||
{
|
|
||||||
Job = j,
|
|
||||||
TechUserId = TechUser.Id,
|
|
||||||
Cost = c.Cost,
|
|
||||||
Description = c.Description
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class JobFlagExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
private static Dictionary<string, Dictionary<long, string>> allFlags;
|
|
||||||
private static void CacheAllFlags()
|
|
||||||
{
|
|
||||||
if (allFlags == null)
|
|
||||||
{
|
|
||||||
var fType = typeof(Job.UserManagementFlags);
|
|
||||||
var fMembers = fType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
|
|
||||||
|
|
||||||
var flags = new Dictionary<string, Dictionary<long, string>>();
|
|
||||||
foreach (var f in fMembers)
|
|
||||||
{
|
|
||||||
DisplayAttribute display = (DisplayAttribute)(f.GetCustomAttributes(typeof(DisplayAttribute), false)[0]);
|
|
||||||
string gn = display.GroupName;
|
|
||||||
Dictionary<long, string> g;
|
|
||||||
if (!flags.TryGetValue(gn, out g))
|
|
||||||
{
|
|
||||||
g = new Dictionary<long, string>();
|
|
||||||
flags.Add(gn, g);
|
|
||||||
}
|
|
||||||
g[(long)f.GetRawConstantValue()] = display.Name;
|
|
||||||
}
|
|
||||||
allFlags = flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<string, List<Tuple<long, string, bool>>> ValidFlagsGrouped(this Job j)
|
|
||||||
{
|
|
||||||
Dictionary<string, List<Tuple<long, string, bool>>> validFlags = new Dictionary<string, List<Tuple<long, string, bool>>>();
|
|
||||||
|
|
||||||
CacheAllFlags();
|
|
||||||
|
|
||||||
var currentFlags = j.Flags ?? 0;
|
|
||||||
|
|
||||||
foreach (var jt in j.JobSubTypes)
|
|
||||||
{
|
|
||||||
Dictionary<long, string> g;
|
|
||||||
if (allFlags.TryGetValue(jt.Id, out g))
|
|
||||||
{
|
|
||||||
validFlags[jt.Id] = g.Select(f => new Tuple<long, string, bool>(f.Key, f.Value, ((currentFlags & f.Key) == f.Key))).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
validFlags[jt.Id] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return validFlags;
|
|
||||||
}
|
|
||||||
public static Dictionary<long, Tuple<string, bool>> ValidFlags(this Job j)
|
|
||||||
{
|
|
||||||
Dictionary<long, Tuple<string, bool>> validFlags = new Dictionary<long, Tuple<string, bool>>();
|
|
||||||
|
|
||||||
CacheAllFlags();
|
|
||||||
|
|
||||||
var currentFlags = j.Flags ?? 0;
|
|
||||||
|
|
||||||
foreach (var jt in j.JobSubTypes)
|
|
||||||
{
|
|
||||||
Dictionary<long, string> g;
|
|
||||||
if (allFlags.TryGetValue(jt.Id, out g))
|
|
||||||
{
|
|
||||||
foreach (var f in g)
|
|
||||||
validFlags[f.Key] = new Tuple<string, bool>(string.Format("{0}: {1}", jt.Description, f.Value), ((currentFlags & f.Key) == f.Key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return validFlags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Job;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class JobTableExtensions
|
|
||||||
{
|
|
||||||
|
|
||||||
public static List<JobTableModel.JobTableItemModel> DetermineItems(this JobTableModel model, DiscoDataContext dbContext, IQueryable<Job> Jobs)
|
|
||||||
{
|
|
||||||
List<JobTableModel.JobTableItemModel> items;
|
|
||||||
|
|
||||||
if (model.ShowStatus)
|
|
||||||
{
|
|
||||||
|
|
||||||
var jobItems = Jobs.Select(j => new JobTableModel.JobTableItemModelIncludeStatus()
|
|
||||||
{
|
|
||||||
Id = j.Id,
|
|
||||||
OpenedDate = j.OpenedDate,
|
|
||||||
ClosedDate = j.ClosedDate,
|
|
||||||
TypeId = j.JobTypeId,
|
|
||||||
TypeDescription = j.JobType.Description,
|
|
||||||
DeviceSerialNumber = j.Device.SerialNumber,
|
|
||||||
DeviceProfileId = j.Device.DeviceProfileId,
|
|
||||||
DeviceModelId = j.Device.DeviceModelId,
|
|
||||||
DeviceModelDescription = j.Device.DeviceModel.Description,
|
|
||||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
|
|
||||||
UserId = j.UserId,
|
|
||||||
UserDisplayName = j.User.DisplayName,
|
|
||||||
OpenedTechUserId = j.OpenedTechUserId,
|
|
||||||
OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName,
|
|
||||||
Location = j.DeviceHeldLocation,
|
|
||||||
|
|
||||||
JobMetaWarranty_ExternalReference = j.JobMetaWarranty.ExternalReference,
|
|
||||||
JobMetaWarranty_ExternalCompletedDate = j.JobMetaWarranty.ExternalCompletedDate,
|
|
||||||
JobMetaNonWarranty_RepairerLoggedDate = j.JobMetaNonWarranty.RepairerLoggedDate,
|
|
||||||
JobMetaNonWarranty_RepairerCompletedDate = j.JobMetaNonWarranty.RepairerCompletedDate,
|
|
||||||
JobMetaNonWarranty_AccountingChargeAddedDate = j.JobMetaNonWarranty.AccountingChargeAddedDate,
|
|
||||||
JobMetaNonWarranty_AccountingChargePaidDate = j.JobMetaNonWarranty.AccountingChargePaidDate,
|
|
||||||
JobMetaNonWarranty_AccountingChargeRequiredDate = j.JobMetaNonWarranty.AccountingChargeRequiredDate,
|
|
||||||
JobMetaNonWarranty_IsInsuranceClaim = j.JobMetaNonWarranty.IsInsuranceClaim,
|
|
||||||
JobMetaInsurance_ClaimFormSentDate = j.JobMetaInsurance.ClaimFormSentDate,
|
|
||||||
|
|
||||||
WaitingForUserAction = j.WaitingForUserAction,
|
|
||||||
DeviceReadyForReturn = j.DeviceReadyForReturn,
|
|
||||||
DeviceHeld = j.DeviceHeld,
|
|
||||||
DeviceReturnedDate = j.DeviceReturnedDate,
|
|
||||||
JobMetaWarranty_ExternalName = j.JobMetaWarranty.ExternalName,
|
|
||||||
JobMetaNonWarranty_RepairerName = j.JobMetaNonWarranty.RepairerName
|
|
||||||
});
|
|
||||||
|
|
||||||
items = new List<JobTableModel.JobTableItemModel>();
|
|
||||||
foreach (var j in jobItems)
|
|
||||||
{
|
|
||||||
j.StatusId = j.CalculateStatusId();
|
|
||||||
j.StatusDescription = JobBI.Utilities.JobStatusDescription(j.StatusId, j);
|
|
||||||
|
|
||||||
items.Add(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
items = Jobs.Select(j => new JobTableModel.JobTableItemModel()
|
|
||||||
{
|
|
||||||
Id = j.Id,
|
|
||||||
OpenedDate = j.OpenedDate,
|
|
||||||
ClosedDate = j.ClosedDate,
|
|
||||||
TypeId = j.JobTypeId,
|
|
||||||
TypeDescription = j.JobType.Description,
|
|
||||||
DeviceSerialNumber = j.Device.SerialNumber,
|
|
||||||
DeviceProfileId = j.Device.DeviceProfileId,
|
|
||||||
DeviceModelId = j.Device.DeviceModelId,
|
|
||||||
DeviceModelDescription = j.Device.DeviceModel.Description,
|
|
||||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
|
|
||||||
UserId = j.UserId,
|
|
||||||
UserDisplayName = j.User.DisplayName,
|
|
||||||
OpenedTechUserId = j.OpenedTechUserId,
|
|
||||||
OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName,
|
|
||||||
Location = j.DeviceHeldLocation
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!model.ShowDeviceAddress.HasValue)
|
|
||||||
model.ShowDeviceAddress = dbContext.DiscoConfiguration.MultiSiteMode;
|
|
||||||
|
|
||||||
foreach (var j in items)
|
|
||||||
if (j.DeviceAddressId.HasValue)
|
|
||||||
j.DeviceAddress = dbContext.DiscoConfiguration.OrganisationAddresses.GetAddress(j.DeviceAddressId.Value).Name;
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Fill(this JobTableModel model, DiscoDataContext dbContext, IQueryable<Job> Jobs)
|
|
||||||
{
|
|
||||||
model.Items = model.DetermineItems(dbContext, Jobs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.IO;
|
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
|
||||||
using Disco.Models.Interop.ActiveDirectory;
|
|
||||||
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class UserExtensions
|
|
||||||
{
|
|
||||||
public static UserAttachment CreateAttachment(this User User, DiscoDataContext dbContext, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
|
||||||
|
|
||||||
UserAttachment ua = new UserAttachment()
|
|
||||||
{
|
|
||||||
UserId = User.Id,
|
|
||||||
TechUserId = CreatorUser.Id,
|
|
||||||
Filename = Filename,
|
|
||||||
MimeType = MimeType,
|
|
||||||
Timestamp = DateTime.Now,
|
|
||||||
Comments = Comments
|
|
||||||
};
|
|
||||||
|
|
||||||
if (DocumentTemplate != null)
|
|
||||||
ua.DocumentTemplateId = DocumentTemplate.Id;
|
|
||||||
|
|
||||||
dbContext.UserAttachments.Add(ua);
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
ua.SaveAttachment(dbContext, Content);
|
|
||||||
Content.Position = 0;
|
|
||||||
if (PdfThumbnail == null)
|
|
||||||
ua.GenerateThumbnail(dbContext, Content);
|
|
||||||
else
|
|
||||||
ua.SaveThumbnailAttachment(dbContext, PdfThumbnail);
|
|
||||||
|
|
||||||
return ua;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<DocumentTemplate> AvailableDocumentTemplates(this User u, DiscoDataContext dbContext, User User, DateTime TimeStamp)
|
|
||||||
{
|
|
||||||
var dts = dbContext.DocumentTemplates.Include("JobSubTypes")
|
|
||||||
.Where(dt => dt.Scope == DocumentTemplate.DocumentTemplateScopes.User)
|
|
||||||
.ToArray()
|
|
||||||
.Where(dt => dt.FilterExpressionMatches(u, dbContext, User, TimeStamp, DocumentState.DefaultState())).ToList();
|
|
||||||
|
|
||||||
return dts;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<DeviceUserAssignment> CurrentDeviceUserAssignments(this User u)
|
|
||||||
{
|
|
||||||
return u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).ToList();
|
|
||||||
}
|
|
||||||
public static ActiveDirectoryUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
return Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(User.Id, AdditionalProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
namespace Disco.BI.Extensions
|
|
||||||
{
|
|
||||||
public static class WirelessCertificateExtensions
|
|
||||||
{
|
|
||||||
public static System.DateTime? CertificateExpirationDate(this DeviceCertificate wc)
|
|
||||||
{
|
|
||||||
if (wc.Content == null || wc.Content.Length == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
X509Certificate2 c = new X509Certificate2(wc.Content, "password");
|
|
||||||
return c.NotAfter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,397 +0,0 @@
|
|||||||
using Disco.Models.Interop.ActiveDirectory;
|
|
||||||
using Disco.BI.DeviceBI;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.DirectoryServices;
|
|
||||||
using System.Linq;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
public static class ActiveDirectory
|
|
||||||
{
|
|
||||||
public static ActiveDirectoryMachineAccount GetMachineAccount(string ComputerName, System.Guid? UUIDNetbootGUID = null, System.Guid? MacAddressNetbootGUID = null, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(ComputerName))
|
|
||||||
throw new System.ArgumentException("Invalid Computer Name - Empty", "ComputerName");
|
|
||||||
if (ComputerName.Contains("\\"))
|
|
||||||
ComputerName = ComputerName.Substring(checked(ComputerName.IndexOf("\\") + 1));
|
|
||||||
if (ComputerName.Length > 24)
|
|
||||||
throw new System.ArgumentException("Invalid Computer Name - Length > 24", "ComputerName");
|
|
||||||
string sAMAccountName = ComputerName;
|
|
||||||
if (!sAMAccountName.EndsWith("$"))
|
|
||||||
sAMAccountName = string.Format("{0}$", sAMAccountName);
|
|
||||||
|
|
||||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
|
||||||
{
|
|
||||||
var loadProperties = new List<string> { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
|
|
||||||
loadProperties.AddRange(AdditionalProperties);
|
|
||||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
||||||
{
|
|
||||||
SearchResult dResult = dSearcher.FindOne();
|
|
||||||
if (dResult != null)
|
|
||||||
{
|
|
||||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UUIDNetbootGUID.HasValue)
|
|
||||||
{
|
|
||||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(UUIDNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
||||||
{
|
|
||||||
SearchResult dResult = dSearcher.FindOne();
|
|
||||||
if (dResult != null)
|
|
||||||
{
|
|
||||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (MacAddressNetbootGUID.HasValue)
|
|
||||||
{
|
|
||||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
||||||
{
|
|
||||||
SearchResult dResult = dSearcher.FindOne();
|
|
||||||
if (dResult != null)
|
|
||||||
{
|
|
||||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
private static ActiveDirectoryMachineAccount DirectorySearchResultToMachineAccount(SearchResult result, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
string name = result.Properties["name"][0].ToString();
|
|
||||||
string sAMAccountName = result.Properties["sAMAccountName"][0].ToString();
|
|
||||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
|
||||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
|
||||||
|
|
||||||
var dNSNameProperty = result.Properties["dNSHostName"];
|
|
||||||
string dNSName = null;
|
|
||||||
if (dNSNameProperty.Count > 0)
|
|
||||||
dNSName = dNSNameProperty[0].ToString();
|
|
||||||
else
|
|
||||||
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
|
||||||
|
|
||||||
bool isCriticalSystemObject = (bool)result.Properties["isCriticalSystemObject"][0];
|
|
||||||
|
|
||||||
System.Guid netbootGUIDResult = default(System.Guid);
|
|
||||||
ResultPropertyValueCollection netbootGUIDProp = result.Properties["netbootGUID"];
|
|
||||||
if (netbootGUIDProp.Count > 0)
|
|
||||||
{
|
|
||||||
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional Properties
|
|
||||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
|
||||||
foreach (string propertyName in AdditionalProperties)
|
|
||||||
{
|
|
||||||
var property = result.Properties[propertyName];
|
|
||||||
var propertyValues = new List<object>();
|
|
||||||
for (int index = 0; index < property.Count; index++)
|
|
||||||
propertyValues.Add(property[index]);
|
|
||||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ActiveDirectoryMachineAccount
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
DistinguishedName = distinguishedName,
|
|
||||||
sAMAccountName = sAMAccountName,
|
|
||||||
ObjectSid = objectSid,
|
|
||||||
NetbootGUID = netbootGUIDResult,
|
|
||||||
Path = result.Path,
|
|
||||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
|
||||||
DnsName = dNSName,
|
|
||||||
IsCriticalSystemObject = isCriticalSystemObject,
|
|
||||||
LoadedProperties = additionalProperties
|
|
||||||
};
|
|
||||||
}
|
|
||||||
private static ActiveDirectoryUserAccount SearchResultToActiveDirectoryUserAccount(SearchResult result, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
string name = result.Properties["name"][0].ToString();
|
|
||||||
string username = result.Properties["sAMAccountName"][0].ToString();
|
|
||||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
|
||||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
|
||||||
|
|
||||||
ResultPropertyValueCollection displayNameProp = result.Properties["displayName"];
|
|
||||||
string displayName = username;
|
|
||||||
if (displayNameProp.Count > 0)
|
|
||||||
displayName = displayNameProp[0].ToString();
|
|
||||||
string surname = null;
|
|
||||||
ResultPropertyValueCollection surnameProp = result.Properties["sn"];
|
|
||||||
if (surnameProp.Count > 0)
|
|
||||||
surname = surnameProp[0].ToString();
|
|
||||||
string givenName = null;
|
|
||||||
ResultPropertyValueCollection givenNameProp = result.Properties["givenName"];
|
|
||||||
if (givenNameProp.Count > 0)
|
|
||||||
givenName = givenNameProp[0].ToString();
|
|
||||||
string email = null;
|
|
||||||
ResultPropertyValueCollection emailProp = result.Properties["mail"];
|
|
||||||
if (emailProp.Count > 0)
|
|
||||||
email = emailProp[0].ToString();
|
|
||||||
string phone = null;
|
|
||||||
ResultPropertyValueCollection phoneProp = result.Properties["telephoneNumber"];
|
|
||||||
if (phoneProp.Count > 0)
|
|
||||||
phone = phoneProp[0].ToString();
|
|
||||||
|
|
||||||
IEnumerable<string> groupCNs = result.Properties["memberOf"].Cast<string>();
|
|
||||||
List<string> groups = ActiveDirectoryCachedGroups.GetGroups(groupCNs).Select(g => g.ToLower()).ToList();
|
|
||||||
|
|
||||||
//foreach (string groupCN in result.Properties["memberOf"])
|
|
||||||
//{
|
|
||||||
// Removed 2012-11-30 G# - Moved to Recursive Cache
|
|
||||||
//var groupCNlower = groupCN.ToLower();
|
|
||||||
//if (groupCNlower.StartsWith("cn="))
|
|
||||||
// groups.Add(groupCNlower.Substring(3, groupCNlower.IndexOf(",") - 3));
|
|
||||||
// End Removed 2012-11-30 G#
|
|
||||||
//}
|
|
||||||
|
|
||||||
string type = null;
|
|
||||||
if (groups.Contains("domain admins") || groups.Contains("disco admins"))
|
|
||||||
{
|
|
||||||
type = "Admin";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (groups.Contains("staff"))
|
|
||||||
{
|
|
||||||
type = "Staff";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (groups.Contains("students"))
|
|
||||||
{
|
|
||||||
type = "Student";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional Properties
|
|
||||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
|
||||||
foreach (string propertyName in AdditionalProperties)
|
|
||||||
{
|
|
||||||
var property = result.Properties[propertyName];
|
|
||||||
var propertyValues = new List<object>();
|
|
||||||
for (int index = 0; index < property.Count; index++)
|
|
||||||
propertyValues.Add(property[index]);
|
|
||||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ActiveDirectoryUserAccount
|
|
||||||
{
|
|
||||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
|
||||||
Name = name,
|
|
||||||
Surname = surname,
|
|
||||||
GivenName = givenName,
|
|
||||||
Email = email,
|
|
||||||
Phone = phone,
|
|
||||||
DistinguishedName = distinguishedName,
|
|
||||||
sAMAccountName = username,
|
|
||||||
DisplayName = displayName,
|
|
||||||
ObjectSid = objectSid,
|
|
||||||
Type = type,
|
|
||||||
Path = result.Path,
|
|
||||||
LoadedProperties = additionalProperties
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public static ActiveDirectoryUserAccount GetUserAccount(string Username, params string[] AdditionalProperties)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(Username))
|
|
||||||
throw new System.ArgumentException("Invalid User Account", "Username");
|
|
||||||
string sAMAccountName = Username;
|
|
||||||
if (sAMAccountName.Contains("\\"))
|
|
||||||
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
|
||||||
|
|
||||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
|
||||||
{
|
|
||||||
var loadProperties = new List<string> {
|
|
||||||
"name",
|
|
||||||
"distinguishedName",
|
|
||||||
"sAMAccountName",
|
|
||||||
"objectSid",
|
|
||||||
"displayName",
|
|
||||||
"sn",
|
|
||||||
"givenName",
|
|
||||||
"memberOf",
|
|
||||||
"mail",
|
|
||||||
"telephoneNumber"
|
|
||||||
};
|
|
||||||
loadProperties.AddRange(AdditionalProperties);
|
|
||||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=user)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
|
||||||
{
|
|
||||||
SearchResult dResult = dSearcher.FindOne();
|
|
||||||
if (dResult != null)
|
|
||||||
return ActiveDirectory.SearchResultToActiveDirectoryUserAccount(dResult, AdditionalProperties);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static string OfflineDomainJoinProvision(ref ActiveDirectoryMachineAccount ExistingAccount, string ComputerName, string OrganisationalUnit = null, string EnrolSessionId = null)
|
|
||||||
{
|
|
||||||
if (ExistingAccount != null && ExistingAccount.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", ExistingAccount.DistinguishedName));
|
|
||||||
|
|
||||||
string DJoinResult = null;
|
|
||||||
if (string.IsNullOrWhiteSpace(ComputerName) || ComputerName.Length > 24)
|
|
||||||
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
|
||||||
|
|
||||||
// Added 2012-10-25 G#
|
|
||||||
// Ensure Specified OU Exists
|
|
||||||
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
|
||||||
{
|
|
||||||
var ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
|
||||||
{
|
|
||||||
if (ou == null)
|
|
||||||
{
|
|
||||||
throw new Exception("OU's Directory Entry couldn't be found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", ouPath), "OrganisationalUnit", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// End Added 2012-10-25 G#
|
|
||||||
|
|
||||||
// Delete Existing
|
|
||||||
if (ExistingAccount != null)
|
|
||||||
ExistingAccount.DeleteAccount();
|
|
||||||
|
|
||||||
string tempFileName = System.IO.Path.GetTempFileName();
|
|
||||||
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0},{1}\"", OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName) : string.Empty;
|
|
||||||
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
|
||||||
ActiveDirectoryHelpers.DefaultDomainName,
|
|
||||||
ActiveDirectoryHelpers.DefaultDomainPDCName,
|
|
||||||
ComputerName,
|
|
||||||
argumentOU,
|
|
||||||
tempFileName
|
|
||||||
);
|
|
||||||
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
|
||||||
{
|
|
||||||
CreateNoWindow = true,
|
|
||||||
ErrorDialog = false,
|
|
||||||
LoadUserProfile = false,
|
|
||||||
RedirectStandardOutput = true,
|
|
||||||
RedirectStandardError = true,
|
|
||||||
UseShellExecute = false
|
|
||||||
};
|
|
||||||
if (EnrolSessionId != null)
|
|
||||||
{
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, string.Format("{0} {1}{2}", "DJOIN.EXE", arguments, System.Environment.NewLine));
|
|
||||||
}
|
|
||||||
|
|
||||||
string stdOutput;
|
|
||||||
string stdError;
|
|
||||||
using (Process commandProc = Process.Start(commandStarter))
|
|
||||||
{
|
|
||||||
commandProc.WaitForExit(20000);
|
|
||||||
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
|
||||||
stdError = commandProc.StandardError.ReadToEnd();
|
|
||||||
}
|
|
||||||
if (EnrolSessionId != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(stdOutput))
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdOutput + System.Environment.NewLine);
|
|
||||||
if (!string.IsNullOrWhiteSpace(stdError))
|
|
||||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdError + System.Environment.NewLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.IO.File.Exists(tempFileName))
|
|
||||||
{
|
|
||||||
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
|
|
||||||
System.IO.File.Delete(tempFileName);
|
|
||||||
}
|
|
||||||
if (string.IsNullOrWhiteSpace(DJoinResult))
|
|
||||||
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
|
|
||||||
ExistingAccount = ActiveDirectory.GetMachineAccount(ComputerName);
|
|
||||||
return DJoinResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<ActiveDirectoryUserAccount> SearchUsers(string term)
|
|
||||||
{
|
|
||||||
List<ActiveDirectoryUserAccount> users = new List<ActiveDirectoryUserAccount>();
|
|
||||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
|
||||||
string defaultNetBiosDomainName = ActiveDirectoryHelpers.DefaultDomainNetBiosName;
|
|
||||||
term = ActiveDirectoryHelpers.EscapeLdapQuery(term);
|
|
||||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
|
||||||
{
|
|
||||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(&(objectClass=User)(objectCategory=Person)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", term), new string[]
|
|
||||||
{
|
|
||||||
"name",
|
|
||||||
"distinguishedName",
|
|
||||||
"sAMAccountName",
|
|
||||||
"objectSid",
|
|
||||||
"displayName",
|
|
||||||
"sn",
|
|
||||||
"givenName",
|
|
||||||
"memberOf",
|
|
||||||
"mail",
|
|
||||||
"telephoneNumber"
|
|
||||||
}, SearchScope.Subtree))
|
|
||||||
{
|
|
||||||
searcher.SizeLimit = 30;
|
|
||||||
SearchResultCollection results = searcher.FindAll();
|
|
||||||
foreach (SearchResult result in results)
|
|
||||||
{
|
|
||||||
users.Add(ActiveDirectory.SearchResultToActiveDirectoryUserAccount(result));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
public static List<ActiveDirectoryOrganisationalUnit> GetOrganisationalUnitStructure()
|
|
||||||
{
|
|
||||||
ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit
|
|
||||||
{
|
|
||||||
Children = new System.Collections.Generic.List<ActiveDirectoryOrganisationalUnit>()
|
|
||||||
};
|
|
||||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
|
||||||
|
|
||||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
|
||||||
{
|
|
||||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref DomainOUs, entry);
|
|
||||||
}
|
|
||||||
return DomainOUs.Children;
|
|
||||||
}
|
|
||||||
private static void GetOrganisationalUnitStructure_Recursive(ref ActiveDirectoryOrganisationalUnit ParentOU, DirectoryEntry Container)
|
|
||||||
{
|
|
||||||
using (DirectorySearcher searcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
|
|
||||||
{
|
|
||||||
"name",
|
|
||||||
"distinguishedName"
|
|
||||||
}, SearchScope.OneLevel))
|
|
||||||
{
|
|
||||||
using (SearchResultCollection results = searcher.FindAll())
|
|
||||||
{
|
|
||||||
foreach (SearchResult result in results)
|
|
||||||
{
|
|
||||||
string i = result.Properties["name"][0].ToString();
|
|
||||||
string dn = result.Properties["distinguishedName"][0].ToString();
|
|
||||||
ActiveDirectoryOrganisationalUnit ChildOU = new ActiveDirectoryOrganisationalUnit
|
|
||||||
{
|
|
||||||
Name = i,
|
|
||||||
Path = dn.Substring(0, dn.IndexOf(",DC=")),
|
|
||||||
Children = new List<ActiveDirectoryOrganisationalUnit>()
|
|
||||||
};
|
|
||||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry());
|
|
||||||
if (ChildOU.Children.Count == 0)
|
|
||||||
ChildOU.Children = null;
|
|
||||||
ParentOU.Children.Add(ChildOU);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,186 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.DirectoryServices;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
using Quartz;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
public class ActiveDirectoryCachedGroups : ScheduledTask
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<string, Tuple<ADCachedGroup, DateTime>> _Cache = new ConcurrentDictionary<string, Tuple<ADCachedGroup, DateTime>>();
|
|
||||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
|
||||||
|
|
||||||
public static IEnumerable<string> GetGroups(IEnumerable<string> GroupCNs)
|
|
||||||
{
|
|
||||||
List<ADCachedGroup> groups = new List<ADCachedGroup>();
|
|
||||||
|
|
||||||
foreach (var groupCN in GroupCNs)
|
|
||||||
foreach (var group in GetGroupsRecursive(groupCN, new Stack<ADCachedGroup>()))
|
|
||||||
if (!groups.Contains(group))
|
|
||||||
{
|
|
||||||
groups.Add(group);
|
|
||||||
yield return group.FriendlyName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static IEnumerable<string> GetGroups(string GroupCN)
|
|
||||||
{
|
|
||||||
foreach (var group in GetGroupsRecursive(GroupCN, new Stack<ADCachedGroup>()))
|
|
||||||
yield return group.FriendlyName;
|
|
||||||
}
|
|
||||||
private static IEnumerable<ADCachedGroup> GetGroupsRecursive(string GroupCN, Stack<ADCachedGroup> RecursiveTree)
|
|
||||||
{
|
|
||||||
var group = GetGroup(GroupCN);
|
|
||||||
|
|
||||||
if (group != null && !RecursiveTree.Contains(group))
|
|
||||||
{
|
|
||||||
yield return group;
|
|
||||||
|
|
||||||
if (group.MemberOf != null)
|
|
||||||
{
|
|
||||||
RecursiveTree.Push(group);
|
|
||||||
|
|
||||||
foreach (var memberOfGroupCN in group.MemberOf)
|
|
||||||
foreach (var memberOfGroup in GetGroupsRecursive(memberOfGroupCN, RecursiveTree))
|
|
||||||
yield return memberOfGroup;
|
|
||||||
|
|
||||||
RecursiveTree.Pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ADCachedGroup GetGroup(string GroupCN)
|
|
||||||
{
|
|
||||||
// Check Cache
|
|
||||||
Tuple<ADCachedGroup, DateTime> groupRecord = TryCache(GroupCN);
|
|
||||||
|
|
||||||
if (groupRecord == null)
|
|
||||||
{
|
|
||||||
// Load from AD
|
|
||||||
var group = ADCachedGroup.LoadFromAD(GroupCN);
|
|
||||||
SetValue(GroupCN, group);
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Return from Cache
|
|
||||||
return groupRecord.Item1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Tuple<ADCachedGroup, DateTime> TryCache(string GroupCN)
|
|
||||||
{
|
|
||||||
string groupCN = GroupCN.ToLower();
|
|
||||||
Tuple<ADCachedGroup, DateTime> groupRecord;
|
|
||||||
if (_Cache.TryGetValue(groupCN, out groupRecord))
|
|
||||||
{
|
|
||||||
if (groupRecord.Item2 > DateTime.Now)
|
|
||||||
return groupRecord;
|
|
||||||
else
|
|
||||||
_Cache.TryRemove(groupCN, out groupRecord);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
private static bool SetValue(string GroupCN, ADCachedGroup GroupRecord)
|
|
||||||
{
|
|
||||||
string key = GroupCN.ToLower();
|
|
||||||
Tuple<ADCachedGroup, DateTime> groupRecord = new Tuple<ADCachedGroup, DateTime>(GroupRecord, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
|
||||||
if (_Cache.ContainsKey(key))
|
|
||||||
{
|
|
||||||
Tuple<ADCachedGroup, DateTime> oldGroupRecord;
|
|
||||||
if (_Cache.TryGetValue(key, out oldGroupRecord))
|
|
||||||
{
|
|
||||||
return _Cache.TryUpdate(key, groupRecord, oldGroupRecord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _Cache.TryAdd(key, groupRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ADCachedGroup
|
|
||||||
{
|
|
||||||
public string CN { get; private set; }
|
|
||||||
public string FriendlyName { get; private set; }
|
|
||||||
|
|
||||||
public List<string> MemberOf { get; private set; }
|
|
||||||
|
|
||||||
public static ADCachedGroup LoadFromAD(string CN)
|
|
||||||
{
|
|
||||||
ADCachedGroup group = null;
|
|
||||||
|
|
||||||
using (DirectoryEntry groupDE = new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, CN)))
|
|
||||||
{
|
|
||||||
if (groupDE != null)
|
|
||||||
{
|
|
||||||
group = new ADCachedGroup()
|
|
||||||
{
|
|
||||||
CN = CN
|
|
||||||
};
|
|
||||||
|
|
||||||
group.FriendlyName = (string)groupDE.Properties["sAMAccountName"].Value;
|
|
||||||
|
|
||||||
var groupMemberOf = groupDE.Properties["memberOf"];
|
|
||||||
if (groupMemberOf != null && groupMemberOf.Count > 0)
|
|
||||||
{
|
|
||||||
group.MemberOf = groupMemberOf.Cast<string>().ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ADCachedGroup()
|
|
||||||
{
|
|
||||||
// Private Constructor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CleanStaleCache()
|
|
||||||
{
|
|
||||||
var groupKeys = _Cache.Keys.ToArray();
|
|
||||||
foreach (string groupKey in groupKeys)
|
|
||||||
{
|
|
||||||
Tuple<ADCachedGroup, DateTime> groupRecord;
|
|
||||||
if (_Cache.TryGetValue(groupKey, out groupRecord))
|
|
||||||
{
|
|
||||||
if (groupRecord.Item2 <= DateTime.Now)
|
|
||||||
_Cache.TryRemove(groupKey, out groupRecord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string TaskName { get { return "AD Group Cache - Clean Stale Cache"; } }
|
|
||||||
|
|
||||||
public override bool SingleInstanceTask { get { return true; } }
|
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
|
||||||
public override bool LogExceptionsOnly { get { return true; } }
|
|
||||||
|
|
||||||
public override void InitalizeScheduledTask(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Run @ every 15mins
|
|
||||||
|
|
||||||
// Next 15min interval
|
|
||||||
DateTime now = DateTime.Now;
|
|
||||||
int mins = (15 - (now.Minute % 15));
|
|
||||||
if (mins < 10)
|
|
||||||
mins += 15;
|
|
||||||
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
|
|
||||||
|
|
||||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(startAt).
|
|
||||||
WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(15));
|
|
||||||
|
|
||||||
this.ScheduleTask(triggerBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ExecuteTask()
|
|
||||||
{
|
|
||||||
CleanStaleCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,169 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.DirectoryServices;
|
|
||||||
using System.DirectoryServices.ActiveDirectory;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
internal static class ActiveDirectoryHelpers
|
|
||||||
{
|
|
||||||
#region Static Cached Properties
|
|
||||||
private static string _DefaultDomainName;
|
|
||||||
private static string _DefaultDomainPDCName;
|
|
||||||
private static System.Collections.Generic.List<string> _DefaultDomainDCNames;
|
|
||||||
private static string _DefaultDomainNetBiosName;
|
|
||||||
private static string _DefaultDomainQualifiedName;
|
|
||||||
private static string _DefaultLdapPath;
|
|
||||||
private static bool _DetermineDomainProperties_Loaded = false;
|
|
||||||
private static object _DetermineDomainProperties_Lock = new object();
|
|
||||||
internal static string DefaultDomainName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
|
||||||
return ActiveDirectoryHelpers._DefaultDomainName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static string DefaultDomainPDCName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
|
||||||
return ActiveDirectoryHelpers._DefaultDomainPDCName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static System.Collections.Generic.List<string> DefaultDomainDCNames
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
|
||||||
return ActiveDirectoryHelpers._DefaultDomainDCNames;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static string DefaultDomainNetBiosName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
|
||||||
return ActiveDirectoryHelpers._DefaultDomainNetBiosName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static string DefaultDomainQualifiedName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
|
||||||
return ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static string DefaultLdapPath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
|
||||||
return ActiveDirectoryHelpers._DefaultLdapPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static string DefaultDCLdapPath(string DC)
|
|
||||||
{
|
|
||||||
return string.Format("LDAP://{0}/", DC);
|
|
||||||
}
|
|
||||||
internal static DirectoryEntry DefaultLdapRoot
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal static DirectoryEntry DefaultDCLdapRoot(string DC)
|
|
||||||
{
|
|
||||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultDCLdapPath(DC), ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DetermineDomainProperties()
|
|
||||||
{
|
|
||||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
|
||||||
{
|
|
||||||
lock (ActiveDirectoryHelpers._DetermineDomainProperties_Lock)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
|
||||||
{
|
|
||||||
using (Domain domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain)))
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainName = domain.Name;
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainPDCName = domain.PdcRoleOwner.Name;
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainDCNames = new System.Collections.Generic.List<string>(domain.DomainControllers.Count);
|
|
||||||
foreach (DomainController dc in domain.DomainControllers)
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainDCNames.Add(dc.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainQualifiedName = string.Format("DC={0}", ActiveDirectoryHelpers._DefaultDomainName.Replace(".", ",DC="));
|
|
||||||
ActiveDirectoryHelpers._DefaultLdapPath = string.Format("LDAP://{0}/", ActiveDirectoryHelpers._DefaultDomainPDCName);
|
|
||||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("{0}CN=Partitions,CN=Configuration,{1}", ActiveDirectoryHelpers._DefaultLdapPath, ActiveDirectoryHelpers._DefaultDomainQualifiedName)))
|
|
||||||
{
|
|
||||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectClass=crossRef)(nETBIOSName=*))", new string[] { "nETBIOSName" }))
|
|
||||||
{
|
|
||||||
SearchResult result = searcher.FindOne();
|
|
||||||
if (result != null)
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = result.Properties["nETBIOSName"][0].ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveDirectoryHelpers._DetermineDomainProperties_Loaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
[System.Runtime.InteropServices.DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
||||||
private static extern bool ConvertSidToStringSid(byte[] pSID, ref System.Text.StringBuilder ptrSid);
|
|
||||||
internal static string ConvertBytesToSIDString(byte[] SID)
|
|
||||||
{
|
|
||||||
System.Text.StringBuilder sidString = new System.Text.StringBuilder();
|
|
||||||
bool flag = ActiveDirectoryHelpers.ConvertSidToStringSid(SID, ref sidString);
|
|
||||||
string ConvertBytesToSIDString;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
ConvertBytesToSIDString = sidString.ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ConvertBytesToSIDString = null;
|
|
||||||
}
|
|
||||||
return ConvertBytesToSIDString;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string EscapeLdapQuery(string query)
|
|
||||||
{
|
|
||||||
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
|
|
||||||
}
|
|
||||||
internal static string FormatGuidForLdapQuery(System.Guid g)
|
|
||||||
{
|
|
||||||
checked
|
|
||||||
{
|
|
||||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
|
||||||
byte[] array = g.ToByteArray();
|
|
||||||
for (int i = 0; i < array.Length; i++)
|
|
||||||
{
|
|
||||||
byte b = array[i];
|
|
||||||
sb.Append("\\");
|
|
||||||
sb.Append(b.ToString("X2"));
|
|
||||||
}
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
using Disco.Models.Interop.ActiveDirectory;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.DirectoryServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Management;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
public static class ActiveDirectoryMachineAccountExtensions
|
|
||||||
{
|
|
||||||
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
|
|
||||||
{
|
|
||||||
if (account.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
|
||||||
{
|
|
||||||
DeleteAccountRecursive(machineDE);
|
|
||||||
|
|
||||||
using (var machineDEParent = machineDE.Parent)
|
|
||||||
{
|
|
||||||
machineDEParent.Children.Remove(machineDE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static void DeleteAccountRecursive(DirectoryEntry parent)
|
|
||||||
{
|
|
||||||
List<DirectoryEntry> children = new List<DirectoryEntry>();
|
|
||||||
foreach (DirectoryEntry child in parent.Children)
|
|
||||||
children.Add(child);
|
|
||||||
|
|
||||||
foreach (var child in children)
|
|
||||||
{
|
|
||||||
DeleteAccountRecursive(child);
|
|
||||||
parent.Children.Remove(child);
|
|
||||||
child.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, System.Guid updatedNetbootGUID)
|
|
||||||
{
|
|
||||||
if (account.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
|
||||||
{
|
|
||||||
PropertyValueCollection netbootGUIDProp = machineDE.Properties["netbootGUID"];
|
|
||||||
bool flag = netbootGUIDProp.Count > 0;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
netbootGUIDProp.Clear();
|
|
||||||
}
|
|
||||||
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
|
|
||||||
machineDE.CommitChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
|
|
||||||
{
|
|
||||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
|
||||||
{
|
|
||||||
PropertyValueCollection descriptionProp = machineDE.Properties["description"];
|
|
||||||
if (descriptionProp.Count > 0)
|
|
||||||
{
|
|
||||||
descriptionProp.Clear();
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(Description))
|
|
||||||
{
|
|
||||||
descriptionProp.Add(Description);
|
|
||||||
}
|
|
||||||
machineDE.CommitChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
|
|
||||||
{
|
|
||||||
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
|
|
||||||
|
|
||||||
if (Device.AssignedUserId != null)
|
|
||||||
{
|
|
||||||
descriptionBuilder.Append(Device.AssignedUser.Id).Append(" (").Append(Device.AssignedUser.DisplayName).Append("); ");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Device.DeviceModelId.HasValue)
|
|
||||||
{
|
|
||||||
descriptionBuilder.Append(Device.DeviceModel.Description).Append("; ");
|
|
||||||
}
|
|
||||||
|
|
||||||
descriptionBuilder.Append(Device.DeviceProfile.Description).Append(";");
|
|
||||||
|
|
||||||
string description = descriptionBuilder.ToString().Trim();
|
|
||||||
if (description.Length > 1024)
|
|
||||||
{
|
|
||||||
description = description.Substring(0, 1024);
|
|
||||||
}
|
|
||||||
account.SetDescription(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
|
|
||||||
{
|
|
||||||
if (account.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
|
||||||
{
|
|
||||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
|
||||||
int updatedAccountControl = (accountControl | 2);
|
|
||||||
if (accountControl != updatedAccountControl)
|
|
||||||
{
|
|
||||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
|
||||||
machineDE.CommitChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
|
|
||||||
{
|
|
||||||
if (account.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
|
||||||
{
|
|
||||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
|
||||||
if ((accountControl & 2) == 2)
|
|
||||||
{
|
|
||||||
int updatedAccountControl = (accountControl ^ 2);
|
|
||||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
|
||||||
machineDE.CommitChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress)
|
|
||||||
{
|
|
||||||
if (account.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
System.Guid netbootGUID = System.Guid.Empty;
|
|
||||||
bool flag = !string.IsNullOrWhiteSpace(UUID);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(UUID);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
flag = !string.IsNullOrWhiteSpace(MACAddress);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(MACAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
flag = (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID);
|
|
||||||
bool UpdateNetbootGUID;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
account.SetNetbootGUID(netbootGUID);
|
|
||||||
UpdateNetbootGUID = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UpdateNetbootGUID = false;
|
|
||||||
}
|
|
||||||
return UpdateNetbootGUID;
|
|
||||||
}
|
|
||||||
internal static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
|
|
||||||
{
|
|
||||||
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
|
|
||||||
bool flag = strippedMACAddress.Length == 12;
|
|
||||||
System.Guid NetbootGUIDFromMACAddress;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
|
|
||||||
NetbootGUIDFromMACAddress = guid;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NetbootGUIDFromMACAddress = System.Guid.Empty;
|
|
||||||
}
|
|
||||||
return NetbootGUIDFromMACAddress;
|
|
||||||
}
|
|
||||||
internal static System.Guid NetbootGUIDFromUUID(string UUID)
|
|
||||||
{
|
|
||||||
System.Guid result = new System.Guid(UUID);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object GetPropertyValue(this ActiveDirectoryMachineAccount account, string PropertyName, int Index = 0)
|
|
||||||
{
|
|
||||||
switch (PropertyName.ToLower())
|
|
||||||
{
|
|
||||||
case "name":
|
|
||||||
return account.Name;
|
|
||||||
case "samaccountname":
|
|
||||||
return account.sAMAccountName;
|
|
||||||
case "distinguishedname":
|
|
||||||
return account.DistinguishedName;
|
|
||||||
case "objectsid":
|
|
||||||
return account.ObjectSid;
|
|
||||||
case "netbootguid":
|
|
||||||
return account.NetbootGUID;
|
|
||||||
default:
|
|
||||||
object[] adProperty;
|
|
||||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
|
||||||
return adProperty[Index];
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IPStatus PingComputer(this ActiveDirectoryMachineAccount account, int Timeout = 2000)
|
|
||||||
{
|
|
||||||
using (var p = new Ping())
|
|
||||||
{
|
|
||||||
PingReply reply = p.Send(account.DnsName, Timeout);
|
|
||||||
return reply.Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Didn't Work - WMI Limitation?
|
|
||||||
// G# - 2012-06-18
|
|
||||||
//public static void OnlineRenameComputer(this ActiveDirectoryMachineAccount account, string NewComputerName)
|
|
||||||
//{
|
|
||||||
// if (account.IsCriticalSystemObject)
|
|
||||||
// throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// IPStatus pingResult = account.PingComputer();
|
|
||||||
// if (pingResult != IPStatus.Success)
|
|
||||||
// throw new Exception(string.Format("Ping Error Result: {0}", pingResult.ToString()));
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// throw new Exception(string.Format("Error trying to Ping the Device: {0}; {1}", account.DnsName, ex.Message), ex);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ConnectionOptions wmiConnectionOptions = new ConnectionOptions()
|
|
||||||
// {
|
|
||||||
// Authentication = AuthenticationLevel.PacketPrivacy,
|
|
||||||
// Impersonation = ImpersonationLevel.Impersonate,
|
|
||||||
// EnablePrivileges = true,
|
|
||||||
// Timeout = new TimeSpan(0, 0, 6)
|
|
||||||
// };
|
|
||||||
// ManagementPath wmiPath = new ManagementPath()
|
|
||||||
// {
|
|
||||||
// Server = account.DnsName,
|
|
||||||
// NamespacePath = @"root\cimv2",
|
|
||||||
// ClassName = "Win32_ComputerSystem"
|
|
||||||
// };
|
|
||||||
|
|
||||||
// ManagementScope wmiScope = new ManagementScope(wmiPath, wmiConnectionOptions);
|
|
||||||
|
|
||||||
// ObjectGetOptions wmiGetOptions = new ObjectGetOptions() { Timeout = new TimeSpan(0, 1, 0) };
|
|
||||||
|
|
||||||
// using (ManagementClass wmiClass = new ManagementClass(wmiScope, wmiPath, wmiGetOptions))
|
|
||||||
// {
|
|
||||||
// foreach (ManagementObject wmiWin32ComputerSystem in wmiClass.GetInstances())
|
|
||||||
// {
|
|
||||||
// UInt32 result = (UInt32)wmiWin32ComputerSystem.InvokeMethod("Rename", new object[] { NewComputerName });
|
|
||||||
// if (result != 0)
|
|
||||||
// throw new Exception(string.Format("Error Renaming Computer; WMI Remote Method 'Rename' returned: {0}", result));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public static void MoveOrganisationUnit(this ActiveDirectoryMachineAccount account, string NewOrganisationUnit)
|
|
||||||
{
|
|
||||||
if (account.IsCriticalSystemObject)
|
|
||||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
|
||||||
|
|
||||||
if (!account.ParentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.InvariantCultureIgnoreCase))
|
|
||||||
{
|
|
||||||
string ouPath;
|
|
||||||
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
|
|
||||||
ouPath = string.Format("{0}CN=Computers,{1}", ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
|
||||||
else
|
|
||||||
ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, NewOrganisationUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
|
||||||
|
|
||||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
|
||||||
{
|
|
||||||
using (DirectoryEntry i = new DirectoryEntry(account.Path) { UsePropertyCache = false })
|
|
||||||
{
|
|
||||||
i.MoveTo(ou);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
public class ActiveDirectoryOrganisationalUnit
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string Path { get; set; }
|
|
||||||
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Services.Logging;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Quartz;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.DirectoryServices;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Net.NetworkInformation;
|
|
||||||
using System.Reflection;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
public class ActiveDirectoryUpdateLastNetworkLogonDateJob : ScheduledTask
|
|
||||||
{
|
|
||||||
|
|
||||||
public override string TaskName { get { return "Active Directory - Update Last Network Logon Dates Task"; } }
|
|
||||||
public override bool SingleInstanceTask { get { return true; } }
|
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
|
||||||
|
|
||||||
public override void InitalizeScheduledTask(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// ActiveDirectoryUpdateLastNetworkLogonDateJob @ 11:30pm
|
|
||||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
|
||||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
|
|
||||||
|
|
||||||
this.ScheduleTask(triggerBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ExecuteTask()
|
|
||||||
{
|
|
||||||
int changeCount;
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(1, "Starting", "Connecting to the Database and initializing the environment");
|
|
||||||
using (DiscoDataContext dbContext = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
UpdateLastNetworkLogonDates(dbContext, this.Status);
|
|
||||||
this.Status.UpdateStatus(95, "Updating Database", "Writing last network logon dates to the Database");
|
|
||||||
changeCount = dbContext.SaveChanges();
|
|
||||||
this.Status.Finished(string.Format("{0} Device last network logon dates updated", changeCount), "/Config/SystemConfig");
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemLog.LogInformation(new string[]
|
|
||||||
{
|
|
||||||
"Updated LastNetworkLogon Device Property for Device/s",
|
|
||||||
changeCount.ToString()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScheduledTaskStatus ScheduleImmediately()
|
|
||||||
{
|
|
||||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ActiveDirectoryUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault();
|
|
||||||
if (existingTask != null)
|
|
||||||
return existingTask;
|
|
||||||
|
|
||||||
var instance = new ActiveDirectoryUpdateLastNetworkLogonDateJob();
|
|
||||||
return instance.ScheduleTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool UpdateLastNetworkLogonDate(Device Device)
|
|
||||||
{
|
|
||||||
System.DateTime? computerLastLogonDate = Device.LastNetworkLogonDate;
|
|
||||||
if (!string.IsNullOrEmpty(Device.ComputerName))
|
|
||||||
{
|
|
||||||
foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Ping p = new Ping();
|
|
||||||
PingReply pr;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pr = p.Send(dcName, 500);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (p != null)
|
|
||||||
{
|
|
||||||
((System.IDisposable)p).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pr.Status == IPStatus.Success)
|
|
||||||
{
|
|
||||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
|
|
||||||
{
|
|
||||||
DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(sAMAccountName={0}$))", ActiveDirectoryHelpers.EscapeLdapQuery(Device.ComputerName)), new string[]
|
|
||||||
{
|
|
||||||
"lastLogon"
|
|
||||||
}, SearchScope.Subtree);
|
|
||||||
SearchResult dResult = dSearcher.FindOne();
|
|
||||||
if (dResult != null)
|
|
||||||
{
|
|
||||||
ResultPropertyValueCollection dProp = dResult.Properties["lastLogon"];
|
|
||||||
if (dProp != null && dProp.Count > 0)
|
|
||||||
{
|
|
||||||
long lastLogonInt = (long)dProp[0];
|
|
||||||
if (lastLogonInt > 0L)
|
|
||||||
{
|
|
||||||
System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
|
|
||||||
if (computerLastLogonDate.HasValue)
|
|
||||||
{
|
|
||||||
if (System.DateTime.Compare(computerLastLogonDate.Value, computerNameDate) < 0)
|
|
||||||
{
|
|
||||||
computerLastLogonDate = computerNameDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
computerLastLogonDate = computerNameDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SystemLog.LogError(new string[]
|
|
||||||
{
|
|
||||||
string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateDeviceLastNetworkLogonDate)", dcName)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
SystemLog.LogException("UpdateDeviceLastNetworkLogonDate", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool UpdateLastNetworkLogonDate;
|
|
||||||
if (computerLastLogonDate.HasValue)
|
|
||||||
{
|
|
||||||
if (!Device.LastNetworkLogonDate.HasValue)
|
|
||||||
{
|
|
||||||
Device.LastNetworkLogonDate = computerLastLogonDate;
|
|
||||||
UpdateLastNetworkLogonDate = true;
|
|
||||||
return UpdateLastNetworkLogonDate;
|
|
||||||
}
|
|
||||||
if (System.DateTime.Compare(computerLastLogonDate.Value, Device.LastNetworkLogonDate.Value) > 0)
|
|
||||||
{
|
|
||||||
Device.LastNetworkLogonDate = computerLastLogonDate;
|
|
||||||
UpdateLastNetworkLogonDate = true;
|
|
||||||
return UpdateLastNetworkLogonDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UpdateLastNetworkLogonDate = false;
|
|
||||||
return UpdateLastNetworkLogonDate;
|
|
||||||
}
|
|
||||||
private static void UpdateLastNetworkLogonDates(DiscoDataContext context, ScheduledTaskStatus status)
|
|
||||||
{
|
|
||||||
System.Collections.Generic.Dictionary<string, System.DateTime> computerLastLogonDates = new System.Collections.Generic.Dictionary<string, System.DateTime>();
|
|
||||||
|
|
||||||
int progressDCCountTotal = ActiveDirectoryHelpers.DefaultDomainDCNames.Count;
|
|
||||||
int progressDCCount = 0;
|
|
||||||
double progressDCProgress = 0;
|
|
||||||
if (progressDCCountTotal > 0)
|
|
||||||
progressDCProgress = 90 / progressDCCountTotal;
|
|
||||||
|
|
||||||
foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PingReply pr;
|
|
||||||
using (Ping p = new Ping())
|
|
||||||
{
|
|
||||||
pr = p.Send(dcName, 2000);
|
|
||||||
}
|
|
||||||
if (pr.Status == IPStatus.Success)
|
|
||||||
{
|
|
||||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
|
|
||||||
{
|
|
||||||
double progressDCStart = 5 + (progressDCCount * progressDCProgress);
|
|
||||||
status.UpdateStatus(progressDCStart, string.Format("Querying Domain Controller: {0}", dcName), "Searching...");
|
|
||||||
|
|
||||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, "(objectClass=computer)", new string[] { "sAMAccountName", "lastLogon" }, SearchScope.Subtree))
|
|
||||||
{
|
|
||||||
using (SearchResultCollection dResults = dSearcher.FindAll())
|
|
||||||
{
|
|
||||||
|
|
||||||
int progressItemCount = 0;
|
|
||||||
double progressItemProgress = dResults.Count == 0 ? 0 : (progressDCProgress / dResults.Count);
|
|
||||||
|
|
||||||
foreach (SearchResult dResult in dResults)
|
|
||||||
{
|
|
||||||
ResultPropertyValueCollection dProp = dResult.Properties["sAMAccountName"];
|
|
||||||
if (dProp != null && dProp.Count > 0)
|
|
||||||
{
|
|
||||||
string computerName = ((string)dProp[0]).TrimEnd(new char[] { '$' }).ToUpper();
|
|
||||||
|
|
||||||
if (progressItemCount % 150 == 0) // Only Update Status every 150 devices
|
|
||||||
status.UpdateStatus(progressDCStart + (progressItemProgress * progressItemCount), string.Format("Analysing Device: {0}", computerName));
|
|
||||||
|
|
||||||
dProp = dResult.Properties["lastLogon"];
|
|
||||||
if (dProp != null && dProp.Count > 0)
|
|
||||||
{
|
|
||||||
long lastLogonInt = (long)dProp[0];
|
|
||||||
if (lastLogonInt > 0L)
|
|
||||||
{
|
|
||||||
System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
|
|
||||||
System.DateTime existingDate;
|
|
||||||
if (computerLastLogonDates.TryGetValue(computerName, out existingDate))
|
|
||||||
{
|
|
||||||
if (System.DateTime.Compare(existingDate, computerNameDate) < 0)
|
|
||||||
{
|
|
||||||
computerLastLogonDates[computerName] = computerNameDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
computerLastLogonDates[computerName] = computerNameDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
progressItemCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SystemLog.LogError(new string[]
|
|
||||||
{
|
|
||||||
string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDates)", dcName)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
SystemLog.LogException("UpdateLastNetworkLogonDates", ex);
|
|
||||||
}
|
|
||||||
progressDCCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach (Device d in context.Devices.Where(device => device.ComputerName != null))
|
|
||||||
{
|
|
||||||
DateTime computerLastLogonDate;
|
|
||||||
if (computerLastLogonDates.TryGetValue(d.ComputerName.ToUpper(), out computerLastLogonDate))
|
|
||||||
{
|
|
||||||
if (d.LastNetworkLogonDate.HasValue)
|
|
||||||
{
|
|
||||||
// Change accuracy to the second
|
|
||||||
computerLastLogonDate = new DateTime((computerLastLogonDate.Ticks / 10000000L) * 10000000L);
|
|
||||||
|
|
||||||
if (System.DateTime.Compare(d.LastNetworkLogonDate.Value, computerLastLogonDate) < 0)
|
|
||||||
{
|
|
||||||
d.LastNetworkLogonDate = computerLastLogonDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
d.LastNetworkLogonDate = computerLastLogonDate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using Disco.Models.Interop.ActiveDirectory;
|
|
||||||
using System;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
namespace Disco.BI.Interop.ActiveDirectory
|
|
||||||
{
|
|
||||||
internal static class ActiveDirectoryUserAccountExtensions
|
|
||||||
{
|
|
||||||
public static bool HasRole(this ActiveDirectoryUserAccount account, string Role)
|
|
||||||
{
|
|
||||||
return account.Groups != null && account.Groups.Contains(Role.ToLower());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static object GetPropertyValue(this ActiveDirectoryUserAccount account, string PropertyName, int Index = 0)
|
|
||||||
{
|
|
||||||
switch (PropertyName.ToLower())
|
|
||||||
{
|
|
||||||
case "name":
|
|
||||||
return account.Name;
|
|
||||||
case "samaccountname":
|
|
||||||
return account.sAMAccountName;
|
|
||||||
case "distinguishedname":
|
|
||||||
return account.DistinguishedName;
|
|
||||||
case "objectsid":
|
|
||||||
return account.ObjectSid;
|
|
||||||
case "sn":
|
|
||||||
return account.Surname;
|
|
||||||
case "givenname":
|
|
||||||
return account.GivenName;
|
|
||||||
case "mail":
|
|
||||||
return account.Email;
|
|
||||||
case "telephonenumber":
|
|
||||||
return account.Phone;
|
|
||||||
default:
|
|
||||||
object[] adProperty;
|
|
||||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
|
||||||
return adProperty[Index];
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using System.Xml.Serialization;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Interop.Community;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.Community
|
|
||||||
{
|
|
||||||
public static class UpdateCheck
|
|
||||||
{
|
|
||||||
private static string UpdateUrl()
|
|
||||||
{
|
|
||||||
return string.Concat(Disco.Data.Configuration.CommunityHelpers.CommunityUrl(), "DiscoUpdate/V1");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Version CurrentDiscoVersion()
|
|
||||||
{
|
|
||||||
return typeof(UpdateCheck).Assembly.GetName().Version;
|
|
||||||
}
|
|
||||||
public static string CurrentDiscoVersionFormatted()
|
|
||||||
{
|
|
||||||
var v = CurrentDiscoVersion();
|
|
||||||
return string.Format("{0}.{1}.{2:0000}.{3:0000}", v.Major, v.Minor, v.Build, v.Revision);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UpdateResponse Check(DiscoDataContext db, bool UseProxy, ScheduledTaskStatus status = null)
|
|
||||||
{
|
|
||||||
if (status != null)
|
|
||||||
status.UpdateStatus(10, "Building Update Request");
|
|
||||||
|
|
||||||
var request = BuildRequest(db);
|
|
||||||
//var requestJson = JsonConvert.SerializeObject(request);
|
|
||||||
|
|
||||||
if (status != null)
|
|
||||||
status.UpdateStatus(40, "Sending Request");
|
|
||||||
|
|
||||||
var DiscoBIVersion = CurrentDiscoVersionFormatted();
|
|
||||||
|
|
||||||
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(UpdateUrl());
|
|
||||||
|
|
||||||
// Added: 2013-02-08 G#
|
|
||||||
// Fix for Proxy Servers which dont support KeepAlive
|
|
||||||
webRequest.KeepAlive = false;
|
|
||||||
// End Added: 2013-02-08 G#
|
|
||||||
|
|
||||||
if (!UseProxy)
|
|
||||||
webRequest.Proxy = new WebProxy();
|
|
||||||
|
|
||||||
webRequest.ContentType = "application/json";
|
|
||||||
webRequest.Method = WebRequestMethods.Http.Post;
|
|
||||||
webRequest.UserAgent = string.Format("Disco/{0} (Update)", DiscoBIVersion);
|
|
||||||
|
|
||||||
using (var wrStream = webRequest.GetRequestStream())
|
|
||||||
{
|
|
||||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateRequestV1));
|
|
||||||
xml.Serialize(wrStream, request);
|
|
||||||
}
|
|
||||||
if (status != null)
|
|
||||||
status.UpdateStatus(50, "Waiting for Response");
|
|
||||||
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
|
|
||||||
{
|
|
||||||
if (webResponse.StatusCode == HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
if (status != null)
|
|
||||||
status.UpdateStatus(90, "Reading Response");
|
|
||||||
UpdateResponse result;
|
|
||||||
using (var wResStream = webResponse.GetResponseStream())
|
|
||||||
{
|
|
||||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateResponse));
|
|
||||||
result = (UpdateResponse)xml.Deserialize(wResStream);
|
|
||||||
}
|
|
||||||
//var result = JsonConvert.DeserializeObject<UpdateResponse>(responseContent);
|
|
||||||
db.DiscoConfiguration.UpdateLastCheck = result;
|
|
||||||
db.SaveChanges();
|
|
||||||
|
|
||||||
status.SetFinishedMessage(string.Format("The update server reported Version {0} is the latest.", result.Version));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (status != null)
|
|
||||||
status.SetTaskException(new WebException(string.Format("Server responded with: [{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription)));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UpdateRequestV1 BuildRequest(DiscoDataContext db)
|
|
||||||
{
|
|
||||||
var m = new UpdateRequestV1();
|
|
||||||
|
|
||||||
m.DeploymentId = db.DiscoConfiguration.DeploymentId;
|
|
||||||
|
|
||||||
m.CurrentDiscoVersion = CurrentDiscoVersionFormatted();
|
|
||||||
|
|
||||||
m.OrganisationName = db.DiscoConfiguration.OrganisationName;
|
|
||||||
m.BroadbandDoeWanId = GetBroadbandDoeWanId();
|
|
||||||
m.BetaDeployment = db.DiscoConfiguration.UpdateBetaDeployment;
|
|
||||||
|
|
||||||
m.Stat_JobCounts = db.Jobs.GroupBy(j => j.JobTypeId).Select(g => new Disco.Models.BI.Interop.Community.UpdateRequestV1.Stat { Key = g.Key, Count = g.Count() }).ToList();
|
|
||||||
m.Stat_OpenJobCounts = db.Jobs.Where(j => j.ClosedDate == null).GroupBy(j => j.JobTypeId).Select(g => new Disco.Models.BI.Interop.Community.UpdateRequestV1.Stat { Key = g.Key, Count = g.Count() }).ToList();
|
|
||||||
var activeThreshold = DateTime.Now.AddDays(-60);
|
|
||||||
m.Stat_ActiveDeviceModelCounts = db.DeviceModels.Select(dm => new Disco.Models.BI.Interop.Community.UpdateRequestV1.Stat { Key = dm.Manufacturer + ";" + dm.Model, Count = dm.Devices.Count(d => d.DecommissionedDate == null && (d.LastNetworkLogonDate == null || d.LastNetworkLogonDate > activeThreshold)) }).ToList();
|
|
||||||
m.Stat_UserCounts = db.Users.GroupBy(u => u.Type).Select(g => new Disco.Models.BI.Interop.Community.UpdateRequestV1.Stat { Key = g.Key, Count = g.Count() }).ToList();
|
|
||||||
|
|
||||||
m.InstalledPlugins = Disco.Services.Plugins.Plugins.GetPlugins().Select(manifest => new Disco.Models.BI.Interop.Community.UpdateRequestV1.PluginRef { Id = manifest.Id, Version = manifest.VersionFormatted }).ToList();
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region DoE Query
|
|
||||||
public static string GetBroadbandDoeWanId()
|
|
||||||
{
|
|
||||||
// DnsQuery for broadband.doe.wan
|
|
||||||
IPHostEntry doeWanDnsEntry;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
doeWanDnsEntry = Dns.GetHostEntry("broadband.doe.wan");
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{ return null; } // Fail on error
|
|
||||||
|
|
||||||
// Try using IPSearch feature
|
|
||||||
XDocument doeWanIPSearchResult = TryDownloadDoeIPSearch(false);
|
|
||||||
if (doeWanIPSearchResult == null)
|
|
||||||
doeWanIPSearchResult = TryDownloadDoeIPSearch(true);
|
|
||||||
|
|
||||||
if (doeWanIPSearchResult == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return doeWanIPSearchResult.Element("resultset").Element("site").Element("number").Value.ToLower();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{ return null; } // Fail on error
|
|
||||||
}
|
|
||||||
private static XDocument TryDownloadDoeIPSearch(bool useProxy)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var DiscoBIVersion = CurrentDiscoVersionFormatted();
|
|
||||||
|
|
||||||
HttpWebRequest wReq = (HttpWebRequest)HttpWebRequest.Create("http://broadband.doe.wan/ipsearch/showresult.php");
|
|
||||||
// Added: 2013-02-08 G#
|
|
||||||
// Fix for Proxy Servers which dont support KeepAlive
|
|
||||||
wReq.KeepAlive = false;
|
|
||||||
// End Added: 2013-02-08 G#
|
|
||||||
if (!useProxy)
|
|
||||||
wReq.Proxy = new WebProxy(); // Empty Proxy Config
|
|
||||||
wReq.Method = WebRequestMethods.Http.Post;
|
|
||||||
wReq.ContentType = "application/x-www-form-urlencoded";
|
|
||||||
wReq.UserAgent = string.Format("Disco/{0}", DiscoBIVersion);
|
|
||||||
using (var wrStream = wReq.GetRequestStream())
|
|
||||||
{
|
|
||||||
using (var wrStreamWriter = new StreamWriter(wrStream))
|
|
||||||
{
|
|
||||||
wrStreamWriter.Write("mode=whoami");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
using (HttpWebResponse wRes = (HttpWebResponse)wReq.GetResponse())
|
|
||||||
{
|
|
||||||
if (wRes.StatusCode == HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
using (var wResStream = wRes.GetResponseStream())
|
|
||||||
{
|
|
||||||
return XDocument.Load(wResStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{ return null; } // Fail on error
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +1,36 @@
|
|||||||
using System;
|
using Disco.BI.Extensions;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
using Disco.Data.Repository;
|
||||||
using Disco.Models.BI.DocumentTemplates;
|
using Disco.Models.Repository;
|
||||||
using System.IO;
|
using Disco.Models.Services.Documents;
|
||||||
|
using Disco.Models.Services.Expressions.Extensions;
|
||||||
|
using Disco.Services;
|
||||||
|
using Disco.Services.Documents;
|
||||||
|
using Disco.Services.Expressions;
|
||||||
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
|
using Disco.Services.Tasks;
|
||||||
|
using Disco.Services.Users;
|
||||||
using iTextSharp.text.pdf;
|
using iTextSharp.text.pdf;
|
||||||
using System.Collections.Concurrent;
|
using iTextSharp.text.pdf.codec;
|
||||||
using Disco.BI.Expressions;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using Disco.BI.Extensions;
|
using System.Collections.Generic;
|
||||||
using Disco.Models.BI.Expressions;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Disco.BI.Interop.Pdf
|
namespace Disco.BI.Interop.Pdf
|
||||||
{
|
{
|
||||||
public static class PdfGenerator
|
public static class PdfGenerator
|
||||||
{
|
{
|
||||||
|
public static Stream GenerateBulkFromPackage(DocumentTemplatePackage package, DiscoDataContext database, User creatorUser, DateTime timestamp, bool? insertBlankPages, List<IAttachmentTarget> dataObjects)
|
||||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
|
|
||||||
{
|
{
|
||||||
if (DataObjects.Length > 0)
|
if (dataObjects.Count > 0)
|
||||||
{
|
{
|
||||||
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length);
|
List<Stream> generatedPdfs = new List<Stream>(dataObjects.Count);
|
||||||
using (Models.BI.DocumentTemplates.DocumentState state = Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
using (var state = DocumentState.DefaultState())
|
||||||
{
|
{
|
||||||
foreach (object d in DataObjects)
|
foreach (var d in dataObjects)
|
||||||
{
|
{
|
||||||
generatedPdfs.Add(dt.GeneratePdf(dbContext, d, CreatorUser, Timestamp, state, true));
|
generatedPdfs.Add(package.GeneratePdfPackage(database, d, creatorUser, timestamp, state));
|
||||||
state.SequenceNumber++;
|
state.SequenceNumber++;
|
||||||
state.FlushScopeCache();
|
state.FlushScopeCache();
|
||||||
}
|
}
|
||||||
@@ -38,7 +41,7 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Stream bulkPdf = DocumentTemplateBI.Utilities.JoinPdfs(generatedPdfs.ToArray());
|
Stream bulkPdf = Utilities.JoinPdfs(insertBlankPages.GetValueOrDefault(package.InsertBlankPages), generatedPdfs);
|
||||||
foreach (Stream singlePdf in generatedPdfs)
|
foreach (Stream singlePdf in generatedPdfs)
|
||||||
singlePdf.Dispose();
|
singlePdf.Dispose();
|
||||||
return bulkPdf;
|
return bulkPdf;
|
||||||
@@ -47,36 +50,164 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params string[] DataObjectsIds)
|
public static Stream GenerateBulkFromPackage(DocumentTemplatePackage package, DiscoDataContext database, User creatorUser, DateTime timestamp, bool? insertBlankPages, List<string> dataObjectsIds)
|
||||||
{
|
{
|
||||||
object[] DataObjects;
|
List<IAttachmentTarget> DataObjects;
|
||||||
|
|
||||||
switch (dt.Scope)
|
switch (package.Scope)
|
||||||
{
|
{
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
case AttachmentTypes.Device:
|
||||||
DataObjects = dbContext.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).ToArray();
|
DataObjects = database.Devices.Where(d => dataObjectsIds.Contains(d.SerialNumber)).ToList<IAttachmentTarget>();
|
||||||
break;
|
break;
|
||||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
case AttachmentTypes.Job:
|
||||||
int[] intDataObjectsIds = DataObjectsIds.Select(i => int.Parse(i)).ToArray();
|
int[] intDataObjectsIds = dataObjectsIds.Select(i => int.Parse(i)).ToArray();
|
||||||
DataObjects = dbContext.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToArray();
|
DataObjects = database.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToList<IAttachmentTarget>();
|
||||||
break;
|
break;
|
||||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
case AttachmentTypes.User:
|
||||||
DataObjects = new object[DataObjectsIds.Length];
|
DataObjects = new List<IAttachmentTarget>(dataObjectsIds.Count);
|
||||||
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
for (int idIndex = 0; idIndex < dataObjectsIds.Count; idIndex++)
|
||||||
{
|
{
|
||||||
DataObjects[idIndex] = UserBI.UserCache.GetUser(DataObjectsIds[idIndex], dbContext, true);
|
string dataObjectId = dataObjectsIds[idIndex];
|
||||||
if (DataObjects[idIndex] == null)
|
var user = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(dataObjectId), database, true);
|
||||||
throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex]));
|
if (user == null)
|
||||||
|
throw new Exception($"Unknown Username specified: {dataObjectId}");
|
||||||
|
DataObjects.Add(user);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException("Invalid DocumentType Scope");
|
throw new InvalidOperationException("Invalid DocumentType Scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
return GenerateBulkFromTemplate(dt, dbContext, CreatorUser, Timestamp, DataObjects);
|
return GenerateBulkFromPackage(package, database, creatorUser, timestamp, insertBlankPages, DataObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static System.IO.Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, object Data, User CreatorUser, System.DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
public static Stream GenerateFromPackage(DocumentTemplatePackage package, DiscoDataContext database, IAttachmentTarget data, User creatorUser, DateTime timestamp, DocumentState state)
|
||||||
|
{
|
||||||
|
var templates = package.GetDocumentTemplates(database);
|
||||||
|
|
||||||
|
if (templates.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
bool generateExpression = !string.IsNullOrEmpty(package.OnGenerateExpression);
|
||||||
|
string generateExpressionResult = null;
|
||||||
|
|
||||||
|
if (generateExpression)
|
||||||
|
generateExpressionResult = package.EvaluateOnGenerateExpression(data, database, creatorUser, timestamp, state);
|
||||||
|
|
||||||
|
List<Stream> generatedPdfs = new List<Stream>(templates.Count);
|
||||||
|
foreach (var template in templates)
|
||||||
|
{
|
||||||
|
generatedPdfs.Add(template.GeneratePdf(database, data, creatorUser, timestamp, state, true));
|
||||||
|
|
||||||
|
state.SequenceNumber++;
|
||||||
|
state.FlushScopeCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generateExpression)
|
||||||
|
DocumentsLog.LogDocumentPackageGenerated(package, data, creatorUser, generateExpressionResult);
|
||||||
|
else
|
||||||
|
DocumentsLog.LogDocumentPackageGenerated(package, data, creatorUser);
|
||||||
|
|
||||||
|
if (generatedPdfs.Count == 1)
|
||||||
|
{
|
||||||
|
return generatedPdfs[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Stream bulkPdf = Utilities.JoinPdfs(package.InsertBlankPages, generatedPdfs);
|
||||||
|
foreach (Stream singlePdf in generatedPdfs)
|
||||||
|
singlePdf.Dispose();
|
||||||
|
return bulkPdf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext database, User creatorUser, DateTime timestamp, bool insertBlankPages, List<IAttachmentTarget> dataObjects, IScheduledTaskStatus taskStatus)
|
||||||
|
{
|
||||||
|
if (dataObjects.Count > 0)
|
||||||
|
{
|
||||||
|
List<Stream> generatedPdfs = new List<Stream>(dataObjects.Count);
|
||||||
|
var progressPerDoc = 80d / dataObjects.Count;
|
||||||
|
var progressDoc = 10d;
|
||||||
|
using (var state = DocumentState.DefaultState())
|
||||||
|
{
|
||||||
|
taskStatus.UpdateStatus(10, "Rendering", "Starting");
|
||||||
|
foreach (var d in dataObjects)
|
||||||
|
{
|
||||||
|
taskStatus.UpdateStatus(progressDoc += progressPerDoc, $"Rendering {d.AttachmentReferenceId}");
|
||||||
|
generatedPdfs.Add(dt.GeneratePdf(database, d, creatorUser, timestamp, state, true));
|
||||||
|
state.SequenceNumber++;
|
||||||
|
state.FlushScopeCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (generatedPdfs.Count == 1)
|
||||||
|
{
|
||||||
|
return generatedPdfs[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
taskStatus.UpdateStatus(90, "Merging", "Merging documents");
|
||||||
|
Stream bulkPdf = Utilities.JoinPdfs(insertBlankPages, generatedPdfs);
|
||||||
|
foreach (Stream singlePdf in generatedPdfs)
|
||||||
|
singlePdf.Dispose();
|
||||||
|
return bulkPdf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext database, User creatorUser, DateTime timestamp, bool insertBlankPages, List<string> dataObjectsIds, IScheduledTaskStatus taskStatus)
|
||||||
|
{
|
||||||
|
Dictionary<string, IAttachmentTarget> dataObjectLookup;
|
||||||
|
List<string> dataObjectIds = dataObjectsIds;
|
||||||
|
|
||||||
|
taskStatus.UpdateStatus(0, "Resolving targets", "Resolving render targets");
|
||||||
|
|
||||||
|
switch (dt.Scope)
|
||||||
|
{
|
||||||
|
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||||
|
dataObjectLookup = database.Devices.Where(d => dataObjectsIds.Contains(d.SerialNumber)).AsEnumerable().Cast<IAttachmentTarget>().ToDictionary(i => i.AttachmentReferenceId, StringComparer.OrdinalIgnoreCase);
|
||||||
|
break;
|
||||||
|
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||||
|
var intDataObjectsIds = dataObjectsIds.Select(i => int.Parse(i)).ToList();
|
||||||
|
dataObjectLookup = database.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).AsEnumerable().Cast<IAttachmentTarget>().ToDictionary(i => i.AttachmentReferenceId, StringComparer.OrdinalIgnoreCase);
|
||||||
|
break;
|
||||||
|
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||||
|
dataObjectLookup = new Dictionary<string, IAttachmentTarget>(dataObjectsIds.Count, StringComparer.OrdinalIgnoreCase);
|
||||||
|
dataObjectIds = new List<string>(dataObjectsIds.Count);
|
||||||
|
foreach (var userId in dataObjectsIds)
|
||||||
|
{
|
||||||
|
var user = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(userId), database, true);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
dataObjectIds.Add(userId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dataObjectIds.Add(user.UserId);
|
||||||
|
dataObjectLookup.Add(user.UserId, user);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Invalid DocumentType Scope");
|
||||||
|
}
|
||||||
|
|
||||||
|
// recreate list to honor the sort-order provided in DataObjectsIds
|
||||||
|
var dataObjects = new List<IAttachmentTarget>(dataObjectsIds.Count);
|
||||||
|
var missingIds = new List<string>();
|
||||||
|
foreach (var id in dataObjectIds)
|
||||||
|
{
|
||||||
|
if (dataObjectLookup.TryGetValue(id, out var dataObject))
|
||||||
|
dataObjects.Add(dataObject);
|
||||||
|
else
|
||||||
|
missingIds.Add(id);
|
||||||
|
}
|
||||||
|
if (missingIds.Any())
|
||||||
|
{
|
||||||
|
throw new Exception($"Unknown id specified: {string.Join("; ", missingIds)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GenerateBulkFromTemplate(dt, database, creatorUser, timestamp, insertBlankPages, dataObjects, taskStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Data, User CreatorUser, DateTime TimeStamp, DocumentState State, bool flattenFields = false)
|
||||||
{
|
{
|
||||||
// Validate Data
|
// Validate Data
|
||||||
switch (dt.Scope)
|
switch (dt.Scope)
|
||||||
@@ -97,33 +228,33 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
throw new InvalidOperationException("Invalid AttachmentType Scope");
|
throw new InvalidOperationException("Invalid AttachmentType Scope");
|
||||||
}
|
}
|
||||||
|
|
||||||
dbContext.Configuration.LazyLoadingEnabled = true;
|
Database.Configuration.LazyLoadingEnabled = true;
|
||||||
|
|
||||||
// Override FlattenFields if Document Template instructs.
|
// Override FlattenFields if Document Template instructs.
|
||||||
if (dt.FlattenForm)
|
if (dt.FlattenForm)
|
||||||
FlattenFields = true;
|
flattenFields = true;
|
||||||
|
|
||||||
ConcurrentDictionary<string, Expression> expressionCache = dt.PdfExpressionsFromCache(dbContext);
|
var expressionCache = dt.PdfExpressionsFromCache(Database);
|
||||||
|
|
||||||
string templateFilename = dt.RepositoryFilename(dbContext);
|
string templateFilename = dt.RepositoryFilename(Database);
|
||||||
PdfReader pdfReader = new PdfReader(templateFilename);
|
PdfReader pdfReader = new PdfReader(templateFilename);
|
||||||
|
|
||||||
MemoryStream pdfGeneratedStream = new MemoryStream();
|
MemoryStream pdfGeneratedStream = new MemoryStream();
|
||||||
PdfStamper pdfStamper = new PdfStamper(pdfReader, pdfGeneratedStream);
|
PdfStamper pdfStamper = new PdfStamper(pdfReader, pdfGeneratedStream);
|
||||||
|
|
||||||
pdfStamper.FormFlattening = FlattenFields;
|
pdfStamper.FormFlattening = flattenFields;
|
||||||
pdfStamper.Writer.CloseStream = false;
|
pdfStamper.Writer.CloseStream = false;
|
||||||
|
|
||||||
IDictionary expressionVariables = Expression.StandardVariables(dt, dbContext, CreatorUser, TimeStamp, State);
|
IDictionary expressionVariables = Expression.StandardVariables(dt, Database, CreatorUser, TimeStamp, State, Data);
|
||||||
|
|
||||||
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
|
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
|
||||||
{
|
{
|
||||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
|
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.Id, TimeStamp);
|
string fieldValue = dt.CreateUniqueIdentifier(Database, Data, CreatorUser, TimeStamp, 0).ToJson();
|
||||||
if (FlattenFields)
|
if (flattenFields)
|
||||||
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
|
pdfStamper.AcroFields.SetField(pdfFieldKey, string.Empty);
|
||||||
else
|
else
|
||||||
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldValue);
|
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldValue);
|
||||||
|
|
||||||
@@ -131,11 +262,22 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||||
{
|
{
|
||||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||||
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.Id, TimeStamp, pdfFieldPosition.page);
|
|
||||||
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
|
// Create Binary Unique Identifier
|
||||||
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
|
var pageUniqueId = dt.CreateUniqueIdentifier(Database, Data, CreatorUser, TimeStamp, pdfFieldPosition.page);
|
||||||
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
var pageUniqueIdBytes = pageUniqueId.ToQRCodeBytes();
|
||||||
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfBarcodeImage);
|
|
||||||
|
// Encode to QRCode byte array
|
||||||
|
var pageUniqueIdEncoded = QRCodeBinaryEncoder.Encode(pageUniqueIdBytes, out var qrWidth, out var qrHeight);
|
||||||
|
|
||||||
|
// Encode byte array to Image
|
||||||
|
var pageUniqueIdImageData = CCITTG4Encoder.Compress(pageUniqueIdEncoded, qrWidth, qrHeight);
|
||||||
|
var pageUniqueIdImage = iTextSharp.text.Image.GetInstance(qrWidth, qrHeight, false, 256, 1, pageUniqueIdImageData, null);
|
||||||
|
|
||||||
|
// Add to the pdf page
|
||||||
|
pageUniqueIdImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||||
|
pageUniqueIdImage.ScaleToFit(pdfFieldPosition.position.Width, pdfFieldPosition.position.Height);
|
||||||
|
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pageUniqueIdImage);
|
||||||
}
|
}
|
||||||
// Hide Fields
|
// Hide Fields
|
||||||
PdfDictionary field = fields.GetValue(0);
|
PdfDictionary field = fields.GetValue(0);
|
||||||
@@ -154,8 +296,7 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Expression fieldExpression = null;
|
if (expressionCache.TryGetValue(pdfFieldKey, out var fieldExpression))
|
||||||
if (expressionCache.TryGetValue(pdfFieldKey, out fieldExpression))
|
|
||||||
{
|
{
|
||||||
if (fieldExpression.IsDynamic)
|
if (fieldExpression.IsDynamic)
|
||||||
{
|
{
|
||||||
@@ -172,8 +313,24 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||||
{
|
{
|
||||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||||
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(imageResult.GetImage((int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height));
|
|
||||||
|
iTextSharp.text.Image pdfImage;
|
||||||
|
var imageWidth = (int)(pdfFieldPosition.position.Width * 1.6);
|
||||||
|
var imageHeight = (int)(pdfFieldPosition.position.Height * 1.6);
|
||||||
|
if (imageResult.Format == ImageExpressionFormat.Jpeg || imageResult.Format == ImageExpressionFormat.Png)
|
||||||
|
{
|
||||||
|
pdfImage = iTextSharp.text.Image.GetInstance(imageResult.GetImage(imageWidth, imageHeight));
|
||||||
|
}
|
||||||
|
else if (imageResult.Format == ImageExpressionFormat.CcittG4)
|
||||||
|
{
|
||||||
|
var imageData = imageResult.GetImage(out imageWidth, out imageHeight);
|
||||||
|
pdfImage = iTextSharp.text.Image.GetInstance(imageWidth, imageHeight, false, 256, 1, imageData.GetBuffer(), null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new NotSupportedException($"Unexpected image format {imageResult.Format}");
|
||||||
|
|
||||||
pdfImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
pdfImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||||
|
pdfImage.ScaleToFit(pdfFieldPosition.position.Width, pdfFieldPosition.position.Height);
|
||||||
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfImage);
|
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfImage);
|
||||||
}
|
}
|
||||||
if (!fieldExpressionResult.Item2 && !imageResult.ShowField)
|
if (!fieldExpressionResult.Item2 && !imageResult.ShowField)
|
||||||
@@ -236,11 +393,11 @@ namespace Disco.BI.Interop.Pdf
|
|||||||
JobLog jl = new JobLog()
|
JobLog jl = new JobLog()
|
||||||
{
|
{
|
||||||
JobId = j.Id,
|
JobId = j.Id,
|
||||||
TechUserId = CreatorUser.Id,
|
TechUserId = CreatorUser.UserId,
|
||||||
Timestamp = DateTime.Now
|
Timestamp = DateTime.Now
|
||||||
};
|
};
|
||||||
jl.Comments = string.Format("Document Generated{0}{1} [{2}]", Environment.NewLine, dt.Description, dt.Id);
|
jl.Comments = $"# Document Generated\r\n**{dt.Description}** [{dt.Id}]";
|
||||||
dbContext.JobLogs.Add(jl);
|
Database.JobLogs.Add(jl);
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfGeneratedStream.Position = 0;
|
pdfGeneratedStream.Position = 0;
|
||||||
|
|||||||
@@ -1,971 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using iTextSharp.text.pdf;
|
|
||||||
using System.IO;
|
|
||||||
using System.Drawing;
|
|
||||||
using Disco.BI.DocumentTemplateBI.Importer;
|
|
||||||
using Disco.BI.DocumentTemplateBI;
|
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
using com.google.zxing;
|
|
||||||
using com.google.zxing.multi.qrcode;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.Web.Caching;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System.Collections;
|
|
||||||
using com.google.zxing.common;
|
|
||||||
using BitMiracle.LibTiff.Classic;
|
|
||||||
using System.Drawing.Imaging;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.Pdf
|
|
||||||
{
|
|
||||||
public static class PdfImporter
|
|
||||||
{
|
|
||||||
public static RectangleF CalculateLocationRatio(this Result zxingResult, int ImageWidth, int ImageHeight)
|
|
||||||
{
|
|
||||||
var orderedPoints = zxingResult.ResultPoints.OrderBy(p => p.X * p.Y).ToArray();
|
|
||||||
var topLeftPoint = orderedPoints.First();
|
|
||||||
var bottomRightPoint = orderedPoints.Last();
|
|
||||||
|
|
||||||
var x = topLeftPoint.X;
|
|
||||||
var y = topLeftPoint.Y;
|
|
||||||
var width = bottomRightPoint.X - x;
|
|
||||||
var height = bottomRightPoint.Y - y;
|
|
||||||
|
|
||||||
return new RectangleF(
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(x / ImageWidth) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(y / ImageHeight) - 0.05)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(width / ImageWidth) + 0.1)),
|
|
||||||
(float)System.Math.Min(1.0, System.Math.Max(0.0, (double)(height / ImageHeight) + 0.1))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetectImageResult : IDisposable
|
|
||||||
{
|
|
||||||
public Result Result { get; set; }
|
|
||||||
public Point ResultOffset { get; set; }
|
|
||||||
public double ResultScale { get; set; }
|
|
||||||
|
|
||||||
public float CalculateRotation()
|
|
||||||
{
|
|
||||||
var p1 = this.Result.ResultPoints[0];
|
|
||||||
var p2 = this.Result.ResultPoints[1];
|
|
||||||
double rotOpposite = p1.X - p2.X;
|
|
||||||
double rotAdjacent = p1.Y - p2.Y;
|
|
||||||
float rotation = 0;
|
|
||||||
|
|
||||||
if (rotOpposite != 0 || rotAdjacent != 0)
|
|
||||||
{
|
|
||||||
rotation = (float)(Math.Atan2(rotOpposite, rotAdjacent) * (180 / Math.PI)); // Degrees
|
|
||||||
}
|
|
||||||
|
|
||||||
return rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// Do Nothing; yet...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetectStateHints
|
|
||||||
{
|
|
||||||
public List<Tuple<RectangleF, Rotation>> PriorDetections { get; set; }
|
|
||||||
|
|
||||||
public DetectStateHints()
|
|
||||||
{
|
|
||||||
this.PriorDetections = new List<Tuple<RectangleF, Rotation>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum Rotation
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Degrees90 = 1,
|
|
||||||
DegreesNeg90 = 2,
|
|
||||||
Degrees180 = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DetectPageResult : IDisposable
|
|
||||||
{
|
|
||||||
public int PageNumber { get; set; }
|
|
||||||
public DocumentUniqueIdentifier DetectedIdentifier { get; set; }
|
|
||||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage ThumbnailImage { get; set; }
|
|
||||||
public MemoryStream AttachmentThumbnailImage { get; set; }
|
|
||||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage UndetectedPageImage { get; set; }
|
|
||||||
|
|
||||||
public void DrawThumbnailImageResult(DetectImageResult Result, Image DetectedImage)
|
|
||||||
{
|
|
||||||
if (Result.Result.ResultPoints.Length == 4)
|
|
||||||
{ // Draw Square on Thumbnail
|
|
||||||
using (Graphics thumbnailGraphics = Graphics.FromImage(ThumbnailImage.Montage))
|
|
||||||
{
|
|
||||||
var thumbnailOffset = ThumbnailImage.MontageSourceImageOffsets[DetectedImage];
|
|
||||||
|
|
||||||
var linePoints = Result.Result.ResultPoints.Select(p => new Point((int)(thumbnailOffset + ((Result.ResultOffset.X + p.X) * Result.ResultScale * ThumbnailImage.MontageScale)), (int)((p.Y + Result.ResultOffset.Y) * Result.ResultScale * ThumbnailImage.MontageScale))).ToArray();
|
|
||||||
using (GraphicsPath graphicsPath = new GraphicsPath())
|
|
||||||
{
|
|
||||||
for (int linePointIndex = 0; linePointIndex < (linePoints.Length - 1); linePointIndex++)
|
|
||||||
graphicsPath.AddLine(linePoints[linePointIndex], linePoints[linePointIndex + 1]);
|
|
||||||
graphicsPath.AddLine(linePoints[linePoints.Length - 1], linePoints[0]);
|
|
||||||
using (SolidBrush graphicsBrush = new SolidBrush(Color.FromArgb(128, 255, 0, 0)))
|
|
||||||
thumbnailGraphics.FillPath(graphicsBrush, graphicsPath);
|
|
||||||
using (Pen graphicsPen = new Pen(Color.FromArgb(200, 255, 0, 0), 2))
|
|
||||||
thumbnailGraphics.DrawPath(graphicsPen, graphicsPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (ThumbnailImage != null)
|
|
||||||
{
|
|
||||||
ThumbnailImage.Dispose();
|
|
||||||
ThumbnailImage = null;
|
|
||||||
}
|
|
||||||
if (AttachmentThumbnailImage != null)
|
|
||||||
{
|
|
||||||
AttachmentThumbnailImage.Dispose();
|
|
||||||
AttachmentThumbnailImage = null;
|
|
||||||
}
|
|
||||||
if (UndetectedPageImage != null)
|
|
||||||
{
|
|
||||||
UndetectedPageImage.Dispose();
|
|
||||||
UndetectedPageImage = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Tuple<Result, Rectangle, Rotation> DetectImageFromSegment(Bitmap pageImage, QRCodeMultiReader zxingReader, Hashtable zxingReaderHints, RectangleF LocationPercentage, Rotation Rotation)
|
|
||||||
{
|
|
||||||
System.Drawing.Rectangle region;
|
|
||||||
|
|
||||||
switch (Rotation)
|
|
||||||
{
|
|
||||||
case Rotation.None: // Original Position
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Left),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Top),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Width),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Height));
|
|
||||||
break;
|
|
||||||
case Rotation.Degrees90: // Clockwise 90 degrees
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width - (pageImage.Width * (LocationPercentage.Top + LocationPercentage.Height))),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Left),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Height),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Width));
|
|
||||||
break;
|
|
||||||
case Rotation.DegreesNeg90: // Anti-clockwise 90 degrees
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Top),
|
|
||||||
(int)(pageImage.Height - (pageImage.Height * (LocationPercentage.Left + LocationPercentage.Width))),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Height),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Width));
|
|
||||||
break;
|
|
||||||
case Rotation.Degrees180: // 180 degrees
|
|
||||||
region = new Rectangle(
|
|
||||||
(int)(pageImage.Width - (pageImage.Width * (LocationPercentage.Left + LocationPercentage.Width))),
|
|
||||||
(int)(pageImage.Height - (pageImage.Height * (LocationPercentage.Top + LocationPercentage.Height))),
|
|
||||||
(int)(pageImage.Width * LocationPercentage.Width),
|
|
||||||
(int)(pageImage.Height * LocationPercentage.Height));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException("Unknown Rotation");
|
|
||||||
}
|
|
||||||
|
|
||||||
LuminanceSource zxingSource;
|
|
||||||
using (Bitmap pageImageRegion = new Bitmap(region.Width, region.Height))
|
|
||||||
{
|
|
||||||
pageImageRegion.SetResolution(pageImage.HorizontalResolution, pageImage.VerticalResolution);
|
|
||||||
|
|
||||||
using (Graphics pageImageRegionGraphics = Graphics.FromImage(pageImageRegion))
|
|
||||||
{
|
|
||||||
pageImageRegionGraphics.DrawImage(pageImage, 0, 0, region, GraphicsUnit.Pixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
zxingSource = new BitmapLuminanceSource(pageImageRegion);
|
|
||||||
}
|
|
||||||
var zxingHB = new HybridBinarizer(zxingSource);
|
|
||||||
var zxingBB = new BinaryBitmap(zxingHB);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var zxingResult = zxingReader.decode(zxingBB, zxingReaderHints);
|
|
||||||
if (zxingResult != null)
|
|
||||||
return new Tuple<Result, Rectangle, Rotation>(zxingResult, region, Rotation);
|
|
||||||
}
|
|
||||||
catch (ReaderException)
|
|
||||||
{
|
|
||||||
// Ignore Location Errors
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DetectImageResult DetectImage(DiscoDataContext dbContext, Bitmap pageImageOriginal, string SessionId, IEnumerable<DocumentTemplate> detectDocumentTemplates, DetectStateHints StateHints)
|
|
||||||
{
|
|
||||||
Bitmap pageImage = pageImageOriginal;
|
|
||||||
double pageImageModifiedScale = 1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Resize if Resolution > 80; Set to 72 Dpi
|
|
||||||
if (pageImage.HorizontalResolution > 80 || pageImage.VerticalResolution > 80)
|
|
||||||
{
|
|
||||||
pageImageModifiedScale = pageImage.HorizontalResolution / 72;
|
|
||||||
int newWidth = (int)((72 / pageImage.HorizontalResolution) * pageImage.Width);
|
|
||||||
int newHeight = (int)((72 / pageImage.VerticalResolution) * pageImage.Height);
|
|
||||||
|
|
||||||
pageImage = pageImage.ResizeImage(newWidth, newHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tuple<Result, Rectangle, Rotation> result = default(Tuple<Result, Rectangle, Rotation>);
|
|
||||||
QRCodeMultiReader zxingMfr = new QRCodeMultiReader();
|
|
||||||
Hashtable zxingMfrHints = new Hashtable();
|
|
||||||
zxingMfrHints.Add(DecodeHintType.TRY_HARDER, true);
|
|
||||||
|
|
||||||
|
|
||||||
// Look in previously found locations
|
|
||||||
if (StateHints.PriorDetections.Count > 0)
|
|
||||||
{
|
|
||||||
foreach (var previousLocation in StateHints.PriorDetections)
|
|
||||||
{
|
|
||||||
result = DetectImageFromSegment(pageImage, zxingMfr, zxingMfrHints,
|
|
||||||
previousLocation.Item1, previousLocation.Item2);
|
|
||||||
if (result != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result == null)
|
|
||||||
{
|
|
||||||
// Try the whole image
|
|
||||||
var zxingSource = new BitmapLuminanceSource(pageImage);
|
|
||||||
var zxingHB = new HybridBinarizer(zxingSource);
|
|
||||||
var zxingBB = new BinaryBitmap(zxingHB);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var zxingResult = zxingMfr.decode(zxingBB, zxingMfrHints);
|
|
||||||
if (zxingResult != null)
|
|
||||||
{
|
|
||||||
result = new Tuple<Result, Rectangle, Rotation>(zxingResult, new Rectangle(0, 0, pageImage.Width, pageImage.Height), Rotation.None);
|
|
||||||
|
|
||||||
StateHints.PriorDetections.Insert(0, new Tuple<RectangleF, Rotation>(
|
|
||||||
result.Item1.CalculateLocationRatio(pageImage.Width, pageImage.Height)
|
|
||||||
, Rotation.None));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ReaderException)
|
|
||||||
{
|
|
||||||
// Ignore Errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result == null)
|
|
||||||
{
|
|
||||||
// Look in 'Known' locations
|
|
||||||
for (int rotationIndex = 0; rotationIndex < 4; rotationIndex++)
|
|
||||||
{
|
|
||||||
foreach (DocumentTemplate dt in detectDocumentTemplates)
|
|
||||||
{
|
|
||||||
var locationBag = dt.QRCodeLocations(dbContext);
|
|
||||||
foreach (var location in locationBag)
|
|
||||||
{
|
|
||||||
result = DetectImageFromSegment(pageImage, zxingMfr, zxingMfrHints,
|
|
||||||
location, (Rotation)rotationIndex);
|
|
||||||
|
|
||||||
StateHints.PriorDetections.Insert(0, new Tuple<RectangleF, Rotation>(location, (Rotation)rotationIndex));
|
|
||||||
}
|
|
||||||
if (result != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (result != null)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != null)
|
|
||||||
|
|
||||||
return new DetectImageResult() { Result = result.Item1, ResultOffset = result.Item2.Location, ResultScale = pageImageModifiedScale };
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (pageImageOriginal != pageImage)
|
|
||||||
pageImage.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DetectPageResult DetectPage(DiscoDataContext dbContext, PdfReader pdfReader, int PageNumber, string SessionId, string DataStoreSessionCacheLocation, IEnumerable<DocumentTemplate> detectDocumentTemplates, DetectStateHints StateHints)
|
|
||||||
{
|
|
||||||
DetectPageResult result = new DetectPageResult() { PageNumber = PageNumber };
|
|
||||||
|
|
||||||
DocumentImporterLog.LogImportPageProgress(SessionId, PageNumber, 10, "Loading Page Images");
|
|
||||||
|
|
||||||
using (DisposableImageCollection pageImages = pdfReader.PdfPageImages(PageNumber))
|
|
||||||
{
|
|
||||||
if (pageImages.Count > 0)
|
|
||||||
{
|
|
||||||
result.ThumbnailImage = pageImages.BuildImageMontage(256, 256);
|
|
||||||
var pageThumbnailFilename = Path.Combine(DataStoreSessionCacheLocation, string.Format("{0}-{1}", SessionId, PageNumber));
|
|
||||||
|
|
||||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
|
||||||
DocumentImporterLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
|
||||||
|
|
||||||
double pageProgressInterval = 90 / pageImages.Count;
|
|
||||||
|
|
||||||
foreach (var pageImageOriginal in pageImages)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.LogImportPageProgress(SessionId, PageNumber, (int)(10 + (pageProgressInterval * pageImages.IndexOf(pageImageOriginal))), String.Format("Processing Page Image {0} of {1}", pageImages.IndexOf(pageImageOriginal) + 1, pageImages.Count));
|
|
||||||
|
|
||||||
using (var zxingResult = DetectImage(dbContext, pageImageOriginal, SessionId, detectDocumentTemplates, StateHints))
|
|
||||||
{
|
|
||||||
if (zxingResult != null)
|
|
||||||
{
|
|
||||||
if (DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(zxingResult.Result.Text))
|
|
||||||
{
|
|
||||||
float imageRotation = zxingResult.CalculateRotation();
|
|
||||||
|
|
||||||
result.DrawThumbnailImageResult(zxingResult, pageImageOriginal);
|
|
||||||
|
|
||||||
if (imageRotation != 0)
|
|
||||||
{
|
|
||||||
var preImageRotation = result.ThumbnailImage.Montage;
|
|
||||||
result.ThumbnailImage.Montage = result.ThumbnailImage.Montage.RotateImage(imageRotation);
|
|
||||||
preImageRotation.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
|
||||||
DocumentImporterLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
|
||||||
|
|
||||||
result.AttachmentThumbnailImage = new MemoryStream();
|
|
||||||
using (var attachmentThumbImage = pageImages.BuildImageMontage(48, 48, true))
|
|
||||||
{
|
|
||||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_pdf16)
|
|
||||||
attachmentThumbImage.Montage.EmbedIconOverlay(mimeTypeIcon);
|
|
||||||
|
|
||||||
if (imageRotation != 0)
|
|
||||||
{
|
|
||||||
var preImageRotation = attachmentThumbImage.Montage;
|
|
||||||
attachmentThumbImage.Montage = attachmentThumbImage.Montage.RotateImage(imageRotation, Brushes.White);
|
|
||||||
preImageRotation.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
attachmentThumbImage.Montage.SaveJpg(95, result.AttachmentThumbnailImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
result.DetectedIdentifier = new DocumentUniqueIdentifier(zxingResult.Result.Text, PageNumber.ToString());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Page Unassigned
|
|
||||||
result.UndetectedPageImage = pageImages.BuildImageMontage(700, 700);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext dbContext, string SessionId, Cache HttpCache)
|
|
||||||
{
|
|
||||||
var dataStoreUnassignedLocation = DataStore.CreateLocation(dbContext, "DocumentDropBox_Unassigned");
|
|
||||||
|
|
||||||
DocumentImporterLog.LogImportProgress(SessionId, 0, "Reading File");
|
|
||||||
|
|
||||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
|
||||||
{
|
|
||||||
var pdfReader = new PdfReader(fs);
|
|
||||||
|
|
||||||
var pdfPagesAssigned = new Dictionary<int, Tuple<DocumentUniqueIdentifier, byte[]>>();
|
|
||||||
|
|
||||||
var dataStoreSessionPagesCacheLocation = DataStore.CreateLocation(dbContext, "Cache\\DocumentDropBox_SessionPages");
|
|
||||||
var detectDocumentTemplates = dbContext.DocumentTemplates.ToArray();
|
|
||||||
|
|
||||||
double progressInterval = 70 / pdfReader.NumberOfPages;
|
|
||||||
|
|
||||||
DetectStateHints detectStateHints = new DetectStateHints();
|
|
||||||
|
|
||||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(PageNumber * progressInterval), string.Format("Processing Page {0} of {1}", PageNumber, pdfReader.NumberOfPages));
|
|
||||||
DocumentImporterLog.LogImportPageStarting(SessionId, PageNumber);
|
|
||||||
|
|
||||||
using (var pageResult = DetectPage(dbContext, pdfReader, PageNumber, SessionId, dataStoreSessionPagesCacheLocation, detectDocumentTemplates, detectStateHints))
|
|
||||||
{
|
|
||||||
if (pageResult.DetectedIdentifier != null)
|
|
||||||
{
|
|
||||||
var docId = pageResult.DetectedIdentifier;
|
|
||||||
pdfPagesAssigned.Add(PageNumber, new Tuple<DocumentUniqueIdentifier, byte[]>(docId, pageResult.AttachmentThumbnailImage.ToArray()));
|
|
||||||
|
|
||||||
docId.LoadComponents(dbContext);
|
|
||||||
DocumentImporterLog.LogImportPageDetected(SessionId, PageNumber, docId.DocumentUniqueId, docId.DocumentTemplate.Description, docId.DocumentTemplate.Scope, docId.DataId, docId.DataDescription);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Undetected Page - Write Preview-Images while still in Memory
|
|
||||||
DocumentImporterLog.LogImportPageUndetected(SessionId, PageNumber);
|
|
||||||
|
|
||||||
// Thumbnail:
|
|
||||||
string unassignedImageThumbnailFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}_thumbnail.png", SessionId, PageNumber));
|
|
||||||
pageResult.ThumbnailImage.Montage.SavePng(unassignedImageThumbnailFilename);
|
|
||||||
// Large Preview
|
|
||||||
string unassignedImageFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.jpg", SessionId, PageNumber));
|
|
||||||
pageResult.UndetectedPageImage.Montage.SaveJpg(90, unassignedImageFilename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out Assigned Documents
|
|
||||||
var assignedDocuments = pdfPagesAssigned.GroupBy(u => u.Value.Item1.DocumentUniqueId).ToList();
|
|
||||||
if (assignedDocuments.Count > 0)
|
|
||||||
{
|
|
||||||
progressInterval = 20 / assignedDocuments.Count;
|
|
||||||
|
|
||||||
foreach (var documentPortion in assignedDocuments)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(70 + (assignedDocuments.IndexOf(documentPortion) * progressInterval)), string.Format("Importing Documents {0} of {1}", assignedDocuments.IndexOf(documentPortion) + 1, assignedDocuments.Count));
|
|
||||||
|
|
||||||
var documentPortionInfo = documentPortion.First().Value;
|
|
||||||
var documentPortionIdentifier = documentPortionInfo.Item1;
|
|
||||||
var documentPortionThumbnail = documentPortionInfo.Item2;
|
|
||||||
|
|
||||||
if (!documentPortionIdentifier.LoadComponents(dbContext))
|
|
||||||
{
|
|
||||||
// Unknown Document Unique Id
|
|
||||||
foreach (var dp in documentPortion)
|
|
||||||
{
|
|
||||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
|
||||||
if (pdfPagesAssigned.ContainsKey(tag))
|
|
||||||
pdfPagesAssigned.Remove(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using (MemoryStream msBuilder = new MemoryStream())
|
|
||||||
{
|
|
||||||
var pdfDoc = new iTextSharp.text.Document();
|
|
||||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
|
||||||
|
|
||||||
pdfDoc.Open();
|
|
||||||
pdfCopy.CloseStream = false;
|
|
||||||
|
|
||||||
foreach (var dp in documentPortion.OrderBy(dg => dg.Value.Item1.Page))
|
|
||||||
{
|
|
||||||
var pageSize = pdfReader.GetPageSizeWithRotation(dp.Key);
|
|
||||||
var page = pdfCopy.GetImportedPage(pdfReader, dp.Key);
|
|
||||||
|
|
||||||
pdfDoc.SetPageSize(pageSize);
|
|
||||||
pdfDoc.NewPage();
|
|
||||||
|
|
||||||
pdfCopy.AddPage(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
pdfDoc.Close();
|
|
||||||
pdfCopy.Close();
|
|
||||||
|
|
||||||
msBuilder.Position = 0;
|
|
||||||
|
|
||||||
var attachmentSuccess = documentPortionIdentifier.ImportPdfAttachment(dbContext, msBuilder, documentPortionThumbnail);
|
|
||||||
|
|
||||||
if (!attachmentSuccess)
|
|
||||||
{ // Unable to add Attachment
|
|
||||||
foreach (var dp in documentPortion)
|
|
||||||
{
|
|
||||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
|
||||||
if (pdfPagesAssigned.ContainsKey(tag))
|
|
||||||
pdfPagesAssigned.Remove(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write out Unassigned Pages
|
|
||||||
List<int> pdfPagesUnassigned = new List<int>();
|
|
||||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
|
||||||
if (!pdfPagesAssigned.ContainsKey(PageNumber))
|
|
||||||
pdfPagesUnassigned.Add(PageNumber);
|
|
||||||
if (pdfPagesUnassigned.Count > 0)
|
|
||||||
{
|
|
||||||
progressInterval = 10 / pdfPagesUnassigned.Count;
|
|
||||||
//dataStoreUnassignedLocation
|
|
||||||
foreach (var PageNumber in pdfPagesUnassigned)
|
|
||||||
{
|
|
||||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(90 + (pdfPagesUnassigned.IndexOf(PageNumber) * progressInterval)), string.Format("Processing Undetected Documents {0} of {1}", pdfPagesUnassigned.IndexOf(PageNumber) + 1, pdfPagesUnassigned.Count));
|
|
||||||
|
|
||||||
using (MemoryStream msBuilder = new MemoryStream())
|
|
||||||
{
|
|
||||||
var pdfDoc = new iTextSharp.text.Document();
|
|
||||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
|
||||||
|
|
||||||
pdfDoc.Open();
|
|
||||||
pdfCopy.CloseStream = false;
|
|
||||||
|
|
||||||
var pageSize = pdfReader.GetPageSizeWithRotation(PageNumber);
|
|
||||||
var page = pdfCopy.GetImportedPage(pdfReader, PageNumber);
|
|
||||||
pdfDoc.SetPageSize(pageSize);
|
|
||||||
pdfDoc.NewPage();
|
|
||||||
|
|
||||||
pdfCopy.AddPage(page);
|
|
||||||
pdfDoc.Close();
|
|
||||||
pdfCopy.Close();
|
|
||||||
|
|
||||||
File.WriteAllBytes(Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.pdf", SessionId, PageNumber)), msBuilder.ToArray());
|
|
||||||
|
|
||||||
DocumentImporterLog.LogImportPageUndetectedStored(SessionId, PageNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
DocumentImporterLog.LogImportProgress(SessionId, 100, "Finished Importing Document");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext dbContext, string DocumentTemplateId, string DataId, string UserId, DateTime Timestamp)
|
|
||||||
{
|
|
||||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
|
||||||
{
|
|
||||||
DocumentUniqueIdentifier identifier = new DocumentUniqueIdentifier(DocumentTemplateId, DataId, UserId, Timestamp);
|
|
||||||
identifier.LoadComponents(dbContext);
|
|
||||||
return identifier.ImportPdfAttachment(dbContext, fs, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DisposableImageCollection GetPageImages(PdfReader pdfReader, int PageNumber)
|
|
||||||
{
|
|
||||||
var pageImages = new DisposableImageCollection();
|
|
||||||
|
|
||||||
var pdfPage = pdfReader.GetPageN(PageNumber);
|
|
||||||
PdfDictionary pdfPageResouces = (PdfDictionary)((PdfDictionary)pdfPage.GetDirectObject(PdfName.RESOURCES)).GetDirectObject(PdfName.XOBJECT);
|
|
||||||
|
|
||||||
foreach (var pdfResKey in pdfPageResouces.Keys)
|
|
||||||
{
|
|
||||||
var pdfRes = pdfPageResouces.GetDirectObject(pdfResKey);
|
|
||||||
if (pdfRes.IsStream())
|
|
||||||
{
|
|
||||||
var pdfResStream = (PdfStream)pdfRes;
|
|
||||||
var pdfResSubType = pdfResStream.Get(PdfName.SUBTYPE);
|
|
||||||
if (pdfResSubType != null && pdfResSubType == PdfName.IMAGE)
|
|
||||||
{
|
|
||||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.CCITTFAXDECODE)
|
|
||||||
{ // TIFF
|
|
||||||
// Try Using GDI+ for TIFF...
|
|
||||||
var width = ((PdfNumber)(pdfResStream.Get(PdfName.WIDTH))).IntValue;
|
|
||||||
var height = ((PdfNumber)(pdfResStream.Get(PdfName.HEIGHT))).IntValue;
|
|
||||||
var bpc = ((PdfNumber)(pdfResStream.Get(PdfName.BITSPERCOMPONENT))).IntValue;
|
|
||||||
|
|
||||||
var compressionMethod = Compression.CCITTFAX3;
|
|
||||||
|
|
||||||
var decodeParams = pdfResStream.GetAsDict(PdfName.DECODEPARMS);
|
|
||||||
if (decodeParams != null && decodeParams.Contains(PdfName.K) && decodeParams.GetAsNumber(PdfName.K).IntValue < 0)
|
|
||||||
compressionMethod = Compression.CCITTFAX4;
|
|
||||||
|
|
||||||
using (MemoryStream tiffStream = PdfToTiffStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream), width, height, bpc, compressionMethod))
|
|
||||||
{
|
|
||||||
pageImages.Add((Bitmap)Bitmap.FromStream(tiffStream));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.DCTDECODE)
|
|
||||||
{ // JPG
|
|
||||||
using (MemoryStream jpgStream = new MemoryStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream)))
|
|
||||||
{
|
|
||||||
pageImages.Add((Bitmap)Bitmap.FromStream(jpgStream, true, true));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pageImages;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MemoryStream PdfToTiffStream(byte[] PdfStream, int Width, int Height, int BitsPerComponent, Compression CompressionMethod)
|
|
||||||
{
|
|
||||||
var ms = new MemoryStream();
|
|
||||||
|
|
||||||
Tiff tif = Tiff.ClientOpen("in-memory", "w", ms, new TiffStream());
|
|
||||||
tif.SetField(TiffTag.IMAGEWIDTH, Width);
|
|
||||||
tif.SetField(TiffTag.IMAGELENGTH, Height);
|
|
||||||
tif.SetField(TiffTag.COMPRESSION, CompressionMethod);
|
|
||||||
tif.SetField(TiffTag.BITSPERSAMPLE, BitsPerComponent);
|
|
||||||
tif.SetField(TiffTag.SAMPLESPERPIXEL, 1);
|
|
||||||
tif.WriteRawStrip(0, PdfStream, PdfStream.Length);
|
|
||||||
tif.Flush();
|
|
||||||
|
|
||||||
return ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2012 ZXing.Net authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
/// <summary>
|
|
||||||
/// The base class for luminance sources which supports
|
|
||||||
/// cropping and rotating based upon the luminance values.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseLuminanceSource : LuminanceSource
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
protected sbyte[] luminances;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
protected BaseLuminanceSource(int width, int height)
|
|
||||||
: base(width, height)
|
|
||||||
{
|
|
||||||
luminances = new sbyte[width * height];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BaseLuminanceSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="luminanceArray">The luminance array.</param>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
protected BaseLuminanceSource(sbyte[] luminanceArray, int width, int height)
|
|
||||||
: base(width, height)
|
|
||||||
{
|
|
||||||
luminances = luminanceArray;
|
|
||||||
//Buffer.BlockCopy(luminanceArray, 0, luminances, 0, width * height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Fetches one row of luminance data from the underlying platform's bitmap. Values range from
|
|
||||||
/// 0 (black) to 255 (white). It is preferable for implementations of this method
|
|
||||||
/// to only fetch this row rather than the whole image, since no 2D Readers may be installed and
|
|
||||||
/// getMatrix() may never be called.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="y">The row to fetch, 0 <= y < Height.</param>
|
|
||||||
/// <param name="row">An optional preallocated array. If null or too small, it will be ignored.
|
|
||||||
/// Always use the returned object, and ignore the .length of the array.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// An array containing the luminance data.
|
|
||||||
/// </returns>
|
|
||||||
override public sbyte[] getRow(int y, sbyte[] row)
|
|
||||||
{
|
|
||||||
int width = Width;
|
|
||||||
if (row == null || row.Length < width)
|
|
||||||
{
|
|
||||||
row = new sbyte[width];
|
|
||||||
}
|
|
||||||
//for (int i = 0; i < width; i++)
|
|
||||||
// row[i] = luminances[y * width + i];
|
|
||||||
Buffer.BlockCopy(luminances, y * width, row, 0, width);
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override sbyte[] Matrix
|
|
||||||
{
|
|
||||||
get { return luminances; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new object with rotated image data by 90 degrees counterclockwise.
|
|
||||||
/// Only callable if {@link #isRotateSupported()} is true.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// A rotated version of this object.
|
|
||||||
/// </returns>
|
|
||||||
public override LuminanceSource rotateCounterClockwise()
|
|
||||||
{
|
|
||||||
var rotatedLuminances = new sbyte[Width * Height];
|
|
||||||
var newWidth = Height;
|
|
||||||
var newHeight = Width;
|
|
||||||
var localLuminances = Matrix;
|
|
||||||
for (var yold = 0; yold < Height; yold++)
|
|
||||||
{
|
|
||||||
for (var xold = 0; xold < Width; xold++)
|
|
||||||
{
|
|
||||||
var ynew = xold;
|
|
||||||
var xnew = newWidth - yold - 1;
|
|
||||||
rotatedLuminances[ynew * newWidth + xnew] = localLuminances[yold * Width + xold];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CreateLuminanceSource(rotatedLuminances, newWidth, newHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns> Whether this subclass supports counter-clockwise rotation.</returns>
|
|
||||||
public override bool RotateSupported
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new object with cropped image data. Implementations may keep a reference to the
|
|
||||||
/// original data rather than a copy. Only callable if CropSupported is true.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="left">The left coordinate, 0 <= left < Width.</param>
|
|
||||||
/// <param name="top">The top coordinate, 0 <= top <= Height.</param>
|
|
||||||
/// <param name="width">The width of the rectangle to crop.</param>
|
|
||||||
/// <param name="height">The height of the rectangle to crop.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// A cropped version of this object.
|
|
||||||
/// </returns>
|
|
||||||
public override LuminanceSource crop(int left, int top, int width, int height)
|
|
||||||
{
|
|
||||||
if (left + width > Width || top + height > Height)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Crop rectangle does not fit within image data.");
|
|
||||||
}
|
|
||||||
var croppedLuminances = new sbyte[width * height];
|
|
||||||
for (int yold = top, ynew = 0; yold < height; yold++, ynew++)
|
|
||||||
{
|
|
||||||
for (int xold = left, xnew = 0; xold < width; xold++, xnew++)
|
|
||||||
{
|
|
||||||
croppedLuminances[ynew * width + xnew] = luminances[yold * Width + xold];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return CreateLuminanceSource(croppedLuminances, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// </summary>
|
|
||||||
/// <returns> Whether this subclass supports cropping.</returns>
|
|
||||||
public override bool CropSupported
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should create a new luminance source with the right class type.
|
|
||||||
/// The method is used in methods crop and rotate.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newLuminances">The new luminances.</param>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected abstract LuminanceSource CreateLuminanceSource(sbyte[] newLuminances, int width, int height);
|
|
||||||
}
|
|
||||||
public partial class BitmapLuminanceSource : BaseLuminanceSource
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
protected BitmapLuminanceSource(int width, int height)
|
|
||||||
: base(width, height)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="BitmapLuminanceSource"/> class
|
|
||||||
/// with the image of a Bitmap instance
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bitmap">The bitmap.</param>
|
|
||||||
public BitmapLuminanceSource(Bitmap bitmap)
|
|
||||||
: base(bitmap.Width, bitmap.Height)
|
|
||||||
{
|
|
||||||
var height = bitmap.Height;
|
|
||||||
var width = bitmap.Width;
|
|
||||||
|
|
||||||
// In order to measure pure decoding speed, we convert the entire image to a greyscale array
|
|
||||||
luminances = new sbyte[width * height];
|
|
||||||
|
|
||||||
// The underlying raster of image consists of bytes with the luminance values
|
|
||||||
#if WindowsCE
|
|
||||||
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
|
|
||||||
#else
|
|
||||||
var data = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
|
|
||||||
#endif
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var stride = Math.Abs(data.Stride);
|
|
||||||
var pixelWidth = stride / width;
|
|
||||||
|
|
||||||
if (pixelWidth > 4)
|
|
||||||
{
|
|
||||||
// old slow way for unsupported bit depth
|
|
||||||
Color c;
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
int offset = y * width;
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
c = bitmap.GetPixel(x, y);
|
|
||||||
luminances[offset + x] = (sbyte)(0.3 * c.R + 0.59 * c.G + 0.11 * c.B + 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var strideStep = data.Stride;
|
|
||||||
var buffer = new byte[stride];
|
|
||||||
var ptrInBitmap = data.Scan0;
|
|
||||||
|
|
||||||
#if !WindowsCE
|
|
||||||
// prepare palette for 1 and 8 bit indexed bitmaps
|
|
||||||
var luminancePalette = new sbyte[bitmap.Palette.Entries.Length];
|
|
||||||
for (var index = 0; index < bitmap.Palette.Entries.Length; index++)
|
|
||||||
{
|
|
||||||
var color = bitmap.Palette.Entries[index];
|
|
||||||
luminancePalette[index] = (sbyte)(0.3 * color.R +
|
|
||||||
0.59 * color.G +
|
|
||||||
0.11 * color.B + 0.01);
|
|
||||||
}
|
|
||||||
if (bitmap.PixelFormat == PixelFormat.Format32bppArgb ||
|
|
||||||
bitmap.PixelFormat == PixelFormat.Format32bppPArgb)
|
|
||||||
{
|
|
||||||
pixelWidth = 40;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
|
||||||
{
|
|
||||||
// copy a scanline not the whole bitmap because of memory usage
|
|
||||||
Marshal.Copy(ptrInBitmap, buffer, 0, stride);
|
|
||||||
#if NET40
|
|
||||||
ptrInBitmap = IntPtr.Add(ptrInBitmap, strideStep);
|
|
||||||
#else
|
|
||||||
ptrInBitmap = new IntPtr(ptrInBitmap.ToInt64() + strideStep);
|
|
||||||
#endif
|
|
||||||
var offset = y * width;
|
|
||||||
switch (pixelWidth)
|
|
||||||
{
|
|
||||||
#if !WindowsCE
|
|
||||||
case 0:
|
|
||||||
for (int x = 0; x * 8 < width; x++)
|
|
||||||
{
|
|
||||||
for (int subX = 0; subX < 8 && 8 * x + subX < width; subX++)
|
|
||||||
{
|
|
||||||
var index = (buffer[x] >> (7 - subX)) & 1;
|
|
||||||
luminances[offset + 8 * x + subX] = luminancePalette[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
luminances[offset + x] = luminancePalette[buffer[x]];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 2:
|
|
||||||
// should be RGB565 or RGB555, assume RGB565
|
|
||||||
{
|
|
||||||
for (int index = 0, x = 0; index < 2 * width; index += 2, x++)
|
|
||||||
{
|
|
||||||
var byte1 = buffer[index];
|
|
||||||
var byte2 = buffer[index + 1];
|
|
||||||
|
|
||||||
var b5 = byte1 & 0x1F;
|
|
||||||
var g5 = (((byte1 & 0xE0) >> 5) | ((byte2 & 0x03) << 3)) & 0x1F;
|
|
||||||
var r5 = (byte2 >> 2) & 0x1F;
|
|
||||||
var r8 = (r5 * 527 + 23) >> 6;
|
|
||||||
var g8 = (g5 * 527 + 23) >> 6;
|
|
||||||
var b8 = (b5 * 527 + 23) >> 6;
|
|
||||||
|
|
||||||
luminances[offset + x] = (sbyte)(0.3 * r8 + 0.59 * g8 + 0.11 * b8 + 0.01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
var luminance = (sbyte)(0.3 * buffer[x * 3] +
|
|
||||||
0.59 * buffer[x * 3 + 1] +
|
|
||||||
0.11 * buffer[x * 3 + 2] + 0.01);
|
|
||||||
luminances[offset + x] = luminance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
// 4 bytes without alpha channel value
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
var luminance = (sbyte)(0.30 * buffer[x * 4] +
|
|
||||||
0.59 * buffer[x * 4 + 1] +
|
|
||||||
0.11 * buffer[x * 4 + 2] + 0.01);
|
|
||||||
|
|
||||||
luminances[offset + x] = luminance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
// with alpha channel; some barcodes are completely black if you
|
|
||||||
// only look at the r, g and b channel but the alpha channel controls
|
|
||||||
// the view
|
|
||||||
for (int x = 0; x < width; x++)
|
|
||||||
{
|
|
||||||
var luminance = (sbyte)(0.30 * buffer[x * 4] +
|
|
||||||
0.59 * buffer[x * 4 + 1] +
|
|
||||||
0.11 * buffer[x * 4 + 2] + 0.01);
|
|
||||||
|
|
||||||
// calculating the resulting luminance based upon a white background
|
|
||||||
// var alpha = buffer[x * pixelWidth + 3] / 255.0;
|
|
||||||
// luminance = (byte)(luminance * alpha + 255 * (1 - alpha));
|
|
||||||
var alpha = buffer[x * 4 + 3];
|
|
||||||
luminance = (sbyte)(((luminance * alpha) >> 8) + (255 * (255 - alpha) >> 8));
|
|
||||||
luminances[offset + x] = luminance;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bitmap.UnlockBits(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should create a new luminance source with the right class type.
|
|
||||||
/// The method is used in methods crop and rotate.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="newLuminances">The new luminances.</param>
|
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
protected override LuminanceSource CreateLuminanceSource(sbyte[] newLuminances, int width, int height)
|
|
||||||
{
|
|
||||||
return new BitmapLuminanceSource(width, height) { luminances = newLuminances };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using iTextSharp.text;
|
||||||
|
using iTextSharp.text.pdf;
|
||||||
|
using iTextSharp.text.pdf.codec;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Disco.BI.Interop.Pdf
|
||||||
|
{
|
||||||
|
public static class Utilities
|
||||||
|
{
|
||||||
|
public static Func<byte[], int, int, byte[]> GetCCITTG4EncoderCompressDelegate()
|
||||||
|
{
|
||||||
|
return CCITTG4Encoder.Compress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stream JoinPdfs(bool InsertBlankPages, List<Stream> Pdfs)
|
||||||
|
{
|
||||||
|
if (Pdfs.Count == 0)
|
||||||
|
throw new ArgumentNullException(nameof(Pdfs));
|
||||||
|
|
||||||
|
// Only One PDF - Possible Reference Bug v's Memory/Speed (Returning Param Memory Stream)
|
||||||
|
if (Pdfs.Count == 1)
|
||||||
|
return Pdfs[0];
|
||||||
|
|
||||||
|
// Join Pdfs
|
||||||
|
var msBuilder = new MemoryStream();
|
||||||
|
|
||||||
|
var pdfLastPageSize = PageSize.A4;
|
||||||
|
var pdfDoc = new Document();
|
||||||
|
var pdfCopy = new PdfSmartCopy(pdfDoc, msBuilder);
|
||||||
|
pdfDoc.Open();
|
||||||
|
pdfCopy.CloseStream = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < Pdfs.Count; i++)
|
||||||
|
{
|
||||||
|
var pdf = Pdfs[i];
|
||||||
|
var pdfReader = new PdfReader(pdf);
|
||||||
|
|
||||||
|
if (InsertBlankPages && (pdfCopy.CurrentPageNumber % 2) == 0)
|
||||||
|
{
|
||||||
|
pdfCopy.AddPage(pdfLastPageSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int indexPage = 1; indexPage <= pdfReader.NumberOfPages; indexPage++)
|
||||||
|
{
|
||||||
|
pdfLastPageSize = pdfReader.GetPageSizeWithRotation(indexPage);
|
||||||
|
var page = pdfCopy.GetImportedPage(pdfReader, indexPage);
|
||||||
|
pdfDoc.SetPageSize(pdfLastPageSize);
|
||||||
|
pdfCopy.AddPage(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfReader.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
pdfDoc.Close();
|
||||||
|
pdfCopy.Close();
|
||||||
|
msBuilder.Position = 0;
|
||||||
|
|
||||||
|
return msBuilder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
//using System;
|
|
||||||
//using System.Collections.Generic;
|
|
||||||
//using System.Linq;
|
|
||||||
//using System.Text;
|
|
||||||
//using Disco.Data.Repository;
|
|
||||||
//using Quartz;
|
|
||||||
|
|
||||||
//namespace Disco.BI.Interop.PluginServices
|
|
||||||
//{
|
|
||||||
// interface IDiscoScheduledTask
|
|
||||||
// {
|
|
||||||
// void InitalizeScheduledTask(DiscoDataContext dbContext, IScheduler Scheduler);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
//using System;
|
|
||||||
//using System.Collections.Generic;
|
|
||||||
//using System.Linq;
|
|
||||||
//using System.Text;
|
|
||||||
//using Disco.Data.Repository;
|
|
||||||
//using Quartz;
|
|
||||||
|
|
||||||
//namespace Disco.BI.Interop.PluginServices
|
|
||||||
//{
|
|
||||||
// public static class Utilities
|
|
||||||
// {
|
|
||||||
|
|
||||||
// public static void InitalizeScheduledTasks(DiscoDataContext dbContext, ISchedulerFactory SchedulerFactory)
|
|
||||||
// {
|
|
||||||
|
|
||||||
// var scheduler = SchedulerFactory.GetScheduler();
|
|
||||||
|
|
||||||
// // Discover IDiscoScheduledTasks (Only from Disco Assemblies)
|
|
||||||
// var appDomain = AppDomain.CurrentDomain;
|
|
||||||
|
|
||||||
// var scheduledTaskTypes = (from a in appDomain.GetAssemblies()
|
|
||||||
// where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
|
|
||||||
// from type in a.GetTypes()
|
|
||||||
// where typeof(IDiscoScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
|
|
||||||
// select type);
|
|
||||||
// foreach (Type scheduledTaskType in scheduledTaskTypes)
|
|
||||||
// {
|
|
||||||
// IDiscoScheduledTask instance = (IDiscoScheduledTask)Activator.CreateInstance(scheduledTaskType);
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// instance.InitalizeScheduledTask(dbContext, scheduler);
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// if (instance == null)
|
|
||||||
// Logging.SystemLog.LogException("Initializing Scheduled Task; Disco.BI.Interop.Plugins.Utilities.InitalizeScheduledTasks()", ex);
|
|
||||||
// else
|
|
||||||
// Logging.SystemLog.LogException(string.Format("Initializing Scheduled Task: '{0}'; Disco.BI.Interop.Plugins.Utilities.InitalizeScheduledTasks()", instance.GetType().Name), ex);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class AdminAuthorizedPersistentConnection : AuthorizedPersistentConnection
|
|
||||||
{
|
|
||||||
private string[] authorizedUserTypes = { User.Types.Admin };
|
|
||||||
|
|
||||||
protected override string[] AuthorizedUserTypes { get { return authorizedUserTypes; } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class AuthorizedPersistentConnection : PersistentConnection
|
|
||||||
{
|
|
||||||
private string[] authorizedUserTypes = null;
|
|
||||||
|
|
||||||
protected virtual string[] AuthorizedUserTypes { get { return authorizedUserTypes; } }
|
|
||||||
|
|
||||||
protected override bool AuthorizeRequest(IRequest request)
|
|
||||||
{
|
|
||||||
if (!request.User.Identity.IsAuthenticated)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var user = UserBI.UserCache.CurrentUser;
|
|
||||||
if (user == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (AuthorizedUserTypes == null || AuthorizedUserTypes.Length == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (AuthorizedUserTypes.Contains(user.Type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using Disco.Data.Repository.Monitor;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class HeldDeviceNotifications : PersistentConnection
|
|
||||||
{
|
|
||||||
private static bool subscribed = false;
|
|
||||||
private static object subscribeLock = new object();
|
|
||||||
private static IPersistentConnectionContext notificationContext;
|
|
||||||
|
|
||||||
static HeldDeviceNotifications()
|
|
||||||
{
|
|
||||||
if (!subscribed)
|
|
||||||
lock (subscribeLock)
|
|
||||||
if (!subscribed)
|
|
||||||
{
|
|
||||||
notificationContext = GlobalHost.ConnectionManager.GetConnectionContext<HeldDeviceNotifications>();
|
|
||||||
|
|
||||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e => e.EntityType == typeof(Job)).Subscribe(JobUpdated);
|
|
||||||
|
|
||||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
|
||||||
e.EntityType == typeof(Device) &&
|
|
||||||
(e.ModifiedProperties.Contains("Location") ||
|
|
||||||
e.ModifiedProperties.Contains("DeviceModelId") ||
|
|
||||||
e.ModifiedProperties.Contains("DeviceProfileId") ||
|
|
||||||
e.ModifiedProperties.Contains("DeviceBatchId") ||
|
|
||||||
e.ModifiedProperties.Contains("ComputerName") ||
|
|
||||||
e.ModifiedProperties.Contains("AssignedUserId"))
|
|
||||||
).Subscribe(DeviceUpdated);
|
|
||||||
|
|
||||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
|
||||||
e.EntityType == typeof(User) &&
|
|
||||||
e.ModifiedProperties.Contains("DisplayName")
|
|
||||||
).Subscribe(UserUpdated);
|
|
||||||
|
|
||||||
subscribed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void JobUpdated(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
Job j = (Job)e.Entity;
|
|
||||||
|
|
||||||
if (j.DeviceSerialNumber != null)
|
|
||||||
notificationContext.Connection.Broadcast(j.DeviceSerialNumber);
|
|
||||||
}
|
|
||||||
private static void DeviceUpdated(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
Device d = (Device)e.Entity;
|
|
||||||
|
|
||||||
notificationContext.Connection.Broadcast(d.SerialNumber);
|
|
||||||
}
|
|
||||||
private static void UserUpdated(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
User u = (User)e.Entity;
|
|
||||||
|
|
||||||
var userDevices = e.dbContext.Devices.Where(d => d.AssignedUserId == u.Id);
|
|
||||||
|
|
||||||
foreach (var userDevice in userDevices)
|
|
||||||
{
|
|
||||||
notificationContext.Connection.Broadcast(userDevice.SerialNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
using Disco.Services.Logging;
|
|
||||||
using Disco.Services.Logging.Models;
|
|
||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class LogNotifications : AdminAuthorizedPersistentConnection
|
|
||||||
{
|
|
||||||
public static bool initialized = false;
|
|
||||||
|
|
||||||
public LogNotifications()
|
|
||||||
{
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
initialized = true;
|
|
||||||
Disco.Services.Logging.Targets.LogLiveContext.LogBroadcast += Broadcast;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Task OnConnected(IRequest request, string connectionId)
|
|
||||||
{
|
|
||||||
string addToGroups = request.QueryString["addToGroups"];
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
|
||||||
{
|
|
||||||
var groups = addToGroups.Split(',');
|
|
||||||
foreach (var g in groups)
|
|
||||||
{
|
|
||||||
this.Groups.Add(connectionId, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnConnected(request, connectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
|
|
||||||
{
|
|
||||||
// Add to Group
|
|
||||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
|
||||||
{
|
|
||||||
var groups = data.Substring(13).Split(',');
|
|
||||||
foreach (var g in groups)
|
|
||||||
{
|
|
||||||
this.Groups.Add(connectionId, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnReceived(request, connectionId, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Broadcast(LogBase logModule, LogEventType eventType, DateTime Timestamp, params object[] Arguments)
|
|
||||||
{
|
|
||||||
var message = LogLiveEvent.Create(logModule, eventType, Timestamp, Arguments);
|
|
||||||
|
|
||||||
var connectionManager = GlobalHost.ConnectionManager;
|
|
||||||
var connectionContext = connectionManager.GetConnectionContext<LogNotifications>();
|
|
||||||
connectionContext.Groups.Send(_GroupNameAll, message);
|
|
||||||
connectionContext.Groups.Send(logModule.ModuleName, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private const string _GroupNameAll = "__All";
|
|
||||||
|
|
||||||
public static string AllNotifications
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _GroupNameAll;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
using Disco.Data.Repository.Monitor;
|
|
||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class RepositoryMonitorNotifications : AdminAuthorizedPersistentConnection
|
|
||||||
{
|
|
||||||
public static void Initialize()
|
|
||||||
{
|
|
||||||
RepositoryMonitor.StreamAfterCommit.Subscribe(AfterCommit);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Task OnConnected(IRequest request, string connectionId)
|
|
||||||
{
|
|
||||||
string addToGroups = request.QueryString["addToGroups"];
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
|
||||||
{
|
|
||||||
var groups = addToGroups.Split(',');
|
|
||||||
foreach (var g in groups)
|
|
||||||
{
|
|
||||||
this.Groups.Add(connectionId, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnConnected(request, connectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Task OnReceived(IRequest request, string connectionId, string data)
|
|
||||||
{
|
|
||||||
// Add to Group
|
|
||||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
|
||||||
{
|
|
||||||
var groups = data.Substring(13).Split(',');
|
|
||||||
foreach (var g in groups)
|
|
||||||
{
|
|
||||||
this.Groups.Add(connectionId, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnReceived(request, connectionId, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void AfterCommit(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
GlobalHost.ConnectionManager.GetConnectionContext<RepositoryMonitorNotifications>().Groups.Send(e.EntityType.Name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
using Disco.Services.Tasks;
|
|
||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class ScheduledTasksStatusNotifications : AdminAuthorizedPersistentConnection
|
|
||||||
{
|
|
||||||
public static bool initialized = false;
|
|
||||||
|
|
||||||
public ScheduledTasksStatusNotifications()
|
|
||||||
{
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
initialized = true;
|
|
||||||
Disco.Services.Tasks.ScheduledTaskStatus.UpdatedBroadcast += Broadcast;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Task OnConnected(IRequest request, string connectionId)
|
|
||||||
{
|
|
||||||
string addToGroups = request.QueryString["addToGroups"];
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
|
||||||
{
|
|
||||||
var groups = addToGroups.Split(',');
|
|
||||||
foreach (var g in groups)
|
|
||||||
{
|
|
||||||
this.Groups.Add(connectionId, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnConnected(request, connectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
|
|
||||||
{
|
|
||||||
// Add to Group
|
|
||||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
|
||||||
{
|
|
||||||
var groups = data.Substring(13).Split(',');
|
|
||||||
foreach (var g in groups)
|
|
||||||
{
|
|
||||||
this.Groups.Add(connectionId, g);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base.OnReceived(request, connectionId, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Broadcast(ScheduledTaskStatusLive SessionStatus)
|
|
||||||
{
|
|
||||||
var connectionManager = GlobalHost.ConnectionManager;
|
|
||||||
var connectionContext = connectionManager.GetConnectionContext<ScheduledTasksStatusNotifications>();
|
|
||||||
connectionContext.Groups.Send(_GroupNameAll, SessionStatus);
|
|
||||||
connectionContext.Groups.Send(SessionStatus.SessionId, SessionStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
private const string _GroupNameAll = "__All";
|
|
||||||
|
|
||||||
public static string AllNotifications
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _GroupNameAll;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using System.Web.Routing;
|
|
||||||
using System.Web.Security;
|
|
||||||
using System.Web.SessionState;
|
|
||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using Owin;
|
|
||||||
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required for SignalR 1.1.0 NTLM support in Firefox & Safari
|
|
||||||
/// Returns 401 (Unauthorized) instead of 403 (Forbidden) when an unauthenticated request is processed
|
|
||||||
///
|
|
||||||
/// TODO: Remove this workaround when implementing SignalR 2.x
|
|
||||||
///
|
|
||||||
/// Thanks to David Fowler (@davidfowl)
|
|
||||||
/// </summary>
|
|
||||||
public static class SignalRAuthenticationWorkaround
|
|
||||||
{
|
|
||||||
public static void AddMiddleware(IAppBuilder app)
|
|
||||||
{
|
|
||||||
Func<AppFunc, AppFunc> convert403To401 = Convert403To401;
|
|
||||||
|
|
||||||
app.Use(convert403To401);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AppFunc Convert403To401(AppFunc next)
|
|
||||||
{
|
|
||||||
return env =>
|
|
||||||
{
|
|
||||||
// Execute the SignalR pipeline
|
|
||||||
Task task = next(env);
|
|
||||||
|
|
||||||
// Get the status code
|
|
||||||
int statusCode = 0;
|
|
||||||
if (env.ContainsKey("owin.ResponseStatusCode"))
|
|
||||||
{
|
|
||||||
statusCode = (int)env["owin.ResponseStatusCode"];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If its 403 then convert it to 401 (we shouldn't do
|
|
||||||
// this if it's a cross domain request since it doesn't make sense)
|
|
||||||
if (statusCode == 403)
|
|
||||||
{
|
|
||||||
env["owin.ResponseStatusCode"] = 401;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the original task
|
|
||||||
return task;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Microsoft.AspNet.SignalR;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
using Disco.Data.Repository.Monitor;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.Interop.SignalRHandlers
|
|
||||||
{
|
|
||||||
public class UserHeldDeviceNotifications : PersistentConnection
|
|
||||||
{
|
|
||||||
private static bool subscribed = false;
|
|
||||||
private static object subscribeLock = new object();
|
|
||||||
private static IPersistentConnectionContext notificationContext;
|
|
||||||
|
|
||||||
static UserHeldDeviceNotifications()
|
|
||||||
{
|
|
||||||
if (!subscribed)
|
|
||||||
lock (subscribeLock)
|
|
||||||
if (!subscribed)
|
|
||||||
{
|
|
||||||
notificationContext = GlobalHost.ConnectionManager.GetConnectionContext<UserHeldDeviceNotifications>();
|
|
||||||
|
|
||||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e => e.EntityType == typeof(Job)).Subscribe(JobUpdated);
|
|
||||||
|
|
||||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
|
||||||
e.EntityType == typeof(Device) &&
|
|
||||||
(e.ModifiedProperties.Contains("DeviceModelId") ||
|
|
||||||
e.ModifiedProperties.Contains("DeviceProfileId") ||
|
|
||||||
e.ModifiedProperties.Contains("DeviceBatchId") ||
|
|
||||||
e.ModifiedProperties.Contains("AssignedUserId"))
|
|
||||||
).Subscribe(DeviceUpdated);
|
|
||||||
|
|
||||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
|
||||||
e.EntityType == typeof(User) &&
|
|
||||||
e.ModifiedProperties.Contains("DisplayName")
|
|
||||||
).Subscribe(UserUpdated);
|
|
||||||
|
|
||||||
subscribed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void JobUpdated(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
Job j = (Job)e.Entity;
|
|
||||||
|
|
||||||
if (j.DeviceSerialNumber != null)
|
|
||||||
{
|
|
||||||
var jobDevice = e.dbContext.Devices.Where(d => d.SerialNumber == j.DeviceSerialNumber).FirstOrDefault();
|
|
||||||
|
|
||||||
if (jobDevice.AssignedUserId != null)
|
|
||||||
notificationContext.Connection.Broadcast(jobDevice.AssignedUserId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static void DeviceUpdated(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
Device d = (Device)e.Entity;
|
|
||||||
|
|
||||||
string previouslyAssignedUserId = null;
|
|
||||||
|
|
||||||
if (e.ModifiedProperties.Contains("AssignedUserId"))
|
|
||||||
previouslyAssignedUserId = e.GetPreviousPropertyValue<string>("AssignedUserId");
|
|
||||||
|
|
||||||
e.ExecuteAfterCommit(me =>
|
|
||||||
{
|
|
||||||
if (previouslyAssignedUserId != null)
|
|
||||||
notificationContext.Connection.Broadcast(previouslyAssignedUserId);
|
|
||||||
|
|
||||||
if (d.AssignedUserId != null)
|
|
||||||
notificationContext.Connection.Broadcast(d.AssignedUserId);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private static void UserUpdated(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
User u = (User)e.Entity;
|
|
||||||
|
|
||||||
notificationContext.Connection.Broadcast(u.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Data.Repository.Monitor;
|
|
||||||
using Disco.Models.BI.Job;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using System.Reactive.Linq;
|
|
||||||
|
|
||||||
namespace Disco.BI.JobBI
|
|
||||||
{
|
|
||||||
public class ManagedJobList : JobTableModel, IDisposable
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public Func<IQueryable<Job>, IQueryable<Job>> FilterFunction { get; set; }
|
|
||||||
public Func<IEnumerable<JobTableItemModel>, IEnumerable<JobTableItemModel>> SortFunction { get; set; }
|
|
||||||
private IDisposable unsubscribeToken;
|
|
||||||
private object updateLock = new object();
|
|
||||||
|
|
||||||
public ManagedJobList Initialize(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
// Initially fill table
|
|
||||||
this.Items = this.SortFunction(this.DetermineItems(dbContext, this.FilterFunction(dbContext.Jobs))).ToList();
|
|
||||||
|
|
||||||
// Subscribe for Changes
|
|
||||||
// - Job (or Job Meta) Changes
|
|
||||||
// - Device Profile Address Changes (for multi-campus Schools)
|
|
||||||
// - Device Model Description Changes
|
|
||||||
// - Device's Profile or Model Changes
|
|
||||||
unsubscribeToken = RepositoryMonitor.StreamAfterCommit
|
|
||||||
.Where(n => n.EntityType == typeof(Job) ||
|
|
||||||
n.EntityType == typeof(JobMetaWarranty) ||
|
|
||||||
n.EntityType == typeof(JobMetaNonWarranty) ||
|
|
||||||
n.EntityType == typeof(JobMetaInsurance) ||
|
|
||||||
(n.EventType == RepositoryMonitorEventType.Modified && (
|
|
||||||
(n.EntityType == typeof(DeviceProfile) && n.ModifiedProperties.Contains("DefaultOrganisationAddress")) ||
|
|
||||||
(n.EntityType == typeof(DeviceModel) && n.ModifiedProperties.Contains("Description")) ||
|
|
||||||
(n.EntityType == typeof(Device) && n.ModifiedProperties.Contains("DeviceProfileId") || n.ModifiedProperties.Contains("DeviceModelId"))
|
|
||||||
)))
|
|
||||||
.Subscribe(JobNotification);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void JobNotification(RepositoryMonitorEvent e)
|
|
||||||
{
|
|
||||||
List<int> jobIds = null;
|
|
||||||
JobTableItemModel[] existingItems = null;
|
|
||||||
|
|
||||||
if (e.EntityType == typeof(Job))
|
|
||||||
jobIds = new List<int>() { ((Job)e.Entity).Id };
|
|
||||||
else
|
|
||||||
if (e.EntityType == typeof(JobMetaWarranty))
|
|
||||||
jobIds = new List<int>() { ((JobMetaWarranty)e.Entity).JobId };
|
|
||||||
else
|
|
||||||
if (e.EntityType == typeof(JobMetaNonWarranty))
|
|
||||||
jobIds = new List<int>() { ((JobMetaNonWarranty)e.Entity).JobId };
|
|
||||||
else
|
|
||||||
if (e.EntityType == typeof(JobMetaInsurance))
|
|
||||||
jobIds = new List<int>() { ((JobMetaInsurance)e.Entity).JobId };
|
|
||||||
else
|
|
||||||
if (e.EntityType == typeof(DeviceProfile))
|
|
||||||
{
|
|
||||||
int deviceProfileId = ((DeviceProfile)e.Entity).Id;
|
|
||||||
existingItems = this.Items.Where(i => i.DeviceProfileId == deviceProfileId).ToArray();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (e.EntityType == typeof(DeviceModel))
|
|
||||||
{
|
|
||||||
int deviceModelId = ((DeviceModel)e.Entity).Id;
|
|
||||||
existingItems = this.Items.Where(i => i.DeviceModelId == deviceModelId).ToArray();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (e.EntityType == typeof(Device))
|
|
||||||
{
|
|
||||||
string deviceSerialNumber = ((Device)e.Entity).SerialNumber;
|
|
||||||
existingItems = this.Items.Where(i => i.DeviceSerialNumber == deviceSerialNumber).ToArray();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return; // Subscription should never reach
|
|
||||||
|
|
||||||
if (jobIds == null)
|
|
||||||
{
|
|
||||||
if (existingItems == null)
|
|
||||||
throw new InvalidOperationException("Notification algorithm didn't indicate any Jobs for update");
|
|
||||||
else
|
|
||||||
jobIds = existingItems.Select(i => i.Id).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jobIds.Count == 0)
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
UpdateJobs(e.dbContext, jobIds, existingItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateJobs(DiscoDataContext dbContext, List<int> jobIds, JobTableItemModel[] existingItems = null)
|
|
||||||
{
|
|
||||||
lock (updateLock)
|
|
||||||
{
|
|
||||||
// Check for existing items, if not handed them
|
|
||||||
if (existingItems == null)
|
|
||||||
existingItems = this.Items.Where(i => jobIds.Contains(i.Id)).ToArray();
|
|
||||||
|
|
||||||
var updatedItems = this.DetermineItems(dbContext, this.FilterFunction(dbContext.Jobs.Where(j => jobIds.Contains(j.Id))));
|
|
||||||
|
|
||||||
var refreshedList = this.Items.ToList();
|
|
||||||
|
|
||||||
// Remove Existing
|
|
||||||
if (existingItems.Length > 0)
|
|
||||||
foreach (var existingItem in existingItems)
|
|
||||||
refreshedList.Remove(existingItem);
|
|
||||||
|
|
||||||
// Add Updated Items
|
|
||||||
if (updatedItems.Count > 0)
|
|
||||||
foreach (var updatedItem in updatedItems)
|
|
||||||
refreshedList.Add(updatedItem);
|
|
||||||
|
|
||||||
// Reorder
|
|
||||||
this.Items = this.SortFunction(refreshedList).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (unsubscribeToken != null)
|
|
||||||
{
|
|
||||||
unsubscribeToken.Dispose();
|
|
||||||
unsubscribeToken = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Job;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
|
|
||||||
namespace Disco.BI.JobBI
|
|
||||||
{
|
|
||||||
public static class Searching
|
|
||||||
{
|
|
||||||
public static JobTableModel Search(DiscoDataContext dbContext, string Term, int? LimitCount = null, bool IncludeJobStatus = true, bool SearchDetails = false)
|
|
||||||
{
|
|
||||||
int termInt = default(int);
|
|
||||||
|
|
||||||
IQueryable<Job> query = default(IQueryable<Job>);
|
|
||||||
|
|
||||||
if (int.TryParse(Term, out termInt))
|
|
||||||
{
|
|
||||||
// Term is a Number (int)
|
|
||||||
if (SearchDetails)
|
|
||||||
{
|
|
||||||
query = BuildJobTableModel(dbContext).Where(j =>
|
|
||||||
j.Id == termInt ||
|
|
||||||
j.DeviceHeldLocation.Contains(Term) ||
|
|
||||||
j.Device.SerialNumber.Contains(Term) ||
|
|
||||||
j.Device.AssetNumber.Contains(Term) ||
|
|
||||||
j.User.Id == Term ||
|
|
||||||
j.User.Surname.Contains(Term) ||
|
|
||||||
j.User.GivenName.Contains(Term) ||
|
|
||||||
j.User.DisplayName.Contains(Term) ||
|
|
||||||
j.JobLogs.Any(jl => jl.Comments.Contains(Term)) ||
|
|
||||||
j.JobAttachments.Any(ja => ja.Comments.Contains(Term)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
query = BuildJobTableModel(dbContext).Where(j =>
|
|
||||||
j.Id == termInt ||
|
|
||||||
j.DeviceHeldLocation.Contains(Term) ||
|
|
||||||
j.Device.SerialNumber.Contains(Term) ||
|
|
||||||
j.Device.AssetNumber.Contains(Term) ||
|
|
||||||
j.User.Id == Term ||
|
|
||||||
j.User.Surname.Contains(Term) ||
|
|
||||||
j.User.GivenName.Contains(Term) ||
|
|
||||||
j.User.DisplayName.Contains(Term));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (SearchDetails)
|
|
||||||
{
|
|
||||||
query = BuildJobTableModel(dbContext).Where(j =>
|
|
||||||
j.DeviceHeldLocation.Contains(Term) ||
|
|
||||||
j.Device.SerialNumber.Contains(Term) ||
|
|
||||||
j.Device.AssetNumber.Contains(Term) ||
|
|
||||||
j.User.Id == Term ||
|
|
||||||
j.User.Surname.Contains(Term) ||
|
|
||||||
j.User.GivenName.Contains(Term) ||
|
|
||||||
j.User.DisplayName.Contains(Term) ||
|
|
||||||
j.JobLogs.Any(jl => jl.Comments.Contains(Term)) ||
|
|
||||||
j.JobAttachments.Any(ja => ja.Comments.Contains(Term)));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
query = BuildJobTableModel(dbContext).Where(j =>
|
|
||||||
j.DeviceHeldLocation.Contains(Term) ||
|
|
||||||
j.Device.SerialNumber.Contains(Term) ||
|
|
||||||
j.Device.AssetNumber.Contains(Term) ||
|
|
||||||
j.User.Id == Term ||
|
|
||||||
j.User.Surname.Contains(Term) ||
|
|
||||||
j.User.GivenName.Contains(Term) ||
|
|
||||||
j.User.DisplayName.Contains(Term));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LimitCount.HasValue)
|
|
||||||
query = query.Take(LimitCount.Value);
|
|
||||||
|
|
||||||
JobTableModel model = new JobTableModel() { ShowStatus = IncludeJobStatus };
|
|
||||||
model.Fill(dbContext, query);
|
|
||||||
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IQueryable<Job> BuildJobTableModel(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
return dbContext.Jobs.Include("JobType").Include("Device").Include("User").Include("OpenedTechUser");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Job;
|
|
||||||
|
|
||||||
namespace Disco.BI.JobBI
|
|
||||||
{
|
|
||||||
public static class Utilities
|
|
||||||
{
|
|
||||||
public static Job Create(DiscoDataContext dbContext, Device device, User user, JobType type, List<JobSubType> subTypes, User initialTech)
|
|
||||||
{
|
|
||||||
Job j = new Job()
|
|
||||||
{
|
|
||||||
JobType = type,
|
|
||||||
OpenedTechUserId = initialTech.Id,
|
|
||||||
OpenedTechUser = initialTech,
|
|
||||||
OpenedDate = DateTime.Now
|
|
||||||
};
|
|
||||||
|
|
||||||
// Device
|
|
||||||
if (device != null)
|
|
||||||
{
|
|
||||||
j.Device = device;
|
|
||||||
j.DeviceSerialNumber = device.SerialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
// User
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
j.User = user;
|
|
||||||
j.UserId = user.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sub Types
|
|
||||||
List<JobSubType> jobSubTypes = subTypes.ToList();
|
|
||||||
j.JobSubTypes = jobSubTypes;
|
|
||||||
|
|
||||||
dbContext.Jobs.Add(j);
|
|
||||||
|
|
||||||
switch (type.Id)
|
|
||||||
{
|
|
||||||
case JobType.JobTypeIds.HWar:
|
|
||||||
dbContext.JobMetaWarranties.Add(new JobMetaWarranty() { Job = j });
|
|
||||||
break;
|
|
||||||
case JobType.JobTypeIds.HNWar:
|
|
||||||
dbContext.JobMetaNonWarranties.Add(new JobMetaNonWarranty() { Job = j });
|
|
||||||
if (device != null)
|
|
||||||
{
|
|
||||||
// Add Job Components
|
|
||||||
var components = dbContext.DeviceComponents.Include("JobSubTypes").Where(c => !c.DeviceModelId.HasValue || c.DeviceModelId == j.Device.DeviceModelId);
|
|
||||||
var addedComponents = new List<DeviceComponent>();
|
|
||||||
foreach (var c in components)
|
|
||||||
{
|
|
||||||
if (c.JobSubTypes.Count == 0)
|
|
||||||
{ // No Filter
|
|
||||||
addedComponents.Add(c);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var st in c.JobSubTypes)
|
|
||||||
{
|
|
||||||
foreach (var jst in jobSubTypes)
|
|
||||||
{
|
|
||||||
if (st.JobTypeId == jst.JobTypeId && st.Id == jst.Id)
|
|
||||||
{
|
|
||||||
addedComponents.Add(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (addedComponents.Contains(c))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var c in addedComponents)
|
|
||||||
dbContext.JobComponents.Add(new JobComponent()
|
|
||||||
{
|
|
||||||
Job = j,
|
|
||||||
TechUserId = initialTech.Id,
|
|
||||||
Cost = c.Cost,
|
|
||||||
Description = c.Description
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string JobStatusDescription(string StatusId, Job j = null)
|
|
||||||
{
|
|
||||||
switch (StatusId)
|
|
||||||
{
|
|
||||||
case Job.JobStatusIds.Open:
|
|
||||||
return "Open";
|
|
||||||
case Job.JobStatusIds.Closed:
|
|
||||||
return "Closed";
|
|
||||||
case Job.JobStatusIds.AwaitingWarrantyRepair:
|
|
||||||
if (j == null)
|
|
||||||
return "Awaiting Warranty Repair";
|
|
||||||
else
|
|
||||||
if (j.DeviceHeld.HasValue)
|
|
||||||
return string.Format("Awaiting Warranty Repair ({0})", j.JobMetaWarranty.ExternalName);
|
|
||||||
else
|
|
||||||
return string.Format("Awaiting Warranty Repair - Not Held ({0})", j.JobMetaWarranty.ExternalName);
|
|
||||||
case Job.JobStatusIds.AwaitingRepairs:
|
|
||||||
if (j == null)
|
|
||||||
return "Awaiting Repairs";
|
|
||||||
else
|
|
||||||
if (j.DeviceHeld.HasValue)
|
|
||||||
return string.Format("Awaiting Repairs ({0})", j.JobMetaNonWarranty.RepairerName);
|
|
||||||
else
|
|
||||||
return string.Format("Awaiting Repairs - Not Held ({0})", j.JobMetaNonWarranty.RepairerName);
|
|
||||||
case Job.JobStatusIds.AwaitingDeviceReturn:
|
|
||||||
return "Awaiting Device Return";
|
|
||||||
case Job.JobStatusIds.AwaitingUserAction:
|
|
||||||
return "Awaiting User Action";
|
|
||||||
case Job.JobStatusIds.AwaitingAccountingPayment:
|
|
||||||
return "Awaiting Accounting Payment";
|
|
||||||
case Job.JobStatusIds.AwaitingAccountingCharge:
|
|
||||||
return "Awaiting Accounting Charge";
|
|
||||||
case Job.JobStatusIds.AwaitingInsuranceProcessing:
|
|
||||||
return "Awaiting Insurance Processing";
|
|
||||||
default:
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static string JobStatusDescription(string StatusId, JobTableModel.JobTableItemModelIncludeStatus j = null)
|
|
||||||
{
|
|
||||||
switch (StatusId)
|
|
||||||
{
|
|
||||||
case Job.JobStatusIds.Open:
|
|
||||||
return "Open";
|
|
||||||
case Job.JobStatusIds.Closed:
|
|
||||||
return "Closed";
|
|
||||||
case Job.JobStatusIds.AwaitingWarrantyRepair:
|
|
||||||
if (j == null)
|
|
||||||
return "Awaiting Warranty Repair";
|
|
||||||
else
|
|
||||||
if (j.DeviceHeld.HasValue)
|
|
||||||
return string.Format("Awaiting Warranty Repair ({0})", j.JobMetaWarranty_ExternalName);
|
|
||||||
else
|
|
||||||
return string.Format("Awaiting Warranty Repair - Not Held ({0})", j.JobMetaWarranty_ExternalName);
|
|
||||||
case Job.JobStatusIds.AwaitingRepairs:
|
|
||||||
if (j == null)
|
|
||||||
return "Awaiting Repairs";
|
|
||||||
else
|
|
||||||
if (j.DeviceHeld.HasValue)
|
|
||||||
return string.Format("Awaiting Repairs ({0})", j.JobMetaNonWarranty_RepairerName);
|
|
||||||
else
|
|
||||||
return string.Format("Awaiting Repairs - Not Held ({0})", j.JobMetaNonWarranty_RepairerName);
|
|
||||||
case Job.JobStatusIds.AwaitingDeviceReturn:
|
|
||||||
return "Awaiting Device Return";
|
|
||||||
case Job.JobStatusIds.AwaitingUserAction:
|
|
||||||
return "Awaiting User Action";
|
|
||||||
case Job.JobStatusIds.AwaitingAccountingPayment:
|
|
||||||
return "Awaiting Accounting Payment";
|
|
||||||
case Job.JobStatusIds.AwaitingAccountingCharge:
|
|
||||||
return "Awaiting Accounting Charge";
|
|
||||||
case Job.JobStatusIds.AwaitingInsuranceProcessing:
|
|
||||||
return "Awaiting Insurance Processing";
|
|
||||||
default:
|
|
||||||
return "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.BI.Search;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
|
|
||||||
namespace Disco.BI.UserBI
|
|
||||||
{
|
|
||||||
public static class Searching
|
|
||||||
{
|
|
||||||
|
|
||||||
public static List<User> SearchUpstream(string Term)
|
|
||||||
{
|
|
||||||
return Interop.ActiveDirectory.ActiveDirectory.SearchUsers(Term).Select(adU => adU.ToRepositoryUser()).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<UserSearchResultItem> Search_SelectUserSearchResultItems(IQueryable<User> Query, int? LimitCount = null)
|
|
||||||
{
|
|
||||||
if (LimitCount.HasValue)
|
|
||||||
Query = Query.Take(LimitCount.Value);
|
|
||||||
|
|
||||||
return Query.Select(u => new UserSearchResultItem()
|
|
||||||
{
|
|
||||||
Id = u.Id,
|
|
||||||
Surname = u.Surname,
|
|
||||||
GivenName = u.GivenName,
|
|
||||||
DisplayName = u.DisplayName,
|
|
||||||
AssignedDevicesCount = u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).Count(),
|
|
||||||
JobCount = u.Jobs.Count()
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<UserSearchResultItem> Search(DiscoDataContext dbContext, string Term, int? LimitCount = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(Term) || Term.Length < 2)
|
|
||||||
throw new ArgumentException("Search Term must contain at least two characters", "Term");
|
|
||||||
|
|
||||||
// Search Active Directory & Import Relevant Users
|
|
||||||
var adImportedUsers = Interop.ActiveDirectory.ActiveDirectory.SearchUsers(Term).Select(adU => adU.ToRepositoryUser());
|
|
||||||
foreach (var adU in adImportedUsers)
|
|
||||||
{
|
|
||||||
var existingUser = dbContext.Users.Find(adU.Id);
|
|
||||||
if (existingUser != null)
|
|
||||||
existingUser.UpdateSelf(adU);
|
|
||||||
else
|
|
||||||
dbContext.Users.Add(adU);
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
UserCache.InvalidateValue(adU.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Search_SelectUserSearchResultItems(dbContext.Users.Where(u =>
|
|
||||||
u.Id.Contains(Term) ||
|
|
||||||
u.Surname.Contains(Term) ||
|
|
||||||
u.GivenName.Contains(Term) ||
|
|
||||||
u.DisplayName.Contains(Term)
|
|
||||||
), LimitCount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using System.Web;
|
|
||||||
using Quartz;
|
|
||||||
using Quartz.Impl;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.BI.UserBI
|
|
||||||
{
|
|
||||||
public class UserCache
|
|
||||||
{
|
|
||||||
private static ConcurrentDictionary<string, Tuple<User, DateTime>> _Cache = new ConcurrentDictionary<string, Tuple<User, DateTime>>();
|
|
||||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
|
||||||
private const string CacheHttpRequestKey = "Disco_CurrentUser";
|
|
||||||
|
|
||||||
public static User CurrentUser
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
string username = null;
|
|
||||||
User user;
|
|
||||||
|
|
||||||
// Check for ASP.NET
|
|
||||||
if (HttpContext.Current != null)
|
|
||||||
{
|
|
||||||
if (HttpContext.Current.Request.IsAuthenticated)
|
|
||||||
{
|
|
||||||
user = (User)HttpContext.Current.Items[CacheHttpRequestKey];
|
|
||||||
if (user != null)
|
|
||||||
return user;
|
|
||||||
|
|
||||||
username = HttpContext.Current.User.Identity.Name;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
//throw new PlatformNotSupportedException("ASP.NET Authentication is not correctly configured");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// User default User
|
|
||||||
if (username == null)
|
|
||||||
{
|
|
||||||
username = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
user = GetUser(username);
|
|
||||||
|
|
||||||
if (HttpContext.Current != null && HttpContext.Current.Request.IsAuthenticated)
|
|
||||||
{
|
|
||||||
// Cache in current request
|
|
||||||
HttpContext.Current.Items[CacheHttpRequestKey] = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User GetUser(string Username)
|
|
||||||
{
|
|
||||||
// Check Cache
|
|
||||||
User u = TryUserCache(Username);
|
|
||||||
|
|
||||||
if (u == null)
|
|
||||||
{
|
|
||||||
// Load from Repository
|
|
||||||
using (DiscoDataContext dbContext = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
u = GetUser(Username, dbContext, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static User GetUser(string Username, DiscoDataContext dbContext, bool ForceRefresh = false)
|
|
||||||
{
|
|
||||||
User u = null;
|
|
||||||
|
|
||||||
// Check Cache
|
|
||||||
if (!ForceRefresh)
|
|
||||||
u = TryUserCache(Username);
|
|
||||||
|
|
||||||
if (u == null)
|
|
||||||
{
|
|
||||||
string username = Username.ToLower();
|
|
||||||
u = UserBI.Utilities.LoadUser(dbContext, username);
|
|
||||||
SetValue(username, u);
|
|
||||||
}
|
|
||||||
return u;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static User TryUserCache(string Username)
|
|
||||||
{
|
|
||||||
string username = Username.ToLower();
|
|
||||||
Tuple<User, DateTime> userRecord;
|
|
||||||
if (_Cache.TryGetValue(username, out userRecord))
|
|
||||||
{
|
|
||||||
if (userRecord.Item2 > DateTime.Now)
|
|
||||||
return userRecord.Item1;
|
|
||||||
else
|
|
||||||
_Cache.TryRemove(username, out userRecord);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool InvalidateValue(string Key)
|
|
||||||
{
|
|
||||||
Tuple<User, DateTime> userRecord;
|
|
||||||
return _Cache.TryRemove(Key.ToLower(), out userRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool SetValue(string Key, User User)
|
|
||||||
{
|
|
||||||
string key = Key.ToLower();
|
|
||||||
Tuple<User, DateTime> userRecord = new Tuple<User, DateTime>(User, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
|
||||||
if (_Cache.ContainsKey(key))
|
|
||||||
{
|
|
||||||
Tuple<User, DateTime> oldUser;
|
|
||||||
if (_Cache.TryGetValue(key, out oldUser))
|
|
||||||
{
|
|
||||||
return _Cache.TryUpdate(key, userRecord, oldUser);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _Cache.TryAdd(key, userRecord);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void CleanStaleCache()
|
|
||||||
{
|
|
||||||
var usernames = _Cache.Keys.ToArray();
|
|
||||||
foreach (string username in usernames)
|
|
||||||
{
|
|
||||||
Tuple<User, DateTime> userRecord;
|
|
||||||
if (_Cache.TryGetValue(username, out userRecord))
|
|
||||||
{
|
|
||||||
if (userRecord.Item2 <= DateTime.Now)
|
|
||||||
_Cache.TryRemove(username, out userRecord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Search;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.DirectoryServices.ActiveDirectory;
|
|
||||||
using Disco.Services.Logging;
|
|
||||||
|
|
||||||
namespace Disco.BI.UserBI
|
|
||||||
{
|
|
||||||
public static class Utilities
|
|
||||||
{
|
|
||||||
|
|
||||||
public static User LoadUser(DiscoDataContext dbContext, string Username)
|
|
||||||
{
|
|
||||||
// Machine Account ?
|
|
||||||
if (Username.EndsWith("$"))
|
|
||||||
{
|
|
||||||
return Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(Username).ToRepositoryUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
// User Account
|
|
||||||
User user = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ADUser = Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(Username);
|
|
||||||
if (ADUser == null)
|
|
||||||
throw new ArgumentException(string.Format("Invalid Username: '{0}'", Username), "Username");
|
|
||||||
user = ADUser.ToRepositoryUser();
|
|
||||||
}
|
|
||||||
catch (COMException ex)
|
|
||||||
{
|
|
||||||
// If "Server is not operational" then Try Cache
|
|
||||||
if (ex.ErrorCode != -2147016646)
|
|
||||||
{
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
SystemLog.LogException("Primary Domain Controller Down? Disco.BI.UserBI.Utilities.LoadUser", ex);
|
|
||||||
}
|
|
||||||
catch (ActiveDirectoryOperationException ex)
|
|
||||||
{
|
|
||||||
// Try From Cache...
|
|
||||||
SystemLog.LogException("Primary Domain Controller Down? Disco.BI.UserBI.Utilities.LoadUser", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Repository
|
|
||||||
User existingUser;
|
|
||||||
if (user == null)
|
|
||||||
{
|
|
||||||
string username = Username.Contains(@"\") ? Username.Substring(Username.IndexOf(@"\") + 1) : Username;
|
|
||||||
existingUser = dbContext.Users.Find(username);
|
|
||||||
if (existingUser == null)
|
|
||||||
throw new ArgumentException(string.Format("Invalid User - Not In Disco DB: '{0}'", Username), "Username");
|
|
||||||
else
|
|
||||||
return existingUser;
|
|
||||||
}
|
|
||||||
existingUser = dbContext.Users.Find(user.Id);
|
|
||||||
if (existingUser == null)
|
|
||||||
{
|
|
||||||
dbContext.Users.Add(user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
existingUser.UpdateSelf(user);
|
|
||||||
user = existingUser;
|
|
||||||
}
|
|
||||||
dbContext.SaveChanges();
|
|
||||||
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
using Disco.BI.Wireless.eduSTAR;
|
|
||||||
using Disco.Data.Configuration;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
namespace Disco.BI.Wireless
|
|
||||||
{
|
|
||||||
public abstract class BaseWirelessProvider
|
|
||||||
{
|
|
||||||
protected DiscoDataContext dbContext;
|
|
||||||
private static object _CertificateAllocateLock = System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(new object());
|
|
||||||
public static BaseWirelessProvider GetProvider(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string provider = dbContext.DiscoConfiguration.Wireless.Provider;
|
|
||||||
if (provider == "eduSTAR")
|
|
||||||
{
|
|
||||||
return new eduSTARWirelessProvider(dbContext);
|
|
||||||
}
|
|
||||||
throw new System.NotSupportedException(string.Format("Wireless Provider Not Supported: '{0}'", dbContext.DiscoConfiguration.Wireless.Provider));
|
|
||||||
}
|
|
||||||
protected BaseWirelessProvider(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
this.dbContext = dbContext;
|
|
||||||
}
|
|
||||||
private DeviceCertificate CertificateAllocate(ref Device repoDevice)
|
|
||||||
{
|
|
||||||
lock (BaseWirelessProvider._CertificateAllocateLock)
|
|
||||||
{
|
|
||||||
this.FillCertificateAutoBuffer();
|
|
||||||
int timeout = 60;
|
|
||||||
int freeCertCount = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).Count();
|
|
||||||
while (!(freeCertCount > 0 | timeout <= 0))
|
|
||||||
{
|
|
||||||
System.Threading.Thread.Sleep(500);
|
|
||||||
freeCertCount = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).Count();
|
|
||||||
timeout--;
|
|
||||||
}
|
|
||||||
DeviceCertificate cert = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).FirstOrDefault();
|
|
||||||
if (cert == null)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogAllocationFailed(repoDevice.SerialNumber);
|
|
||||||
throw new System.InvalidOperationException("Unable to Allocate a Wireless Certificate");
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.LogAllocated(cert.Name, repoDevice.SerialNumber);
|
|
||||||
cert.DeviceSerialNumber = repoDevice.SerialNumber;
|
|
||||||
cert.AllocatedDate = System.DateTime.Now;
|
|
||||||
this.dbContext.SaveChanges();
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public DeviceCertificate Enrol(Device repoDevice)
|
|
||||||
{
|
|
||||||
DeviceCertificate allocatedCert = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == repoDevice.SerialNumber && c.Enabled).FirstOrDefault();
|
|
||||||
if (allocatedCert != null)
|
|
||||||
{
|
|
||||||
return allocatedCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
|
||||||
//if (repoDevice.DeviceProfile.Configuration(this.dbContext).AllocateWirelessCertificate)
|
|
||||||
if (repoDevice.DeviceProfile.AllocateCertificate)
|
|
||||||
{
|
|
||||||
allocatedCert = this.CertificateAllocate(ref repoDevice);
|
|
||||||
return allocatedCert;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected abstract void FillCertificateAutoBuffer();
|
|
||||||
public abstract void FillCertificateBuffer(int Amount);
|
|
||||||
public abstract System.Collections.Generic.List<string> RemoveExistingCertificateNames();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
using Disco.Logging;
|
|
||||||
using Disco.Logging.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
namespace Disco.BI.Wireless
|
|
||||||
{
|
|
||||||
public class WirelessCertificatesLog : LogBase
|
|
||||||
{
|
|
||||||
public enum EventTypeIds
|
|
||||||
{
|
|
||||||
RetrievalStarting = 10,
|
|
||||||
RetrievalProgress,
|
|
||||||
RetrievalFinished,
|
|
||||||
RetrievalWarning = 15,
|
|
||||||
RetrievalError,
|
|
||||||
RetrievalCertificateStarting = 20,
|
|
||||||
RetrievalCertificateFinished = 22,
|
|
||||||
RetrievalCertificateWarning = 25,
|
|
||||||
RetrievalCertificateError,
|
|
||||||
Allocated = 40,
|
|
||||||
AllocationFailed = 50
|
|
||||||
}
|
|
||||||
private const int _ModuleId = 60;
|
|
||||||
private static bool _IsCertificateRetrievalProcessing;
|
|
||||||
private static string _CertificateRetrievalStatus;
|
|
||||||
private static int _CertificateRetrievalProgress;
|
|
||||||
public static WirelessCertificatesLog Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (WirelessCertificatesLog)LogContext.LogModules[60];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static bool IsCertificateRetrievalProcessing
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return WirelessCertificatesLog._IsCertificateRetrievalProcessing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Wireless Certificates";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override int ModuleId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return 60;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "WirelessCertificates";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[System.Diagnostics.DebuggerNonUserCode]
|
|
||||||
public WirelessCertificatesLog()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
private static void Log(WirelessCertificatesLog.EventTypeIds EventTypeId, params object[] Args)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Current.Log((int)EventTypeId, Args);
|
|
||||||
}
|
|
||||||
public static void LogRetrievalStarting(int CertificateCount, int CertificateIdFrom, int CertificateIdTo)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalStarting, new object[]
|
|
||||||
{
|
|
||||||
CertificateCount,
|
|
||||||
CertificateIdFrom,
|
|
||||||
CertificateIdTo
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalFinished()
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalFinished, new object[0]);
|
|
||||||
}
|
|
||||||
public static void LogRetrievalWarning(string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalWarning, new object[]
|
|
||||||
{
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalError(string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalError, new object[]
|
|
||||||
{
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateStarting(string CertificateId)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateStarting, new object[]
|
|
||||||
{
|
|
||||||
CertificateId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateFinished(string CertificateId)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateFinished, new object[]
|
|
||||||
{
|
|
||||||
CertificateId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateWarning(string CertificateId, string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateWarning, new object[]
|
|
||||||
{
|
|
||||||
CertificateId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateError(string CertificateId, string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateError, new object[]
|
|
||||||
{
|
|
||||||
CertificateId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogAllocated(string CertificateId, string DeviceSerialNumber)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.Allocated, new object[]
|
|
||||||
{
|
|
||||||
CertificateId,
|
|
||||||
DeviceSerialNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogAllocationFailed(string DeviceSerialNumber)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.AllocationFailed, new object[]
|
|
||||||
{
|
|
||||||
DeviceSerialNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogCertificateRetrievalProgress(bool? IsProcessing, int? Progress, string Status)
|
|
||||||
{
|
|
||||||
bool flag = IsProcessing.HasValue;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._IsCertificateRetrievalProcessing = IsProcessing.Value;
|
|
||||||
}
|
|
||||||
flag = WirelessCertificatesLog._IsCertificateRetrievalProcessing;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
bool flag2 = Status != null;
|
|
||||||
if (flag2)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalStatus = Status;
|
|
||||||
}
|
|
||||||
flag2 = Progress.HasValue;
|
|
||||||
if (flag2)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalProgress = Progress.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalStatus = null;
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalProgress = 0;
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalProgress, new object[]
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._IsCertificateRetrievalProcessing,
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalProgress,
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalStatus
|
|
||||||
});
|
|
||||||
}
|
|
||||||
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<LogEventType>
|
|
||||||
{
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 10,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Starting",
|
|
||||||
Format = "Starting retrieval of {0} certificate/s ({1} to {2})",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 11,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Progress",
|
|
||||||
Format = "Processing: {0}; {1}% Complete; Status: {2}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 12,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Finished",
|
|
||||||
Format = "Retrieval of Certificates Complete",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 15,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Warning",
|
|
||||||
Format = "Retrieval Warning: {0}",
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 16,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Error",
|
|
||||||
Format = "Retrieval Error: {0}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 20,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Starting",
|
|
||||||
Format = "Retrieving Certificate: {0}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 22,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Finished",
|
|
||||||
Format = "Certificate Retrieved: {0}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 25,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Warning",
|
|
||||||
Format = "{0} Certificate Warning: {1}",
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 26,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Error",
|
|
||||||
Format = "{0} Certificate Error: {1}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 40,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Allocated",
|
|
||||||
Format = "Certificate {0} allocated to {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 50,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Allocation Failed",
|
|
||||||
Format = "No certificates available for Device: {0}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
using Disco.BI.Wireless.eduSTAR.eduSTARWirelessCertService;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Ionic.Zip;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.ServiceModel;
|
|
||||||
using System.ServiceModel.Channels;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Disco.BI.Wireless.eduSTAR
|
|
||||||
{
|
|
||||||
public class eduSTARWirelessProvider : BaseWirelessProvider
|
|
||||||
{
|
|
||||||
private class BulkLoadCertificatesContract
|
|
||||||
{
|
|
||||||
public int Start { get; set; }
|
|
||||||
public int Count { get; set; }
|
|
||||||
}
|
|
||||||
private static object _BulkLoadThreadLock = new object();
|
|
||||||
private static System.Threading.Thread _BulkLoadThread;
|
|
||||||
public eduSTARWirelessProvider(DiscoDataContext dbContext)
|
|
||||||
: base(dbContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
protected override void FillCertificateAutoBuffer()
|
|
||||||
{
|
|
||||||
int freeCertCount = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).Count();
|
|
||||||
if (freeCertCount <= this.dbContext.DiscoConfiguration.Wireless.CertificateAutoBufferLow)
|
|
||||||
{
|
|
||||||
this.BulkLoadCertificates(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override void FillCertificateBuffer(int Amount)
|
|
||||||
{
|
|
||||||
this.BulkLoadCertificates(Amount);
|
|
||||||
}
|
|
||||||
public override System.Collections.Generic.List<string> RemoveExistingCertificateNames()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<string>
|
|
||||||
{
|
|
||||||
"(eduPaSS)",
|
|
||||||
"(CN=Computers, ?DC=services, ?DC=education, ?DC=vic, ?DC=gov, ?DC=au)"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
private void BulkLoadCertificates(int Amount = 0)
|
|
||||||
{
|
|
||||||
if (eduSTARWirelessProvider._BulkLoadThread == null)
|
|
||||||
{
|
|
||||||
lock (eduSTARWirelessProvider._BulkLoadThreadLock)
|
|
||||||
{
|
|
||||||
if (eduSTARWirelessProvider._BulkLoadThread == null)
|
|
||||||
{
|
|
||||||
int start = 0;
|
|
||||||
if (this.dbContext.DeviceCertificates.Count() > 0)
|
|
||||||
{
|
|
||||||
start = this.dbContext.DeviceCertificates.Max(c => c.ProviderIndex) + 1;
|
|
||||||
}
|
|
||||||
int buffer = this.dbContext.DeviceCertificates.Count(c => c.DeviceSerialNumber == null && c.Enabled);
|
|
||||||
int count = this.dbContext.DiscoConfiguration.Wireless.CertificateAutoBufferMax - buffer;
|
|
||||||
if (Amount > 0)
|
|
||||||
{
|
|
||||||
count = Amount;
|
|
||||||
}
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
eduSTARWirelessProvider.BulkLoadCertificatesContract contract = new eduSTARWirelessProvider.BulkLoadCertificatesContract
|
|
||||||
{
|
|
||||||
Start = start,
|
|
||||||
Count = count
|
|
||||||
};
|
|
||||||
System.Threading.ParameterizedThreadStart threadStart = delegate(object a0)
|
|
||||||
{
|
|
||||||
this.BulkLoadCertificatesStart((eduSTARWirelessProvider.BulkLoadCertificatesContract)a0);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
eduSTARWirelessProvider._BulkLoadThread = new System.Threading.Thread(threadStart);
|
|
||||||
eduSTARWirelessProvider._BulkLoadThread.Start(contract);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void BulkLoadCertificatesStart(eduSTARWirelessProvider.BulkLoadCertificatesContract contract)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalStarting(contract.Count, contract.Start, contract.Start + contract.Count - 1);
|
|
||||||
WirelessCertificatesLog.LogCertificateRetrievalProgress(true, 0, string.Format("Starting Bulk Retrieval (Loading {0} Certificate/s)", contract.Count));
|
|
||||||
DiscoDataContext dbLocalContext = new DiscoDataContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WirelessCertServiceSoapClient proxy = this.GetProxy();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int num = contract.Start + contract.Count - 1;
|
|
||||||
int index = contract.Start;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int num2 = num;
|
|
||||||
if (index > num2)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.LogCertificateRetrievalProgress(true, (int)System.Math.Round(unchecked(((double)checked(index - contract.Start) + 0.5) / (double)contract.Count * 100.0)), string.Format("Retrieving Certificate {0} of {1}", index - contract.Start + 1, contract.Count));
|
|
||||||
DeviceCertificate cert = this.LoadCertificate(index, proxy, dbLocalContext);
|
|
||||||
dbLocalContext.DeviceCertificates.Add(cert);
|
|
||||||
dbLocalContext.SaveChanges();
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateFinished(cert.Name);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bool flag = proxy != null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)proxy).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bool flag = dbLocalContext != null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)dbLocalContext).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalError(string.Format("[{0}] {1}", ex.GetType().Name, ex.Message));
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
lock (eduSTARWirelessProvider._BulkLoadThreadLock)
|
|
||||||
{
|
|
||||||
eduSTARWirelessProvider._BulkLoadThread = null;
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.LogRetrievalFinished();
|
|
||||||
WirelessCertificatesLog.LogCertificateRetrievalProgress(false, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private DeviceCertificate LoadCertificate(int Index, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
DeviceCertificate LoadCertificate;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WirelessCertServiceSoapClient proxy = this.GetProxy();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LoadCertificate = this.LoadCertificate(Index, proxy, dbContext);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bool flag = proxy != null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)proxy).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateError(Index.ToString(), string.Format("[{0}] {1}", ex.GetType().Name, ex.Message));
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
return LoadCertificate;
|
|
||||||
}
|
|
||||||
private DeviceCertificate LoadCertificate(int Index, WirelessCertServiceSoapClient Proxy, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
bool flag = string.IsNullOrWhiteSpace(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountSchoolId);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Wireless Certificates: Invalid ServiceAccount SchoolId");
|
|
||||||
}
|
|
||||||
flag = string.IsNullOrWhiteSpace(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountUsername);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Wireless Certificates: Invalid ServiceAccount Username");
|
|
||||||
}
|
|
||||||
flag = string.IsNullOrWhiteSpace(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountPassword);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Wireless Certificates: Invalid ServiceAccount Password");
|
|
||||||
}
|
|
||||||
DeviceCertificate cert = new DeviceCertificate
|
|
||||||
{
|
|
||||||
ProviderIndex = Index,
|
|
||||||
Name = string.Format("{0}-{1}", dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountSchoolId, Index.ToString("00000")),
|
|
||||||
Enabled = true
|
|
||||||
};
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateStarting(cert.Name);
|
|
||||||
string response;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response = Proxy.GetWirelessCert(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountSchoolId, cert.Name, "password", dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountUsername, dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountPassword);
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateError(cert.Name, ex.Message);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] responseBytes = System.Convert.FromBase64String(response);
|
|
||||||
System.IO.MemoryStream responseByteStream = new System.IO.MemoryStream(responseBytes);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ZipFile responseZip = ZipFile.Read(responseByteStream);
|
|
||||||
ZipEntry certFile = responseZip.FirstOrDefault((ZipEntry ze) => ze.FileName.EndsWith(".pfx", System.StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
System.IO.MemoryStream certByteStream = new System.IO.MemoryStream();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
certFile.Extract(certByteStream);
|
|
||||||
cert.Content = certByteStream.ToArray();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
flag = (certByteStream != null);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)certByteStream).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
flag = (responseByteStream != null);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)responseByteStream).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex2)
|
|
||||||
{
|
|
||||||
if (response.Contains("Computer with this name already exists"))
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateWarning(cert.Name, "Already exists on eduSTAR server, disabling and skipping.");
|
|
||||||
cert.ExpirationDate = System.DateTime.Now;
|
|
||||||
cert.Enabled = false;
|
|
||||||
cert.Content = null;
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
throw new System.InvalidOperationException(string.Format("Unable to Uncompress (Server returned: {0})", response), ex2);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
X509Certificate2 x509Cert = new X509Certificate2(cert.Content, "password");
|
|
||||||
cert.ExpirationDate = x509Cert.NotAfter;
|
|
||||||
}
|
|
||||||
catch (System.Exception ex3)
|
|
||||||
{
|
|
||||||
throw new System.InvalidOperationException("Invalid Certificate returned by Server", ex3);
|
|
||||||
}
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
private WirelessCertServiceSoapClient GetProxy()
|
|
||||||
{
|
|
||||||
BasicHttpBinding binding = new BasicHttpBinding();
|
|
||||||
|
|
||||||
// Don't Use Proxy
|
|
||||||
binding.UseDefaultWebProxy = false;
|
|
||||||
binding.ProxyAddress = null;
|
|
||||||
|
|
||||||
binding.Security.Mode = BasicHttpSecurityMode.Transport;
|
|
||||||
binding.MaxReceivedMessageSize = 524288L;
|
|
||||||
binding.ReaderQuotas.MaxStringContentLength = 524288;
|
|
||||||
EndpointAddress endpointAddress = new EndpointAddress(new Uri("https://www.eduweb.vic.gov.au/edustar/WirelessCertWS/wirelesscertws.asmx"), new AddressHeader[0]);
|
|
||||||
return new WirelessCertServiceSoapClient(binding, endpointAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+14
-161
@@ -10,7 +10,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>Disco</RootNamespace>
|
<RootNamespace>Disco</RootNamespace>
|
||||||
<AssemblyName>Disco.BI</AssemblyName>
|
<AssemblyName>Disco.BI</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||||
@@ -37,50 +37,15 @@
|
|||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="BitMiracle.LibTiff.NET">
|
|
||||||
<HintPath>..\Resources\Libraries\LibTiff.NET\BitMiracle.LibTiff.NET.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="EntityFramework">
|
<Reference Include="EntityFramework">
|
||||||
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
|
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="itextsharp">
|
<Reference Include="itextsharp">
|
||||||
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="LumenWorks.Framework.IO">
|
|
||||||
<HintPath>..\..\..\Resources\Libraries\LumenWorks.Framework.IO\LumenWorks.Framework.IO.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.1.2\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.1.2\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Owin.Host.SystemWeb">
|
|
||||||
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<Private>True</Private>
|
|
||||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\packages\Newtonsoft.Json.5.0.5\lib\net45\Newtonsoft.Json.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Owin">
|
|
||||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Quartz">
|
<Reference Include="Quartz">
|
||||||
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Spring.Core">
|
|
||||||
<HintPath>..\Resources\Libraries\Spring.NET\Spring.Core.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -88,20 +53,13 @@
|
|||||||
<Reference Include="System.DirectoryServices" />
|
<Reference Include="System.DirectoryServices" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Management" />
|
<Reference Include="System.Management" />
|
||||||
<Reference Include="System.Reactive.Core, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="System.Net.Http.Extensions, Version=2.2.22.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll</HintPath>
|
||||||
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Reactive.Interfaces, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="System.Net.Http.Primitives, Version=4.2.22.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll</HintPath>
|
||||||
<HintPath>..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll</HintPath>
|
<Private>True</Private>
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reactive.Linq, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reactive.PlatformServices">
|
|
||||||
<HintPath>..\packages\Rx-PlatformServices.2.1.30214.0\lib\Net45\System.Reactive.PlatformServices.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Runtime.Serialization" />
|
<Reference Include="System.Runtime.Serialization" />
|
||||||
<Reference Include="System.ServiceModel" />
|
<Reference Include="System.ServiceModel" />
|
||||||
@@ -111,98 +69,11 @@
|
|||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Tamir.SharpSSH">
|
|
||||||
<HintPath>..\Resources\Libraries\SharpSSH\Tamir.SharpSSH.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="zxing">
|
|
||||||
<HintPath>..\Resources\Libraries\ZXing\zxing.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="BI\DataStore.cs" />
|
|
||||||
<Compile Include="BI\AttachmentBI\Utilities.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\BatchUtilities.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\DeviceModelBI.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Importing\Export.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Importing\Import.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Importing\ImportParseTask.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Importing\ImportProcessTask.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Searching.cs" />
|
|
||||||
<Compile Include="BI\DisposableImageCollection.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\DocumentTemplateQRCodeLocationCache.cs" />
|
|
||||||
<Compile Include="BI\Expressions\EvaluateExpressionParseException.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionCachePreloadTask.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\DataExt.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\DeviceExt.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageExt.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\BaseImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\FileMontageImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\FileImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\ImageResultImplementations\BitmapImageExpressionResult.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Extensions\UserExt.cs" />
|
|
||||||
<Compile Include="BI\Extensions\AttachmentActionExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\AttachmentExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\ClientServicesExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DeviceActionExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DeviceBatchExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DeviceCertificateExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DeviceModelExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DeviceProfileExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\JobActionExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\JobExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\JobFlagExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\JobTableExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\UserExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\WirelessCertificateExtensions.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DeviceExtensions.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\EnrolSafeException.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Enrol.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\EnrolmentLog.cs" />
|
|
||||||
<Compile Include="BI\Extensions\DocumentTemplateExtensions.cs" />
|
<Compile Include="BI\Extensions\DocumentTemplateExtensions.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\Utilities.cs" />
|
<Compile Include="BI\Interop\Pdf\Utilities.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\DocumentUniqueIdentifier.cs" />
|
|
||||||
<Compile Include="BI\Expressions\EvaluateExpressionPart.cs" />
|
|
||||||
<Compile Include="BI\Expressions\Expression.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionTypeDescriptor.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionTypeMemberDescriptor.cs" />
|
|
||||||
<Compile Include="BI\Expressions\IExpressionPart.cs" />
|
|
||||||
<Compile Include="BI\Expressions\TextExpressionPart.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentDropBoxMonitor.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterJob.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterCleanCacheJob.cs" />
|
|
||||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterLog.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectory.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryCachedGroups.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryHelpers.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryMachineAccountExtensions.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryOrganisationalUnit.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryUpdateLastNetworkLogonDateJob.cs" />
|
|
||||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryUserAccountExtensions.cs" />
|
|
||||||
<Compile Include="BI\Expressions\ExpressionCache.cs" />
|
|
||||||
<Compile Include="BI\Interop\Community\UpdateCheck.cs" />
|
|
||||||
<Compile Include="BI\Interop\Community\UpdateCheckTask.cs" />
|
|
||||||
<Compile Include="BI\Interop\MimeTypes.cs" />
|
|
||||||
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
||||||
<Compile Include="BI\Interop\Pdf\PdfImporter.cs" />
|
|
||||||
<Compile Include="BI\Interop\PluginServices\IDiscoScheduledTask.cs" />
|
|
||||||
<Compile Include="BI\Interop\PluginServices\Utilities.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\AdminAuthorizedPersistentConnection.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\AuthorizedPersistentConnection.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\HeldDeviceNotifications.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\LogNotifications.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\RepositoryMonitorNotifications.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\ScheduledTasksStatusNotifications.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\SignalRAuthenticationWorkaround.cs" />
|
|
||||||
<Compile Include="BI\Interop\SignalRHandlers\UserHeldDeviceNotifications.cs" />
|
|
||||||
<Compile Include="BI\JobBI\ManagedJobList.cs" />
|
|
||||||
<Compile Include="BI\JobBI\Searching.cs" />
|
|
||||||
<Compile Include="BI\JobBI\Statistics\DailyOpenedClosed.cs" />
|
|
||||||
<Compile Include="BI\JobBI\Utilities.cs" />
|
|
||||||
<Compile Include="BI\UserBI\Searching.cs" />
|
|
||||||
<Compile Include="BI\UserBI\UserCache.cs" />
|
|
||||||
<Compile Include="BI\UserBI\UserCachePruneTask.cs" />
|
|
||||||
<Compile Include="BI\UserBI\Utilities.cs" />
|
|
||||||
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
@@ -232,34 +103,16 @@
|
|||||||
<EmbeddedResource Include="Properties\Resources.resx">
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\MimeType-img16.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\MimeType-pdf16.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\EmptyLogo.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\MimeType-doc48.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\MimeType-pdf48.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\MimeType-unknown48.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup />
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<Import Project="..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets" Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" />
|
||||||
<VisualStudio>
|
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
|
||||||
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
<Error Condition="!Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=317567." HelpKeyword="BCLBUILD2001" />
|
||||||
</VisualStudio>
|
<Error Condition="Exists('..\packages\Microsoft.Bcl.Build.1.0.14\tools\Microsoft.Bcl.Build.targets')" Text="The build restored NuGet packages. Build the project again to include these packages in the build. For more information, see http://go.microsoft.com/fwlink/?LinkID=317568." HelpKeyword="BCLBUILD2002" />
|
||||||
</ProjectExtensions>
|
</Target>
|
||||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("Disco - Business Intelligence")]
|
[assembly: AssemblyTitle("Disco ICT - Business Intelligence")]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription("")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration("")]
|
||||||
[assembly: AssemblyCompany("")]
|
[assembly: AssemblyCompany("https://discoict.com.au")]
|
||||||
[assembly: AssemblyProduct("Disco")]
|
[assembly: AssemblyProduct("Disco ICT")]
|
||||||
[assembly: AssemblyCopyright("")]
|
[assembly: AssemblyCopyright("")]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
@@ -32,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("1.2.0725.2249")]
|
[assembly: AssemblyVersion("2.5.25262.0000")]
|
||||||
[assembly: AssemblyFileVersion("1.2.0725.2249")]
|
[assembly: AssemblyFileVersion("2.5.25262.0000")]
|
||||||
+2
-52
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.17929
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -19,7 +19,7 @@ namespace Disco.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
@@ -59,55 +59,5 @@ namespace Disco.Properties {
|
|||||||
resourceCulture = value;
|
resourceCulture = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap MimeType_doc48 {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("MimeType_doc48", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap MimeType_img16 {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("MimeType_img16", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap MimeType_pdf16 {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("MimeType_pdf16", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap MimeType_pdf48 {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("MimeType_pdf48", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
|
||||||
/// </summary>
|
|
||||||
internal static System.Drawing.Bitmap MimeType_unknown48 {
|
|
||||||
get {
|
|
||||||
object obj = ResourceManager.GetObject("MimeType_unknown48", resourceCulture);
|
|
||||||
return ((System.Drawing.Bitmap)(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,20 +117,4 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
|
||||||
<data name="MimeType_doc48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\MimeType-doc48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="MimeType_img16" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\MimeType-img16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="MimeType_pdf16" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\MimeType-pdf16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="MimeType_pdf48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\MimeType-pdf48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
<data name="MimeType_unknown48" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
|
||||||
<value>..\Resources\MimeType-unknown48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
</root>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
+49
-1
@@ -16,6 +16,54 @@
|
|||||||
</defaultConnectionFactory>
|
</defaultConnectionFactory>
|
||||||
</entityFramework>
|
</entityFramework>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
|
||||||
</startup>
|
</startup>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.2.2.0" newVersion="4.2.2.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.2.2.0" newVersion="4.2.2.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.1.1.3" newVersion="4.1.1.3" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,16 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
|
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net45" />
|
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" targetFramework="net45" />
|
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" />
|
||||||
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.1" targetFramework="net45" />
|
|
||||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" />
|
|
||||||
<package id="Newtonsoft.Json" version="5.0.5" targetFramework="net45" />
|
|
||||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
|
||||||
<package id="Rx-Core" version="2.1.30214.0" targetFramework="net45" />
|
|
||||||
<package id="Rx-Interfaces" version="2.1.30214.0" targetFramework="net45" />
|
|
||||||
<package id="Rx-Linq" version="2.1.30214.0" targetFramework="net45" />
|
|
||||||
<package id="Rx-Main" version="2.1.30214.0" targetFramework="net45" />
|
|
||||||
<package id="Rx-PlatformServices" version="2.1.30214.0" targetFramework="net45" />
|
|
||||||
</packages>
|
</packages>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -9,9 +9,8 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>Disco.Client</RootNamespace>
|
<RootNamespace>Disco.Client</RootNamespace>
|
||||||
<AssemblyName>Disco.Client</AssemblyName>
|
<AssemblyName>Disco.Client</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
|
||||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||||
<RestorePackages>true</RestorePackages>
|
<RestorePackages>true</RestorePackages>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -24,6 +23,7 @@
|
|||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -33,6 +33,7 @@
|
|||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StartupObject>Disco.Client.Program</StartupObject>
|
<StartupObject>Disco.Client.Program</StartupObject>
|
||||||
@@ -48,9 +49,8 @@
|
|||||||
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||||
<HintPath>..\packages\Newtonsoft.Json.5.0.5\lib\net40\Newtonsoft.Json.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -66,6 +66,54 @@
|
|||||||
<Compile Include="..\Disco.Models\ClientServices\Enrol.cs">
|
<Compile Include="..\Disco.Models\ClientServices\Enrol.cs">
|
||||||
<Link>Models\ClientServices\Enrol.cs</Link>
|
<Link>Models\ClientServices\Enrol.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\BaseBoard.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\BaseBoard.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\Battery.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\Battery.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\Bios.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\Bios.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\Certificate.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\Certificate.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\CertificateStore.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\CertificateStore.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\ComputerSystem.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\ComputerSystem.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\DeviceHardware.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\DeviceHardware.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\DiskDrive.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\DiskDrive.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\DiskDrivePartition.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\DiskDrivePartition.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\DiskLogical.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\DiskLogical.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\NetworkAdapter.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\NetworkAdapter.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\PhysicalMemory.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\PhysicalMemory.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\Processor.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\Processor.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\WirelessProfile.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\WirelessProfile.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\WirelessProfileStore.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\WirelessProfileStore.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Disco.Models\ClientServices\EnrolmentInformation\WirelessProfileTransformation.cs">
|
||||||
|
<Link>Models\ClientServices\EnrolmentInformation\WirelessProfileTransformation.cs</Link>
|
||||||
|
</Compile>
|
||||||
<Compile Include="..\Disco.Models\ClientServices\EnrolResponse.cs">
|
<Compile Include="..\Disco.Models\ClientServices\EnrolResponse.cs">
|
||||||
<Link>Models\ClientServices\EnrolResponse.cs</Link>
|
<Link>Models\ClientServices\EnrolResponse.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -93,10 +141,20 @@
|
|||||||
<Compile Include="Extensions\EnrolExtensions.cs" />
|
<Compile Include="Extensions\EnrolExtensions.cs" />
|
||||||
<Compile Include="Extensions\WhoAmIExtensions.cs" />
|
<Compile Include="Extensions\WhoAmIExtensions.cs" />
|
||||||
<Compile Include="Interop\Certificates.cs" />
|
<Compile Include="Interop\Certificates.cs" />
|
||||||
|
<Compile Include="Interop\EndpointDiscovery.cs" />
|
||||||
|
<Compile Include="Interop\Hardware.cs" />
|
||||||
<Compile Include="Interop\LocalAuthentication.cs" />
|
<Compile Include="Interop\LocalAuthentication.cs" />
|
||||||
|
<Compile Include="Interop\Native\NetworkConnectionStatuses.cs" />
|
||||||
|
<Compile Include="Interop\Native\ProfileInfoFlags.cs" />
|
||||||
|
<Compile Include="Interop\Native\WlanApi.cs" />
|
||||||
|
<Compile Include="Interop\Native\WLAN_INTERFACE_INFO.cs" />
|
||||||
|
<Compile Include="Interop\Native\WLAN_INTERFACE_INFO_LIST.cs" />
|
||||||
|
<Compile Include="Interop\Native\WLAN_INTERFACE_STATE.cs" />
|
||||||
|
<Compile Include="Interop\Native\WLAN_PROFILE_INFO.cs" />
|
||||||
|
<Compile Include="Interop\Native\WLAN_PROFILE_INFO_LIST.cs" />
|
||||||
<Compile Include="Interop\Network.cs" />
|
<Compile Include="Interop\Network.cs" />
|
||||||
|
<Compile Include="Interop\WirelessNetwork.cs" />
|
||||||
<Compile Include="Presentation.cs" />
|
<Compile Include="Presentation.cs" />
|
||||||
<Compile Include="Interop\SystemAudit.cs" />
|
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@@ -120,17 +178,16 @@
|
|||||||
<None Include="Package Creation\7z.exe" />
|
<None Include="Package Creation\7z.exe" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
|
||||||
<VisualStudio>
|
|
||||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" />
|
|
||||||
</VisualStudio>
|
|
||||||
</ProjectExtensions>
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>DEL "$(ProjectDir)Package Creation\PreparationClient.zip"
|
<PostBuildEvent>DEL "$(ProjectDir)Package Creation\PreparationClient.zip"
|
||||||
"$(ProjectDir)Package Creation\7z.exe" a -tzip "$(ProjectDir)Package Creation\PreparationClient.zip" "$(TargetDir)*.*" -x!*.tmp -x!*.vshost.* -x!Newtonsoft.Json.xml -x!*.pdb
|
"$(ProjectDir)Package Creation\7z.exe" a -tzip "$(ProjectDir)Package Creation\PreparationClient.zip" "$(TargetDir)*.*" -x!*.tmp -x!*.vshost.* -x!Newtonsoft.Json.xml -x!*.pdb
|
||||||
COPY "$(ProjectDir)Package Creation\PreparationClient.zip" "$(ProjectDir)..\Disco.Web\ClientBin"</PostBuildEvent>
|
COPY "$(ProjectDir)Package Creation\PreparationClient.zip" "$(ProjectDir)..\Disco.Web\ClientBin"</PostBuildEvent>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
<ProjectExtensions>
|
||||||
|
<VisualStudio>
|
||||||
|
<UserProperties BuildVersion_StartDate="2000/1/1" />
|
||||||
|
</VisualStudio>
|
||||||
|
</ProjectExtensions>
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
|
|||||||
@@ -1,31 +1,27 @@
|
|||||||
using System;
|
using Disco.Client.Extensions;
|
||||||
using System.Collections.Generic;
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using Disco.Client.Extensions;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Disco.Client
|
namespace Disco.Client
|
||||||
{
|
{
|
||||||
public static class ErrorReporting
|
public static class ErrorReporting
|
||||||
{
|
{
|
||||||
private const string ServicePathTemplate = "http://DISCO:9292/Services/Client/ClientError";
|
|
||||||
public static string DeviceIdentifier { get; set; }
|
public static string DeviceIdentifier { get; set; }
|
||||||
public static string EnrolmentSessionId { get; set; }
|
public static string EnrolmentSessionId { get; set; }
|
||||||
|
|
||||||
public static void ReportError(Exception Ex, bool ReportToServer)
|
public static void ReportError(Exception exception, bool reportToServer)
|
||||||
{
|
{
|
||||||
bool isClientServiceException = Ex is ClientServiceException;
|
bool isClientServiceException = exception is ClientServiceException;
|
||||||
|
|
||||||
ErrorReport report = new ErrorReport()
|
ErrorReport report = new ErrorReport()
|
||||||
{
|
{
|
||||||
DeviceIdentifier = DeviceIdentifier,
|
DeviceIdentifier = DeviceIdentifier,
|
||||||
SessionId = EnrolmentSessionId,
|
SessionId = EnrolmentSessionId,
|
||||||
JsonException = Ex.IntenseExceptionSerialization()
|
JsonException = exception.IntenseExceptionSerialization()
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -41,7 +37,7 @@ namespace Disco.Client
|
|||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
|
|
||||||
// Don't log server errors back to the server
|
// Don't log server errors back to the server
|
||||||
if (!isClientServiceException && ReportToServer)
|
if (!isClientServiceException && reportToServer)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -52,7 +48,7 @@ namespace Disco.Client
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Presentation.WriteFatalError(Ex);
|
Presentation.WriteFatalError(exception);
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
@@ -88,8 +84,10 @@ namespace Disco.Client
|
|||||||
string reportJson = JsonConvert.SerializeObject(report);
|
string reportJson = JsonConvert.SerializeObject(report);
|
||||||
string reportResponse;
|
string reportResponse;
|
||||||
|
|
||||||
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(ServicePathTemplate);
|
var serverUri = new Uri(Program.ServerUrl ?? new Uri("http://disco:9292"), "/Services/Client/ClientError");
|
||||||
request.UserAgent = string.Format("Disco-Client/{0}", Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
|
|
||||||
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serverUri);
|
||||||
|
request.UserAgent = $"Disco-Client/{Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}";
|
||||||
request.ContentType = "application/json";
|
request.ContentType = "application/json";
|
||||||
request.Method = WebRequestMethods.Http.Post;
|
request.Method = WebRequestMethods.Http.Post;
|
||||||
request.UseDefaultCredentials = true;
|
request.UseDefaultCredentials = true;
|
||||||
@@ -108,7 +106,7 @@ namespace Disco.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Diagnostics.Debug.WriteLine("Error Report Logged to Server; Response: {0}", reportResponse);
|
Debug.WriteLine($"Error Report Logged to Server; Response: {reportResponse}");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.Client.Extensions
|
namespace Disco.Client.Extensions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,55 +1,53 @@
|
|||||||
using System;
|
using Disco.Models.ClientServices;
|
||||||
using System.Collections.Generic;
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Disco.Models.ClientServices;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Disco.Client.Extensions
|
namespace Disco.Client.Extensions
|
||||||
{
|
{
|
||||||
public static class ClientServicesExtensions
|
internal static class ClientServicesExtensions
|
||||||
{
|
{
|
||||||
public const string ServicePathAuthenticatedTemplate = "http://DISCO:9292/Services/Client/Authenticated/{0}";
|
public static ResponseType Post<ResponseType>(this ServiceBase<ResponseType> service, bool authenticated)
|
||||||
public const string ServicePathUnauthenticatedTemplate = "http://DISCO:9292/Services/Client/Unauthenticated/{0}";
|
{
|
||||||
|
ResponseType serviceResponse;
|
||||||
|
Uri serviceUrl;
|
||||||
|
|
||||||
public static ResponseType Post<ResponseType>(this ServiceBase<ResponseType> Service, bool Authenticated)
|
if (authenticated)
|
||||||
{
|
serviceUrl = new Uri(Program.ServerUrl, $"/Services/Client/Authenticated/{service.Feature}");
|
||||||
string jsonResponse;
|
|
||||||
string serviceUrl;
|
|
||||||
if (Authenticated)
|
|
||||||
serviceUrl = string.Format(ServicePathAuthenticatedTemplate, Service.Feature);
|
|
||||||
else
|
else
|
||||||
serviceUrl = string.Format(ServicePathUnauthenticatedTemplate, Service.Feature);
|
serviceUrl = new Uri(Program.ServerUrl, $"/Services/Client/Unauthenticated/{service.Feature}");
|
||||||
|
|
||||||
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(serviceUrl);
|
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(serviceUrl);
|
||||||
request.UserAgent = string.Format("Disco-Client/{0}", Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
|
request.UserAgent = $"Disco-Client/{Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}";
|
||||||
request.ContentType = "application/json";
|
request.ContentType = "application/json";
|
||||||
request.Method = WebRequestMethods.Http.Post;
|
request.Method = WebRequestMethods.Http.Post;
|
||||||
request.UseDefaultCredentials = true;
|
request.UseDefaultCredentials = true;
|
||||||
request.Timeout = 300000; // 5 Minutes
|
request.Timeout = 300000; // 5 Minutes
|
||||||
string jsonRequest = JsonConvert.SerializeObject(Service);
|
|
||||||
|
|
||||||
using (StreamWriter requestWriter = new StreamWriter(request.GetRequestStream()))
|
var jsonSerializer = new JsonSerializer();
|
||||||
|
|
||||||
|
using (var requestWriter = new StreamWriter(request.GetRequestStream()))
|
||||||
{
|
{
|
||||||
requestWriter.Write(jsonRequest);
|
using (var jsonWriter = new JsonTextWriter(requestWriter))
|
||||||
|
{
|
||||||
|
jsonSerializer.Serialize(jsonWriter, service);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
|
||||||
{
|
{
|
||||||
using (StreamReader responseReader = new StreamReader(response.GetResponseStream()))
|
using (var responseReader = new StreamReader(response.GetResponseStream()))
|
||||||
{
|
{
|
||||||
jsonResponse = responseReader.ReadToEnd();
|
using (var jsonReader = new JsonTextReader(responseReader))
|
||||||
|
{
|
||||||
|
serviceResponse = jsonSerializer.Deserialize<ResponseType>(jsonReader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(jsonResponse))
|
return serviceResponse;
|
||||||
return default(ResponseType);
|
|
||||||
else
|
|
||||||
return JsonConvert.DeserializeObject<ResponseType>(jsonResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,32 @@
|
|||||||
using System;
|
using Disco.Client.Interop;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Disco.Models.ClientServices;
|
using Disco.Models.ClientServices;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.IO;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using System.Text.RegularExpressions;
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Disco.Client.Extensions
|
namespace Disco.Client.Extensions
|
||||||
{
|
{
|
||||||
public static class EnrolExtensions
|
internal static class EnrolExtensions
|
||||||
{
|
{
|
||||||
|
|
||||||
public static void Build(this Enrol enrol)
|
public static void Build(this Enrol enrol)
|
||||||
{
|
{
|
||||||
enrol.DeviceUUID = Interop.SystemAudit.DeviceUUID;
|
enrol.ComputerName = Environment.MachineName;
|
||||||
enrol.DeviceSerialNumber = Interop.SystemAudit.DeviceSerialNumber;
|
enrol.RunningUserDomain = Environment.UserDomainName;
|
||||||
|
enrol.RunningUserName = Environment.UserName;
|
||||||
|
enrol.RunningInteractively = Environment.UserInteractive;
|
||||||
|
|
||||||
enrol.DeviceComputerName = Interop.LocalAuthentication.ComputerName;
|
// Hardware Audit
|
||||||
|
enrol.Hardware = Hardware.Information;
|
||||||
|
enrol.SerialNumber = enrol.Hardware.SerialNumber;
|
||||||
|
|
||||||
enrol.DeviceManufacturer = Interop.SystemAudit.DeviceManufacturer;
|
// Apply System Information
|
||||||
enrol.DeviceModel = Interop.SystemAudit.DeviceModel;
|
enrol.ApplySystemInformation();
|
||||||
enrol.DeviceModelType = Interop.SystemAudit.DeviceType;
|
|
||||||
|
|
||||||
enrol.DeviceIsPartOfDomain = Interop.SystemAudit.DeviceIsPartOfDomain;
|
|
||||||
|
|
||||||
// LAN
|
|
||||||
enrol.DeviceLanMacAddress = Interop.Network.PrimaryLanMacAddress;
|
|
||||||
|
|
||||||
// WAN
|
|
||||||
enrol.DeviceWlanMacAddress = Interop.Network.PrimaryWlanMacAddress;
|
|
||||||
|
|
||||||
// Certificates
|
// Certificates
|
||||||
enrol.DeviceCertificates = Interop.Certificates.GetCertificateSubjects(StoreName.My, StoreLocation.LocalMachine);
|
enrol.Certificates = Certificates.GetAllCertificates();
|
||||||
|
|
||||||
|
// Wireless Profiles
|
||||||
|
enrol.WirelessProfiles = WirelessNetwork.GetWirelessProfiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Process(this EnrolResponse enrolResponse)
|
public static void Process(this EnrolResponse enrolResponse)
|
||||||
@@ -47,15 +39,20 @@ namespace Disco.Client.Extensions
|
|||||||
if (!string.IsNullOrEmpty(enrolResponse.ErrorMessage))
|
if (!string.IsNullOrEmpty(enrolResponse.ErrorMessage))
|
||||||
throw new ClientServiceException("Enrolment", enrolResponse.ErrorMessage);
|
throw new ClientServiceException("Enrolment", enrolResponse.ErrorMessage);
|
||||||
|
|
||||||
|
if (enrolResponse.IsPending)
|
||||||
|
return;
|
||||||
|
|
||||||
// Offline Domain Join
|
// Offline Domain Join
|
||||||
bool requireReboot = enrolResponse.ApplyOfflineDomainJoin();
|
bool requireReboot = enrolResponse.ApplyOfflineDomainJoin();
|
||||||
|
|
||||||
// Certificates
|
|
||||||
enrolResponse.ApplyDeviceCertificates();
|
|
||||||
|
|
||||||
// Device Owner
|
// Device Owner
|
||||||
enrolResponse.ApplyDeviceAssignedUser();
|
enrolResponse.ApplyDeviceAssignedUser();
|
||||||
|
|
||||||
|
// Certificates
|
||||||
|
enrolResponse.ApplyDeviceCertificates();
|
||||||
|
|
||||||
|
// Wireless Profiles
|
||||||
|
enrolResponse.ApplyWirelessProfiles();
|
||||||
|
|
||||||
Presentation.UpdateStatus("Enrolling Device", "Device Enrolment Successfully Completed", false, 0, 1500);
|
Presentation.UpdateStatus("Enrolling Device", "Device Enrolment Successfully Completed", false, 0, 1500);
|
||||||
|
|
||||||
@@ -63,6 +60,28 @@ namespace Disco.Client.Extensions
|
|||||||
Program.AllowUninstall = enrolResponse.AllowBootstrapperUninstall;
|
Program.AllowUninstall = enrolResponse.AllowBootstrapperUninstall;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum NETSETUP_PROVISION_FLAGS : int
|
||||||
|
{
|
||||||
|
NETSETUP_PROVISION_DOWNLEVEL_PRIV_SUPPORT = 0x00000001,
|
||||||
|
NETSETUP_PROVISION_REUSE_ACCOUNT = 0x00000002,
|
||||||
|
NETSETUP_PROVISION_USE_DEFAULT_PASSWORD = 0x00000004,
|
||||||
|
NETSETUP_PROVISION_SKIP_ACCOUNT_SEARCH = 0x00000008,
|
||||||
|
NETSETUP_PROVISION_ROOT_CA_CERTS = 0x00000010,
|
||||||
|
NETSETUP_PROVISION_PERSISTENTSITE = 0x00000020,
|
||||||
|
NETSETUP_PROVISION_ONLINE_CALLER = 0x40000000,
|
||||||
|
NETSETUP_PROVISION_CHECK_PWD_ONLY = unchecked((int)0x80000000),
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("Netapi32.dll", CallingConvention = CallingConvention.Winapi)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I4)]
|
||||||
|
private static extern int NetRequestOfflineDomainJoin(
|
||||||
|
[In] IntPtr pProvisionBinData,
|
||||||
|
[In, MarshalAs(UnmanagedType.I4)] int cbProvisionBinDataSize,
|
||||||
|
[In, MarshalAs(UnmanagedType.I4)] NETSETUP_PROVISION_FLAGS dwOptions,
|
||||||
|
[In, MarshalAs(UnmanagedType.LPWStr)] string lpWindowsPath
|
||||||
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes a Client Service Enrol Response for Offline Domain Join Actions
|
/// Processes a Client Service Enrol Response for Offline Domain Join Actions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -70,41 +89,43 @@ namespace Disco.Client.Extensions
|
|||||||
/// <returns>Boolean indicating whether a reboot is required.</returns>
|
/// <returns>Boolean indicating whether a reboot is required.</returns>
|
||||||
private static bool ApplyOfflineDomainJoin(this EnrolResponse enrolResponse)
|
private static bool ApplyOfflineDomainJoin(this EnrolResponse enrolResponse)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(enrolResponse.OfflineDomainJoin))
|
if (!string.IsNullOrWhiteSpace(enrolResponse.OfflineDomainJoinManifest))
|
||||||
{
|
{
|
||||||
Presentation.UpdateStatus("Enrolling Device", string.Format("Performing Offline Domain Join:{0}Renaming Computer: {1} -> {2}", Environment.NewLine, Interop.LocalAuthentication.ComputerName, enrolResponse.DeviceComputerName), true, -1, 1500);
|
Presentation.UpdateStatus("Enrolling Device", $"Performing Offline Domain Join:\r\nRenaming Computer: {Environment.MachineName} -> {enrolResponse.ComputerName}", true, -1, 1500);
|
||||||
|
|
||||||
string odjFile = Path.GetTempFileName();
|
var provisionData = Convert.FromBase64String(enrolResponse.OfflineDomainJoinManifest);
|
||||||
File.WriteAllBytes(odjFile, Convert.FromBase64String(enrolResponse.OfflineDomainJoin));
|
string systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
|
||||||
|
|
||||||
string odjWindowsPath = Environment.GetEnvironmentVariable("SystemRoot");
|
var provisionDataPointer = Marshal.AllocCoTaskMem(provisionData.Length);
|
||||||
string odjProcessArguments = string.Format("/REQUESTODJ /LOADFILE \"{0}\" /WINDOWSPATH \"{1}\" /LOCALOS", odjFile, odjWindowsPath);
|
Marshal.Copy(provisionData, 0, provisionDataPointer, provisionData.Length);
|
||||||
|
var joinResult = default(int);
|
||||||
ProcessStartInfo odjProcessStartInfo = new ProcessStartInfo("DJOIN.EXE", odjProcessArguments)
|
try
|
||||||
{
|
{
|
||||||
CreateNoWindow = true,
|
joinResult = NetRequestOfflineDomainJoin(provisionDataPointer, provisionData.Length, NETSETUP_PROVISION_FLAGS.NETSETUP_PROVISION_ONLINE_CALLER, systemRoot);
|
||||||
ErrorDialog = false,
|
}
|
||||||
LoadUserProfile = true,
|
finally
|
||||||
RedirectStandardOutput = true,
|
{
|
||||||
UseShellExecute = false
|
Marshal.FreeCoTaskMem(provisionDataPointer);
|
||||||
};
|
|
||||||
string odjResult;
|
|
||||||
using (Process odjProcess = System.Diagnostics.Process.Start(odjProcessStartInfo))
|
|
||||||
{
|
|
||||||
odjResult = odjProcess.StandardOutput.ReadToEnd();
|
|
||||||
odjProcess.WaitForExit(20000); // 20 Seconds
|
|
||||||
}
|
}
|
||||||
Presentation.UpdateStatus("Enrolling Device", string.Format("Offline Domain Join Result:{0}{1}", Environment.NewLine, odjResult), true, -1, 3000);
|
|
||||||
|
|
||||||
if (File.Exists(odjFile))
|
if (joinResult != 0)
|
||||||
File.Delete(odjFile);
|
{
|
||||||
|
var win32Exception = new System.ComponentModel.Win32Exception(joinResult);
|
||||||
|
Presentation.UpdateStatus("Enrolling Device", $"Offline Domain Join Failed:\r\n{win32Exception.Message} [{joinResult}]", true, -1, 3000);
|
||||||
|
throw new InvalidOperationException($"Offline Domain Join Failed:\r\n{win32Exception.Message} [{joinResult}]");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Presentation.UpdateStatus("Enrolling Device", $"Offline Domain Join Succeeded", true, -1, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
// Flush Logged-On History
|
// Flush Logged-On History
|
||||||
if (!string.IsNullOrEmpty(enrolResponse.DeviceDomainName))
|
if (enrolResponse.SetAssignedUserForLogon && !string.IsNullOrEmpty(enrolResponse.DomainName))
|
||||||
{
|
{
|
||||||
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true)){
|
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true))
|
||||||
regWinlogon.SetValue("DefaultDomainName", enrolResponse.DeviceDomainName, RegistryValueKind.String);
|
{
|
||||||
regWinlogon.SetValue("DefaultUserName", String.Empty, RegistryValueKind.String);
|
regWinlogon.SetValue("DefaultDomainName", enrolResponse.DomainName, RegistryValueKind.String);
|
||||||
|
regWinlogon.SetValue("DefaultUserName", string.Empty, RegistryValueKind.String);
|
||||||
}
|
}
|
||||||
using (RegistryKey regLogonUI = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI", true))
|
using (RegistryKey regLogonUI = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI", true))
|
||||||
{
|
{
|
||||||
@@ -128,61 +149,47 @@ namespace Disco.Client.Extensions
|
|||||||
private static void ApplyDeviceAssignedUser(this EnrolResponse enrolResponse)
|
private static void ApplyDeviceAssignedUser(this EnrolResponse enrolResponse)
|
||||||
{
|
{
|
||||||
// Only run task if Assigned User was specified
|
// Only run task if Assigned User was specified
|
||||||
if (!string.IsNullOrWhiteSpace(enrolResponse.DeviceAssignedUserSID))
|
if (!string.IsNullOrWhiteSpace(enrolResponse.AssignedUserSID))
|
||||||
{
|
{
|
||||||
Presentation.UpdateStatus("Enrolling Device", string.Format(@"Configuring permissions for the device owner:{0}{1} ({2}\{3})", Environment.NewLine, enrolResponse.DeviceAssignedUserName, enrolResponse.DeviceAssignedUserDomain, enrolResponse.DeviceAssignedUserUsername), true, -1, 3000);
|
Presentation.UpdateStatus("Enrolling Device", $"Configuring the device owner:\r\n{enrolResponse.AssignedUserDescription} ({enrolResponse.AssignedUserDomain}\\{enrolResponse.AssignedUserUsername})", true, -1, 3000);
|
||||||
|
|
||||||
Interop.LocalAuthentication.AddLocalGroupMembership("Administrators", enrolResponse.DeviceAssignedUserSID, enrolResponse.DeviceAssignedUserUsername, enrolResponse.DeviceAssignedUserDomain);
|
if (enrolResponse.AssignedUserIsLocalAdmin)
|
||||||
|
LocalAuthentication.AddLocalGroupMembership("Administrators", enrolResponse.AssignedUserSID, enrolResponse.AssignedUserUsername, enrolResponse.AssignedUserDomain);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enrolResponse.SetAssignedUserForLogon && !string.IsNullOrEmpty(enrolResponse.AssignedUserDomain) && !string.IsNullOrEmpty(enrolResponse.AssignedUserUsername))
|
||||||
|
{
|
||||||
// Make Windows think this user was the last to logon
|
// Make Windows think this user was the last to logon
|
||||||
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true))
|
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true))
|
||||||
{
|
{
|
||||||
regWinlogon.SetValue("DefaultDomainName", enrolResponse.DeviceAssignedUserDomain, RegistryValueKind.String);
|
regWinlogon.SetValue("DefaultDomainName", enrolResponse.AssignedUserDomain, RegistryValueKind.String);
|
||||||
regWinlogon.SetValue("DefaultUserName", enrolResponse.DeviceAssignedUserUsername, RegistryValueKind.String);
|
regWinlogon.SetValue("DefaultUserName", enrolResponse.AssignedUserUsername, RegistryValueKind.String);
|
||||||
}
|
}
|
||||||
using (RegistryKey regLogonUI = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI", true))
|
using (RegistryKey regLogonUI = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI", true))
|
||||||
{
|
{
|
||||||
regLogonUI.SetValue("LastLoggedOnUser", string.Format(@"{0}\{1}", enrolResponse.DeviceAssignedUserDomain, enrolResponse.DeviceAssignedUserUsername), RegistryValueKind.String);
|
regLogonUI.SetValue("LastLoggedOnUser", $@"{enrolResponse.AssignedUserDomain}\{enrolResponse.AssignedUserUsername}", RegistryValueKind.String);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Processes a Client Service Enrol Response for Device Certificate Actions
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="enrolResponse"></param>
|
|
||||||
private static void ApplyDeviceCertificates(this EnrolResponse enrolResponse)
|
private static void ApplyDeviceCertificates(this EnrolResponse enrolResponse)
|
||||||
{
|
{
|
||||||
// Only run if a Certificate was supplied
|
if (enrolResponse.Certificates != null)
|
||||||
if (!string.IsNullOrEmpty(enrolResponse.DeviceCertificate))
|
|
||||||
{
|
{
|
||||||
Presentation.UpdateStatus("Enrolling Device", "Configuring Wireless Certificates", true, -1, 1000);
|
Presentation.UpdateStatus("Enrolling Device", "Configuring Certificates", true, -1, 1000);
|
||||||
|
|
||||||
var certPersonalBytes = Convert.FromBase64String(enrolResponse.DeviceCertificate);
|
enrolResponse.Certificates.Apply();
|
||||||
var certPersonal = new X509Certificate2(certPersonalBytes, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
|
}
|
||||||
if (certPersonal == null)
|
}
|
||||||
throw new ClientServiceException("Enrolment > Device Certificate", "Unable to Import Device Certificate Provided, possibly check password.");
|
|
||||||
|
|
||||||
// Certificate Removal
|
private static void ApplyWirelessProfiles(this EnrolResponse enrolResponse)
|
||||||
if (enrolResponse.DeviceCertificateRemoveExisting != null && enrolResponse.DeviceCertificateRemoveExisting.Count > 0)
|
|
||||||
{
|
{
|
||||||
List<Regex> regExMatchesSubject = new List<Regex>();
|
if (enrolResponse.WirelessProfiles != null)
|
||||||
foreach (var subjectRegEx in enrolResponse.DeviceCertificateRemoveExisting)
|
{
|
||||||
regExMatchesSubject.Add(new Regex(subjectRegEx, RegexOptions.IgnoreCase));
|
Presentation.UpdateStatus("Enrolling Device", "Configuring Wireless Profiles", true, -1, 1000);
|
||||||
|
|
||||||
// Remove from 'My' Store
|
enrolResponse.WirelessProfiles.Apply();
|
||||||
Interop.Certificates.RemoveCertificates(StoreName.My, StoreLocation.LocalMachine, regExMatchesSubject, certPersonal);
|
|
||||||
// Remove from 'Root' Store
|
|
||||||
Interop.Certificates.RemoveCertificates(StoreName.Root, StoreLocation.LocalMachine, regExMatchesSubject, certPersonal);
|
|
||||||
// Remove from 'CertificateAuthority' Store
|
|
||||||
Interop.Certificates.RemoveCertificates(StoreName.CertificateAuthority, StoreLocation.LocalMachine, regExMatchesSubject, certPersonal);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Certificate
|
|
||||||
Presentation.UpdateStatus("Enrolling Device", string.Format("Configuring Wireless Certificates{0}Installing Certificate: {1}", Environment.NewLine, Interop.Certificates.GetCertificateFriendlyName(certPersonal)), true, -1);
|
|
||||||
Interop.Certificates.AddCertificate(StoreName.My, StoreLocation.LocalMachine, certPersonal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using Disco.Models.ClientServices;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Disco.Models.ClientServices;
|
|
||||||
|
|
||||||
namespace Disco.Client.Extensions
|
namespace Disco.Client.Extensions
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 32 KiB |
@@ -1,103 +1,129 @@
|
|||||||
using System;
|
using Disco.Models.ClientServices.EnrolmentInformation;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace Disco.Client.Interop
|
namespace Disco.Client.Interop
|
||||||
{
|
{
|
||||||
public static class Certificates
|
public static class Certificates
|
||||||
{
|
{
|
||||||
|
public static List<Certificate> GetAllCertificates()
|
||||||
public static string GetCertificateFriendlyName(X509Certificate2 Certificate)
|
|
||||||
{
|
{
|
||||||
string subject = Certificate.Subject;
|
var certificates = new List<Certificate>();
|
||||||
return subject.Substring(subject.IndexOf("=") + 1, subject.IndexOf(",") - subject.IndexOf("=") - 1);
|
|
||||||
|
// Trusted Root Certificates
|
||||||
|
certificates.AddRange(GetCertificates(StoreName.Root, "TrustedRoot"));
|
||||||
|
|
||||||
|
// Intermediate Certificates
|
||||||
|
certificates.AddRange(GetCertificates(StoreName.CertificateAuthority, "Intermediate"));
|
||||||
|
|
||||||
|
// Personal Certificates
|
||||||
|
certificates.AddRange(GetCertificates(StoreName.My, "Personal"));
|
||||||
|
|
||||||
|
return certificates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<string> GetCertificateSubjects(StoreName StoreName, StoreLocation StoreLocation)
|
private static IEnumerable<Certificate> GetCertificates(StoreName StoreName, string StoreDescription)
|
||||||
{
|
{
|
||||||
X509Store certStore = new X509Store(StoreName, StoreLocation);
|
var store = new X509Store(StoreName, StoreLocation.LocalMachine);
|
||||||
certStore.Open(OpenFlags.ReadOnly);
|
store.Open(OpenFlags.ReadOnly);
|
||||||
var certSubjects = certStore.Certificates.Cast<X509Certificate2>().Select(c => c.Subject).ToList();
|
|
||||||
certStore.Close();
|
|
||||||
return certSubjects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool AddCertificate(StoreName StoreName, StoreLocation StoreLocation, X509Certificate2 Certificate)
|
|
||||||
{
|
|
||||||
X509Store certStore = new X509Store(StoreName, StoreLocation);
|
|
||||||
bool certAlreadyAdded = false;
|
|
||||||
|
|
||||||
certStore.Open(OpenFlags.ReadWrite);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (X509Certificate2 cert in certStore.Certificates)
|
foreach (var certificate in store.Certificates)
|
||||||
{
|
{
|
||||||
if (cert.SerialNumber.Equals(Certificate.SerialNumber))
|
yield return new Certificate()
|
||||||
{
|
{
|
||||||
certAlreadyAdded = true;
|
Store = StoreDescription,
|
||||||
break;
|
SubjectName = certificate.SubjectName.Name,
|
||||||
|
Thumbprint = certificate.Thumbprint,
|
||||||
|
FriendlyName = certificate.FriendlyName,
|
||||||
|
DnsName = certificate.GetNameInfo(X509NameType.DnsName, false),
|
||||||
|
Version = certificate.Version,
|
||||||
|
SignatureAlgorithm = certificate.SignatureAlgorithm.FriendlyName,
|
||||||
|
Issuer = certificate.IssuerName.Name,
|
||||||
|
NotAfter = certificate.NotAfter,
|
||||||
|
NotBefore = certificate.NotBefore,
|
||||||
|
HasPrivateKey = certificate.HasPrivateKey
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!certAlreadyAdded)
|
|
||||||
{
|
|
||||||
Presentation.UpdateStatus("Enrolling Device", string.Format("Configuring Wireless Certificates{0}Adding Certificate: '{1}' from {2}@{3}", Environment.NewLine, GetCertificateFriendlyName(Certificate), StoreName.ToString(), StoreLocation.ToString()), true, -1, 3000);
|
|
||||||
certStore.Add(Certificate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception) { throw; }
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
certStore.Close();
|
store.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !certAlreadyAdded;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<string> RemoveCertificates(StoreName StoreName, StoreLocation StoreLocation, List<Regex> RegExMatchesSubject, X509Certificate2 CertificateException)
|
public static void Apply(this CertificateStore EnrolStore)
|
||||||
{
|
{
|
||||||
X509Store certStore = new X509Store(StoreName, StoreLocation);
|
if (EnrolStore != null)
|
||||||
List<string> results = new List<string>();
|
{
|
||||||
List<X509Certificate2> certStoreRemove = new List<X509Certificate2>();
|
// Apply Trusted Root
|
||||||
|
ApplyToStore(StoreName.Root, EnrolStore.TrustedRootCertificates, EnrolStore.TrustedRootRemoveThumbprints);
|
||||||
|
|
||||||
certStore.Open(OpenFlags.ReadWrite);
|
// Apply Intermediate
|
||||||
|
ApplyToStore(StoreName.CertificateAuthority, EnrolStore.IntermediateCertificates, EnrolStore.IntermediateRemoveThumbprints);
|
||||||
|
|
||||||
|
// Apply Personal
|
||||||
|
ApplyToStore(StoreName.My, EnrolStore.PersonalCertificates, EnrolStore.PersonalRemoveThumbprints);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyToStore(StoreName StoreName, List<byte[]> Certificates, List<string> RemoveThumbprints)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((Certificates != null && Certificates.Count > 0) ||
|
||||||
|
(RemoveThumbprints != null && RemoveThumbprints.Count > 0))
|
||||||
|
{
|
||||||
|
var store = new X509Store(StoreName, StoreLocation.LocalMachine);
|
||||||
|
store.Open(OpenFlags.ReadWrite);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (X509Certificate2 cert in certStore.Certificates)
|
var addedThumbprints = new List<string>();
|
||||||
|
var existingThumbprints = store.Certificates.Cast<X509Certificate2>().GroupBy(c => c.Thumbprint).ToDictionary(c => c.Key, c => c.ToList(), StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// Add
|
||||||
|
if (Certificates != null && Certificates.Count > 0)
|
||||||
{
|
{
|
||||||
if (!cert.SerialNumber.Equals(CertificateException.SerialNumber))
|
foreach (var certificateBytes in Certificates)
|
||||||
{
|
{
|
||||||
foreach (var subjectRegEx in RegExMatchesSubject)
|
var certificate = new X509Certificate2(certificateBytes, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
|
||||||
|
|
||||||
|
// check if it already exists
|
||||||
|
if (!existingThumbprints.ContainsKey(certificate.Thumbprint) && !addedThumbprints.Contains(certificate.Thumbprint))
|
||||||
{
|
{
|
||||||
if (subjectRegEx.IsMatch(cert.Subject))
|
Presentation.UpdateStatus("Enrolling Device", $"Configuring Certificates\r\nAdding Certificate: '{certificate.GetNameInfo(X509NameType.DnsName, false)}' from {store.Name}@{store.Location}", true, -1, 1000);
|
||||||
{
|
store.Add(certificate);
|
||||||
certStoreRemove.Add(cert);
|
addedThumbprints.Add(certificate.Thumbprint);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var cert in certStoreRemove)
|
// Remove
|
||||||
|
if (RemoveThumbprints != null && RemoveThumbprints.Count > 0)
|
||||||
{
|
{
|
||||||
results.Add(cert.Subject);
|
foreach (var thumbprint in RemoveThumbprints)
|
||||||
|
{
|
||||||
Presentation.UpdateStatus("Enrolling Device", string.Format("Configuring Wireless Certificates{0}Removing Certificate: '{1}' from {2}@{3}", Environment.NewLine, GetCertificateFriendlyName(cert), StoreName.ToString(), StoreLocation.ToString()), true, -1, 1500);
|
if (existingThumbprints.TryGetValue(thumbprint, out var certificates) && !addedThumbprints.Contains(thumbprint))
|
||||||
certStore.Remove(cert);
|
{
|
||||||
|
foreach (var certificate in certificates)
|
||||||
|
{
|
||||||
|
Presentation.UpdateStatus("Enrolling Device", $"Configuring Certificates\r\nRemoving Certificate: '{certificate.GetNameInfo(X509NameType.DnsName, false)}' from {store.Name}@{store.Location}", true, -1, 1000);
|
||||||
|
store.Remove(certificate);
|
||||||
|
existingThumbprints.Remove(thumbprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception) { throw; }
|
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
certStore.Close();
|
store.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,317 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.NetworkInformation;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop
|
||||||
|
{
|
||||||
|
internal class EndpointDiscovery
|
||||||
|
{
|
||||||
|
[DllImport("dnsapi", EntryPoint = "DnsQuery_W", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
|
||||||
|
private static extern int DnsQuery([MarshalAs(UnmanagedType.VBByRefStr)] ref string pszName, NativeDnsQueryTypes wType, NativeDnsQueryOptions options, int aipServers, ref IntPtr ppQueryResults, int pReserved);
|
||||||
|
|
||||||
|
[DllImport("dnsapi", CharSet = CharSet.Auto, SetLastError = true)]
|
||||||
|
private static extern void DnsRecordListFree(IntPtr pRecordList, int FreeType);
|
||||||
|
private const int DNS_ERROR_RCODE_NAME_ERROR = 0x232B;
|
||||||
|
private const int DNS_ERROR_BAD_PACKET = 0x251E;
|
||||||
|
public static Tuple<Uri, string> DiscoverServer(Uri forcedServerUri)
|
||||||
|
{
|
||||||
|
// 1. Check first command line argument for server name
|
||||||
|
if (forcedServerUri != null)
|
||||||
|
return Tuple.Create(forcedServerUri, "Manual");
|
||||||
|
|
||||||
|
// 2. Check for a DNS SRV record for _discoict._tcp.domain
|
||||||
|
var domainSuffixes = new List<string>();
|
||||||
|
var primaryDomain = IPGlobalProperties.GetIPGlobalProperties().DomainName;
|
||||||
|
if (!string.IsNullOrEmpty(primaryDomain))
|
||||||
|
domainSuffixes.Add(primaryDomain);
|
||||||
|
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
|
||||||
|
.Where(ni => ni.OperationalStatus == OperationalStatus.Up);
|
||||||
|
foreach (var ni in networkInterfaces)
|
||||||
|
{
|
||||||
|
var domainSuffix = ni.GetIPProperties().DnsSuffix;
|
||||||
|
if (!string.IsNullOrWhiteSpace(domainSuffix))
|
||||||
|
{
|
||||||
|
if (domainSuffix.Equals("mshome.net", StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!domainSuffixes.Contains(domainSuffix, StringComparer.OrdinalIgnoreCase))
|
||||||
|
domainSuffixes.Add(domainSuffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var domain in domainSuffixes)
|
||||||
|
{
|
||||||
|
var dnsRecords = GetSRVRecords("_discoict._tcp." + domain);
|
||||||
|
if (dnsRecords.Count > 0)
|
||||||
|
{
|
||||||
|
var firstRecord = dnsRecords.OrderBy(r => r.Priority).ThenByDescending(r => r.Weight).First();
|
||||||
|
if (firstRecord.Port == 443)
|
||||||
|
return Tuple.Create(new Uri($"https://{firstRecord.Target}"), "SRV");
|
||||||
|
else
|
||||||
|
return Tuple.Create(new Uri($"https://{firstRecord.Target}:{firstRecord.Port}"), "SRV");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Detect VicSmart network and try resolving with Disco ICT Online Services
|
||||||
|
if (TryResolveVicSmartServer(domainSuffixes, out var vicSmartServerUrl))
|
||||||
|
return Tuple.Create(vicSmartServerUrl, "VicSmart");
|
||||||
|
|
||||||
|
// 4. Legacy: Ping 'disco' and assume port 9292
|
||||||
|
using (Ping p = new Ping())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
PingReply pr = p.Send("disco", 2000);
|
||||||
|
if (pr.Status == IPStatus.Success)
|
||||||
|
return Tuple.Create(new Uri("http://disco:9292"), "Legacy");
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("Could not locate Disco ICT server on the network.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryResolveVicSmartServer(List<string> domainSuffixes, out Uri serverUrl)
|
||||||
|
{
|
||||||
|
if (IsVicSmartNetwork(domainSuffixes))
|
||||||
|
{
|
||||||
|
var potentialVicSmartAddresses = NetworkInterface.GetAllNetworkInterfaces()
|
||||||
|
.Where(ni => ni.OperationalStatus == OperationalStatus.Up)
|
||||||
|
.SelectMany(ni => ni.GetIPProperties().UnicastAddresses)
|
||||||
|
.Where(ua => ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
||||||
|
.Select(ua => ua.Address.GetAddressBytes())
|
||||||
|
.Where(a => a[0] == 10)
|
||||||
|
.Select(a => (ushort)((a[1] >> 4) & 0x000F) | ((a[1] << 4) & 0x00F0) | ((a[2] << 12) & 0xF000) | ((a[2] << 4) & 0x0F00))
|
||||||
|
.Distinct()
|
||||||
|
.Select(a => $"{a:x4}.vicsmart.discoict.com")
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var potentialAddress in potentialVicSmartAddresses)
|
||||||
|
{
|
||||||
|
var records = GetTxtRecords(potentialAddress);
|
||||||
|
|
||||||
|
foreach (var record in records)
|
||||||
|
{
|
||||||
|
if (!record.Content.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (Uri.TryCreate(record.Content, UriKind.Absolute, out var discoveredUri))
|
||||||
|
{
|
||||||
|
serverUrl = discoveredUri;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serverUrl = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsVicSmartNetwork(List<string> domainSuffixes)
|
||||||
|
{
|
||||||
|
if (domainSuffixes.Any(s => string.Equals("services.education.vic.gov.au", s, StringComparison.OrdinalIgnoreCase)) ||
|
||||||
|
domainSuffixes.Any(s => string.Equals("education.vic.gov.au", s, StringComparison.OrdinalIgnoreCase))
|
||||||
|
)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
IPHostEntry doeWanDnsEntry;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
doeWanDnsEntry = Dns.GetHostEntry("broadband.doe.wan");
|
||||||
|
if (doeWanDnsEntry.AddressList.Length > 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{ }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<DnsTxtRecord> GetTxtRecords(string name)
|
||||||
|
{
|
||||||
|
IntPtr resourceRecordsPointer = IntPtr.Zero;
|
||||||
|
var records = new List<DnsTxtRecord>();
|
||||||
|
var retry = 5;
|
||||||
|
retry:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int queryResult = DnsQuery(ref name, NativeDnsQueryTypes.DNS_TYPE_TEXT, NativeDnsQueryOptions.DNS_QUERY_STANDARD, 0, ref resourceRecordsPointer, 0);
|
||||||
|
if (queryResult != 0)
|
||||||
|
{
|
||||||
|
if (queryResult == DNS_ERROR_RCODE_NAME_ERROR)
|
||||||
|
return records;
|
||||||
|
else if (queryResult == DNS_ERROR_BAD_PACKET && retry > 0)
|
||||||
|
{
|
||||||
|
// Sometimes a BAD_PACKET error is returned, retry a few times
|
||||||
|
Thread.Sleep(200);
|
||||||
|
retry--;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Win32Exception(queryResult);
|
||||||
|
}
|
||||||
|
NativeDnsTxtRecord record;
|
||||||
|
for (var resourceRecordPointer = resourceRecordsPointer; !resourceRecordPointer.Equals(IntPtr.Zero); resourceRecordPointer = record.pNext)
|
||||||
|
{
|
||||||
|
record = Marshal.PtrToStructure<NativeDnsTxtRecord>(resourceRecordPointer);
|
||||||
|
if (record.wType == (ushort)NativeDnsQueryTypes.DNS_TYPE_TEXT)
|
||||||
|
records.Add(DnsTxtRecord.FromNativeRecord(record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (resourceRecordsPointer != IntPtr.Zero)
|
||||||
|
DnsRecordListFree(resourceRecordsPointer, 0);
|
||||||
|
}
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<DnsSrvRecord> GetSRVRecords(string name)
|
||||||
|
{
|
||||||
|
IntPtr resourceRecordsPointer = IntPtr.Zero;
|
||||||
|
var records = new List<DnsSrvRecord>();
|
||||||
|
var retry = 5;
|
||||||
|
retry:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int queryResult = DnsQuery(ref name, NativeDnsQueryTypes.DNS_TYPE_SRV, NativeDnsQueryOptions.DNS_QUERY_STANDARD, 0, ref resourceRecordsPointer, 0);
|
||||||
|
if (queryResult != 0)
|
||||||
|
{
|
||||||
|
if (queryResult == DNS_ERROR_RCODE_NAME_ERROR)
|
||||||
|
return records;
|
||||||
|
else if (queryResult == DNS_ERROR_BAD_PACKET && retry > 0)
|
||||||
|
{
|
||||||
|
// Sometimes a BAD_PACKET error is returned, retry a few times
|
||||||
|
Thread.Sleep(200);
|
||||||
|
retry--;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Win32Exception(queryResult);
|
||||||
|
}
|
||||||
|
NativeDnsSrvRecord record;
|
||||||
|
for (var resourceRecordPointer = resourceRecordsPointer; !resourceRecordPointer.Equals(IntPtr.Zero); resourceRecordPointer = record.pNext)
|
||||||
|
{
|
||||||
|
record = Marshal.PtrToStructure<NativeDnsSrvRecord>(resourceRecordPointer);
|
||||||
|
if (record.wType == (ushort)NativeDnsQueryTypes.DNS_TYPE_SRV)
|
||||||
|
records.Add(DnsSrvRecord.FromNativeRecord(record));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (resourceRecordsPointer != IntPtr.Zero)
|
||||||
|
DnsRecordListFree(resourceRecordsPointer, 0);
|
||||||
|
}
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum NativeDnsQueryOptions
|
||||||
|
{
|
||||||
|
DNS_QUERY_ACCEPT_TRUNCATED_RESPONSE = 1,
|
||||||
|
DNS_QUERY_BYPASS_CACHE = 8,
|
||||||
|
DNS_QUERY_DONT_RESET_TTL_VALUES = 0x100000,
|
||||||
|
DNS_QUERY_NO_HOSTS_FILE = 0x40,
|
||||||
|
DNS_QUERY_NO_LOCAL_NAME = 0x20,
|
||||||
|
DNS_QUERY_NO_NETBT = 0x80,
|
||||||
|
DNS_QUERY_NO_RECURSION = 4,
|
||||||
|
DNS_QUERY_NO_WIRE_QUERY = 0x10,
|
||||||
|
DNS_QUERY_RESERVED = -16777216,
|
||||||
|
DNS_QUERY_RETURN_MESSAGE = 0x200,
|
||||||
|
DNS_QUERY_STANDARD = 0,
|
||||||
|
DNS_QUERY_TREAT_AS_FQDN = 0x1000,
|
||||||
|
DNS_QUERY_USE_TCP_ONLY = 2,
|
||||||
|
DNS_QUERY_WIRE_ONLY = 0x100
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum NativeDnsQueryTypes
|
||||||
|
{
|
||||||
|
DNS_TYPE_TEXT = 0x0010,
|
||||||
|
DNS_TYPE_SRV = 0x0021
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct NativeDnsSrvRecord
|
||||||
|
{
|
||||||
|
public IntPtr pNext;
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string pName;
|
||||||
|
public ushort wType;
|
||||||
|
public ushort wDataLength;
|
||||||
|
public int flags;
|
||||||
|
public int dwTtl;
|
||||||
|
public int dwReserved;
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string pNameTarget;
|
||||||
|
public ushort wPriority;
|
||||||
|
public ushort wWeight;
|
||||||
|
public ushort wPort;
|
||||||
|
public ushort Pad;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DnsSrvRecord
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Type { get; set; }
|
||||||
|
public int Ttl { get; set; }
|
||||||
|
public string Target { get; set; }
|
||||||
|
public int Priority { get; set; }
|
||||||
|
public int Weight { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
|
||||||
|
public static DnsSrvRecord FromNativeRecord(NativeDnsSrvRecord nativeRecord)
|
||||||
|
{
|
||||||
|
return new DnsSrvRecord
|
||||||
|
{
|
||||||
|
Name = nativeRecord.pName,
|
||||||
|
Type = nativeRecord.wType,
|
||||||
|
Ttl = nativeRecord.dwTtl,
|
||||||
|
Target = nativeRecord.pNameTarget,
|
||||||
|
Priority = nativeRecord.wPriority,
|
||||||
|
Weight = nativeRecord.wWeight,
|
||||||
|
Port = nativeRecord.wPort
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct NativeDnsTxtRecord
|
||||||
|
{
|
||||||
|
public IntPtr pNext;
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string pName;
|
||||||
|
public ushort wType;
|
||||||
|
public ushort wDataLength;
|
||||||
|
public int flags;
|
||||||
|
public int dwTtl;
|
||||||
|
public int dwReserved;
|
||||||
|
public uint dwStringLength;
|
||||||
|
[MarshalAs(UnmanagedType.LPWStr)]
|
||||||
|
public string pStringArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DnsTxtRecord
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Type { get; set; }
|
||||||
|
public int Ttl { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
|
||||||
|
public static DnsTxtRecord FromNativeRecord(NativeDnsTxtRecord nativeRecord)
|
||||||
|
{
|
||||||
|
return new DnsTxtRecord
|
||||||
|
{
|
||||||
|
Name = nativeRecord.pName,
|
||||||
|
Type = nativeRecord.wType,
|
||||||
|
Ttl = nativeRecord.dwTtl,
|
||||||
|
Content = nativeRecord.pStringArray,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,702 @@
|
|||||||
|
using Disco.Models.ClientServices;
|
||||||
|
using Disco.Models.ClientServices.EnrolmentInformation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop
|
||||||
|
{
|
||||||
|
public static class Hardware
|
||||||
|
{
|
||||||
|
private static DeviceHardware information;
|
||||||
|
|
||||||
|
public static DeviceHardware Information
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (information == null)
|
||||||
|
{
|
||||||
|
information = GatherInformation();
|
||||||
|
}
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DeviceHardware GatherInformation()
|
||||||
|
{
|
||||||
|
var audit = new DeviceHardware();
|
||||||
|
|
||||||
|
audit.ApplyBIOSInformation();
|
||||||
|
audit.ApplySystemInformation();
|
||||||
|
audit.ApplyBaseBoardInformation();
|
||||||
|
audit.ApplySystemProductInformation();
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(audit.SerialNumber))
|
||||||
|
{
|
||||||
|
throw new Exception("This device has no serial number stored in BIOS or BaseBoard");
|
||||||
|
}
|
||||||
|
if (audit.SerialNumber.Length > 60)
|
||||||
|
{
|
||||||
|
throw new Exception($"The serial number reported by this device is over 60 characters long:\r\n{audit.SerialNumber}");
|
||||||
|
}
|
||||||
|
|
||||||
|
audit.ApplyProcessorInformation();
|
||||||
|
audit.ApplyPhysicalMemoryInformation();
|
||||||
|
audit.ApplyDiskDriveInformation();
|
||||||
|
audit.ApplyBatteryInformation();
|
||||||
|
audit.ApplyMobileDeviceManagementInformation();
|
||||||
|
|
||||||
|
audit.NetworkAdapters = Network.GetNetworkAdapters();
|
||||||
|
|
||||||
|
return audit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyProcessorInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT DeviceID, Manufacturer, Name, Description, Architecture, Family, MaxClockSpeed, NumberOfCores, NumberOfLogicalProcessors FROM Win32_Processor"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
if (mResults.Count > 0)
|
||||||
|
{
|
||||||
|
var processors = new List<Processor>(mResults.Count);
|
||||||
|
foreach (var mItem in mResults.Cast<ManagementObject>())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
var processor = new Processor();
|
||||||
|
|
||||||
|
processor.DeviceID = (string)mItem.GetPropertyValue("DeviceID");
|
||||||
|
processor.Manufacturer = (string)mItem.GetPropertyValue("Manufacturer");
|
||||||
|
processor.Name = (string)mItem.GetPropertyValue("Name");
|
||||||
|
processor.Description = (string)mItem.GetPropertyValue("Description");
|
||||||
|
processor.Family = (ushort?)mItem.GetPropertyValue("Family");
|
||||||
|
processor.MaxClockSpeed = (uint?)mItem.GetPropertyValue("MaxClockSpeed");
|
||||||
|
processor.NumberOfCores = (uint?)mItem.GetPropertyValue("NumberOfCores");
|
||||||
|
processor.NumberOfLogicalProcessors = (uint?)mItem.GetPropertyValue("NumberOfLogicalProcessors");
|
||||||
|
processor.Architecture = ((ProcessorArchitectures?)(ushort?)mItem.GetPropertyValue("Architecture"))?.ToString();
|
||||||
|
|
||||||
|
processors.Add(processor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceHardware.Processors = processors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignore errors to ensure backwards compatibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyPhysicalMemoryInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT Tag, SerialNumber, Manufacturer, PartNumber, Capacity, ConfiguredClockSpeed, Speed, DeviceLocator FROM Win32_PhysicalMemory"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
if (mResults.Count > 0)
|
||||||
|
{
|
||||||
|
var physicalMemories = new List<PhysicalMemory>(mResults.Count);
|
||||||
|
foreach (var mItem in mResults.Cast<ManagementObject>())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
var physicalMemory = new PhysicalMemory();
|
||||||
|
|
||||||
|
physicalMemory.Tag = (string)mItem.GetPropertyValue("Tag");
|
||||||
|
physicalMemory.SerialNumber = (string)mItem.GetPropertyValue("SerialNumber");
|
||||||
|
physicalMemory.Manufacturer = (string)mItem.GetPropertyValue("Manufacturer");
|
||||||
|
physicalMemory.PartNumber = (string)mItem.GetPropertyValue("PartNumber");
|
||||||
|
physicalMemory.Capacity = (ulong?)mItem.GetPropertyValue("Capacity");
|
||||||
|
physicalMemory.ConfiguredClockSpeed = (uint?)mItem.GetPropertyValue("ConfiguredClockSpeed");
|
||||||
|
physicalMemory.Speed = (uint?)mItem.GetPropertyValue("Speed");
|
||||||
|
physicalMemory.DeviceLocator = (string)mItem.GetPropertyValue("DeviceLocator");
|
||||||
|
|
||||||
|
physicalMemories.Add(physicalMemory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceHardware.PhysicalMemory = physicalMemories;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignore errors to ensure backwards compatibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyDiskDriveInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var diskSearcher = new ManagementObjectSearcher("SELECT DeviceID, Manufacturer, Model, MediaType, InterfaceType, SerialNumber, FirmwareRevision, Size FROM Win32_DiskDrive"))
|
||||||
|
{
|
||||||
|
using (var diskResults = diskSearcher.Get())
|
||||||
|
{
|
||||||
|
if (diskResults.Count > 0)
|
||||||
|
{
|
||||||
|
var diskDrives = new List<DiskDrive>(diskResults.Count);
|
||||||
|
foreach (var diskResult in diskResults.Cast<ManagementObject>())
|
||||||
|
{
|
||||||
|
if (diskResult != null)
|
||||||
|
{
|
||||||
|
var diskDrive = new DiskDrive();
|
||||||
|
|
||||||
|
diskDrive.DeviceID = (string)diskResult.GetPropertyValue("DeviceID");
|
||||||
|
diskDrive.Manufacturer = (string)diskResult.GetPropertyValue("Manufacturer");
|
||||||
|
diskDrive.Model = (string)diskResult.GetPropertyValue("Model");
|
||||||
|
diskDrive.MediaType = (string)diskResult.GetPropertyValue("MediaType");
|
||||||
|
diskDrive.InterfaceType = (string)diskResult.GetPropertyValue("InterfaceType");
|
||||||
|
diskDrive.SerialNumber = (string)diskResult.GetPropertyValue("SerialNumber");
|
||||||
|
diskDrive.FirmwareRevision = (string)diskResult.GetPropertyValue("FirmwareRevision");
|
||||||
|
diskDrive.Size = (ulong?)diskResult.GetPropertyValue("Size");
|
||||||
|
|
||||||
|
using (var partitionSearcher = new ManagementObjectSearcher($"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID=\"{diskDrive.DeviceID.Replace(@"\", @"\\")}\"}} WHERE AssocClass = Win32_DiskDriveToDiskPartition"))
|
||||||
|
{
|
||||||
|
using (var partitionResults = partitionSearcher.Get())
|
||||||
|
{
|
||||||
|
if (partitionResults.Count > 0)
|
||||||
|
{
|
||||||
|
var partitions = new List<DiskDrivePartition>(partitionResults.Count);
|
||||||
|
foreach (var partitionResult in partitionResults.Cast<ManagementObject>())
|
||||||
|
{
|
||||||
|
if (partitionResult != null)
|
||||||
|
{
|
||||||
|
var partition = new DiskDrivePartition();
|
||||||
|
|
||||||
|
partition.DeviceID = (string)partitionResult.GetPropertyValue("DeviceID");
|
||||||
|
partition.Bootable = (bool?)partitionResult.GetPropertyValue("Bootable");
|
||||||
|
partition.BootPartition = (bool?)partitionResult.GetPropertyValue("BootPartition");
|
||||||
|
partition.PrimaryParition = (bool?)partitionResult.GetPropertyValue("PrimaryPartition");
|
||||||
|
partition.Size = (ulong?)partitionResult.GetPropertyValue("Size");
|
||||||
|
partition.StartingOffset = (ulong?)partitionResult.GetPropertyValue("StartingOffset");
|
||||||
|
partition.Type = (string)partitionResult.GetPropertyValue("Type");
|
||||||
|
|
||||||
|
using (var logicalSearcher = new ManagementObjectSearcher($"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID=\"{partition.DeviceID}\"}} WHERE AssocClass = Win32_LogicalDiskToPartition"))
|
||||||
|
{
|
||||||
|
using (var logicalResults = logicalSearcher.Get())
|
||||||
|
{
|
||||||
|
if (logicalResults.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var logicalResult in logicalResults.Cast<ManagementObject>().Take(1))
|
||||||
|
{
|
||||||
|
if (logicalResult != null)
|
||||||
|
{
|
||||||
|
var logical = new DiskLogical();
|
||||||
|
|
||||||
|
logical.DeviceID = (string)logicalResult.GetPropertyValue("DeviceID");
|
||||||
|
logical.Description = (string)logicalResult.GetPropertyValue("Description");
|
||||||
|
logical.DriveType = ((DiskLogicalDriveTypes?)(uint?)logicalResult.GetPropertyValue("DriveType")).ToString();
|
||||||
|
logical.MediaType = ((DiskLogicalMediaTypes?)(uint?)logicalResult.GetPropertyValue("MediaType")).ToString();
|
||||||
|
logical.FileSystem = (string)logicalResult.GetPropertyValue("FileSystem");
|
||||||
|
logical.Size = (ulong?)logicalResult.GetPropertyValue("Size");
|
||||||
|
logical.FreeSpace = (ulong?)logicalResult.GetPropertyValue("FreeSpace");
|
||||||
|
logical.VolumeName = (string)logicalResult.GetPropertyValue("VolumeName");
|
||||||
|
logical.VolumeSerialNumber = (string)logicalResult.GetPropertyValue("VolumeSerialNumber");
|
||||||
|
|
||||||
|
partition.LogicalDisk = logical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partitions.Add(partition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diskDrive.Partitions = partitions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diskDrives.Add(diskDrive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceHardware.DiskDrives = diskDrives;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignore errors to ensure backwards compatibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void ApplyBatteryInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT DeviceID, Availability, Chemistry, Description, DesignCapacity, DesignVoltage, FullChargeCapacity, Name FROM Win32_Battery"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
if (mResults.Count > 0)
|
||||||
|
{
|
||||||
|
var batteries = new List<Battery>(mResults.Count);
|
||||||
|
foreach (var mItem in mResults.Cast<ManagementObject>())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
var battery = new Battery();
|
||||||
|
|
||||||
|
battery.Availability = ((BatteryAvailability?)(ushort?)mItem.GetPropertyValue("Availability"))?.ToString();
|
||||||
|
battery.Chemistry = ((BatteryChemistry?)(ushort?)mItem.GetPropertyValue("Chemistry"))?.ToString();
|
||||||
|
battery.Description = (string)mItem.GetPropertyValue("Description");
|
||||||
|
battery.DesignCapacity = (uint?)mItem.GetPropertyValue("DesignCapacity");
|
||||||
|
battery.DeviceID = (string)mItem.GetPropertyValue("DeviceID");
|
||||||
|
battery.FullChargeCapacity = (uint?)mItem.GetPropertyValue("FullChargeCapacity");
|
||||||
|
battery.Name = (string)mItem.GetPropertyValue("Name");
|
||||||
|
|
||||||
|
batteries.Add(battery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deviceHardware.Batteries = batteries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignore errors to ensure backwards compatibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyBIOSInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT BIOSVersion, Manufacturer, ReleaseDate, SerialNumber, SMBIOSBIOSVersion, SMBIOSMajorVersion, SMBIOSMinorVersion, SystemBiosMajorVersion, SystemBiosMinorVersion FROM Win32_BIOS WHERE PrimaryBios=true"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
var serialNumber = (string)mItem.GetPropertyValue("SerialNumber");
|
||||||
|
if (!string.IsNullOrWhiteSpace(serialNumber))
|
||||||
|
deviceHardware.SerialNumber = serialNumber.Trim();
|
||||||
|
|
||||||
|
var manufacturer = (string)mItem.GetPropertyValue("Manufacturer");
|
||||||
|
if (deviceHardware.Manufacturer == null && !string.IsNullOrWhiteSpace(manufacturer))
|
||||||
|
deviceHardware.Manufacturer = manufacturer.Trim();
|
||||||
|
|
||||||
|
ErrorReporting.DeviceIdentifier = deviceHardware.SerialNumber;
|
||||||
|
|
||||||
|
var biosVersion = (string[])mItem.GetPropertyValue("BIOSVersion");
|
||||||
|
var releaseDate = default(DateTime?);
|
||||||
|
var releaseDateString = (string)mItem.GetPropertyValue("ReleaseDate");
|
||||||
|
if (releaseDateString != null && releaseDateString.Length == 25 && int.TryParse(releaseDateString.Substring(22), out var offsetMinutes))
|
||||||
|
{
|
||||||
|
releaseDateString = $"{releaseDateString.Substring(0, 22)}{offsetMinutes / 60:00}:{Math.Abs(offsetMinutes % 60):00}";
|
||||||
|
if (DateTime.TryParseExact(releaseDateString, "yyyyMMddHHmmss.ffffffzzz", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var releaseDateResult))
|
||||||
|
releaseDate = releaseDateResult;
|
||||||
|
}
|
||||||
|
var sMBIOSBIOSVersion = (string)mItem.GetPropertyValue("SMBIOSBIOSVersion");
|
||||||
|
var sMBIOSMajorVersion = (ushort?)mItem.GetPropertyValue("SMBIOSMajorVersion");
|
||||||
|
var sMBIOSMinorVersion = (ushort?)mItem.GetPropertyValue("SMBIOSMinorVersion");
|
||||||
|
var systemBiosMajorVersion = (byte?)mItem.GetPropertyValue("SystemBiosMajorVersion");
|
||||||
|
var systemBiosMinorVersion = (byte?)mItem.GetPropertyValue("SystemBiosMinorVersion");
|
||||||
|
|
||||||
|
var bios = new Bios()
|
||||||
|
{
|
||||||
|
BIOSVersion = biosVersion,
|
||||||
|
Manufacturer = manufacturer,
|
||||||
|
ReleaseDate = releaseDate,
|
||||||
|
SerialNumber = serialNumber,
|
||||||
|
SMBIOSBIOSVersion = sMBIOSBIOSVersion,
|
||||||
|
SMBIOSMajorVersion = sMBIOSMajorVersion,
|
||||||
|
SMBIOSMinorVersion = sMBIOSMinorVersion,
|
||||||
|
SystemBiosMajorVersion = systemBiosMajorVersion,
|
||||||
|
SystemBiosMinorVersion = systemBiosMinorVersion,
|
||||||
|
};
|
||||||
|
deviceHardware.Bios = new List<Bios>() { bios };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("No Win32_BIOS WHERE PrimaryBios=true was found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception("Disco ICT Client was unable to retrieve BIOS information from WMI", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplySystemInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT ChassisSKUNumber, CurrentTimeZone, Description, Manufacturer, Model, OEMStringArray, PCSystemType, PrimaryOwnerContact, PrimaryOwnerName, Roles, SystemSKUNumber, SystemType FROM Win32_ComputerSystem"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
var manufacturer = (string)mItem.GetPropertyValue("Manufacturer");
|
||||||
|
if (!string.IsNullOrWhiteSpace(manufacturer))
|
||||||
|
deviceHardware.Manufacturer = manufacturer.Trim();
|
||||||
|
|
||||||
|
var model = (string)mItem.GetPropertyValue("Model");
|
||||||
|
if (!string.IsNullOrWhiteSpace(model))
|
||||||
|
deviceHardware.Model = model;
|
||||||
|
|
||||||
|
deviceHardware.ModelType = ((PCSystemTypes)mItem.GetPropertyValue("PCSystemType")).Description();
|
||||||
|
|
||||||
|
var chassisSKUNumber = (string)mItem.GetPropertyValue("ChassisSKUNumber");
|
||||||
|
var currentTimeZone = (short?)mItem.GetPropertyValue("CurrentTimeZone");
|
||||||
|
var description = (string)mItem.GetPropertyValue("Description");
|
||||||
|
var oemStringArray = (string[])mItem.GetPropertyValue("OEMStringArray");
|
||||||
|
var pcSystemType = ((PCSystemTypes)mItem.GetPropertyValue("PCSystemType")).ToString();
|
||||||
|
var primaryOwnerContact = (string)mItem.GetPropertyValue("PrimaryOwnerContact");
|
||||||
|
var primaryOwnerName = (string)mItem.GetPropertyValue("PrimaryOwnerName");
|
||||||
|
var roles = (string[])mItem.GetPropertyValue("Roles");
|
||||||
|
var systemSKUNumber = (string)mItem.GetPropertyValue("SystemSKUNumber");
|
||||||
|
var systemType = (string)mItem.GetPropertyValue("SystemType");
|
||||||
|
|
||||||
|
var computerSystem = new ComputerSystem()
|
||||||
|
{
|
||||||
|
ChassisSKUNumber = chassisSKUNumber,
|
||||||
|
CurrentTimeZone = currentTimeZone,
|
||||||
|
Description = description,
|
||||||
|
OEMStringArray = oemStringArray,
|
||||||
|
PCSystemType = pcSystemType,
|
||||||
|
PrimaryOwnerContact = primaryOwnerContact,
|
||||||
|
PrimaryOwnerName = primaryOwnerName,
|
||||||
|
Roles = roles,
|
||||||
|
SystemSKUNumber = systemSKUNumber,
|
||||||
|
SystemType = systemType,
|
||||||
|
};
|
||||||
|
|
||||||
|
deviceHardware.ComputerSystem = new List<ComputerSystem>() { computerSystem };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("No Win32_ComputerSystem was found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception("Disco ICT Client was unable to retrieve ComputerSystem information from WMI", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ApplySystemInformation(this Enrol enrol)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT PartOfDomain, Domain FROM Win32_ComputerSystem"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
enrol.IsPartOfDomain = (bool)mItem.GetPropertyValue("PartOfDomain");
|
||||||
|
|
||||||
|
if (enrol.IsPartOfDomain)
|
||||||
|
{
|
||||||
|
enrol.DNSDomainName = (string)mItem.GetPropertyValue("Domain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("No Win32_ComputerSystem was found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception("Disco ICT Client was unable to retrieve ComputerSystem information from WMI", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyBaseBoardInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT ConfigOptions, Manufacturer, Model, PartNumber, Product, SerialNumber, SKU, Version FROM Win32_BaseBoard"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
// Apply Manufacturer/Model information only if not previously found in Win32_ComputerSystem
|
||||||
|
var manufacturer = (string)mItem.GetPropertyValue("Manufacturer");
|
||||||
|
if (deviceHardware.Manufacturer == null && !string.IsNullOrWhiteSpace(manufacturer))
|
||||||
|
{
|
||||||
|
deviceHardware.Manufacturer = manufacturer.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
var model = (string)mItem.GetPropertyValue("Model");
|
||||||
|
if (deviceHardware.Model == null && !string.IsNullOrWhiteSpace(model))
|
||||||
|
{
|
||||||
|
deviceHardware.Model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
var product = (string)mItem.GetPropertyValue("Product");
|
||||||
|
if (deviceHardware.Model == null && !string.IsNullOrWhiteSpace(product))
|
||||||
|
{
|
||||||
|
deviceHardware.Model = product;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added 2012-11-22 G# - Lenovo IdeaPad Serial SHIM
|
||||||
|
// http://www.discoict.com.au/forum/feature-requests/2012/11/serial-number-detection-on-ideapads.aspx
|
||||||
|
var serialNumber = (string)mItem.GetPropertyValue("SerialNumber");
|
||||||
|
if (!string.IsNullOrWhiteSpace(serialNumber) &&
|
||||||
|
(deviceHardware.SerialNumber == null ||
|
||||||
|
((deviceHardware.Manufacturer?.Equals("LENOVO", StringComparison.OrdinalIgnoreCase) ?? false) &&
|
||||||
|
((deviceHardware.Model?.Equals("S10-3", StringComparison.OrdinalIgnoreCase) ?? false) // S10-3
|
||||||
|
|| (deviceHardware.Model?.Equals("2957", StringComparison.OrdinalIgnoreCase) ?? false)))))
|
||||||
|
{
|
||||||
|
deviceHardware.SerialNumber = serialNumber.Trim();
|
||||||
|
ErrorReporting.DeviceIdentifier = deviceHardware.SerialNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
var configOptions = (string[])mItem.GetPropertyValue("ConfigOptions");
|
||||||
|
var partNumber = (string)mItem.GetPropertyValue("PartNumber");
|
||||||
|
var sku = (string)mItem.GetPropertyValue("SKU");
|
||||||
|
var version = (string)mItem.GetPropertyValue("Version");
|
||||||
|
|
||||||
|
var baseBoard = new BaseBoard()
|
||||||
|
{
|
||||||
|
ConfigOptions = configOptions,
|
||||||
|
Manufacturer = manufacturer,
|
||||||
|
Model = model,
|
||||||
|
PartNumber = partNumber,
|
||||||
|
Product = product,
|
||||||
|
SerialNumber = serialNumber,
|
||||||
|
SKU = sku,
|
||||||
|
Version = version,
|
||||||
|
};
|
||||||
|
|
||||||
|
deviceHardware.BasebBoard = new List<BaseBoard>() { baseBoard };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("No Win32_BaseBoard was found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception("Disco ICT Client was unable to retrieve BaseBoard information from WMI", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplySystemProductInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var mSearcher = new ManagementObjectSearcher("SELECT IdentifyingNumber, UUID FROM Win32_ComputerSystemProduct"))
|
||||||
|
{
|
||||||
|
using (var mResults = mSearcher.Get())
|
||||||
|
{
|
||||||
|
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
|
||||||
|
{
|
||||||
|
if (mItem != null)
|
||||||
|
{
|
||||||
|
if (deviceHardware.SerialNumber == null)
|
||||||
|
{
|
||||||
|
var serialNumber = mItem.GetPropertyValue("IdentifyingNumber") as string;
|
||||||
|
if (!string.IsNullOrWhiteSpace(serialNumber))
|
||||||
|
{
|
||||||
|
deviceHardware.SerialNumber = serialNumber.Trim();
|
||||||
|
ErrorReporting.DeviceIdentifier = deviceHardware.SerialNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var uUID = (string)mItem.GetPropertyValue("UUID");
|
||||||
|
if (!string.IsNullOrWhiteSpace(uUID))
|
||||||
|
{
|
||||||
|
deviceHardware.UUID = uUID.Trim();
|
||||||
|
|
||||||
|
// if serial number is absent attempt using UUID if valid
|
||||||
|
if (string.IsNullOrWhiteSpace(deviceHardware.SerialNumber))
|
||||||
|
{
|
||||||
|
if (Guid.TryParse(deviceHardware.UUID, out var uuidGuid) && uuidGuid != Guid.Empty)
|
||||||
|
{
|
||||||
|
deviceHardware.SerialNumber = $"UUID{uuidGuid:N}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("No Win32_ComputerSystemProduct was found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception("Disco ICT Client was unable to retrieve ComputerSystemProduct information from WMI", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ApplyMobileDeviceManagementInformation(this DeviceHardware deviceHardware)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var wmiObject = new ManagementObject(@"\\.\ROOT\CIMV2\mdm\dmmap:MDM_DevDetail_Ext01.InstanceID=""Ext"",ParentID=""./DevDetail"""))
|
||||||
|
{
|
||||||
|
deviceHardware.MdmHardwareData = (string)wmiObject.GetPropertyValue("DeviceHardwareData");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Description(this PCSystemTypes type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case PCSystemTypes.Desktop:
|
||||||
|
return "Desktop";
|
||||||
|
case PCSystemTypes.Mobile:
|
||||||
|
return "Mobile";
|
||||||
|
case PCSystemTypes.Workstation:
|
||||||
|
return "Workstation";
|
||||||
|
case PCSystemTypes.EnterpriseServer:
|
||||||
|
return "Enterprise Server";
|
||||||
|
case PCSystemTypes.SmallOfficeAndHomeOfficeServer:
|
||||||
|
return "Small Office And Home Office Server";
|
||||||
|
case PCSystemTypes.AppliancePC:
|
||||||
|
return "Appliance PC";
|
||||||
|
case PCSystemTypes.PerformanceServer:
|
||||||
|
return "Performance Server";
|
||||||
|
case PCSystemTypes.Maximum:
|
||||||
|
return "Maximum";
|
||||||
|
case PCSystemTypes.Unknown:
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum PCSystemTypes : ushort
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Desktop,
|
||||||
|
Mobile,
|
||||||
|
Workstation,
|
||||||
|
EnterpriseServer,
|
||||||
|
SmallOfficeAndHomeOfficeServer,
|
||||||
|
AppliancePC,
|
||||||
|
PerformanceServer,
|
||||||
|
Maximum
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ProcessorArchitectures : ushort
|
||||||
|
{
|
||||||
|
x86 = 0,
|
||||||
|
MIPS = 1,
|
||||||
|
Alpha = 2,
|
||||||
|
PowerPC = 3,
|
||||||
|
ia64 = 6,
|
||||||
|
x64 = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DiskLogicalDriveTypes : uint
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
NoRootDirectory,
|
||||||
|
Removable,
|
||||||
|
Fixed,
|
||||||
|
Remote,
|
||||||
|
CDRom,
|
||||||
|
RAMDisk,
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DiskLogicalMediaTypes : uint
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
F5_1Pt2_512,
|
||||||
|
F3_1Pt44_512,
|
||||||
|
F3_2Pt88_512,
|
||||||
|
F3_20Pt8_512,
|
||||||
|
F3_720_512,
|
||||||
|
F5_360_512,
|
||||||
|
F5_320_512,
|
||||||
|
F5_320_1024,
|
||||||
|
F5_180_512,
|
||||||
|
F5_160_512,
|
||||||
|
RemovableMedia,
|
||||||
|
FixedMedia,
|
||||||
|
F3_120M_512,
|
||||||
|
F3_640_512,
|
||||||
|
F5_640_512,
|
||||||
|
F5_720_512,
|
||||||
|
F3_1Pt2_512,
|
||||||
|
F3_1Pt23_1024,
|
||||||
|
F5_1Pt23_1024,
|
||||||
|
F3_128Mb_512,
|
||||||
|
F3_230Mb_512,
|
||||||
|
F8_256_128,
|
||||||
|
F3_200Mb_512,
|
||||||
|
F3_240M_512,
|
||||||
|
F3_32M_512,
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum BatteryAvailability : ushort
|
||||||
|
{
|
||||||
|
Other = 1,
|
||||||
|
Unknown = 2,
|
||||||
|
RunningFullPower = 3,
|
||||||
|
Warning = 4,
|
||||||
|
InTest = 5,
|
||||||
|
NotApplicable = 6,
|
||||||
|
PowerOff = 7,
|
||||||
|
OffLine = 8,
|
||||||
|
OffDuty = 9,
|
||||||
|
Degraded = 10,
|
||||||
|
NotInstalled = 11,
|
||||||
|
InstallError = 12,
|
||||||
|
PowerSaveUnknown = 13,
|
||||||
|
PowerSaveLowPowerMode = 14,
|
||||||
|
PowerSaveStandby = 15,
|
||||||
|
PowerCycle = 16,
|
||||||
|
PowerSaveWarning = 17,
|
||||||
|
Paused = 18,
|
||||||
|
NotReady = 19,
|
||||||
|
NotConfigured = 20,
|
||||||
|
Quiesced = 21,
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum BatteryChemistry : ushort
|
||||||
|
{
|
||||||
|
Other = 1,
|
||||||
|
Unknown = 2,
|
||||||
|
LeadAcid = 3,
|
||||||
|
NickelCadmium = 4,
|
||||||
|
NickelMetalHydride = 5,
|
||||||
|
LithiumIon = 6,
|
||||||
|
ZincAir = 7,
|
||||||
|
LithiumPolymer = 8,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.DirectoryServices;
|
using System.DirectoryServices;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.Client.Interop
|
namespace Disco.Client.Interop
|
||||||
{
|
{
|
||||||
@@ -14,7 +10,7 @@ namespace Disco.Client.Interop
|
|||||||
public static bool AddLocalGroupMembership(string GroupName, string UserSID, string Username, string UserDomain)
|
public static bool AddLocalGroupMembership(string GroupName, string UserSID, string Username, string UserDomain)
|
||||||
{
|
{
|
||||||
|
|
||||||
using (DirectoryEntry group = new DirectoryEntry(string.Format("WinNT://./{0},group", GroupName)))
|
using (DirectoryEntry group = new DirectoryEntry($"WinNT://./{GroupName},group"))
|
||||||
{
|
{
|
||||||
// Check to see if the User is already a member
|
// Check to see if the User is already a member
|
||||||
foreach (object memberRef in (IEnumerable)group.Invoke("Members"))
|
foreach (object memberRef in (IEnumerable)group.Invoke("Members"))
|
||||||
@@ -22,38 +18,15 @@ namespace Disco.Client.Interop
|
|||||||
using (DirectoryEntry member = new DirectoryEntry(memberRef))
|
using (DirectoryEntry member = new DirectoryEntry(memberRef))
|
||||||
{
|
{
|
||||||
var memberPath = member.Path;
|
var memberPath = member.Path;
|
||||||
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.InvariantCultureIgnoreCase) ||
|
if (memberPath.Equals($"WinNT://{UserDomain}/{Username}", StringComparison.OrdinalIgnoreCase) ||
|
||||||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.InvariantCultureIgnoreCase))
|
memberPath.Equals($"WinNT://{UserSID}", StringComparison.OrdinalIgnoreCase))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
group.Invoke("Add", string.Format("WinNT://{0}", UserSID));
|
group.Invoke("Add", $"WinNT://{UserSID}");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string CurrentUserDomain
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Environment.UserDomainName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static string CurrentUserName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Environment.UserName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ComputerName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return Environment.MachineName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
public enum NetworkConnectionStatuses : ushort
|
||||||
|
{
|
||||||
|
Disconnected = 0,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
Disconnecting,
|
||||||
|
HardwareNotPresent,
|
||||||
|
HardwareDisabled,
|
||||||
|
HardwareMalfunction,
|
||||||
|
MediaDisconnected,
|
||||||
|
Authenticating,
|
||||||
|
AuthenticationSucceeded,
|
||||||
|
AuthenticationFailed,
|
||||||
|
InvalidAddress,
|
||||||
|
CredentialsRequired
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum ProfileInfoFlags : uint
|
||||||
|
{
|
||||||
|
WLAN_PROFILE_GROUP_POLICY = 1,
|
||||||
|
WLAN_PROFILE_USER = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
/// <summary >
|
||||||
|
/// The WLAN_INTERFACE_INFO structure contains information about a wireless LAN interface.
|
||||||
|
/// </summary >
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
public struct WLAN_INTERFACE_INFO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the GUID of the interface.
|
||||||
|
/// </summary>
|
||||||
|
public Guid InterfaceGuid;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the description of the interface.
|
||||||
|
/// </summary>
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||||
|
public string strInterfaceDescription;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains a WLAN_INTERFACE_STATE value that indicates the current state of the interface.
|
||||||
|
/// Windows XP with SP3 and Wireless LAN API for Windows XP with SP2: Only the wlan_interface_state_connected,
|
||||||
|
/// wlan_interface_state_disconnected, and wlan_interface_state_authenticating values are supported.
|
||||||
|
/// </summary>
|
||||||
|
public WLAN_INTERFACE_STATE isState;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The WLAN_INTERFACE_INFO_LIST structure contains an array of NIC interface information.
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct WLAN_INTERFACE_INFO_LIST
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the number of items in the InterfaceInfo member.
|
||||||
|
/// </summary>
|
||||||
|
public uint dwNumberOfItems;
|
||||||
|
/// <summary>
|
||||||
|
/// The index of the current item. The index of the first item is 0. dwIndex must be less than dwNumberOfItems.
|
||||||
|
/// This member is not used by the wireless service. Applications can use this member when processing individual
|
||||||
|
/// interfaces in the WLAN_INTERFACE_INFO_LIST structure. When an application passes this structure from one
|
||||||
|
/// function to another, it can set the value of dwIndex to the index of the item currently being processed.
|
||||||
|
/// This can help an application maintain state.
|
||||||
|
/// dwIndex should always be initialized before use.
|
||||||
|
/// </summary>
|
||||||
|
public uint dwIndex;
|
||||||
|
|
||||||
|
private IntPtr InterfaceInfoPtr;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An array of WLAN_INTERFACE_INFO structures containing interface information.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<WLAN_INTERFACE_INFO> InterfaceInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf(typeof(WLAN_INTERFACE_INFO));
|
||||||
|
for (int i = 0; i < dwNumberOfItems; i++)
|
||||||
|
{
|
||||||
|
yield return (WLAN_INTERFACE_INFO)Marshal.PtrToStructure(InterfaceInfoPtr + (i * size), typeof(WLAN_INTERFACE_INFO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WLAN_INTERFACE_INFO_LIST(IntPtr Pointer)
|
||||||
|
{
|
||||||
|
dwNumberOfItems = (uint)Marshal.ReadInt32(Pointer, 0);
|
||||||
|
dwIndex = (uint)Marshal.ReadInt32(Pointer, 4);
|
||||||
|
InterfaceInfoPtr = Pointer + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The WLAN_INTERFACE_STATE enumerated type indicates the state of an interface.
|
||||||
|
/// Windows XP with SP3 and Wireless LAN API for Windows XP with SP2: Only the wlan_interface_state_connected,
|
||||||
|
/// wlan_interface_state_disconnected, and wlan_interface_state_authenticating values are supported.
|
||||||
|
/// </summary>
|
||||||
|
public enum WLAN_INTERFACE_STATE
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is not ready to operate.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_not_ready = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is connected to a network.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_connected = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is the first node in an ad hoc network. No peer has connected.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_ad_hoc_network_formed = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is disconnecting from the current network.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_disconnecting = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is not connected to any network.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_disconnected = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is attempting to associate with a network.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_associating = 5,
|
||||||
|
/// <summary>
|
||||||
|
/// Auto configuration is discovering the settings for the network.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_discovering = 6,
|
||||||
|
/// <summary>
|
||||||
|
/// The interface is in the process of authenticating.
|
||||||
|
/// </summary>
|
||||||
|
wlan_interface_state_authenticating = 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
public struct WLAN_PROFILE_INFO
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the profile. This value may be the name of a domain if the profile is for provisioning. Profile names are case-sensitive.
|
||||||
|
/// This string must be NULL-terminated.
|
||||||
|
/// Windows XP with SP3 and Wireless LAN API for Windows XP with SP2: The name of the profile is derived automatically from
|
||||||
|
/// the SSID of the wireless network. For infrastructure network profiles, the name of the profile is the SSID of the network.
|
||||||
|
/// For ad hoc network profiles, the name of the profile is the SSID of the ad hoc network followed by -adhoc.
|
||||||
|
/// </summary>
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||||
|
public string strInterfaceDescription;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A set of flags specifying settings for wireless profile. These values are defined in the Wlanapi.h header file.
|
||||||
|
/// Windows XP with SP3 and Wireless LAN API for Windows XP with SP2: dwFlags must be 0. Per-user profiles are not supported.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileInfoFlags dwFlags;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Disco.Client.Interop.Native
|
||||||
|
{
|
||||||
|
public struct WLAN_PROFILE_INFO_LIST
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The number of wireless profile entries in the ProfileInfo member.
|
||||||
|
/// </summary>
|
||||||
|
public uint dwNumberOfItems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The index of the current item. The index of the first item is 0. The dwIndex member must be less than the dwNumberOfItems member.
|
||||||
|
/// This member is not used by the wireless service. Applications can use this member when processing individual profiles in the
|
||||||
|
/// WLAN_PROFILE_INFO_LIST structure. When an application passes this structure from one function to another, it can set the value
|
||||||
|
/// of dwIndex to the index of the item currently being processed. This can help an application maintain state.
|
||||||
|
/// dwIndex should always be initialized before use.
|
||||||
|
/// </summary>
|
||||||
|
public uint dwIndex;
|
||||||
|
|
||||||
|
private IntPtr ProfileInfoPointer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An array of WLAN_PROFILE_INFO structures containing interface information. The number of items in the array is specified in the dwNumberOfItems member.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<WLAN_PROFILE_INFO> ProfileInfo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var size = Marshal.SizeOf(typeof(WLAN_PROFILE_INFO));
|
||||||
|
for (int i = 0; i < dwNumberOfItems; i++)
|
||||||
|
{
|
||||||
|
yield return (WLAN_PROFILE_INFO)Marshal.PtrToStructure(ProfileInfoPointer + (i * size), typeof(WLAN_PROFILE_INFO));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WLAN_PROFILE_INFO_LIST(IntPtr Pointer)
|
||||||
|
{
|
||||||
|
dwNumberOfItems = (uint)Marshal.ReadInt32(Pointer, 0);
|
||||||
|
dwIndex = (uint)Marshal.ReadInt32(Pointer, 4);
|
||||||
|
ProfileInfoPointer = Pointer + 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user