Compare commits

...

488 Commits

Author SHA1 Message Date
Shannon Deminick a0651f4383 Merge with 4.11.6 2013-03-27 03:09:36 +06:00
Shannon Deminick 9452d5fd09 adds patch for #U4-1754 and updates 2013-03-27 03:08:37 +06:00
Shannon Deminick 1f40d726de adds patch for #U4-1754 2013-03-27 02:59:42 +06:00
Shannon Deminick 2699611ba3 adds patch for #U4-1754 2013-03-27 02:58:59 +06:00
Shannon Deminick 43795f0007 Merge with 4.11.6 2013-03-26 22:03:23 +06:00
Shannon Deminick b1fa06bfe8 Removes unused code. 2013-03-26 22:02:49 +06:00
Shannon Deminick 4dc22b6ce4 Applies patch for #U4-497 for getting exceptions for xslt 2013-03-26 22:02:08 +06:00
Sebastiaan Janssen d4ab60f8af Merge with 4.11.6 2013-03-26 13:29:45 -01:00
Sebastiaan Janssen 883277125a Can't use parameters here as the query gets butchered. 2013-03-26 13:27:46 -01:00
Sebastiaan Janssen 8edfc0ffdd Merge with 4.11.6 2013-03-26 09:53:59 -01:00
Sebastiaan Janssen ff961abaab Actual fix for U4-1987 Error when attempting to save document type 2013-03-26 09:50:48 -01:00
Sebastiaan Janssen b2414c1ab8 Fixes U4-1987 Error when attempting to save document type 2013-03-26 09:33:08 -01:00
Sebastiaan Janssen 9dde86d591 Fixes U4-1999 When copying content with subcontent, the new subcontent data is a
direct reference to the old.
2013-03-26 08:39:50 -01:00
Sebastiaan Janssen b4ce4fbdef Logging warning when package installer can't create a property due to a missing
datatype for that property
2013-03-26 07:55:43 -01:00
Sebastiaan Janssen 4285484c1b Update code comment 2013-03-26 07:19:39 -01:00
Sebastiaan Janssen 2fd299ebfc Change TinyMCE to use the mediaservice to get the original image + some updates
to the new mediaservice method.
2013-03-26 07:15:22 -01:00
Morten Christensen f545f293b1 Adding GetMediaByUrl method to MediaService cause Sebastiaan needs it for less hacky code. 2013-03-26 05:46:20 -01:00
Sebastiaan Janssen b745c0ae90 If the image is not resized, there's probably not going to be an underscore,
just query for the whole image source then.
2013-03-25 18:18:14 -01:00
Sebastiaan Janssen f2efff5411 Temporary fix until we can fix this properly for U4-1812 - Changing Width or
Height in Insert Picture popup results in NaN in other dimension
2013-03-25 18:09:31 -01:00
Sebastiaan Janssen 9ef5890636 Changing sortorder on tabs now also re-orders the tabs in the contenttype editor 2013-03-25 13:33:32 -01:00
Sebastiaan Janssen bc9fd04a36 Related to U4-1847 - Tabs weren't imported with the correct sort order and when
a datatype can't be found we should silently fail and not create the property
that wants that datatype (that's how v4 did it).
2013-03-25 12:49:43 -01:00
Sebastiaan Janssen 185c5d78f1 Query changed due to fix fe02cef72d87 that uses 1/0 instead of True/False 2013-03-25 11:27:54 -01:00
Brian Powell 3ea9963166 Fixes U4-1904 / U4-1905 2013-03-25 10:39:35 -01:00
Sebastiaan Janssen ab40822a98 Fix merge issue by re-applying Stephen Roberts' patch 2013-03-25 10:30:55 -01:00
Sebastiaan Janssen dffce76e29 Merge with 4.11.6 2013-03-25 10:24:36 -01:00
Sebastiaan Janssen d1e02f506c PropertyGroupId can be null 2013-03-25 07:51:44 -01:00
Morten Christensen 5e18d13178 Fixing parsing issue with saving boolean values in the Integer column for Members.
Related to issue U4-1989
2013-03-23 07:22:43 -01:00
Shannon Deminick 1dfca6836d Merge with 4.11.6 2013-03-23 02:34:59 +06:00
Shannon Deminick dbbdd16bb9 Fixes: #U4-497 2013-03-23 02:34:34 +06:00
Shannon Deminick 74362fba23 Merge 2013-03-22 22:11:26 +06:00
Morten Christensen 112502cf18 Fixes U4-547 2013-03-22 15:09:36 -01:00
Shannon Deminick 1db7f808c9 Merge with 4.11.6 2013-03-22 21:59:52 +06:00
Shannon Deminick 762cca145f Fixes: #U4-1931 - allow empty string in dictionary item. 2013-03-22 21:59:21 +06:00
Morten Christensen 65dc5eaeee Corrects incorrect sql query in the ContentTypeBaseRepository and looping through property types in the DataTypeService.
Adds initial test fixture for the DataTypeService.
Fixes U4-1939
2013-03-22 14:54:44 -01:00
Morten Christensen 4f81e06d3d Fixes U4-1894 by ensuring that all overloads of SetValue uses the IOHelper.SafeFileName 2013-03-22 14:18:45 -01:00
Morten Christensen 6b74b75b6f Adding a few checks to ensure that we don't try to bulk save an empty list 2013-03-22 14:08:20 -01:00
Morten Christensen 98e53b3d74 Correcting a few checks for multiple or single item imports in the PackagingService 2013-03-22 13:58:21 -01:00
Morten Christensen a1f01f9d5c re-inverting the check for existing datatypedefinitions in the packaging service 2013-03-22 13:48:51 -01:00
Sebastiaan Janssen f5d8cb0275 Merge 2013-03-22 13:36:26 -01:00
Sebastiaan Janssen 0d8b65caea Merge 2013-03-22 13:36:04 -01:00
Sebastiaan Janssen 70285991bb I think this was an oversight, if a definition is NOT null, then fill it 2013-03-22 13:35:47 -01:00
Sebastiaan Janssen a336eaa4a1 Check all of the elements for null, apparently any kind of installable thing can
be missing from the install xml file
2013-03-22 13:35:19 -01:00
Morten Christensen fdefe993b7 Fixes U4-1990 2013-03-22 12:54:46 -01:00
Morten Christensen ba0e72a1c1 Fixes U4-1937 by calling save when media is updated with new properties. Also uses the incremented folder count instead of the property id. 2013-03-22 12:30:20 -01:00
Morten Christensen c5710277a5 Redoing the fix for U4-1875 2013-03-22 12:13:06 -01:00
Morten Christensen 5cd2d568e3 Fixes U4-1938 by actually calling and checking the Before/AfterDelete events for DataTypeDefinitions.
Backported from 32fb51f603a3
2013-03-22 11:12:32 -01:00
Morten Christensen 9c89a56d8d Fixes U4-1938 by actually calling and checking the Before/AfterDelete events for DataTypeDefinitions. 2013-03-22 10:53:07 -01:00
Morten Christensen 9ba7664f78 Updating repositories to handle sort order upon updating in a consistent manner.
Related to U4-1828
2013-03-22 10:34:05 -01:00
Morten Christensen 4b87a5c2d3 Adding safe alias cast to Templates.
Updating doc type create dialog to verify alias before saving.
Updating ContentTypeRepository to Mandate that the alias is not empty.
Fixes the cause for U4-1976
2013-03-22 09:56:21 -01:00
Morten Christensen f0699afb6e Fixes U4-1974 2013-03-21 18:45:06 -01:00
Morten Christensen b4d5658d45 Fixes U4-1828 by correctly incrementing the sortorder ... doh! 2013-03-21 17:34:08 -01:00
Morten Christensen d485c3da97 Fixes U4-1875 by correcting the Creating events in the ContentService and MediaService, so null is returned if the creation of an object is cancelled.
In the legacy Document and Media classes we check if the created object is null to determine if the event has been cancelled through the new api.
2013-03-21 16:09:45 -01:00
Morten Christensen 1214082997 Fixes U4-1883 by setting the Document/Media UpdateDate property in the Save/SaveAndPublish methods 2013-03-21 14:56:50 -01:00
Morten Christensen 1a56e6693a Removing dictionary from DataTypeDefinition as it wasn't used.
Updating package xml to include DatabaseType for testing.
2013-03-21 14:50:39 -01:00
Morten Christensen c6b7f20dab Fixes U4-1849 by introducing a new attribute for packaged DataTypes, so it stores information about the database type.
Will still default to Ntext, but seeing as the database type has never been used before it always defaulted to Ntext.
2013-03-21 14:40:17 -01:00
Morten Christensen 5cc55ad6e2 Fixing U4-1948 by setting the Published property when using document.Publish so updating the cache won't be skipped. 2013-03-21 13:51:45 -01:00
Morten Christensen a55fedab0a Adding a few checks to ensure package installation doesn't fail when properties are not present in the xml. 2013-03-21 13:40:54 -01:00
Morten Christensen 0e12f14a4a Making the export method internal until its been properly implemented 2013-03-21 13:10:31 -01:00
Morten Christensen 3e25b71d9e Updating test for adding PropertyType outside a group to use the proper method for doing so. 2013-03-21 12:58:55 -01:00
Morten Christensen 63de9e6691 Refactoring package installer to use the new PackagingService.
Refactoring ImportDocumentType dialog to import through the PackagingService.
Making a few corrections to the ProppertyGroup and PropertyType classes to support bulk saving.
2013-03-21 12:34:10 -01:00
Morten Christensen b9ea85d29d Updating Template to have a lazy master template id.
Adding a few new methods to the DataTypeService, which were needed for the import of DataTypes.
Adding bulk saving of templates.
Adding TopologicalSorter for sorting dependencies.
Implementing import of DataTypes and Templates.
Renaming the import test fixture for consistency after having creating the PackagingService.
2013-03-20 20:31:44 -01:00
Morten Christensen d0787e92fe Implementing PackagingService and moving Import Export methods to this service to have it specialized and centralized around packaging operations. 2013-03-20 13:51:46 -01:00
Morten Christensen ffe9953c43 Merge 2013-03-19 20:08:40 -01:00
Morten Christensen 99a9f1ab87 Adding note to mediaService regarding issue U4-1937 2013-03-19 20:06:33 -01:00
Morten Christensen 7def26a489 Implementing import methods in the Content- and ContentType services.
Adding tests to verify import is correct.
2013-03-19 20:05:55 -01:00
Shannon Deminick a76ffe8daf Backported changes from 6.1 to fix how RePublishAll behaves in the content service to ensure its the same as what was done with
Document.RePublishAll
2013-03-20 00:19:36 +06:00
Sebastiaan Janssen 259fbcb8f0 Fixed U4-1934 Error in comments of config files 2013-03-18 08:50:24 -01:00
Shannon Deminick ee9f91b5cf Merge with 4.11.6 2013-03-15 11:31:34 +06:00
Shannon Deminick db3f21429e Fixes infinite loop bug with string trimming. 2013-03-15 11:31:11 +06:00
Shannon Deminick 033692d7ee had some strange issues with unit tests, added error checks. 2013-03-15 08:26:49 +04:00
Shannon Deminick 23146cb12a Merge with 4.11.6 2013-03-15 08:06:26 +04:00
Shannon Deminick 04b9607741 Fixes: #U4-1916 and another issue for vdirs, added unit tests, changed UI web project to always
launch in a VDIR.
2013-03-15 08:03:19 +04:00
Stephen Roberts 0e392b398c Fixed Property order for document types with Master document types. 2013-03-14 11:08:02 +00:00
Sebastiaan Janssen 5914690ad8 Allow leading sign in number field so that negative numbers are supported 2013-03-25 10:09:02 -01:00
Morten Christensen c4aa9095f2 Fixes U4-1858 by ensuring that the text field is reset before setting or removing a value 2013-03-13 20:24:21 -01:00
Morten Christensen 79ce586c8b Fixes U4-1808 by removing the database lookup from an id that was resolved from the media url 2013-03-13 19:26:22 -01:00
Morten Christensen 8fba03c05d Fixes U4-1863 and U4-1908 by ensuring that content and media are loaded in the same manner through the new api 2013-03-13 18:55:25 -01:00
Shannon Deminick 2fdcb9164a Fix merge issues 2013-03-12 00:19:06 +04:00
Shannon Deminick 7404a1f93d Merge with 4.11.6 2013-03-12 00:14:50 +04:00
Shannon Deminick c8b8b28e9b applies patch for #U4-1890 2013-03-12 00:10:59 +04:00
Shannon Deminick 5bd2571395 Merge 2013-03-12 00:01:14 +04:00
Shannon Deminick c0cd157e60 applies patch for #U4-1890 2013-03-12 00:00:55 +04:00
Sebastiaan Janssen ac2f9b172c .transformed files are auto-generated and shouldn't be under source control 2013-03-11 17:15:30 -01:00
Sebastiaan Janssen b8e4a73c3b Revert Casey's mistakenly added files 2013-03-11 15:55:35 -01:00
Shannon Deminick 63192f3a65 Merge 2013-03-11 22:04:06 +06:00
Shannon Deminick 727f62d418 Merge with 4.11.6 2013-03-11 21:49:27 +06:00
Shannon Deminick 68c4255a51 updates proper error handling for razor script macros 2013-03-11 21:49:04 +06:00
Shannon Deminick 187af3e361 Fixed merge issue 2013-03-11 21:23:35 +06:00
Shannon Deminick c6f29a50d6 Merge with 4.11.6 2013-03-11 21:17:57 +06:00
Shannon Deminick d07212c89b Fixed changes with new MacroErrors config and how macros are rendered so it supports all macro types and also fixes up a bit of code
in the umbraco.macro class.
2013-03-11 21:06:02 +06:00
Shannon Deminick 28c55320a1 Updates the pull request for handling macro errors.
Backports fixes for partial view macros from 6.x - U4-1488, U4-1844, U4-1730, U4-1843
2013-03-11 20:11:11 +06:00
Morten Christensen cb0dd70434 Minor change to the SqlSyntaxProvidersResolver in the CoreBootManager as per Shannons review. 2013-03-11 12:44:12 -01:00
Shannon Deminick fd58017e97 imported patches for pull request spudstuff/u4497 2013-03-11 18:49:45 +06:00
Morten Christensen 928d92fce4 Making the Sql Syntax Providers public and changing a few names and bits for consistency.
Adding resolver for the syntax providers and wiring it up in the boot manager.
2013-03-09 10:43:34 -01:00
Casey Neehouse 09408b898e Merge 2013-03-08 19:38:33 +05:00
Morten Christensen d1b05332c5 Manually adds fix for U4-1869 from 6.0.3 branch 2013-03-07 20:28:13 -01:00
Morten Christensen 836b0f39c2 Additional correction of the implementation for U4-1869 2013-03-07 20:19:39 -01:00
Morten Christensen 1b01386673 Changing the initial fix of U4-1869 to use UrlReplacingCharacters 2013-03-07 19:56:59 -01:00
Morten Christensen 2a09f02afb Fixing incorrect sql syntax when the query contains two expressions. 2013-03-07 19:56:10 -01:00
Morten Christensen ee95434cea Implements U4-1869 by adding the 3 characters to the list of reserved characters. 2013-03-07 19:04:25 -01:00
Casey Neehouse caad0afed8 Corrects u4-1870 - Refactor Load Content SQL to check if ID is in published list
versus using a join that can cause duplicate entries.
2013-03-07 21:00:31 +05:00
Morten Christensen fe08e7fc2f Fixes U4-1865 by excluding trashed items from GetByLevel method for both Content and Media 2013-03-07 13:42:14 -01:00
Morten Christensen 4ad96b49e7 Fixes U4-1862 2013-03-07 13:35:17 -01:00
Morten Christensen 9a1bb4a2dd Adding unit test to assert issue with issue with creation of property types outside a property type group.
Fixes U4-1861.
2013-03-07 13:33:22 -01:00
Sebastiaan Janssen c39f902ed5 And one more fix for U4-1845 to make upgrades succeed as well 2013-03-06 14:30:09 -01:00
Sebastiaan Janssen b7dc052cb2 Additional fixes for U4-1845 to maintain compatibility for people using the
wrong connection string
2013-03-06 14:09:01 -01:00
Morten Christensen 0c77114cd5 Fixes U4-1845 by correcting the sql ce connectionstring 2013-03-06 13:36:03 -01:00
Morten Christensen 222a5237b0 Version updated to 6.0.3 2013-03-06 12:03:01 -01:00
Morten Christensen de55cb8392 Correcting fix for U4-1835 2013-03-06 08:32:05 -01:00
Morten Christensen df164ee618 Fixes U4-1835 by checking if the value is null before running the regex validation against the value. 2013-03-06 08:02:09 -01:00
Morten Christensen 21b0687a57 Fixes U4-1837 by syncing tree after saveing DataTypeDefinition 2013-03-06 07:57:00 -01:00
Morten Christensen 9310efa280 Fixes U4-1831 by catching exception if there is no current logged in user. 2013-03-06 07:54:09 -01:00
Morten Christensen a41b55a9e6 Fixes U4-1846 2013-03-06 07:50:20 -01:00
Morten Christensen af2d8a4755 Fix related to U4-1407 but for Media. We already committed this fix for Content. 2013-03-06 07:49:29 -01:00
Shannon Deminick d48e339b81 Fixes: #U4-1844, #U4-1730, #U4-1843 2013-03-06 04:12:28 +06:00
Shannon Deminick 9b6d498cf7 Merge with 4.11.6 2013-03-06 03:17:47 +06:00
Shannon Deminick 62d365573f Back ports fixes for: #U4-1614, #U4-793 - preview working properly in mvc 2013-03-06 03:17:18 +06:00
Shannon Deminick 04bf011fcd Merge with 4.11.6 2013-03-05 23:55:09 +06:00
Shannon Deminick f3b7a8a581 Fixes: #U4-1471 - issue with having NewRelic installed and some sort of conflict with shutting down
our logger.
2013-03-05 23:49:45 +06:00
Shannon Deminick 5d62902684 Fixes up the double event for MakeNew on document (#U4-1737) 2013-03-05 22:34:31 +06:00
Shannon Deminick 82d645a0f7 Merge with 4.11.6 2013-03-05 22:18:53 +06:00
Shannon Deminick a8936de638 Fixes: #U4-1834 2013-03-05 21:52:22 +06:00
Shannon Deminick a765f36d24 Adds unit tests for DynamicNode and DynamicPublishedContent, fixes both when querying for recursive properties.
Fixes: #U4-1839
2013-03-05 21:00:16 +06:00
Shannon Deminick 6b691eb461 Merge with 4.11.6 2013-03-05 08:34:14 +06:00
Shannon Deminick 046da1a8ce Fixes: #U4-1824 - issue with razor dynamic node property access performance enhancements. 2013-03-05 07:06:41 +06:00
Shannon Deminick ca7abd6c78 Merge 2013-03-05 06:08:59 +06:00
Shannon Deminick 452688b2bb Merge with 4.11.6 2013-03-05 05:57:35 +06:00
Shannon Deminick 7cc0f2a514 Fixes: #U4-1819 2013-03-05 05:56:53 +06:00
Sebastiaan Janssen a2251fe062 Created branch 6.0.3 2013-03-04 10:19:22 -01:00
Sebastiaan Janssen 3d0684eac0 Closing branch 6.0.2 2013-03-04 10:18:18 -01:00
Sebastiaan Janssen a8fafaa194 Added tag Release-6.0.2 for changeset b247b35d8211 2013-03-04 10:18:08 -01:00
Morten Christensen 2b8a6e532e Fixing U4-1820 2013-03-03 11:25:48 -01:00
Morten Christensen d497659f1f Fixes U4-1814 for Document and Media by adding both legacy Before/After Move events 2013-03-03 11:19:15 -01:00
Morten Christensen 0cafeac6eb Fixes U4-1818 2013-03-03 11:11:51 -01:00
Morten Christensen 4516305f3c Fixes U4-1816 2013-03-03 10:34:39 -01:00
Morten Christensen 04c8390a4f Fixes sorting of ContentTypes and Content related to U4-1816.
Updating upgrade code for PropertyTypes / PropertyTypeGroups.
2013-03-02 08:11:47 -01:00
Hendy fc94d92b37 Merge 2013-03-01 23:26:00 +00:00
Hendy 84171c6b98 Added Media and Member support to XPath CheckBoxList 2013-03-01 22:53:14 +00:00
Shannon Deminick 3ff88bc4fa Fixing strange merge issues. 2013-03-02 03:44:43 +06:00
Shannon Deminick 4b54edf660 Merge 2013-03-02 02:51:05 +06:00
Shannon Deminick 1bc9d1d9c3 Merge with 4.11.6 2013-03-02 02:45:19 +06:00
Shannon Deminick b5cbe63a4e Back merged from 6.1 the changes required for #U4-1822 and #U4-1797 2013-03-02 02:43:22 +06:00
Shannon Deminick 4882df43bd Back merged from 6.1 the changes required for #U4-1822 and #U4-1797 2013-03-02 01:50:53 +06:00
Morten Christensen cb03178d99 Updating version 2013-03-01 15:39:24 -01:00
Morten Christensen 361fa8836b Merge 2013-03-01 15:37:06 -01:00
Morten Christensen 194ebb57b9 Updating migration 2013-03-01 15:36:53 -01:00
Hendy 5effe5015e Added Media and Member support to XPath DropDownList 2013-03-01 15:28:03 +00:00
Sebastiaan Janssen ee2943b9fb Created branch 4.11.6 2013-03-01 06:56:34 -01:00
Sebastiaan Janssen a3b03988b3 Created branch 6.0.2 2013-03-01 06:55:54 -01:00
Sebastiaan Janssen 6d5f7c4293 Checking the filepath correctly this time 2013-02-28 16:23:43 -01:00
Morten Christensen cc32e73235 Merge 2013-02-28 16:00:49 -01:00
Morten Christensen 92ef4d8055 Adds migration execute method for code, so it'll run in the process method of the migration runner. 2013-02-28 16:00:35 -01:00
Sebastiaan Janssen e57e2f5b5f Migrations should be sorted by version number as well 2013-02-28 15:38:07 -01:00
Sebastiaan Janssen 0b4efe4eeb Merge with 4.11.5 2013-02-28 15:10:31 -01:00
Sebastiaan Janssen c250fa560e Restrict the NuGet .Core dependency to the same version. 2013-02-28 15:08:30 -01:00
Morten Christensen 6eeae52333 Adding the actually migration class 2013-02-28 15:01:50 -01:00
Morten Christensen c38c18fed8 Adding migration for updating PropertyGroups and PropertyTypes 2013-02-28 14:54:42 -01:00
Sebastiaan Janssen 0af47963c6 Merge 2013-02-28 09:56:19 -01:00
Sebastiaan Janssen b017e8690a Fix errors in log caused by no prevalues beind selected. 2013-02-28 09:53:57 -01:00
Sebastiaan Janssen 916e442ee4 Fix errors in log caused by no prevalues beind selected. 2013-02-28 09:53:57 -01:00
Morten Christensen ecae9c47b7 Fixes U4-1798 by adding the current user's id when saving Media, MediaTypes and DocumentTypes. 2013-02-28 09:37:33 -01:00
Morten Christensen 836a99128f Fixes moving PropertyTypes between Tabs/PropertyGroups from inherited doc types.
Adds method to move a PropertyType to another PropertyGroup.
2013-02-28 09:07:15 -01:00
Morten Christensen abefbc7581 Merge 2013-02-27 17:02:10 -01:00
Morten Christensen 365addedf4 Fixes deleting tabs and having the property types move to Generic Properties 2013-02-27 17:01:53 -01:00
Shannon Deminick 44f5439a2c Merge with 4.11.5 2013-02-27 23:14:50 +06:00
Shannon Deminick 8a9680e75c updated unit test logic 2013-02-27 23:13:48 +06:00
Shannon Deminick ae0991bc67 Fixed unit tests now that we have default values stored in GlobalSettings. 2013-02-27 23:02:12 +06:00
Shannon Deminick 0caaaa500c Merge with 4.11.5 2013-02-27 22:38:46 +06:00
Shannon Deminick 36c66e676a Fixed unit tests 2013-02-27 22:35:27 +06:00
Sebastiaan Janssen a14baeb111 Merge 2013-02-27 14:58:47 -01:00
Sebastiaan Janssen 5b4d8ed6f3 U4-1793 YSOD when moving a node back to root 2013-02-27 14:57:42 -01:00
Morten Christensen 25ea4003f9 Merge 2013-02-27 14:42:43 -01:00
Morten Christensen 30cef671dc Removing unused code 2013-02-27 14:42:17 -01:00
Morten Christensen 250e627b1d Fixes saving of RegEx in DocTypes.
Fixes loading and saving of properties on inherited tabs.
Adjusts logic around the creation of tabs/property groups
2013-02-27 14:39:11 -01:00
Sebastiaan Janssen 5b00501d21 trySkipIisCustomErrors was defined twice in the Release config 2013-02-27 14:38:15 -01:00
Shannon Deminick 06e5350c43 Fixes: #U4-1790 - Examine indexing non-published items for indexers that are not supporting non-published items. 2013-02-27 21:35:36 +06:00
Sebastiaan Janssen ba530061a0 Merge 2013-02-27 13:53:14 -01:00
Sebastiaan Janssen 89ae3bc143 Add RevertToCleanInstall.bat to 4.11.5 too, it's handy. 2013-02-27 13:51:58 -01:00
Shannon Deminick 484afccf89 Merge with 4.11.5 2013-02-27 20:46:29 +06:00
Shannon Deminick 3951f59d09 Merge 2013-02-27 20:46:06 +06:00
Shannon Deminick 2589ec8367 Merge 2013-02-27 20:45:25 +06:00
Shannon Deminick a6aeada197 Merge with 4.11.5 2013-02-27 20:44:56 +06:00
Shannon Deminick cd8c998ebf Fixes: U4-1788 - ensures internal reserved paths and urls (that cannot be modified) are stored staticly in code,
Also fixes that the _reservedPathsCache and _reservedUrlsCache actually works, before we were doing an
object.ReferenceEquals comparison which would never have worked and it was also not thread safe.
2013-02-27 20:42:11 +06:00
Shannon Deminick 2a9e32e8fd Fixes: U4-1788 - ensures internal reserved paths and urls (that cannot be modified) are stored staticly in code 2013-02-27 20:13:15 +06:00
Sebastiaan Janssen 603724ddd6 Merge 2013-02-27 12:47:21 -01:00
Sebastiaan Janssen 902cfc5a22 Merge with 4.11.5 2013-02-27 12:43:52 -01:00
Sebastiaan Janssen 2cb544591b Pull in new translations 2013-02-27 12:43:21 -01:00
Morten Christensen db7aa99b85 Fixes PerformGetByQuery related to U4-1783. The query does not need to be version specific. 2013-02-27 11:19:53 -01:00
Morten Christensen 031ceccf5d Removing need to load a Property from within FileHandlerData.
This means that newly created properties based on the upload field can be properly saved.
2013-02-27 11:02:27 -01:00
Morten Christensen 7127706c43 Merge 2013-02-27 10:29:26 -01:00
Morten Christensen d078ef8f5e Minor adjustment to property tracking 2013-02-27 10:28:40 -01:00
Morten Christensen 289b9743c5 Fixes regression issue with installing document types using legacy api. 2013-02-27 10:23:48 -01:00
Sebastiaan Janssen eda9ba07f4 Wrongly doing an append where I meant to just replace the html 2013-02-27 09:53:45 -01:00
Stephan 1b1b5c047c U4-1779 - Web.BaseRest supports rest extensions over multiple classes 2013-02-26 16:52:06 -01:00
Sebastiaan Janssen fa5b9e5689 Typo: U4-512 "Memebertype saved" 2013-02-26 17:29:53 -01:00
Stephan 6948d70b75 U4-1779 - Web.BaseRest supports rest extensions over multiple classes 2013-02-26 16:52:06 -01:00
Sebastiaan Janssen 3f9b022ae4 Merge with 4.11.5 2013-02-26 17:30:50 -01:00
Sebastiaan Janssen 990ab7f87f Merge 2013-02-26 15:52:48 -01:00
Sebastiaan Janssen 861198eec9 Merge with 4.11.5 2013-02-26 15:50:11 -01:00
Sebastiaan Janssen c26df8da6f U4-591 Access bug in dashboard 2013-02-26 15:48:22 -01:00
Morten Christensen b5aefdce04 Merge 2013-02-26 14:53:41 -01:00
Morten Christensen adfb7cfaa4 Fixes U4-1756 by ordering the DocumentTypes prior to deleting them 2013-02-26 14:52:55 -01:00
Morten Christensen 0a88ba05c8 Corrected an issue related to the upload field when a Document without any files uploaded was deleted 2013-02-26 14:52:33 -01:00
Shannon Deminick 9ee295d49e Merge with 4.11.5 2013-02-26 21:35:55 +06:00
Shannon Deminick 1e02d85fca Fixes: #U4-1773 (backport fix from 6.0.1) 2013-02-26 21:35:09 +06:00
Shannon Deminick 7173b44b4f Merge with 4.11.5 2013-02-26 21:18:17 +06:00
Shannon Deminick 69f6edadb3 Merge 2013-02-26 21:17:57 +06:00
Shannon Deminick d1dc2331f8 Merge 2013-02-26 21:15:31 +06:00
Morten Christensen bb2f3a1732 Fixes U4-1784 2013-02-26 14:11:24 -01:00
Shannon Deminick 4b29d7ba2e Merge with 4.11.5 2013-02-26 21:11:20 +06:00
Shannon Deminick d503deb8c5 reverted member index config, for pre 6.1 we will still need to manually set the member fields. 2013-02-26 21:07:59 +06:00
Morten Christensen 0859b92aaf Fixes U4-1781 so Saved is called when saving a DataTypeDefinition in the backoffice 2013-02-26 13:59:08 -01:00
Morten Christensen b409740da5 Merge 2013-02-26 13:35:52 -01:00
Morten Christensen a888e0564c Calling save when creating a DataTypeDefinition related to U4-1781 2013-02-26 13:32:02 -01:00
Morten Christensen fef96e8b43 Fixes issue related to moving PropertyTypes between tabs.
Ensures that the right tabs with the right ids are loaded in the dropdown.
2013-02-26 13:31:29 -01:00
Sebastiaan Janssen 429522a0bc U4-1775 Copying nodes results in same name under sort and in MNTP 2013-02-26 13:08:31 -01:00
Morten Christensen e9b2261aab Fixes the moving of a PropertyType from a named tab to generic properties 2013-02-26 11:30:19 -01:00
Morten Christensen 02adb6e112 Removing the creation of Properties that doesn't exist from within the Content class, as it could cause other issues.
Refactoring how Properties are loaded to ensure that new properties are created for newly added PropertyTypes.
Corrected the saving of PropertyTypes not within a PropertyGroup.
Changed the loading of Content/Document to use the new API to ensure that properties are properly loaded.
2013-02-26 10:57:40 -01:00
Sebastiaan Janssen 695d26434c U4-600 Wrong membersearch.png path in MemberSearch.ascx 2013-02-26 09:48:14 -01:00
Morten Christensen 00d408e6bc Merge 2013-02-26 09:13:34 -01:00
Morten Christensen 0498161367 Fixes U4-1630 by ensuring that PropertyTypes with a changed name or alias aren't deleted from the db upon comparison.
Ensures cache is cleared for updated PropertyTypes.
2013-02-26 09:13:05 -01:00
Shannon Deminick 0d3d4693b4 Merge with 4.11.5 2013-02-26 01:00:44 +06:00
Shannon Deminick a19de645e4 Merge 2013-02-26 00:59:06 +06:00
Shannon Deminick f0a53ea9c0 Merge 2013-02-26 00:58:24 +06:00
Shannon Deminick fbcabc94f2 Merge with 4.11.5 2013-02-26 00:50:58 +06:00
Shannon Deminick de9a27db10 Updates to latest Examine lib (another bug fixed) 2013-02-26 00:45:42 +06:00
Morten Christensen d494b061f3 Merge 2013-02-25 15:00:55 -01:00
Morten Christensen ebc8443e70 Removing unnecessary save from MediaType 2013-02-25 14:58:04 -01:00
Morten Christensen 48ee59b94e Adding check related to U4-1757 2013-02-25 14:57:43 -01:00
Sebastiaan Janssen 560dcad90a Updates for MySQL: Check for case-sensitivity 2013-02-25 14:42:07 -01:00
Morten Christensen 7498b2f994 Merge 2013-02-25 14:37:14 -01:00
Morten Christensen df4f92197a Fixes U4-1764 by reducing the number of times a DocumentType is saved from 3 to 1.
Instead of having the Allowed Templates saved in the EditNodeTypeNew control its now done via a callback.
2013-02-25 14:34:29 -01:00
Sebastiaan Janssen 13b1191aad Additional fixes for U4-1776 SafeAlias culture problem 2013-02-25 13:44:31 -01:00
Sebastiaan Janssen adaec42982 Merge with 4.11.5 2013-02-25 13:35:39 -01:00
Sebastiaan Janssen b6d5b7d603 Fixes U4-1776 SafeAlias culture problem 2013-02-25 13:33:51 -01:00
Sebastiaan Janssen 93d7cf4dc3 Fixes U4-1776 SafeAlias culture problem 2013-02-25 13:28:54 -01:00
Shannon Deminick e9f2546c2a Merge 2013-02-25 20:17:18 +06:00
Shannon Deminick 007c4d5862 Fixes: #U4-1773 2013-02-25 20:17:04 +06:00
Sebastiaan Janssen f3621aa743 MySQL: Check for case-sensitivity 2013-02-25 13:14:26 -01:00
Morten Christensen 46cf4398a0 Fixes issue with the Member editor throwing a YSOD because new API was used in the ContentControl.
The new API is now only used if available, which is the case for Content and Media, but currently not for Members.
2013-02-25 13:13:10 -01:00
Morten Christensen 1599f493fa Fixes U4-1696 2013-02-25 13:11:58 -01:00
Morten Christensen b5d79ebb74 Fixes U4-1690 with a proper implementation for removing ContentTypes from a composition. 2013-02-25 11:15:56 -01:00
Morten Christensen 1cc8367fa9 Merge 2013-02-25 10:32:01 -01:00
Morten Christensen 7e5087ae7d Fixing issues related to DocTypes 2013-02-25 10:31:38 -01:00
Sebastiaan Janssen d6f9909bec Merge with 4.11.5 2013-02-25 08:46:22 -01:00
Tom Fulton 0c42596dc8 Fixed: U4-1678 Saving a Media should show a SpeechBubble 2013-02-25 08:39:18 -01:00
Shannon Deminick 9b4da4c8f8 Merge with 4.11.5 2013-02-23 00:21:52 +06:00
Shannon Deminick cfc81d0e84 Merge 2013-02-23 00:21:44 +06:00
Morten Christensen 00e10deecb Merge 2013-02-22 16:42:17 -01:00
Morten Christensen 46e67e4a92 Skipping PropertyTypes that doesn't belong to the current ContentType 2013-02-22 16:42:06 -01:00
Morten Christensen 520a7f238d Refactoring ContentTypeControlNew and ContentControl 2013-02-22 16:25:45 -01:00
Shannon Deminick 3c41871e59 Fixes: #U4-1748 2013-02-22 21:42:38 +06:00
Sebastiaan Janssen 8cf9c1ba97 Fixes: U4-1769 Dictionary Item with "Illigal" character can not be deleted 2013-02-22 14:15:22 -01:00
Shannon Deminick e2d806f5d9 Merge with 4.11.5 2013-02-22 20:00:10 +06:00
Shannon Deminick 7a47d63b48 Fixed remaining tests 2013-02-22 19:55:22 +06:00
Sebastiaan Janssen 596c4ac329 Fixes: U4-1721 V6: Publish of a page ends in YSOD when using legacy schema 2013-02-22 12:36:24 -01:00
Sebastiaan Janssen 8ad8a3239a Make sure that the installer doesn't crash if dbSettings are null 2013-02-22 12:01:47 -01:00
Morten Christensen c0fa011cc3 Merge 2013-02-22 11:50:00 -01:00
Sebastiaan Janssen 4648a8c103 Fixes U4-1746 Duplicate image source (src) when inserting resized image in tiny
mce (richtext editor)
2013-02-22 11:41:01 -01:00
Sebastiaan Janssen 2df05da7fc Fixes U4-1746 Duplicate image source (src) when inserting resized image in tiny
mce (richtext editor)
2013-02-22 11:41:01 -01:00
Sebastiaan Janssen 87947871d1 Have to add new Examine version to Web.UI as well, else the build output from
build.bat file will not be able to find it.
2013-02-22 09:57:58 -01:00
Sebastiaan Janssen 87fee572ff Enable nuget package restore for teamcity, upgrade examine dll 2013-02-22 09:47:23 -01:00
Shannon Deminick e00c0fc447 Another update to examine to fix another issue: 10362 2013-02-22 10:41:42 +06:00
Shannon Deminick 7137c57ac9 merge issue with mediaxml file 2013-02-22 06:49:02 +06:00
Shannon Deminick d68b4d97f6 Fixing merge issues 2013-02-22 06:43:52 +06:00
Shannon Deminick 89f7a3ec63 Clearly these files shouldn't be deleted :P 2013-02-22 06:23:03 +06:00
Shannon Deminick 96a62b57fb Merge with 4.11.5 2013-02-22 06:21:12 +06:00
Shannon Deminick 7092a9ccbb Reverted the macro engines and web proj's, it would seem as though 4.x on the build server hasn't
been configured for nuget package restor (or something like that)
2013-02-22 06:05:10 +06:00
Shannon Deminick e9ea9b5e1b Updates DynamicNode with some performance enhancements especially around things like HasProperty and GetProperty.
Also when it returned children, it was actually re-iterating over all children (going to the repo to find them even though
they were already resolved).
2013-02-22 05:44:17 +06:00
Shannon Deminick fd1efb29ec Fixes issue when saving settings to web.config, not sure how this error never came up before. Was missing a "\" between the path and "web.config".
Using Path.Combine is much safer than just string.Concat!
2013-02-22 04:45:20 +06:00
Shannon Deminick cf4781153e Fixes: #U4-873, #U4-888 - fixes media sorting in razor + MVC. Updates Nunit libs and Examine lib. Adds unit tests to
support new sorting fixes. Fixes up a few other issues with the legacy ExamineBackedMedia class, it will now handle all data
stored in Examine. Simplifies the Examine internal index sets to include all data.
2013-02-22 04:12:24 +06:00
Morten Christensen 46687429fb Merge 2013-02-21 16:52:13 -01:00
Morten Christensen ce7aa43aa7 Refactoring ContentTypeControlNew to better work with the new api.
Adding a few helper methods to ContentTypeBase, which should make it easier to work with PropertyTypes and Groups.
2013-02-21 16:48:19 -01:00
Shannon Deminick ebed142cd5 Another fix for file sys test 2013-02-21 23:47:16 +06:00
Shannon Deminick 76e5304233 Merge with 4.11.5 2013-02-21 23:07:59 +06:00
Shannon Deminick d162aba14a Fix for file system test 2013-02-21 23:07:37 +06:00
Shannon Deminick 387398b044 Merge 2013-02-21 22:52:29 +06:00
Shannon Deminick 635b8bd82e Removes all need of UmbracoSettings.UseLegacyXmlSchema = false; in unit tests since the default is false. 2013-02-21 22:46:50 +06:00
Shannon Deminick f2071379fc Merge with 4.11.5 2013-02-21 22:40:24 +06:00
Shannon Deminick ec075f5807 Merge 2013-02-21 22:38:38 +06:00
Shannon Deminick eb8875066c Reverts LookupByNiceUrlTests to not require a database setup 2013-02-21 22:12:30 +06:00
Sebastiaan Janssen dca90e6316 Merge 2013-02-21 15:09:20 -01:00
Sebastiaan Janssen 2a47b384d2 Merge 2013-02-21 15:08:43 -01:00
Sebastiaan Janssen 29e5872a0f Merge with 4.11.5 2013-02-21 15:07:17 -01:00
Sebastiaan Janssen df31fafec5 Update en_us umbracoembed file, had the wrong content 2013-02-21 15:06:37 -01:00
Shannon Deminick 5f28f279e0 Merge with 4.11.5 2013-02-21 22:03:42 +06:00
Shannon Deminick 828dc64035 Backports fix for FullpathToRoot in GlobalSettings... not sure how some unit tests have been working this whole time.
Changes UseLegacySchema default value to false... was set to true!?
un-ignores LookupByNiceUrl tests and still ensures it doesn't require a database to test by passing in an optional parameter
to LookupByNiceUrl to specify if we want to include domain lookups or not (default is true)
2013-02-21 22:02:56 +06:00
Shannon Deminick 1d9e445a42 Merge 2013-02-21 21:34:30 +06:00
Shannon Deminick 1aa137e9da merge fix 2013-02-21 21:13:21 +06:00
Shannon Deminick 042eb47c17 Merge with 4.11.5 2013-02-21 21:02:11 +06:00
Sebastiaan Janssen a6556d0195 Merge 2013-02-21 14:01:28 -01:00
Shannon Deminick 0b74164a8e New base test class for anything relating to published content/media, un-ignores strongly typed tests. 2013-02-21 21:01:00 +06:00
Sebastiaan Janssen 807b32fb0d Fixed: U4-1676 Renamed node has old name on sort 2013-02-21 14:00:10 -01:00
Shannon Deminick 62be1b1267 un-ignores Can_Get_File_Dates in AbstractFileSystemTests... not sure why it was ignored seems to work properly. 2013-02-21 20:42:49 +06:00
Shannon Deminick bda3fbc698 Merge with 4.11.5 2013-02-21 20:07:05 +06:00
Sebastiaan Janssen 85ae7e764f Merge 2013-02-21 08:52:48 -01:00
Sebastiaan Janssen c744e47665 Fixes U4-1668 4.11.4 NiceUrl property on dynamicnode does not work until a
property has been requested from the dynamic node
2013-02-21 08:52:23 -01:00
Sebastiaan Janssen 3daa624627 Fixes U4-1668 4.11.4 NiceUrl property on dynamicnode does not work until a
property has been requested from the dynamic node
2013-02-21 08:52:23 -01:00
Shannon Deminick 9a7894df76 Merge with 4.11.5 2013-02-21 06:18:30 +06:00
Shannon Deminick d8af1aaf7b Changed logging in unit tests to filter out things we don't need to see 2013-02-21 03:13:16 +06:00
Shannon Deminick f2d105d8b9 Fixed #U4-814 and got all possible unit tests that were not working for DynamicNode but were working for
DynamicPublishedContent working. And fixed up the DynamicPublishedContent unit tests as these weren't working at all...
but seemed to say they did on the build server. strange.
2013-02-21 05:44:44 +06:00
Shannon Deminick c93193c5c8 Changed logging in unit tests to filter out things we don't need to see 2013-02-21 03:13:16 +06:00
Shannon Deminick 6734420c6f merge issue, had 2 declarations in the proj for SettingsForTests 2013-02-21 06:03:56 +06:00
Shannon Deminick fd795e14c6 Merge with 4.11.5 2013-02-21 05:52:42 +06:00
Shannon Deminick d622f76393 Fixed #U4-814 and got all possible unit tests that were not working for DynamicNode but were working for
DynamicPublishedContent working.
2013-02-21 05:02:06 +06:00
Sebastiaan Janssen d4fc82dae1 Calculate the hash of the WebPI package so it's not such a manual process. 2013-02-20 18:28:07 -01:00
Sebastiaan Janssen d4058bd81f Merge 2013-02-20 15:57:16 -01:00
Sebastiaan Janssen bc824ba66a Updates for WebPI testers: Check if SQL CE file exists when connectionstring is
filled in, make sure the connection string exists in web.config and if it has
empty values, run the installer instead of trying to start the site.
Also never claim the database is configure when the providername is empty.
2013-02-20 15:55:39 -01:00
Sebastiaan Janssen 4201286038 Don't check for database.windows.net to determine SQL Azure as WebPI sets a
custom server name
2013-02-20 15:03:43 -01:00
Stephan e333ad2b23 Tests.Routing - fix tests 2013-02-20 14:38:28 -01:00
Sebastiaan Janssen a8eeabb73d Merge 2013-02-20 14:34:49 -01:00
Sebastiaan Janssen b06620f56e Make the SQL Azure connection string support custom domains and all kinds of
ways of entering it.
2013-02-20 14:34:18 -01:00
Morten Christensen e8524963dd Fixes U4-1716 2013-02-20 11:20:06 -01:00
Stephan 5b0a8c0668 Tests - fix build broken by back-porting 6.x code 2013-02-20 10:12:41 -01:00
Sebastiaan Janssen 5d931d1146 Merge 2013-02-20 08:52:06 -01:00
Shannon Deminick 879c77c68d Applies same try/catch logic for setup/teardown because I'm still experiencing issues with the SQLCE
db file being locked which mucks up the rest of the setup/teardowns and tests fail.
2013-02-20 07:07:57 +06:00
Shannon Deminick e71dd3008d Merge 2013-02-20 06:39:09 +06:00
Shannon Deminick 597c888d36 Merge 2013-02-20 06:36:21 +06:00
Sebastiaan Janssen ef4c02f759 Merge 2013-02-19 20:58:00 -01:00
Sebastiaan Janssen 452a0a43b0 Fixes U4-1561 V6.0 RC - Member Profile property saving doesn't work 2013-02-19 20:57:20 -01:00
Stephan c3ccf3a609 Tests - cleanup settings handling for more reliable tests 2013-02-19 18:01:52 -01:00
Stephan 60bbede408 U4-1441 - fix, fix and fix! 2013-02-19 17:49:49 -01:00
Shannon Deminick 0751aff31f Fixes more of #U4-1706 and adds another unit test. Ensures we never return items from the recycle bin even if the indexes exist. Updated logic to ensure
items don't get indexed even if they are saved and currently exist in the recycle bin and ensures that indexes are removed on both trashed
and deleted.
2013-02-20 00:13:35 +06:00
Shannon Deminick a2ea20de70 un-ignores PublishedMedia tests. Streamlines BaseWebTest so now we only have one place for database init logic (will
enhance this more today). Changed ExamineEvents to not delete indexes on trashed and changed PublishedMediaStore to ignore
nodes in the recycle bin path... and now to write unit tests for that.
2013-02-19 22:46:44 +06:00
Shannon Deminick 3bfa1be60c Patch applied for #U4-1636 2013-02-19 22:14:08 +06:00
Shannon Deminick 8d38cf3c44 Applying patch for #U4-1636 2013-02-19 22:11:55 +06:00
Shannon Deminick a3a9ab069a Applying patch for #U4-1636 2013-02-19 22:09:55 +06:00
Morten Christensen da908501e5 Merge 2013-02-19 14:58:12 -01:00
Morten Christensen 995ed22401 Comments related to U4-1714 2013-02-19 14:58:02 -01:00
Sebastiaan Janssen c9cd4c721c Merge 2013-02-19 14:52:34 -01:00
Sebastiaan Janssen c059c14d7a Fixes U4-1706 DynamicMedia pulls content from Recyling Bin 2013-02-19 14:51:51 -01:00
Stephan 04c9771978 U4-1611 - bugfix 2013-02-19 13:58:16 -01:00
Stephan 9c8b5cd97e U4-1441 - fix, fix and fix! 2013-02-19 17:49:49 -01:00
Stephan 8bb447065c Tests - cleanup settings handling for more reliable tests 2013-02-19 17:45:22 -01:00
Stephan 1d0299af89 U4-1611 - bugfix 2013-02-19 13:58:16 -01:00
Morten Christensen 5b8beceea8 Merge 2013-02-19 13:46:45 -01:00
Morten Christensen e4568520a9 Improves performance when working with DocumentTypes in the backoffice - related to U4-1714 2013-02-19 13:45:57 -01:00
Shannon Deminick cbba628eaf Merge with 4.11.5 2013-02-19 20:18:15 +06:00
Shannon Deminick c2d0e255df Fixes: #U4-1537 2013-02-19 20:17:17 +06:00
Shannon Deminick e096890400 Fixes: #U4-1537 2013-02-19 20:12:13 +06:00
Morten Christensen ec4b1c8f70 Fixes U4-1689 and U4-1719.
Refactoring UmbracoImageMediaFactory so it uses the extension method for uploading/setting images, so its a bit more DRY.
2013-02-19 11:06:00 -01:00
Morten Christensen 1af904435a Merge 2013-02-19 08:47:04 -01:00
Shannon Deminick 7b2f03ba50 Merge with 4.11.5 2013-02-19 06:20:12 +06:00
Shannon Deminick 005d3e7d64 Removes area routing for local surface controllers and BeginUmbracoForm, adds strongly typed Html.Action<T>
method for rendering SurfaceController child actions regardless of area (so you don't have to specify).
All relates to #U4-1727
2013-02-19 06:19:26 +06:00
Shannon Deminick 12f8638223 Fixes: #U4-1727 2013-02-19 06:18:51 +06:00
Shannon Deminick 137b0754d6 Removes area routing for local surface controllers and BeginUmbracoForm, adds strongly typed Html.Action<T>
method for rendering SurfaceController child actions regardless of area (so you don't have to specify).
All relates to #U4-1727
2013-02-19 06:11:58 +06:00
Shannon Deminick 7d1e9cfd72 Fixes: #U4-1727 2013-02-19 06:11:17 +06:00
Shannon Deminick d01a39e0c6 Fixes merge issue 2013-02-19 04:10:01 +06:00
Shannon Deminick 73bd0137e3 Merge with 4.11.5 2013-02-19 03:57:24 +06:00
Shannon Deminick e3f9e8c842 Fixes: #U4-552 2013-02-19 03:42:19 +06:00
Shannon Deminick 7a38726b26 Fixes: #U4-552 2013-02-19 03:40:36 +06:00
Shannon Deminick a475f72d50 Fixes: #U4-1695 2013-02-19 02:25:57 +06:00
Shannon Deminick 36cadf39e9 Fixes: #U4-1695 2013-02-19 02:22:00 +06:00
Shannon Deminick a559ef9f90 Fixes: #U4-1732 2013-02-19 00:59:21 +06:00
Shannon Deminick b45f6e0393 Fixes: #U4-1732 2013-02-19 00:53:20 +06:00
Morten Christensen b99ff6c981 Merge 2013-02-18 15:48:02 -01:00
Morten Christensen 81021f5821 Part of the fix for U4-1689
Adds an alternative to the naming of the media subfolders instead of using the PropertyId.
2013-02-18 15:46:18 -01:00
Sebastiaan Janssen 29724b352b Fixes U4-1451 2013-02-18 13:22:12 -01:00
Sebastiaan Janssen be83302b14 Fixes U4-1451 2013-02-18 13:22:12 -01:00
Sebastiaan Janssen 83d7ea9ef1 Ignoring wrong unit test for now 2013-02-18 12:53:15 -01:00
Sebastiaan Janssen 95024442de Copy the umbracoSettings for PublishMediaStoreTests as well 2013-02-18 12:22:53 -01:00
Sebastiaan Janssen 69f54b5f22 Copy the umbracoSettings for LibraryTests as well 2013-02-18 11:57:58 -01:00
Sebastiaan Janssen 3404f95b2e Forgot one trailing slash in previous commit 2013-02-18 11:42:45 -01:00
Sebastiaan Janssen e56738481b Adding trailing slash to failing routing tests.
The issue with these tests might again be because of the UmbracoSettings file, which has the trailing slash setting. But with the settings being reset after teardown the tests were still failing, so made these minor corrections which shoudl correspond to the default setting.
2013-02-18 11:38:07 -01:00
Sebastiaan Janssen cb59dc353b Update version to 4.11.5 2013-02-18 10:31:43 -01:00
Sebastiaan Janssen d1b75eac08 Update wrong config path in unit tests 2013-02-18 10:31:17 -01:00
Sebastiaan Janssen 1f7651d0e3 Set version to 6.0.1 2013-02-18 10:16:24 -01:00
Sebastiaan Janssen 8fabd4e4ed Merge 2013-02-15 12:05:46 -01:00
Sebastiaan Janssen 564d92bed7 Possible fix for TeamCity 2013-02-15 12:05:25 -01:00
Shannon Deminick d73dd47e7b Merge 2013-02-15 18:56:24 +06:00
Shannon Deminick 95f103ccc2 Merge 2013-02-15 18:55:50 +06:00
Shannon Deminick c21b232a33 Merge with 4.11.5 2013-02-14 23:34:58 +06:00
Stephan 0ace2fdae7 U4-1611 - fix xpath special chars escaping issues in published content store 2013-02-14 16:31:45 -01:00
Shannon Deminick dfb2a31f26 Fixes up examine config for internal indexes: #U4-1710 2013-02-14 23:29:11 +06:00
Stephan 5da3541584 U4-1441 - bugfix 2013-02-14 16:27:27 -01:00
Shannon Deminick ef86d2f1f1 Manually applies patch for #U4-1718 2013-02-14 23:26:29 +06:00
Stephan be98425956 U4-1611 - fix xpath special chars escaping issues in published content store 2013-02-14 16:23:56 -01:00
Stephan 61d1f87611 U4-1441 - bugfix 2013-02-14 16:34:17 -01:00
Shannon Deminick 598d66ac7f Imports patch to fix: #U4-1718 2013-02-14 23:14:43 +06:00
Sebastiaan Janssen a10a6d1af8 Need to wrap the login javascript in a placeholder for Concorde 2013-02-14 09:06:15 -01:00
Sebastiaan Janssen 7640908781 Need to wrap the login javascript in a placeholder for Concorde 2013-02-14 09:06:15 -01:00
Morten Christensen b101e25e7a Correcting a check related to U4-1690.
Fixes a typo in an internal class and private method.
2013-02-13 08:05:04 -01:00
Morten Christensen 319f257ee5 Minor change related to U4-1672 2013-02-08 18:54:18 -01:00
Morten Christensen 14d40697b2 Fixes U4-1662 2013-02-08 18:40:52 -01:00
Morten Christensen 6e6b1beffd Fixes U4-1664 2013-02-08 18:37:59 -01:00
Morten Christensen e22de5c9a0 Fixes U4-1666 2013-02-08 18:34:47 -01:00
Morten Christensen 1eea4dab33 Fixes U4-1661 2013-02-08 18:29:59 -01:00
Morten Christensen 83518de981 Adding no guard for testing purposes 2013-02-08 11:37:50 -01:00
Stephan 6d87174cc1 U4-1441 - improve logging 2013-02-08 07:54:16 -01:00
Stephan 2da18d4500 U4-1441 - improve logging 2013-02-08 07:54:16 -01:00
Stephan 9af9c3fe77 U4-1441 - change trySkipIisCustomError config key 2013-02-08 07:36:35 -01:00
Stephan 9cedf5da4c U4-1441 - make trySkipIisCustomError value a setting 2013-02-08 08:08:36 -01:00
Stephan d50396ce68 U4-1441 - change trySkipIisCustomError config key 2013-02-08 07:36:35 -01:00
Stephan f7d4080472 U4-1441 - make trySkipIisCustomError value a setting 2013-02-08 07:51:22 -01:00
Morten Christensen e24ff1b92b Updating the CreateDatabaseSchema method, so it can't be used if Umbraco is configured. Just to ensure that Richard doesn't accidentally break anything. 2013-02-07 13:56:00 -01:00
Morten Christensen 0c05cbc9db Updating the EmptyRecycleBin method in the services to account for a deleted structure.
Optimizing the CallTheGarbageMan method because it was sooo easy, and it would be stupid not to.
2013-02-07 13:31:39 -01:00
Shannon Deminick 906d675dca Merge 2013-02-07 02:09:32 +06:00
Shannon Deminick 860ef73fab Merge 2013-02-07 02:07:43 +06:00
Shannon Deminick ec6158792a Adds patch fixes for #U4-1653 2013-02-07 02:07:07 +06:00
Shannon Deminick f1b3105202 Patch for #U4-1653 - media library cache refresh issue 2013-02-06 20:56:47 +06:00
Shannon Deminick 3ebb213916 Patches installer issue. 2013-02-06 19:18:42 +06:00
Shannon Deminick 97536086c0 Patches installer issue. 2013-02-06 19:14:34 +06:00
Morten Christensen 0853f8da85 Fixes U4-1619 so MediaTypes are deleted the same way as DocumentTypes using the legacy api/backoffice. 2013-02-06 09:43:53 -01:00
Morten Christensen 32d36d66c9 Removing unused media events 2013-02-06 09:12:38 -01:00
Morten Christensen 2aef75a70a Fixing SaveAndPublish method related to U4-1624 2013-02-06 09:10:08 -01:00
Morten Christensen fc21d10192 Updating cleanup script 2013-02-06 09:04:56 -01:00
Morten Christensen c6bd94532d Fixing issue U4-1648 caused by incorrect sql statement 2013-02-06 09:04:46 -01:00
Stephan a65ca205de U4-1441 - fix issue with IIS taking over custom errors 2013-02-05 16:29:10 -01:00
Stephan c8e08b8ef8 U4-1441 - fix issue with IIS taking over custom errors 2013-02-05 16:29:10 -01:00
Stephan 683d793460 U4-1441 - refactor (fix) legacy NotFoundHandler support 2013-02-06 12:46:54 -01:00
Morten Christensen d430efa7ab Updating logging in DatabaseContext 2013-02-05 14:38:58 -01:00
Morten Christensen c828c6ede3 Updating schema result to account for foreign tables when determining the current schema. 2013-02-05 08:41:10 -01:00
Stephan 3e1120612b Update version number 2013-02-04 12:00:58 -01:00
Stephan 8d06d39a62 Create branch for 4.11.5 2013-02-04 11:59:30 -01:00
Morten Christensen f64d4c9272 Updating the get media in recycle bin query as the parent is not necessarily -21 2013-02-04 08:00:31 -01:00
Morten Christensen b2f6620d80 Merge 2013-02-04 07:57:36 -01:00
Morten Christensen 812d38878c Updating the get content in recycle bin query as the parent is not necessarily -20 2013-02-04 07:47:05 -01:00
Stephan da7fea47c6 U4-1441 - refactor (fix) legacy NotFoundHandler support 2013-02-03 14:34:04 -01:00
Sebastiaan Janssen 71ddaf04b9 Put in an explicit comment to not disable useAspNetMasterPages when switching to
MVC as the default render engine
2013-02-02 09:49:21 -01:00
Shannon Deminick 6e1316cb95 Fixes up some merge issues. 2013-02-01 19:41:23 +06:00
Shannon Deminick f2442b25f6 Close 4.11.4 branch 2013-02-01 19:25:12 +06:00
Shannon Deminick bfb8912518 Merge with 4.11.4 2013-02-01 19:23:56 +06:00
Sebastiaan Janssen 300d3ff09b Added tag Release-4.11.4 for changeset e02f5aebb87e 2013-02-01 08:41:26 -01:00
Sebastiaan Janssen e6337b8f14 Properly reference uGoLive MyGet package 2013-02-01 08:38:13 -01:00
Morten Christensen 39d45ba4b0 Fixes U4-1618 2013-02-01 08:21:44 -01:00
Sebastiaan Janssen 2be785ace3 Merge 2013-02-01 08:16:18 -01:00
Sebastiaan Janssen 5e2d991fab Update uGoLive 2013-02-01 08:16:10 -01:00
Morten Christensen 536cb4caf1 Fixes U4-1571 2013-02-01 07:42:51 -01:00
Morten Christensen 27745ea141 Fixes U4-1483 2013-02-01 07:35:48 -01:00
Sebastiaan Janssen 5289c55740 Translation updates 2013-02-01 07:24:21 -01:00
Sebastiaan Janssen 791773fc8a Add some more translations 2013-02-01 07:23:33 -01:00
Shannon Deminick 3179b2794b Merge with 4.11.4 2013-02-01 06:46:00 +06:00
Shannon Deminick 1da27e6c2b Removes all upgrade script stuff since we've deployed the fix in a package. 2013-02-01 06:42:42 +06:00
Shannon Deminick bea6031de1 Removes UpgradeScripts stuff from 4.11.4 ... now to go remove it from there too since I've moved the script to a package. 2013-02-01 06:34:28 +06:00
Shannon Deminick 3608242b25 Merge with 4.11.4 2013-02-01 06:22:28 +06:00
Shannon Deminick 5602701645 Fixes uGoLive id and changes dashboard ascx to use CDF to load scripts/styles and using the knockout version shipped in the core.
Removes duplicate tree from the config.
2013-02-01 06:05:39 +06:00
Shannon Deminick a909b7904e Fixes uGoLive ascx 2013-02-01 05:29:54 +06:00
Sebastiaan Janssen 6e0af6827e Fix weird merge issues 2013-01-31 14:35:18 -01:00
Sebastiaan Janssen 51ff861e44 Merge with 6.0.0 2013-01-31 14:09:24 -01:00
Sebastiaan Janssen aa092ab3f3 Closing 6.0.0 2013-01-31 11:41:34 -01:00
Sebastiaan Janssen aaaace8dd3 Added tag Release-6.0.0 for changeset 1719fbd857f2 2013-01-31 11:32:05 -01:00
Shannon Deminick 1b1abce7da Merge 2013-01-31 04:48:29 +06:00
Shannon Deminick fbc10be381 Reverted logic of Document to be what it used to be... Published and HasPublishedVersion() are the same and will
return the same thing, though we've kept the lazy loading and optimizations.
2013-01-31 04:46:51 +06:00
Shannon Deminick 61f2647b62 missing file 2013-01-31 04:26:47 +06:00
Shannon Deminick a5bea7fc59 Added the ability to automate any c# scripts for an upgrade process. I realize this is superceded already in 6.0
but we need a way to do this in 4.x too especially for this release since we need to run a script to fix some db
issues. I've added a framework using an UpgradeScriptManager and another install step + unit tests for some of the
UpgradeScriptManager methods.
2013-01-31 04:26:37 +06:00
Sebastiaan Janssen b9be5c2561 Also implement optimization in fdfa687e6f41 to v4: no need to try and republish
the child pages if the page you are trying to publish was already published
2013-01-30 15:01:38 -01:00
Shannon Deminick 97556de447 Changed methods created yesterday to internal so we can port to 6+ nicely. 2013-01-30 18:58:42 +06:00
Stephan ea805a7af8 Merge with 6.0.0 2013-01-29 18:49:05 -01:00
Shannon Deminick c9d55a4a5e Merge with 6.0.0 - Ensures 6.1 is in sync with 6.0 too 2013-01-29 10:15:49 +06:00
Shannon Deminick d404970c74 Fixes up minor merge issues, removes the unused giant SQL constants (we have them in our history) 2013-01-29 10:07:30 +06:00
Shannon Deminick 66bf667100 Merge with 4.11.4 2013-01-29 09:58:47 +06:00
Shannon Deminick c5d1439422 Fixes: #U4-1458 - due to a null check on PublishedContentRequest on UmbracoContext 2013-01-29 08:35:09 +06:00
Shannon Deminick 5e9f4559b6 Fixes: #U4-1536 2013-01-29 07:49:14 +06:00
Shannon Deminick 4bbb0441a6 Merge 2013-01-29 05:50:50 +06:00
Shannon Deminick 4cf1d7d9a4 Fixes: #U4-1577 - HasPublishedVersion checks for trashed 2013-01-29 05:48:18 +06:00
Shannon Deminick a6a3ddca75 Fixes: #U4-1580 - m_SQLOptimizedMany includes the 'trashed' flag which can be used by business logic. 2013-01-29 05:37:14 +06:00
Shannon Deminick 27cfa85d3a Fixes: #U4-1579 - moving a node doesn't update the descendants of that node's level or path. 2013-01-29 04:39:44 +06:00
Shannon Deminick a9e1e7b634 Updating: #U4-1491 - Updated HasPublishedVersion() to ensure it checks for 'newest' 2013-01-29 03:42:58 +06:00
leekelleher 9f5f920c81 MNTP: Corrected a typo in the example XPath (additional apostrophe) 2013-01-28 17:18:20 +00:00
Stephan 09c19512d9 fix build 2013-01-27 13:32:04 -01:00
Stephan 212b86d8f6 merge from 4.11.4 2013-01-27 12:59:41 -01:00
Stephan a86b831735 Create 6.0.1 branch 2013-01-27 12:39:59 -01:00
Shannon Deminick f9a0d91299 Fixes: #U4-1527 - Creates a public property on UmbracoHelper to return the currently assigned IPublishedContent of the UmbracoHelper. 2013-01-25 06:04:10 +03:00
netaddicts d5bde0d8df Makes sure preview is not using cached versions of any macro 2013-01-24 11:00:15 -01:00
Sebastiaan Janssen cc5ca0b5fe Fixing U4-359 Previewing new nested pages doesn't work 2013-01-30 09:21:43 -01:00
Shannon Deminick 0cb9cc6840 just cleaned up some code formatting. 2013-01-30 07:59:15 +06:00
Shannon Deminick d38d7b1ff4 Updates all code calling UnPublishSingleNode & UpdateDocumentCache to pass in the already existing Document object if there is one
instead of the ID... this'll save a another ton of SQL calls.
2013-01-30 07:59:03 +06:00
Shannon Deminick 2d87f933d5 Updates Document's Published property to return true if the document is 100% published (viewable on the front-end)
Reverts Document's HasPublishedVersion() to return true if the document has any published version (may or may not be viewable on the front-end)
Updates the Document's new UpdatePublishedOnDescendants to set both the Published and PathPublished fields.
Reverts some stuff in the editContent to use HasPublishedContent() to set the _documentHasPublishedVersion field.
Reverts the BaseContentTree to use the Published property now that it returns the correct value.
Updates the editContent method to use the UpdateDocumentCache overload accepting an object so there's not another N+1 SQL call made.
2013-01-30 07:57:31 +06:00
Shannon Deminick a734a0cff7 Fixes unit tests for Umbraco_Route_User_Defined_Controller_Action 2013-01-30 05:37:32 +06:00
Shannon Deminick d0ace55d03 Fixes: #U4-1593 - Content tree doesn't check for correct publish state. 2013-01-30 05:04:31 +06:00
Shannon Deminick 3fda0308ac Fixes: #U4-1594 - SQL for SqlOptimizedSingle not correct for published state
Fixes: #U4-1596 - new GetPathPublishedDescendants method on Document for optimizations
Fixes: #U4-1595 - Obsoletes HasPublishedVersion() method and ensures lazy loading of Published property,
as well as ensuring that the backing property is set correctly on first load (optmization)
Fixes: #U4-1597 - PathPublished property should be set in an optimized way and/or lazy loaded if it cannot be
2013-01-30 04:56:28 +06:00
Shannon Deminick d796b2afc1 Fixes: #U4-1170 - template with hyphen or dash 2013-01-29 21:19:16 +06:00
Shannon Deminick f95cfc2ee0 Changes v4.x config transforms 2013-01-29 21:18:17 +06:00
Shannon Deminick 82c2560822 Ensures all resolvers are sealed. Changes CacheRefreshersResolver, DataTypesResolver, MacroFieldEditorsResolver, PackageActionsResolver, ActionsResolver
to all be lazy resolvers as they are not needed instantly on app startup (not needed by the front-end) This will
make app startup a lot quicker. Fixes ActionsResolver to not use the PluginManager to resolve the types when it
is instantiating them since these are passed in the ctor. Updates all unit tests to use lazy delegate for these resolvers
and they are all passing.
2013-01-23 18:40:40 +03:00
Shannon Deminick f467b8cb6c Adds more functionality for LazyManyObjectsResolverBase - adding type list delegates for lazy resolution. 2013-01-23 17:39:07 +03:00
Shannon Deminick aea1a03453 Updates ManyObjectsResolverBase to properly check for resolution freezing and fixes a few issues found regarding
inheritance in complex situations like the new LazyManyObjectsResolverBase.
Creates the new LazyManyObjectsResolverBase to lazily resolve types in order to create them. This is for
work item : #U4-1522
Adds unit test to support.
2013-01-23 07:45:00 +03:00
Shannon Deminick 1568e5f19c updated comments. 2013-01-23 01:44:01 +03:00
Shannon Deminick 8dff47db78 Merge 2013-01-23 01:39:45 +03:00
Shannon Deminick 987e48733a Merge 2013-01-23 01:39:25 +03:00
pcw@pcw-PC.shout.local ac5142443a Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit
http://issues.umbraco.org/issue/U4-1455
2013-01-15 20:40:28 +00:00
pcw@pcw-PC.shout.local 44360d83aa Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit
http://issues.umbraco.org/issue/U4-1455
2013-01-15 20:20:05 +00:00
pcw@pcw-PC.shout.local 021cb817d4 Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit
http://issues.umbraco.org/issue/U4-1455
2013-01-15 20:17:12 +00:00
pcw@pcw-PC.shout.local f4f91fba78 Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit
http://issues.umbraco.org/issue/U4-1455
2013-01-15 20:09:29 +00:00
pcw@pcw-PC.shout.local dec5e8ad6c Fixed EncryptWithMachineKey to handle values longer than FormsAuthentication.Encrypt max length limit
http://issues.umbraco.org/issue/U4-1455
2013-01-15 20:07:07 +00:00
Max Rotvel 4321c8d24e Fix part of U4-1355 by making umbracoembed translatable and supply da lang files 2013-01-15 14:33:25 -01:00
Stephan 6cb3fcf9ad U4-1411 - fix post-4.9 regression in NotFoundHandler url 2013-01-08 16:41:31 -01:00
Sebastiaan Janssen e5878554bd Fixes U4-1482 Regression - RTE unable to edit hyperlink on image 2013-01-21 14:21:29 -01:00
Sebastiaan Janssen 44c8c4b5b8 Revert 024896ba7bcf as it's a breaking change 2013-01-18 08:47:38 -01:00
401 changed files with 20618 additions and 7781 deletions
+1
View File
@@ -44,6 +44,7 @@ src\Umbraco.Web.UI\[Mm]acro[Ss]cripts\*
src\Umbraco.Web.UI\[Xx]slt\*
src\Umbraco.Web.UI\[Ii]mages\*
src\Umbraco.Web.UI\[Ss]cripts\*
src\Umbraco.Web.UI\Web.*.config.transformed
umbraco\presentation\umbraco\plugins\uComponents\uComponentsInstaller.ascx
umbraco\presentation\packages\uComponents\MultiNodePicker\CustomTreeService.asmx
+3
View File
@@ -24,3 +24,6 @@ f6da531fbb4c251ff61d314e2a7effb13c71e74a Release-4.10.0
54cde33b809dcb3a1f7e7ae0d5375f6dd0d89c8d Release-4.11.2.2
ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta
56015ac26f5ab60e3c61b1d09075297b660afa07 Release-6.0.0-RC
1719fbd857f28b376639ac2aa0abada0ef2e7560 Release-6.0.0
e02f5aebb87e3f07d27376647756caa9762931d8 Release-4.11.4
b247b35d821144849f551e02da8ba719f91d5fb0 Release-6.0.2
+1 -1
View File
@@ -1,5 +1,5 @@
@ECHO OFF
SET release=6.0.0
SET release=6.0.3
SET comment=
SET version=%release%
+48 -1
View File
@@ -1,3 +1,4 @@
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!--
@@ -13,7 +14,45 @@
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
<UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
<OutputFile ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System.IO" />
<Using Namespace="System.Linq" />
<Using Namespace="System.Security.Cryptography" />
<Code Type="Fragment" Language="cs">
<![CDATA[
using (var ms = new MemoryStream())
{
foreach (var item in InputFiles)
{
string path = item.ItemSpec;
using (FileStream stream = new FileStream(path, FileMode.Open))
{
using (var cryptoProvider = new SHA1CryptoServiceProvider())
{
var fileHash = cryptoProvider.ComputeHash(stream);
using (TextWriter w = new StreamWriter(OutputFile, false))
{
w.WriteLine(string.Join("", fileHash.Select(b => b.ToString("x2"))));
}
}
}
}
}
]]>
</Code>
</Task>
</UsingTask>
<!--
****************************************************
VARIABLES
@@ -71,10 +110,18 @@
*****************************************************
-->
<Target Name="Build" DependsOnTargets="ZipWebPiApp">
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
<Message Text="Build finished" />
</Target>
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
<ItemGroup>
<WebPiFile Include="$(BuildZipFileNameWebPi)" />
</ItemGroup>
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
</Target>
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
<Message Text="Deleting $(BuildFolder)" Importance="high" />
<RemoveDir Directories="$(BuildFolder)" />
+1 -1
View File
@@ -15,7 +15,7 @@
<language>en-US</language>
<tags>umbraco</tags>
<dependencies>
<dependency id="UmbracoCms.Core" version="$version$" />
<dependency id="UmbracoCms.Core" version="[$version$]" />
</dependencies>
</metadata>
<files>
+41 -11
View File
@@ -21,29 +21,44 @@ echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\U
echo Removing plugin cache files
del ..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*
echo Removing cache files and examine index
del ..\src\Umbraco.Web.UI\App_Data\TEMP\*.*
echo Removing log files
del ..\src\Umbraco.Web.UI\App_Data\Logs\*.*
echo Removing packages
del ..\src\Umbraco.Web.UI\App_Data\packages\*.*
echo Removing previews
del ..\src\Umbraco.Web.UI\App_Data\preview\*.*
echo Removing app code files (typically added by starterkits)
del ..\src\Umbraco.Web.UI\App_Code\*.*
echo Removing xslt files
del ..\src\Umbraco.Web.UI\Xslt\*.*
del ..\src\Umbraco.Web.UI\xslt\*.*
echo Removing user control files
del ..\src\Umbraco.Web.UI\UserControls\*.*
echo Removing masterpage files
del ..\src\Umbraco.Web.UI\masterpages\*.*
echo Removing view files
del ..\src\Umbraco.Web.UI\Views\*.*
echo Removing razor files
del ..\src\Umbraco.Web.UI\MacroScripts\*.*
del ..\src\Umbraco.Web.UI\macroScripts\*.*
echo Removing media files
del ..\src\Umbraco.Web.UI\Media\*.*
del ..\src\Umbraco.Web.UI\media\*.*
echo Removing script files
del ..\src\Umbraco.Web.UI\Scripts\*.*
del ..\src\Umbraco.Web.UI\scripts\*.*
echo Removing css files
del ..\src\Umbraco.Web.UI\Css\*.*
del ..\src\Umbraco.Web.UI\css\*.*
echo "Umbraco install reverted to clean install"
pause
@@ -64,29 +79,44 @@ echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\U
echo Removing plugin cache files
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*) DO DEL %%A
echo Removing cache files and examine index
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\*.*) DO DEL %%A
echo Removing log files
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\Logs\*.*) DO DEL %%A
echo Removing packages
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\packages\*.*) DO DEL %%A
echo Removing previews
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\preview\*.*) DO DEL %%A
echo Removing app code files (typically added by starterkits)
FOR %%A IN (..\src\Umbraco.Web.UI\App_Code\*.*) DO DEL %%A
echo Removing xslt files
FOR %%A IN (..\src\Umbraco.Web.UI\Xslt\*.*) DO DEL %%A
FOR %%A IN (..\src\Umbraco.Web.UI\xslt\*.*) DO DEL %%A
echo Removing masterpage files
FOR %%A IN (..\src\Umbraco.Web.UI\masterpages\*.*) DO DEL %%A
echo Removing user control files
FOR %%A IN (..\src\Umbraco.Web.UI\UserControls\*.*) DO DEL %%A
FOR %%A IN (..\src\Umbraco.Web.UI\usercontrols\*.*) DO DEL %%A
echo Removing view files
FOR %%A IN (..\src\Umbraco.Web.UI\Views\*.*) DO DEL %%A
echo Removing razor files
FOR %%A IN (..\src\Umbraco.Web.UI\MacroScripts\*.*) DO DEL %%A
FOR %%A IN (..\src\Umbraco.Web.UI\macroScripts\*.*) DO DEL %%A
echo Removing media files
FOR %%A IN (..\src\Umbraco.Web.UI\Media\*.*) DO DEL %%A
FOR %%A IN (..\src\Umbraco.Web.UI\media\*.*) DO DEL %%A
echo Removing script files
FOR %%A IN (..\src\Umbraco.Web.UI\Scripts\*.*) DO DEL %%A
FOR %%A IN (..\src\Umbraco.Web.UI\scripts\*.*) DO DEL %%A
echo Removing css files
FOR %%A IN (..\src\Umbraco.Web.UI\Css\*.*) DO DEL %%A
FOR %%A IN (..\src\Umbraco.Web.UI\css\*.*) DO DEL %%A
echo "Umbraco install reverted to clean install"
pause
+75 -18
View File
@@ -50,35 +50,90 @@ namespace SqlCE4Umbraco
/// </summary>
internal void ClearDatabase()
{
// drop constraints before tables to avoid exceptions
// looping on try/catching exceptions was not really nice
// http://stackoverflow.com/questions/536350/drop-all-the-tables-stored-procedures-triggers-constriants-and-all-the-depend
var localConnection = new SqlCeConnection(ConnectionString);
if (System.IO.File.Exists(ReplaceDataDirectory(localConnection.Database)))
{
var tables = new List<string>();
using (var reader = ExecuteReader("select table_name from information_schema.tables where TABLE_TYPE <> 'VIEW'"))
List<string> tables;
// drop foreign keys
// SQL may need "where constraint_catalog=DB_NAME() and ..."
tables = new List<string>();
using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' order by table_name"))
{
while (reader.Read())
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
}
foreach (var table in tables)
{
var constraints = new List<string>();
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name"))
{
tables.Add(reader.GetString("TABLE_NAME"));
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
}
foreach (var constraint in constraints)
{
// SQL may need "[dbo].[table]"
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
}
}
while(tables.Any())
// drop primary keys
// SQL may need "where constraint_catalog=DB_NAME() and ..."
tables = new List<string>();
using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' order by table_name"))
{
for (var i = 0; i < tables.Count; i++)
{
var dropTable = "DROP TABLE " + tables[i];
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
}
try
{
ExecuteNonQuery(dropTable);
tables.Remove(tables[i]);
}
catch (SqlHelperException ex)
{
//this will occur because there is no cascade option, so we just wanna try the next one
}
foreach (var table in tables)
{
var constraints = new List<string>();
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' and table_name = '" + table + "' order by constraint_name"))
{
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
}
foreach (var constraint in constraints)
{
// SQL may need "[dbo].[table]"
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
}
}
// drop tables
tables = new List<string>();
using (var reader = ExecuteReader("select table_name from information_schema.tables where table_type <> 'VIEW' order by table_name"))
{
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
}
foreach (var table in tables)
{
ExecuteNonQuery("drop table [" + table + "]");
}
}
}
/// <summary>
/// Drops all foreign keys on a table.
/// </summary>
/// <param name="table">The name of the table.</param>
/// <remarks>To be used in unit tests.</remarks>
internal void DropForeignKeys(string table)
{
var constraints = new List<string>();
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name"))
{
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
}
foreach (var constraint in constraints)
{
// SQL may need "[dbo].[table]"
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
}
}
@@ -94,7 +149,9 @@ namespace SqlCE4Umbraco
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
if (!string.IsNullOrEmpty(dataDirectory))
{
path = path.Replace("|DataDirectory|", dataDirectory + System.IO.Path.DirectorySeparatorChar);
path = path.Contains(@"|\")
? path.Replace("|DataDirectory|", dataDirectory)
: path.Replace("|DataDirectory|", dataDirectory + System.IO.Path.DirectorySeparatorChar);
}
}
+4 -4
View File
@@ -9,14 +9,14 @@ namespace Umbraco.Core
/// <summary>
/// A resolver to return all IAction objects
/// </summary>
internal sealed class ActionsResolver : ManyObjectsResolverBase<ActionsResolver, IAction>
internal sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="packageActions"></param>
internal ActionsResolver(IEnumerable<Type> packageActions)
internal ActionsResolver(Func<IEnumerable<Type>> packageActions)
: base(packageActions)
{
@@ -34,9 +34,9 @@ namespace Umbraco.Core
}
protected override IEnumerable<IAction> CreateInstances()
{
{
var actions = new List<IAction>();
var foundIActions = PluginManager.Current.ResolveActions();
var foundIActions = InstanceTypes;
foreach (var type in foundIActions)
{
IAction typeInstance;
+1 -1
View File
@@ -17,7 +17,7 @@ namespace Umbraco.Core
/// Constructor
/// </summary>
/// <param name="refreshers"></param>
internal CacheRefreshersResolver(IEnumerable<Type> refreshers)
internal CacheRefreshersResolver(Func<IEnumerable<Type>> refreshers)
: base(refreshers)
{
@@ -28,24 +28,49 @@ namespace Umbraco.Core.Configuration
#region Private static fields
private static Version _version;
private static string _reservedUrlsCache;
private static readonly object Locker = new object();
//make this volatile so that we can ensure thread safety with a double check lock
private static volatile string _reservedUrlsCache;
private static string _reservedPathsCache;
private static StartsWithContainer _reservedList = new StartsWithContainer();
private static string _reservedPaths;
private static string _reservedUrls;
//ensure the built on (non-changeable) reserved paths are there at all times
private const string StaticReservedPaths = "~/app_plugins/,~/install/,";
private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
#endregion
/// <summary>
/// used for unit tests
/// </summary>
internal static void ResetCache()
{
_reservedUrlsCache = null;
_reservedPaths = null;
_reservedUrls = null;
}
/// <summary>
/// Gets the reserved urls from web.config.
/// </summary>
/// <value>The reserved urls.</value>
public static string ReservedUrls
{
get
{
return ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls")
? ConfigurationManager.AppSettings["umbracoReservedUrls"]
: string.Empty;
{
if (_reservedUrls == null)
{
var urls = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls")
? ConfigurationManager.AppSettings["umbracoReservedUrls"]
: string.Empty;
//ensure the built on (non-changeable) reserved paths are there at all times
_reservedUrls = StaticReservedUrls + urls;
}
return _reservedUrls;
}
internal set { _reservedUrls = value; }
}
/// <summary>
@@ -56,10 +81,25 @@ namespace Umbraco.Core.Configuration
{
get
{
return ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths")
? ConfigurationManager.AppSettings["umbracoReservedPaths"]
: string.Empty;
if (_reservedPaths == null)
{
var reservedPaths = StaticReservedPaths;
//always add the umbraco path to the list
if (ConfigurationManager.AppSettings.ContainsKey("umbracoPath")
&& !ConfigurationManager.AppSettings["umbracoPath"].IsNullOrWhiteSpace())
{
reservedPaths += ConfigurationManager.AppSettings["umbracoPath"].EnsureEndsWith(',');
}
var allPaths = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths")
? ConfigurationManager.AppSettings["umbracoReservedPaths"]
: string.Empty;
_reservedPaths = reservedPaths + allPaths;
}
return _reservedPaths;
}
internal set { _reservedPaths = value; }
}
/// <summary>
@@ -114,6 +154,9 @@ namespace Umbraco.Core.Configuration
/// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
/// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
/// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
///
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
/// </remarks>
internal static string UmbracoMvcArea
{
@@ -123,7 +166,7 @@ namespace Umbraco.Core.Configuration
{
throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
}
return Path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim();
return Path.TrimStart(SystemDirectories.Root).TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
}
}
@@ -201,6 +244,7 @@ namespace Umbraco.Core.Configuration
}
}
/// <summary>
/// Saves a setting into the configuration file.
/// </summary>
@@ -622,38 +666,42 @@ namespace Umbraco.Core.Configuration
/// </returns>
public static bool IsReservedPathOrUrl(string url)
{
// check if GlobalSettings.ReservedPaths and GlobalSettings.ReservedUrls are unchanged
if (!object.ReferenceEquals(_reservedPathsCache, GlobalSettings.ReservedPaths)
|| !object.ReferenceEquals(_reservedUrlsCache, GlobalSettings.ReservedUrls))
if (_reservedUrlsCache == null)
{
// store references to strings to determine changes
_reservedPathsCache = GlobalSettings.ReservedPaths;
_reservedUrlsCache = GlobalSettings.ReservedUrls;
string _root = SystemDirectories.Root.Trim().ToLower();
// add URLs and paths to a new list
StartsWithContainer _newReservedList = new StartsWithContainer();
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
lock (Locker)
{
//resolves the url to support tilde chars
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
if (reservedUrlTrimmed.Length > 0)
_newReservedList.Add(reservedUrlTrimmed);
if (_reservedUrlsCache == null)
{
// store references to strings to determine changes
_reservedPathsCache = GlobalSettings.ReservedPaths;
_reservedUrlsCache = GlobalSettings.ReservedUrls;
string _root = SystemDirectories.Root.Trim().ToLower();
// add URLs and paths to a new list
StartsWithContainer _newReservedList = new StartsWithContainer();
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
{
//resolves the url to support tilde chars
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
if (reservedUrlTrimmed.Length > 0)
_newReservedList.Add(reservedUrlTrimmed);
}
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
{
bool trimEnd = !reservedPath.EndsWith("/");
//resolves the url to support tilde chars
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
if (reservedPathTrimmed.Length > 0)
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
}
// use the new list from now on
_reservedList = _newReservedList;
}
}
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
{
bool trimEnd = !reservedPath.EndsWith("/");
//resolves the url to support tilde chars
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
if (reservedPathTrimmed.Length > 0)
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
}
// use the new list from now on
_reservedList = _newReservedList;
}
//The url should be cleaned up before checking:
@@ -0,0 +1,190 @@
using System.Configuration;
namespace Umbraco.Core.Configuration.InfrastructureSettings
{
public class Infrastructure : ConfigurationSection
{
private const string InfrastructureSectionName = "umbraco/infrastructure";
public static Infrastructure Instance
{
get { return (Infrastructure) ConfigurationManager.GetSection(InfrastructureSectionName); }
}
#region RepositoriesSection Property
internal const string RepositoriesPropertyName = "repositories";
[ConfigurationProperty(RepositoriesPropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
public Repositories Repositories
{
get { return ((Repositories)base[RepositoriesPropertyName]); }
set { base[RepositoriesPropertyName] = value; }
}
#endregion
#region PublishingStrategy Property
internal const string PublishingStrategyPropertyName = "publishingStrategy";
[ConfigurationProperty(PublishingStrategyPropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
public PublishingProvider PublishingStrategy
{
get { return ((PublishingProvider)base[PublishingStrategyPropertyName]); }
set { base[PublishingStrategyPropertyName] = value; }
}
#endregion
}
public class Repositories : ConfigurationElement
{
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
public RepositoryElementCollection Repository
{
get { return ((RepositoryElementCollection)(base[""])); }
}
}
[ConfigurationCollection(typeof(Repository), CollectionType = ConfigurationElementCollectionType.BasicMapAlternate, AddItemName = RepositoryPropertyName)]
public class RepositoryElementCollection : ConfigurationElementCollection
{
internal const string RepositoryPropertyName = "repository";
public override ConfigurationElementCollectionType CollectionType
{
get
{
return ConfigurationElementCollectionType.BasicMapAlternate;
}
}
protected override string ElementName
{
get
{
return RepositoryPropertyName;
}
}
protected override bool IsElementName(string elementName)
{
return elementName == RepositoryPropertyName;
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((Repository)element).InterfaceShortTypeName;
}
protected override ConfigurationElement CreateNewElement()
{
return new Repository();
}
#region Indexer
public Repository this[int index]
{
get { return (Repository)base.BaseGet(index); }
}
public Repository this[string interfaceShortTypeName]
{
get { return (Repository)base.BaseGet(interfaceShortTypeName); }
}
#endregion
#region Add
public void Add(Repository repository)
{
BaseAdd(repository);
}
#endregion
#region Remove
public void Remove(Repository repository)
{
BaseRemove(repository);
}
#endregion
#region GetItem
public Repository GetItemAt(int index)
{
return (Repository)BaseGet(index);
}
public Repository GetItemByKey(string interfaceShortTypeName)
{
return (Repository)BaseGet(interfaceShortTypeName);
}
#endregion
public bool ContainsKey(string interfaceShortName)
{
bool result = false;
object[] keys = this.BaseGetAllKeys();
foreach (object key in keys)
{
if ((string)key == interfaceShortName)
{
result = true;
break;
}
}
return result;
}
}
public class Repository : ConfigurationElement
{
internal const string InterfaceShortTypeNamePropertyName = "interfaceShortTypeName";
[ConfigurationPropertyAttribute(InterfaceShortTypeNamePropertyName, IsRequired = true, IsKey = true, IsDefaultCollection = false)]
public string InterfaceShortTypeName
{
get { return (string) base[InterfaceShortTypeNamePropertyName]; }
set { base[InterfaceShortTypeNamePropertyName] = value; }
}
internal const string RepositoryFullTypeNamePropertyName = "repositoryFullTypeName";
[ConfigurationPropertyAttribute(RepositoryFullTypeNamePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
public string RepositoryFullTypeName
{
get { return (string)base[RepositoryFullTypeNamePropertyName]; }
set { base[RepositoryFullTypeNamePropertyName] = value; }
}
internal const string CacheProviderFullTypeNamePropertyName = "cacheProviderFullTypeName";
[ConfigurationPropertyAttribute(CacheProviderFullTypeNamePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
public string CacheProviderFullTypeName
{
get { return (string)base[CacheProviderFullTypeNamePropertyName]; }
set { base[CacheProviderFullTypeNamePropertyName] = value; }
}
}
public class PublishingProvider : ConfigurationElement
{
internal const string TypePropertyName = "type";
[ConfigurationPropertyAttribute(TypePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
public string Type
{
get { return (string)base[TypePropertyName]; }
set { base[TypePropertyName] = value; }
}
}
}
+126 -97
View File
@@ -25,7 +25,31 @@ namespace Umbraco.Core.Configuration
/// </summary>
internal class UmbracoSettings
{
/// <summary>
private static bool GetKeyValue(string key, bool defaultValue)
{
bool value;
string stringValue = GetKey(key);
if (string.IsNullOrWhiteSpace(stringValue))
return defaultValue;
if (bool.TryParse(stringValue, out value))
return value;
return defaultValue;
}
private static int GetKeyValue(string key, int defaultValue)
{
int value;
string stringValue = GetKey(key);
if (string.IsNullOrWhiteSpace(stringValue))
return defaultValue;
if (int.TryParse(stringValue, out value))
return value;
return defaultValue;
}
/// <summary>
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
/// </summary>
internal static void ResetSetters()
@@ -35,6 +59,7 @@ namespace Umbraco.Core.Configuration
_useLegacySchema = null;
_useDomainPrefixes = null;
_umbracoLibraryCacheDuration = null;
_trySkipIisCustomErrors = null;
SettingsFilePath = null;
}
@@ -126,11 +151,32 @@ namespace Umbraco.Core.Configuration
{
EnsureSettingsDocument();
string attrName = null;
var pos = key.IndexOf('@');
if (pos > 0)
{
attrName = key.Substring(pos + 1);
key = key.Substring(0, pos - 1);
}
var node = UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode(key);
if (node == null || node.FirstChild == null || node.FirstChild.Value == null)
return string.Empty;
return node.FirstChild.Value;
}
if (node == null)
return string.Empty;
if (pos < 0)
{
if (node.FirstChild == null || node.FirstChild.Value == null)
return string.Empty;
return node.FirstChild.Value;
}
else
{
var attr = node.Attributes[attrName];
if (attr == null)
return string.Empty;
return attr.Value;
}
}
/// <summary>
/// Gets a value indicating whether the media library will create new directories in the /media directory.
@@ -203,6 +249,7 @@ namespace Umbraco.Core.Configuration
return value != null ? value.Attributes["assembly"].Value : "";
}
}
/// <summary>
/// Gets the type of an external logger that can be used to store log items in 3rd party systems
/// </summary>
@@ -351,24 +398,13 @@ namespace Umbraco.Core.Configuration
{
get
{
try
{
if (_useDomainPrefixes.HasValue)
return _useDomainPrefixes.Value;
bool result;
if (bool.TryParse(GetKey("/settings/requestHandler/useDomainPrefixes"), out result))
return result;
return false;
}
catch
{
return false;
}
// default: false
return _useDomainPrefixes ?? GetKeyValue("/settings/requestHandler/useDomainPrefixes", false);
}
// for unit tests only
internal set
{
_useDomainPrefixes = value;
// for unit tests only
_useDomainPrefixes = value;
}
}
@@ -382,31 +418,14 @@ namespace Umbraco.Core.Configuration
{
get
{
try
{
if (GlobalSettings.UseDirectoryUrls)
{
if (_addTrailingSlash.HasValue)
return _addTrailingSlash.Value;
bool result;
if (bool.TryParse(GetKey("/settings/requestHandler/addTrailingSlash"), out result))
return result;
return false;
}
else
{
return false;
}
}
catch
{
return false;
}
// default: false
return GlobalSettings.UseDirectoryUrls
&& (_addTrailingSlash ?? GetKeyValue("/settings/requestHandler/addTrailingSlash", false));
}
// for unit tests only
internal set
{
_addTrailingSlash = value;
// for unit tests only
_addTrailingSlash = value;
}
}
@@ -623,31 +642,34 @@ namespace Umbraco.Core.Configuration
{
get
{
if (_forceSafeAliases.HasValue)
return _forceSafeAliases.Value;
string forceSafeAlias = GetKey("/settings/content/ForceSafeAliases");
if (String.IsNullOrEmpty(forceSafeAlias))
return true;
else
{
try
{
return bool.Parse(forceSafeAlias);
}
catch
{
return true;
}
}
// default: true
return _forceSafeAliases ?? GetKeyValue("/settings/content/ForceSafeAliases", true);
}
internal set
{
//used for unit testing
// used for unit testing
_forceSafeAliases = value;
}
}
private static bool? _trySkipIisCustomErrors;
/// <summary>
/// Gets or sets a value indicating where to try to skip IIS custom errors.
/// </summary>
public static bool TrySkipIisCustomErrors
{
get
{
// default: false
return _trySkipIisCustomErrors ?? GetKeyValue("/settings/web.routing/@trySkipIisCustomErrors", false);
}
internal set
{
// used for unit testing
_trySkipIisCustomErrors = value;
}
}
/// <summary>
/// Gets the allowed image file types.
@@ -677,26 +699,14 @@ namespace Umbraco.Core.Configuration
{
get
{
if (_umbracoLibraryCacheDuration.HasValue)
return _umbracoLibraryCacheDuration.Value;
string libraryCacheDuration = GetKey("/settings/content/UmbracoLibraryCacheDuration");
if (String.IsNullOrEmpty(libraryCacheDuration))
return 1800;
else
{
try
{
return int.Parse(libraryCacheDuration);
}
catch
{
return 1800;
}
}
// default: 1800
return _umbracoLibraryCacheDuration ?? GetKeyValue("/settings/content/UmbracoLibraryCacheDuration", 1800);
}
internal set { _umbracoLibraryCacheDuration = value; }
internal set
{
// for unit tests only
_umbracoLibraryCacheDuration = value;
}
}
/// <summary>
@@ -1052,27 +1062,12 @@ namespace Umbraco.Core.Configuration
{
get
{
try
{
if (_useLegacySchema.HasValue)
return _useLegacySchema.Value;
string value = GetKey("/settings/content/UseLegacyXmlSchema");
bool result;
if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
return result;
return true;
}
catch (Exception)
{
//default. TODO: When we change this to a real config section we won't have to worry about parse errors
// and should handle defaults with unit tests properly.
return false;
}
// default: true
return _useLegacySchema ?? GetKeyValue("/settings/content/UseLegacyXmlSchema", false);
}
internal set
{
//used for unit testing
// used for unit testing
_useLegacySchema = value;
}
}
@@ -1221,6 +1216,40 @@ namespace Umbraco.Core.Configuration
}
}
private static MacroErrorBehaviour? _macroErrorBehaviour;
/// <summary>
/// This configuration setting defines how to handle macro errors:
/// - Inline - Show error within macro as text (default and current Umbraco 'normal' behavior)
/// - Silent - Suppress error and hide macro
/// - Throw - Throw an exception and invoke the global error handler (if one is defined, if not you'll get a YSOD)
/// </summary>
/// <value>MacroErrorBehaviour enum defining how to handle macro errors.</value>
public static MacroErrorBehaviour MacroErrorBehaviour
{
get
{
if (_macroErrorBehaviour == null)
{
try
{
var behaviour = MacroErrorBehaviour.Inline;
var value = GetKey("/settings/content/MacroErrors");
if (value != null)
{
Enum<MacroErrorBehaviour>.TryParse(value, true, out behaviour);
}
_macroErrorBehaviour = behaviour;
}
catch (Exception ex)
{
LogHelper.Error<UmbracoSettings>("Could not load /settings/content/MacroErrors from umbracosettings.config", ex);
_macroErrorBehaviour = MacroErrorBehaviour.Inline;
}
}
return _macroErrorBehaviour.Value;
}
}
/// <summary>
/// Configuration regarding webservices
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("6.0.0");
private static readonly Version Version = new Version("6.0.3");
/// <summary>
/// Gets the current version of Umbraco.
+53 -27
View File
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
@@ -9,6 +7,8 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Publishing;
@@ -60,27 +60,36 @@ namespace Umbraco.Core
new PetaPocoUnitOfWorkProvider(dbFactory),
new FileUnitOfWorkProvider(),
new PublishingStrategy());
//create the ApplicationContext
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext);
//initialize the DatabaseContext
dbContext.Initialize();
CreateApplicationContext(dbContext, serviceContext);
InitializeApplicationEventsResolver();
InitializeResolvers();
//initialize the DatabaseContext
dbContext.Initialize();
//now we need to call the initialize methods
ApplicationEventsResolver.Current.ApplicationEventHandlers
.ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
_isInitialized = true;
return this;
}
/// <summary>
/// Creates and assigns the application context singleton
/// </summary>
/// <param name="dbContext"></param>
/// <param name="serviceContext"></param>
protected virtual void CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
{
//create the ApplicationContext
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext);
}
/// <summary>
/// Special method to initialize the ApplicationEventsResolver and any modifications required for it such
/// as adding custom types to the resolver.
@@ -110,15 +119,15 @@ namespace Umbraco.Core
if (_isStarted)
throw new InvalidOperationException("The boot manager has already been initialized");
if (afterStartup != null)
{
afterStartup(ApplicationContext.Current);
}
//call OnApplicationStarting of each application events handler
ApplicationEventsResolver.Current.ApplicationEventHandlers
.ForEach(x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext));
if (afterStartup != null)
{
afterStartup(ApplicationContext.Current);
}
_isStarted = true;
return this;
@@ -134,21 +143,23 @@ namespace Umbraco.Core
if (_isComplete)
throw new InvalidOperationException("The boot manager has already been completed");
//freeze resolution to not allow Resolvers to be modified
Resolution.Freeze();
FreezeResolution();
//stop the timer and log the output
_timer.Dispose();
if (afterComplete != null)
{
afterComplete(ApplicationContext.Current);
}
//call OnApplicationStarting of each application events handler
ApplicationEventsResolver.Current.ApplicationEventHandlers
.ForEach(x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
//Now, startup all of our legacy startup handler
ApplicationEventsResolver.Current.InstantiateLegacyStartupHanlders();
if (afterComplete != null)
{
afterComplete(ApplicationContext.Current);
}
_isComplete = true;
// we're ready to serve content!
@@ -157,6 +168,14 @@ namespace Umbraco.Core
return this;
}
/// <summary>
/// Freeze resolution to not allow Resolvers to be modified
/// </summary>
protected virtual void FreezeResolution()
{
Resolution.Freeze();
}
/// <summary>
/// Create the resolvers
/// </summary>
@@ -165,20 +184,26 @@ namespace Umbraco.Core
RepositoryResolver.Current = new RepositoryResolver(
new RepositoryFactory());
SqlSyntaxProvidersResolver.Current = new SqlSyntaxProvidersResolver(
new[] { typeof(MySqlSyntaxProvider), typeof(SqlCeSyntaxProvider), typeof(SqlServerSyntaxProvider) })
{
CanResolveBeforeFrozen = true
};
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
PluginManager.Current.ResolveCacheRefreshers());
() => PluginManager.Current.ResolveCacheRefreshers());
DataTypesResolver.Current = new DataTypesResolver(
PluginManager.Current.ResolveDataTypes());
() => PluginManager.Current.ResolveDataTypes());
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
PluginManager.Current.ResolveMacroRenderings());
() => PluginManager.Current.ResolveMacroRenderings());
PackageActionsResolver.Current = new PackageActionsResolver(
PluginManager.Current.ResolvePackageActions());
() => PluginManager.Current.ResolvePackageActions());
ActionsResolver.Current = new ActionsResolver(
PluginManager.Current.ResolveActions());
() => PluginManager.Current.ResolveActions());
MacroPropertyTypeResolver.Current = new MacroPropertyTypeResolver(
PluginManager.Current.ResolveMacroPropertyTypes());
@@ -201,7 +226,8 @@ namespace Umbraco.Core
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
typeof (UpdateCmsContentTypeTable),
typeof (UpdateCmsContentVersionTable),
typeof (UpdateCmsPropertyTypeGroupTable)
typeof (UpdateCmsPropertyTypeGroupTable),
typeof (UpdatePropertyTypesAndGroups)
});
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
+1 -1
View File
@@ -14,7 +14,7 @@ namespace Umbraco.Core
/// Constructor
/// </summary>
/// <param name="dataTypes"></param>
internal DataTypesResolver(IEnumerable<Type> dataTypes)
internal DataTypesResolver(Func<IEnumerable<Type>> dataTypes)
: base(dataTypes)
{
+113 -24
View File
@@ -112,7 +112,7 @@ namespace Umbraco.Core
public void ConfigureEmbeddedDatabaseConnection()
{
const string providerName = "System.Data.SqlServerCe.4.0";
const string connectionString = "Datasource=|DataDirectory|Umbraco.sdf";
const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf";
SaveConnectionString(connectionString, providerName);
@@ -158,7 +158,7 @@ namespace Umbraco.Core
}
else if (databaseProvider.ToLower().Contains("azure"))
{
connectionString = string.Format("Server=tcp:{0}.database.windows.net;Database={1};User ID={2}@{0};Password={3}", server, databaseName, user, password);
connectionString = BuildAzureConnectionString(server, databaseName, user, password);
}
else
{
@@ -169,6 +169,52 @@ namespace Umbraco.Core
Initialize(providerName);
}
internal string BuildAzureConnectionString(string server, string databaseName, string user, string password)
{
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
server = string.Format("tcp:{0}", server);
if (server.Contains(".") == false && ServerStartsWithTcp(server))
{
string serverName = server.Contains(",")
? server.Substring(0, server.IndexOf(",", StringComparison.Ordinal))
: server;
var portAddition = string.Empty;
if (server.Contains(","))
portAddition = server.Substring(server.IndexOf(",", StringComparison.Ordinal));
server = string.Format("{0}.database.windows.net{1}", serverName, portAddition);
}
if (ServerStartsWithTcp(server) == false)
server = string.Format("tcp:{0}.database.windows.net", server);
if (server.Contains(",") == false)
server = string.Format("{0},1433", server);
if (user.Contains("@") == false)
{
var userDomain = server;
if (ServerStartsWithTcp(server))
userDomain = userDomain.Substring(userDomain.IndexOf(":", StringComparison.Ordinal) + 1);
if (userDomain.Contains("."))
userDomain = userDomain.Substring(0, userDomain.IndexOf(".", StringComparison.Ordinal));
user = string.Format("{0}@{1}", user, userDomain);
}
return string.Format("Server={0};Database={1};User ID={2};Password={3}", server, databaseName, user, password);
}
private static bool ServerStartsWithTcp(string server)
{
return server.ToLower().StartsWith("tcp:".ToLower());
}
/// <summary>
/// Saves the connection string as a proper .net ConnectionString and the legacy AppSettings key/value.
/// </summary>
@@ -218,7 +264,7 @@ namespace Umbraco.Core
xml.Save(fileName, SaveOptions.DisableFormatting);
LogHelper.Info<DatabaseContext>("Configured new ConnectionString: " + connectionString);
LogHelper.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
}
/// <summary>
@@ -232,7 +278,8 @@ namespace Umbraco.Core
/// </remarks>
internal void Initialize()
{
if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null)
var databaseSettings = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName];
if (databaseSettings != null && string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) == false && string.IsNullOrWhiteSpace(databaseSettings.ProviderName) == false)
{
var providerName = "System.Data.SqlClient";
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName))
@@ -254,8 +301,7 @@ namespace Umbraco.Core
{
ConfigureEmbeddedDatabaseConnection();
}
else if (legacyConnString.ToLowerInvariant().Contains("database.windows.net") &&
legacyConnString.ToLowerInvariant().Contains("tcp:"))
else if (legacyConnString.ToLowerInvariant().Contains("tcp:"))
{
//Must be sql azure
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
@@ -291,21 +337,22 @@ namespace Umbraco.Core
internal void Initialize(string providerName)
{
if (providerName.StartsWith("MySql"))
{
SyntaxConfig.SqlSyntaxProvider = MySqlSyntax.Provider;
}
else if (providerName.Contains("SqlServerCe"))
{
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
}
else
{
SyntaxConfig.SqlSyntaxProvider = SqlServerSyntax.Provider;
}
_providerName = providerName;
_configured = true;
try
{
SqlSyntaxContext.SqlSyntaxProvider =
SqlSyntaxProvidersResolver.Current.GetByProviderNameOrDefault(providerName);
_configured = true;
}
catch (Exception e)
{
_configured = false;
LogHelper.Info<DatabaseContext>("Initialization of the DatabaseContext failed with following error: " + e.Message);
LogHelper.Info<DatabaseContext>(e.StackTrace);
}
}
internal DatabaseSchemaResult ValidateDatabaseSchema()
@@ -337,16 +384,56 @@ namespace Umbraco.Core
try
{
LogHelper.Info<DatabaseContext>("Database configuration status: Started");
var message = string.Empty;
var database = new UmbracoDatabase(_connectionString, ProviderName);
var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
if (supportsCaseInsensitiveQueries == false)
{
message = "<p>&nbsp;</p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
"<p>You can fix this by changing the following two settings in your my.ini file in your MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
return new Result { Message = message, Success = false, Percentage = "15" };
}
else if (supportsCaseInsensitiveQueries == null)
{
message = "<p>&nbsp;</p><p>Warning! Could not check if your database type supports case insensitive queries. <br />We currently do not support these databases that do not support case insensitive queries.</p>" +
"<p>You can check this by looking for the following two settings in your my.ini file in your MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
}
else
{
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
{
message = "<p>&nbsp;</p><p>Congratulations, the database step ran successfully!</p>" +
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
"<p>They can check this by looking for the following two settings in the my.ini file in their MySQL installation directory:</p>" +
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
}
}
var schemaResult = ValidateDatabaseSchema();
var installedVersion = schemaResult.DetermineInstalledVersion();
string message;
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedVersion.Equals(new Version(0, 0, 0)))
{
database.CreateDatabaseSchema();
message = "Installation completed!";
message = message + "<p>Installation completed!</p>";
}
else
{
@@ -356,9 +443,11 @@ namespace Umbraco.Core
var targetVersion = UmbracoVersion.Current;
var runner = new MigrationRunner(configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
var upgraded = runner.Execute(database, true);
message = "Upgrade completed!";
message = message + "<p>Upgrade completed!</p>";
}
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
return new Result { Message = message, Success = true, Percentage = "100" };
}
catch (Exception ex)
@@ -374,7 +463,7 @@ namespace Umbraco.Core
{
Message =
"The database configuration failed with the following message: " + ex.Message +
"\n Please check log file for addtional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
"\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
Success = false,
Percentage = "90"
};
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Dictionary
/// <summary>
/// Resolves the current CultureDictionaryFactory
/// </summary>
internal class CultureDictionaryFactoryResolver : SingleObjectResolverBase<CultureDictionaryFactoryResolver, ICultureDictionaryFactory>
internal sealed class CultureDictionaryFactoryResolver : SingleObjectResolverBase<CultureDictionaryFactoryResolver, ICultureDictionaryFactory>
{
internal CultureDictionaryFactoryResolver(ICultureDictionaryFactory factory)
: base(factory)
+218 -120
View File
@@ -9,35 +9,106 @@ using System.Xml.XPath;
using System.Collections;
using System.IO;
using System.Web;
using Umbraco.Core;
namespace Umbraco.Core.Dynamics
{
[TypeConverter(typeof(DynamicXmlConverter))]
public class DynamicXml : DynamicObject, IEnumerable<DynamicXml>, IEnumerable<XElement>
{
/// <summary>
/// Returns the XElement used to create the DynamicXml structure
/// </summary>
public XElement BaseElement { get; set; }
/// <summary>
/// Returns the raw XElement used to create the DynamicXml structure if one was specified otherwise returns the
/// same value as BaseElement.
/// </summary>
/// <remarks>
/// This is purely used for when an instance of DynamicXml is created with the overload that supports
/// passing in both a raw xml version and a dash-stripped xml version. Otherwise this value is exactly the
/// same as BaseElement.
/// </remarks>
public XElement RawXmlElement { get; internal set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="baseElement"></param>
public DynamicXml(XElement baseElement)
{
this.BaseElement = baseElement;
if (baseElement == null) return;
//same
RawXmlElement = baseElement;
BaseElement = baseElement;
}
public DynamicXml(string xml)
/// <summary>
/// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure
/// </summary>
/// <param name="strippedXml"></param>
/// <param name="rawXml"></param>
internal DynamicXml(XElement strippedXml, XElement rawXml)
{
var baseElement = XElement.Parse(xml);
this.BaseElement = baseElement;
if (rawXml == null) return;
if (strippedXml == null) return;
RawXmlElement = rawXml;
BaseElement = strippedXml;
}
/// <summary>
/// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure
/// </summary>
/// <param name="strippedXml"></param>
/// <param name="rawXml"></param>
internal DynamicXml(string strippedXml, string rawXml)
{
if (rawXml == null) return;
if (strippedXml == null) return;
RawXmlElement = XElement.Parse(rawXml);
BaseElement = XElement.Parse(strippedXml);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="xml"></param>
public DynamicXml(string xml)
{
if (xml.IsNullOrWhiteSpace()) return;
var baseElement = XElement.Parse(xml);
//same
RawXmlElement = baseElement;
BaseElement = baseElement;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="xpni"></param>
public DynamicXml(XPathNodeIterator xpni)
{
if (xpni != null)
{
if (xpni.Current != null)
{
var xml = xpni.Current.OuterXml;
var baseElement = XElement.Parse(xml);
this.BaseElement = baseElement;
}
}
if (xpni == null) return;
if (xpni.Current == null) return;
//TODO: OuterXml is really bad for performance! Should actually use the XPathNodeIterator api
var xml = xpni.Current.OuterXml;
var baseElement = XElement.Parse(xml);
//same
RawXmlElement = baseElement;
BaseElement = baseElement;
}
/// <summary>
/// Returns the InnertText based on the BaseElement object
/// </summary>
public string InnerText
{
get
@@ -45,17 +116,34 @@ namespace Umbraco.Core.Dynamics
return BaseElement.Value;
}
}
/// <summary>
/// Returns the string representation of the BaseElement object
/// </summary>
/// <returns></returns>
public string ToXml()
{
return BaseElement.ToString(SaveOptions.DisableFormatting);
}
/// <summary>
/// Returns the string representation of the RawXmlElement object
/// </summary>
/// <returns></returns>
public string ToRawXml()
{
return RawXmlElement.ToString(SaveOptions.DisableFormatting);
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
int index = 0;
if (indexes.Length > 0)
{
index = (int)indexes[0];
result = new DynamicXml(this.BaseElement.Elements().ToList()[index]);
result = new DynamicXml(
RawXmlElement.Elements().ElementAt(index),
BaseElement.Elements().ElementAt(index));
return true;
}
return base.TryGetIndex(binder, indexes, out result);
@@ -64,12 +152,12 @@ namespace Umbraco.Core.Dynamics
{
if (args.Length == 0 && binder.Name == "ToXml")
{
result = this.BaseElement.ToString();
result = BaseElement.ToString();
return true;
}
if (args.Length == 1 && binder.Name == "XPath")
{
var elements = this.BaseElement.XPathSelectElements(args[0].ToString());
var elements = BaseElement.XPathSelectElements(args[0].ToString());
HandleIEnumerableXElement(elements, out result);
return true; //anyway
}
@@ -102,7 +190,9 @@ namespace Umbraco.Core.Dynamics
}
else if (attempt.Result.ObjectResult is IEnumerable<DynamicXml>)
{
result = ((IEnumerable<DynamicXml>)attempt.Result.ObjectResult).Select(x => new DynamicXml(x.BaseElement));
result = ((IEnumerable<DynamicXml>) attempt.Result.ObjectResult).Select(x => new DynamicXml(
x.RawXmlElement,
x.BaseElement));
}
}
}
@@ -123,55 +213,102 @@ namespace Umbraco.Core.Dynamics
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (BaseElement == null || binder == null)
if (RawXmlElement == null || binder == null)
{
result = null;
return false;
}
//Go ahead and try to fetch all of the elements matching the member name, and wrap them
var elements = BaseElement.Elements(binder.Name);
if (!elements.Any() && BaseElement.Name == "root" && BaseElement.Elements().Count() == 1)
{
//no elements matched, lets try first child
elements = BaseElement.Elements().ElementAt(0).Elements(binder.Name);
}
if (HandleIEnumerableXElement(elements, out result))
{
return true;
}
else
{
//Ok, so no elements matched, so lets try attributes
IEnumerable<string> attributes = BaseElement.Attributes(binder.Name).Select(attr => attr.Value);
int count = attributes.Count();
if (count > 0)
//Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped)
var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement);
if (elementByNameAttempt.Success)
{
if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result))
{
if (count > 1)
result = attributes; //more than one attribute matched, lets return the collection
else
result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it
return true;
}
}
return true; // return true because we matched
//Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped)
var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement);
if (attributeByNameAttempt.Success)
{
if (attributeByNameAttempt.Result.Count() > 1)
{
//more than one attribute matched, lets return the collection
result = attributeByNameAttempt.Result;
}
else
{
//no attributes matched, lets try first child
if (BaseElement.Name == "root" && BaseElement.Elements().Count() == 1)
{
attributes = BaseElement.Elements().ElementAt(0).Attributes(binder.Name).Select(attr => attr.Value);
count = attributes.Count();
if (count > 1)
result = attributes; //more than one attribute matched, lets return the collection
else
result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it
//only one attribute matched, lets just return it
result = attributeByNameAttempt.Result.FirstOrDefault();
}
return true;
}
return true; // return true because we matched
}
return base.TryGetMember(binder, out result);
}
/// <summary>
/// Checks if the 'name' matches any attributes of xmlElement
/// </summary>
/// <param name="name">The name to match</param>
/// <param name="xmlElement">The xml element to check against</param>
/// <returns></returns>
private static Attempt<IEnumerable<string>> CheckAttributeNameMatch(string name, XElement xmlElement)
{
var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray();
if (attributes.Any())
{
return new Attempt<IEnumerable<string>>(true, attributes);
}
if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
{
//no elements matched and this node is called 'root' and only has one child... lets see if it matches.
var childElements = xmlElement.Elements().ElementAt(0).Attributes(name).Select(attr => attr.Value).ToArray();
if (childElements.Any())
{
//we've found a match by the first child of an element called 'root' (strange, but sure)
return new Attempt<IEnumerable<string>>(true, childElements);
}
}
//no deal
return Attempt<IEnumerable<string>>.False;
}
/// <summary>
/// Checks if the 'name' matches any elements of xmlElement
/// </summary>
/// <param name="name">The name to match</param>
/// <param name="xmlElement">The xml element to check against</param>
/// <returns></returns>
private Attempt<IEnumerable<XElement>> CheckNodeNameMatch(string name, XElement xmlElement)
{
//Go ahead and try to fetch all of the elements matching the member name, and wrap them
var elements = xmlElement.Elements(name).ToArray();
//Check if we've got any matches, if so then return true
if (elements.Any())
{
return new Attempt<IEnumerable<XElement>>(true, elements);
}
if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
{
//no elements matched and this node is called 'root' and only has one child... lets see if it matches.
var childElements = xmlElement.Elements().ElementAt(0).Elements(name).ToArray();
if (childElements.Any())
{
//we've found a match by the first child of an element called 'root' (strange, but sure)
return new Attempt<IEnumerable<XElement>>(true, childElements);
}
}
return base.TryGetMember(binder, out result);
//no deal
return Attempt<IEnumerable<XElement>>.False;
}
private bool HandleIEnumerableXElement(IEnumerable<XElement> elements, out object result)
@@ -193,7 +330,7 @@ namespace Umbraco.Core.Dynamics
//We have more than one matching element, so let's return the collection
//elements is IEnumerable<DynamicXml>
//but we want to be able to re-enter this code
XElement root = new XElement(XName.Get("root"));
var root = new XElement(XName.Get("root"));
root.Add(elements);
result = new DynamicXml(root);
@@ -205,10 +342,16 @@ namespace Umbraco.Core.Dynamics
result = null;
return false;
}
/// <summary>
/// Executes an XPath expression over the BaseElement object
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
public DynamicXml XPath(string expression)
{
var matched = this.BaseElement.XPathSelectElements(expression);
DynamicXml root = new DynamicXml("<results/>");
var matched = BaseElement.XPathSelectElements(expression);
var root = new DynamicXml("<results/>");
foreach (var element in matched)
{
root.BaseElement.Add(element);
@@ -217,7 +360,7 @@ namespace Umbraco.Core.Dynamics
}
/// <summary>
/// Return the string version of Xml
/// Return the string version of the BaseElement object
/// </summary>
/// <returns></returns>
public override string ToString()
@@ -231,23 +374,23 @@ namespace Umbraco.Core.Dynamics
}
public DynamicXml Find(string expression)
{
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault());
}
public DynamicXml Find(string attributeName, object value)
{
string expression = string.Format("//*[{0}='{1}']", attributeName, value);
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault());
}
IEnumerator<XElement> IEnumerable<XElement>.GetEnumerator()
{
return this.BaseElement.Elements().GetEnumerator();
return BaseElement.Elements().GetEnumerator();
}
public IEnumerator<DynamicXml> GetEnumerator()
{
return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
return BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
@@ -310,7 +453,7 @@ namespace Umbraco.Core.Dynamics
}
public bool IsPosition(int index)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return false;
}
@@ -318,7 +461,7 @@ namespace Umbraco.Core.Dynamics
}
public HtmlString IsPosition(int index, string valueIfTrue)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return new HtmlString(string.Empty);
}
@@ -326,7 +469,7 @@ namespace Umbraco.Core.Dynamics
}
public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return new HtmlString(valueIfFalse);
}
@@ -334,7 +477,7 @@ namespace Umbraco.Core.Dynamics
}
public bool IsModZero(int modulus)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return false;
}
@@ -342,7 +485,7 @@ namespace Umbraco.Core.Dynamics
}
public HtmlString IsModZero(int modulus, string valueIfTrue)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return new HtmlString(string.Empty);
}
@@ -350,7 +493,7 @@ namespace Umbraco.Core.Dynamics
}
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return new HtmlString(valueIfFalse);
}
@@ -359,7 +502,7 @@ namespace Umbraco.Core.Dynamics
public bool IsNotModZero(int modulus)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || BaseElement.Parent == null)
{
return false;
}
@@ -367,7 +510,7 @@ namespace Umbraco.Core.Dynamics
}
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
{
if (this.BaseElement == null || this.BaseElement.Parent == null)
if (BaseElement == null || this.BaseElement.Parent == null)
{
return new HtmlString(string.Empty);
}
@@ -573,7 +716,8 @@ namespace Umbraco.Core.Dynamics
}
public IEnumerable<DynamicXml> Descendants(Func<XElement, bool> func)
{
var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); });
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n));
}
public IEnumerable<DynamicXml> DescendantsOrSelf()
@@ -582,7 +726,8 @@ namespace Umbraco.Core.Dynamics
}
public IEnumerable<DynamicXml> DescendantsOrSelf(Func<XElement, bool> func)
{
var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); });
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
var list = new List<DynamicXml>();
list.Add(this);
list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)));
@@ -689,57 +834,10 @@ namespace Umbraco.Core.Dynamics
return test(this) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse);
}
[Obsolete("Use XmlHelper.StripDashesInElementOrAttributeNames instead")]
public static string StripDashesInElementOrAttributeNames(string xml)
{
using (MemoryStream outputms = new MemoryStream())
{
using (TextWriter outputtw = new StreamWriter(outputms))
{
using (MemoryStream ms = new MemoryStream())
{
using (TextWriter tw = new StreamWriter(ms))
{
tw.Write(xml);
tw.Flush();
ms.Position = 0;
using (TextReader tr = new StreamReader(ms))
{
bool IsInsideElement = false, IsInsideQuotes = false;
int ic = 0;
while ((ic = tr.Read()) != -1)
{
if (ic == (int)'<' && !IsInsideQuotes)
{
if (tr.Peek() != (int)'!')
{
IsInsideElement = true;
}
}
if (ic == (int)'>' && !IsInsideQuotes)
{
IsInsideElement = false;
}
if (ic == (int)'"')
{
IsInsideQuotes = !IsInsideQuotes;
}
if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes)
{
outputtw.Write((char)ic);
}
}
}
}
}
outputtw.Flush();
outputms.Position = 0;
using (TextReader outputtr = new StreamReader(outputms))
{
return outputtr.ReadToEnd();
}
}
}
return XmlHelper.StripDashesInElementOrAttributeNames(xml);
}
@@ -7,6 +7,58 @@ using System.Xml.Linq;
namespace Umbraco.Core.Dynamics
{
/// <summary>
/// Used to return the raw xml string value from DynamicXml when using type converters
/// </summary>
public class RawXmlString
{
public string Value { get; private set; }
public RawXmlString(string value)
{
Value = value;
}
}
/// <summary>
/// Used to return the raw xml XElement value from DynamicXml when using type converters
/// </summary>
public class RawXElement
{
public XElement Value { get; private set; }
public RawXElement(XElement value)
{
Value = value;
}
}
/// <summary>
/// Used to return the raw xml XElement value from DynamicXml when using type converters
/// </summary>
public class RawXmlElement
{
public XmlElement Value { get; private set; }
public RawXmlElement(XmlElement value)
{
Value = value;
}
}
/// <summary>
/// Used to return the raw xml XmlDocument value from DynamicXml when using type converters
/// </summary>
public class RawXmlDocument
{
public XmlDocument Value { get; private set; }
public RawXmlDocument(XmlDocument value)
{
Value = value;
}
}
/// <summary>
/// A custom type converter for DynamicXml
/// </summary>
@@ -14,7 +66,17 @@ namespace Umbraco.Core.Dynamics
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
{
var convertableTypes = new[] {typeof(string), typeof(XElement), typeof(XmlElement), typeof(XmlDocument)};
var convertableTypes = new[]
{
typeof(string),
typeof(XElement),
typeof(XmlElement),
typeof(XmlDocument),
typeof(RawXmlString),
typeof(RawXElement),
typeof(RawXmlElement),
typeof(RawXmlDocument)
};
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType))
|| base.CanConvertFrom(context, sourceType);
@@ -34,6 +96,7 @@ namespace Umbraco.Core.Dynamics
{
return value.ToString();
}
//XElement
if (TypeHelper.IsTypeAssignableFrom<XElement>(destinationType))
{
@@ -53,6 +116,34 @@ namespace Umbraco.Core.Dynamics
xDoc.LoadXml(dxml.ToString());
return xDoc;
}
//RAW values:
//string
if (TypeHelper.IsTypeAssignableFrom<RawXmlString>(destinationType))
{
return new RawXmlString(dxml.ToRawXml());
}
//XElement
if (TypeHelper.IsTypeAssignableFrom<RawXElement>(destinationType))
{
return new RawXElement(dxml.RawXmlElement);
}
//XmlElement
if (TypeHelper.IsTypeAssignableFrom<RawXmlElement>(destinationType))
{
var xDoc = new XmlDocument();
xDoc.LoadXml(dxml.ToRawXml());
return new RawXmlElement(xDoc.DocumentElement);
}
//XmlDocument
if (TypeHelper.IsTypeAssignableFrom<RawXmlDocument>(destinationType))
{
var xDoc = new XmlDocument();
xDoc.LoadXml(dxml.ToRawXml());
return new RawXmlDocument(xDoc);
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
+31 -28
View File
@@ -5,36 +5,35 @@ using Umbraco.Core.Models;
namespace Umbraco.Core.Dynamics
{
[Obsolete("This class should not be used, it is just referenced by already obsoleted code and will be removed in the future")]
internal static class ExtensionMethods
{
public static IEnumerable<TSource> Map<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> selectorFunction,
Func<TSource, IEnumerable<TSource>> getChildrenFunction)
{
if (!source.Any())
{
return source;
}
// Add what we have to the stack
var flattenedList = source.Where(selectorFunction);
// Go through the input enumerable looking for children,
// and add those if we have them
foreach (TSource element in source)
{
var secondInner = getChildrenFunction(element);
if (secondInner.Any())
{
secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
}
flattenedList = flattenedList.Concat(secondInner);
}
return flattenedList;
}
//public static IEnumerable<TSource> Map<TSource>(
// this IEnumerable<TSource> source,
// Func<TSource, bool> selectorFunction,
// Func<TSource, IEnumerable<TSource>> getChildrenFunction)
//{
// if (!source.Any())
// {
// return source;
// }
// // Add what we have to the stack
// var flattenedList = source.Where(selectorFunction);
// // Go through the input enumerable looking for children,
// // and add those if we have them
// foreach (TSource element in source)
// {
// var secondInner = getChildrenFunction(element);
// if (secondInner.Any())
// {
// secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
// }
// flattenedList = flattenedList.Concat(secondInner);
// }
// return flattenedList;
//}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -44,6 +43,7 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, params string[] needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -53,6 +53,7 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, StringComparison comparison, IEnumerable<string> needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -62,6 +63,7 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsAny(this string haystack, StringComparison comparison, params string[] needles)
{
if (haystack == null) throw new ArgumentNullException("haystack");
@@ -71,12 +73,13 @@ namespace Umbraco.Core.Dynamics
}
return false;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool ContainsInsensitive(this string haystack, string needle)
{
if (haystack == null) throw new ArgumentNullException("haystack");
return haystack.IndexOf(needle, StringComparison.CurrentCultureIgnoreCase) >= 0;
}
[Obsolete("This method should not be used and will be removed in the future")]
public static bool HasValue(this string s)
{
return !string.IsNullOrWhiteSpace(s);
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Umbraco.Core.Events
{
// Provides information on the macro that caused an error
public class MacroErrorEventArgs : System.EventArgs
{
/// <summary>
/// Name of the faulting macro.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Alias of the faulting macro.
/// </summary>
public string Alias { get; set; }
/// <summary>
/// Filename, file path, fully qualified class name, or other key used by the macro engine to do it's processing of the faulting macro.
/// </summary>
public string ItemKey { get; set; }
/// <summary>
/// Exception raised.
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// Gets or sets the desired behaviour when a matching macro causes an error. See
/// <see cref="MacroErrorBehaviour"/> for definitions. By setting this in your event
/// you can override the default behaviour defined in UmbracoSettings.config.
/// </summary>
/// <value>Macro error behaviour enum.</value>
public MacroErrorBehaviour Behaviour { get; set; }
}
}
+15
View File
@@ -8,6 +8,7 @@ using System.IO;
using System.Configuration;
using System.Web;
using System.Text.RegularExpressions;
using System.Xml;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
@@ -230,6 +231,20 @@ namespace Umbraco.Core.IO
filePath = String.Empty;
}
//Break up the file in name and extension before applying the UrlReplaceCharacters
var fileNamePart = filePath.Substring(0, filePath.LastIndexOf('.'));
var ext = filePath.Substring(filePath.LastIndexOf('.'));
//Because the file usually is downloadable as well we check characters against 'UmbracoSettings.UrlReplaceCharacters'
XmlNode replaceChars = UmbracoSettings.UrlReplaceCharacters;
foreach (XmlNode n in replaceChars.SelectNodes("char"))
{
if (n.Attributes.GetNamedItem("org") != null && n.Attributes.GetNamedItem("org").Value != "")
fileNamePart = fileNamePart.Replace(n.Attributes.GetNamedItem("org").Value, XmlHelper.GetNodeValue(n));
}
filePath = string.Concat(fileNamePart, ext);
// Adapted from: http://stackoverflow.com/a/4827510/5018
// Combined both Reserved Characters and Character Data
// from http://en.wikipedia.org/wiki/Percent-encoding
+9 -2
View File
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.IO
@@ -27,6 +25,15 @@ namespace Umbraco.Core.IO
return propertyId.ToString() + seperator + fileName;
}
public string GetRelativePath(string subfolder, string fileName)
{
var seperator = UmbracoSettings.UploadAllowDirectories
? Path.DirectorySeparatorChar
: '-';
return subfolder + seperator + fileName;
}
public IEnumerable<string> GetThumbnails(string path)
{
var parentDirectory = System.IO.Path.GetDirectoryName(path);
+14 -4
View File
@@ -183,16 +183,26 @@ namespace Umbraco.Core.IO
}
}
private static string _root;
/// <summary>
/// Gets the root path of the application
/// </summary>
public static string Root
{
get
{
string appPath = HttpRuntime.AppDomainAppVirtualPath ?? string.Empty;
if (appPath == "/")
appPath = string.Empty;
if (_root == null)
{
string appPath = HttpRuntime.AppDomainAppVirtualPath ?? string.Empty;
if (appPath == "/")
appPath = string.Empty;
return appPath;
_root = appPath;
}
return _root;
}
//Only required for unit tests
internal set { _root = value; }
}
}
@@ -64,23 +64,28 @@ namespace Umbraco.Core.Logging
{
_forceStop = true;
var windowsIdentity = WindowsIdentity.GetCurrent();
base.Append(new LoggingEvent(new LoggingEventData
{
Level = Level.Error,
Message =
"Unable to clear out the AsynchronousRollingFileAppender buffer in the allotted time, forcing a shutdown",
TimeStamp = DateTime.UtcNow,
Identity = "",
ExceptionString = "",
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
Domain = AppDomain.CurrentDomain.FriendlyName,
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
LocationInfo =
new LocationInfo(this.GetType().Name, "OnClose", "AsynchronousRollingFileAppender.cs", "59"),
LoggerName = this.GetType().FullName,
Properties = new PropertiesDictionary(),
})
);
var logEvent = new LoggingEvent(new LoggingEventData
{
Level = global::log4net.Core.Level.Error,
Message =
"Unable to clear out the AsynchronousRollingFileAppender buffer in the allotted time, forcing a shutdown",
TimeStamp = DateTime.UtcNow,
Identity = "",
ExceptionString = "",
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
Domain = AppDomain.CurrentDomain.FriendlyName,
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
LocationInfo =
new LocationInfo(this.GetType().Name, "OnClose", "AsynchronousRollingFileAppender.cs", "59"),
LoggerName = this.GetType().FullName,
Properties = new PropertiesDictionary(),
});
if (this.DateTimeStrategy != null)
{
base.Append(logEvent);
}
}
base.OnClose();
+23
View File
@@ -0,0 +1,23 @@
namespace Umbraco.Core
{
public enum MacroErrorBehaviour
{
/// <summary>
/// Default umbraco behavior - show an inline error within the
/// macro but allow the page to continue rendering.
/// </summary>
Inline,
/// <summary>
/// Silently eat the error and do not display the offending macro.
/// </summary>
Silent,
/// <summary>
/// Throw an exception which can be caught by the global error handler
/// defined in Application_OnError. If no such error handler is defined
/// then you'll see the Yellow Screen Of Death (YSOD) error page.
/// </summary>
Throw
}
}
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Umbraco.Core.IO;
namespace Umbraco.Core.Media
{
/// <summary>
/// Internal singleton to handle the numbering of subfolders within the Media-folder.
/// When this class is initiated it will look for numbered subfolders and select the highest number,
/// which will be the start point for the naming of the next subfolders. If no subfolders exists
/// then the starting point will be 1000, ie. /media/1000/koala.jpg
/// </summary>
internal class MediaSubfolderCounter
{
#region Singleton
private long _numberedFolder = 1000;//Default starting point
private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
private static readonly Lazy<MediaSubfolderCounter> Lazy = new Lazy<MediaSubfolderCounter>(() => new MediaSubfolderCounter());
public static MediaSubfolderCounter Current { get { return Lazy.Value; } }
private MediaSubfolderCounter()
{
var folders = new List<long>();
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
var directories = fs.GetDirectories("");
foreach (var directory in directories)
{
long dirNum;
if (long.TryParse(directory, out dirNum))
{
folders.Add(dirNum);
}
}
var last = folders.OrderBy(x => x).LastOrDefault();
if(last != default(long))
_numberedFolder = last;
}
#endregion
/// <summary>
/// Returns an increment of the numbered media subfolders.
/// </summary>
/// <returns>A <see cref="System.Int64"/> value</returns>
public long Increment()
{
using (new ReadLock(ClearLock))
{
_numberedFolder = _numberedFolder + 1;
return _numberedFolder;
}
}
}
}
+55 -16
View File
@@ -10,6 +10,7 @@ using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Media;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.UnitOfWork;
@@ -57,16 +58,22 @@ namespace Umbraco.Core.Models
/// <summary>
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
/// </summary>
/// <param name="content"><see cref="IContent"/> to add property value to</param>
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value)
{
// Ensure we get the filename without the path in IE in intranet mode
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
var fileName = value.FileName;
if (fileName.LastIndexOf(@"\") > 0)
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
var name =
IOHelper.SafeFileName(
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
.ToLower());
fileName.Substring(fileName.LastIndexOf(IOHelper.DirSepChar) + 1,
fileName.Length - fileName.LastIndexOf(IOHelper.DirSepChar) - 1)
.ToLower());
if (string.IsNullOrEmpty(name) == false)
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
@@ -75,16 +82,22 @@ namespace Umbraco.Core.Models
/// <summary>
/// Sets and uploads the file from a HttpPostedFile object as the property value
/// </summary>
/// <param name="content"><see cref="IContent"/> to add property value to</param>
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFile"/> containing the file that will be uploaded</param>
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFile value)
{
// Ensure we get the filename without the path in IE in intranet mode
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
var fileName = value.FileName;
if (fileName.LastIndexOf(@"\") > 0)
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
var name =
IOHelper.SafeFileName(
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
.ToLower());
fileName.Substring(fileName.LastIndexOf(IOHelper.DirSepChar) + 1,
fileName.Length - fileName.LastIndexOf(IOHelper.DirSepChar) - 1)
.ToLower());
if (string.IsNullOrEmpty(name) == false)
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
@@ -93,13 +106,37 @@ namespace Umbraco.Core.Models
/// <summary>
/// Sets and uploads the file from a HttpPostedFileWrapper object as the property value
/// </summary>
/// <param name="content"><see cref="IContent"/> to add property value to</param>
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="value">The <see cref="HttpPostedFileWrapper"/> containing the file that will be uploaded</param>
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileWrapper value)
{
if (string.IsNullOrEmpty(value.FileName) == false)
SetFileOnContent(content, propertyTypeAlias, value.FileName, value.InputStream);
// Ensure we get the filename without the path in IE in intranet mode
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
var fileName = value.FileName;
if (fileName.LastIndexOf(@"\") > 0)
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
var name = IOHelper.SafeFileName(fileName);
if (string.IsNullOrEmpty(name) == false)
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
}
/// <summary>
/// Sets and uploads the file from a <see cref="Stream"/> as the property value
/// </summary>
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
/// <param name="fileName">Name of the file</param>
/// <param name="fileStream"><see cref="Stream"/> to save to disk</param>
public static void SetValue(this IContentBase content, string propertyTypeAlias, string fileName,
Stream fileStream)
{
var name = IOHelper.SafeFileName(fileName);
if (string.IsNullOrEmpty(name) == false && fileStream != null)
SetFileOnContent(content, propertyTypeAlias, name, fileStream);
}
private static void SetFileOnContent(IContentBase content, string propertyTypeAlias, string name, Stream fileStream)
@@ -109,10 +146,12 @@ namespace Umbraco.Core.Models
return;
bool supportsResizing = false;
var numberedFolder = MediaSubfolderCounter.Current.Increment();
string fileName = UmbracoSettings.UploadAllowDirectories
? Path.Combine(property.Id.ToString(), name)
: property.Id + "-" + name;
string extension = Path.GetExtension(name);
? Path.Combine(numberedFolder.ToString(CultureInfo.InvariantCulture), name)
: numberedFolder + "-" + name;
string extension = Path.GetExtension(name).Substring(1).ToLowerInvariant();
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
fs.AddFile(fileName, fileStream);
@@ -182,7 +221,7 @@ namespace Umbraco.Core.Models
private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, string propertyValue)
{
XmlNode propertyNode = uploadFieldConfigNode.SelectSingleNode(propertyAlias);
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false)
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false && content.HasProperty(propertyNode.FirstChild.Value))
{
content.SetValue(propertyNode.FirstChild.Value, propertyValue);
}
@@ -407,7 +446,7 @@ namespace Umbraco.Core.Models
//Check for umbracoUrlName convention
if (property.Alias == "umbracoUrlName" && property.Value != null &&
property.Value.ToString().Trim() != string.Empty)
xml.SetAttributeValue("urlName", property.Value);
xml.SetAttributeValue("urlName", property.Value.ToString().FormatUrl().ToLower());
}
return xml;
+73 -5
View File
@@ -4,7 +4,6 @@ using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
@@ -323,6 +322,74 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Checks whether a PropertyType with a given alias already exists
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
public abstract bool PropertyTypeExists(string propertyTypeAlias);
/// <summary>
/// Adds a PropertyGroup.
/// This method will also check if a group already exists with the same name and link it to the parent.
/// </summary>
/// <param name="groupName">Name of the PropertyGroup to add</param>
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
public abstract bool AddPropertyGroup(string groupName);
/// <summary>
/// Adds a PropertyType to a specific PropertyGroup
/// </summary>
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
public abstract bool AddPropertyType(PropertyType propertyType, string propertyGroupName);
/// <summary>
/// Adds a PropertyType, which does not belong to a PropertyGroup.
/// </summary>
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
public bool AddPropertyType(PropertyType propertyType)
{
if (PropertyTypeExists(propertyType.Alias) == false)
{
_propertyTypes.Add(propertyType);
_propertyTypes.CollectionChanged += PropertyTypesChanged;
return true;
}
return false;
}
/// <summary>
/// Moves a PropertyType to a specified PropertyGroup
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType to move</param>
/// <param name="propertyGroupName">Name of the PropertyGroup to move the PropertyType to</param>
/// <returns></returns>
public bool MovePropertyType(string propertyTypeAlias, string propertyGroupName)
{
if (PropertyTypes.Any(x => x.Alias == propertyTypeAlias) == false || PropertyGroups.Any(x => x.Name == propertyGroupName) == false)
return false;
var propertyType = PropertyTypes.First(x => x.Alias == propertyTypeAlias);
//The PropertyType already belongs to a PropertyGroup, so we have to remove the PropertyType from that group
if (PropertyGroups.Any(x => x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias)))
{
var oldPropertyGroup = PropertyGroups.First(x => x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias));
oldPropertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
}
propertyType.PropertyGroupId = new Lazy<int>(() => default(int));
propertyType.ResetDirtyProperties();
var propertyGroup = PropertyGroups.First(x => x.Name == propertyGroupName);
propertyGroup.PropertyTypes.Add(propertyType);
return true;
}
/// <summary>
/// Removes a PropertyType from the current ContentType
/// </summary>
@@ -333,6 +400,11 @@ namespace Umbraco.Core.Models
{
propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
}
if (_propertyTypes.Any(x => x.Alias == propertyTypeAlias))
{
_propertyTypes.RemoveItem(propertyTypeAlias);
}
}
/// <summary>
@@ -343,9 +415,5 @@ namespace Umbraco.Core.Models
{
_parentId = id;
}
//TODO Implement moving PropertyType between groups.
/*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName)
{}*/
}
}
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
{
private readonly List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
internal List<int> RemovedContentTypeKeyTracker = new List<int>();
protected ContentTypeCompositionBase(int parentId) : base(parentId)
{
@@ -44,7 +45,7 @@ namespace Umbraco.Core.Models
{
get
{
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
var groups = ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups).Union(PropertyGroups);
return groups;
}
}
@@ -57,8 +58,7 @@ namespace Umbraco.Core.Models
{
get
{
var propertyTypes =
PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
var propertyTypes = ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes).Union(PropertyTypes);
return propertyTypes;
}
}
@@ -89,9 +89,11 @@ namespace Umbraco.Core.Models
/// <returns>True if ContentType was removed, otherwise returns False</returns>
public bool RemoveContentType(string alias)
{
if (!ContentTypeCompositionExists(alias))
if (ContentTypeCompositionExists(alias))
{
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
RemovedContentTypeKeyTracker.Add(contentTypeComposition.Id);
OnPropertyChanged(ContentTypeCompositionSelector);
return _contentTypeComposition.Remove(contentTypeComposition);
}
return false;
@@ -113,6 +115,83 @@ namespace Umbraco.Core.Models
return false;
}
/// <summary>
/// Checks whether a PropertyType with a given alias already exists
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
public override bool PropertyTypeExists(string propertyTypeAlias)
{
return CompositionPropertyTypes.Any(x => x.Alias == propertyTypeAlias);
}
/// <summary>
/// Adds a PropertyGroup.
/// This method will also check if a group already exists with the same name and link it to the parent.
/// </summary>
/// <param name="groupName">Name of the PropertyGroup to add</param>
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
public override bool AddPropertyGroup(string groupName)
{
if (PropertyGroups.Any(x => x.Name == groupName))
return false;
var propertyGroup = new PropertyGroup {Name = groupName, SortOrder = 0};
if (CompositionPropertyGroups.Any(x => x.Name == groupName))
{
var firstGroup = CompositionPropertyGroups.First(x => x.Name == groupName && x.ParentId.HasValue == false);
propertyGroup.SetLazyParentId(new Lazy<int?>(() => firstGroup.Id));
}
if (PropertyGroups.Any())
{
var last = PropertyGroups.Last();
propertyGroup.SortOrder = last.SortOrder + 1;
}
PropertyGroups.Add(propertyGroup);
return true;
}
/// <summary>
/// Adds a PropertyType to a specific PropertyGroup
/// </summary>
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
public override bool AddPropertyType(PropertyType propertyType, string propertyGroupName)
{
if (PropertyTypeExists(propertyType.Alias) == false)
{
if (PropertyGroups.Contains(propertyGroupName))
{
propertyType.PropertyGroupId = new Lazy<int>(() => PropertyGroups[propertyGroupName].Id);
PropertyGroups[propertyGroupName].PropertyTypes.Add(propertyType);
}
else
{
//If the PropertyGroup doesn't already exist we create a new one
var propertyTypes = new List<PropertyType> { propertyType };
var propertyGroup = new PropertyGroup(new PropertyTypeCollection(propertyTypes)) { Name = propertyGroupName, SortOrder = 1 };
//and check if its an inherited PropertyGroup, which exists in the composition
if (CompositionPropertyGroups.Any(x => x.Name == propertyGroupName))
{
var parentPropertyGroup = CompositionPropertyGroups.First(x => x.Name == propertyGroupName && x.ParentId.HasValue == false);
propertyGroup.SortOrder = parentPropertyGroup.SortOrder;
//propertyGroup.ParentId = parentPropertyGroup.Id;
propertyGroup.SetLazyParentId(new Lazy<int?>(() => parentPropertyGroup.Id));
}
PropertyGroups.Add(propertyGroup);
}
return true;
}
return false;
}
/// <summary>
/// Gets a list of ContentType aliases from the current composition
/// </summary>
@@ -8,6 +8,17 @@ namespace Umbraco.Core.Models
/// </summary>
public class ContentTypeSort : IValueObject
{
public ContentTypeSort()
{
}
public ContentTypeSort(Lazy<int> id, int sortOrder, string @alias)
{
Id = id;
SortOrder = sortOrder;
Alias = alias;
}
/// <summary>
/// Gets or sets the Id of the ContentType
/// </summary>
@@ -15,12 +15,12 @@ namespace Umbraco.Core.Models
public enum DataTypeDatabaseType
{
[EnumMember]
Integer,
[EnumMember]
Date,
Ntext,
[EnumMember]
Nvarchar,
[EnumMember]
Ntext /*, Object*/
Integer,
[EnumMember]
Date
}
}
@@ -172,7 +172,9 @@ namespace Umbraco.Core.Models
internal override void AddingEntity()
{
base.AddingEntity();
Key = Guid.NewGuid();
if(Key == default(Guid))
Key = Guid.NewGuid();
}
}
}
@@ -66,6 +66,15 @@ namespace Umbraco.Core.Models.EntityBase
[DataMember]
public DateTime UpdateDate { get; set; }
/// <summary>
/// Gets or sets the WasCancelled flag, which is used to track
/// whether some action against an entity was cancelled through some event.
/// This only exists so we have a way to check if an event was cancelled through
/// the new api, which also needs to take effect in the legacy api.
/// </summary>
[IgnoreDataMember]
internal bool WasCancelled { get; set; }
/// <summary>
/// Property changed event
/// </summary>
@@ -69,5 +69,43 @@ namespace Umbraco.Core.Models
/// </summary>
/// <param name="id">Id of the Parent</param>
void SetLazyParentId(Lazy<int> id);
/// <summary>
/// Checks whether a PropertyType with a given alias already exists
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
bool PropertyTypeExists(string propertyTypeAlias);
/// <summary>
/// Adds a PropertyType to a specific PropertyGroup
/// </summary>
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
bool AddPropertyType(PropertyType propertyType, string propertyGroupName);
/// <summary>
/// Adds a PropertyType, which does not belong to a PropertyGroup.
/// </summary>
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
bool AddPropertyType(PropertyType propertyType);
/// <summary>
/// Adds a PropertyGroup.
/// This method will also check if a group already exists with the same name and link it to the parent.
/// </summary>
/// <param name="groupName">Name of the PropertyGroup to add</param>
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
bool AddPropertyGroup(string groupName);
/// <summary>
/// Moves a PropertyType to a specified PropertyGroup
/// </summary>
/// <param name="propertyTypeAlias">Alias of the PropertyType to move</param>
/// <param name="propertyGroupName">Name of the PropertyGroup to move the PropertyType to</param>
/// <returns></returns>
bool MovePropertyType(string propertyTypeAlias, string propertyGroupName);
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.Membership
int SessionTimeout { get; set; }
int StartContentId { get; set; }
int StartMediaId { get; set; }
string Lanuguage { get; set; }
string Language { get; set; }
bool DefaultToLiveEditing { get; set; }
IEnumerable<string> Applications { get; set; }
bool NoConsole { get; set; }
+1 -1
View File
@@ -88,7 +88,7 @@ namespace Umbraco.Core.Models.Membership
#region Implementation of IUser
[DataMember]
public string Lanuguage { get; set; }
public string Language { get; set; }
[DataMember]
public string Permissions { get; set; }
[DataMember]
@@ -19,6 +19,14 @@ namespace Umbraco.Core.Models
var xd = new XmlDocument();
XmlNode xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
//Add the property alias to the legacy schema
if (UmbracoSettings.UseLegacyXmlSchema)
{
var alias = xd.CreateAttribute("alias");
alias.Value = property.Alias.ToSafeAlias();
xmlNode.Attributes.Append(alias);
}
//This seems to fail during testing
xmlNode.AppendChild(property.PropertyType.DataType(property.Id).Data.ToXMl(xd));
+22 -4
View File
@@ -14,7 +14,7 @@ namespace Umbraco.Core.Models
public class PropertyGroup : Entity, IEquatable<PropertyGroup>
{
private string _name;
private int? _parentId;
private Lazy<int?> _parentId;
private int _sortOrder;
private PropertyTypeCollection _propertyTypes;
@@ -51,15 +51,24 @@ namespace Umbraco.Core.Models
}
/// <summary>
/// Gets or sets the Name of the Group, which corresponds to the Tab-name in the UI
/// Gets or sets the Id of the Parent PropertyGroup.
/// </summary>
/// <remarks>
/// A Parent PropertyGroup corresponds to an inherited PropertyGroup from a composition.
/// If a PropertyType is inserted into an inherited group then a new group will be created with an Id reference to the parent.
/// </remarks>
[DataMember]
public int? ParentId
{
get { return _parentId; }
get
{
if (_parentId == null)
return default(int?);
return _parentId.Value;
}
set
{
_parentId = value;
_parentId = new Lazy<int?>(() => value);
OnPropertyChanged(ParentIdSelector);
}
}
@@ -92,6 +101,15 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Sets the ParentId from the lazy integer id
/// </summary>
/// <param name="id">Id of the Parent</param>
internal void SetLazyParentId(Lazy<int?> id)
{
_parentId = id;
}
public bool Equals(PropertyGroup other)
{
//Check whether the compared object is null.
+5 -5
View File
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Models
private string _alias;
private string _description;
private int _dataTypeDefinitionId;
private int _propertyGroupId;
private Lazy<int> _propertyGroupId;
private Guid _dataTypeId;
private DataTypeDatabaseType _dataTypeDatabaseType;
private bool _mandatory;
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo HelpTextSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.HelpText);
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.SortOrder);
private static readonly PropertyInfo ValidationRegExpSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.ValidationRegExp);
private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.PropertyGroupId);
private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, Lazy<int>>(x => x.PropertyGroupId);
/// <summary>
/// Gets of Sets the Name of the PropertyType
@@ -153,7 +153,7 @@ namespace Umbraco.Core.Models
/// Gets or Sets the PropertyGroup's Id for which this PropertyType belongs
/// </summary>
[DataMember]
internal int PropertyGroupId
internal Lazy<int> PropertyGroupId
{
get { return _propertyGroupId; }
set
@@ -335,8 +335,8 @@ namespace Umbraco.Core.Models
if (Mandatory && (value == null || string.IsNullOrEmpty(value.ToString())))
return false;
//Check against Regular Expression for Legacy DataTypes
if(!string.IsNullOrEmpty(ValidationRegExp))
//Check against Regular Expression for Legacy DataTypes - Validation exists and value is not null:
if(string.IsNullOrEmpty(ValidationRegExp) == false && (value != null && string.IsNullOrEmpty(value.ToString()) == false))
{
var regexPattern = new Regex(ValidationRegExp);
return regexPattern.IsMatch(value.ToString());
+3 -3
View File
@@ -29,8 +29,8 @@ namespace Umbraco.Core.Models
base.Path = path;
ParentId = -1;
Key = name.EncodeAsGuid();
_name = name;
_alias = alias;
_name = name.Replace("/", ".").Replace("\\", "");
_alias = alias.ToSafeAlias();
CreateDate = DateTime.Now;
UpdateDate = DateTime.Now;
@@ -52,7 +52,7 @@ namespace Umbraco.Core.Models
internal string NodePath { get; set; }
[DataMember]
internal int MasterTemplateId { get; set; }
internal Lazy<int> MasterTemplateId { get; set; }
[DataMember]
internal string MasterTemplateAlias { get; set; }
@@ -8,27 +8,49 @@ namespace Umbraco.Core.ObjectResolution
/// <summary>
/// A resolver to return all IApplicationEvents objects
/// </summary>
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationEventHandler>
{
/// <summary>
private readonly LegacyStartupHandlerResolver _legacyResolver;
/// <summary>
/// Constructor
/// </summary>
/// <param name="applicationEventHandlers"></param>
internal ApplicationEventsResolver(IEnumerable<Type> applicationEventHandlers)
: base(applicationEventHandlers)
{
//create the legacy resolver and only include the legacy types
_legacyResolver = new LegacyStartupHandlerResolver(
applicationEventHandlers.Where(x => !TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>(x)));
}
/// <summary>
/// <summary>
/// Override in order to only return types of IApplicationEventHandler and above,
/// do not include the legacy types of IApplicationStartupHandler
/// </summary>
protected override IEnumerable<Type> InstanceTypes
{
get { return base.InstanceTypes.Where(TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>); }
}
/// <summary>
/// Gets the <see cref="IApplicationEventHandler"/> implementations.
/// </summary>
public IEnumerable<IApplicationEventHandler> ApplicationEventHandlers
{
get { return Values.OfType<IApplicationEventHandler>(); }
get { return Values; }
}
/// <summary>
/// Create instances of all of the legacy startup handlers
/// </summary>
public void InstantiateLegacyStartupHanlders()
{
//this will instantiate them all
var handlers = _legacyResolver.LegacyStartupHandlers;
}
protected override bool SupportsClear
{
get { return false; }
@@ -44,5 +66,19 @@ namespace Umbraco.Core.ObjectResolution
get { return false; }
}
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
{
internal LegacyStartupHandlerResolver(IEnumerable<Type> legacyStartupHandlers)
: base(legacyStartupHandlers)
{
}
public IEnumerable<IApplicationStartupHandler> LegacyStartupHandlers
{
get { return Values; }
}
}
}
}
@@ -0,0 +1,235 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
namespace Umbraco.Core.ObjectResolution
{
/// <summary>
/// A base class for lazily resolving types for a resolver
/// </summary>
/// <typeparam name="TResolver"></typeparam>
/// <typeparam name="TResolved"></typeparam>
/// <remarks>
/// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
/// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
/// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances.
///
/// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless
/// the types are marked with the WeightedPluginAttribute.
/// </remarks>
internal abstract class LazyManyObjectsResolverBase<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
where TResolved : class
where TResolver : class
{
#region Constructors
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: base(scope)
{
}
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
: base(httpContext)
{
}
/// <summary>
/// Constructor accepting a list of lazy types
/// </summary>
/// <param name="listOfLazyTypes"></param>
/// <param name="scope"></param>
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
AddTypes(listOfLazyTypes);
}
/// <summary>
/// Constructor accepting a delegate to return a list of types
/// </summary>
/// <param name="typeListDelegate"></param>
/// <param name="scope"></param>
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
/// <summary>
/// Constructor accepting a list of lazy types
/// </summary>
/// <param name="httpContext"></param>
/// <param name="listOfLazyTypes"></param>
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> listOfLazyTypes)
: this(httpContext)
{
AddTypes(listOfLazyTypes);
}
/// <summary>
/// Constructor accepting a delegate to return a list of types
/// </summary>
/// <param name="httpContext"></param>
/// <param name="typeListDelegate"></param>
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListDelegate)
: this(httpContext)
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
#endregion
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
private readonly List<Func<IEnumerable<Type>>> _listOfTypeListDelegates = new List<Func<IEnumerable<Type>>>();
private List<Type> _resolvedTypes = null;
private readonly ReaderWriterLockSlim _typeResolutionLock = new ReaderWriterLockSlim();
/// <summary>
/// Used for unit tests
/// </summary>
internal bool HasResolvedTypes
{
get { return _resolvedTypes != null; }
}
/// <summary>
/// Once this is called this will resolve all types registered in the lazy list
/// </summary>
protected override IEnumerable<Type> InstanceTypes
{
get
{
using (var lck = new UpgradeableReadLock(_typeResolutionLock))
{
var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
//we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
if (!HasResolvedTypes)
{
lck.UpgradeToWriteLock();
_resolvedTypes = new List<Type>();
//first iterate the lazy type list
foreach (var l in lazyTypeList)
{
UpdateUniqueList(_resolvedTypes, l);
}
//next iterate the list of list type delegates
foreach (var l in listofTypeListDelegates)
{
UpdateUniqueList(_resolvedTypes, l);
}
}
return _resolvedTypes;
}
}
}
private void UpdateUniqueList(List<Type> uniqueList, Type toAdd)
{
EnsureCorrectType(toAdd);
if (uniqueList.Contains(toAdd))
{
throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
}
uniqueList.Add(toAdd);
}
/// <summary>
/// Allows adding of multiple lazy types at once
/// </summary>
/// <param name="types"></param>
protected void AddTypes(IEnumerable<Lazy<Type>> types)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
foreach (var t in types)
{
_lazyTypeList.Add(t);
}
}
}
/// <summary>
/// Adds a type list delegate to the collection
/// </summary>
/// <param name="typeListDelegate"></param>
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListDelegate)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_listOfTypeListDelegates.Add(typeListDelegate);
}
}
/// <summary>
/// Adds a lazy type to the list
/// </summary>
/// <param name="value"></param>
public void AddType(Lazy<Type> value)
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_lazyTypeList.Add(value);
}
}
/// <summary>
/// Converts the static type added to a lazy type and adds it to the internal list
/// </summary>
/// <param name="value"></param>
public override void AddType(Type value)
{
AddType(new Lazy<Type>(() => value));
}
/// <summary>
/// Clears all lazy types
/// </summary>
public override void Clear()
{
EnsureClearSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
_lazyTypeList.Clear();
}
}
/// <summary>
/// Does not support removal
/// </summary>
protected override bool SupportsRemove
{
get { return false; }
}
/// <summary>
/// Does not support insert
/// </summary>
protected override bool SupportsInsert
{
get { return false; }
}
}
}
@@ -17,7 +17,7 @@ namespace Umbraco.Core.ObjectResolution
/// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this
/// for use in the GetById method.
/// </remarks>
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : LazyManyObjectsResolverBase<TResolver, TResolved>
where TResolved : class
where TResolver : class
{
@@ -27,16 +27,15 @@ namespace Umbraco.Core.ObjectResolution
/// <summary>
/// Constructor
/// </summary>
/// <param name="refreshers"></param>
/// <param name="types"></param>
/// <remarks>
/// We are creating Transient instances (new instances each time) because this is how the legacy code worked and
/// I don't want to muck anything up by changing them to application based instances.
/// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier.
/// </remarks>
protected LegacyTransientObjectsResolver(IEnumerable<Type> refreshers)
: base(ObjectLifetimeScope.Transient) // new objects every time
{
AddTypes(refreshers);
protected LegacyTransientObjectsResolver(Func<IEnumerable<Type>> types)
: base(types, ObjectLifetimeScope.Transient) // new objects every time
{
}
#endregion
@@ -55,7 +54,7 @@ namespace Umbraco.Core.ObjectResolution
protected abstract Guid GetUniqueIdentifier(TResolved obj);
/// <summary>
/// Returns a new ICacheRefresher instance by id
/// Returns a new TResolved instance by id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using Umbraco.Core.Macros;
@@ -14,14 +15,14 @@ namespace Umbraco.Core.ObjectResolution
/// Much of this classes methods are based on legacy code from umbraco.editorControls.macrocontainer.MacroControlFactory
/// this code should probably be reviewed and cleaned up if necessary.
/// </remarks>
internal sealed class MacroFieldEditorsResolver : ManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
internal sealed class MacroFieldEditorsResolver : LazyManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="macroEditors"></param>
internal MacroFieldEditorsResolver(IEnumerable<Type> macroEditors)
internal MacroFieldEditorsResolver(Func<IEnumerable<Type>> macroEditors)
: base(macroEditors, ObjectLifetimeScope.Transient)
{
@@ -56,7 +57,7 @@ namespace Umbraco.Core.ObjectResolution
/// </remarks>
internal List<Type> MacroControlTypes
{
get { return InstanceTypes; }
get { return InstanceTypes.ToList(); }
}
/// <summary>
@@ -6,14 +6,14 @@ using System.Web;
namespace Umbraco.Core.ObjectResolution
{
internal abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
where TResolved : class
where TResolver : class
{
private List<TResolved> _applicationInstances = null;
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
private readonly List<Type> _instanceTypes = new List<Type>();
#region Constructors
@@ -34,7 +34,7 @@ namespace Umbraco.Core.ObjectResolution
}
LifetimeScope = scope;
InstanceTypes = new List<Type>();
_instanceTypes = new List<Type>();
}
/// <summary>
@@ -48,7 +48,7 @@ namespace Umbraco.Core.ObjectResolution
if (httpContext == null) throw new ArgumentNullException("httpContext");
LifetimeScope = ObjectLifetimeScope.HttpRequest;
CurrentHttpContext = httpContext;
InstanceTypes = new List<Type>();
_instanceTypes = new List<Type>();
}
/// <summary>
@@ -58,8 +58,8 @@ namespace Umbraco.Core.ObjectResolution
/// <param name="scope">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
protected ManyObjectsResolverBase(IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
: this(scope)
{
InstanceTypes = new List<Type>(value);
{
_instanceTypes = new List<Type>(value);
}
/// <summary>
@@ -71,7 +71,7 @@ namespace Umbraco.Core.ObjectResolution
protected ManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Type> value)
: this(httpContext)
{
InstanceTypes = new List<Type>(value);
_instanceTypes = new List<Type>(value);
}
#endregion
@@ -83,7 +83,10 @@ namespace Umbraco.Core.ObjectResolution
/// <summary>
/// Returns the list of Types registered that instances will be created from
/// </summary>
protected List<Type> InstanceTypes { get; private set; }
protected virtual IEnumerable<Type> InstanceTypes
{
get { return _instanceTypes; }
}
/// <summary>
/// Returns the Current HttpContextBase used to construct this object if one exists.
@@ -97,11 +100,7 @@ namespace Umbraco.Core.ObjectResolution
protected ObjectLifetimeScope LifetimeScope { get; private set; }
private int _defaultPluginWeight = 10;
private bool _supportsAdd = true;
private bool _supportsInsert = true;
private bool _supportsClear = true;
private bool _supportsRemove = true;
/// <summary>
/// Used in conjunction with GetSortedValues and WeightedPluginAttribute, if any of the objects
/// being resolved do not contain the WeightedPluginAttribute then this will be the default weight applied
@@ -189,15 +188,16 @@ namespace Umbraco.Core.ObjectResolution
/// Removes a type.
/// </summary>
/// <param name="value">The type to remove.</param>
public void RemoveType(Type value)
public virtual void RemoveType(Type value)
{
if (!SupportsRemove)
throw new InvalidOperationException("This resolver does not support Removing types");
EnsureRemoveSupport();
using (new WriteLock(_lock))
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
EnsureCorrectType(value);
InstanceTypes.Remove(value);
_instanceTypes.Remove(value);
}
}
@@ -215,8 +215,12 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="types"></param>
protected void AddTypes(IEnumerable<Type> types)
{
using (var l = new WriteLock(_lock))
{
EnsureAddSupport();
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
foreach(var t in types)
{
@@ -225,7 +229,7 @@ namespace Umbraco.Core.ObjectResolution
{
throw new InvalidOperationException("The Type " + t + " already exists in the collection");
};
InstanceTypes.Add(t);
_instanceTypes.Add(t);
}
}
}
@@ -234,19 +238,20 @@ namespace Umbraco.Core.ObjectResolution
/// Adds a Type to the end of the list.
/// </summary>
/// <param name="value">The object to be added.</param>
public void AddType(Type value)
public virtual void AddType(Type value)
{
if (!SupportsAdd)
throw new InvalidOperationException("This resolver does not support Adding new types");
EnsureAddSupport();
using (var l = new WriteLock(_lock))
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
EnsureCorrectType(value);
if (InstanceTypes.Contains(value))
{
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
};
InstanceTypes.Add(value);
_instanceTypes.Add(value);
}
}
@@ -262,14 +267,15 @@ namespace Umbraco.Core.ObjectResolution
/// <summary>
/// Clears the list.
/// </summary>
public void Clear()
public virtual void Clear()
{
if (!SupportsClear)
throw new InvalidOperationException("This resolver does not support Clearing types");
EnsureClearSupport();
using (new WriteLock(_lock))
EnsureResolutionNotFrozen();
using (GetWriteLock())
{
InstanceTypes.Clear();
_instanceTypes.Clear();
}
}
@@ -278,12 +284,13 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="index">The zero-based index at which the object should be inserted.</param>
/// <param name="value">The object to insert.</param>
public void InsertType(int index, Type value)
public virtual void InsertType(int index, Type value)
{
if (!SupportsInsert)
throw new InvalidOperationException("This resolver does not support Inserting new types");
EnsureInsertSupport();
using (var l = new UpgradeableReadLock(_lock))
EnsureResolutionNotFrozen();
using (var l = GetWriteLock())
{
EnsureCorrectType(value);
if (InstanceTypes.Contains(value))
@@ -291,8 +298,7 @@ namespace Umbraco.Core.ObjectResolution
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
};
l.UpgradeToWriteLock();
InstanceTypes.Insert(index, value);
_instanceTypes.Insert(index, value);
}
}
@@ -306,7 +312,65 @@ namespace Umbraco.Core.ObjectResolution
InsertType(index, typeof (T));
}
private void EnsureCorrectType(Type t)
/// <summary>
/// Returns a WriteLock to use when modifying collections
/// </summary>
/// <returns></returns>
protected WriteLock GetWriteLock()
{
return new WriteLock(_lock);
}
/// <summary>
/// Throws an exception if resolution is frozen
/// </summary>
protected void EnsureResolutionNotFrozen()
{
if (Resolution.IsFrozen)
throw new InvalidOperationException("The type list cannot be modified after resolution has been frozen");
}
/// <summary>
/// Throws an exception if this does not support Remove
/// </summary>
protected void EnsureRemoveSupport()
{
if (!SupportsRemove)
throw new InvalidOperationException("This resolver does not support Removing types");
}
/// <summary>
/// Throws an exception if this does not support Clear
/// </summary>
protected void EnsureClearSupport()
{
if (!SupportsClear)
throw new InvalidOperationException("This resolver does not support Clearing types");
}
/// <summary>
/// Throws an exception if this does not support Add
/// </summary>
protected void EnsureAddSupport()
{
if (!SupportsAdd)
throw new InvalidOperationException("This resolver does not support Adding new types");
}
/// <summary>
/// Throws an exception if this does not support insert
/// </summary>
protected void EnsureInsertSupport()
{
if (!SupportsInsert)
throw new InvalidOperationException("This resolver does not support Inserting new types");
}
/// <summary>
/// Throws an exception if the type is not of the TResolved type
/// </summary>
/// <param name="t"></param>
protected void EnsureCorrectType(Type t)
{
if (!TypeHelper.IsTypeAssignableFrom<TResolved>(t))
throw new InvalidOperationException("The resolver " + this.GetType() + " can only accept types of " + typeof(TResolved) + ". The Type passed in to this method is " + t);
@@ -314,22 +378,22 @@ namespace Umbraco.Core.ObjectResolution
protected virtual bool SupportsAdd
{
get { return _supportsAdd; }
get { return true; }
}
protected virtual bool SupportsInsert
{
get { return _supportsInsert; }
get { return true; }
}
protected virtual bool SupportsClear
{
get { return _supportsClear; }
get { return true; }
}
protected virtual bool SupportsRemove
{
get { return _supportsRemove; }
get { return true; }
}
}
}
+2 -2
View File
@@ -8,14 +8,14 @@ namespace Umbraco.Core
/// <summary>
/// A resolver to return all IPackageAction objects
/// </summary>
internal sealed class PackageActionsResolver : ManyObjectsResolverBase<PackageActionsResolver, IPackageAction>
internal sealed class PackageActionsResolver : LazyManyObjectsResolverBase<PackageActionsResolver, IPackageAction>
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="packageActions"></param>
internal PackageActionsResolver(IEnumerable<Type> packageActions)
internal PackageActionsResolver(Func<IEnumerable<Type>> packageActions)
: base(packageActions)
{
@@ -0,0 +1,34 @@
using System;
using System.Threading;
using Umbraco.Core.Configuration;
namespace Umbraco.Core.Persistence
{
/// <summary>
/// Provides access to the PetaPoco database as Singleton, so the database is created once in app lifecycle.
/// This is necessary for transactions to work properly
/// </summary>
public sealed class DatabaseFactory
{
#region Singleton
private static readonly Database _database = new Database(GlobalSettings.DbDsn);
private static readonly Lazy<DatabaseFactory> lazy = new Lazy<DatabaseFactory>(() => new DatabaseFactory());
public static DatabaseFactory Current { get { return lazy.Value; } }
private DatabaseFactory()
{
}
#endregion
/// <summary>
/// Returns an instance of the PetaPoco database
/// </summary>
public Database Database
{
get { return _database; }
}
}
}
@@ -127,9 +127,8 @@ namespace Umbraco.Core.Persistence.Factories
private NodeDto BuildNodeDto(IContent entity)
{
//TODO: Change this once the Language property is public on IContent
var content = entity as Content;
var nodeName = content != null && string.IsNullOrEmpty(content.NodeName) == false ? content.NodeName : entity.Name;
//TODO: Change this once the Language property is public on IContent
var nodeName = entity.Name;
var nodeDto = new NodeDto
{
@@ -8,41 +8,34 @@ namespace Umbraco.Core.Persistence.Factories
{
internal class PropertyFactory : IEntityFactory<IEnumerable<Property>, IEnumerable<PropertyDataDto>>
{
private readonly IContentType _contentType;
private readonly IMediaType _mediaType;
private readonly IContentTypeComposition _contentType;
private readonly Guid _version;
private readonly int _id;
public PropertyFactory(IContentType contentType, Guid version, int id)
public PropertyFactory(IContentTypeComposition contentType, Guid version, int id)
{
_contentType = contentType;
_version = version;
_id = id;
}
public PropertyFactory(IMediaType mediaType, Guid version, int id)
{
_mediaType = mediaType;
_version = version;
_id = id;
}
#region Implementation of IEntityFactory<IContent,PropertyDataDto>
public IEnumerable<Property> BuildEntity(IEnumerable<PropertyDataDto> dtos)
{
var properties = new List<Property>();
foreach (var dto in dtos)
foreach (var propertyType in _contentType.CompositionPropertyTypes)
{
if (_contentType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
{
var propertyType = _contentType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
var propertyDataDto = dtos.LastOrDefault(x => x.PropertyTypeId == propertyType.Id);
var property = propertyDataDto == null
? propertyType.CreatePropertyFromValue(null)
: propertyType.CreatePropertyFromRawValue(propertyDataDto.GetValue,
propertyDataDto.VersionId.Value,
propertyDataDto.Id);
property.ResetDirtyProperties();
properties.Add(property);
}
property.ResetDirtyProperties();
properties.Add(property);
}
return properties;
@@ -97,22 +90,5 @@ namespace Umbraco.Core.Persistence.Factories
}
#endregion
public IEnumerable<Property> BuildMediaEntity(IEnumerable<PropertyDataDto> dtos)
{
var properties = new List<Property>();
foreach (var dto in dtos)
{
if (_mediaType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
{
var propertyType = _mediaType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
property.ResetDirtyProperties();
properties.Add(property);
}
}
return properties;
}
}
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
@@ -22,9 +23,21 @@ namespace Umbraco.Core.Persistence.Factories
foreach (var groupDto in dto)
{
var group = new PropertyGroup();
group.Id = groupDto.Id;
//Only assign an Id if the PropertyGroup belongs to this ContentType
if (groupDto.ContentTypeNodeId == _id)
{
group.Id = groupDto.Id;
if (groupDto.ParentGroupId.HasValue)
group.ParentId = groupDto.ParentGroupId.Value;
}
else
{
//If the PropertyGroup is inherited, we add a reference to the group as a Parent.
group.ParentId = groupDto.Id;
}
group.Name = groupDto.Text;
group.ParentId = groupDto.ParentGroupId;
group.SortOrder = groupDto.SortOrder;
group.PropertyTypes = new PropertyTypeCollection();
@@ -32,7 +45,8 @@ namespace Umbraco.Core.Persistence.Factories
var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0);
foreach (var typeDto in typeDtos)
{
group.PropertyTypes.Add(new PropertyType(typeDto.DataTypeDto.ControlId,
var tempGroupDto = groupDto;
var propertyType = new PropertyType(typeDto.DataTypeDto.ControlId,
typeDto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
{
Alias = typeDto.Alias,
@@ -43,9 +57,12 @@ namespace Umbraco.Core.Persistence.Factories
HelpText = typeDto.HelpText,
Mandatory = typeDto.Mandatory,
SortOrder = typeDto.SortOrder,
PropertyGroupId = groupDto.Id
});
ValidationRegExp = typeDto.ValidationRegExp,
PropertyGroupId = new Lazy<int>(() => tempGroupDto.Id)
};
propertyType.ResetDirtyProperties();
group.PropertyTypes.Add(propertyType);
}
group.ResetDirtyProperties();
propertyGroups.Add(group);
@@ -67,10 +84,12 @@ namespace Umbraco.Core.Persistence.Factories
{
ContentTypeNodeId = _id,
SortOrder = propertyGroup.SortOrder,
Text = propertyGroup.Name,
ParentGroupId = propertyGroup.ParentId
Text = propertyGroup.Name
};
if (propertyGroup.ParentId.HasValue)
dto.ParentGroupId = propertyGroup.ParentId.Value;
if (propertyGroup.HasIdentity)
dto.Id = propertyGroup.Id;
@@ -90,11 +109,18 @@ namespace Umbraco.Core.Persistence.Factories
HelpText = propertyType.HelpText,
Mandatory = propertyType.Mandatory,
Name = propertyType.Name,
SortOrder = propertyType.SortOrder
SortOrder = propertyType.SortOrder,
ValidationRegExp = propertyType.ValidationRegExp
};
if (tabId != default(int))
{
propertyTypeDto.PropertyTypeGroupId = tabId;
}
else
{
propertyTypeDto.PropertyTypeGroupId = null;
}
if (propertyType.HasIdentity)
propertyTypeDto.Id = propertyType.Id;
@@ -28,17 +28,22 @@ namespace Umbraco.Core.Persistence.Factories
public Template BuildEntity(TemplateDto dto)
{
return new Template(string.Empty, dto.NodeDto.Text, dto.Alias)
{
CreateDate = dto.NodeDto.CreateDate,
Id = dto.NodeId,
Key = dto.NodeDto.UniqueId.Value,
CreatorId = dto.NodeDto.UserId.Value,
Level = dto.NodeDto.Level,
ParentId = dto.NodeDto.ParentId,
SortOrder = dto.NodeDto.SortOrder,
NodePath = dto.NodeDto.Path
};
var template = new Template(string.Empty, dto.NodeDto.Text, dto.Alias)
{
CreateDate = dto.NodeDto.CreateDate,
Id = dto.NodeId,
Key = dto.NodeDto.UniqueId.Value,
CreatorId = dto.NodeDto.UserId.Value,
Level = dto.NodeDto.Level,
ParentId = dto.NodeDto.ParentId,
SortOrder = dto.NodeDto.SortOrder,
NodePath = dto.NodeDto.Path
};
if(dto.Master.HasValue)
template.MasterTemplateId = new Lazy<int>(() => dto.Master.Value);
return template;
}
public TemplateDto BuildDto(Template entity)
@@ -50,6 +55,11 @@ namespace Umbraco.Core.Persistence.Factories
NodeDto = BuildNodeDto(entity)
};
if (entity.MasterTemplateId != null && entity.MasterTemplateId.Value != default(int))
{
dto.Master = entity.MasterTemplateId.Value;
}
if (entity.HasIdentity)
{
dto.NodeId = entity.Id;
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Factories
IsLockedOut = dto.Disabled,
IsApproved = dto.Disabled == false,
Email = dto.Email,
Lanuguage = dto.UserLanguage,
Language = dto.UserLanguage,
DefaultToLiveEditing = dto.DefaultToLiveEditing,
NoConsole = dto.NoConsole,
Permissions = dto.DefaultPermissions
@@ -48,7 +48,7 @@ namespace Umbraco.Core.Persistence.Factories
Login = entity.Username,
NoConsole = entity.NoConsole,
Password = entity.Password,
UserLanguage = entity.Lanuguage,
UserLanguage = entity.Language,
UserName = entity.Name,
Type = short.Parse(entity.UserType.Id.ToString()),
DefaultPermissions = entity.Permissions
@@ -30,8 +30,8 @@ namespace Umbraco.Core.Persistence.Mappers
string columnName = columnAttribute.Name;
string columnMap = string.Format("{0}.{1}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
return columnMap;
}
}
@@ -0,0 +1,86 @@
using System;
using System.Reflection;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Mappers
{
internal class ModelDtoMapper : IMapper
{
public void GetTableInfo(Type t, TableInfo ti)
{ }
public bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn)
{
if (pi.DeclaringType == typeof(Content) || pi.DeclaringType == typeof(IContent))
{
switch (pi.Name)
{
case "Trashed":
columnName = "[umbracoNode].[trashed]";
return true;
case "ParentId":
columnName = "[umbracoNode].[parentID]";
return true;
case "UserId":
columnName = "[umbracoNode].[nodeUser]";
return true;
case "Level":
columnName = "[umbracoNode].[level]";
return true;
case "Path":
columnName = "[umbracoNode].[path]";
return true;
case "SortOrder":
columnName = "[umbracoNode].[sortOrder]";
return true;
case "NodeId":
columnName = "[umbracoNode].[id]";
return true;
case "Published":
columnName = "[cmsDocument].[published]";
return true;
case "Key":
columnName = "[umbracoNode].[uniqueID]";
return true;
case "CreateDate":
columnName = "[umbracoNode].[createDate]";
return true;
case "Name":
columnName = "[umbracoNode].[text]";
return true;
}
}
if (pi.DeclaringType == typeof(ContentType) || pi.DeclaringType == typeof(IContentType))
{
switch (pi.Name)
{
case "Alias":
columnName = "[cmsContentType].[alias]";
return true;
case "Icon":
columnName = "[cmsContentType].[icon]";
return true;
case "Thumbnail":
columnName = "[cmsContentType].[thumbnail]";
return true;
case "Description":
columnName = "[cmsContentType].[description]";
return true;
}
}
return true;
}
public Func<object, object> GetFromDbConverter(PropertyInfo pi, Type sourceType)
{
return null;
}
public Func<object, object> GetToDbConverter(Type sourceType)
{
return null;
}
}
}
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Mappers
CacheMap<User, UserDto>(src => src.IsApproved, dto => dto.Disabled);
CacheMap<User, UserDto>(src => src.NoConsole, dto => dto.NoConsole);
CacheMap<User, UserDto>(src => src.UserType, dto => dto.Type);
CacheMap<User, UserDto>(src => src.Lanuguage, dto => dto.UserLanguage);
CacheMap<User, UserDto>(src => src.Language, dto => dto.UserLanguage);
}
internal override string Map(string propertyName)
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
}
//Check tables in configured database against tables in schema
var tablesInDatabase = SyntaxConfig.SqlSyntaxProvider.GetTablesInSchema(_database).ToList();
var tablesInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetTablesInSchema(_database).ToList();
var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList();
//Add valid and invalid table differences to the result object
var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema);
@@ -117,7 +117,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
}
//Check columns in configured database against columns in schema
var columnsInDatabase = SyntaxConfig.SqlSyntaxProvider.GetColumnsInSchema(_database);
var columnsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(_database);
var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList();
var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList();
//Add valid and invalid column differences to the result object
@@ -134,11 +134,11 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
//MySql doesn't conform to the "normal" naming of constraints, so there is currently no point in doing these checks.
//NOTE: At a later point we do other checks for MySql, but ideally it should be necessary to do special checks for different providers.
if (SyntaxConfig.SqlSyntaxProvider is MySqlSyntaxProvider)
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider)
return result;
//Check constraints in configured database against constraints in schema
var constraintsInDatabase = SyntaxConfig.SqlSyntaxProvider.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList();
var constraintsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList();
var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("FK_")).Select(x => x.Item3).ToList();
var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("PK_")).Select(x => x.Item3).ToList();
var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("IX_")).Select(x => x.Item3).ToList();
@@ -42,8 +42,10 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
if(ValidTables.Count == 0)
return new Version(0, 0, 0);
//If Errors is empty then we're at current version
if (Errors.Any() == false)
//If Errors is empty or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version
if (Errors.Any() == false ||
TableDefinitions.Any(x => ValidTables.Contains(x.Name) == false) == false &&
TableDefinitions.SelectMany(definition => definition.Columns).Any(x => ValidColumns.Contains(x.Name) == false) == false)
return UmbracoVersion.Current;
//If Errors contains umbracoApp or umbracoAppTree its pre-6.0.0 -> new Version(4, 10, 0);
@@ -64,7 +66,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
return new Version(4, 9, 0);
}
return new Version(0, 0, 0);
return UmbracoVersion.Current;
}
/// <summary>
@@ -109,7 +111,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
sb.AppendLine(" ");
}
if (SyntaxConfig.SqlSyntaxProvider is MySqlSyntaxProvider)
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider)
{
sb.AppendLine("Please note that the constraints could not be validated because the current dataprovider is MySql.");
}
@@ -105,7 +105,7 @@ namespace Umbraco.Core.Persistence.Migrations
migrationAttribute.TargetVersion > _configuredVersion &&
migrationAttribute.TargetVersion <= _targetVersion &&
migrationAttribute.ProductName == _productName
orderby migrationAttribute.SortOrder ascending
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending
select migration);
return migrations;
}
@@ -119,7 +119,8 @@ namespace Umbraco.Core.Persistence.Migrations
migrationAttribute.TargetVersion > _configuredVersion &&
migrationAttribute.TargetVersion <= _targetVersion &&
migrationAttribute.ProductName == _productName
orderby migrationAttribute.SortOrder descending
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending
select migration);
return migrations;
}
@@ -21,9 +21,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
public override string ToString()
{
return string.Format(SyntaxConfig.SqlSyntaxProvider.AlterColumn,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(Column.Name));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name));
}
}
}
@@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
{
//NOTE Should probably investigate if Deleting a Default Constraint is different from deleting a 'regular' constraint
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ConstraintName));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ConstraintName));
}
}
}
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
{
var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE";
if (Constraint.IsPrimaryKeyConstraint && SyntaxConfig.SqlSyntaxProvider.SupportsClustered())
if (Constraint.IsPrimaryKeyConstraint && SqlSyntaxContext.SqlSyntaxProvider.SupportsClustered())
constraintType += " CLUSTERED";
if (Constraint.IsNonUniqueConstraint)
@@ -27,12 +27,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
for (int i = 0; i < Constraint.Columns.Count; i++)
{
columns[i] = SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(Constraint.Columns.ElementAt(i));
columns[i] = SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Constraint.Columns.ElementAt(i));
}
return string.Format(SyntaxConfig.SqlSyntaxProvider.CreateConstraint,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName),
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.CreateConstraint,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName),
constraintType,
string.Join(", ", columns));
}
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
{
var table = new TableDefinition{Name = TableName, SchemaName = SchemaName, Columns = Columns};
return string.Format(SyntaxConfig.SqlSyntaxProvider.Format(table));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.Format(table));
}
}
}
@@ -31,9 +31,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
foreach (string columnName in ColumnNames)
{
if (ColumnNames.First() != columnName) sb.AppendLine(";");
sb.AppendFormat(SyntaxConfig.SqlSyntaxProvider.DropColumn,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
sb.AppendFormat(SqlSyntaxContext.SqlSyntaxProvider.DropColumn,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
}
return sb.ToString();
@@ -14,9 +14,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
public override string ToString()
{
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName));
}
}
}
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
if (IsAllRows)
{
deleteItems.Add(string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteData, SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), "1 = 1"));
deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData, SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName), "1 = 1"));
}
else
{
@@ -42,13 +42,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
foreach (KeyValuePair<string, object> item in row)
{
whereClauses.Add(string.Format("{0} {1} {2}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
item.Value == null ? "IS" : "=",
SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
}
deleteItems.Add(string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteData,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
String.Join(" AND ", whereClauses.ToArray())));
}
}
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
if (IsExpressionSupported() == false)
return string.Empty;
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteDefaultConstraint,
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteDefaultConstraint,
TableName,
ColumnName);
}
@@ -33,10 +33,10 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
if (string.IsNullOrEmpty(ForeignKey.Name))
ForeignKey.Name = string.Format("{0}_ibfk_1", ForeignKey.ForeignTable.ToLower());
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
"FOREIGN KEY ",
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
}
if (string.IsNullOrEmpty(ForeignKey.Name))
@@ -44,9 +44,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
ForeignKey.Name = string.Format("FK_{0}_{1}", ForeignKey.ForeignTable, ForeignKey.PrimaryTable);
}
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
}
}
}
@@ -19,9 +19,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
public override string ToString()
{
return string.Format(SyntaxConfig.SqlSyntaxProvider.DropIndex,
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Index.Name),
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Index.TableName));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DropIndex,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Index.Name),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Index.TableName));
}
}
}
@@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
public override string ToString()
{
return string.Format(SyntaxConfig.SqlSyntaxProvider.DropTable,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DropTable,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName));
}
}
}
@@ -1,4 +1,5 @@
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
using System;
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
{
@@ -21,5 +22,14 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
_databaseProviders) {SqlStatement = sqlStatement};
_context.Expressions.Add(expression);
}
public void Code(Func<Database, string> codeStatement)
{
var expression = _databaseProviders == null
? new ExecuteCodeStatementExpression { CodeStatement = codeStatement }
: new ExecuteCodeStatementExpression(_context.CurrentDatabaseProvider,
_databaseProviders) { CodeStatement = codeStatement };
_context.Expressions.Add(expression);
}
}
}
@@ -0,0 +1,26 @@
using System;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions
{
public class ExecuteCodeStatementExpression : MigrationExpressionBase
{
public ExecuteCodeStatementExpression()
{
}
public ExecuteCodeStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
: base(current, databaseProviders)
{
}
public virtual Func<Database, string> CodeStatement { get; set; }
public override string Process(Database database)
{
if(CodeStatement != null)
return CodeStatement(database);
return base.Process(database);
}
}
}
@@ -1,7 +1,10 @@
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
using System;
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
{
public interface IExecuteBuilder : IFluentSyntax
{
void Sql(string sqlStatement);
void Code(Func<Database, string> codeStatement);
}
}
@@ -28,9 +28,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
if (string.IsNullOrEmpty(Column.TableName))
Column.TableName = TableName;
return string.Format(SyntaxConfig.SqlSyntaxProvider.AddColumn,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Column.TableName),
SyntaxConfig.SqlSyntaxProvider.Format(Column));
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AddColumn,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Column.TableName),
SqlSyntaxContext.SqlSyntaxProvider.Format(Column));
}
}
}
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
if (IsExpressionSupported() == false)
return string.Empty;
return SyntaxConfig.SqlSyntaxProvider.Format(ForeignKey);
return SqlSyntaxContext.SqlSyntaxProvider.Format(ForeignKey);
}
}
}
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Expressions
public override string ToString()
{
return SyntaxConfig.SqlSyntaxProvider.Format(Index);
return SqlSyntaxContext.SqlSyntaxProvider.Format(Index);
}
}
}
@@ -52,7 +52,7 @@ SELECT CONCAT(
if (IsExpressionSupported() == false)
return string.Empty;
return SyntaxConfig.SqlSyntaxProvider.FormatColumnRename(TableName, OldName, NewName);
return SqlSyntaxContext.SqlSyntaxProvider.FormatColumnRename(TableName, OldName, NewName);
}
}
}
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Rename.Expressions
if (IsExpressionSupported() == false)
return string.Empty;
return SyntaxConfig.SqlSyntaxProvider.FormatTableRename(OldName, NewName);
return SqlSyntaxContext.SqlSyntaxProvider.FormatTableRename(OldName, NewName);
}
}
}
@@ -31,8 +31,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
foreach (var item in Set)
{
updateItems.Add(string.Format("{0} = {1}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
}
if (IsAllRows)
@@ -44,13 +44,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Update.Expressions
foreach (var item in Where)
{
whereClauses.Add(string.Format("{0} {1} {2}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
item.Value == null ? "IS" : "=",
SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
}
}
return string.Format(SyntaxConfig.SqlSyntaxProvider.UpdateData,
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.UpdateData,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
string.Join(", ", updateItems.ToArray()),
string.Join(" AND ", whereClauses.ToArray()));
}
@@ -0,0 +1,79 @@
using System;
using System.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
{
[Migration("6.0.2", 0, GlobalSettings.UmbracoMigrationName)]
public class UpdatePropertyTypesAndGroups : MigrationBase
{
public override void Up()
{
Execute.Code(UpdatePropertyTypesAndGroupsDo);
}
public override void Down()
{
}
public static string UpdatePropertyTypesAndGroupsDo(Database database)
{
if (database != null)
{
//Fetch all PropertyTypes that belongs to a PropertyTypeGroup
var propertyTypes = database.Fetch<PropertyTypeDto>("WHERE propertyTypeGroupId > 0");
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
foreach (var propertyType in propertyTypes)
{
//Get the PropertyTypeGroup that the current PropertyType references
var parentPropertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyTypeGroupId);
if (parentPropertyTypeGroup != null)
{
//If the ContentType is the same on the PropertyType and the PropertyTypeGroup the group is valid and we skip to the next
if (parentPropertyTypeGroup.ContentTypeNodeId == propertyType.ContentTypeId) continue;
//Check if the 'new' PropertyTypeGroup has already been created
var existingPropertyTypeGroup =
propertyGroups.FirstOrDefault(
x =>
x.ParentGroupId == parentPropertyTypeGroup.Id && x.Text == parentPropertyTypeGroup.Text &&
x.ContentTypeNodeId == propertyType.ContentTypeId);
//This should ensure that we don't create duplicate groups for a single ContentType
if (existingPropertyTypeGroup == null)
{
//Create a new PropertyTypeGroup that references the parent group that the PropertyType was referencing pre-6.0.1
var propertyGroup = new PropertyTypeGroupDto
{
ContentTypeNodeId = propertyType.ContentTypeId,
ParentGroupId = parentPropertyTypeGroup.Id,
Text = parentPropertyTypeGroup.Text,
SortOrder = parentPropertyTypeGroup.SortOrder
};
//Save the PropertyTypeGroup in the database and update the list of groups with this new group
int id = Convert.ToInt16(database.Insert(propertyGroup));
propertyGroup.Id = id;
propertyGroups.Add(propertyGroup);
//Update the reference to the new PropertyTypeGroup on the current PropertyType
propertyType.PropertyTypeGroupId = id;
database.Update(propertyType);
}
else
{
//Update the reference to the existing PropertyTypeGroup on the current PropertyType
propertyType.PropertyTypeGroupId = existingPropertyTypeGroup.Id;
database.Update(propertyType);
}
}
}
}
return string.Empty;
}
}
}
@@ -33,10 +33,10 @@ namespace Umbraco.Core.Persistence
var tableDefinition = DefinitionFactory.GetTableDefinition(modelType);
var tableName = tableDefinition.Name;
string createSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition);
string createPrimaryKeySql = SyntaxConfig.SqlSyntaxProvider.FormatPrimaryKey(tableDefinition);
var foreignSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition.ForeignKeys);
var indexSql = SyntaxConfig.SqlSyntaxProvider.Format(tableDefinition.Indexes);
string createSql = SqlSyntaxContext.SqlSyntaxProvider.Format(tableDefinition);
string createPrimaryKeySql = SqlSyntaxContext.SqlSyntaxProvider.FormatPrimaryKey(tableDefinition);
var foreignSql = SqlSyntaxContext.SqlSyntaxProvider.Format(tableDefinition.ForeignKeys);
var indexSql = SqlSyntaxContext.SqlSyntaxProvider.Format(tableDefinition.Indexes);
var tableExist = db.TableExist(tableName);
if (overwrite && tableExist)
@@ -65,18 +65,18 @@ namespace Umbraco.Core.Persistence
var e = new TableCreationEventArgs();
//Turn on identity insert if db provider is not mysql
if (SyntaxConfig.SqlSyntaxProvider.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity))
db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName))));
if (SqlSyntaxContext.SqlSyntaxProvider.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity))
db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} ON ", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName))));
//Call the NewTable-event to trigger the insert of base/default data
NewTable(tableName, db, e);
//Turn off identity insert if db provider is not mysql
if (SyntaxConfig.SqlSyntaxProvider.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity))
db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName))));
if (SqlSyntaxContext.SqlSyntaxProvider.SupportsIdentityInsert() && tableDefinition.Columns.Any(x => x.IsIdentity))
db.Execute(new Sql(string.Format("SET IDENTITY_INSERT {0} OFF;", SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName))));
//Special case for MySql
if (SyntaxConfig.SqlSyntaxProvider is MySqlSyntaxProvider && tableName.Equals("umbracoUser"))
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider && tableName.Equals("umbracoUser"))
{
db.Update<UserDto>("SET id = @IdAfter WHERE id = @IdBefore AND userLogin = @Login", new { IdAfter = 0, IdBefore = 1, Login = "admin" });
}
@@ -120,22 +120,40 @@ namespace Umbraco.Core.Persistence
public static void DropTable(this Database db, string tableName)
{
var sql = new Sql(string.Format("DROP TABLE {0}", SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName)));
var sql = new Sql(string.Format(
SqlSyntaxContext.SqlSyntaxProvider.DropTable,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName)));
db.Execute(sql);
}
public static void TruncateTable(this Database db, string tableName)
{
var sql = new Sql(string.Format(
SqlSyntaxContext.SqlSyntaxProvider.TruncateTable,
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName)));
db.Execute(sql);
}
public static bool TableExist(this Database db, string tableName)
{
return SyntaxConfig.SqlSyntaxProvider.DoesTableExist(db, tableName);
return SqlSyntaxContext.SqlSyntaxProvider.DoesTableExist(db, tableName);
}
public static bool TableExist(this UmbracoDatabase db, string tableName)
{
return SyntaxConfig.SqlSyntaxProvider.DoesTableExist(db, tableName);
return SqlSyntaxContext.SqlSyntaxProvider.DoesTableExist(db, tableName);
}
public static void CreateDatabaseSchema(this Database db)
{
CreateDatabaseSchema(db, true);
}
internal static void CreateDatabaseSchema(this Database db, bool guardConfiguration)
{
if (guardConfiguration && ApplicationContext.Current.IsConfigured)
throw new Exception("Umbraco is already configured!");
NewTable += PetaPocoExtensions_NewTable;
LogHelper.Info<Database>("Initializing database schema creation");
@@ -143,6 +161,8 @@ namespace Umbraco.Core.Persistence
var creation = new DatabaseSchemaCreation(db);
creation.InitializeDatabaseSchema();
LogHelper.Info<Database>("Finalized database schema creation");
NewTable -= PetaPocoExtensions_NewTable;
}
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence
var tableNameAttribute = type.FirstAttribute<TableNameAttribute>();
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
return sql.From(SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName));
return sql.From(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName));
}
public static Sql Where<T>(this Sql sql, Expression<Func<T, bool>> predicate)
@@ -38,8 +38,8 @@ namespace Umbraco.Core.Persistence
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
var syntax = string.Format("{0}.{1}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
return sql.OrderBy(syntax);
}
@@ -54,8 +54,8 @@ namespace Umbraco.Core.Persistence
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
var syntax = string.Format("{0}.{1} DESC",
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
return sql.OrderBy(syntax);
}
@@ -65,7 +65,7 @@ namespace Umbraco.Core.Persistence
var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo;
var columnName = column.FirstAttribute<ColumnAttribute>().Name;
return sql.GroupBy(SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
return sql.GroupBy(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
}
public static Sql.SqlJoinClause InnerJoin<T>(this Sql sql)
@@ -74,7 +74,7 @@ namespace Umbraco.Core.Persistence
var tableNameAttribute = type.FirstAttribute<TableNameAttribute>();
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
return sql.InnerJoin(SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName));
return sql.InnerJoin(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName));
}
public static Sql.SqlJoinClause LeftJoin<T>(this Sql sql)
@@ -83,7 +83,7 @@ namespace Umbraco.Core.Persistence
var tableNameAttribute = type.FirstAttribute<TableNameAttribute>();
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
return sql.LeftJoin(SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName));
return sql.LeftJoin(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName));
}
public static Sql.SqlJoinClause LeftOuterJoin<T>(this Sql sql)
@@ -92,7 +92,7 @@ namespace Umbraco.Core.Persistence
var tableNameAttribute = type.FirstAttribute<TableNameAttribute>();
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
return sql.LeftOuterJoin(SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName));
return sql.LeftOuterJoin(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName));
}
public static Sql.SqlJoinClause RightJoin<T>(this Sql sql)
@@ -101,7 +101,7 @@ namespace Umbraco.Core.Persistence
var tableNameAttribute = type.FirstAttribute<TableNameAttribute>();
string tableName = tableNameAttribute == null ? string.Empty : tableNameAttribute.Value;
return sql.RightJoin(SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName));
return sql.RightJoin(SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName));
}
public static Sql On<TLeft, TRight>(this Sql.SqlJoinClause sql, Expression<Func<TLeft, object>> leftMember,
@@ -118,10 +118,10 @@ namespace Umbraco.Core.Persistence
var rightColumnName = right.FirstAttribute<ColumnAttribute>().Name;
string onClause = string.Format("{0}.{1} = {2}.{3}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(leftTableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(leftColumnName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(rightTableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(rightColumnName));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(leftTableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(leftColumnName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(rightTableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(rightColumnName));
return sql.On(onClause);
}
}
@@ -0,0 +1,572 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Umbraco.Core.Persistence.Mappers;
namespace Umbraco.Core.Persistence.Querying
{
internal class ExpressionHelper<T>
{
private string selectExpression = string.Empty;
private string whereExpression;
private string groupBy = string.Empty;
private string havingExpression;
private string orderBy = string.Empty;
IList<string> updateFields = new List<string>();
IList<string> insertFields = new List<string>();
private string sep = string.Empty;
private bool useFieldName = false;
private Database.PocoData pd;
public ExpressionHelper()
{
Database.Mapper = new ModelDtoMapper();
pd = new Database.PocoData(typeof(T));
}
protected internal virtual string Visit(Expression exp)
{
if (exp == null) return string.Empty;
switch (exp.NodeType)
{
case ExpressionType.Lambda:
return VisitLambda(exp as LambdaExpression);
case ExpressionType.MemberAccess:
return VisitMemberAccess(exp as MemberExpression);
case ExpressionType.Constant:
return VisitConstant(exp as ConstantExpression);
case ExpressionType.Add:
case ExpressionType.AddChecked:
case ExpressionType.Subtract:
case ExpressionType.SubtractChecked:
case ExpressionType.Multiply:
case ExpressionType.MultiplyChecked:
case ExpressionType.Divide:
case ExpressionType.Modulo:
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
case ExpressionType.RightShift:
case ExpressionType.LeftShift:
case ExpressionType.ExclusiveOr:
return "(" + VisitBinary(exp as BinaryExpression) + ")";
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Not:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.ArrayLength:
case ExpressionType.Quote:
case ExpressionType.TypeAs:
return VisitUnary(exp as UnaryExpression);
case ExpressionType.Parameter:
return VisitParameter(exp as ParameterExpression);
case ExpressionType.Call:
return VisitMethodCall(exp as MethodCallExpression);
case ExpressionType.New:
return VisitNew(exp as NewExpression);
case ExpressionType.NewArrayInit:
case ExpressionType.NewArrayBounds:
return VisitNewArray(exp as NewArrayExpression);
default:
return exp.ToString();
}
}
protected virtual string VisitLambda(LambdaExpression lambda)
{
if (lambda.Body.NodeType == ExpressionType.MemberAccess && sep == " ")
{
MemberExpression m = lambda.Body as MemberExpression;
if (m.Expression != null)
{
string r = VisitMemberAccess(m);
return string.Format("{0}={1}", r, GetQuotedTrueValue());
}
}
return Visit(lambda.Body);
}
protected virtual string VisitBinary(BinaryExpression b)
{
string left, right;
var operand = BindOperant(b.NodeType); //sep= " " ??
if (operand == "AND" || operand == "OR")
{
MemberExpression m = b.Left as MemberExpression;
if (m != null && m.Expression != null)
{
string r = VisitMemberAccess(m);
left = string.Format("{0}={1}", r, GetQuotedTrueValue());
}
else
{
left = Visit(b.Left);
}
m = b.Right as MemberExpression;
if (m != null && m.Expression != null)
{
string r = VisitMemberAccess(m);
right = string.Format("{0}={1}", r, GetQuotedTrueValue());
}
else
{
right = Visit(b.Right);
}
}
else
{
left = Visit(b.Left);
right = Visit(b.Right);
}
if (operand == "=" && right == "null") operand = "is";
else if (operand == "<>" && right == "null") operand = "is not";
else if (operand == "=" || operand == "<>")
{
if (IsTrueExpression(right)) right = GetQuotedTrueValue();
else if (IsFalseExpression(right)) right = GetQuotedFalseValue();
if (IsTrueExpression(left)) left = GetQuotedTrueValue();
else if (IsFalseExpression(left)) left = GetQuotedFalseValue();
}
switch (operand)
{
case "MOD":
case "COALESCE":
return string.Format("{0}({1},{2})", operand, left, right);
default:
return left + sep + operand + sep + right;
}
}
protected virtual string VisitMemberAccess(MemberExpression m)
{
if (m.Expression != null &&
m.Expression.NodeType == ExpressionType.Parameter
&& m.Expression.Type == typeof(T))
{
string field = GetFieldName(pd, m.Member.Name);
return field;
}
if (m.Expression != null && m.Expression.NodeType != ExpressionType.Constant)
{
Database.Mapper = new ModelDtoMapper();
var def = new Database.PocoData(m.Expression.Type);
string field = GetFieldName(def, m.Member.Name);
return field;
}
var member = Expression.Convert(m, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
object o = getter();
return GetQuotedValue(o, o != null ? o.GetType() : null);
}
protected virtual string VisitNew(NewExpression nex)
{
// TODO : check !
var member = Expression.Convert(nex, typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
try
{
var getter = lambda.Compile();
object o = getter();
return GetQuotedValue(o, o.GetType());
}
catch (System.InvalidOperationException)
{ // FieldName ?
List<Object> exprs = VisitExpressionList(nex.Arguments);
var r = new StringBuilder();
foreach (Object e in exprs)
{
r.AppendFormat("{0}{1}",
r.Length > 0 ? "," : "",
e);
}
return r.ToString();
}
}
protected virtual string VisitParameter(ParameterExpression p)
{
return p.Name;
}
protected virtual string VisitConstant(ConstantExpression c)
{
if (c.Value == null)
return "null";
else if (c.Value.GetType() == typeof(bool))
{
object o = GetQuotedValue(c.Value, c.Value.GetType());
return string.Format("({0}={1})", GetQuotedTrueValue(), o);
}
else
return GetQuotedValue(c.Value, c.Value.GetType());
}
protected virtual string VisitUnary(UnaryExpression u)
{
switch (u.NodeType)
{
case ExpressionType.Not:
string o = Visit(u.Operand);
if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool));
return "NOT (" + o + ")";
default:
return Visit(u.Operand);
}
}
protected virtual string VisitMethodCall(MethodCallExpression m)
{
List<Object> args = this.VisitExpressionList(m.Arguments);
Object r;
if (m.Object != null)
r = Visit(m.Object);
else
{
r = args[0];
args.RemoveAt(0);
}
switch (m.Method.Name)
{
case "ToUpper":
return string.Format("upper({0})", r);
case "ToLower":
return string.Format("lower({0})", r);
case "StartsWith":
return string.Format("upper({0}) starting with {1} ", r, args[0].ToString().ToUpper());
case "EndsWith":
return string.Format("upper({0}) like '%{1}'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Contains":
return string.Format("upper({0}) like '%{1}%'", r, RemoveQuote(args[0].ToString()).ToUpper());
case "Substring":
var startIndex = Int32.Parse(args[0].ToString()) + 1;
if (args.Count == 2)
{
var length = Int32.Parse(args[1].ToString());
return string.Format("substring({0} from {1} for {2})",
r,
startIndex,
length);
}
else
return string.Format("substring({0} from {1})",
r,
startIndex);
case "Round":
case "Floor":
case "Ceiling":
case "Coalesce":
case "Abs":
case "Sum":
return string.Format("{0}({1}{2})",
m.Method.Name,
r,
args.Count == 1 ? string.Format(",{0}", args[0]) : "");
case "Concat":
var s = new StringBuilder();
foreach (Object e in args)
{
s.AppendFormat(" || {0}", e);
}
return string.Format("{0}{1}", r, s.ToString());
case "In":
var member = Expression.Convert(m.Arguments[1], typeof(object));
var lambda = Expression.Lambda<Func<object>>(member);
var getter = lambda.Compile();
var inArgs = getter() as object[];
var sIn = new StringBuilder();
foreach (Object e in inArgs)
{
if (e.GetType().ToString() != "System.Collections.Generic.List`1[System.Object]")
{
sIn.AppendFormat("{0}{1}",
sIn.Length > 0 ? "," : "",
GetQuotedValue(e, e.GetType()));
}
else
{
var listArgs = e as IList<Object>;
foreach (Object el in listArgs)
{
sIn.AppendFormat("{0}{1}",
sIn.Length > 0 ? "," : "",
GetQuotedValue(el, el.GetType()));
}
}
}
return string.Format("{0} {1} ({2})", r, m.Method.Name, sIn.ToString());
case "Desc":
return string.Format("{0} DESC", r);
case "Alias":
case "As":
return string.Format("{0} As {1}", r,
GetQuotedColumnName(RemoveQuoteFromAlias(RemoveQuote(args[0].ToString()))));
case "ToString":
return r.ToString();
default:
var s2 = new StringBuilder();
foreach (Object e in args)
{
s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType()));
}
return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString());
}
}
protected virtual List<Object> VisitExpressionList(ReadOnlyCollection<Expression> original)
{
var list = new List<Object>();
for (int i = 0, n = original.Count; i < n; i++)
{
if (original[i].NodeType == ExpressionType.NewArrayInit ||
original[i].NodeType == ExpressionType.NewArrayBounds)
{
list.AddRange(VisitNewArrayFromExpressionList(original[i] as NewArrayExpression));
}
else
list.Add(Visit(original[i]));
}
return list;
}
protected virtual string VisitNewArray(NewArrayExpression na)
{
List<Object> exprs = VisitExpressionList(na.Expressions);
var r = new StringBuilder();
foreach (Object e in exprs)
{
r.Append(r.Length > 0 ? "," + e : e);
}
return r.ToString();
}
protected virtual List<Object> VisitNewArrayFromExpressionList(NewArrayExpression na)
{
List<Object> exprs = VisitExpressionList(na.Expressions);
return exprs;
}
protected virtual string BindOperant(ExpressionType e)
{
switch (e)
{
case ExpressionType.Equal:
return "=";
case ExpressionType.NotEqual:
return "<>";
case ExpressionType.GreaterThan:
return ">";
case ExpressionType.GreaterThanOrEqual:
return ">=";
case ExpressionType.LessThan:
return "<";
case ExpressionType.LessThanOrEqual:
return "<=";
case ExpressionType.AndAlso:
return "AND";
case ExpressionType.OrElse:
return "OR";
case ExpressionType.Add:
return "+";
case ExpressionType.Subtract:
return "-";
case ExpressionType.Multiply:
return "*";
case ExpressionType.Divide:
return "/";
case ExpressionType.Modulo:
return "MOD";
case ExpressionType.Coalesce:
return "COALESCE";
default:
return e.ToString();
}
}
public virtual string GetQuotedTableName(string tableName)
{
return string.Format("\"{0}\"", tableName);
}
public virtual string GetQuotedColumnName(string columnName)
{
return string.Format("\"{0}\"", columnName);
}
public virtual string GetQuotedName(string name)
{
return string.Format("\"{0}\"", name);
}
private string GetQuotedTrueValue()
{
return GetQuotedValue(true, typeof(bool));
}
private string GetQuotedFalseValue()
{
return GetQuotedValue(false, typeof(bool));
}
public virtual string GetQuotedValue(object value, Type fieldType)
{
if (value == null) return "NULL";
if (!fieldType.UnderlyingSystemType.IsValueType && fieldType != typeof(string))
{
//if (TypeSerializer.CanCreateFromString(fieldType))
//{
// return "'" + EscapeParam(TypeSerializer.SerializeToString(value)) + "'";
//}
throw new NotSupportedException(
string.Format("Property of type: {0} is not supported", fieldType.FullName));
}
if (fieldType == typeof(int))
return ((int)value).ToString(CultureInfo.InvariantCulture);
if (fieldType == typeof(float))
return ((float)value).ToString(CultureInfo.InvariantCulture);
if (fieldType == typeof(double))
return ((double)value).ToString(CultureInfo.InvariantCulture);
if (fieldType == typeof(decimal))
return ((decimal)value).ToString(CultureInfo.InvariantCulture);
return ShouldQuoteValue(fieldType)
? "'" + EscapeParam(value) + "'"
: value.ToString();
}
public virtual string EscapeParam(object paramValue)
{
return paramValue.ToString().Replace("'", "''");
}
public virtual bool ShouldQuoteValue(Type fieldType)
{
return true;
}
protected virtual string GetFieldName(Database.PocoData pocoData, string name)
{
var column = pocoData.Columns.FirstOrDefault(x => x.Value.PropertyInfo.Name == name);
return column.Value.ColumnName;
}
protected virtual string GetFieldName(string name)
{
if (useFieldName)
{
//FieldDefinition fd = modelDef.FieldDefinitions.FirstOrDefault(x => x.Name == name);
//string fn = fd != default(FieldDefinition) ? fd.FieldName : name;
//return OrmLiteConfig.DialectProvider.GetQuotedColumnName(fn);
return "[" + name + "]";
}
else
{
return name;
}
}
protected string RemoveQuote(string exp)
{
if (exp.StartsWith("'") && exp.EndsWith("'"))
{
exp = exp.Remove(0, 1);
exp = exp.Remove(exp.Length - 1, 1);
}
return exp;
}
protected string RemoveQuoteFromAlias(string exp)
{
if ((exp.StartsWith("\"") || exp.StartsWith("`") || exp.StartsWith("'"))
&&
(exp.EndsWith("\"") || exp.EndsWith("`") || exp.EndsWith("'")))
{
exp = exp.Remove(0, 1);
exp = exp.Remove(exp.Length - 1, 1);
}
return exp;
}
private string GetTrueExpression()
{
object o = GetQuotedTrueValue();
return string.Format("({0}={1})", o, o);
}
private string GetFalseExpression()
{
return string.Format("({0}={1})",
GetQuotedTrueValue(),
GetQuotedFalseValue());
}
private bool IsTrueExpression(string exp)
{
return (exp == GetTrueExpression());
}
private bool IsFalseExpression(string exp)
{
return (exp == GetFalseExpression());
}
protected bool IsFieldName(string quotedExp)
{
return true;
}
}
}
@@ -523,7 +523,8 @@ namespace Umbraco.Core.Persistence.Querying
protected bool IsFieldName(string quotedExp)
{
return true;
//Not entirely sure this is reliable, but its better then simply returning true
return quotedExp.LastIndexOf("'", StringComparison.InvariantCultureIgnoreCase) + 1 != quotedExp.Length;
}
}
}
@@ -468,6 +468,9 @@ namespace Umbraco.Core.Persistence.Querying
if(fieldType == typeof(DateTime))
return "'" + EscapeParam(((DateTime)value).ToString(CultureInfo.InvariantCulture)) + "'";
if (fieldType == typeof(bool))
return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture);
return ShouldQuoteValue(fieldType)
? "'" + EscapeParam(value) + "'"
: value.ToString();
@@ -487,8 +490,8 @@ namespace Umbraco.Core.Persistence.Querying
{
var column = pocoData.Columns.FirstOrDefault(x => x.Value.PropertyInfo.Name == name);
return string.Format("{0}.{1}",
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(pocoData.TableInfo.TableName),
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(column.Value.ColumnName));
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(pocoData.TableInfo.TableName),
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(column.Value.ColumnName));
}
protected string RemoveQuote(string exp)
@@ -78,7 +78,10 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContent>(sqlClause, query);
var sql = translator.Translate();
var sql = translator.Translate()
.Where<DocumentDto>(x => x.Newest)
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
.OrderBy<NodeDto>(x => x.SortOrder);
//NOTE: This doesn't allow properties to be part of the query
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql);
@@ -263,8 +266,11 @@ namespace Umbraco.Core.Persistence.Repositories
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
entity.Path = string.Concat(parent.Path, ",", entity.Id);
entity.Level = parent.Level + 1;
var maxSortOrder = Database.ExecuteScalar<int>("SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId", new { ParentId = entity.ParentId });
entity.SortOrder = maxSortOrder;
var maxSortOrder =
Database.ExecuteScalar<int>(
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new {ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId});
entity.SortOrder = maxSortOrder + 1;
}
var factory = new ContentFactory(NodeObjectTypeId, entity.Id);
@@ -368,7 +374,7 @@ namespace Umbraco.Core.Persistence.Repositories
//Loop through properties to check if the content contains images/files that should be deleted
foreach (var property in entity.Properties)
{
if (property.PropertyType.DataTypeId == uploadFieldId &&
if (property.PropertyType.DataTypeId == uploadFieldId && property.Value != null &&
string.IsNullOrEmpty(property.Value.ToString()) == false
&& fs.FileExists(IOHelper.MapPath(property.Value.ToString())))
{
@@ -450,6 +456,17 @@ namespace Umbraco.Core.Persistence.Repositories
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
var propertyFactory = new PropertyFactory(contentType, versionId, id);
var properties = propertyFactory.BuildEntity(propertyDataDtos);
var newProperties = properties.Where(x => x.HasIdentity == false);
foreach (var property in newProperties)
{
var propertyDataDto = new PropertyDataDto{ NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
property.Version = versionId;
property.Id = primaryKey;
}
return new PropertyCollection(properties);
}
}
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -40,11 +41,11 @@ namespace Umbraco.Core.Persistence.Repositories
.RightJoin<PropertyTypeDto>()
.On<PropertyTypeGroupDto, PropertyTypeDto>(left => left.Id, right => right.PropertyTypeGroupId)
.InnerJoin<DataTypeDto>()
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId)
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId);
.On<PropertyTypeDto, DataTypeDto>(left => left.DataTypeId, right => right.DataTypeId);
var translator = new SqlTranslator<PropertyType>(sqlClause, query);
var sql = translator.Translate();
var sql = translator.Translate()
.OrderBy<PropertyTypeDto>(x => x.PropertyTypeGroupId);
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
@@ -107,7 +108,12 @@ namespace Umbraco.Core.Persistence.Repositories
//Insert collection of allowed content types
foreach (var allowedContentType in entity.AllowedContentTypes)
{
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id.Value, SortOrder = allowedContentType.SortOrder });
Database.Insert(new ContentTypeAllowedContentTypeDto
{
Id = entity.Id,
AllowedId = allowedContentType.Id.Value,
SortOrder = allowedContentType.SortOrder
});
}
var propertyFactory = new PropertyGroupFactory(nodeDto.NodeId);
@@ -118,103 +124,181 @@ namespace Umbraco.Core.Persistence.Repositories
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
var primaryKey = Convert.ToInt32(Database.Insert(tabDto));
propertyGroup.Id = primaryKey;//Set Id on PropertyGroup
//Ensure that the PropertyGroup's Id is set on the PropertyTypes within a group
//unless the PropertyGroupId has already been changed.
foreach (var propertyType in propertyGroup.PropertyTypes)
{
if (propertyType.IsPropertyDirty("PropertyGroupId") == false)
{
var tempGroup = propertyGroup;
propertyType.PropertyGroupId = new Lazy<int>(() => tempGroup.Id);
}
}
}
//Insert PropertyTypes
foreach (var propertyGroup in entity.PropertyGroups)
foreach (var propertyType in entity.PropertyTypes)
{
foreach (var propertyType in propertyGroup.PropertyTypes)
{
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyGroup.Id, propertyType);
var primaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto));
propertyType.Id = primaryKey;//Set Id on PropertyType
var tabId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int);
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(tabId, propertyType);
int typePrimaryKey = Convert.ToInt32(Database.Insert(propertyTypeDto));
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
//Update the current PropertyType with correct ControlId and DatabaseType
var dataTypeDto = Database.FirstOrDefault<DataTypeDto>("WHERE nodeId = @Id", new { Id = propertyTypeDto.DataTypeId });
propertyType.DataTypeId = dataTypeDto.ControlId;
propertyType.DataTypeDatabaseType = dataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true);
}
//Update the current PropertyType with correct ControlId and DatabaseType
var dataTypeDto = Database.FirstOrDefault<DataTypeDto>("WHERE nodeId = @Id", new { Id = propertyTypeDto.DataTypeId });
propertyType.DataTypeId = dataTypeDto.ControlId;
propertyType.DataTypeDatabaseType = dataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true);
}
}
protected void PersistUpdatedBaseContentType(ContentTypeDto dto, IContentTypeComposition entity)
{
var propertyFactory = new PropertyGroupFactory(entity.Id);
var propertyGroupFactory = new PropertyGroupFactory(entity.Id);
var nodeDto = dto.NodeDto;
var o = Database.Update(nodeDto);
//Look up ContentType entry to get PrimaryKey for updating the DTO
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new { Id = entity.Id });
var dtoPk = Database.First<ContentTypeDto>("WHERE nodeId = @Id", new {Id = entity.Id});
dto.PrimaryKey = dtoPk.PrimaryKey;
Database.Update(dto);
//Delete the ContentType composition entries before adding the updated collection
Database.Delete<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new { Id = entity.Id });
Database.Delete<ContentType2ContentTypeDto>("WHERE childContentTypeId = @Id", new {Id = entity.Id});
//Update ContentType composition in new table
foreach (var composition in entity.ContentTypeComposition)
{
Database.Insert(new ContentType2ContentTypeDto { ParentId = composition.Id, ChildId = entity.Id });
Database.Insert(new ContentType2ContentTypeDto {ParentId = composition.Id, ChildId = entity.Id});
}
//Removing a ContentType from a composition (U4-1690)
//1. Find content based on the current ContentType: entity.Id
//2. Find all PropertyTypes on the ContentType that was removed - tracked id (key)
//3. Remove properties based on property types from the removed content type where the content ids correspond to those found in step one
var compositionBase = entity as ContentTypeCompositionBase;
if (compositionBase != null && compositionBase.RemovedContentTypeKeyTracker != null &&
compositionBase.RemovedContentTypeKeyTracker.Any())
{
//Find Content based on the current ContentType
var sql = new Sql();
sql.Select("*")
.From<ContentDto>()
.InnerJoin<NodeDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == new Guid("C66BA18E-EAF3-4CFF-8A22-41B16D66A972"))
.Where<ContentDto>(x => x.ContentTypeId == entity.Id);
var contentDtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto>(sql);
//Loop through all tracked keys, which corresponds to the ContentTypes that has been removed from the composition
foreach (var key in compositionBase.RemovedContentTypeKeyTracker)
{
//Find PropertyTypes for the removed ContentType
var propertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new {Id = key});
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
//based on the PropertyTypes that belong to the removed ContentType.
foreach (var contentDto in contentDtos)
{
foreach (var propertyType in propertyTypes)
{
var nodeId = contentDto.NodeId;
var propertyTypeId = propertyType.Id;
var propertySql = new Sql().Select("*")
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>()
.On<PropertyDataDto, PropertyTypeDto>(
left => left.PropertyTypeId, right => right.Id)
.Where<PropertyDataDto>(x => x.NodeId == nodeId)
.Where<PropertyTypeDto>(x => x.Id == propertyTypeId);
//Finally delete the properties that match our criteria for removing a ContentType from the composition
Database.Delete<PropertyDataDto>(propertySql);
}
}
}
}
//Delete the allowed content type entries before adding the updated collection
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new { Id = entity.Id });
Database.Delete<ContentTypeAllowedContentTypeDto>("WHERE Id = @Id", new {Id = entity.Id});
//Insert collection of allowed content types
foreach (var allowedContentType in entity.AllowedContentTypes)
{
Database.Insert(new ContentTypeAllowedContentTypeDto { Id = entity.Id, AllowedId = allowedContentType.Id.Value, SortOrder = allowedContentType.SortOrder });
Database.Insert(new ContentTypeAllowedContentTypeDto
{
Id = entity.Id,
AllowedId = allowedContentType.Id.Value,
SortOrder = allowedContentType.SortOrder
});
}
//Check Dirty properties for Tabs/Groups and PropertyTypes - insert and delete accordingly
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
if (((ICanBeDirty) entity).IsPropertyDirty("PropertyTypes") || entity.PropertyTypes.Any(x => x.IsDirty()))
{
//Delete PropertyTypes by excepting entries from db with entries from collections
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = entity.Id });
var dbPropertyTypeAlias = dbPropertyTypes.Select(x => x.Alias.ToLowerInvariant());
var entityPropertyTypes = entity.PropertyTypes.Select(x => x.Alias.ToLowerInvariant());
var aliases = dbPropertyTypeAlias.Except(entityPropertyTypes);
foreach (var alias in aliases)
var dbPropertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new {Id = entity.Id});
var dbPropertyTypeAlias = dbPropertyTypes.Select(x => x.Id);
var entityPropertyTypes = entity.PropertyTypes.Where(x => x.HasIdentity).Select(x => x.Id);
var items = dbPropertyTypeAlias.Except(entityPropertyTypes);
foreach (var item in items)
{
//Before a PropertyType can be deleted, all Properties based on that PropertyType should be deleted.
var propertyType = dbPropertyTypes.FirstOrDefault(x => x.Alias.ToLowerInvariant() == alias);
if (propertyType != null)
{
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new { Id = propertyType.Id });
}
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND Alias = @Alias", new { Id = entity.Id, Alias = alias });
Database.Delete<PropertyDataDto>("WHERE propertytypeid = @Id", new {Id = item});
Database.Delete<PropertyTypeDto>("WHERE contentTypeId = @Id AND id = @PropertyTypeId",
new {Id = entity.Id, PropertyTypeId = item});
}
}
if (((ICanBeDirty) entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
{
//Delete Tabs/Groups by excepting entries from db with entries from collections
var dbPropertyGroups = Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = entity.Id }).Select(x => x.Text);
var entityPropertyGroups = entity.PropertyGroups.Select(x => x.Name);
var dbPropertyGroups =
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new {Id = entity.Id})
.Select(x => new Tuple<int, string>(x.Id, x.Text));
var entityPropertyGroups = entity.PropertyGroups.Select(x => new Tuple<int, string>(x.Id, x.Name));
var tabs = dbPropertyGroups.Except(entityPropertyGroups);
foreach (var tabName in tabs)
foreach (var tab in tabs)
{
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name", new { Id = entity.Id, Name = tabName });
Database.Update<PropertyTypeDto>("SET propertyTypeGroupId = NULL WHERE propertyTypeGroupId = @PropertyGroupId",
new {PropertyGroupId = tab.Item1});
Database.Update<PropertyTypeGroupDto>("SET parentGroupId = NULL WHERE parentGroupId = @TabId",
new {TabId = tab.Item1});
Database.Delete<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id AND text = @Name",
new {Id = entity.Id, Name = tab.Item2});
}
}
//Run through all groups to insert or update entries
foreach (var propertyGroup in entity.PropertyGroups)
{
var tabDto = propertyFactory.BuildGroupDto(propertyGroup);
int groupPrimaryKey = propertyGroup.HasIdentity
? Database.Update(tabDto)
: Convert.ToInt32(Database.Insert(tabDto));
if (!propertyGroup.HasIdentity)
propertyGroup.Id = groupPrimaryKey;//Set Id on new PropertyGroup
}
//Run through all groups to insert or update entries
foreach (var propertyGroup in entity.PropertyGroups)
{
var tabDto = propertyGroupFactory.BuildGroupDto(propertyGroup);
int groupPrimaryKey = propertyGroup.HasIdentity
? Database.Update(tabDto)
: Convert.ToInt32(Database.Insert(tabDto));
if (propertyGroup.HasIdentity == false)
propertyGroup.Id = groupPrimaryKey; //Set Id on new PropertyGroup
//Run through all PropertyTypes to insert or update entries
foreach (var propertyType in entity.PropertyTypes)
//Ensure that the PropertyGroup's Id is set on the PropertyTypes within a group
//unless the PropertyGroupId has already been changed.
foreach (var propertyType in propertyGroup.PropertyTypes)
{
var propertyTypeDto = propertyFactory.BuildPropertyTypeDto(propertyType.PropertyGroupId, propertyType);
int typePrimaryKey = propertyType.HasIdentity
? Database.Update(propertyTypeDto)
: Convert.ToInt32(Database.Insert(propertyTypeDto));
if (!propertyType.HasIdentity)
propertyType.Id = typePrimaryKey;//Set Id on new PropertyType
if (propertyType.IsPropertyDirty("PropertyGroupId") == false)
{
var tempGroup = propertyGroup;
propertyType.PropertyGroupId = new Lazy<int>(() => tempGroup.Id);
}
}
}
//Run through all PropertyTypes to insert or update entries
foreach (var propertyType in entity.PropertyTypes)
{
var tabId = propertyType.PropertyGroupId != null ? propertyType.PropertyGroupId.Value : default(int);
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType);
int typePrimaryKey = propertyType.HasIdentity
? Database.Update(propertyTypeDto)
: Convert.ToInt32(Database.Insert(propertyTypeDto));
if (propertyType.HasIdentity == false)
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
}
}
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
@@ -242,8 +326,8 @@ namespace Umbraco.Core.Persistence.Repositories
var dtos = Database.Fetch<PropertyTypeGroupDto, PropertyTypeDto, DataTypeDto, PropertyTypeGroupDto>(new GroupPropertyTypeRelator().Map, sql);
var propertyFactory = new PropertyGroupFactory(id);
var propertyGroups = propertyFactory.BuildEntity(dtos);
var propertyGroupFactory = new PropertyGroupFactory(id);
var propertyGroups = propertyGroupFactory.BuildEntity(dtos);
return new PropertyGroupCollection(propertyGroups);
}
@@ -272,9 +356,13 @@ namespace Umbraco.Core.Persistence.Repositories
Name = dto.Name,
HelpText = dto.HelpText,
Mandatory = dto.Mandatory,
SortOrder = dto.SortOrder
});
SortOrder = dto.SortOrder,
ValidationRegExp = dto.ValidationRegExp
}).ToList();
//Reset dirty properties
Parallel.ForEach(list, currentFile => currentFile.ResetDirtyProperties());
return new PropertyTypeCollection(list);
}
}
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -93,7 +94,8 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContentType>(sqlClause, query);
var sql = translator.Translate();
var sql = translator.Translate()
.OrderBy<NodeDto>(x => x.Text);
var dtos = Database.Fetch<DocumentTypeDto, ContentTypeDto, NodeDto>(sql);
@@ -166,6 +168,19 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistNewItem(IContentType entity)
{
Mandate.That<Exception>(string.IsNullOrEmpty(entity.Alias) == false,
() =>
{
var message =
string.Format(
"ContentType '{0}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
entity.Name);
var exception = new Exception(message);
LogHelper.Error<ContentTypeRepository>(message, exception);
throw exception;
});
((ContentType)entity).AddingEntity();
var factory = new ContentTypeFactory(NodeObjectTypeId);
@@ -191,6 +206,19 @@ namespace Umbraco.Core.Persistence.Repositories
protected override void PersistUpdatedItem(IContentType entity)
{
Mandate.That<Exception>(string.IsNullOrEmpty(entity.Alias) == false,
() =>
{
var message =
string.Format(
"ContentType '{0}' cannot have an empty Alias. This is most likely due to invalid characters stripped from the Alias.",
entity.Name);
var exception = new Exception(message);
LogHelper.Error<ContentTypeRepository>(message, exception);
throw exception;
});
//Updates Modified date
((ContentType)entity).UpdatingEntity();
@@ -199,6 +227,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
entity.Path = string.Concat(parent.Path, ",", entity.Id);
entity.Level = parent.Level + 1;
var maxSortOrder =
Database.ExecuteScalar<int>(
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
entity.SortOrder = maxSortOrder + 1;
}
var factory = new ContentTypeFactory(NodeObjectTypeId);
@@ -159,6 +159,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
entity.Path = string.Concat(parent.Path, ",", entity.Id);
entity.Level = parent.Level + 1;
var maxSortOrder =
Database.ExecuteScalar<int>(
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
entity.SortOrder = maxSortOrder + 1;
}
var factory = new DataTypeDefinitionFactory(NodeObjectTypeId);
@@ -246,8 +246,11 @@ namespace Umbraco.Core.Persistence.Repositories
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
entity.Path = string.Concat(parent.Path, ",", entity.Id);
entity.Level = parent.Level + 1;
var maxSortOrder = Database.ExecuteScalar<int>("SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId", new { ParentId = entity.ParentId });
entity.SortOrder = maxSortOrder;
var maxSortOrder =
Database.ExecuteScalar<int>(
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
entity.SortOrder = maxSortOrder + 1;
}
var factory = new MediaFactory(NodeObjectTypeId, entity.Id);
@@ -347,7 +350,18 @@ namespace Umbraco.Core.Persistence.Repositories
var propertyDataDtos = Database.Fetch<PropertyDataDto, PropertyTypeDto>(sql);
var propertyFactory = new PropertyFactory(contentType, versionId, id);
var properties = propertyFactory.BuildMediaEntity(propertyDataDtos);
var properties = propertyFactory.BuildEntity(propertyDataDtos);
var newProperties = properties.Where(x => x.HasIdentity == false);
foreach (var property in newProperties)
{
var propertyDataDto = new PropertyDataDto { NodeId = id, PropertyTypeId = property.PropertyTypeId, VersionId = versionId };
int primaryKey = Convert.ToInt32(Database.Insert(propertyDataDto));
property.Version = versionId;
property.Id = primaryKey;
}
return new PropertyCollection(properties);
}
}
@@ -168,6 +168,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = entity.ParentId });
entity.Path = string.Concat(parent.Path, ",", entity.Id);
entity.Level = parent.Level + 1;
var maxSortOrder =
Database.ExecuteScalar<int>(
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new { ParentId = entity.ParentId, NodeObjectType = NodeObjectTypeId });
entity.SortOrder = maxSortOrder + 1;
}
var factory = new MediaTypeFactory(NodeObjectTypeId);
@@ -26,13 +26,13 @@ namespace Umbraco.Core.Persistence.Repositories
public TemplateRepository(IDatabaseUnitOfWork work)
: base(work)
{
EnsureDepedencies();
EnsureDependencies();
}
public TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache)
: base(work, cache)
{
EnsureDepedencies();
EnsureDependencies();
}
internal TemplateRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem)
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Persistence.Repositories
_viewsFileSystem = viewFileSystem;
}
private void EnsureDepedencies()
private void EnsureDependencies()
{
_masterpagesFileSystem = new PhysicalFileSystem(SystemDirectories.Masterpages);
_viewsFileSystem = new PhysicalFileSystem(SystemDirectories.MvcViews);
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var masterTemplate = Get(dto.Master.Value);
template.MasterTemplateAlias = masterTemplate.Alias;
template.MasterTemplateId = dto.Master.Value;
template.MasterTemplateId = new Lazy<int>(() => dto.Master.Value);
}
if (_viewsFileSystem.FileExists(csViewName))
@@ -172,14 +172,18 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc)
{
_viewsFileSystem.AddFile(entity.Name, stream, true);
string viewName = string.Concat(entity.Alias, ".cshtml");
_viewsFileSystem.AddFile(viewName, stream, true);
}
else
{
_masterpagesFileSystem.AddFile(entity.Name, stream, true);
string masterpageName = string.Concat(entity.Alias, ".master");
_masterpagesFileSystem.AddFile(masterpageName, stream, true);
}
}
//TODO Possibly ensure unique alias here (as is done in the legacy Template class)?
//Save to db
var template = entity as Template;
var factory = new TemplateFactory(NodeObjectTypeId);
@@ -223,11 +227,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
if (entity.GetTypeOfRenderingEngine() == RenderingEngine.Mvc)
{
_viewsFileSystem.AddFile(entity.Name, stream, true);
string viewName = string.Concat(entity.Alias, ".cshtml");
_viewsFileSystem.AddFile(viewName, stream, true);
}
else
{
_masterpagesFileSystem.AddFile(entity.Name, stream, true);
string masterpageName = string.Concat(entity.Alias, ".master");
_masterpagesFileSystem.AddFile(masterpageName, stream, true);
}
}
@@ -236,6 +242,12 @@ namespace Umbraco.Core.Persistence.Repositories
{
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = ((Template)entity).ParentId });
entity.Path = string.Concat(parent.Path, ",", entity.Id);
((Template)entity).Level = parent.Level + 1;
var maxSortOrder =
Database.ExecuteScalar<int>(
"SELECT coalesce(max(sortOrder),0) FROM umbracoNode WHERE parentid = @ParentId AND nodeObjectType = @NodeObjectType",
new { ParentId = ((Template)entity).ParentId, NodeObjectType = NodeObjectTypeId });
((Template)entity).SortOrder = maxSortOrder + 1;
}
//Get TemplateDto from db to get the Primary key of the entity
@@ -328,8 +340,8 @@ namespace Umbraco.Core.Persistence.Repositories
public ITemplate Get(string alias)
{
var sql = GetBaseQuery(false);
sql.Where("cmsTemplate.alias = @Alias", new { Alias = alias });
var sql = GetBaseQuery(false)
.Where<TemplateDto>(x => x.Alias == alias);
var dto = Database.Fetch<TemplateDto, NodeDto>(sql).FirstOrDefault();
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Caching;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
@@ -4,7 +4,7 @@ using System.Data;
namespace Umbraco.Core.Persistence.SqlSyntax
{
internal class DbTypes<TSyntax>
public class DbTypes<TSyntax>
where TSyntax : ISqlSyntaxProvider
{
public DbType DbType;
@@ -31,6 +31,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string InsertData { get; }
string UpdateData { get; }
string DeleteData { get; }
string TruncateTable { get; }
string CreateConstraint { get; }
string DeleteConstraint { get; }
string CreateForeignKeyConstraint { get; }
@@ -48,6 +49,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
string FormatTableRename(string oldName, string newName);
bool SupportsClustered();
bool SupportsIdentityInsert();
bool? SupportsCaseInsensitiveQueries(Database db);
IEnumerable<string> GetTablesInSchema(Database db);
IEnumerable<ColumnInfo> GetColumnsInSchema(Database db);
IEnumerable<Tuple<string, string>> GetConstraintsPerTable(Database db);
@@ -7,21 +7,20 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Static class that provides simple access to the MySql SqlSyntax Providers singleton
/// Static class that provides simple access to the MySql SqlSyntax Provider
/// </summary>
internal static class MySqlSyntax
{
public static ISqlSyntaxProvider Provider { get { return MySqlSyntaxProvider.Instance; } }
public static ISqlSyntaxProvider Provider { get { return new MySqlSyntaxProvider(); } }
}
/// <summary>
/// Represents an SqlSyntaxProvider for MySql
/// </summary>
internal class MySqlSyntaxProvider : SqlSyntaxProviderBase<MySqlSyntaxProvider>
[SqlSyntaxProviderAttribute("MySql.Data.MySqlClient")]
public class MySqlSyntaxProvider : SqlSyntaxProviderBase<MySqlSyntaxProvider>
{
public static MySqlSyntaxProvider Instance = new MySqlSyntaxProvider();
private MySqlSyntaxProvider()
public MySqlSyntaxProvider()
{
DefaultStringLength = 255;
StringLengthColumnDefinitionFormat = StringLengthUnicodeColumnDefinitionFormat;
@@ -309,5 +308,33 @@ namespace Umbraco.Core.Persistence.SqlSyntax
public override string DropIndex { get { return "DROP INDEX {0} ON {1}"; } }
public override string RenameColumn { get { return "ALTER TABLE {0} CHANGE {1} {2}"; } }
public override bool? SupportsCaseInsensitiveQueries(Database db)
{
bool? supportsCaseInsensitiveQueries = null;
try
{
db.OpenSharedConnection();
// Need 4 @ signs as it is regarded as a parameter, @@ escapes it once, @@@@ escapes it twice
var lowerCaseFileSystem = db.Fetch<int>("SELECT @@@@Global.lower_case_file_system");
var lowerCaseTableNames = db.Fetch<int>("SELECT @@@@Global.lower_case_table_names");
if(lowerCaseFileSystem.Any() && lowerCaseTableNames.Any())
supportsCaseInsensitiveQueries = lowerCaseFileSystem.First() == 1 && lowerCaseTableNames.First() == 1;
}
catch(Exception ex)
{
Logging.LogHelper.Error<MySqlSyntaxProvider>("Error querying for lower_case support", ex);
}
finally
{
db.CloseSharedConnection();
}
// Could return null, which means testing failed,
// add message to check with their hosting provider
return supportsCaseInsensitiveQueries;
}
}
}
@@ -1,28 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Static class that provides simple access to the Sql CE SqlSyntax Providers singleton
/// Static class that provides simple access to the Sql CE SqlSyntax Provider
/// </summary>
internal static class SqlCeSyntax
{
public static ISqlSyntaxProvider Provider { get { return SqlCeSyntaxProvider.Instance; } }
public static ISqlSyntaxProvider Provider { get { return new SqlCeSyntaxProvider(); } }
}
/// <summary>
/// Represents an SqlSyntaxProvider for Sql Ce
/// </summary>
internal class SqlCeSyntaxProvider : SqlSyntaxProviderBase<SqlCeSyntaxProvider>
[SqlSyntaxProviderAttribute("System.Data.SqlServerCe.4.0")]
public class SqlCeSyntaxProvider : SqlSyntaxProviderBase<SqlCeSyntaxProvider>
{
public static SqlCeSyntaxProvider Instance = new SqlCeSyntaxProvider();
private SqlCeSyntaxProvider()
public SqlCeSyntaxProvider()
{
StringLengthColumnDefinitionFormat = StringLengthUnicodeColumnDefinitionFormat;
StringColumnDefinition = string.Format(StringLengthColumnDefinitionFormat, DefaultStringLength);
@@ -44,6 +42,14 @@ namespace Umbraco.Core.Persistence.SqlSyntax
return false;
}
/// <summary>
/// SqlCe doesn't support the Truncate Table syntax, so we just have to do a DELETE FROM which is slower but we have no choice.
/// </summary>
public override string TruncateTable
{
get { return "DELETE FROM {0}"; }
}
public override string GetIndexType(IndexTypes indexTypes)
{
string indexType;
@@ -6,21 +6,20 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Static class that provides simple access to the Sql Server SqlSyntax Providers singleton
/// Static class that provides simple access to the Sql Server SqlSyntax Provider
/// </summary>
internal static class SqlServerSyntax
{
public static ISqlSyntaxProvider Provider { get { return SqlServerSyntaxProvider.Instance; } }
public static ISqlSyntaxProvider Provider { get { return new SqlServerSyntaxProvider(); } }
}
/// <summary>
/// Represents an SqlSyntaxProvider for Sql Server
/// </summary>
internal class SqlServerSyntaxProvider : SqlSyntaxProviderBase<SqlServerSyntaxProvider>
[SqlSyntaxProviderAttribute("System.Data.SqlClient")]
public class SqlServerSyntaxProvider : SqlSyntaxProviderBase<SqlServerSyntaxProvider>
{
public static SqlServerSyntaxProvider Instance = new SqlServerSyntaxProvider();
private SqlServerSyntaxProvider()
public SqlServerSyntaxProvider()
{
StringLengthColumnDefinitionFormat = StringLengthUnicodeColumnDefinitionFormat;
StringColumnDefinition = string.Format(StringLengthColumnDefinitionFormat, DefaultStringLength);
@@ -3,9 +3,9 @@
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Singleton to handle the configuration of an SqlSyntaxProvider
/// Singleton to handle the configuration of a SqlSyntaxProvider
/// </summary>
internal static class SyntaxConfig
public static class SqlSyntaxContext
{
private static ISqlSyntaxProvider _sqlSyntaxProvider;
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence.SqlSyntax
if(_sqlSyntaxProvider == null)
{
throw new ArgumentNullException("SqlSyntaxProvider",
"You must set the singleton 'Umbraco.Core.Persistence.SqlSyntax.SyntaxConfig' to use an sql syntax provider");
"You must set the singleton 'Umbraco.Core.Persistence.SqlSyntax.SqlSyntaxContext' to use an sql syntax provider");
}
return _sqlSyntaxProvider;
}
@@ -0,0 +1,21 @@
using System;
namespace Umbraco.Core.Persistence.SqlSyntax
{
/// <summary>
/// Attribute for implementations of an ISqlSyntaxProvider
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class SqlSyntaxProviderAttribute : Attribute
{
public SqlSyntaxProviderAttribute(string providerName)
{
ProviderName = providerName;
}
/// <summary>
/// Gets or sets the ProviderName that corresponds to the sql syntax in a provider.
/// </summary>
public string ProviderName { get; set; }
}
}

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