362 Commits

Author SHA1 Message Date
dependabot[bot] f1ba0c21de build(deps): bump jQuery from 2.1.1 to 3.5.0 in /Disco.Web
Bumps jQuery from 2.1.1 to 3.5.0.

---
updated-dependencies:
- dependency-name: jQuery
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-31 20:06:13 +00:00
Gary Sharp 0a4a2816a0 feature: bulk generate documents for device batches, models and profiles 2023-05-04 15:30:04 +10:00
Gary Sharp 473b02f718 bug fix: TryBinaryNumericEncode on small numbers 2023-05-04 15:27:46 +10:00
Gary Sharp 5a2c29ea0b bug: unable to bulk generate documents for devices/job; honor the id sort order 2023-05-04 13:06:04 +10:00
Gary Sharp 1a8ec32f0f view batch devices from index
requested by @RB
2023-04-28 15:39:44 +10:00
Gary Sharp 9e7daf2043 data tables remember pagination size preference 2023-04-28 14:36:01 +10:00
Gary Sharp 0c690cff5a bulk generation refactoring 2023-04-27 14:54:32 +10:00
Gary Sharp b55b77de9f initialize plugin scheduled tasks when installed 2023-04-26 18:16:46 +10:00
Gary Sharp 937508c440 document template user flag rules should use the creator user for flag assignment 2023-04-16 15:14:14 +10:00
Gary Sharp cfe4c4b912 refactor expression caching; add document fields 2023-04-16 14:02:35 +10:00
Gary Sharp d75663a219 document template on import user flag rules 2023-04-16 09:50:19 +10:00
Gary Sharp 1e24844e88 respect whitespace when rendering logs 2023-04-14 16:40:30 +10:00
Gary Sharp 273b67c422 support user details category in document bulk generation 2023-04-14 16:40:13 +10:00
Gary Sharp 13549e7ec4 bug fix: calculate task progress offsets and multiplier correctly 2023-04-14 16:39:14 +10:00
Gary Sharp bbb40bd5c4 register plugin references before initialization 2023-04-14 16:38:38 +10:00
Gary Sharp 22dad072b9 refactor user details plugin interface 2023-04-14 16:37:42 +10:00
Gary Sharp 215e9863a2 bug: client was unable to run djoin.exe
perhaps a behaviour change between dotnet 4.5 and 4.5.2. It was looking for djoin.exe in the SysWow directory.
2023-02-12 18:42:19 +11:00
Gary Sharp 190abc72dd bug: when adding computer offline, computer name should not be required 2023-02-09 20:03:20 +11:00
Gary Sharp af75a55d44 AddFlag helper method for expressions 2023-02-08 18:03:55 +11:00
Gary Sharp e05206d405 bug: correctly store email settings 2023-02-08 16:57:49 +11:00
Gary Sharp 53eed02a4f globally enable TLS1.2 2023-02-08 16:52:28 +11:00
Gary Sharp 57a7f67c3a remove device custom details
this plugin functionality has never been used
2023-02-08 16:24:21 +11:00
Gary Sharp 47e11c0fd6 bugs: minor 2023-01-29 10:10:37 +11:00
Gary Sharp 708ca16de8 minor framework updates 2023-01-29 10:07:19 +11:00
Gary Sharp 535a3f2967 bug: dont throw if unable to resolve online services 2023-01-28 13:37:27 +11:00
Gary Sharp ebd1c79f64 fix: increase pdf generated image resolution 2022-12-15 16:23:54 +11:00
Gary Sharp 7194dd612d bug: image montage layout 2022-12-15 16:08:24 +11:00
Gary Sharp 584bc07824 minor: when creating a job scoped document template default to all job types 2022-12-15 15:00:31 +11:00
Gary Sharp 2bd9238090 feature: support hiding user details with asterisk and ampersand suffixes 2022-12-09 12:23:41 +11:00
Gary Sharp b11fa5b1d6 Newtonsoft.Json 13.0.2 update 2022-12-08 11:15:34 +11:00
Gary Sharp 7667eaa49e maintenance: improved css minify 2022-12-04 15:21:04 +11:00
Gary Sharp 9f7c0f965e Microsoft.Owin update 2022-12-04 15:12:33 +11:00
Gary Sharp a274a33cf6 Newtonsoft.Json update 2022-12-04 15:05:51 +11:00
Gary Sharp 4acfd54319 Merge pull request #119 from garysharp/dependabot/nuget/Disco.Web.Extensions/Newtonsoft.Json-13.0.1
Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Web.Extensions
2022-12-04 14:20:40 +11:00
dependabot[bot] 941f1cf13e Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Web.Extensions
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 03:20:30 +00:00
Gary Sharp f225edd2d4 Merge pull request #118 from garysharp/dependabot/nuget/Disco.Data/Newtonsoft.Json-13.0.1
Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Data
2022-12-04 14:20:06 +11:00
Gary Sharp 5824680e2a Merge pull request #117 from garysharp/dependabot/nuget/Disco.Models/Newtonsoft.Json-13.0.1
Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Models
2022-12-04 14:19:55 +11:00
Gary Sharp ed4ec890da Merge pull request #120 from garysharp/dependabot/nuget/Disco.Client/Newtonsoft.Json-13.0.1
Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Client
2022-12-04 14:19:39 +11:00
Gary Sharp 56453fa081 Merge pull request #121 from garysharp/dependabot/nuget/Disco.Services/Newtonsoft.Json-13.0.1
Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Services
2022-12-04 14:19:25 +11:00
dependabot[bot] 11c824518f Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Client
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 03:18:33 +00:00
dependabot[bot] d720303a83 Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Data
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 03:18:32 +00:00
dependabot[bot] 02b29948ce Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Models
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 03:18:29 +00:00
dependabot[bot] a152365312 Bump Newtonsoft.Json from 6.0.3 to 13.0.1 in /Disco.Services
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.3 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.3...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 03:18:22 +00:00
Gary Sharp dba6c383f6 moment.js update 2022-12-04 14:17:31 +11:00
dependabot[bot] ba32b3b717 Bump Moment.js from 2.7.0 to 2.29.4 in /Disco.Web
Bumps [Moment.js](https://github.com/timrwood/moment) from 2.7.0 to 2.29.4.
- [Release notes](https://github.com/timrwood/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/timrwood/moment/compare/2.7.0...2.29.4)

---
updated-dependencies:
- dependency-name: Moment.js
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-04 14:00:00 +11:00
Gary Sharp 51cebd0706 maintenance: update T4MVC 2022-12-04 14:00:00 +11:00
Gary Sharp 983bdbefb9 maintenance: rebuild bundling/minify 2022-12-04 13:59:59 +11:00
Gary Sharp be99083d6a feature: bulk generating user documents 2022-12-04 13:47:24 +11:00
Gary Sharp 4c19a1ef63 minor: return correct content type for jpg 2022-12-04 13:47:24 +11:00
Gary Sharp 4f9f0fd0a8 maintenance: plugin refactoring 2022-12-04 13:47:24 +11:00
Gary Sharp 05593a1466 maintenance: document template refactoring 2022-12-04 13:47:23 +11:00
Gary Sharp 2873b4be8a bug: log detected thumbnail after collecting more information 2022-12-04 13:47:23 +11:00
Gary Sharp 7a1ff211a0 feature: user contact details 2022-12-04 13:47:23 +11:00
Gary Sharp fcf70f724e maintenance: dependency updates 2022-12-04 13:47:22 +11:00
Gary Sharp 99be87ed9c maintenance: AD integration refactoring 2022-12-04 13:47:22 +11:00
Gary Sharp 261baf669e fix: add accept attribute to file pickers 2022-12-04 13:47:22 +11:00
Gary Sharp b0fddd491b fix: simplify document template managed groups 2022-12-04 13:47:21 +11:00
Gary Sharp dff47c0e8b feature: export device custom details 2022-12-04 13:47:21 +11:00
Gary Sharp ed58619919 fix: configuration optimization 2022-12-04 13:47:20 +11:00
Gary Sharp 2a2731b9f3 feature: task-based document bulk generation 2022-12-04 13:47:20 +11:00
Gary Sharp 13e666d95a feature: document handlers 2022-12-04 13:47:19 +11:00
Gary Sharp 96cccab958 feature: pdf field locations cached 2022-12-04 13:47:18 +11:00
Gary Sharp e463a7361e feature: email address and phone numbers as links 2022-12-04 13:47:17 +11:00
Gary Sharp 58e467b6d6 feature: support importing device computer name 2022-12-04 13:47:17 +11:00
Gary Sharp 81bd6ccd83 bug: importing a PDF attachment fails if the template or target no longer exist 2022-09-07 18:08:28 +10:00
Gary Sharp 3e7db6b552 qol: remove exceptionless 2022-02-18 13:57:42 +11:00
Gary Sharp 09a6369693 qol: update javascript bundling 2022-02-18 13:52:31 +11:00
Gary Sharp 9bfeff8c42 feature: expose custom details to expressions
custom details can now be easily retrieved from any expression
2021-02-07 18:17:03 +11:00
Gary Sharp 3e57af394d feature: custom details first-class
custom details (such as those from the UserDetails plugin) can now be more deeply integrated throughtout the system
2021-02-07 18:15:52 +11:00
Gary Sharp e11d0871c4 feature: add reply-to address for email service 2021-02-05 15:24:20 +11:00
Gary Sharp f7fdfb0c8a maintenance unify document generation ui 2021-01-13 15:41:51 +11:00
Gary Sharp 806aadd161 feature: email service and configuration 2021-01-10 13:57:25 +11:00
Gary Sharp af4a94870e additional device details 2020-12-04 15:51:23 +11:00
Gary Sharp 486ce17857 Feature: Export device hardware audit information
Allows processor, memory, disk and network adapter information to be included in device exports
2020-11-29 16:46:20 +11:00
Gary Sharp f82b47dd46 Feature: Display detailed device hardware audit information
The device Details tab now displays processor, memory, disk and network adapter information collected at the previous enrolment
2020-11-29 16:45:10 +11:00
Gary Sharp f1d27732c7 Feature: Collect additional hardware audit information
When devices enrol the client collects processor, memory, disk and network information which is persisted in the database
2020-11-29 16:43:44 +11:00
Gary Sharp 28e5901929 Feature: Device Batch Attachments
allows for attachments to be uploaded and associated with Device Batches
2020-11-29 16:41:56 +11:00
Gary Sharp e531ffe2b7 support active directory trust relationships 2020-11-26 15:01:03 +11:00
Gary Sharp 4fca015afa bug fix: delete devices with assignment history 2020-11-13 20:15:31 +11:00
Gary Sharp a80ed14038 bug fix: csv device import first record was skipped 2020-09-10 12:43:03 +10:00
Gary Sharp f3e0939a06 Bug Fix: Ldap Query Escaping 2018-05-21 16:22:41 +10:00
Gary Sharp 2cd6ddfa24 Bug: EntityFramework does not understand Tuple.Create 2018-04-26 15:38:25 +10:00
Gary Sharp b4a30061e3 Bug fix #109 SQL Server 2016 Support 2018-04-23 18:21:44 +10:00
Gary Sharp cb033c0b70 Allow remote maintenance via web.config setting 2018-04-19 17:11:19 +10:00
Gary Sharp 3c197e7b2f Bug: Correctly write enrolment log device info 2018-04-19 17:09:34 +10:00
Gary Sharp 9f62da9ccd Bug: Stale cache when adding user flag in expression 2018-04-19 17:08:43 +10:00
Gary Sharp df721d7d6e Searching: Add detail to device search results 2018-04-19 17:06:58 +10:00
Gary Sharp 8278efb9a6 Bug: AD distinguishedName attribute name 2018-04-19 17:05:02 +10:00
Gary Sharp d477ad5d9c Client: Use UUID if no serial number is found 2018-04-19 17:04:25 +10:00
Gary Sharp 0755b6fc8a Workaround: Dont remove client certificates 2018-04-19 17:03:21 +10:00
Gary Sharp 78dd494304 Fix: Device import case-sensitive serial numbers 2018-04-19 17:02:38 +10:00
Gary Sharp 0497e145ea Bug fix: Allow for unexpected cert subject names 2017-05-25 13:47:17 +10:00
Gary Sharp 4d6aa18095 Perf: Save only when user updated 2017-03-29 13:00:15 +11:00
Gary Sharp fdf1bd4bc6 UI: Device models list, default hide decommissioned 2017-03-29 12:55:07 +11:00
Gary Sharp 82183f6508 UI: Device Table hide/show decommissioned devices 2017-03-29 12:18:37 +11:00
Gary Sharp d6ee70b860 Fix: NetBIOS computer name limit correction
16 character limit, not 24 as previously thought. Due to appended '$'
for machine accounts, a character limit of 15 is now enforced.
2017-03-29 12:17:01 +11:00
Gary Sharp 5ce9e51ae7 Feature: MS Excel (xlsx) Import/Export
Microsoft Excel files can be used to import/export devices. Several
import bugs were also fixed in the process.
2017-03-25 15:37:28 +11:00
Gary Sharp ed66f4f285 Tidy: Sort/remove usings, simplify names 2017-03-25 15:29:51 +11:00
Gary Sharp 526f8547f7 Client/Bootstrapper Fix: Try gathering model from BaseBoard 2017-03-24 15:50:18 +11:00
Gary Sharp d8e93cb31b Fix: Generate pdf for unimported users
If a user wasn't previously imported into the database generating of
PDFs failed. This change attempts to import the user if its not found.
2017-03-24 15:36:05 +11:00
Gary Sharp 5fa74a8cc0 Bug fix #106 - job queues: case-sensitive usernames 2016-12-08 17:01:13 +11:00
Gary Sharp a0d643eda1 Version bump for #103 2016-11-21 16:40:50 +11:00
Gary Sharp 0887eb447e Bug fix #103 Save User Flag assignment to DB 2016-11-21 16:02:45 +11:00
Gary Sharp d9cade74b6 Version bump for v2.2 2016-11-17 00:26:46 +11:00
Gary Sharp 67261cd5b8 Fix: pdf insert blank pages 2016-11-16 00:19:29 +11:00
Gary Sharp aca037ecf8 Feature: Document Template Packages
Document Templates can be grouped into a package and generated on-demand
in the same was as individual document templates. Packages can be
generated in bulk.
2016-11-14 01:21:23 +11:00
Gary Sharp ef8df08e29 Page Identifiers in OnAttachmentImportExpression 2016-11-11 12:07:51 +11:00
Gary Sharp 4c91d03385 Hide Document Templates & UI Tweaks
Flag Document Templates as hidden. UI changes aim to improve visibility
of used features in lists.
2016-11-10 17:42:10 +11:00
Gary Sharp b52cbcb94a Job Expressions
Expressions can be triggered when jobs are created and closed
2016-11-09 22:26:43 +11:00
Gary Sharp 065b14b158 User Flag Expressions
Adds the ability to have expressions evaluated when flags are added and
removed.
2016-11-09 20:06:24 +11:00
Gary Sharp cbf16a41a6 Additional AD Helper Methods
Useful when referenced from expressions
2016-11-09 20:03:50 +11:00
Gary Sharp f74d49b96e Fix Device Batch Managed Groups 2016-11-09 16:27:07 +11:00
Gary Sharp afa548fb70 Device enrolment with no model information
An exception was previously thrown when a device lacking
manufacturer/model information attempted to enrol.
2016-11-09 15:43:44 +11:00
Gary Sharp c72c18e825 Bug Fix #98 Ensure Usernames are not case-sensitive 2016-11-03 17:12:50 +11:00
Gary Sharp 6df2e16a7f Bug Fix #97 - Removed Organisation Address References
Remove Device Profile references to an address when its removed, and
anticipate missing addresses where referenced.
2016-11-03 16:47:07 +11:00
Gary Sharp 3e4dda683d Bug Fix: #88 Update PList Parsing
Various versions of OSX/MacOS are producing slightly different PList
files. The PList library was having difficulty with some versions. An
updated PList library has been included and source changed to utilise
this library.
2016-11-02 17:04:00 +11:00
Gary Sharp dc8a5ab806 Bug Fix #101 - Rename ZXing Dependency 2016-11-02 15:28:41 +11:00
Gary Sharp 0f20b16f41 Decommission AD descriptions #96 2016-10-10 20:11:03 +11:00
Gary Sharp 23975f8fc3 Add date-based managed group filtering 2016-10-10 19:21:01 +11:00
Gary Sharp 062769a7e3 Bug Fix #102 - Ignore WLAN service disabled 2016-10-10 15:35:32 +11:00
Gary Sharp 1dfa3f4f15 Use Json.Net for MVC ValueProviderFactory 2016-10-06 19:39:19 +11:00
Gary Sharp e082c22983 Critical function message wording
Critical functions require a localhost connection. Instead of reporting
503 Service Unavailable, report a useful message.
2016-10-06 19:33:34 +11:00
Gary Sharp b286f8473a Changed wireless profile client messages
These messages are intended to be informative, but were interpretted as
errors by some.
2016-10-06 18:33:29 +11:00
Gary Sharp 0a67e9544d Bug Fix #87 - Scroll multiple devices on create job 2016-09-29 20:02:37 +10:00
Gary Sharp 687713428b Consistent style of attachments 2016-09-29 19:37:42 +10:00
Gary Sharp aeb9eb4d3a Style bundling update
Using VS extension: 'Web Compiler'
2016-09-29 19:28:57 +10:00
Gary Sharp 9baca7f633 Javascript bundling updated
Using VS extension: 'Bundler & Minifier'
2016-09-29 18:34:06 +10:00
Gary Sharp 5fcb81e9e8 Bug Fix #80 - Prompt for attachment comment 2016-09-29 18:32:52 +10:00
Gary Sharp 3c521541fd Bug Fix #79 Ban '/' from serial numbers 2016-09-29 17:55:39 +10:00
Gary Sharp 669de7e46b Bug Fix: #76 importing devices 2016-09-29 17:35:41 +10:00
Gary Sharp a15f3daad5 Bug Fix: Disco Client 32-bit regression 2016-09-29 17:01:23 +10:00
Gary Sharp 86faf02cf0 scheduled tasks tidy up 2016-09-28 21:20:18 +10:00
Gary Sharp 27c21175d7 Certificate/wireless plugins; major refactoring
Migrate much of BI to Services.
Added Wireless Profile Provider plugin feature.
Added Certificate Authority Provider plugin feature.
Modified Certificate Provider plugin feature.
Database migration v17, for Device Profiles.
Enrolment Client Updated to support CA Certificates, Wireless Profiles
and Hardware Info.
New Client Enrolment Protocol to support new features.
Plugin Manifest Generator added to main solution.
Improved AD search performance.
2016-09-28 20:17:55 +10:00
Gary Sharp 489a5df7cc Preview document template pdf
Renders document template pdfs to an image which is displayed in the
configuration ui.
2016-09-21 19:55:57 +10:00
Gary Sharp 85425d2a1f Improve QR binary encoding compression 2016-09-21 19:55:00 +10:00
Gary Sharp 4b866c9486 Escape AD Distinguished Names that contain "/"
for EFC
2016-09-15 19:45:14 +10:00
Gary Sharp acfa0e5094 Document Template Binary QR Codes
The QR Code now stores the data using a custom binary encoding format.
This reduces the amount of data stored by ~30%. This increases the
chance of a lower-version QR Code being used and the likelyhood of even
small QR Codes being detected. Compatibility with previously generated
documents is maintained.
2016-09-15 19:27:52 +10:00
Gary Sharp 5ea9a814d6 Pdf Import Rewrite
Pdf Import rewritten to greatly improve QR Code detection, reduce
reliance on iTextSharp and improve thumbnails. Fixes #50
2016-09-01 18:31:35 +10:00
Gary Sharp 44f6d325db Update: Mac Enrol using SshNet
SshNet supports required cryptographic algorithms. Simplified data
gathering using plist/xml format from system_profiler. Fixes #88 and #92
2016-09-01 18:31:22 +10:00
Gary Sharp 4e6093702d Improvement: Simplify JobTable SQL Generation
New EF expressions which simplify SQL and avoid some strange behaviour
on SQL Express.
2016-05-30 14:37:12 +10:00
Gary Sharp d955addc26 AD Performance Improvement
When searching very large Active Directories prefix wildcards greatly
reduce performance. A configuration switch is implemented when results
in only suffix wildcards being used.
2016-05-02 18:54:27 +10:00
Gary Sharp dee347128e Add RazorGenerator Directives 2015-12-23 10:55:04 +11:00
Gary Sharp d6de5e5958 Add TempPath parameter to bootstrapper install
Allows a temporary path to be passed to the Bootstrapper to be used when
mounting WIM images during the offline install phase. Allows mounting to
be done on another (faster, SSD) volume.
2015-12-23 10:55:03 +11:00
Gary Sharp 80f7cd0275 Merge pull request #95 from ahmedshash/master
Fix for ability to import keyboard in device import #94
2015-12-23 10:52:59 +11:00
ahmedshash 538fd2e394 Fix for ability to import keyboard in device import #94
As per request #94 this extends functionality when importing/exporting
devices by adding a keyboard field.
2015-12-22 21:16:34 +11:00
Gary Sharp ad5aea6df2 Initial config CSS animation
Uses CSS animation instead of GIF; GIF animation stops when browser
navigation begins, CSS continues.
2015-05-26 21:01:46 +07:00
Gary Sharp b070283270 Razor Generator Directives
Enable `GeneratePrettyNames` so that namespaces and class names are
preserved as in the past (after changes in RazorGenerator Extension)
2015-05-26 12:46:02 +07:00
Gary Sharp 6a017c7be9 Version Bump
Basis of a future release (2.1)
2015-05-14 15:02:51 +10:00
Gary Sharp 6fe8d9c8e0 Bug Fix: Assemblies missing from deployment 2015-05-14 13:11:11 +10:00
Gary Sharp 7eb17a91c9 Removed minify source maps
These files have no route in mvc, so only cause 404 errors in browser
dev tools.
2015-02-02 20:58:47 +11:00
Gary Sharp d2acf31b81 Migrate VS2013 version incrementing extension
"Build Version Increment" doesn't support VS2013, migrates to "Automatic
Versions".
2015-02-02 20:17:58 +11:00
Gary Sharp 50399f4f48 Bug Fix #82: Dereference managed groups on delete
Managed Group references (and subscriptions) continued to exist after
Device Profiles, Device Batches and Document Templates were deleted.
This prevented assigning the same group to another
Profile/Batch/Template without first recycling the IIS App Pool.
2015-02-02 19:23:27 +11:00
Gary Sharp 23db0b6111 Bug Fix #83: Correct case in attachment usernames 2015-02-02 19:00:58 +11:00
Gary Sharp a7b3f045d6 Project updated to VS2013 2015-02-02 18:43:01 +11:00
Gary Sharp 76318d8d00 Release v2.0.0918.1700 2014-09-18 19:11:21 +10:00
Gary Sharp f2ac35a7fa Bug Fix #75: Display errors creating device batch
Thanks Patrick Connell
2014-09-15 13:24:28 +10:00
Gary Sharp b1575fa321 Unified SignalR disconnected/error dialogs
Dialogs (with a refresh option) appear whenever the SignalR client
disconnects or encounters an error. Nonsensical error messages replaced.
Page refresh technique changed to allow for urls containing fragment
hashes.
2014-09-11 17:21:39 +10:00
Gary Sharp 4283b62803 Bug Fix: Job searching with username
When searching jobs, the default domain is now assumed if none is
provided when checking for job users.
2014-09-11 16:48:45 +10:00
Gary Sharp 7551b39b8e Generated Job Log to Markdown
Generated job logs are formatted with Markdown. Includes other minor css
changes.
2014-09-09 13:54:14 +10:00
Gary Sharp 3ae99f45bb Update device model type on Enrolment 2014-09-08 14:53:10 +10:00
Gary Sharp c846fa053a Dialog height reduced & remove js minify maps
Provide better support for lower resolution devices (buttons became
hidden in tall dialogs). Remove references to JavaScript minification
source maps which aren't deployed and caused confusion.
2014-09-08 14:51:51 +10:00
Gary Sharp 57c2e062fc Update: Plugin provided assemblies
Update assemblies which are available to all plugins.
2014-09-02 14:45:44 +10:00
Gary Sharp e940c24522 Bug Fix: Document template bulk examples 2014-09-02 14:45:02 +10:00
Gary Sharp 73d6160db6 Fix typo: AvilableDomainControllers
AvilableDomainControllers -> AvailableDomainControllers
Thanks Boris Pekez
2014-08-29 14:46:29 +10:00
Gary Sharp 13c5efe5d6 Added new UI Icons in FontAwesome 4.2.0 2014-08-28 15:32:57 +10:00
Gary Sharp bbe4cccc91 Update #74: Friendly disconnected messages
When the live connection to the server is interrupted some ui elements
are disabled. If the connection fails (due to errors or failed
reconnection) a dialog instructs the user to check their connection and
refresh the browser. Relates to Device, Job and User pages (logs and
attachments).
2014-08-28 14:59:39 +10:00
Gary Sharp 41e061df54 Update: Font Awesome 4.2.0 2014-08-28 13:53:35 +10:00
Gary Sharp 35a07344cc Bug Fix #71: Update managed groups on device enrol 2014-08-28 12:50:53 +10:00
Gary Sharp 4b6604df5b Feature #69 #72: Noticeboard themes and filtering 2014-08-26 16:27:37 +10:00
Gary Sharp 0de162fce3 Update: Update Job Identifiers 2014-08-19 10:53:59 +10:00
Gary Sharp f26474fa4d Device decommissioning 'returned' reason 2014-08-07 13:43:59 +10:00
Gary Sharp 8e2a17cfc5 Beta Release: v2.0.0731 2014-07-31 16:23:56 +10:00
Gary Sharp 3b0286fe11 Feature: Disco Device Registration
A method of 'Enrolling' devices which only updates the Disco database
(makes no changes to clients or AD). Can be easily called from a script
and used to add servers or any custom device.
2014-07-31 15:52:42 +10:00
Gary Sharp 12fc071786 Bug Fix: Reimage Job Enrol wouldn't join AD domain 2014-07-31 11:53:42 +10:00
Gary Sharp 1d931463a8 Update: Cannot close job until charge added
If a Non-Warranty job has 'Accounting Charge Required' it cannot be
normally closed until 'Accounting Charge Added' (even if 'Account Charge
Paid'). The job can still be forcibly closed (by those with permission
to forcibly close jobs).
The 'Awaiting Finance' and 'Accounting Charge' lists have been updated
to reflect this requirement.
2014-07-30 21:53:25 +10:00
Gary Sharp f01bc940f6 Bug Fix: Task progress incorrectly calculated 2014-07-29 14:17:58 +10:00
Gary Sharp ea80876286 Feature #40: Exceptionless error reporting 2014-07-28 20:55:53 +10:00
Gary Sharp 7062a40dfb Bug Fix #68: Undetected Pages dialog scale
Automatically scales the undetected page preview based on the browser
size.
2014-07-28 17:33:49 +10:00
Gary Sharp 2d8dcb6900 Bug Fix: Device/User search filtering and sorting 2014-07-28 16:51:17 +10:00
Gary Sharp 3358d9e320 Update: Disco ICT Online Services - Plugin Library
Migrate plugin library to https://services.discoict.com.au
2014-07-28 15:02:33 +10:00
Gary Sharp 1cc7e94646 Feature #67: Advanced document template events
OnGenerated and OnImportAttachment allow advanced users to enter
expressions which will be evaluated whenever these document
template/importing events are triggered. This enables greater
automation.
2014-07-26 20:02:59 +10:00
Gary Sharp c528a2be26 Bug Fix #66: Add offline device ui glitch
Only updates the text-box with the user id (instead of the full name),
to avoid users not correctly selecting a item from the auto-complete
list and then trying to submit the form.
2014-07-26 16:06:56 +10:00
Gary Sharp a43db01b96 Update: 3rd-party libraries updated, refactoring
Updated: SignalR 2.1.1, Moment.js 2.7, Reactive Extensions 2.2.5,
TinyMCE 4.1.2.
Customized TinyMCE skin and implemented FontAwesome icons.
T4MVC refactored.
2014-07-26 15:54:01 +10:00
Gary Sharp b78ce003a7 Bug Fix: Error when assigning devices
The noticeboard listens for updates to user assignments (including who
was previously assigned the device), but was requesting data which no
longer existed (as updates are delayed and buffered for up to 500ms).
2014-07-26 12:25:20 +10:00
Gary Sharp 81d024618a Bug Fix #65: Mac enrolment not updating model 2014-07-26 11:32:18 +10:00
Gary Sharp 4d8fec2ced Update: Job Publishing - Repair Jobs
Repair jobs can also submit attachments to repairers via Disco ICT
Online Services.
2014-07-24 21:27:24 +10:00
Gary Sharp 7cbed23a74 Feature: Disco ICT Online Services - Job Publishing
When warranty jobs are submitted (via plugins) users can choose to
include attachments. These attachments are submitted to Disco ICT Online
Services. A secure link is then provided to the plugin so the
attachments can be retrieved.
2014-07-24 20:58:48 +10:00
Gary Sharp 6700d092b3 Update: Disco Online Services Update Checking
Migrates Disco Update checking to new services at
https://services.discoict.com.au.
2014-07-23 19:14:08 +10:00
Gary Sharp 4b3905b4fc Bug Fix #62: DeviceDomainId may be null 2014-07-15 14:57:58 +10:00
Gary Sharp 09b1c93bf0 Export devices without a batch assigned #60 2014-07-14 13:30:25 +10:00
Gary Sharp 5c5e5a23a2 Bug Fix #61: Fix Decommission/Recommission Device
Checks to ensure a device domain id is valid before interacting with AD.
2014-07-14 13:04:42 +10:00
Gary Sharp 9bfa95e263 Bug Fix #58: Fail to assign MacSecureEnrol devices
Various code-paths *assumed* valid domain account ids as long as an id
existed (simple null-check). Correct checks for valid domain account ids
has been implemented.
2014-07-10 18:33:05 +10:00
Gary Sharp 2274e2201d Bug Fix #56: Noticeboard device profile filtering 2014-07-10 17:49:36 +10:00
Gary Sharp f4394fe2a0 Feature #2: Implement Repair Provider
Logging Repair for Non-Warranty jobs has been brought into line with
Logging Warranty. RepairProviderFeature implemented which allows plugins
to be used in submitting jobs to third-parties for repair.
2014-07-10 17:45:13 +10:00
Gary Sharp 5ba9fde10f Feature #2: Improve Warranty Logging
Warranty job UI changes to make consistent with plans for Repair Logging
2014-07-08 16:47:13 +10:00
Gary Sharp 67a624d5b5 Bug Fix #53: Plugin install fails when dll loaded 2014-07-07 15:19:46 +10:00
Gary Sharp 0b79140290 Bug Fix #54: Save proxy settings with ajax 2014-07-07 13:49:38 +10:00
Gary Sharp 5013fa27bd Bug Fix #55: Updating device batch when unassigned 2014-07-07 10:19:52 +10:00
Gary Sharp 83e9b7a832 Beta Release: v2.0.0626 2014-06-26 14:54:48 +10:00
Gary Sharp a3a92245ae Update: SignalR 2.1
https://github.com/SignalR/SignalR/releases/tag/2.1.0
2014-06-19 16:02:42 +10:00
Gary Sharp 045fb0b65d Complete #48: Migrate Role Claims
To ease upgrading to vNext, migrate claims so behaviour is roughly the
same.
2014-06-19 14:51:16 +10:00
Gary Sharp 304ffd7ee1 Remove depreciated projects/libraries 2014-06-19 13:59:31 +10:00
Gary Sharp 8b74dbabf5 Bug Fix #49: Update group when attachment removed 2014-06-19 13:56:11 +10:00
Gary Sharp 7f8ed7e752 Feature #52: UserExt Auth methods for expressions
Extension methods can be used to test for user authorization (against
claims) within Expressions
2014-06-17 14:31:11 +10:00
Gary Sharp 84a4ba281f UI Improvements: info-box css 2014-06-17 00:00:56 +10:00
Gary Sharp 34842012b7 Bug Fix: Webcam Attachment in <= Win 7
Flash video overlay was hiding the Comments model dialog. The flash
object is now hidden where <= Win 7 is detected (navigator.userAgent).
2014-06-16 23:10:45 +10:00
Gary Sharp a819d2722a Feature #49: Active Directory Managed Groups
Document Template Attachments, Device Batches, Device Profiles and User
Flags can be associated with an Active Directory group. This AD group is
then automatically synchronized with relevant User/Machine accounts.
Contains various other UI tweaks and configuration enhancements.
2014-06-16 22:21:31 +10:00
Gary Sharp ebf78dd08d Bug Fix: Sharepoint Public Reports XSLT
Incorrect serialization of HeldDeviceItem and referencing in the XSLT.
2014-06-11 21:56:50 +10:00
Gary Sharp 6186237028 Bug Fix: Bulk Generate Documents UserId Domain
Where no domain is provided, the primary domain should be assumed.
2014-06-11 21:32:50 +10:00
Gary Sharp 513397779d Bug Fix: Org Logo config minor UI tweak
The update dialog height was hard-coded and partially obstructed the
input element.
2014-06-11 21:29:12 +10:00
Gary Sharp 815216fd73 Update #26: User Flags Bulk Assignment
Add or Override User Flag assignments in bulk.
2014-06-11 21:23:32 +10:00
Gary Sharp 8254e7ec5a Feature #51: Markdown Support
Markdown implemented in Job Logs, Job Queue comments, various other
places.
2014-06-11 14:51:51 +10:00
Gary Sharp 4c3a68da30 Feature #26: User Flags
Flags can be associated with Users. Includes minor updates to Job Queues
and improved visibility of user information.
2014-06-10 17:16:24 +10:00
Gary Sharp b64ac3b16f Feature #44: Image capture WebRTC & HTML5 FileIO
Silverlight was previously used to capture webcam pictures and upload
file attachments. HTML5 FileIO is now used for all attachment uploading
- including drag-drop support. WebRTC is used to capture webcam images -
this falls back to a Flash polyfill when WebRTC isn't supported.
2014-06-05 21:01:43 +10:00
Gary Sharp d040ab094c Bug Fix: Floats must come first [Firefox]
Floated elements need to come first, otherwise float layout occurs
underneath non-floated content.
2014-06-05 20:57:45 +10:00
Gary Sharp a0e18ef963 SignalR Bug Fixes & Minor UI Changes
Document Template import status and Device Enrolment status fixes.
Attachment download fixes for SignalR foreverFrame transport. Database
queries for Devices, Jobs and Users updated. Device attributes (model,
profile, batch) now shown in various places.
2014-06-03 12:36:48 +10:00
Gary Sharp 830a9c8d05 Update: Minor styling changes
Dialogs reposition to center when window resized & Update heading moved
so that background is correctly shown.
2014-06-02 20:25:43 +10:00
Gary Sharp ea51ba1f88 Bug Fix: Scheduled Task Status Updates
Scheduled Task status is more reliable
2014-06-02 20:02:48 +10:00
Gary Sharp 5510d34885 Bug Fix: Document Generation and SignalR iFrame
Performing page navigation (within an iFrame, or the top window) causes
the foreverFrame transport in SignalR to abort which takes several
seconds to reconnect. Popup windows are now used to navigate to Document
Generation API when the foreverFrame transport is in use.
2014-06-02 19:06:07 +10:00
Gary Sharp be25569245 Update 3rd Party Libraries
Json.NET, jQuery, jQuery UI, modernizr, moment.js, Highcharts, TinyMCE,
normalize.css, T4MVC, RazorGenerator, Reactive Extensions
2014-06-02 02:11:03 +10:00
Gary Sharp 7af6a2220c Update #41: Device Detail: Keyboard
'Keyboard' Device Detail added.
2014-06-01 23:42:08 +10:00
Gary Sharp 4cd57f4a90 Update: SignalR 2.0.3 Migration; Noticeboards
Migrate all SignalR 1.x Persistent Connections to SignalR 2.x Hubs.
Abstracts ScheduledTaskStatus with core interface and adds a Mock for
optional status reporting. Noticeboards rewritten (with new theme) to be
more resilient and accurate.
2014-06-01 23:27:07 +10:00
Gary Sharp f6fae26bc7 Update #9: Hide decommissioned batches by default 2014-05-28 15:01:06 +10:00
Gary Sharp 7cad69598f Update: Device Trusted Enrolment Import/Export
Added AllowUnauthenticatedEnrol to import and export functionality.
2014-05-27 17:08:39 +10:00
Gary Sharp 4e69253852 Update: Device Battery field, Excel CSV Format
Device Battery import & export; Leading zero workaround for Excel
2014-05-27 16:36:42 +10:00
Gary Sharp 825627e345 Bug Fix: Update Admins blocked all Admins
The updated subject hash was case-sensitive when it should have been
reinitialized with the OrdinalIgnoreCase string comparer.
2014-05-27 13:49:13 +10:00
Gary Sharp e9042f7666 Feature #33: Enhanced Device Importing
Dynamic device importing. better input parsing and 5 additional import
fields.
2014-05-25 17:33:18 +10:00
Gary Sharp 6a45348bdb Bug Fix: Sort Job Queue menu 2014-05-25 16:30:01 +10:00
Gary Sharp f3351af9e8 Bug Fix: Indicate failed task if waiting
If using ScheduledTaskStatus.WaitUntilFinished, only return true if the
task completed successfully.
2014-05-25 16:21:33 +10:00
Gary Sharp a5e38406d1 Update: Font Awesome 4.1.0
Font Awesome updated and added several new icons as options for job
queues.
2014-05-25 16:15:59 +10:00
Gary Sharp 3c759ac4d7 #34 Update: Update LastNetworkLogon Dates
Perform UpdateNetworkLongDates task during export if the appropriate
field is selected.
2014-05-22 12:29:03 +10:00
Gary Sharp f70261aa25 #34 Update: Additional Validation & UI Changes
Ensure at least one field is selected, and UI improvements.
2014-05-22 12:11:26 +10:00
Gary Sharp 3fdb4f1053 #34 Feature: Detailed Device Exporting
Many additional device properties are available to export. The previous
export configuration is remembered.
2014-05-22 01:22:57 +10:00
Gary Sharp 53ca13c7f4 Update: Name clarification
Name updated in various places: "Disco ICT"
2014-05-12 23:55:59 +10:00
Gary Sharp 185c4682f0 Certificate provider log update
Add 'UpdatedCertificate' event and renamed some existing log types.
2014-05-12 23:50:29 +10:00
Gary Sharp 39c3bf9fc7 Bug Fix: Initial Config Typo
Thanks to Elijah Solly for finding this one
2014-05-10 20:50:14 +10:00
Gary Sharp c87ee6a0e7 Update: jQuery Validate & Unobtrusive Updated 2014-05-10 20:26:57 +10:00
Gary Sharp 4a08c8c275 Certificate Provider Log Additions
Add Disabled and Deleted certificate log events
2014-05-10 20:26:03 +10:00
Gary Sharp fb6067afc3 Update: Configuration Optimisation and Caching
Loads entire configuration at start-up (rather than scope-based
loading). Deserialization occurs once, with the resulting value cached
and replayed if the requested type matches.
2014-05-07 22:45:59 +10:00
Gary Sharp 6b2cd47610 Bug Fix: Targeted user search without domain
If no domain is specified, the primary domain should be assumed
2014-04-23 13:20:03 +10:00
Gary Sharp 392de396df Bug Fix: Pointer/Touch events triggered navigate
When using touch the anchor navigates immediately even though the Click
event has preventDefault()
2014-04-23 12:59:28 +10:00
Gary Sharp 3cf6d5475d Bug Fixes: enrolment, assignment and search order 2014-04-22 13:55:46 +10:00
Gary Sharp 74df073b29 Bug Fix: AD User Searching
Group properties were loaded instead of User properties
2014-04-22 10:12:03 +10:00
Gary Sharp 09c2a24222 Update #42: AD Migration
Refactor to target specific Domain Controllers, with failover.
2014-04-21 21:43:13 +10:00
Gary Sharp 43fc622121 Use AD site-servers where possible 2014-04-17 17:37:59 +10:00
Gary Sharp b8ec44293f Parallelize AD searching
Where multiple queries are required to complete a search, the query is
parallelized
2014-04-17 17:00:02 +10:00
Gary Sharp 36100bfef5 Optimise for quick AD user searching
Avoids loading users groups when not needed
2014-04-17 15:49:22 +10:00
Gary Sharp b77bdf16f5 Bug Fix: Search fails with unassigned devices 2014-04-17 15:47:15 +10:00
Gary Sharp 5aede7153c Bug Fix: Avoid unnecessary AD queries
In multi-domains, parent domains were searched for child containers.
2014-04-17 15:23:47 +10:00
Gary Sharp 4fc6c3ca9f Status when loading AD Organisational Units
Large domains can take significant time (several seconds) to load the
domain structure (where there are 1000's of OUs)
2014-04-17 13:08:37 +10:00
Gary Sharp d86280ae3e Fix various Multi-Domain bugs 2014-04-16 13:16:08 +10:00
Gary Sharp 2281313966 App Maintenance Theme
Updated to 'Initial Config' theme
2014-04-16 12:59:11 +10:00
Gary Sharp 740e806ef0 Fix #46: Job Table overflow ellipsis 2014-04-13 23:33:15 +10:00
Gary Sharp f35f9d3661 Update: Dialog styling & animation
Dialogs slide & fade in. All appear in the same spot (50px from top)
2014-04-13 23:18:24 +10:00
Gary Sharp 201acc1976 Feature #43: Specify Admins at Initial Config
Disco Administrators can be specified during the Initial Configuration
2014-04-13 23:17:01 +10:00
Gary Sharp a4f4b7d0b3 Initial Config Theme & File Store Changes
Update theme & remove dynatree requirement
2014-04-13 20:19:02 +10:00
Gary Sharp 41dc002ef8 Update #43: Disco Administrators are configurable 2014-04-11 19:57:51 +10:00
Gary Sharp e984221c95 Bug Fix: User Attachment Refs, AD Group Domain
User Attachments updated in the DataStore to reflect new UserId (which
includes the domain); AD Groups were using DnsName instead of
NetBiosName.
2014-04-11 19:56:17 +10:00
Gary Sharp 3238a916a2 Removal of Old AD Interop Files 2014-04-10 22:22:13 +10:00
Gary Sharp db73cc1a12 Feature #42: Active Directory Interop Upgrade
AD Interop moved to Disco.Services; Supports multi-domain environments,
sites, and searching restricted with OUs.
2014-04-10 17:58:04 +10:00
Gary Sharp b841c6b2c0 Bug Fix: Warranty Repair list 2014-03-18 14:18:59 +11:00
Gary Sharp 69091e0785 Update: Create Job redirect shows Job Id 2014-03-18 14:10:50 +11:00
Gary Sharp 3d5f71aba9 Add LICENSE.txt to repository
The license has always been present
(Disco.Web/Areas/Public/Views/Public/Licence.cshtml), but adding to the
repository is considered best-practice.
2014-03-18 13:26:04 +11:00
Gary Sharp da166e5cd2 Update: LESS Compiler Updated
Minor compiled css formatting changes
2014-03-03 14:31:07 +11:00
Gary Sharp 74775e9e3d Bug Fix: Unauthorized HTTP Status Desc length
Status Description was to long causing a 0-byte result to be returned
(HTTP 504).
2014-03-03 14:29:17 +11:00
Gary Sharp 96c5860080 Bug Fix: Statistics for Quick-Logged Jobs
Jobs now perform a check when Quick-Logged and update Statistics
accordingly.
2014-02-20 10:56:06 +11:00
Gary Sharp 6ac87633ac Update: Quick Log & Queue Support 2014-02-18 17:26:03 +11:00
Gary Sharp 0db43d9200 Bug Fix: Delete Jobs with Queue references
Job Queue references were not deleted when the job was deleted causing a
database reference constraint error.
2014-02-18 17:03:35 +11:00
Gary Sharp a82e039140 Bug Fix #4: Only reference jobs where device held 2014-02-18 17:00:14 +11:00
Gary Sharp bfa3bf1e94 Update #4: Import Location Lists 2014-02-18 16:45:58 +11:00
Gary Sharp 5be747afbc Feature #4: Pre-defined/Restricted Locations
Configurable list and location suggestions. Ability to restrict
locations. Shows 'occupied' locations.
2014-02-17 21:44:34 +11:00
Gary Sharp ed7caf8b4a Bug Fix: Job Index Authorization Check
The LongRunningJobs claim is checked instead of the StaleJobs claim
which resulted in an NullReferenceException for users without StaleJobs
authorization.
2014-02-14 21:16:17 +11:00
Gary Sharp 7027b33fe2 Bug Fix: Job Quick-Logging with Queues
Jobs logged cannot be quick-logged if they are added into a queue.
'Device Held' can only be configured if the authorization is given.
2014-02-13 22:26:26 +11:00
Gary Sharp 68256d7abd Feature #37: Stale Jobs
Stale Jobs replaces Long-Running Jobs on the homepage. Last Activity is
added to the job table.
2014-02-13 22:17:49 +11:00
Gary Sharp 2ac3a9bdd3 Bug Fix: Minor permission enforcements
Also some UI tweaks.
2014-02-13 15:27:04 +11:00
Gary Sharp a6a65c54c7 Bug Fix: Incorrect default date in dialog 2014-02-13 15:26:10 +11:00
Gary Sharp 7bdbeb6a82 Feature #35: Livestamp implemented
Humanized dates now update automatically when a page is left open for
some time.
2014-02-11 16:50:03 +11:00
Gary Sharp c4cc54d316 Bug Fix: Job Expected Date UI
Incorrect format displayed - which couldn't be interpreted by the
date-picker.
2014-02-11 13:59:16 +11:00
Gary Sharp 3ae657f2ba Update Minor Job UI tweaks
Job Queue 'Tasks' wording; Job ui-tabs item counting
2014-02-10 17:16:31 +11:00
Gary Sharp 2e7b66ee5b Update: Change UI for "Show Closed Jobs"
Move to a button at the bottom of the list.
2014-02-06 18:57:10 +11:00
Gary Sharp 6d54f3f972 Update: Quick Search supports shortcuts
!/#/@ Shortcut Support
2014-02-06 18:18:46 +11:00
Gary Sharp cd31ba4a6c Feature: Quick Search
Device/Job/User Search refactoring. Quick-Search implemented.
2014-02-06 16:11:45 +11:00
Gary Sharp 9ea0273936 Update: Minor styling for Job Lists
Especially for 'No Jobs' or 'All Jobs Closed' situations.
2014-02-06 12:22:15 +11:00
Gary Sharp 7748f15d76 Update: Auth Claims Refinement, Job Creation
Auth Claims for Job Creation types, user details.
2014-02-04 17:41:00 +11:00
Gary Sharp eea71e6eb0 Bug Fix: Could not delete Job Queues 2014-02-04 15:03:19 +11:00
Gary Sharp 3bc8b63700 Bug Fix: Accounting Payment List
"Jobs Awaiting Finance - Awaiting Payment" list was incorrectly
including jobs.
2014-02-04 12:13:11 +11:00
Gary Sharp 6bacf6e3a5 Fix: Navigation and page width styles
Search bar was disappearing
2014-02-04 12:08:59 +11:00
Gary Sharp cc4682875b Change: Rename Undetected Pages permission
Change to: "Process Undetected Pages"
2014-02-04 10:52:49 +11:00
Gary Sharp bfcbcf9da2 Fix: Client Icons
Update to current theme.
2014-02-04 10:52:07 +11:00
Gary Sharp ad28729a85 Change: Job Queue Description not required 2014-02-04 10:51:33 +11:00
Gary Sharp 3f63281dc4 Feature: Job Queues
Also UI style, theme and element changes
2014-02-03 14:50:08 +11:00
Gary Sharp bdb3e1e6b4 Bug Fix #36: Repair computer name template error
Corrects existing invalid computer name templates.
2014-01-23 13:43:23 +11:00
Gary Sharp 10394c4e39 Bug Fix #36: Default Profile name template error
The "Initial Default Workstation Profile" had an incorrect Computer Name
Template set by default. This does not affect newly created Device
Profiles which use a valid template.
2014-01-23 13:36:19 +11:00
Gary Sharp 2ddf4b7bd9 Update: menu separators & text placeholder 2013-12-26 11:53:02 +11:00
Gary Sharp 35391ad1a1 Feature: Thread-blocking task status completion
Thread can be blocked until a task completes (or a timeout period
elapses). Used to wait up to 3 seconds before redirecting to the
TaskStatus when downloading the Plugin Catalogue.
2013-12-25 18:35:19 +11:00
Gary Sharp ab553a05cb Update: FontAwesome Pass 2
Removal of bitmap icons, replacing with vector based icons from
FontAwesome. Includes other UI style changes.
2013-12-25 17:49:30 +11:00
Gary Sharp 20263905f9 Feature: FontAwesome Added
FontAwesome 4.0.3.1 Added, and an initial pass to replace bitmap icons.
2013-12-24 16:22:26 +11:00
Gary Sharp f1ee2937cd Feature: New Theme
New icon, theme, and fuzzy time. Add moment.js
2013-12-24 14:15:07 +11:00
Gary Sharp ec118a3395 Bug Fix #32: ConvertHWarToHNWar Components
Components are now correctly filtered and associated with jobs when
converting from "Hardware - Warranty" to "Hardware - Non Warranty".
2013-12-09 18:47:24 +11:00
Gary Sharp 551b1d3a41 Bug Fix #28: DataStore Drive not present 2013-12-03 11:19:51 +11:00
Gary Sharp 214ecf6212 Bug Fix #31: Restrict AD User Search to Users
Added "objectClass=user" LDAP filter which excludes AD Contacts.
2013-12-03 09:37:21 +11:00
Gary Sharp fad8eae9f4 Bug Fix #30: Upload File & Capture Image Buttons
Now both buttons work as expected, rather than having to refresh that
page to gain access to the other feature.
2013-12-02 17:21:56 +11:00
Gary Sharp 2dd3f5f9ab JobParts\Resources tooltip update
Updated tooltips to reflect discussion in #29
2013-12-02 17:09:00 +11:00
Gary Sharp 8ace60f10d Merge pull request #29 from doctorjbeam/patch-1
Added tooltips to JobParts\Resources.cshtml
2013-12-01 22:06:07 -08:00
Michael Greenhill 136c371b01 Added tooltips to JobParts\Resources.cshtml
Example use of tooltips (title attribute) to give give end users more instruction.
2013-12-02 12:51:38 +11:00
Gary Sharp a5c051916e Version bump for release 1.2.1128 2013-11-28 15:09:56 +11:00
Gary Sharp 4f4dbabf8b Bug Fix: Bootstrapper crash if previously failed
Updated bootstrapper correctly cleans up temporary files left by a
previous run which failed.
2013-11-26 17:30:05 +11:00
Gary Sharp e4c86f1cc1 Bug Fix: Touch support for menu
Support for PointerEvents, MSPointerEvents and Touch with fallback to
Mouse events.
2013-11-20 15:06:37 +11:00
Gary Sharp eabd9671f0 Bug Fix: Touch support for menu
Support for Touch, PointerEvents and Mouse event specifications.
2013-11-19 16:35:03 +11:00
Gary Sharp 9b34abfa29 Bug Fix: Default DeviceProfile DistributionType
The DistributionType is required but was not specified (null) in the
Database Seed (as a result of the move to an enum).
2013-11-19 14:19:41 +11:00
Gary Sharp d1007266c9 Include LumenWorks Framework Dependency
Disco.BI Dependency for CSV Parsing.
2013-11-19 09:55:23 +11:00
Gary Sharp 230b1af9f7 Bug Fix: MVC Layouts to Static 2013-11-14 14:13:23 +11:00
Gary Sharp fe00963cb0 Update: Error UI Updated 2013-11-14 13:34:53 +11:00
Gary Sharp b1048588e7 Bug Fix: Upload attachments required refresh 2013-11-12 12:21:35 +11:00
Gary Sharp 9ac487e7e0 Update: Max Request Length 20MB
Increase from default (4MB)
2013-11-12 12:20:17 +11:00
Gary Sharp 404d5c9120 Update: Silverlight Script Module 2013-11-12 12:12:54 +11:00
Gary Sharp 1cbbf1dde4 Custom Error Handling 2013-11-11 17:04:04 +11:00
Gary Sharp a63041abf2 Bug Fix: Check Box List script
Migrate from .attr() to .prop() as per: http://api.jquery.com/prop/
2013-11-05 16:14:44 +11:00
Gary Sharp bd4f0bd9a7 Bug Fix: jQuery Ext for Firefox 2013-11-05 14:29:53 +11:00
Gary Sharp bc08bd7dc2 Fix #22: PluginWebViewPage ReferenceNullException
Plugin Helper needs to be lazy loaded
2013-10-31 16:44:20 +11:00
Gary Sharp d8fc45ee6f Feature #3: Server SKU support for Enrolment
The Disco Client (which is launched by the Bootstrapper) supports
Windows Server SKUs. Removes dependancy on WLANAPI.DLL. Updates to
enrolment allows for successful addition to System Critial objects (eg.
DC/PDCs) into Disco without making any changes to AD objects.
2013-10-31 14:15:00 +11:00
Gary Sharp fce371231c Fix #25: 'Long Running' status on closed jobs 2013-10-31 12:11:12 +11:00
Gary Sharp 76aead2011 Update #15: Community Reporting
Active Devices are more correctly reported, and metrics on warranty job
vendor logging.
2013-10-29 14:36:29 +11:00
Gary Sharp df633b3591 Feature #7: AC Adapter Device Detail 2013-10-29 13:30:41 +11:00
Gary Sharp 94c7cae443 Feature #19: Allow auto unauthenticated enrolment 2013-10-29 12:26:33 +11:00
Gary Sharp 10a38af08b Feature #20: Assigned User Is Local Admin
Device Profile setting which specifies whether assigned users are set as
Local Administrators. Default is true (which maintains compatibility).
2013-10-28 18:16:22 +11:00
Gary Sharp c13d13c91c Update: 3rd Party Libraries
Newtonsoft.Json 5.0.8; RazorGenerator.Mvc 2.1.2; jQuery 2.0.3; jQuery
Validate Unobtrusive 3.0.0; Microsoft.Net.Http 2.1.10; KnockoutJS 2.3.0;
Highcharts 2.0; T4MVC 3.7.4; TinyMCE 4.0.9
2013-10-28 17:42:38 +11:00
Gary Sharp 7096a511c3 Fix: CheckBoxList checked attribute encoding 2013-10-28 14:11:31 +11:00
Gary Sharp 233d62442c Update #18: UX Document Template Bulk Generating
Improved UX
2013-10-24 22:15:46 +11:00
Gary Sharp 723eeec91e Feature #25: Job General Preferences
Initially to make 'long running job threshold' configurable. Updates to
ManagedJobList and fix for missing GetClaimKeys method (#24).
2013-10-24 18:19:05 +11:00
Gary Sharp 0d60fb422c Update: Plugin Web Helpers
Web Helpers included in UI Extensions and WebHandlers
2013-10-22 13:48:25 +11:00
Gary Sharp cc218a08e4 Update: Install Plugin (or Update)
Check to update the plugin when installing to avoid
uninstall->wait->install cycle.
2013-10-21 20:50:31 +11:00
Gary Sharp 401ae029f1 Update: Use Generics for Compiled View
Also standardize inclusion of StyleSheets/Scripts for Plugin Resources
2013-10-21 20:05:33 +11:00
Gary Sharp 4dfe9ad086 Fix: Computer authorized enrolment
Computer Accounts could not enrol
2013-10-21 20:02:40 +11:00
Gary Sharp 5f9a49bca3 Fix #13: Don't hide initialize errors 2013-10-17 15:31:50 +11:00
Gary Sharp faee1e724e Enhancement: Menu Style #6
Remove transparency; improve text clarity.
2013-10-17 12:44:10 +11:00
Gary Sharp d6859dcde4 Community Services use HTTPS #21 2013-10-17 11:34:22 +11:00
Gary Sharp fdb5d37ec8 Fix: AuthorizationRole.Subjects can be null #24
Fixes the resulting NullReferenceException.
2013-10-17 11:05:22 +11:00
Gary Sharp 51ebc673e7 Fix: Update details device during enrolment #14 2013-10-17 11:03:54 +11:00
Gary Sharp 017b1435d8 Authorization Logging #24
Record 'Access Denied' and any changes to Authorization Roles.
2013-10-15 16:13:41 +11:00
Gary Sharp 7b62eabeee Fix: Job UI Authorization #24
Insurance Claim Form Sent authorization logic was incorrect causing a
NullReferenceException.
2013-10-15 10:12:20 +11:00
Gary Sharp d8c4d13def Fix: Handle User UI when not found in AD #24 2013-10-15 09:17:37 +11:00
Gary Sharp 9784c5d282 Plugin Base WebViewPage #22 & Authorization #24
Plugins have a base WebViewPage to inherit, this offers integration with
various Disco services. Plugins can also add Authorization attributes to
their Web Handlers and Controller Methods.
2013-10-14 20:13:00 +11:00
Gary Sharp 4b822d3ae3 Fix: Assigned User Not Set 2013-10-14 19:58:41 +11:00
Gary Sharp 24751780cc Fix: CurrentUserId returned domain 2013-10-14 16:23:59 +11:00
Gary Sharp 4d19e381fd Authorization Subject Link #24
Create links to user when browsing Authorization Roles. Also removes
uncompiled views from published application.
2013-10-14 12:44:41 +11:00
Gary Sharp ec74039400 User Authorization UI #24
Additional UI to help determining what effective authorization users
have.
2013-10-14 12:12:50 +11:00
Gary Sharp a099d68915 Permissions & Authorization for Users #24
Initial Release; Includes Database and MVC refactoring
2013-10-10 19:13:16 +11:00
Gary Sharp 172ce5524a Update: Managed Modules for All Requests
Run all requests through managed modules. May impact on performance, but
improves compatibility with various IIS configurations.
2013-10-09 13:25:12 +11:00
Gary Sharp 2ad4cd2080 Update: Shorten MacAddress Importing Delay
Reduce from 15 minutes to 5 minutes after startup.
2013-09-12 16:40:14 +10:00
Gary Sharp 2e820cd720 Feature #14: Device Details
Initial Commit - LAN/WAN MAC Addresses
2013-09-12 13:39:39 +10:00
Gary Sharp 75ebfdaa80 Bug: Global search occurs twice 2013-09-12 13:25:30 +10:00
Gary Sharp 122f719e3b Fix #16: Include AD Primary Group when Searching
Fix regression when searching for users.
2013-09-09 17:02:00 +10:00
Gary Sharp 60f7384c97 Update: Job Entity -> Enum Support 2
Support the DistributionType Enum in Device Profiles
2013-09-09 15:09:28 +10:00
Gary Sharp 02b91f1ea4 Fix #17: Computer Name Template Cache
Correctly invalidates the Expression Cache when a Computer Name Template
changes.
2013-09-09 14:39:49 +10:00
Gary Sharp d0aea2401b Feature: Device Lost/Stolen Sub Types
As requested in #1
2013-09-05 18:31:02 +10:00
Gary Sharp 29a6057443 Feature: Decommission Reasons
As requested in #1
2013-09-05 18:23:59 +10:00
Gary Sharp f3efa56750 Update: Job Entity -> Enum Support 2013-09-05 12:45:23 +10:00
Gary Sharp 090322126a Fix #16: Include Primary Group for AD Users
Caches group SIDs and retires unmanaged SID transform PInvoke for
managed equivalents
2013-09-03 20:21:20 +10:00
Gary Sharp d8538d2792 Fix: Remove Unnecessary AJAX at Log Warranty
Page is always refreshed to provide information to Warranty Plugin -
generate address UI at server.
2013-09-02 18:58:49 +10:00
Gary Sharp 37810656fd Fix #12: Update users when logging warranty
Job User is updated when available.
2013-09-02 18:37:30 +10:00
Gary Sharp 3596d325eb Fix #11 : jQuery delegated events for Firefox 2013-08-19 17:36:22 +10:00
1589 changed files with 368715 additions and 128539 deletions
+2
View File
@@ -3,6 +3,8 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
.vs/
# User-specific files
*.suo
*.user
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
</configuration>
BIN
View File
Binary file not shown.
-153
View File
@@ -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>
-96
View File
@@ -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;
}
}
}
-31
View File
@@ -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;
}
}
}
-61
View File
@@ -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#
}
}
-578
View File
@@ -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)
{
}
}
}
-482
View File
@@ -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
}
};
}
}
}
-102
View File
@@ -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();
}
}
}
-265
View File
@@ -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);
}
}
}
-56
View File
@@ -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);
}
}
}
-21
View File
@@ -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;
}
}
}
-259
View File
@@ -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
}
};
}
}
}
-103
View File
@@ -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
};
}
}
}
@@ -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,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,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;
}
}
}
-192
View File
@@ -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,183 +1,134 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Web;
using Disco.Data.Repository;
using Disco.Models.BI.DocumentTemplates;
using Disco.Models.Repository;
using System.Collections;
using System.Collections.Generic;
using Disco.Models.Services.Documents;
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 Disco.BI.Expressions;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Drawing;
using System.IO;
using Disco.BI.DocumentTemplateBI;
using System.Linq;
namespace Disco.BI.Extensions
{
public static class DocumentTemplateExtensions
{
private const string DocumentTemplateExpressionCacheTemplate = "DocumentTemplate_{0}";
private static Tuple<Dictionary<string, Expression>, List<DocumentField>> CreateExpressions(DocumentTemplate dt, 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)
{
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);
string templateFilename = dt.RepositoryFilename(database);
PdfReader pdfReader = new PdfReader(templateFilename);
int pdfFieldOrdinal = 0;
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);
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++;
}
pdfReader.Close();
module = Expressions.ExpressionCache.GetModule(cacheModuleKey, true);
}
return module;
return Tuple.Create(expressions, fields);
}
public static List<BI.Expressions.Expression> ExtractPdfExpressions(this DocumentTemplate dt, DiscoDataContext dbContext)
public static Dictionary<string, Expression> PdfExpressionsFromCache(this DocumentTemplate dt, DiscoDataContext Database)
{
return dt.PdfExpressionsFromCache(dbContext).Values.OrderBy(e => e.Ordinal).ToList();
}
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);
return ExpressionCache.GetOrCreateExpressions(dt, () => CreateExpressions(dt, Database));
}
public static Expression FilterExpressionFromCache(this DocumentTemplate dt)
public static List<DocumentField> PdfFieldsFromCache(this DocumentTemplate dt, DiscoDataContext Database)
{
return ExpressionCache.GetValue("DocumentTemplateFilterExpression", dt.Id, () => { return Expression.TokenizeSingleDynamic(null, dt.FilterExpression, 0); });
return ExpressionCache.GetOrCreateFields(dt, () => CreateExpressions(dt, Database));
}
public static void FilterExpressionInvalidateCache(this DocumentTemplate dt)
public static List<Expression> ExtractPdfExpressions(this DocumentTemplate dt, DiscoDataContext Database)
{
ExpressionCache.InvalidateKey("DocumentTemplateFilterExpression", dt.Id);
return dt.PdfExpressionsFromCache(Database).Values.OrderBy(e => e.Ordinal).ToList();
}
public static bool FilterExpressionMatches(this DocumentTemplate dt, object Data, DiscoDataContext DataContext, User User, System.DateTime TimeStamp, DocumentState State)
public static Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Target, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
{
if (!string.IsNullOrEmpty(dt.FilterExpression))
{
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))
{
return erBool;
}
}
catch
{
return false;
}
}
return true;
}
public static string GetDataId(this DocumentTemplate dt, object Data)
{
if (Data is string)
{
return (string)Data;
}
bool generateExpression = !string.IsNullOrEmpty(dt.OnGenerateExpression);
string generateExpressionResult = null;
if (generateExpression)
generateExpressionResult = dt.EvaluateOnGenerateExpression(Target, Database, CreatorUser, TimeStamp, State);
var pdfStream = Interop.Pdf.PdfGenerator.GenerateFromTemplate(dt, Database, Target, CreatorUser, TimeStamp, State, FlattenFields);
if (generateExpression)
DocumentsLog.LogDocumentGenerated(dt, Target, CreatorUser, generateExpressionResult);
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:
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");
return Interop.Pdf.PdfGenerator.GenerateBulkFromPackage(package, Database, CreatorUser, Timestamp, InsertBlankPages, DataObjectsIds);
}
}
}
public static string UniqueIdentifier(string DocumentTemplateId, string DataId, string CreatorId, System.DateTime Timestamp)
public static Stream GeneratePdfPackageBulk(this DocumentTemplatePackage package, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, List<IAttachmentTarget> DataObjects)
{
return string.Format("Disco|1|{0}|{1}|{2}|{3:s}",
DocumentTemplateId,
DataId,
CreatorId,
Timestamp
);
return Interop.Pdf.PdfGenerator.GenerateBulkFromPackage(package, Database, CreatorUser, Timestamp, InsertBlankPages, DataObjects);
}
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}",
dt.Id,
dt.GetDataId(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Data)),
CreatorId,
Timestamp
);
}
public static string UniquePageIdentifier(this DocumentTemplate dt, object Data, string CreatorId, System.DateTime Timestamp, int Page)
string templateFilename = dt.RepositoryFilename(Database);
if (!File.Exists(templateFilename))
throw new FileNotFoundException("PDF template not found", templateFilename);
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();
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}",
dt.Id,
dt.GetDataId(System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(Data)),
CreatorId,
Timestamp,
Page
);
result[fieldPosition.page - 1] = true;
}
public static List<RectangleF> QRCodeLocations(this DocumentTemplate dt, DiscoDataContext dbContext)
{
return DocumentTemplateBI.DocumentTemplateQRCodeLocationCache.GetLocations(dt, dbContext);
pdfReader.Close();
return result.ToList();
}
public static void Delete(this DocumentTemplate dt, DiscoDataContext Context)
public static void Delete(this DocumentTemplate dt, DiscoDataContext Database)
{
// Find & Rename all references
foreach (DeviceAttachment a in Context.DeviceAttachments.Where(a => a.DocumentTemplateId == dt.Id))
foreach (DeviceAttachment a in Database.DeviceAttachments.Where(a => a.DocumentTemplateId == dt.Id))
{
a.Comments = string.Format("{0} - {1}", dt.Description, a.Comments);
if (a.Comments.Length > 500)
@@ -185,7 +136,7 @@ namespace Disco.BI.Extensions
a.DocumentTemplateId = null;
a.DocumentTemplate = null;
}
foreach (JobAttachment a in Context.JobAttachments.Where(a => a.DocumentTemplateId == dt.Id))
foreach (JobAttachment a in Database.JobAttachments.Where(a => a.DocumentTemplateId == dt.Id))
{
a.Comments = string.Format("{0} - {1}", dt.Description, a.Comments);
if (a.Comments.Length > 500)
@@ -193,7 +144,7 @@ namespace Disco.BI.Extensions
a.DocumentTemplateId = null;
a.DocumentTemplate = null;
}
foreach (UserAttachment a in Context.UserAttachments.Where(a => a.DocumentTemplateId == dt.Id))
foreach (UserAttachment a in Database.UserAttachments.Where(a => a.DocumentTemplateId == dt.Id))
{
a.Comments = string.Format("{0} - {1}", dt.Description, a.Comments);
if (a.Comments.Length > 500)
@@ -202,11 +153,15 @@ namespace Disco.BI.Extensions
a.DocumentTemplate = null;
}
// Remove Linked Group
ActiveDirectory.Context.ManagedGroups.Remove(DocumentTemplateDevicesManagedGroup.GetKey(dt));
ActiveDirectory.Context.ManagedGroups.Remove(DocumentTemplateUsersManagedGroup.GetKey(dt));
// Delete SubTypes
dt.JobSubTypes.Clear();
// Delete Template
string templateRepositoryFilename = dt.RepositoryFilename(Context);
string templateRepositoryFilename = dt.RepositoryFilename(Database);
if (System.IO.File.Exists(templateRepositoryFilename))
System.IO.File.Delete(templateRepositoryFilename);
@@ -214,7 +169,7 @@ namespace Disco.BI.Extensions
dt.FilterExpressionInvalidateCache();
// 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
}
}
-296
View File
@@ -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,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);
}
}
}
-65
View File
@@ -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
}
}
+195 -51
View File
@@ -1,33 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Models.Repository;
using Disco.BI.Extensions;
using Disco.Data.Repository;
using Disco.Models.BI.DocumentTemplates;
using System.IO;
using iTextSharp.text.pdf;
using System.Collections.Concurrent;
using Disco.BI.Expressions;
using System.Collections;
using Disco.BI.Extensions;
using Disco.Models.BI.Expressions;
using Disco.Models.Repository;
using Disco.Models.Services.Documents;
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.codec;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Disco.BI.Interop.Pdf
{
public static class PdfGenerator
{
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
public static Stream GenerateBulkFromPackage(DocumentTemplatePackage package, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, List<IAttachmentTarget> DataObjects)
{
if (DataObjects.Length > 0)
if (DataObjects.Count > 0)
{
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length);
using (Models.BI.DocumentTemplates.DocumentState state = Models.BI.DocumentTemplates.DocumentState.DefaultState())
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Count);
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.FlushScopeCache();
}
@@ -38,7 +41,7 @@ namespace Disco.BI.Interop.Pdf
}
else
{
Stream bulkPdf = DocumentTemplateBI.Utilities.JoinPdfs(generatedPdfs.ToArray());
Stream bulkPdf = Utilities.JoinPdfs(package.InsertBlankPages || InsertBlankPages, generatedPdfs);
foreach (Stream singlePdf in generatedPdfs)
singlePdf.Dispose();
return bulkPdf;
@@ -47,36 +50,164 @@ namespace Disco.BI.Interop.Pdf
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:
DataObjects = dbContext.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).ToArray();
case AttachmentTypes.Device:
DataObjects = Database.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).ToList<IAttachmentTarget>();
break;
case DocumentTemplate.DocumentTemplateScopes.Job:
case AttachmentTypes.Job:
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;
case DocumentTemplate.DocumentTemplateScopes.User:
DataObjects = new object[DataObjectsIds.Length];
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
case AttachmentTypes.User:
DataObjects = new List<IAttachmentTarget>(DataObjectsIds.Count);
for (int idIndex = 0; idIndex < DataObjectsIds.Count; idIndex++)
{
DataObjects[idIndex] = UserBI.UserCache.GetUser(DataObjectsIds[idIndex], dbContext, true);
if (DataObjects[idIndex] == null)
throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex]));
string dataObjectId = DataObjectsIds[idIndex];
var user = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(dataObjectId), Database, true);
if (user == null)
throw new Exception($"Unknown Username specified: {dataObjectId}");
DataObjects.Add(user);
}
break;
default:
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
switch (dt.Scope)
@@ -97,15 +228,15 @@ namespace Disco.BI.Interop.Pdf
throw new InvalidOperationException("Invalid AttachmentType Scope");
}
dbContext.Configuration.LazyLoadingEnabled = true;
Database.Configuration.LazyLoadingEnabled = true;
// Override FlattenFields if Document Template instructs.
if (dt.FlattenForm)
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);
MemoryStream pdfGeneratedStream = new MemoryStream();
@@ -114,16 +245,16 @@ namespace Disco.BI.Interop.Pdf
pdfStamper.FormFlattening = FlattenFields;
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)
{
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
{
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)
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
pdfStamper.AcroFields.SetField(pdfFieldKey, string.Empty);
else
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldValue);
@@ -131,11 +262,23 @@ namespace Disco.BI.Interop.Pdf
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; 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);
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfBarcodeImage);
// Create Binary Unique Identifier
var pageUniqueId = dt.CreateUniqueIdentifier(Database, Data, CreatorUser, TimeStamp, pdfFieldPosition.page);
var pageUniqueIdBytes = pageUniqueId.ToQRCodeBytes();
// Encode to QRCode byte array
var pageUniqueIdWidth = (int)pdfFieldPosition.position.Width;
var pageUniqueIdHeight = (int)pdfFieldPosition.position.Height;
var pageUniqueIdEncoded = QRCodeBinaryEncoder.Encode(pageUniqueIdBytes, pageUniqueIdWidth, pageUniqueIdHeight);
// Encode byte array to Image
var pageUniqueIdImageData = CCITTG4Encoder.Compress(pageUniqueIdEncoded, pageUniqueIdWidth, pageUniqueIdHeight);
var pageUniqueIdImage = iTextSharp.text.Image.GetInstance(pageUniqueIdWidth, pageUniqueIdHeight, false, 256, 1, pageUniqueIdImageData, null);
// Add to the pdf page
pageUniqueIdImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pageUniqueIdImage);
}
// Hide Fields
PdfDictionary field = fields.GetValue(0);
@@ -172,8 +315,9 @@ namespace Disco.BI.Interop.Pdf
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; 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 = iTextSharp.text.Image.GetInstance(imageResult.GetImage((int)(pdfFieldPosition.position.Width * 1.6), (int)(pdfFieldPosition.position.Height * 1.6)));
pdfImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
pdfImage.ScaleToFit(pdfFieldPosition.position.Width, pdfFieldPosition.position.Height);
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfImage);
}
if (!fieldExpressionResult.Item2 && !imageResult.ShowField)
@@ -236,11 +380,11 @@ namespace Disco.BI.Interop.Pdf
JobLog jl = new JobLog()
{
JobId = j.Id,
TechUserId = CreatorUser.Id,
TechUserId = CreatorUser.UserId,
Timestamp = DateTime.Now
};
jl.Comments = string.Format("Document Generated{0}{1} [{2}]", Environment.NewLine, dt.Description, dt.Id);
dbContext.JobLogs.Add(jl);
jl.Comments = string.Format("# Document Generated\r\n**{0}** [{1}]", dt.Description, dt.Id);
Database.JobLogs.Add(jl);
}
pdfGeneratedStream.Position = 0;
-971
View File
@@ -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 &lt;= y &lt; 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 &lt;= left &lt; Width.</param>
/// <param name="top">The top coordinate, 0 &lt;= top &lt;= 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 };
}
}
}
+56
View File
@@ -0,0 +1,56 @@
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.Collections.Generic;
using System.IO;
namespace Disco.BI.Interop.Pdf
{
public static class Utilities
{
public static Stream JoinPdfs(bool InsertBlankPages, List<Stream> Pdfs)
{
if (Pdfs.Count == 0)
throw new System.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);
}
}
}
-135
View File
@@ -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;
}
}
}
}
-93
View File
@@ -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");
}
}
}
-171
View File
@@ -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";
}
}
}
}
-61
View File
@@ -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);
}
}
}
-146
View File
@@ -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);
}
}
}
}
}
-76
View File
@@ -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);
}
}
}
+16 -161
View File
@@ -10,7 +10,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Disco</RootNamespace>
<AssemblyName>Disco.BI</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
@@ -37,50 +37,15 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="BitMiracle.LibTiff.NET">
<HintPath>..\Resources\Libraries\LibTiff.NET\BitMiracle.LibTiff.NET.dll</HintPath>
</Reference>
<Reference Include="EntityFramework">
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
</Reference>
<Reference Include="itextsharp">
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
</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">
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
</Reference>
<Reference Include="Spring.Core">
<HintPath>..\Resources\Libraries\Spring.NET\Spring.Core.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
@@ -88,21 +53,16 @@
<Reference Include="System.DirectoryServices" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Reactive.Core, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Extensions, Version=2.2.22.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Reactive.Interfaces, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll</HintPath>
</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 Include="System.Net.Http.Primitives, Version=4.2.22.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Net.Http.2.2.22\lib\net45\System.Net.Http.Primitives.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
@@ -111,98 +71,11 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<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>
<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\DocumentTemplateBI\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\Utilities.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\Resources.Designer.cs">
<AutoGen>True</AutoGen>
@@ -232,34 +105,16 @@
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</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 />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<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" />
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<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')" />
<Target Name="EnsureBclBuildImported" BeforeTargets="BeforeBuild" Condition="'$(BclBuildImported)' == ''">
<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" />
<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" />
</Target>
<!-- 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.
<Target Name="BeforeBuild">
+5 -6
View File
@@ -1,15 +1,14 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Disco - Business Intelligence")]
[assembly: AssemblyTitle("Disco ICT - Business Intelligence")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Disco")]
[assembly: AssemblyCompany("https://discoict.com.au")]
[assembly: AssemblyProduct("Disco ICT")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[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
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.0725.2249")]
[assembly: AssemblyFileVersion("1.2.0725.2249")]
[assembly: AssemblyVersion("2.2.16326.0500")]
[assembly: AssemblyFileVersion("2.2.16326.0500")]
+1 -51
View File
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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
// the code is regenerated.
@@ -59,55 +59,5 @@ namespace Disco.Properties {
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));
}
}
}
}
-16
View File
@@ -117,20 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</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>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

+36
View File
@@ -18,4 +18,40 @@
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</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>
</assemblyBinding>
</runtime>
</configuration>
+3 -12
View File
@@ -1,16 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net45" />
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" 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" />
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" />
</packages>
+69 -13
View File
@@ -1,5 +1,5 @@
<?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')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -9,9 +9,8 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Disco.Client</RootNamespace>
<AssemblyName>Disco.Client</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
@@ -24,6 +23,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -33,6 +33,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Disco.Client.Program</StartupObject>
@@ -48,9 +49,8 @@
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<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\net40\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.2\lib\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
@@ -66,6 +66,54 @@
<Compile Include="..\Disco.Models\ClientServices\Enrol.cs">
<Link>Models\ClientServices\Enrol.cs</Link>
</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">
<Link>Models\ClientServices\EnrolResponse.cs</Link>
</Compile>
@@ -93,10 +141,19 @@
<Compile Include="Extensions\EnrolExtensions.cs" />
<Compile Include="Extensions\WhoAmIExtensions.cs" />
<Compile Include="Interop\Certificates.cs" />
<Compile Include="Interop\Hardware.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\WirelessNetwork.cs" />
<Compile Include="Presentation.cs" />
<Compile Include="Interop\SystemAudit.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
@@ -120,17 +177,16 @@
<None Include="Package Creation\7z.exe" />
</ItemGroup>
<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>
<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
COPY "$(ProjectDir)Package Creation\PreparationClient.zip" "$(ProjectDir)..\Disco.Web\ClientBin"</PostBuildEvent>
</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.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+1 -1
View File
@@ -89,7 +89,7 @@ namespace Disco.Client
string reportResponse;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(ServicePathTemplate);
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.Method = WebRequestMethods.Http.Post;
request.UseDefaultCredentials = true;
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Client.Extensions
{
@@ -1,55 +1,60 @@
using System;
using System.Collections.Generic;
using Disco.Models.ClientServices;
using Newtonsoft.Json;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Disco.Models.ClientServices;
using Newtonsoft.Json;
namespace Disco.Client.Extensions
{
public static class ClientServicesExtensions
{
//#if DEBUG
// public const string ServicePathAuthenticatedTemplate = "http://WS-GSHARP:57252/Services/Client/Authenticated/{0}";
// public const string ServicePathUnauthenticatedTemplate = "http://WS-GSHARP:57252/Services/Client/Unauthenticated/{0}";
//#else
public const string ServicePathAuthenticatedTemplate = "http://DISCO:9292/Services/Client/Authenticated/{0}";
public const string ServicePathUnauthenticatedTemplate = "http://DISCO:9292/Services/Client/Unauthenticated/{0}";
//#endif
public static ResponseType Post<ResponseType>(this ServiceBase<ResponseType> Service, bool Authenticated)
{
string jsonResponse;
ResponseType serviceResponse;
string serviceUrl;
if (Authenticated)
serviceUrl = string.Format(ServicePathAuthenticatedTemplate, Service.Feature);
else
serviceUrl = string.Format(ServicePathUnauthenticatedTemplate, Service.Feature);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.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.Method = WebRequestMethods.Http.Post;
request.UseDefaultCredentials = true;
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 (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 default(ResponseType);
else
return JsonConvert.DeserializeObject<ResponseType>(jsonResponse);
return serviceResponse;
}
}
+48 -68
View File
@@ -1,13 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Disco.Client.Interop;
using Disco.Models.ClientServices;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Diagnostics;
using Microsoft.Win32;
using System.Text.RegularExpressions;
using System;
using System.Diagnostics;
using System.IO;
namespace Disco.Client.Extensions
{
@@ -16,25 +12,23 @@ namespace Disco.Client.Extensions
public static void Build(this Enrol enrol)
{
enrol.DeviceUUID = Interop.SystemAudit.DeviceUUID;
enrol.DeviceSerialNumber = Interop.SystemAudit.DeviceSerialNumber;
enrol.ComputerName = Environment.MachineName;
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;
enrol.DeviceModel = Interop.SystemAudit.DeviceModel;
enrol.DeviceModelType = Interop.SystemAudit.DeviceType;
enrol.DeviceIsPartOfDomain = Interop.SystemAudit.DeviceIsPartOfDomain;
// LAN
enrol.DeviceLanMacAddress = Interop.Network.PrimaryLanMacAddress;
// WAN
enrol.DeviceWlanMacAddress = Interop.Network.PrimaryWlanMacAddress;
// Apply System Information
enrol.ApplySystemInformation();
// 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)
@@ -50,12 +44,14 @@ namespace Disco.Client.Extensions
// Offline Domain Join
bool requireReboot = enrolResponse.ApplyOfflineDomainJoin();
// Certificates
enrolResponse.ApplyDeviceCertificates();
// Device Owner
enrolResponse.ApplyDeviceAssignedUser();
// Certificates
enrolResponse.ApplyDeviceCertificates();
// Wireless Profiles
enrolResponse.ApplyWirelessProfiles();
Presentation.UpdateStatus("Enrolling Device", "Device Enrolment Successfully Completed", false, 0, 1500);
@@ -70,15 +66,15 @@ namespace Disco.Client.Extensions
/// <returns>Boolean indicating whether a reboot is required.</returns>
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();
File.WriteAllBytes(odjFile, Convert.FromBase64String(enrolResponse.OfflineDomainJoin));
File.WriteAllBytes(odjFile, Convert.FromBase64String(enrolResponse.OfflineDomainJoinManifest));
string odjWindowsPath = Environment.GetEnvironmentVariable("SystemRoot");
string odjProcessArguments = string.Format("/REQUESTODJ /LOADFILE \"{0}\" /WINDOWSPATH \"{1}\" /LOCALOS", odjFile, odjWindowsPath);
string odjProcessArguments = $"/REQUESTODJ /LOADFILE \"{odjFile}\" /WINDOWSPATH \"{odjWindowsPath}\" /LOCALOS";
ProcessStartInfo odjProcessStartInfo = new ProcessStartInfo("DJOIN.EXE", odjProcessArguments)
{
@@ -94,16 +90,17 @@ namespace Disco.Client.Extensions
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);
Presentation.UpdateStatus("Enrolling Device", $"Offline Domain Join Result:\r\n{odjResult}", true, -1, 3000);
if (File.Exists(odjFile))
File.Delete(odjFile);
// Flush Logged-On History
if (!string.IsNullOrEmpty(enrolResponse.DeviceDomainName))
if (!string.IsNullOrEmpty(enrolResponse.DomainName))
{
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true)){
regWinlogon.SetValue("DefaultDomainName", enrolResponse.DeviceDomainName, RegistryValueKind.String);
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true))
{
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))
@@ -128,61 +125,44 @@ namespace Disco.Client.Extensions
private static void ApplyDeviceAssignedUser(this EnrolResponse enrolResponse)
{
// 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)
Interop.LocalAuthentication.AddLocalGroupMembership("Administrators", enrolResponse.AssignedUserSID, enrolResponse.AssignedUserUsername, enrolResponse.AssignedUserDomain);
// Make Windows think this user was the last to logon
using (RegistryKey regWinlogon = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon", true))
{
regWinlogon.SetValue("DefaultDomainName", enrolResponse.DeviceAssignedUserDomain, RegistryValueKind.String);
regWinlogon.SetValue("DefaultUserName", enrolResponse.DeviceAssignedUserUsername, RegistryValueKind.String);
regWinlogon.SetValue("DefaultDomainName", enrolResponse.AssignedUserDomain, RegistryValueKind.String);
regWinlogon.SetValue("DefaultUserName", enrolResponse.AssignedUserUsername, RegistryValueKind.String);
}
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)
{
// Only run if a Certificate was supplied
if (!string.IsNullOrEmpty(enrolResponse.DeviceCertificate))
if (enrolResponse.Certificates != null)
{
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);
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.");
enrolResponse.Certificates.Apply();
}
}
// Certificate Removal
if (enrolResponse.DeviceCertificateRemoveExisting != null && enrolResponse.DeviceCertificateRemoveExisting.Count > 0)
private static void ApplyWirelessProfiles(this EnrolResponse enrolResponse)
{
List<Regex> regExMatchesSubject = new List<Regex>();
foreach (var subjectRegEx in enrolResponse.DeviceCertificateRemoveExisting)
regExMatchesSubject.Add(new Regex(subjectRegEx, RegexOptions.IgnoreCase));
if (enrolResponse.WirelessProfiles != null)
{
Presentation.UpdateStatus("Enrolling Device", "Configuring Wireless Profiles", true, -1, 1000);
// Remove from 'My' Store
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);
enrolResponse.WirelessProfiles.Apply();
}
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 32 KiB

+85 -58
View File
@@ -1,103 +1,130 @@
using System;
using Disco.Models.ClientServices.EnrolmentInformation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
namespace Disco.Client.Interop
{
public static class Certificates
{
public static string GetCertificateFriendlyName(X509Certificate2 Certificate)
public static List<Certificate> GetAllCertificates()
{
string subject = Certificate.Subject;
return subject.Substring(subject.IndexOf("=") + 1, subject.IndexOf(",") - subject.IndexOf("=") - 1);
var certificates = new List<Certificate>();
// 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);
certStore.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);
var store = new X509Store(StoreName, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
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;
break;
Store = StoreDescription,
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
{
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);
List<string> results = new List<string>();
List<X509Certificate2> certStoreRemove = new List<X509Certificate2>();
if (EnrolStore != null)
{
// 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
{
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))
{
certStoreRemove.Add(cert);
break;
}
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);
addedThumbprints.Add(certificate.Thumbprint);
}
}
}
foreach (var cert in certStoreRemove)
// Remove
if (RemoveThumbprints != null && RemoveThumbprints.Count > 0)
{
results.Add(cert.Subject);
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);
certStore.Remove(cert);
foreach (var thumbprint in RemoveThumbprints)
{
List<X509Certificate2> certificates;
if (existingThumbprints.TryGetValue(thumbprint, out certificates) && !addedThumbprints.Contains(thumbprint))
{
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
{
certStore.Close();
store.Close();
}
}
}
return results;
}
}
}
+690
View File
@@ -0,0 +1,690 @@
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.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 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 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 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 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))
{
Guid uuidGuid;
if (Guid.TryParse(deviceHardware.UUID, out 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 Client was unable to retrieve ComputerSystemProduct information from WMI", ex);
}
}
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,
}
}
}
+4 -31
View File
@@ -1,10 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Client.Interop
{
@@ -14,7 +10,7 @@ namespace Disco.Client.Interop
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
foreach (object memberRef in (IEnumerable)group.Invoke("Members"))
@@ -22,38 +18,15 @@ namespace Disco.Client.Interop
using (DirectoryEntry member = new DirectoryEntry(memberRef))
{
var memberPath = member.Path;
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.InvariantCultureIgnoreCase) ||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.InvariantCultureIgnoreCase))
if (memberPath.Equals($"WinNT://{UserDomain}/{Username}", StringComparison.OrdinalIgnoreCase) ||
memberPath.Equals($"WinNT://{UserSID}", StringComparison.OrdinalIgnoreCase))
return false;
}
}
group.Invoke("Add", string.Format("WinNT://{0}", UserSID));
group.Invoke("Add", $"WinNT://{UserSID}");
}
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,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
}
}
}
+208
View File
@@ -0,0 +1,208 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Disco.Client.Interop.Native
{
public static class WlanApi
{
public const uint WLAN_API_VERSION_2_0 = 2; // Windows Vista WiFi API Version
public const int ERROR_SUCCESS = 0;
public const int ERROR_INVALID_PARAMETER = 87;
public const int ERROR_NOT_ENOUGH_MEMORY = 8;
public const int ERROR_SERVICE_NOT_ACTIVE = 1062; // The service has not been started.
/// <summary>
/// The WlanOpenHandle function opens a connection to the server.
/// </summary>
/// <param name="dwClientVersion">The highest version of the WLAN API that the client supports.
/// 1 = Client version for Windows XP with SP3 and Wireless LAN API for Windows XP with SP2.
/// 2 = Client version for Windows Vista and Windows Server 2008</param>
/// <param name="pReserved">Reserved for future use. Must be set to NULL.</param>
/// <param name="pdwNegotiatedVersion">The version of the WLAN API that will be used in this session. This value is usually the highest version supported by both the client and server.</param>
/// <param name="phClientHandle">A handle for the client to use in this session. This handle is used by other functions throughout the session.</param>
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
/// If the function fails, the return value may be one of the following return codes.
/// ERROR_INVALID_PARAMETER: pdwNegotiatedVersion is NULL, phClientHandle is NULL, or pReserved is not NULL.
/// ERROR_NOT_ENOUGH_MEMORY: Failed to allocate memory to create the client context.
/// RPC_STATUS: Various error codes.
/// ERROR_REMOTE_SESSION_LIMIT_EXCEEDED: Too many handles have been issued by the server.
/// </returns>
/// <remarks>
/// The version number specified by dwClientVersion and pdwNegotiatedVersion is a composite version number
/// made up of both major and minor versions. The major version is specified by the low-order word, and the
/// minor version is specified by the high-order word. The macros WLAN_API_VERSION_MAJOR(_v) and
/// WLAN_API_VERSION_MINOR(_v) return the major and minor version numbers respectively.
/// You can construct a version number using the macro WLAN_API_MAKE_VERSION(_major, _minor).
/// Windows XP with SP3 and Wireless LAN API for Windows XP with SP2:  WlanOpenHandle will return an
/// error message if the Wireless Zero Configuration (WZC) service has not been started or if the WZC service is not responsive.
/// </remarks>
[DllImport("Wlanapi.dll", SetLastError = true)]
public static extern uint WlanOpenHandle(uint dwClientVersion, IntPtr pReserved, out uint pdwNegotiatedVersion, out IntPtr phClientHandle);
/// <summary>
/// The WlanCloseHandle function closes a connection to the server.
/// </summary>
/// <param name="hClientHandle">The client's session handle, which identifies the connection to be closed. This handle was obtained by a previous call to the WlanOpenHandle function.</param>
/// <param name="pReserved">Reserved for future use. Set this parameter to NULL.</param>
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
/// If the function fails, the return value may be one of the following return codes.
/// ERROR_INVALID_PARAMETER: hClientHandle is NULL or invalid, or pReserved is not NULL.
/// ERROR_INVALID_HANDLE: The handle hClientHandle was not found in the handle table.
/// RPC_STATUS: Various error codes.
/// </returns>
/// <remarks>
/// After a connection has been closed, any attempted use of the closed handle can cause unexpected errors.
/// Upon closing, all outstanding notifications are discarded.
/// Do not call WlanCloseHandle from a callback function. If the client is in the middle of a
/// notification callback when WlanCloseHandle is called, the function waits for the callback to
/// finish before returning a value. Calling this function inside a callback function will result in
/// the call never completing. If both the callback function and the thread that closes the handle try
/// to acquire the same lock, a deadlock may occur. In addition, do not call WlanCloseHandle from
/// the DllMain function in an application DLL. This could also cause a deadlock.
/// </remarks>
[DllImport("Wlanapi", SetLastError = true)]
public static extern uint WlanCloseHandle(IntPtr hClientHandle, IntPtr pReserved);
/// <summary>
/// The WlanEnumInterfaces function enumerates all of the wireless LAN interfaces currently enabled on the local computer.
/// </summary>
/// <param name="hClientHandle">The client's session handle, obtained by a previous call to the WlanOpenHandle function.</param>
/// <param name="pReserved">Reserved for future use. This parameter must be set to NULL.</param>
/// <param name="ppInterfaceList">
/// A pointer to storage for a pointer to receive the returned list of wireless LAN interfaces in a WLAN_INTERFACE_INFO_LIST structure.
/// The buffer for the WLAN_INTERFACE_INFO_LIST returned is allocated by the WlanEnumInterfaces function if the call succeeds.
/// </param>
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
/// If the function fails, the return value may be one of the following return codes.
/// ERROR_INVALID_PARAMETER: A parameter is incorrect. This error is returned if the hClientHandle or ppInterfaceList parameter is NULL. This error is returned if the pReserved is not NULL.
/// This error is also returned if the hClientHandle parameter is not valid.
/// ERROR_INVALID_HANDLE: The handle hClientHandle was not found in the handle table.
/// RPC_STATUS: Various error codes.
/// ERROR_NOT_ENOUGH_MEMORY: Not enough memory is available to process this request and allocate memory for the query results.
/// </returns>
/// <remarks>
/// The WlanEnumInterfaces function allocates memory for the list of returned interfaces that is returned in the
/// buffer pointed to by the ppInterfaceList parameter when the function succeeds. The memory used for the buffer
/// pointed to by ppInterfaceList parameter should be released by calling the WlanFreeMemory function
/// after the buffer is no longer needed.
/// </remarks>
[DllImport("Wlanapi", SetLastError = true)]
public static extern uint WlanEnumInterfaces(IntPtr hClientHandle, IntPtr pReserved, out IntPtr ppInterfaceList);
/// <summary>
/// The WlanGetProfileList function retrieves the list of profiles in preference order.
/// </summary>
/// <param name="hClientHandle">The client's session handle, obtained by a previous call to the WlanOpenHandle function.</param>
/// <param name="pInterfaceGuid">The GUID of the wireless interface.</param>
/// <param name="pReserved">Reserved for future use. Must be set to NULL.</param>
/// <param name="ppProfileList">A PWLAN_PROFILE_INFO_LIST structure that contains the list of profile information.</param>
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
/// If the function fails, the return value may be one of the following return codes.
/// ERROR_INVALID_HANDLE: The handle hClientHandle was not found in the handle table.
/// ERROR_INVALID_PARAMETER: A parameter is incorrect.
/// ERROR_NOT_ENOUGH_MEMORY: Not enough memory is available to process this request and allocate memory for the query results.
/// RPC_STATUS: Various error codes.
/// </returns>
/// <remarks>
/// The WlanGetProfileList function returns only the basic information on the wireless profiles on a wireless interface.
/// The list of wireless profiles on a wireless interface are retrieved in the preference order. The WlanSetProfilePosition
/// can be used to change the preference order for the wireless profiles on a wireless interface.
/// More detailed information for a wireless profile on a wireless interface can be retrieved by using the WlanGetProfile
/// function. The WlanGetProfileCustomUserData function can be used to retrieve custom user data for a wireless profile on
/// a wireless interface. A list of the wireless interfaces and associated GUIDs on the local computer can be retrieved
/// using the WlanEnumInterfaces function.
/// The WlanGetProfileList function allocates memory for the list of profiles returned in the buffer pointed to by the
/// ppProfileList parameter. The caller is responsible for freeing this memory using the WlanFreeMemory function when
/// this buffer is no longer needed.
/// Windows XP with SP3 and Wireless LAN API for Windows XP with SP2:  Guest profiles, profiles with Wireless Provisioning
/// Service (WPS) authentication, and profiles with Wi-Fi Protected Access-None (WPA-None) authentication are not
/// supported. These types of profiles are not returned by WlanGetProfileList, even if a profile of this type appears
/// on the preferred profile list.
/// </remarks>
[DllImport("Wlanapi", SetLastError = true)]
public static extern uint WlanGetProfileList(IntPtr hClientHandle, [MarshalAs(UnmanagedType.LPStruct)] Guid pInterfaceGuid, IntPtr pReserved, out IntPtr ppProfileList);
/// <summary>
/// The WlanGetProfile function retrieves all information about a specified wireless profile.
/// </summary>
/// <param name="hClientHandle">The client's session handle, obtained by a previous call to the WlanOpenHandle function.</param>
/// <param name="pInterfaceGuid">The GUID of the wireless interface. </param>
/// <param name="strProfileName">The name of the profile. Profile names are case-sensitive. This string must be NULL-terminated. The maximum length of the profile name is 255 characters. This means that the maximum length of this string, including the NULL terminator, is 256 characters.</param>
/// <param name="pReserved">Reserved for future use. Must be set to NULL.</param>
/// <param name="pstrProfileXml">A string that is the XML representation of the queried profile. There is no predefined maximum string length.</param>
/// <param name="pdwFlags">On input, a pointer to the address location used to provide additional information about the request. If this parameter is NULL on input, then no information on profile flags will be returned. On output, a pointer to the address location used to receive profile flags.</param>
/// <param name="pdwGrantedAccess">The access mask of the all-user profile.</param>
/// <returns>If the function succeeds, the return value is ERROR_SUCCESS.</returns>
[DllImport("Wlanapi", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint WlanGetProfile(IntPtr hClientHandle, [MarshalAs(UnmanagedType.LPStruct)] Guid pInterfaceGuid, [MarshalAs(UnmanagedType.LPWStr)] string strProfileName, IntPtr pReserved, out IntPtr pstrProfileXml, out uint pdwFlags, out IntPtr pdwGrantedAccess);
/// <summary>
/// The WlanSetProfile function sets the content of a specific profile.
/// </summary>
/// <param name="hClientHandle">The client's session handle, obtained by a previous call to the WlanOpenHandle function.</param>
/// <param name="pInterfaceGuid">The GUID of the interface.</param>
/// <param name="dwFlags">The flags to set on the profile.</param>
/// <param name="strProfileXml">Contains the XML representation of the profile. The WLANProfile element is the root profile element. To view sample profiles, see Wireless Profile Samples. There is no predefined maximum string length.</param>
/// <param name="strAllUserProfileSecurity">Sets the security descriptor string on the all-user profile. For more information about profile permissions, see the Remarks section.</param>
/// <param name="bOverwrite">Specifies whether this profile is overwriting an existing profile. If this parameter is FALSE and the profile already exists, the existing profile will not be overwritten and an error will be returned.</param>
/// <param name="pReserved">Reserved for future use. Must be set to NULL.</param>
/// <param name="pdwReasonCode">A WLAN_REASON_CODE value that indicates why the profile is not valid.</param>
/// <returns>If the function succeeds, the return value is ERROR_SUCCESS.</returns>
[DllImport("Wlanapi", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint WlanSetProfile(IntPtr hClientHandle, [MarshalAs(UnmanagedType.LPStruct)] Guid pInterfaceGuid, uint dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string strProfileXml, [MarshalAs(UnmanagedType.LPWStr)] string strAllUserProfileSecurity, bool bOverwrite, IntPtr pReserved, out uint pdwReasonCode);
/// <summary>
/// The WlanDeleteProfile function deletes a wireless profile for a wireless interface on the local computer.
/// </summary>
/// <param name="hClientHandle">The client's session handle, obtained by a previous call to the WlanOpenHandle function.</param>
/// <param name="pInterfaceGuid">The GUID of the interface from which to delete the profile. </param>
/// <param name="strProfileName">The name of the profile to be deleted. Profile names are case-sensitive. This string must be NULL-terminated.</param>
/// <param name="pReserved">Reserved for future use. Must be set to NULL.</param>
/// <returns>
/// If the function succeeds, the return value is ERROR_SUCCESS.
/// If the function fails, the return value may be one of the following return codes.
/// ERROR_INVALID_PARAMETER: The hClientHandle parameter is NULL or not valid, the pInterfaceGuid parameter is NULL, the strProfileName parameter is NULL, or pReserved is not NULL.
/// ERROR_INVALID_HANDLE: The handle specified in the hClientHandle parameter was not found in the handle table.
/// ERROR_NOT_FOUND: The wireless profile specified by strProfileName was not found in the profile store.
/// ERROR_ACCESS_DENIED: The caller does not have sufficient permissions to delete the profile.
/// RPC_STATUS: Various error codes.
/// </returns>
/// <remarks>
/// The WlanDeleteProfile function deletes a wireless profile for a wireless interface on the local computer.
/// All wireless LAN functions require an interface GUID for the wireless interface when performing profile operations.
/// When a wireless interface is removed, its state is cleared from Wireless LAN Service (WLANSVC) and no profile operations are possible.
/// The WlanDeleteProfile function can fail with ERROR_INVALID_PARAMETER if the wireless interface specified in the pInterfaceGuid parameter
/// for the wireless LAN profile has been removed from the system (a USB wireless adapter that has been removed, for example).
/// </remarks>
[DllImport("Wlanapi", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint WlanDeleteProfile(IntPtr hClientHandle, [MarshalAs(UnmanagedType.LPStruct)] Guid pInterfaceGuid, [MarshalAs(UnmanagedType.LPWStr)] string strProfileName, IntPtr pReserved);
/// <summary>
/// The WlanReasonCodeToString function retrieves a string that describes a specified reason code.
/// </summary>
/// <param name="dwReasonCode">A WLAN_REASON_CODE value of which the string description is requested.</param>
/// <param name="dwBufferSize">The size of the buffer used to store the string, in WCHAR. If the reason code string is longer than the buffer, it will be truncated and NULL-terminated. If dwBufferSize is larger than the actual amount of memory allocated to pStringBuffer, then an access violation will occur in the calling program.</param>
/// <param name="pStringBuffer">Pointer to a buffer that will receive the string. The caller must allocate memory to pStringBuffer before calling WlanReasonCodeToString.</param>
/// <param name="pReserved">Reserved for future use. Must be set to NULL.</param>
/// <returns>If the function succeeds, the return value is a pointer to a constant string.</returns>
[DllImport("Wlanapi", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint WlanReasonCodeToString(uint dwReasonCode, uint dwBufferSize, ref StringBuilder pStringBuffer, IntPtr pReserved);
/// <summary>
/// The WlanFreeMemory function frees memory. Any memory returned from Native Wifi functions must be freed.
/// </summary>
/// <param name="pMemory">Pointer to the memory to be freed.</param>
/// <remarks>
/// If pMemory points to memory that has already been freed, an access violation or heap corruption may occur.
/// </remarks>
[DllImport("Wlanapi")]
public static extern void WlanFreeMemory(IntPtr pMemory);
}
}
+69 -285
View File
@@ -1,66 +1,69 @@
using System;
using Disco.Client.Interop.Native;
using Disco.Models.ClientServices.EnrolmentInformation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Runtime.InteropServices;
using System.Text;
namespace Disco.Client.Interop
{
public static class Network
{
private static List<NetworkAdapterInfo> NetworkAdapters { get; set; }
private static NetworkAdapterInfo PrimaryLanNetworkAdapter { get; set; }
private static NetworkAdapterInfo PrimaryWlanNetworkAdapter { get; set; }
static Network()
public static List<NetworkAdapter> GetNetworkAdapters()
{
// Get All Adapters
RetrieveLanAdapters();
var adapters = GetWmiNetworkAdapters();
if (NetworkAdapters.Count > 0)
if (adapters != null && adapters.Count > 0)
{
// Only Retrieve Wlan Adapters if at least one adapter was found by WMI
RetrieveWlanAdapters();
// Determine Primary Adapters
// Lan
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
// Might be too restrictive - remove name restriction just in case.
if (PrimaryLanNetworkAdapter == null)
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter).OrderByDescending(n => n.Speed).FirstOrDefault();
// Wan
PrimaryWlanNetworkAdapter = NetworkAdapters.Where(n => n.IsWLanAdapter).OrderByDescending(n => n.Speed).FirstOrDefault();
}
// Apply Wlan Information
adapters.ApplyWlanInformation();
}
private static void RetrieveLanAdapters()
return adapters;
}
private static List<NetworkAdapter> GetWmiNetworkAdapters()
{
// Get NetworkAdapter Information
try
{
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT Index, GUID, MACAddress, Name, NetConnectionID, Speed FROM Win32_NetworkAdapter WHERE PhysicalAdapter=true AND MACAddress IS NOT NULL AND Name IS NOT NULL AND NetConnectionID IS NOT NULL AND Speed IS NOT NULL"))
// Load Physical Adapters
using (var wmiSearcher = new ManagementObjectSearcher("SELECT DeviceID, GUID, Manufacturer, ProductName, AdapterType, MACAddress, Speed, NetConnectionID, NetConnectionStatus, NetEnabled FROM Win32_NetworkAdapter WHERE PhysicalAdapter=true AND MACAddress IS NOT NULL AND NetConnectionID IS NOT NULL AND Speed IS NOT NULL"))
{
using (ManagementObjectCollection mResults = mSearcher.Get())
using (var wmiResults = wmiSearcher.Get())
{
NetworkAdapters = new List<NetworkAdapterInfo>();
foreach (var mResult in mResults.Cast<ManagementObject>())
return wmiResults
.Cast<ManagementObject>()
.Select(wmiResult =>
{
NetworkAdapterInfo nic = new NetworkAdapterInfo()
var adapter = new NetworkAdapter()
{
Index = (UInt32)mResult.GetPropertyValue("Index"),
Guid = Guid.Parse((string)mResult.GetPropertyValue("GUID")),
MacAddress = mResult.GetPropertyValue("MACAddress").ToString(),
Name = mResult.GetPropertyValue("Name").ToString(),
NetConnectionId = mResult.GetPropertyValue("NetConnectionID").ToString(),
Speed = Convert.ToUInt64(mResult.GetPropertyValue("Speed")),
IsWLanAdapter = false
DeviceID = (string)wmiResult.GetPropertyValue("DeviceID"),
ConnectionIdentifier = Guid.Parse((string)wmiResult.GetPropertyValue("GUID")),
Manufacturer = (string)wmiResult.GetPropertyValue("Manufacturer"),
ProductName = (string)wmiResult.GetPropertyValue("ProductName"),
AdapterType = (string)wmiResult.GetPropertyValue("AdapterType"),
MACAddress = (string)wmiResult.GetPropertyValue("MACAddress"),
Speed = (ulong)wmiResult.GetPropertyValue("Speed"),
NetConnectionID = (string)wmiResult.GetPropertyValue("NetConnectionID"),
NetConnectionStatus = ((NetworkConnectionStatuses)wmiResult.GetPropertyValue("NetConnectionStatus")).Description(),
NetEnabled = (bool)wmiResult.GetPropertyValue("NetEnabled")
};
NetworkAdapters.Add(nic);
using (var wmiRelatedResults = wmiResult.GetRelated("Win32_NetworkAdapterConfiguration", "Win32_NetworkAdapterSetting", null, null, null, null, false, null))
{
var wmiConfiguration = wmiRelatedResults.Cast<ManagementObject>().First();
adapter.IPEnabled = (bool)wmiConfiguration.GetPropertyValue("IPEnabled");
if (adapter.IPEnabled)
{
adapter.IPAddresses = ((string[])wmiConfiguration.GetPropertyValue("IPAddress")).ToList();
}
}
return adapter;
})
.ToList();
}
}
}
catch (Exception ex)
@@ -69,259 +72,40 @@ namespace Disco.Client.Interop
}
}
private static void RetrieveWlanAdapters()
public static string Description(this NetworkConnectionStatuses Status)
{
WLAN_INTERFACE_INFO_LIST wlanApiInterfaceList;
IntPtr wlanApiHandle = IntPtr.Zero;
uint wlanApiServiceVersion = 0;
if (WlanOpenHandle(WLAN_API_VERSION_2_0, IntPtr.Zero, out wlanApiServiceVersion, ref wlanApiHandle) == ERROR_SUCCESS)
switch (Status)
{
IntPtr wlanApiInterfaceListPointer = IntPtr.Zero;
if (WlanEnumInterfaces(wlanApiHandle, IntPtr.Zero, ref wlanApiInterfaceListPointer) == ERROR_SUCCESS)
{
wlanApiInterfaceList = new WLAN_INTERFACE_INFO_LIST(wlanApiInterfaceListPointer);
WlanFreeMemory(wlanApiInterfaceListPointer);
}
else
{
// Error - No Wlan Adapters Reported
WlanCloseHandle(wlanApiHandle, IntPtr.Zero);
return;
}
WlanCloseHandle(wlanApiHandle, IntPtr.Zero);
}
else
{
// Error - No Wlan Adapters Reported
return;
}
if (wlanApiInterfaceList.InterfaceInfo != null)
{
foreach (var wlanApiAdapter in wlanApiInterfaceList.InterfaceInfo)
{
var wlanApiAdapterInfo = wlanApiAdapter;
var wmiAdapterInfo = NetworkAdapters.FirstOrDefault(n => n.Guid == wlanApiAdapterInfo.InterfaceGuid);
if (wmiAdapterInfo != null)
{
wmiAdapterInfo.IsWLanAdapter = true;
wmiAdapterInfo.WlanState = wlanApiAdapterInfo.isState;
}
}
}
}
public static string PrimaryLanMacAddress
{
get
{
// Return null if no Primary LAN Network Adapter found on this Device
return (PrimaryLanNetworkAdapter == null) ? null : PrimaryLanNetworkAdapter.MacAddress;
}
}
public static string PrimaryWlanMacAddress
{
get
{
// Return null if no Primary WLAN Network Adapter found on this Device
return (PrimaryWlanNetworkAdapter == null) ? null : PrimaryWlanNetworkAdapter.MacAddress;
}
}
private class NetworkAdapterInfo
{
public UInt32 Index { get; set; }
public Guid Guid { get; set; }
public string Name { get; set; }
public string NetConnectionId { get; set; }
public string MacAddress { get; set; }
public UInt64 Speed { get; set; }
public bool IsWLanAdapter { get; set; }
public WLAN_INTERFACE_STATE WlanState { get; set; }
public string WlanStateDescription
{
get
{
switch (WlanState)
{
case WLAN_INTERFACE_STATE.wlan_interface_state_not_ready:
return "Not Ready";
case WLAN_INTERFACE_STATE.wlan_interface_state_connected:
return "Connected";
case WLAN_INTERFACE_STATE.wlan_interface_state_ad_hoc_network_formed:
return "Ad Hoc Network Formed";
case WLAN_INTERFACE_STATE.wlan_interface_state_disconnecting:
return "Disconnecting";
case WLAN_INTERFACE_STATE.wlan_interface_state_disconnected:
case NetworkConnectionStatuses.Disconnected:
return "Disconnected";
case WLAN_INTERFACE_STATE.wlan_interface_state_associating:
return "Associating";
case WLAN_INTERFACE_STATE.wlan_interface_state_discovering:
return "Discovering";
case WLAN_INTERFACE_STATE.wlan_interface_state_authenticating:
case NetworkConnectionStatuses.Connecting:
return "Connecting";
case NetworkConnectionStatuses.Connected:
return "Connected";
case NetworkConnectionStatuses.Disconnecting:
return "Disconnecting";
case NetworkConnectionStatuses.HardwareNotPresent:
return "Hardware Not Present";
case NetworkConnectionStatuses.HardwareDisabled:
return "Hardware Disabled";
case NetworkConnectionStatuses.HardwareMalfunction:
return "Hardware Malfunction";
case NetworkConnectionStatuses.MediaDisconnected:
return "Media Disconnected";
case NetworkConnectionStatuses.Authenticating:
return "Authenticating";
case NetworkConnectionStatuses.AuthenticationSucceeded:
return "Authentication Succeeded";
case NetworkConnectionStatuses.AuthenticationFailed:
return "Authentication Failed";
case NetworkConnectionStatuses.InvalidAddress:
return "Invalid Address";
case NetworkConnectionStatuses.CredentialsRequired:
return "Credentials Required";
default:
return "Unknown";
}
}
}
}
#region Wlan Win32 Interop
private const uint WLAN_API_VERSION_2_0 = 2; // Windows Vista WiFi API Version
private const int ERROR_SUCCESS = 0;
/// <summary >
/// Opens a connection to the server
/// </summary >
[DllImport("Wlanapi.dll")]
private static extern int WlanOpenHandle(
uint dwClientVersion,
IntPtr pReserved, //not in MSDN but required
[Out] out uint pdwNegotiatedVersion,
ref IntPtr ClientHandle);
/// <summary >
/// Closes a connection to the server
/// </summary >
[DllImport("Wlanapi", EntryPoint = "WlanCloseHandle")]
private static extern uint WlanCloseHandle(
[In] IntPtr hClientHandle,
IntPtr pReserved);
/// <summary >
/// Enumerates all wireless interfaces in the laptop
/// </summary >
[DllImport("Wlanapi", EntryPoint = "WlanEnumInterfaces")]
private static extern uint WlanEnumInterfaces(
[In] IntPtr hClientHandle,
IntPtr pReserved,
ref IntPtr ppInterfaceList);
/// <summary >
/// Frees memory returned by native WiFi functions
/// </summary >
[DllImport("Wlanapi", EntryPoint = "WlanFreeMemory")]
private static extern void WlanFreeMemory([In] IntPtr pMemory);
/// <summary>
/// Defines the state of the interface. e.g. connected, disconnected.
/// </summary>
private enum WLAN_INTERFACE_STATE
{
/// <summary>
/// wlan_interface_state_not_ready -> 0
/// </summary>
wlan_interface_state_not_ready = 0,
/// <summary>
/// wlan_interface_state_connected -> 1
/// </summary>
wlan_interface_state_connected = 1,
/// <summary>
/// wlan_interface_state_ad_hoc_network_formed -> 2
/// </summary>
wlan_interface_state_ad_hoc_network_formed = 2,
/// <summary>
/// wlan_interface_state_disconnecting -> 3
/// </summary>
wlan_interface_state_disconnecting = 3,
/// <summary>
/// wlan_interface_state_disconnected -> 4
/// </summary>
wlan_interface_state_disconnected = 4,
/// <summary>
/// wlan_interface_state_associating -> 5
/// </summary>
wlan_interface_state_associating = 5,
/// <summary>
/// wlan_interface_state_discovering -> 6
/// </summary>
wlan_interface_state_discovering = 6,
/// <summary>
/// wlan_interface_state_authenticating -> 7
/// </summary>
wlan_interface_state_authenticating = 7,
}
/// <summary >
/// Stores interface info
/// </summary >
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WLAN_INTERFACE_INFO
{
/// GUID->_GUID
public Guid InterfaceGuid;
/// WCHAR[256]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string strInterfaceDescription;
/// WLAN_INTERFACE_STATE->_WLAN_INTERFACE_STATE
public WLAN_INTERFACE_STATE isState;
}
/// <summary>
/// Contains an array of NIC information
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct WLAN_INTERFACE_INFO_LIST
{
/// <summary>
/// Length of <see cref="InterfaceInfo"/> array
/// </summary>
public Int32 dwNumberOfItems;
/// <summary>
/// This member is not used by the wireless service. Applications can use this member when processing individual interfaces.
/// </summary>
public Int32 dwIndex;
/// <summary>
/// Array of WLAN interfaces.
/// </summary>
public WLAN_INTERFACE_INFO[] InterfaceInfo;
/// <summary>
/// Constructor for WLAN_INTERFACE_INFO_LIST.
/// Constructor is needed because the InterfaceInfo member varies based on how many adapters are in the system.
/// </summary>
/// <param name="pList">the unmanaged pointer containing the list.</param>
public WLAN_INTERFACE_INFO_LIST(IntPtr pList)
{
// The first 4 bytes are the number of WLAN_INTERFACE_INFO structures.
dwNumberOfItems = Marshal.ReadInt32(pList, 0);
// The next 4 bytes are the index of the current item in the unmanaged API.
dwIndex = Marshal.ReadInt32(pList, 4);
// Construct the array of WLAN_INTERFACE_INFO structures.
InterfaceInfo = new WLAN_INTERFACE_INFO[dwNumberOfItems];
for (int i = 0; i <= dwNumberOfItems - 1; i++)
{
// The offset of the array of structures is 8 bytes past the beginning.
// Then, take the index and multiply it by the number of bytes in the
// structure.
// The length of the WLAN_INTERFACE_INFO structure is 532 bytes - this
// was determined by doing a Marshall.SizeOf(WLAN_INTERFACE_INFO)
IntPtr pItemList = new IntPtr(pList.ToInt64() + (i * 532) + 8);
// Construct the WLAN_INTERFACE_INFO structure, marshal the unmanaged
// structure into it, then copy it to the array of structures.
InterfaceInfo[i] = (WLAN_INTERFACE_INFO)Marshal.PtrToStructure(pItemList, typeof(WLAN_INTERFACE_INFO));
}
}
}
#endregion
}
}
-198
View File
@@ -1,198 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Management;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Client.Interop
{
public static class SystemAudit
{
public static string DeviceSerialNumber { get; private set; }
public static string DeviceSMBIOSVersion { get; private set; }
public static string DeviceManufacturer { get; private set; }
public static string DeviceModel { get; private set; }
public static string DeviceType { get; private set; }
public static string DeviceUUID { get; private set; }
public static bool DeviceIsPartOfDomain { get; private set; }
static SystemAudit()
{
// Get BIOS Information
try
{
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT SerialNumber, SMBIOSBIOSVersion FROM Win32_BIOS WHERE PrimaryBios=true"))
{
using (ManagementObjectCollection mResults = mSearcher.Get())
{
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
{
if (mItem != null)
{
DeviceSerialNumber = mItem.GetPropertyValue("SerialNumber") as string;
if (!string.IsNullOrEmpty(DeviceSerialNumber))
DeviceSerialNumber = DeviceSerialNumber.Trim();
ErrorReporting.DeviceIdentifier = DeviceSerialNumber;
DeviceSMBIOSVersion = mItem.GetPropertyValue("SMBIOSBIOSVersion") as string;
if (!string.IsNullOrEmpty(DeviceSMBIOSVersion))
DeviceSMBIOSVersion = DeviceSMBIOSVersion.Trim();
}
else
{
throw new Exception("No Win32_BIOS WHERE PrimaryBios=true was found");
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to retrieve BIOS information from WMI", ex);
}
// Get System Information
try
{
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT Manufacturer, Model, PartOfDomain, PCSystemType FROM Win32_ComputerSystem"))
{
using (ManagementObjectCollection mResults = mSearcher.Get())
{
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
{
if (mItem != null)
{
DeviceManufacturer = mItem.GetPropertyValue("Manufacturer") as string;
if (!string.IsNullOrEmpty(DeviceManufacturer))
DeviceManufacturer = DeviceManufacturer.Trim();
DeviceModel = mItem.GetPropertyValue("Model") as string;
if (!string.IsNullOrEmpty(DeviceModel))
DeviceModel = DeviceModel.Trim();
DeviceIsPartOfDomain = (bool)mItem.GetPropertyValue("PartOfDomain");
DeviceType = PCSystemTypeToString((UInt16)mItem.GetPropertyValue("PCSystemType"));
}
else
{
throw new Exception("No Win32_ComputerSystem was found");
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to retrieve ComputerSystem information from WMI", ex);
}
// Get System Product Information
string ComputerSystemProductSerialNumber;
try
{
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT IdentifyingNumber, UUID FROM Win32_ComputerSystemProduct"))
{
using (ManagementObjectCollection mResults = mSearcher.Get())
{
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
{
if (mItem != null)
{
ComputerSystemProductSerialNumber = mItem.GetPropertyValue("IdentifyingNumber") as string;
if (!string.IsNullOrEmpty(ComputerSystemProductSerialNumber))
ComputerSystemProductSerialNumber = ComputerSystemProductSerialNumber.Trim();
DeviceUUID = mItem.GetPropertyValue("UUID") as string;
if (!string.IsNullOrEmpty(DeviceUUID))
DeviceUUID = DeviceUUID.Trim();
}
else
{
throw new Exception("No Win32_ComputerSystemProduct was found");
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to retrieve ComputerSystemProduct information from WMI", ex);
}
// 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
if (string.IsNullOrWhiteSpace(DeviceSerialNumber) ||
(DeviceManufacturer.Equals("LENOVO", StringComparison.InvariantCultureIgnoreCase) &&
(DeviceModel.Equals("S10-3", StringComparison.InvariantCultureIgnoreCase) // S10-3
|| DeviceModel.Equals("2957", StringComparison.InvariantCultureIgnoreCase)))) // S10-2
{
try
{
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard"))
{
using (ManagementObjectCollection mResults = mSearcher.Get())
{
using (var mItem = mResults.Cast<ManagementObject>().FirstOrDefault())
{
if (mItem != null)
{
DeviceSerialNumber = mItem.GetPropertyValue("SerialNumber") as string;
if (!string.IsNullOrEmpty(DeviceSerialNumber))
DeviceSerialNumber = DeviceSerialNumber.Trim();
}
else
{
throw new Exception("No Win32_BaseBoard was found");
}
}
}
}
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to retrieve BaseBoard information from WMI", ex);
}
if (string.IsNullOrWhiteSpace(DeviceSerialNumber))
DeviceSerialNumber = ComputerSystemProductSerialNumber;
}
// End Added 2012-11-22 G#
ErrorReporting.DeviceIdentifier = DeviceSerialNumber;
// Validate Device 'State'
if (string.IsNullOrWhiteSpace(DeviceSerialNumber))
throw new Exception("This device has no serial number stored in BIOS or BaseBoard");
if (DeviceSerialNumber.Length > 60)
throw new Exception(string.Format("The serial number reported by this device is over 60 characters long:{0}{1}", Environment.NewLine, DeviceSerialNumber));
}
private static string PCSystemTypeToString(UInt16 PCSystemType)
{
switch (PCSystemType)
{
case 0:
return "Unknown";
case 1:
return "Desktop";
case 2:
return "Mobile";
case 3:
return "Workstation";
case 4:
return "EnterpriseServer";
case 5:
return "SmallOfficeAndHomeOfficeServer";
case 6:
return "AppliancePC";
case 7:
return "PerformanceServer";
case 8:
return "Maximum";
default:
return "Unknown";
}
}
}
}
+388
View File
@@ -0,0 +1,388 @@
using Disco.Client.Interop.Native;
using Disco.Models.ClientServices.EnrolmentInformation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace Disco.Client.Interop
{
public static class WirelessNetwork
{
public static void ApplyWlanInformation(this List<NetworkAdapter> Adapters)
{
try
{
IntPtr wlanHandle;
uint wlanServiceVersion;
if (WlanApi.WlanOpenHandle(WlanApi.WLAN_API_VERSION_2_0, IntPtr.Zero, out wlanServiceVersion, out wlanHandle) == WlanApi.ERROR_SUCCESS)
{
try
{
IntPtr wlanInterfacesPtr;
if (WlanApi.WlanEnumInterfaces(wlanHandle, IntPtr.Zero, out wlanInterfacesPtr) == WlanApi.ERROR_SUCCESS)
{
try
{
var wlanInterfaces = new WLAN_INTERFACE_INFO_LIST(wlanInterfacesPtr);
foreach (var wlanInterface in wlanInterfaces.InterfaceInfo)
{
var adapter = Adapters.FirstOrDefault(a => a.ConnectionIdentifier == wlanInterface.InterfaceGuid);
if (adapter != null)
{
adapter.IsWlanAdapter = true;
adapter.WlanStatus = wlanInterface.isState.Description();
}
}
}
finally
{
WlanApi.WlanFreeMemory(wlanInterfacesPtr);
}
}
}
finally
{
WlanApi.WlanCloseHandle(wlanHandle, IntPtr.Zero);
}
}
}
catch (DllNotFoundException)
{
// Ignore
// Indicates 'Wlanapi.dll' isn't present (ie. Servers)
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to retrieve Wireless NetworkAdapter information from WlanApi", ex);
}
}
public static List<WirelessProfile> GetWirelessProfiles()
{
try
{
IntPtr wlanHandle;
uint wlanServiceVersion;
uint interopResult;
// Connect to wireless service
interopResult = WlanApi.WlanOpenHandle(WlanApi.WLAN_API_VERSION_2_0, IntPtr.Zero, out wlanServiceVersion, out wlanHandle);
if (interopResult == WlanApi.ERROR_SERVICE_NOT_ACTIVE)
{
// Indicates the Wlan service has not been started on the client
// typically as it is not needed (no wireless adapter) or if it
// has been forcibly disabled.
return null;
}
if (interopResult != WlanApi.ERROR_SUCCESS)
{
throw new Exception($"Unable to connect to local wireless service. WlanOpenHandle returned: {interopResult}");
}
try
{
return GetWirelessProfiles(wlanHandle);
}
finally
{
WlanApi.WlanCloseHandle(wlanHandle, IntPtr.Zero);
}
}
catch (DllNotFoundException)
{
// Indicates 'Wlanapi.dll' isn't present (ie. Servers)
return null;
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to retrieve Wireless Profiles from WlanApi", ex);
}
}
private static List<WirelessProfile> GetWirelessProfiles(IntPtr wlanHandle)
{
uint interopResult;
IntPtr wlanInterfacesPtr;
// Enumerate wireless interfaces
interopResult = WlanApi.WlanEnumInterfaces(wlanHandle, IntPtr.Zero, out wlanInterfacesPtr);
if (interopResult != WlanApi.ERROR_SUCCESS)
{
throw new Exception($"Unable to list interfaces with the local wireless service. WlanEnumInterfaces returned: {interopResult}");
}
try
{
var wlanInterfaces = new WLAN_INTERFACE_INFO_LIST(wlanInterfacesPtr);
var profiles = new List<WirelessProfile>();
foreach (var wlanInterface in wlanInterfaces.InterfaceInfo)
{
IntPtr wlanProfilesPtr;
// Enumerate wireless profiles for interface
interopResult = WlanApi.WlanGetProfileList(wlanHandle, wlanInterface.InterfaceGuid, IntPtr.Zero, out wlanProfilesPtr);
if (interopResult != WlanApi.ERROR_SUCCESS)
{
throw new Exception($"Unable to list wireless profiles for the {wlanInterface.InterfaceGuid} interface with the local wireless service. WlanGetProfileList returned: {interopResult}");
}
try
{
var wlanProfiles = new WLAN_PROFILE_INFO_LIST(wlanProfilesPtr);
foreach (var wlanProfile in wlanProfiles.ProfileInfo)
{
profiles.Add(new WirelessProfile()
{
Name = wlanProfile.strInterfaceDescription,
InterfaceGuid = wlanInterface.InterfaceGuid,
IsGroupPolicy = wlanProfile.dwFlags.HasFlag(ProfileInfoFlags.WLAN_PROFILE_GROUP_POLICY)
});
}
}
finally
{
WlanApi.WlanFreeMemory(wlanProfilesPtr);
}
}
return profiles;
}
finally
{
WlanApi.WlanFreeMemory(wlanInterfacesPtr);
}
}
public static void Apply(this WirelessProfileStore ProfileStore)
{
var adapters = Network.GetNetworkAdapters().Where(a => a.IsWlanAdapter).ToList();
try
{
IntPtr wlanHandle;
uint wlanServiceVersion;
uint interopResult;
// Connect to wireless service
interopResult = WlanApi.WlanOpenHandle(WlanApi.WLAN_API_VERSION_2_0, IntPtr.Zero, out wlanServiceVersion, out wlanHandle);
if (interopResult == WlanApi.ERROR_SERVICE_NOT_ACTIVE)
{
// Indicates the Wlan service has not been started on the client
// typically as it is not needed (no wireless adapter) or if it
// has been forcibly disabled.
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nSkipping, the WLAN service is not enabled", true, -1, 3000);
return;
}
if (interopResult != WlanApi.ERROR_SUCCESS)
{
throw new Exception($"Unable to connect to local wireless service. WlanOpenHandle returned: {interopResult}");
}
try
{
var existingProfiles = GetWirelessProfiles(wlanHandle);
var addedProfiles = new List<string>();
// Remove Profiles
if (ProfileStore.RemoveNames != null && ProfileStore.RemoveNames.Count > 0)
{
var profileRemoved = false;
foreach (var removeName in ProfileStore.RemoveNames)
{
var foundProfiles = existingProfiles.Where(p => p.Name == removeName);
foreach (var profile in foundProfiles)
{
var adapter = adapters.FirstOrDefault(a => a.ConnectionIdentifier == profile.InterfaceGuid);
if (profile.IsGroupPolicy == true)
{
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nUnable to remove Group Policy Wireless Profile '{removeName}' from '{adapter?.NetConnectionID ?? profile.InterfaceGuid.ToString()}'", true, -1, 3000);
}
else
{
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nRemoving Wireless Profile '{removeName}' from '{adapter?.NetConnectionID ?? profile.InterfaceGuid.ToString()}'", true, -1, 1000);
interopResult = WlanApi.WlanDeleteProfile(wlanHandle, profile.InterfaceGuid.Value, profile.Name, IntPtr.Zero);
if (interopResult != WlanApi.ERROR_SUCCESS)
{
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nFailed to remove Wireless Profile '{removeName}' from '{adapter?.NetConnectionID ?? profile.InterfaceGuid.ToString()}'; WlanDeleteProfile returned: {interopResult}", true, -1, 3000);
}
profileRemoved = true;
}
}
}
if (profileRemoved)
{
existingProfiles = GetWirelessProfiles(wlanHandle);
}
}
// Add Profiles
if (ProfileStore.Profiles != null && ProfileStore.Profiles.Count > 0)
{
foreach (var addProfile in ProfileStore.Profiles)
{
foreach (var adapter in adapters)
{
var existingProfile = existingProfiles.FirstOrDefault(p => p.Name == addProfile.Name && p.InterfaceGuid == adapter.ConnectionIdentifier);
if (addProfile.ForceDeployment.Value ||
existingProfile == null)
{
if (existingProfile != null && existingProfile.IsGroupPolicy.Value)
{
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nSkipped Wireless Profile '{addProfile.Name}' on '{adapter.NetConnectionID}' as this profile is managed by Group Policy", true, -1, 3000);
}
else
{
uint pdwReasonCode;
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nAdding Wireless Profile '{addProfile.Name}' on '{adapter.NetConnectionID}'", true, -1, 1000);
interopResult = WlanApi.WlanSetProfile(wlanHandle, adapter.ConnectionIdentifier, 0, addProfile.ProfileXml, null, true, IntPtr.Zero, out pdwReasonCode);
if (interopResult != WlanApi.ERROR_SUCCESS)
{
// Get Reason Code
var reason = new StringBuilder(256);
WlanApi.WlanReasonCodeToString(pdwReasonCode, (uint)reason.Capacity, ref reason, IntPtr.Zero);
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nFailed to add Wireless Profile '{addProfile.Name}' on '{adapter.NetConnectionID}'; WlanSetProfile returned: {interopResult}; {reason.ToString()}", true, -1, 3000);
}
}
addedProfiles.Add(addProfile.Name);
}
}
}
}
// Transform Profiles
if (ProfileStore.Transformations != null && ProfileStore.Transformations.Count > 0)
{
foreach (var transformGroup in ProfileStore.Transformations.GroupBy(t => t.Name))
{
var profileName = transformGroup.Key;
// Don't transform if just added
if (!addedProfiles.Contains(transformGroup.Key))
{
foreach (var adapter in adapters)
{
var existingProfile = existingProfiles.FirstOrDefault(p => p.Name == profileName && p.InterfaceGuid == adapter.ConnectionIdentifier);
if (existingProfile != null)
{
if (existingProfile.IsGroupPolicy.Value)
{
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nSkipped Wireless Profile '{profileName}' on '{adapter.NetConnectionID}' as this profile is managed by Group Policy", true, -1, 3000);
}
else
{
// Load profile
IntPtr pstrProfileXml;
uint pdwFlags;
IntPtr pdwGrantAccess;
interopResult = WlanApi.WlanGetProfile(wlanHandle, adapter.ConnectionIdentifier, profileName, IntPtr.Zero, out pstrProfileXml, out pdwFlags, out pdwGrantAccess);
if (interopResult == WlanApi.ERROR_SUCCESS)
{
try
{
var profileXml = Marshal.PtrToStringUni(pstrProfileXml);
var originalProfileXml = XElement.Parse(profileXml);
var transformProfileXml = originalProfileXml.ToString(SaveOptions.DisableFormatting);
// Apply Transforms
foreach (var transform in transformGroup)
{
var regex = new Regex(transform.RegularExpression, RegexOptions.Singleline);
transformProfileXml = regex.Replace(transformProfileXml, transform.RegularExpressionReplacement);
}
// Compare XML
var transformedProfileXml = XElement.Parse(transformProfileXml);
if (!XNode.DeepEquals(originalProfileXml, transformedProfileXml))
{
// Set Profile
uint pdwReasonCode;
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nModifying Wireless Profile '{profileName}' on '{adapter.NetConnectionID}'", true, -1, 1000);
transformProfileXml = transformedProfileXml.ToString(SaveOptions.None);
interopResult = WlanApi.WlanSetProfile(wlanHandle, adapter.ConnectionIdentifier, 0, transformProfileXml, null, true, IntPtr.Zero, out pdwReasonCode);
if (interopResult != WlanApi.ERROR_SUCCESS)
{
// Get Reason Code
var reason = new StringBuilder(256);
WlanApi.WlanReasonCodeToString(pdwReasonCode, (uint)reason.Capacity, ref reason, IntPtr.Zero);
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nFailed to modify Wireless Profile '{profileName}' to '{adapter.NetConnectionID}'; WlanSetProfile returned: {interopResult}; {reason.ToString()}", true, -1, 3000);
}
}
}
finally
{
WlanApi.WlanFreeMemory(pstrProfileXml);
}
}
else
{
Presentation.UpdateStatus("Enrolling Device", $"Configuring Wireless Profiles\r\nFailed to transform Wireless Profile '{profileName}' on '{adapter.NetConnectionID}'; WlanGetProfile returned: {interopResult}", true, -1, 3000);
}
}
}
}
}
}
}
}
finally
{
WlanApi.WlanCloseHandle(wlanHandle, IntPtr.Zero);
}
}
catch (DllNotFoundException)
{
// Indicates 'Wlanapi.dll' isn't present (ie. Servers)
// Ignore policies
}
catch (Exception ex)
{
throw new Exception("Disco Client was unable to apply Wireless Profile Changes using WlanApi", ex);
}
}
public static string Description(this WLAN_INTERFACE_STATE State)
{
switch (State)
{
case WLAN_INTERFACE_STATE.wlan_interface_state_not_ready:
return "Not Ready";
case WLAN_INTERFACE_STATE.wlan_interface_state_connected:
return "Connected";
case WLAN_INTERFACE_STATE.wlan_interface_state_ad_hoc_network_formed:
return "Ad Hoc Network";
case WLAN_INTERFACE_STATE.wlan_interface_state_disconnecting:
return "Disconnecting";
case WLAN_INTERFACE_STATE.wlan_interface_state_disconnected:
return "Disconnected";
case WLAN_INTERFACE_STATE.wlan_interface_state_associating:
return "Associating";
case WLAN_INTERFACE_STATE.wlan_interface_state_discovering:
return "Discovering";
case WLAN_INTERFACE_STATE.wlan_interface_state_authenticating:
return "Authenticating";
default:
return "Unknown";
}
}
}
}
+4 -3
View File
@@ -5,6 +5,7 @@ using System.Reflection;
using System.Text;
using System.Threading;
using Disco.Client.Extensions;
using Disco.Client.Interop;
namespace Disco.Client
{
@@ -38,8 +39,8 @@ namespace Disco.Client
public static void WriteBanner()
{
StringBuilder message = new StringBuilder();
message.Append("Version: ").AppendLine(Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
message.Append("Device: ").Append(Interop.SystemAudit.DeviceSerialNumber).Append(" (").Append(Interop.SystemAudit.DeviceManufacturer).Append(" ").Append(Interop.SystemAudit.DeviceModel).AppendLine(")");
message.AppendLine($"Version: {Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}");
message.AppendLine($"Device: {Hardware.Information.SerialNumber} ({Hardware.Information.Manufacturer} {Hardware.Information.Model})");
Console.ForegroundColor = ConsoleColor.Yellow;
UpdateStatus("Preparation Client Started", message.ToString(), false, 0);
Console.ForegroundColor = ConsoleColor.White;
@@ -52,7 +53,7 @@ namespace Disco.Client
ClientServiceException clientServiceException = ex as ClientServiceException;
if (clientServiceException != null)
{
UpdateStatus(string.Format("An error occurred during {0}", clientServiceException.ServiceFeature),
UpdateStatus($"An error occurred during {clientServiceException.ServiceFeature}",
clientServiceException.Message, false, 0);
}
else
+12 -1
View File
@@ -20,6 +20,17 @@ namespace Disco.Client
{
bool keepProcessing;
#if DEBUG
if (args != null && args.Any(a => a.Equals("debug", StringComparison.OrdinalIgnoreCase)))
{
do
{
Console.WriteLine("Waiting for Debugger to Attach");
System.Threading.Thread.Sleep(1000);
} while (!System.Diagnostics.Debugger.IsAttached);
}
#endif
// Initialize Environment Settings
SetupEnvironment();
@@ -44,7 +55,7 @@ namespace Disco.Client
// Ignore Local Proxies
WebRequest.DefaultWebProxy = new WebProxy();
// Override Http 100 Continue Behavour
// Override Http 100 Continue Behaviour
ServicePointManager.Expect100Continue = false;
// Assume success unless otherwise notified
+5 -6
View File
@@ -1,15 +1,14 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Disco - Client")]
[assembly: AssemblyTitle("Disco ICT - Client")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Disco")]
[assembly: AssemblyCompany("https://discoict.com.au")]
[assembly: AssemblyProduct("Disco ICT")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[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
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.2.0725.2102")]
[assembly: AssemblyFileVersion("1.2.0725.2102")]
[assembly: AssemblyVersion("2.2.16326.0500")]
[assembly: AssemblyFileVersion("2.2.16326.0500")]
+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="5.0.5" targetFramework="net40-Client" />
<package id="Newtonsoft.Json" version="13.0.2" targetFramework="net40-client" />
</packages>
+20 -12
View File
@@ -1,6 +1,4 @@
//#define Debug
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -22,6 +20,14 @@ namespace Disco.ClientBootstrapper
private StringBuilder errorMessage;
private Process clientProcess;
//#if DEBUG
// public const string DiscoServerName = "WS-GSHARP";
// public const int DiscoServerPort = 57252;
//#else
public const string DiscoServerName = "DISCO";
public const int DiscoServerPort = 9292;
//#endif
public BootstrapperLoop(IStatus StatusUI, LoopCompleteCallback Callback)
{
this.statusUI = StatusUI;
@@ -79,12 +85,12 @@ namespace Disco.ClientBootstrapper
// Check for Network Connectivity
statusUI.UpdateStatus(null, "Detecting Network", "Checking network connectivity, Please wait...", true, -1);
if (!Interop.NetworkInterop.PingDisco())
if (!Interop.NetworkInterop.PingDisco(DiscoServerName))
{
statusUI.UpdateStatus(null, "Detecting Network", "No network connectivity detected, Diagnosing...", true, -1);
statusUI_WriteAdapterInfo();
if (!Interop.NetworkInterop.PingDisco())
if (!Interop.NetworkInterop.PingDisco(DiscoServerName))
{
// Check for Wireless
var hasWireless = (Interop.NetworkInterop.NetworkAdapters.Count(na => na.IsWireless) > 0);
@@ -99,17 +105,17 @@ namespace Disco.ClientBootstrapper
statusUI_WriteAdapterInfo();
statusUI.UpdateStatus(null, null, null, true, i);
Program.SleepThread(500, false);
if (Interop.NetworkInterop.PingDisco())
if (Interop.NetworkInterop.PingDisco(DiscoServerName))
break;
}
if (!Interop.NetworkInterop.PingDisco())
if (!Interop.NetworkInterop.PingDisco(DiscoServerName))
{
statusUI.UpdateStatus(null, "Wireless Network Failed", "Unable to connect to the wireless network, please connect the network cable...", false);
Program.SleepThread(3000, false);
}
}
if (!Interop.NetworkInterop.PingDisco())
if (!Interop.NetworkInterop.PingDisco(DiscoServerName))
{
// Instruct user to connect network cable
statusUI.UpdateStatus(null, "Please connect the network cable", null);
@@ -118,13 +124,13 @@ namespace Disco.ClientBootstrapper
statusUI_WriteAdapterInfo();
statusUI.UpdateStatus(null, null, null, true, i);
Program.SleepThread(500, false);
if (Interop.NetworkInterop.PingDisco())
if (Interop.NetworkInterop.PingDisco(DiscoServerName))
break;
}
}
}
if (!Interop.NetworkInterop.PingDisco())
if (!Interop.NetworkInterop.PingDisco(DiscoServerName))
{
// Client Failed
if (this.mLoopCompleteCallback != null)
@@ -143,13 +149,15 @@ namespace Disco.ClientBootstrapper
// Don't use a proxy when downloading the Client
webClient.Proxy = new WebProxy();
webClient.DownloadFile("http://disco:9292/Services/Client/PreparationClient", clientSourceLocation);
webClient.DownloadFile($"http://{DiscoServerName}:{DiscoServerPort}/Services/Client/PreparationClient", clientSourceLocation);
}
// Unzip Client
statusUI.UpdateStatus(null, "Extracting", "Retrieving Preparation Client, Please wait...", true, -1);
string clientLocation = Path.Combine(tempWorkingDirectory, "PreparationClient");
if (!Directory.Exists(clientLocation))
if (Directory.Exists(clientLocation))
Directory.Delete(clientLocation, true);
Directory.CreateDirectory(clientLocation);
using (var clientSource = Ionic.Zip.ZipFile.Read(clientSourceLocation))
{

Some files were not shown because too many files have changed in this diff Show More