Compare commits

...

133 Commits

Author SHA1 Message Date
Sebastiaan Janssen 21426610ad Need to take the current schema into account for the ExcessiveHeadersCheck 2016-10-19 17:01:15 +02:00
Sebastiaan Janssen 40b0a62cc3 Use int.MaxValue instead of 0 2016-10-19 14:58:56 +02:00
Shannon Deminick 3949b78c61 Merge pull request #1533 from callumbwhyte/U4-9042
U4-9042: Fixes backoffice members list view for custom membership providers
2016-10-19 14:48:44 +02:00
Claus 55179d7400 adding missing multiple content picker macro parameter. 2016-10-19 13:56:26 +02:00
Mads Rasmussen 517147346e Merge pull request #1534 from umbraco/temp-u4-9048
temp-U4-9048 - security when uploading files
2016-10-19 11:01:19 +02:00
Mads Rasmussen e1e63d079f add curly brackets to fix "grunt vs" task 2016-10-19 10:48:14 +02:00
Sebastiaan Janssen 86744046e3 Merge pull request #1531 from umbraco/temp-u4-8981
U4-8981 - fix package actions
2016-10-19 09:15:01 +02:00
Stephan a5f1c3e564 Merge pull request #1530 from umbraco/temp-U4-8769
fixes: U4-8769 ImageCropper focal points randomly sets to 'null'
2016-10-19 09:01:55 +02:00
Stephan 2b2734cd66 U4-8981 - fix package actions 2016-10-19 08:48:35 +02:00
Sebastiaan Janssen c2d33f3301 Merge pull request #1532 from richarth/patch-1
Update noNodes.aspx
2016-10-18 22:12:52 +02:00
Sebastiaan Janssen 8fc999f771 Merge pull request #1510 from lukawefocus/dev-v7
U4-7238 issue sorting listview after 7.3.0 upgrade
2016-10-18 20:25:17 +02:00
Sebastiaan Janssen be0fb51193 Merge pull request #1529 from mzajkowski/U4-6710
Cast tag value to unicoded text before inserting it into database
2016-10-18 18:37:11 +02:00
Sebastiaan Janssen 097f5355e2 U4-9050 Update to latest Examine 0.1.70.0 2016-10-18 18:03:43 +02:00
Sebastiaan Janssen 843fad9963 Merge pull request #1477 from arknu/U4-8968
Fix U4-8968: Add missing check for backoffice session in ClaimsIdentity
2016-10-18 17:53:14 +02:00
Sebastiaan Janssen 7b5670f275 U4-9076 Update to latest ImageProcessor 2016-10-18 16:45:16 +02:00
Sebastiaan Janssen f4410891e4 Merge pull request #1459 from umbraco/temp-U4-8829-dashboards-from-remote-feed
Temp u4 8829 dashboards from remote feed
2016-10-18 15:50:15 +02:00
Sebastiaan Janssen 9da95ce28f Moved UmbracoAuthorize to the class level
Unfortunately can't consolidate GetCacheItem and InsertCacheItem because of different timespan
Can't directly cache the `content` variable due to problems with modified closures
2016-10-18 14:16:37 +02:00
Sebastiaan Janssen 33e05625ed Fixes based on review 2016-10-18 10:10:50 +02:00
Sebastiaan Janssen b8575d04ad Adds default/fallback dashboard missing content 2016-10-18 09:56:25 +02:00
Stephan b64b67ce81 U4-9048 - return proper Forbidden status code when uploading to invalid folder 2016-10-18 08:47:03 +02:00
Stephan 1b6a2c7d5c U4-9048 - validate user before retrying queued promises 2016-10-18 08:46:41 +02:00
Callum Whyte a1a90d5bff Fixes backoffice members list view for custom membership providers by using key instead of id in edit URL 2016-10-17 16:26:20 +01:00
richarth 08733d7351 Update noNodes.aspx
Grammar correction
2016-10-17 14:28:16 +01:00
Sebastiaan Janssen 5d0d65c624 Merge branch 'dev-v7' into temp-U4-8829-dashboards-from-remote-feed 2016-10-17 15:00:40 +02:00
Stephan 6c7c333d8f Merge pull request #1523 from umbraco/temp-U4-8896
fixes: U4-8896 U7 (7.4.2) - Uploading images in media library fails
2016-10-17 14:45:24 +02:00
Mads Rasmussen b039fbfb13 Merge pull request #1498 from bjarnef/dev-v7-U4-9007
Format package created date
2016-10-17 14:41:36 +02:00
Mads Rasmussen 428bc7fbad Merge pull request #1525 from JeffreyPerplex/patch-2
Update imagecropper.html
2016-10-17 14:21:55 +02:00
Stephan fe9686f215 U4-8981 - fix package actions 2016-10-17 14:21:51 +02:00
Mads Rasmussen e4a472f902 fixes: U4-8769 ImageCropper focal points randomly sets to 'null' 2016-10-17 13:32:09 +02:00
Sebastiaan Janssen 900f8970f0 Check for null orderBy argument earlier to avoid doing unnecessary work 2016-10-17 09:56:50 +02:00
Claus dd6c24d3b8 Merge pull request #1527 from leekelleher/issue/U4-9073
Grid: Quote editor - wrong CSS style rule for italic
2016-10-17 09:08:52 +02:00
Marcin Zajkowski 8175e68ecd Cast tag value to unicoded text before inserting it into database
Quick fix for: http://issues.umbraco.org/issue/U4-6710
2016-10-16 03:15:02 +02:00
leekelleher c839285f90 Grid: Quote editor - wrong CSS style rule for italic
[Issue #U4-9073](http://issues.umbraco.org/issue/U4-9073)

In `grid.editors.config.js`, the style config for the Quote editor has an incorrect CSS style rule for italic, it has...

```css
font-variant: italic;
```

It should be...

```css
font-style: italic;
```

I wasn't sure which `grid.editors.config.js` to change, so I did them all.
2016-10-14 16:37:06 +01:00
Claus 21378a07c8 Merge pull request #1466 from AndyButland/u4-8941
u4-8941 - Used configurable application URL when constructing password reset link
2016-10-14 11:05:37 +02:00
Jeffrey Schoemaker 74e6633f2a Update imagecropper.html
Remove ng-show="imageIsLoaded" so "Remove file" is always visible when there's an image or file uploaded, even if it can't be rendered because whether is .tif-file (correct image, but not rendered in modern browsers), .pdf-file (foolish action) or the image is removed from the server (staging with a production-environment-database).

Related to http://issues.umbraco.org/issue/U4-8490
2016-10-14 10:31:12 +02:00
Claus 8693b13e68 Merge pull request #1511 from umbraco/temp-U4-8992
U4-8992 - update content and media xml caches when upgrading from bef…
2016-10-13 15:31:09 +02:00
Mads Rasmussen a0a861370b Merge pull request #1499 from darrenferguson/dev-v7
U4-9012 The word "Oops" should probably be removed, because we can ca…
2016-10-13 15:20:59 +02:00
Mads Rasmussen 7282626c0f Merge pull request #1514 from abryukhov/patch-6
Update UI language ru.xml
2016-10-13 14:50:12 +02:00
Mads Rasmussen cf604255fc fixes: U4-8896 U7 (7.4.2) - Uploading images in media library fails 2016-10-13 13:12:24 +02:00
Shannon Deminick b275850aca Merge pull request #1515 from seth-reeser/patch-1
Update README.md
2016-10-13 11:46:43 +02:00
Seth Reeser 8aa36a82c4 Update README.md 2016-10-12 22:48:10 -04:00
Alexander Bryukhov 06132fcdaf Update UI language ru.xml
New key in healthCheck area added
2016-10-12 11:17:04 +07:00
Stephan f1e5b3fcfa Prevent tests from failing due to dates rounding 2016-10-11 15:06:33 +02:00
Mads Rasmussen fba4b91bec Merge pull request #1465 from abryukhov/patch-6
Localizing URL tracker dashboard
2016-10-11 14:42:37 +02:00
Mads Rasmussen 0ef987207b Merge pull request #1489 from abryukhov/patch-7
U4-8985 Label for row configurations in the grid editor
2016-10-11 14:21:06 +02:00
Mads Rasmussen 2d7b5b959e Merge pull request #1497 from bjarnef/dev-v7-U4-8897
Change color of remove button to red
2016-10-11 14:01:27 +02:00
Mads Rasmussen 2837861d9a Merge pull request #1501 from jt3432/dev-v7
Added title attribute to image tags
2016-10-11 13:27:32 +02:00
Mads Rasmussen 212222c98e Merge pull request #1505 from bjarnef/dev-v7-U4-9031
Make increase/decrease buttons in grid layout and row configurations …
2016-10-11 13:14:09 +02:00
Mads Rasmussen 15237a6d91 Merge pull request #1512 from Joddsson/changeDocTypeToolbar
Styled toolbar buttons in ChangeDocType dialog
2016-10-11 13:02:03 +02:00
Ivar 95b2ef0f3c Styled toolbar buttons in ChangeDocType dialog 2016-10-10 23:27:42 +00:00
Stephan c452d31f25 Prevent tests from failing due to dates rounding 2016-10-10 19:18:49 +02:00
Stephan 7361d1f16f U4-8992 - update content and media xml caches when upgrading from before 7.3 2016-10-10 18:25:54 +02:00
Luka Kuljic 7ffb22a40f U4-7238 issue sorting listview after 7.3.0 upgrade
http://issues.umbraco.org/issue/U4-7238

System field publish only available for Content, didn't work on content
sorting by this field. Fixed by prefixing the field with table:
cmsDocumen.published.
2016-10-06 15:59:59 +02:00
Claus f78e496e69 Merge pull request #1509 from umbraco/temp-u4-8983
U4-8983 - clear EntityService cache on content events
2016-10-06 10:56:30 +02:00
Stephan 48ed511ba5 U4-8983 - clear EntityService cache on content events 2016-10-06 09:06:25 +02:00
Stephan 3cff6fdd6c Merge pull request #1451 from umbraco/temp-u4-8698
U4-8698 - fix notification service perfs issues
2016-10-06 08:31:39 +02:00
Shannon Deminick 81da2e49f7 Merge pull request #1508 from umbraco/temp-U4-9005
U4-9005 Update comments in urlrewriting.config to note it's obsolete
2016-10-05 18:32:51 +02:00
Shannon 2cd6427958 Fixes more issues with notifications which weren't sending properly do to a i++ instead of a ++1, have refactored that to read better. Also fixes up performance issues since we were returning every single fully resolved IContent for all versions when all we need is the top 2 version ids, have added methods to do that plus a unit test. Have tested the emails and the diffs and they all work. 2016-10-05 18:30:03 +02:00
Sebastiaan Janssen 061f1ae0b1 U4-9005 Update comments in urlrewriting.config to note it's obsolete 2016-10-05 17:49:09 +02:00
Shannon f503cd41de Merge branch 'refs/heads/dev-v7' into temp-u4-8698 2016-10-05 11:52:05 +02:00
Shannon Deminick 4428877158 Merge pull request #1507 from umbraco/temp-U4-6809
U4-6809 u7.2.6 Updating media items with large file cause out of memo…
2016-10-05 11:23:50 +02:00
Shannon 876f61ac27 U4-8788 ContentService.GetByIds() returns items in different order
U4-8937 ContentController.PostSort is not honouring the passed sorted ids.
2016-10-05 11:20:48 +02:00
Claus 2cc541e084 U4-6809 u7.2.6 Updating media items with large file cause out of memory exception 2016-10-05 11:06:51 +02:00
Shannon ddd3c78fa6 Merge branch 'refs/heads/temp-u4-8937' into dev-v7 2016-10-05 11:05:44 +02:00
Shannon Deminick 62dffedc02 Merge pull request #1491 from umbraco/temp-U4-9001
U4-9001 Health Check, HTTPS Configuration is missing a message when c…
2016-10-05 10:53:49 +02:00
Claus 13e5409ab2 Merge pull request #1492 from jswietek/U4-8975
U4 8975
2016-10-05 10:51:14 +02:00
bjarnef 927e9cf14a Make increase/decrease buttons in grid layout and row configurations use same icons 2016-10-02 21:09:52 +02:00
Per Ploug 7611829f2e Changes http to https 2016-09-29 13:28:57 +02:00
Jason Thomas 1ff5d171e3 Added title attribute to image tags for mediapicker.html and umb-media-grid.html. 2016-09-28 17:22:08 -06:00
Sebastiaan Janssen b8aaebf51a Fix automapper remove/insert transform 2016-09-28 16:05:35 +02:00
Shannon Deminick 2c9bc5135c Merge pull request #1483 from umbraco/temp-U4-8984
U4-8984 Upgrade AutoMapper to latest 3.x
2016-09-28 15:41:38 +02:00
Shannon 248177f518 Ensures Nuspec has correct AutoMapper, ensures config transform is correct (we cannot remove something that isn't there since it never existed before) 2016-09-28 15:33:32 +02:00
Shannon Deminick d34901fd13 Merge pull request #1500 from markwemekamp/dev-v7
Bugfix in Initialize method of UmbracoMediaFile
2016-09-27 09:44:29 +02:00
Mark 94b12dfb02 Updated code according to coding rules 2016-09-27 09:36:35 +02:00
Mark 0cc88a1706 Bugfix in Initialize method of UmbracoMediaFile
GetExtension returns an empty string instead of null which causes the
substring to return an argumentoutofrange exception. Discovered this
when trying to use Save(HttpPostedFile file) and Save(HttpPostedFileBase
file), but since the temporary generated path didn't include an
extension, these methods always threw an exception
2016-09-27 09:08:56 +02:00
Darren Ferguson 78524398b7 U4-9012 The word "Oops" should probably be removed, because we can cancel publish by API, it may be deliberate. http://issues.umbraco.org/issue/U4-9012 2016-09-23 18:43:55 +01:00
bjarnef f97123015a Format package created date 2016-09-22 19:55:32 +02:00
bjarnef b1e6559f4d Change color of remove button to red 2016-09-22 19:29:32 +02:00
Sebastiaan Janssen 9d9c36b253 U4-9001 Health Check, HTTPS Configuration is missing a message when certificate is valid 2016-09-21 13:04:06 +02:00
Jakub Swietek 6d9a747b34 Added option to delete cell from a row 2016-09-21 13:00:02 +02:00
Jakub Swietek a28cd8a54f Changed row cell's minimum width to 1 2016-09-21 12:57:57 +02:00
Jakub Swietek 44ad842542 Added option to delete selected section from layout 2016-09-21 12:56:31 +02:00
Jakub Swietek 917e05a16c Changed section's minimum width to 1 2016-09-21 12:55:05 +02:00
Alexander Bryukhov e60d5c8f2c U4-8985 Label for row configurations in the grid editor 2016-09-20 20:39:31 +07:00
Warren Buckley 03f16dfb78 Merge pull request #1485 from umbraco/temp-U4-8986
U4-8986 Allowing for more complex settings of the applyTo configurati…
2016-09-20 10:40:48 +01:00
Claus c9106065fd config transform for nuget upgrade. 2016-09-20 09:12:44 +02:00
Warren Buckley 2c9e96406b Merge pull request #1486 from umbraco/temp-U4-8987
U4-8987 Grid editor radiobuttonlist in settings should allow prevalue…
2016-09-19 12:01:54 +01:00
Warren Buckley 21c7d6a667 Merge pull request #1484 from umbraco/temp-U4-8985
U4-8985 Label for row configurations in the grid editor
2016-09-19 10:45:22 +01:00
Warren Buckley e0f95f18d3 Small mod to ensure the copy for the updated warning is easier to read that modifying the label is OK to do so 2016-09-19 10:07:23 +01:00
Warren Buckley b9ffbe9a57 Merge pull request #1481 from umbraco/temp-U4-8924
U4-8924 Heath Check: Pingback to HTTPS uses wrong protocol
2016-09-19 09:11:38 +01:00
Sebastiaan Janssen dc9b2b3ca8 Fix the ClickJackingCheck to make sure it adds an "s" to "http" when SSL is enforced or site is running on port 443 2016-09-19 09:44:03 +02:00
Claus baafa604fe Merge pull request #1448 from abjerner/patch-11
The p in picker should be uppercase
2016-09-17 14:34:04 +02:00
Claus e79bfebb76 U4-8987 Grid editor radiobuttonlist in settings should allow prevalues to have a label 2016-09-17 14:01:58 +02:00
Claus 131fdab675 U4-8986 Allowing for more complex settings of the applyTo configuration for grid editor. 2016-09-17 12:35:49 +02:00
Claus efc2a8e2ea U4-8985 Label for row configurations in the grid editor 2016-09-16 23:20:47 +02:00
Claus d725f1362f U4-8984 Upgrade AutoMapper to latest 3.x 2016-09-16 21:23:31 +02:00
Claus e79427619b Revert "U4-8984 Upgrade AutoMapper to latest 3.x"
This reverts commit 4887302b51.
2016-09-16 21:22:35 +02:00
Claus 4887302b51 U4-8984 Upgrade AutoMapper to latest 3.x 2016-09-16 21:21:14 +02:00
Warren Buckley aea735f20e Merge pull request #1441 from umbraco/temp-U4-8866
U4-8866 Deleting a parent document type fails if any documents using …
2016-09-16 15:46:50 +01:00
Warren Buckley 7a34b490c7 Merge pull request #1468 from umbraco/temp-u4-8954
U4-8954 - fix WhereIn issue with non-value-types
2016-09-16 11:37:12 +01:00
Warren Buckley 8091d9a098 Resetting UmbracoSettings file in this PR back to what it was previously - seems to have been committed by mistake 2016-09-16 11:04:50 +01:00
Sebastiaan Janssen e2e6440109 Merge pull request #1482 from romanlytvyn/temp-u4-8956
U4-8956 PublicAccessEntry.ClearRules() triggers an unhandled exception
2016-09-16 09:49:54 +02:00
Roman Lytvyn caffb36ec2 U4-8956 PublicAccessEntry.ClearRules() triggers an unhandled exception
fixed System.InvalidOperationException (Collection was modified;
enumeration operation may not execute.) by reverse iterating the
collection.
2016-09-16 10:35:14 +03:00
Sebastiaan Janssen 0d054de6ac U4-8924 Heath Check: Pingback to HTTPS uses wrong protocol 2016-09-15 17:37:42 +02:00
Warren Buckley 5397f2c53a Merge pull request #1447 from umbraco/temp-u4-8906
U4-8906 - optimize member perfs
2016-09-15 15:14:34 +01:00
Warren Buckley 61b11025bd Merge pull request #1476 from umbraco/temp-U4-8966
U4-8966 Unable to uninstall Umbraco Forms - The relative virtual path…
2016-09-15 13:40:48 +01:00
Claus 8c8a0160a1 U4-7705 Media Picker does not render when image has been deleted
refixing - seems to have been left out in a merge somewhere.
2016-09-14 08:43:32 +02:00
Asbjørn Riis-Knudsen cbd980357b Fix U4-8968: Add missing check for backoffice session in ClaimsIdentity (like the comment says) 2016-09-13 22:36:14 +02:00
Sebastiaan Janssen 8b37f1dc6c Really cleaned up all of the other unneeded usings now... 2016-09-12 23:29:34 +02:00
Sebastiaan Janssen 6ec7028fe8 No need to add umbraco.Utils.. also cleaned up all of the other unneeded usings 2016-09-12 23:26:39 +02:00
Sebastiaan Janssen 14c0055899 U4-8966 Unable to uninstall Umbraco Forms - The relative virtual path 'bin/Umbraco.Forms.Core.dll' is not allowed here. 2016-09-12 23:24:01 +02:00
Claus e0981f1c44 Merge pull request #1475 from umbraco/temp-U4-8965
U4-8965 Updates for ImageProcessor parameters to support new crop mod…
2016-09-12 13:36:24 +02:00
Claus 2ca7304215 Merge pull request #1444 from Jeavon/u4-8876
Update ImageCropMode & ImageCropAnchor enums with options available i…
2016-09-12 13:33:03 +02:00
Claus 88f8052573 U4-8965 Updates for ImageProcessor parameters to support new crop modes in v. 4.4.0 2016-09-12 12:51:48 +02:00
Stephan 5afeb315ba U4-8954 - rename file 2016-09-08 10:39:56 +02:00
Stephan c2eeff6e47 U4-8954 - fix WhereIn issue with non-value-types 2016-09-08 10:37:03 +02:00
Shannon 893c2a99be adds some comments 2016-09-08 09:30:13 +02:00
AndyButland 9da18d0697 Used configurable application URL when constructing password reset link 2016-09-06 08:42:53 +02:00
Alexander Bryukhov 3bb991edd3 Missing key 'signInWith' added 2016-09-06 11:52:19 +07:00
Alexander Bryukhov dd0373b855 Localizing URL tracker dashboard 2016-09-06 11:36:00 +07:00
Stephan fce0a4b0eb U4-8937 - cleanup 2016-09-05 12:20:05 +02:00
Stephan 381de750e7 Merge branch 'U4-8937' of https://github.com/SayTen/Umbraco-CMS into temp-u4-8937 2016-09-05 11:44:06 +02:00
Per Ploug f5d18157bf resource to load dashboard data 2016-09-02 16:27:40 +02:00
Per Ploug 7c7dd0736e DashboardBoard to render remote grid data
- Includes offline mode
- loading state
- replaces content with data loaded from dashboard.umbraco.org
2016-09-02 16:27:30 +02:00
Per Ploug 0a5cd9f113 Change dashboardcontroller to UmbracoApiController
- Enables us to proxy css through the local server without a token on
the css request
- Adds method to load remote grid json
- Adds method to load remote grid css
2016-09-02 16:26:47 +02:00
Matt Cheale 9b498b8471 U4-8937 ContentController.PostSort is not honouring the passed sorted ids.
* Updates media to content for comments and logging.
* Adds sorting of the retrieved content items to match the passed sort order before persisting.
2016-09-02 14:50:54 +01:00
Stephan 365da75d1b U4-8698 - fix notification service perfs issues 2016-09-01 15:25:40 +02:00
Stephan 3489bf22bb U4-8698 - fix notification service perfs issues 2016-09-01 12:15:03 +02:00
Stephan 9e82b8d693 U4-8906 - optimize member perfs 2016-09-01 12:11:12 +02:00
Anders Bjerner 8216fa1d88 The p in picker should be uppercase 2016-08-26 21:49:10 +02:00
Stephan 4133574db0 U4-8906 - optimize member perfs 2016-08-26 15:30:24 +02:00
Jeavon bc9a6abccf Update ImageCropMode & ImageCropAnchor enums with options available in ImageProcessor v4.4+ 2016-08-19 16:14:56 +01:00
Claus 9f5a9f179f U4-8866 Deleting a parent document type fails if any documents using a child document type exist
ensures that we also manually delete content of any child content type being deleted, instead of only deleting content of the actual content type sent for delete.
2016-08-18 11:17:05 +02:00
104 changed files with 1747 additions and 934 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ If you're interested in making changes to Belle without running Visual Studio ma
Note that you can always [download a nightly build](http://nightly.umbraco.org/?container=umbraco-750) so you don't have to build the code yourself.
## Watch a introduction video ##
## Watch an introduction video ##
[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/)
+4 -4
View File
@@ -30,11 +30,11 @@
<dependency id="ClientDependency" version="[1.9.1, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
<!-- AutoMapper can not be updated due to: https://github.com/AutoMapper/AutoMapper/issues/373#issuecomment-127644405 -->
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
<dependency id="Examine" version="[0.1.69, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.4.4, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.6.4, 5.0.0)" />
<dependency id="Examine" version="[0.1.70, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.4.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.6.6, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
@@ -319,6 +319,7 @@
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='HtmlAgilityPack')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='AutoMapper')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Newtonsoft.Json')" xdt:Transform="Remove" />
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Web.Mvc')" xdt:Transform="Remove" />
@@ -338,6 +339,10 @@
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.4.9.0" newVersion="1.4.9.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="AutoMapper" publicKeyToken="be96cd2c38ef1005" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.3.1.0" newVersion="3.3.1.0" />
</dependentAssembly>
<dependentAssembly xdt:Transform="Insert">
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
+1 -1
View File
@@ -1,2 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.5.3
7.5.4
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.5.3")]
[assembly: AssemblyInformationalVersion("7.5.3")]
[assembly: AssemblyFileVersion("7.5.4")]
[assembly: AssemblyInformationalVersion("7.5.4")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.5.3");
private static readonly Version Version = new Version("7.5.4");
/// <summary>
/// Gets the current version of Umbraco.
@@ -69,6 +69,11 @@ namespace Umbraco.Core
/// </summary>
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
/// <summary>
/// Guid for a Document object.
/// </summary>
public static readonly Guid DocumentGuid = new Guid(Document);
/// <summary>
/// Guid for a Document Type object.
/// </summary>
@@ -128,8 +128,14 @@ namespace Umbraco.Core.Events
get { return TargetSemVersion.GetVersion(); }
}
/// <summary>
/// Gets the origin version of the migration, i.e. the one that is currently installed.
/// </summary>
public SemVersion ConfiguredSemVersion { get; private set; }
/// <summary>
/// Gets the target version of the migration.
/// </summary>
public SemVersion TargetSemVersion { get; private set; }
public string ProductName { get; private set; }
+1 -5
View File
@@ -41,11 +41,7 @@ namespace Umbraco.Core.IO
{
using (var file = fs.OpenFile(path))
{
using (var sr = new StreamReader(file))
{
var str = sr.ReadToEnd();
return str.Length;
}
return file.Length;
}
}
+1 -1
View File
@@ -86,7 +86,7 @@ namespace Umbraco.Core.IO
private void Initialize()
{
Filename = _fs.GetFileName(Path);
Extension = _fs.GetExtension(Path) != null
Extension = string.IsNullOrEmpty(_fs.GetExtension(Path)) == false
? _fs.GetExtension(Path).Substring(1).ToLowerInvariant()
: "";
Url = _fs.GetUrl(Path);
+2 -2
View File
@@ -107,9 +107,9 @@ namespace Umbraco.Core.Models
public void ClearRules()
{
foreach (var rule in _ruleCollection)
for (var i = _ruleCollection.Count - 1; i >= 0; i--)
{
RemoveRule(rule);
RemoveRule(_ruleCollection[i]);
}
}
@@ -122,7 +122,7 @@ namespace Umbraco.Core.Persistence.Factories
else if (entity is IMemberType)
nodeObjectType = Constants.ObjectTypes.MemberTypeGuid;
else
throw new Exception("oops: invalid entity.");
throw new Exception("Invalid entity.");
var contentTypeDto = new ContentTypeDto
{
@@ -79,7 +79,7 @@ namespace Umbraco.Core.Persistence.Factories
{
// note: no idea why Id is nullable here, but better check
if (groupDto.Id.HasValue == false)
throw new Exception("oops: groupDto.Id has no value.");
throw new Exception("GroupDto.Id has no value.");
group.Id = groupDto.Id.Value;
}
@@ -34,11 +34,27 @@ namespace Umbraco.Core.Persistence
return sql.Where(whereExpression, expresionist.GetSqlParameters());
}
private static string GetFieldName<T>(Expression<Func<T, object>> fieldSelector, ISqlSyntaxProvider sqlSyntax)
{
var field = ExpressionHelper.FindProperty(fieldSelector) as PropertyInfo;
var fieldName = field.GetColumnName();
var type = typeof(T);
var tableName = type.GetTableName();
return sqlSyntax.GetQuotedTableName(tableName) + "." + sqlSyntax.GetQuotedColumnName(fieldName);
}
[Obsolete("Use the overload specifying ISqlSyntaxProvider instead")]
public static Sql WhereIn<T>(this Sql sql, Expression<Func<T, object>> fieldSelector, IEnumerable values)
{
var expresionist = new PocoToSqlExpressionHelper<T>();
var fieldExpression = expresionist.Visit(fieldSelector);
return sql.Where(fieldExpression + " IN (@values)", new {@values = values});
return sql.WhereIn(fieldSelector, values, SqlSyntaxContext.SqlSyntaxProvider);
}
public static Sql WhereIn<T>(this Sql sql, Expression<Func<T, object>> fieldSelector, IEnumerable values, ISqlSyntaxProvider sqlSyntax)
{
var fieldName = GetFieldName(fieldSelector, sqlSyntax);
return sql.Where(fieldName + " IN (@values)", new { values });
}
[Obsolete("Use the overload specifying ISqlSyntaxProvider instead")]
@@ -49,17 +65,7 @@ namespace Umbraco.Core.Persistence
public static Sql OrderBy<TColumn>(this Sql sql, Expression<Func<TColumn, object>> columnMember, ISqlSyntaxProvider sqlSyntax)
{
var column = ExpressionHelper.FindProperty(columnMember) as PropertyInfo;
var columnName = column.GetColumnName();
var type = typeof(TColumn);
var tableName = type.GetTableName();
//need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
var syntax = string.Format("({0}.{1})",
sqlSyntax.GetQuotedTableName(tableName),
sqlSyntax.GetQuotedColumnName(columnName));
var syntax = "(" + GetFieldName(columnMember, sqlSyntax) + ")";
return sql.OrderBy(syntax);
}
@@ -34,11 +34,19 @@ namespace Umbraco.Core.Persistence.Repositories
int CountDescendants(int parentId, string contentTypeAlias = null);
/// <summary>
/// Gets a list of all versions for an <see cref="TEntity"/>.
/// Gets a list of all versions for an <see cref="TEntity"/> ordered so latest is first
/// </summary>
/// <param name="id">Id of the <see cref="TEntity"/> to retrieve versions from</param>
/// <returns>An enumerable list of the same <see cref="TEntity"/> object with different versions</returns>
IEnumerable<TEntity> GetAllVersions(int id);
IEnumerable<TEntity> GetAllVersions(int id);
/// <summary>
/// Gets a list of all version Ids for the given content item
/// </summary>
/// <param name="id"></param>
/// <param name="maxRows">The maximum number of rows to return</param>
/// <returns></returns>
IEnumerable<Guid> GetVersionIds(int id, int maxRows);
/// <summary>
/// Gets a specific version of an <see cref="TEntity"/>.
@@ -18,6 +18,27 @@ namespace Umbraco.Core.Persistence.Repositories
_unitOfWork = unitOfWork;
}
public IEnumerable<Notification> GetUsersNotifications(IEnumerable<int> userIds, string action, IEnumerable<int> nodeIds, Guid objectType)
{
var nodeIdsA = nodeIds.ToArray();
var syntax = ApplicationContext.Current.DatabaseContext.SqlSyntax; // bah
var sql = new Sql()
.Select("DISTINCT umbracoNode.id nodeId, umbracoUser.id userId, umbracoNode.nodeObjectType, umbracoUser2NodeNotify.action")
.From<User2NodeNotifyDto>(syntax)
.InnerJoin<NodeDto>(syntax).On<User2NodeNotifyDto, NodeDto>(syntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<UserDto>(syntax).On<User2NodeNotifyDto, UserDto>(syntax, left => left.UserId, right => right.Id)
.Where<NodeDto>(x => x.NodeObjectType == objectType)
.Where<UserDto>(x => x.Disabled == false) // only approved users
.Where<User2NodeNotifyDto>(x => x.Action == action); // on the specified action
if (nodeIdsA.Length > 0)
sql
.WhereIn<NodeDto>(x => x.NodeId, nodeIdsA); // for the specified nodes
sql
.OrderBy<UserDto>(x => x.Id, syntax)
.OrderBy<NodeDto>(dto => dto.NodeId, syntax);
return _unitOfWork.Database.Fetch<dynamic>(sql).Select(x => new Notification(x.nodeId, x.userId, x.action, objectType));
}
public IEnumerable<Notification> GetUserNotifications(IUser user)
{
var sql = new Sql()
@@ -565,7 +565,7 @@ namespace Umbraco.Core.Persistence.Repositories
var array = tagsToInsert
.Select(tag =>
string.Format("select '{0}' as Tag, '{1}' as " + SqlSyntax.GetQuotedColumnName("group") + @"",
string.Format("select N'{0}' as Tag, '{1}' as " + SqlSyntax.GetQuotedColumnName("group") + @"",
PetaPocoExtensions.EscapeAtSymbols(tag.Text.Replace("'", "''")), tag.Group))
.ToArray();
return "(" + string.Join(" union ", array).Replace(" ", " ") + ") as TagSet";
@@ -320,51 +320,51 @@ namespace Umbraco.Core.Persistence.Repositories
/// </remarks>
public IEnumerable<IUser> GetPagedResultsByQuery(IQuery<IUser> query, int pageIndex, int pageSize, out int totalRecords, Expression<Func<IUser, string>> orderBy)
{
if (orderBy == null) throw new ArgumentNullException("orderBy");
if (orderBy == null)
throw new ArgumentNullException("orderBy");
var sql = new Sql();
sql.Select("*").From<UserDto>();
Sql resultQuery;
if (query != null)
{
var translator = new SqlTranslator<IUser>(sql, query);
resultQuery = translator.Translate();
}
else
{
resultQuery = sql;
}
//get the referenced column name
// get the referenced column name and find the corresp mapped column name
var expressionMember = ExpressionHelper.GetMemberInfo(orderBy);
//now find the mapped column name
var mapper = MappingResolver.Current.ResolveMapperByType(typeof(IUser));
var mappedField = mapper.Map(expressionMember.Name);
if (mappedField.IsNullOrWhiteSpace())
{
throw new ArgumentException("Could not find a mapping for the column specified in the orderBy clause");
}
//need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
resultQuery.OrderBy(string.Format("({0})", mappedField));
var pagedResult = Database.Page<UserDto>(pageIndex + 1, pageSize, resultQuery);
var sql = new Sql()
.Select("umbracoUser.Id")
.From<UserDto>(SqlSyntax);
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
var idsQuery = query == null ? sql : new SqlTranslator<IUser>(sql, query).Translate();
// need to ensure the order by is in brackets, see: https://github.com/toptensoftware/PetaPoco/issues/177
idsQuery.OrderBy("(" + mappedField + ")");
var page = Database.Page<int>(pageIndex + 1, pageSize, idsQuery);
totalRecords = Convert.ToInt32(page.TotalItems);
//now that we have the user dto's we need to construct true members from the list.
if (totalRecords == 0)
{
return Enumerable.Empty<IUser>();
}
var ids = pagedResult.Items.Select(x => x.Id).ToArray();
var result = ids.Length == 0 ? Enumerable.Empty<IUser>() : GetAll(ids);
//now we need to ensure this result is also ordered by the same order by clause
return result.OrderBy(orderBy.Compile());
// now get the actual users and ensure they are ordered properly (same clause)
var ids = page.Items.ToArray();
return ids.Length == 0 ? Enumerable.Empty<IUser>() : GetAll(ids).OrderBy(orderBy.Compile());
}
internal IEnumerable<IUser> GetNextUsers(int id, int count)
{
var idsQuery = new Sql()
.Select("umbracoUser.Id")
.From<UserDto>(SqlSyntax)
.Where<UserDto>(x => x.Id >= id)
.OrderBy<UserDto>(x => x.Id, SqlSyntax);
// first page is index 1, not zero
var ids = Database.Page<int>(1, count, idsQuery).Items.ToArray();
// now get the actual users and ensure they are ordered properly (same clause)
return ids.Length == 0 ? Enumerable.Empty<IUser>() : GetAll(ids).OrderBy(x => x.Id);
}
/// <summary>
/// Returns permissions for a given user for any number of nodes
/// </summary>
@@ -40,6 +40,11 @@ namespace Umbraco.Core.Persistence.Repositories
#region IRepositoryVersionable Implementation
/// <summary>
/// Gets a list of all versions for an <see cref="TEntity"/> ordered so latest is first
/// </summary>
/// <param name="id">Id of the <see cref="TEntity"/> to retrieve versions from</param>
/// <returns>An enumerable list of the same <see cref="TEntity"/> object with different versions</returns>
public virtual IEnumerable<TEntity> GetAllVersions(int id)
{
var sql = new Sql();
@@ -60,6 +65,28 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
/// <summary>
/// Gets a list of all version Ids for the given content item ordered so latest is first
/// </summary>
/// <param name="id"></param>
/// <param name="maxRows">The maximum number of rows to return</param>
/// <returns></returns>
public virtual IEnumerable<Guid> GetVersionIds(int id, int maxRows)
{
var sql = new Sql();
sql.Select("cmsDocument.versionId")
.From<DocumentDto>(SqlSyntax)
.InnerJoin<ContentDto>(SqlSyntax)
.On<DocumentDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
.Where<NodeDto>(x => x.NodeId == id)
.OrderByDescending<DocumentDto>(x => x.UpdateDate, SqlSyntax);
return Database.Fetch<Guid>(SqlSyntax.SelectTop(sql, maxRows));
}
public virtual void DeleteVersion(Guid versionId)
{
var dto = Database.FirstOrDefault<ContentVersionDto>("WHERE versionId = @VersionId", new { VersionId = versionId });
@@ -583,6 +610,8 @@ WHERE EXISTS(
return "cmsContentVersion.VersionDate";
case "NAME":
return "umbracoNode.text";
case "PUBLISHED":
return "cmsDocument.published";
case "OWNER":
//TODO: This isn't going to work very nicely because it's going to order by ID, not by letter
return "umbracoNode.nodeUser";
@@ -113,8 +113,8 @@ namespace Umbraco.Core.Security
//Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session
var claimsIdentity = http.User.Identity as ClaimsIdentity;
if (claimsIdentity != null && claimsIdentity.IsAuthenticated)
{
if (claimsIdentity != null && claimsIdentity.IsAuthenticated && claimsIdentity.HasClaim(x => x.Type == Constants.Security.SessionIdClaimType))
{
try
{
return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity);
+29 -2
View File
@@ -342,11 +342,23 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IContent"/></returns>
public IEnumerable<IContent> GetByIds(IEnumerable<int> ids)
{
if (ids.Any() == false) return Enumerable.Empty<IContent>();
var idsArray = ids.ToArray();
if (idsArray.Length == 0) return Enumerable.Empty<IContent>();
using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
{
return repository.GetAll(ids.ToArray());
//ensure that the result has the order based on the ids passed in
var result = repository.GetAll(idsArray);
var content = result.ToDictionary(x => x.Id, x => x);
var sortedResult = idsArray.Select(x =>
{
IContent c;
return content.TryGetValue(x, out c) ? c : null;
}).WhereNotNull();
return sortedResult;
}
}
@@ -436,6 +448,21 @@ namespace Umbraco.Core.Services
}
}
/// <summary>
/// Gets a list of all version Ids for the given content item ordered so latest is first
/// </summary>
/// <param name="id"></param>
/// <param name="maxRows">The maximum number of rows to return</param>
/// <returns></returns>
public IEnumerable<Guid> GetVersionIds(int id, int maxRows)
{
using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
{
var versions = repository.GetVersionIds(id, maxRows);
return versions;
}
}
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects, which are ancestors of the current content.
/// </summary>
+20 -14
View File
@@ -791,21 +791,23 @@ namespace Umbraco.Core.Services
using (new WriteLock(Locker))
{
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
// this method will recursively go lookup every content item, check if any of it's descendants are
// of a different type, move them to the recycle bin, then permanently delete the content items.
// The main problem with this is that for every content item being deleted, events are raised...
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
_contentService.DeleteContentOfType(contentType.Id);
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
{
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
// this method will recursively go lookup every content item, check if any of it's descendants are
// of a different type, move them to the recycle bin, then permanently delete the content items.
// The main problem with this is that for every content item being deleted, events are raised...
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
var deletedContentTypes = new List<IContentType>() {contentType};
deletedContentTypes.AddRange(contentType.Descendants().OfType<IContentType>());
foreach (var deletedContentType in deletedContentTypes)
{
_contentService.DeleteContentOfType(deletedContentType.Id);
}
repository.Delete(contentType);
uow.Commit();
@@ -833,11 +835,6 @@ namespace Umbraco.Core.Services
using (new WriteLock(Locker))
{
foreach (var contentType in asArray)
{
_contentService.DeleteContentOfType(contentType.Id);
}
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
{
@@ -847,6 +844,15 @@ namespace Umbraco.Core.Services
foreach (var contentType in asArray)
{
deletedContentTypes.AddRange(contentType.Descendants().OfType<IContentType>());
}
foreach (var deletedContentType in deletedContentTypes)
{
_contentService.DeleteContentOfType(deletedContentType.Id);
}
foreach (var contentType in asArray)
{
repository.Delete(contentType);
}
@@ -298,6 +298,14 @@ namespace Umbraco.Core.Services
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetVersions(int id);
/// <summary>
/// Gets a list of all version Ids for the given content item ordered so latest is first
/// </summary>
/// <param name="id"></param>
/// <param name="maxRows">The maximum number of rows to return</param>
/// <returns></returns>
IEnumerable<Guid> GetVersionIds(int id, int maxRows);
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects, which reside at the first level / root
/// </summary>
+249 -117
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -15,7 +16,6 @@ using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Strings;
using umbraco.interfaces;
namespace Umbraco.Core.Services
{
@@ -55,38 +55,72 @@ namespace Umbraco.Core.Services
Func<IUser, string[], string> createSubject,
Func<IUser, string[], string> createBody)
{
if ((entity is IContent) == false)
if (entity is IContent == false)
throw new NotSupportedException();
var content = (IContent) entity;
// lazily get versions - into a list to ensure we can enumerate multiple times
List<IContent> allVersions = null;
var content = (IContent) entity;
int totalUsers;
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
foreach (var u in allUsers.Where(x => x.IsApproved))
// lazily get previous version
IContentBase prevVersion = null;
// do not load *all* users in memory at once
// do not load notifications *per user* (N+1 select)
// cannot load users & notifications in 1 query (combination btw User2AppDto and User2NodeNotifyDto)
// => get batches of users, get all their notifications in 1 query
// re. users:
// users being (dis)approved = not an issue, filtered in memory not in SQL
// users being modified or created = not an issue, ordering by ID, as long as we don't *insert* low IDs
// users being deleted = not an issue for GetNextUsers
var id = 0;
var nodeIds = content.Path.Split(',').Select(int.Parse).ToArray();
const int pagesz = 400; // load batches of 400 users
do
{
var userNotifications = GetUserNotifications(u, content.Path);
var notificationForAction = userNotifications.FirstOrDefault(x => x.Action == action);
if (notificationForAction == null) continue;
// users are returned ordered by id, notifications are returned ordered by user id
var users = ((UserService) _userService).GetNextUsers(id, pagesz).Where(x => x.IsApproved).ToList();
var notifications = GetUsersNotifications(users.Select(x => x.Id), action, nodeIds, Constants.ObjectTypes.DocumentGuid).ToList();
if (notifications.Count == 0) break;
if (allVersions == null) // lazy load
allVersions = _contentService.GetVersions(entity.Id).ToList();
try
var i = 0;
foreach (var user in users)
{
SendNotification(operatingUser, u, content, allVersions,
actionName, http, createSubject, createBody);
// continue if there's no notification for this user
if (notifications[i].UserId != user.Id) continue; // next user
_logger.Debug<NotificationService>(string.Format("Notification type: {0} sent to {1} ({2})",
action, u.Name, u.Email));
// lazy load prev version
if (prevVersion == null)
{
prevVersion = GetPreviousVersion(entity.Id);
}
// queue notification
var req = CreateNotificationRequest(operatingUser, user, content, prevVersion, actionName, http, createSubject, createBody);
Enqueue(req);
// skip other notifications for this user
while (i < notifications.Count && notifications[i++].UserId == user.Id) ;
if (i >= notifications.Count) break; // break if no more notifications
}
catch (Exception ex)
{
_logger.Error<NotificationService>("An error occurred sending notification", ex);
}
}
// load more users if any
id = users.Count == pagesz ? users.Last().Id + 1 : -1;
} while (id > 0);
}
/// <summary>
/// Gets the previous version to the latest version of the content item if there is one
/// </summary>
/// <param name="contentId"></param>
/// <returns></returns>
private IContentBase GetPreviousVersion(int contentId)
{
// Regarding this: http://issues.umbraco.org/issue/U4-5180
// we know they are descending from the service so we know that newest is first
// we are only selecting the top 2 rows since that is all we need
var allVersions = _contentService.GetVersionIds(contentId, 2).ToList();
var prevVersionIndex = allVersions.Count > 1 ? 1 : 0;
return _contentService.GetByVersion(allVersions[prevVersionIndex]);
}
/// <summary>
@@ -106,47 +140,76 @@ namespace Umbraco.Core.Services
Func<IUser, string[], string> createSubject,
Func<IUser, string[], string> createBody)
{
if ((entities is IEnumerable<IContent>) == false)
if (entities is IEnumerable<IContent> == false)
throw new NotSupportedException();
// ensure we can enumerate multiple times
var entitiesL = entities as List<IContent> ?? entities.Cast<IContent>().ToList();
// lazily get versions - into lists to ensure we can enumerate multiple times
var allVersionsDictionary = new Dictionary<int, List<IContent>>();
//exit if there are no entities
if (entitiesL.Count == 0) return;
int totalUsers;
var allUsers = _userService.GetAll(0, int.MaxValue, out totalUsers);
foreach (var u in allUsers.Where(x => x.IsApproved))
//put all entity's paths into a list with the same indicies
var paths = entitiesL.Select(x => x.Path.Split(',').Select(int.Parse).ToArray()).ToArray();
// lazily get versions
var prevVersionDictionary = new Dictionary<int, IContentBase>();
// see notes above
var id = 0;
const int pagesz = 400; // load batches of 400 users
do
{
var userNotifications = GetUserNotifications(u).ToArray();
foreach (var content in entitiesL)
// users are returned ordered by id, notifications are returned ordered by user id
var users = ((UserService)_userService).GetNextUsers(id, pagesz).Where(x => x.IsApproved).ToList();
var notifications = GetUsersNotifications(users.Select(x => x.Id), action, Enumerable.Empty<int>(), Constants.ObjectTypes.DocumentGuid).ToList();
if (notifications.Count == 0) break;
var i = 0;
foreach (var user in users)
{
var userNotificationsByPath = FilterUserNotificationsByPath(userNotifications, content.Path);
var notificationForAction = userNotificationsByPath.FirstOrDefault(x => x.Action == action);
if (notificationForAction == null) continue;
// continue if there's no notification for this user
if (notifications[i].UserId != user.Id) continue; // next user
var allVersions = allVersionsDictionary.ContainsKey(content.Id) // lazy load
? allVersionsDictionary[content.Id]
: allVersionsDictionary[content.Id] = _contentService.GetVersions(content.Id).ToList();
try
for (var j = 0; j < entitiesL.Count; j++)
{
SendNotification(operatingUser, u, content, allVersions,
actionName, http, createSubject, createBody);
var content = entitiesL[j];
var path = paths[j];
// test if the notification applies to the path ie to this entity
if (path.Contains(notifications[i].EntityId) == false) continue; // next entity
if (prevVersionDictionary.ContainsKey(content.Id) == false)
{
prevVersionDictionary[content.Id] = GetPreviousVersion(content.Id);
}
// queue notification
var req = CreateNotificationRequest(operatingUser, user, content, prevVersionDictionary[content.Id], actionName, http, createSubject, createBody);
Enqueue(req);
}
_logger.Debug<NotificationService>(string.Format("Notification type: {0} sent to {1} ({2})",
action, u.Name, u.Email));
}
catch (Exception ex)
// skip other notifications for this user, essentially this means moving i to the next index of notifications
// for the next user.
do
{
_logger.Error<NotificationService>("An error occurred sending notification", ex);
}
}
}
i++;
} while (i < notifications.Count && notifications[i].UserId == user.Id);
if (i >= notifications.Count) break; // break if no more notifications
}
// load more users if any
id = users.Count == pagesz ? users.Last().Id + 1 : -1;
} while (id > 0);
}
private IEnumerable<Notification> GetUsersNotifications(IEnumerable<int> userIds, string action, IEnumerable<int> nodeIds, Guid objectType)
{
var uow = _uowProvider.GetUnitOfWork();
var repository = new NotificationsRepository(uow);
return repository.GetUsersNotifications(userIds, action, nodeIds, objectType);
}
/// <summary>
/// Gets the notifications for the user
@@ -184,7 +247,7 @@ namespace Umbraco.Core.Services
public IEnumerable<Notification> FilterUserNotificationsByPath(IEnumerable<Notification> userNotifications, string path)
{
var pathParts = path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
return userNotifications.Where(r => pathParts.InvariantContains(r.EntityId.ToString(CultureInfo.InvariantCulture))).ToList();
return userNotifications.Where(r => pathParts.InvariantContains(r.EntityId.ToString(CultureInfo.InvariantCulture))).ToList();
}
/// <summary>
@@ -254,29 +317,23 @@ namespace Umbraco.Core.Services
/// <param name="performingUser"></param>
/// <param name="mailingUser"></param>
/// <param name="content"></param>
/// <param name="allVersions"></param>
/// <param name="oldDoc"></param>
/// <param name="actionName">The action readable name - currently an action is just a single letter, this is the name associated with the letter </param>
/// <param name="http"></param>
/// <param name="createSubject">Callback to create the mail subject</param>
/// <param name="createBody">Callback to create the mail body</param>
private void SendNotification(IUser performingUser, IUser mailingUser, IContent content, IEnumerable<IContent> allVersions, string actionName, HttpContextBase http,
private NotificationRequest CreateNotificationRequest(IUser performingUser, IUser mailingUser, IContentBase content, IContentBase oldDoc,
string actionName, HttpContextBase http,
Func<IUser, string[], string> createSubject,
Func<IUser, string[], string> createBody)
{
if (performingUser == null) throw new ArgumentNullException("performingUser");
if (mailingUser == null) throw new ArgumentNullException("mailingUser");
if (content == null) throw new ArgumentNullException("content");
if (allVersions == null) throw new ArgumentNullException("allVersions");
if (http == null) throw new ArgumentNullException("http");
if (createSubject == null) throw new ArgumentNullException("createSubject");
if (createBody == null) throw new ArgumentNullException("createBody");
//Ensure they are sorted: http://issues.umbraco.org/issue/U4-5180
var allVersionsAsArray = allVersions.OrderBy(x => x.UpdateDate).ToArray();
int versionCount = (allVersionsAsArray.Length > 1) ? (allVersionsAsArray.Length - 2) : (allVersionsAsArray.Length - 1);
var oldDoc = _contentService.GetByVersion(allVersionsAsArray[versionCount].Version);
if (createBody == null) throw new ArgumentNullException("createBody");
// build summary
var summary = new StringBuilder();
var props = content.Properties.ToArray();
@@ -290,16 +347,16 @@ namespace Umbraco.Core.Services
{
var oldProperty = oldDoc.Properties[p.PropertyType.Alias];
oldText = oldProperty.Value != null ? oldProperty.Value.ToString() : "";
// replace html with char equivalent
ReplaceHtmlSymbols(ref oldText);
ReplaceHtmlSymbols(ref newText);
}
// make sure to only highlight changes done using TinyMCE editor... other changes will be displayed using default summary
// TODO: We should probably allow more than just tinymce??
if ((p.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias)
if ((p.PropertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias)
&& string.CompareOrdinal(oldText, newText) != 0)
{
summary.Append("<tr>");
@@ -308,26 +365,31 @@ namespace Umbraco.Core.Services
"<td style='text-align: left; vertical-align: top;'> <span style='background-color:red;'>Red for deleted characters</span>&nbsp;<span style='background-color:yellow;'>Yellow for inserted characters</span></td>");
summary.Append("</tr>");
summary.Append("<tr>");
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> New " +
p.PropertyType.Name + "</th>");
summary.Append("<td style='text-align: left; vertical-align: top;'>" +
ReplaceLinks(CompareText(oldText, newText, true, false, "<span style='background-color:yellow;'>", string.Empty), http.Request) +
"</td>");
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> New ");
summary.Append(p.PropertyType.Name);
summary.Append("</th>");
summary.Append("<td style='text-align: left; vertical-align: top;'>");
summary.Append(ReplaceLinks(CompareText(oldText, newText, true, false, "<span style='background-color:yellow;'>", string.Empty), http.Request));
summary.Append("</td>");
summary.Append("</tr>");
summary.Append("<tr>");
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> Old " +
p.PropertyType.Name + "</th>");
summary.Append("<td style='text-align: left; vertical-align: top;'>" +
ReplaceLinks(CompareText(newText, oldText, true, false, "<span style='background-color:red;'>", string.Empty), http.Request) +
"</td>");
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'> Old ");
summary.Append(p.PropertyType.Name);
summary.Append("</th>");
summary.Append("<td style='text-align: left; vertical-align: top;'>");
summary.Append(ReplaceLinks(CompareText(newText, oldText, true, false, "<span style='background-color:red;'>", string.Empty), http.Request));
summary.Append("</td>");
summary.Append("</tr>");
}
else
{
summary.Append("<tr>");
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'>" +
p.PropertyType.Name + "</th>");
summary.Append("<td style='text-align: left; vertical-align: top;'>" + newText + "</td>");
summary.Append("<th style='text-align: left; vertical-align: top; width: 25%;'>");
summary.Append(p.PropertyType.Name);
summary.Append("</th>");
summary.Append("<td style='text-align: left; vertical-align: top;'>");
summary.Append(newText);
summary.Append("</td>");
summary.Append("</tr>");
}
summary.Append(
@@ -338,29 +400,27 @@ namespace Umbraco.Core.Services
string[] subjectVars = {
http.Request.ServerVariables["SERVER_NAME"] + ":" +
http.Request.Url.Port +
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
string.Concat(http.Request.ServerVariables["SERVER_NAME"], ":", http.Request.Url.Port, IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
actionName,
content.Name
};
string[] bodyVars = {
mailingUser.Name,
actionName,
content.Name,
mailingUser.Name,
actionName,
content.Name,
performingUser.Name,
http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port + IOHelper.ResolveUrl(SystemDirectories.Umbraco),
string.Concat(http.Request.ServerVariables["SERVER_NAME"], ":", http.Request.Url.Port, IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
content.Id.ToString(CultureInfo.InvariantCulture), summary.ToString(),
string.Format("{2}://{0}/{1}",
http.Request.ServerVariables["SERVER_NAME"] + ":" + http.Request.Url.Port,
string.Concat(http.Request.ServerVariables["SERVER_NAME"], ":", http.Request.Url.Port),
//TODO: RE-enable this so we can have a nice url
/*umbraco.library.NiceUrl(documentObject.Id))*/
content.Id + ".aspx",
string.Concat(content.Id, ".aspx"),
protocol)
};
// create the mail message
// create the mail message
var mail = new MailMessage(UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress, mailingUser.Email);
// populate the message
@@ -374,10 +434,10 @@ namespace Umbraco.Core.Services
{
mail.IsBodyHtml = true;
mail.Body =
@"<html><head>
string.Concat(@"<html><head>
</head>
<body style='font-family: Trebuchet MS, arial, sans-serif; font-color: black;'>
" + createBody(mailingUser, bodyVars);
", createBody(mailingUser, bodyVars));
}
// nh, issue 30724. Due to hardcoded http strings in resource files, we need to check for https replacements here
@@ -390,32 +450,17 @@ namespace Umbraco.Core.Services
string.Format("https://{0}", serverName));
}
// send it asynchronously, we don't want to got up all of the request time to send emails!
ThreadPool.QueueUserWorkItem(state =>
{
try
{
using (mail)
{
using (var sender = new SmtpClient())
{
sender.Send(mail);
}
}
}
catch (Exception ex)
{
_logger.Error<NotificationService>("An error occurred sending notification", ex);
}
});
return new NotificationRequest(mail, actionName, mailingUser.Name, mailingUser.Email);
}
private static string ReplaceLinks(string text, HttpRequestBase request)
{
string domain = GlobalSettings.UseSSL ? "https://" : "http://";
domain += request.ServerVariables["SERVER_NAME"] + ":" + request.Url.Port + "/";
var sb = new StringBuilder(GlobalSettings.UseSSL ? "https://" : "http://");
sb.Append(request.ServerVariables["SERVER_NAME"]);
sb.Append(":");
sb.Append(request.Url.Port);
sb.Append("/");
var domain = sb.ToString();
text = text.Replace("href=\"/", "href=\"" + domain);
text = text.Replace("src=\"/", "src=\"" + domain);
return text;
@@ -484,7 +529,7 @@ namespace Umbraco.Core.Services
pos++;
} // while
sb.Append("</span>");
} // if
} // if
} // while
// write rest of unchanged chars
@@ -495,8 +540,95 @@ namespace Umbraco.Core.Services
} // while
return sb.ToString();
}
// manage notifications
// ideally, would need to use IBackgroundTasks - but they are not part of Core!
private static readonly object Locker = new object();
private static readonly BlockingCollection<NotificationRequest> Queue = new BlockingCollection<NotificationRequest>();
private static volatile bool _running;
private void Enqueue(NotificationRequest notification)
{
Queue.Add(notification);
if (_running) return;
lock (Locker)
{
if (_running) return;
Process(Queue);
_running = true;
}
}
private class NotificationRequest
{
public NotificationRequest(MailMessage mail, string action, string userName, string email)
{
Mail = mail;
Action = action;
UserName = userName;
Email = email;
}
public MailMessage Mail { get; private set; }
public string Action { get; private set; }
public string UserName { get; private set; }
public string Email { get; private set; }
}
private void Process(BlockingCollection<NotificationRequest> notificationRequests)
{
ThreadPool.QueueUserWorkItem(state =>
{
var s = new SmtpClient();
try
{
_logger.Debug<NotificationService>("Begin processing notifications.");
while (true)
{
NotificationRequest request;
while (notificationRequests.TryTake(out request, 8 * 1000)) // stay on for 8s
{
try
{
if (Sendmail != null) Sendmail(s, request.Mail, _logger); else s.Send(request.Mail);
_logger.Debug<NotificationService>(string.Format("Notification \"{0}\" sent to {1} ({2})", request.Action, request.UserName, request.Email));
}
catch (Exception ex)
{
_logger.Error<NotificationService>("An error occurred sending notification", ex);
s.Dispose();
s = new SmtpClient();
}
finally
{
request.Mail.Dispose();
}
}
lock (Locker)
{
if (notificationRequests.Count > 0) continue; // last chance
_running = false; // going down
break;
}
}
}
finally
{
s.Dispose();
}
_logger.Debug<NotificationService>("Done processing notifications.");
});
}
// for tests
internal static Action<SmtpClient, MailMessage, ILogger> Sendmail;
//= (_, msg, logger) => logger.Debug<NotificationService>("Email " + msg.To.ToString());
#endregion
}
}
+10
View File
@@ -9,6 +9,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Security;
@@ -506,6 +507,15 @@ namespace Umbraco.Core.Services
}
}
internal IEnumerable<IUser> GetNextUsers(int id, int count)
{
var uow = UowProvider.GetUnitOfWork();
using (var repository = (UserRepository) RepositoryFactory.CreateUserRepository(uow))
{
return repository.GetNextUsers(id, count);
}
}
#endregion
#region Implementation of IUserService
@@ -142,7 +142,8 @@ namespace Umbraco.Core.Sync
? ":" + request.ServerVariables["SERVER_PORT"]
: "";
var ssl = GlobalSettings.UseSSL ? "s" : ""; // force, whatever the first request
var useSsl = GlobalSettings.UseSSL || port == "443";
var ssl = useSsl ? "s" : ""; // force, whatever the first request
var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco);
appContext._umbracoApplicationUrl = url.TrimEnd('/');
+7 -6
View File
@@ -37,12 +37,12 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
@@ -52,8 +52,8 @@
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor, Version=2.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.4.4.0\lib\net45\ImageProcessor.dll</HintPath>
<Reference Include="ImageProcessor, Version=2.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.4.5.0\lib\net45\ImageProcessor.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
@@ -1452,6 +1452,7 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
@@ -48,6 +48,9 @@ namespace Umbraco.Core
LogHelper.Error<UmbracoApplicationBase>(msg, exception);
};
// this only gets called when an assembly can't be resolved
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainOnAssemblyResolve;
//boot up the application
GetBootManager()
.Initialize()
@@ -58,6 +61,22 @@ namespace Umbraco.Core
ApplicationEventsResolver.Current.Dispose();
}
/// <summary>
/// Called when an assembly can't be resolved. In here we can do magic with the assembly name and try loading another.
/// This is used for loading a signed assembly of AutoMapper (v. 3.1+) without having to recompile old code.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
/// <returns></returns>
private Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args)
{
// ensure the assembly is indeed AutoMapper and that the PublicKeyToken is null before trying to Load again
// do NOT just replace this with 'return Assembly', as it will cause an infinite loop -> stackoverflow
if (args.Name.StartsWith("AutoMapper") && args.Name.EndsWith("PublicKeyToken=null"))
return Assembly.Load(args.Name.Replace(", PublicKeyToken=null", ", PublicKeyToken=be96cd2c38ef1005"));
return null;
}
/// <summary>
/// Initializes the Umbraco application
/// </summary>
+23 -4
View File
@@ -35,7 +35,7 @@ namespace Umbraco.Core
return;
}
if (n.Attributes[name] == null)
{
{
var a = xml.CreateAttribute(name);
a.Value = value;
n.Attributes.Append(a);
@@ -155,7 +155,7 @@ namespace Umbraco.Core
elt = null;
return false;
}
/// <summary>
/// Sorts the children of a parentNode.
/// </summary>
@@ -163,7 +163,7 @@ namespace Umbraco.Core
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
internal static void SortNodes(
XmlNode parentNode,
XmlNode parentNode,
string childNodesXPath,
Func<XmlNode, int> orderBy)
{
@@ -227,7 +227,7 @@ namespace Umbraco.Core
/// <param name="node">The child node to sort.</param>
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
/// <returns>A value indicating whether sorting was needed.</returns>
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
/// the right position without moving all the nodes (as SortNodes would do) - should improve perfs.</remarks>
internal static bool SortNode(
XmlNode parentNode,
@@ -415,6 +415,25 @@ namespace Umbraco.Core
return AddTextNode(xd, name, value);
}
/// <summary>
/// Sets or creates an Xml node from its inner Xml.
/// </summary>
/// <param name="xd">The xmldocument.</param>
/// <param name="parent">The node to set or create the child text node on</param>
/// <param name="name">The node name.</param>
/// <param name="value">The node inner Xml.</param>
/// <returns>a XmlNode</returns>
public static XmlNode SetInnerXmlNode(XmlDocument xd, XmlNode parent, string name, string value)
{
if (xd == null) throw new ArgumentNullException("xd");
if (parent == null) throw new ArgumentNullException("parent");
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
var child = parent.SelectSingleNode(name) ?? xd.CreateNode(XmlNodeType.Element, name, "");
child.InnerXml = value;
return child;
}
/// <summary>
/// Creates a cdata XmlNode with the specified name and value
/// </summary>
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="ImageProcessor" version="2.4.4.0" targetFramework="net45" />
<package id="ImageProcessor" version="2.4.5.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
@@ -0,0 +1,36 @@
using NUnit.Framework;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Tests.Persistence
{
[TestFixture]
public class PetaPocoExpressionsTests
{
[Test]
public void WhereInValueFieldTest()
{
var syntax = SqlSyntaxContext.SqlSyntaxProvider = new SqlCeSyntaxProvider();
var sql = new Sql()
.Select("*")
.From<NodeDto>(syntax)
.WhereIn<NodeDto>(x => x.NodeId, new[] { 1, 2, 3 }, syntax);
Assert.AreEqual("SELECT *\nFROM [umbracoNode]\nWHERE ([umbracoNode].[id] IN (@0,@1,@2))", sql.SQL);
}
[Test]
public void WhereInObjectFieldTest()
{
// this test used to fail because x => x.Text was evaluated as a lambda
// and returned "[umbracoNode].[text] = @0"... had to fix WhereIn.
var syntax = SqlSyntaxContext.SqlSyntaxProvider = new SqlCeSyntaxProvider();
var sql = new Sql()
.Select("*")
.From<NodeDto>(syntax)
.WhereIn<NodeDto>(x => x.Text, new[] { "a", "b", "c" }, syntax);
Assert.AreEqual("SELECT *\nFROM [umbracoNode]\nWHERE ([umbracoNode].[text] IN (@0,@1,@2))", sql.SQL);
}
}
}
@@ -261,8 +261,17 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetCropUrl_SpecifiedCropModeTest()
{
var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode:ImageCropMode.Max);
Assert.AreEqual(mediaPath + "?mode=max&width=300&height=150", urlString);
var urlStringMin = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Min);
var urlStringBoxPad = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.BoxPad);
var urlStringPad = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Pad);
var urlStringMax = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Max);
var urlStringStretch = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Stretch);
Assert.AreEqual(mediaPath + "?mode=min&width=300&height=150", urlStringMin);
Assert.AreEqual(mediaPath + "?mode=boxpad&width=300&height=150", urlStringBoxPad);
Assert.AreEqual(mediaPath + "?mode=pad&width=300&height=150", urlStringPad);
Assert.AreEqual(mediaPath + "?mode=max&width=300&height=150", urlStringMax);
Assert.AreEqual(mediaPath + "?mode=stretch&width=300&height=150", urlStringStretch);
}
/// <summary>
@@ -68,6 +68,50 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(contentService.PublishWithStatus(content).Success);
}
[Test]
public void Get_Top_Version_Ids()
{
// Arrange
var contentService = ServiceContext.ContentService;
// Act
var content = contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0);
for (int i = 0; i < 20; i++)
{
content.SetValue("bodyText", "hello world " + Guid.NewGuid());
contentService.SaveAndPublishWithStatus(content);
}
// Assert
var allVersions = contentService.GetVersionIds(content.Id, int.MaxValue);
Assert.AreEqual(21, allVersions.Count());
var topVersions = contentService.GetVersionIds(content.Id, 4);
Assert.AreEqual(4, topVersions.Count());
}
[Test]
public void Get_By_Ids_Sorted()
{
// Arrange
var contentService = ServiceContext.ContentService;
// Act
var results = new List<IContent>();
for (int i = 0; i < 20; i++)
{
results.Add(contentService.CreateContentWithIdentity("Test", -1, "umbTextpage", 0));
}
var sortedGet = contentService.GetByIds(new[] {results[10].Id, results[5].Id, results[12].Id}).ToArray();
// Assert
Assert.AreEqual(sortedGet[0].Id, results[10].Id);
Assert.AreEqual(sortedGet[1].Id, results[5].Id);
Assert.AreEqual(sortedGet[2].Id, results[12].Id);
}
[Test]
public void Count_All()
{
@@ -275,6 +275,35 @@ namespace Umbraco.Tests.Services
Assert.That(success, Is.False);
}
[Test]
public void Can_Delete_Parent_ContentType_When_Child_Has_Content()
{
var cts = ServiceContext.ContentTypeService;
var contentType = MockedContentTypes.CreateSimpleContentType("page", "Page", null, true);
cts.Save(contentType);
var childContentType = MockedContentTypes.CreateSimpleContentType("childPage", "Child Page", contentType, true, "Child Content");
cts.Save(childContentType);
var cs = ServiceContext.ContentService;
var content = cs.CreateContent("Page 1", -1, childContentType.Alias);
cs.Save(content);
cts.Delete(contentType);
Assert.IsNotNull(content.Id);
Assert.AreNotEqual(0, content.Id);
Assert.IsNotNull(childContentType.Id);
Assert.AreNotEqual(0, childContentType.Id);
Assert.IsNotNull(contentType.Id);
Assert.AreNotEqual(0, contentType.Id);
var deletedContent = cs.GetById(content.Id);
var deletedChildContentType = cts.GetContentType(childContentType.Id);
var deletedContentType = cts.GetContentType(contentType.Id);
Assert.IsNull(deletedChildContentType);
Assert.IsNull(deletedContent);
Assert.IsNull(deletedContentType);
}
[Test]
public void Deleting_ContentType_Sends_Correct_Number_Of_DeletedEntities_In_Events()
{
+7 -1
View File
@@ -142,7 +142,13 @@ namespace Umbraco.Tests.TestHelpers
}
else if (dateTimeFormat.IsNullOrWhiteSpace() == false && actualValue is DateTime)
{
Assert.AreEqual(((DateTime) expectedValue).ToString(dateTimeFormat), ((DateTime)actualValue).ToString(dateTimeFormat), "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
// round to second else in some cases tests can fail ;-(
var expectedDateTime = (DateTime) expectedValue;
expectedDateTime = expectedDateTime.AddTicks(-(expectedDateTime.Ticks%TimeSpan.TicksPerSecond));
var actualDateTime = (DateTime) actualValue;
actualDateTime = actualDateTime.AddTicks(-(actualDateTime.Ticks % TimeSpan.TicksPerSecond));
Assert.AreEqual(expectedDateTime.ToString(dateTimeFormat), actualDateTime.ToString(dateTimeFormat), "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expectedValue, actualValue);
}
else
{
+8 -6
View File
@@ -51,16 +51,16 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Examine, Version=0.1.69.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.69.0\lib\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
@@ -177,6 +177,7 @@
<ItemGroup>
<Compile Include="Migrations\MigrationIssuesTests.cs" />
<Compile Include="Persistence\Migrations\MigrationStartupHandlerTests.cs" />
<Compile Include="Persistence\PetaPocoExpressionsTests.cs" />
<Compile Include="Persistence\Repositories\RedirectUrlRepositoryTests.cs" />
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
<Compile Include="TryConvertToTests.cs" />
@@ -764,6 +765,7 @@
xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D</PreBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="Examine" version="0.1.69.0" targetFramework="net45" />
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
@@ -118,9 +118,13 @@ angular.module("umbraco.directives")
$timeout(function(){
setDimensions();
});
var offsetX = $overlay[0].offsetLeft;
var offsetY = $overlay[0].offsetTop;
calculateGravity(offsetX, offsetY);
// Make sure we can find the offset values for the overlay(dot) before calculating
// fixes issue with resize event when printing the page (ex. hitting ctrl+p inside the rte)
if($overlay.is(':visible')) {
var offsetX = $overlay[0].offsetLeft;
var offsetY = $overlay[0].offsetTop;
calculateGravity(offsetX, offsetY);
}
});
});
@@ -20,6 +20,8 @@ angular.module("umbraco.directives")
var curr = $(event.target); // active tab
var prev = $(event.relatedTarget); // previous tab
$scope.$apply();
for (var c in callbacks) {
callbacks[c].apply(this, [{current: curr, previous: prev}]);
}
@@ -58,7 +58,7 @@ angular.module('umbraco.mocks').
"view": "textstring",
"icon": "icon-quote",
"config": {
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px",
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-style: italic; font-size: 18px",
"markup": "<blockquote>#value#</blockquote>"
}
}
@@ -134,7 +134,7 @@ angular.module('umbraco.mocks').
"content_nodeName": "Page Title",
"content_otherElements": "Properties",
"content_parentNotPublished": "This document is published but is not visible because the parent '%0%' is unpublished",
"content_parentNotPublishedAnomaly": "Oops: this document is published but is not in the cache (internal error)",
"content_parentNotPublishedAnomaly": "This document is published but is not in the cache",
"content_publish": "Publish",
"content_publishStatus": "Publication Status",
"content_releaseDate": "Publish at",
@@ -20,7 +20,6 @@ function dashboardResource($q, $http, umbRequestHelper) {
*
*/
getDashboard: function (section) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
@@ -28,7 +27,53 @@ function dashboardResource($q, $http, umbRequestHelper) {
"GetDashboard",
[{ section: section }])),
'Failed to get dashboard ' + section);
},
/**
* @ngdoc method
* @name umbraco.resources.dashboardResource#getRemoteDashboardContent
* @methodOf umbraco.resources.dashboardResource
*
* @description
* Retrieves dashboard content from a remote source for a given section
*
* @param {string} section Alias of section to retrieve dashboard content for
* @returns {Promise} resourcePromise object containing the user array.
*
*/
getRemoteDashboardContent: function (section, baseurl) {
//build request values with optional params
var values = [{ section: section }];
if (baseurl)
{
values.push({ baseurl: baseurl });
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"dashboardApiBaseUrl",
"GetRemoteDashboardContent",
values)), "Failed to get dashboard content");
},
getRemoteDashboardCssUrl: function (section, baseurl) {
//build request values with optional params
var values = [{ section: section }];
if (baseurl) {
values.push({ baseurl: baseurl });
}
return umbRequestHelper.getApiUrl(
"dashboardApiBaseUrl",
"GetRemoteDashboardCss",
values);
}
};
}
@@ -5,10 +5,12 @@ angular.module('umbraco.security.retryQueue', [])
.factory('securityRetryQueue', ['$q', '$log', function ($q, $log) {
var retryQueue = [];
var retryUser = null;
var service = {
// The security service puts its own handler in here!
onItemAddedCallbacks: [],
hasMore: function() {
return retryQueue.length > 0;
},
@@ -23,13 +25,20 @@ angular.module('umbraco.security.retryQueue', [])
}
});
},
pushRetryFn: function(reason, retryFn) {
pushRetryFn: function(reason, userName, retryFn) {
// The reason parameter is optional
if ( arguments.length === 1) {
retryFn = reason;
if ( arguments.length === 2) {
retryFn = userName;
userName = reason;
reason = undefined;
}
if ((retryUser && retryUser !== userName) || userName === null) {
throw new Error('invalid user');
}
retryUser = userName;
// The deferred object that will be resolved or rejected by calling retry or cancel
var deferred = $q.defer();
var retryItem = {
@@ -59,8 +68,19 @@ angular.module('umbraco.security.retryQueue', [])
while(service.hasMore()) {
retryQueue.shift().cancel();
}
retryUser = null;
},
retryAll: function() {
retryAll: function (userName) {
if (retryUser == null) {
return;
}
if (retryUser !== userName) {
service.cancelAll();
return;
}
while(service.hasMore()) {
retryQueue.shift().retry();
}
@@ -6,7 +6,7 @@ angular.module('umbraco.security.interceptor')
return promise.then(
function(originalResponse) {
// Intercept successful requests
//Here we'll check if our custom header is in the response which indicates how many seconds the user's session has before it
//expires. Then we'll update the user in the user service accordingly.
var headers = originalResponse.headers();
@@ -15,11 +15,11 @@ angular.module('umbraco.security.interceptor')
var userService = $injector.get('userService');
userService.setUserTimeout(headers["x-umb-user-seconds"]);
}
return promise;
}, function(originalResponse) {
// Intercept failed requests
//Here we'll check if we should ignore the error, this will be based on an original header set
var headers = originalResponse.config ? originalResponse.config.headers : {};
if (headers["x-umb-ignore-error"] === "ignore") {
@@ -36,17 +36,24 @@ angular.module('umbraco.security.interceptor')
//A 401 means that the user is not logged in
if (originalResponse.status === 401) {
// The request bounced because it was not authorized - add a new request to the retry queue
promise = queue.pushRetryFn('unauthorized-server', function retryRequest() {
var userService = $injector.get('userService'); // see above
//Associate the user name with the retry to ensure we retry for the right user
promise = userService.getCurrentUser()
.then(function (user) {
var userName = user ? user.name : null;
//The request bounced because it was not authorized - add a new request to the retry queue
return queue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
// We must use $injector to get the $http service to prevent circular dependency
return $injector.get('$http')(originalResponse.config);
});
});
}
else if (originalResponse.status === 404) {
//a 404 indicates that the request was not found - this could be due to a non existing url, or it could
//be due to accessing a url with a parameter that doesn't exist, either way we should notifiy the user about it
var errMsg = "The URL returned a 404 (not found): <br/><i>" + originalResponse.config.url.split('?')[0] + "</i>";
if (originalResponse.data && originalResponse.data.ExceptionMessage) {
errMsg += "<br/> with error: <br/><i>" + originalResponse.data.ExceptionMessage + "</i>";
@@ -58,17 +65,17 @@ angular.module('umbraco.security.interceptor')
notifications.error(
"Request error",
errMsg);
}
else if (originalResponse.status === 403) {
//if the status was a 403 it means the user didn't have permission to do what the request was trying to do.
//How do we deal with this now, need to tell the user somehow that they don't have permission to do the thing that was
//How do we deal with this now, need to tell the user somehow that they don't have permission to do the thing that was
//requested. We can either deal with this globally here, or we can deal with it globally for individual requests on the umbRequestHelper,
// or completely custom for services calling resources.
//http://issues.umbraco.org/issue/U4-2749
//It was decided to just put these messages into the normal status messages.
//It was decided to just put these messages into the normal status messages.
var msg = "Unauthorized access to URL: <br/><i>" + originalResponse.config.url.split('?')[0] + "</i>";
if (originalResponse.config.data) {
@@ -354,7 +354,7 @@ angular.module('umbraco.services')
* @description
* Opens a content picker tree in a modal, the callback returns an array of selected documents
* @param {Object} options content picker dialog options object
* @param {Boolean} options.multipicker should the picker return one or multiple items
* @param {Boolean} options.multiPicker should the picker return one or multiple items
* @param {Function} options.callback callback function
* @returns {Object} modal object
*/
@@ -31,7 +31,7 @@ angular.module('umbraco.services')
loginDialog = null;
if (success) {
securityRetryQueue.retryAll();
securityRetryQueue.retryAll(currentUser.name);
}
else {
securityRetryQueue.cancelAll();
@@ -39,9 +39,9 @@ angular.module('umbraco.services')
}
}
/**
This methods will set the current user when it is resolved and
will then start the counter to count in-memory how many seconds they have
/**
This methods will set the current user when it is resolved and
will then start the counter to count in-memory how many seconds they have
remaining on the auth session
*/
function setCurrentUser(usr) {
@@ -54,8 +54,8 @@ angular.module('umbraco.services')
countdownUserTimeout();
}
/**
Method to count down the current user's timeout seconds,
/**
Method to count down the current user's timeout seconds,
this will continually count down their current remaining seconds every 5 seconds until
there are no more seconds remaining.
*/
@@ -70,8 +70,8 @@ angular.module('umbraco.services')
//if there are more than 30 remaining seconds, recurse!
if (currentUser.remainingAuthSeconds > 30) {
//we need to check when the last time the timeout was set from the server, if
// it has been more than 30 seconds then we'll manually go and retrieve it from the
//we need to check when the last time the timeout was set from the server, if
// it has been more than 30 seconds then we'll manually go and retrieve it from the
// server - this helps to keep our local countdown in check with the true timeout.
if (lastServerTimeoutSet != null) {
var now = new Date();
@@ -79,7 +79,7 @@ angular.module('umbraco.services')
if (seconds > 30) {
//first we'll set the lastServerTimeoutSet to null - this is so we don't get back in to this loop while we
//first we'll set the lastServerTimeoutSet to null - this is so we don't get back in to this loop while we
// wait for a response from the server otherwise we'll be making double/triple/etc... calls while we wait.
lastServerTimeoutSet = null;
@@ -98,7 +98,7 @@ angular.module('umbraco.services')
}
else {
//we are either timed out or very close to timing out so we need to show the login dialog.
//we are either timed out or very close to timing out so we need to show the login dialog.
if (Umbraco.Sys.ServerVariables.umbracoSettings.keepUserLoggedIn !== true) {
//NOTE: the safeApply because our timeout is set to not run digests (performance reasons)
angularHelper.safeApply($rootScope, function () {
@@ -109,14 +109,14 @@ angular.module('umbraco.services')
}
finally {
userAuthExpired();
}
}
});
}
else {
//we've got less than 30 seconds remaining so let's check the server
if (lastServerTimeoutSet != null) {
//first we'll set the lastServerTimeoutSet to null - this is so we don't get back in to this loop while we
//first we'll set the lastServerTimeoutSet to null - this is so we don't get back in to this loop while we
// wait for a response from the server otherwise we'll be making double/triple/etc... calls while we wait.
lastServerTimeoutSet = null;
@@ -211,8 +211,8 @@ angular.module('umbraco.services')
return result;
});
},
/** Logs the user out
/** Logs the user out
*/
logout: function () {
@@ -39,7 +39,7 @@
"view": "textstring",
"icon": "icon-quote",
"config": {
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px",
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-style: italic; font-size: 18px",
"markup": "<blockquote>#value#</blockquote>"
}
}
@@ -151,6 +151,15 @@
background-color: @blueDark;
}
.umb-era-button.-red {
background: @btnDangerBackground;
color: white;
}
.umb-era-button.-red:hover {
background-color: darken(@btnDangerBackground, 5%);
}
.umb-era-button.-link {
padding: 0;
background: transparent;
@@ -12,10 +12,10 @@
<div class="umb-media-grid__image-background" ng-if="item.thumbnail || item.extension == 'svg'"></div>
<!-- Image thumbnail -->
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="item.thumbnail" ng-src="{{item.thumbnail}}" alt="{{item.name}}" draggable="false" />
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="item.thumbnail" ng-src="{{item.thumbnail}}" alt="{{item.name}}" title="{{item.name}}" draggable="false" />
<!-- SVG -->
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="!item.thumbnail && item.extension == 'svg'" ng-src="{{item.file}}" alt="{{item.name}}" draggable="false" />
<img class="umb-media-grid__item-image" width="{{item.width}}" height="{{item.height}}" ng-if="!item.thumbnail && item.extension == 'svg'" ng-src="{{item.file}}" alt="{{item.name}}" title="{{item.name}}" draggable="false" />
<!-- Transparent image - fallback - used to keep image proportions on wrapper-->
<img class="umb-media-grid__item-image-placeholder" ng-if="!item.thumbnail && item.extension != 'svg'" src="assets/img/transparent.png" alt="{{item.name}}" draggable="false" />
@@ -14,9 +14,42 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
});
};
}
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
function startUpDynamicContentController(dashboardResource, assetsService) {
var vm = this;
vm.loading = true;
vm.showDefault = false;
//proxy remote css through the local server
assetsService.loadCss( dashboardResource.getRemoteDashboardCssUrl("content") );
dashboardResource.getRemoteDashboardContent("content").then(
function (data) {
vm.loading = false;
//test if we have received valid data
//we capture it like this, so we avoid UI errors - which automatically triggers ui based on http response code
if (data && data.sections) {
vm.dashboard = data;
} else{
vm.showDefault = true;
}
},
function (exception) {
console.error(exception);
vm.loading = false;
vm.showDefault = true;
});
}
angular.module("umbraco").controller("Umbraco.Dashboard.StartUpDynamicContentController", startUpDynamicContentController);
function FormsController($scope, $route, $cookieStore, packageResource, localizationService) {
$scope.installForms = function(){
$scope.state = localizationService.localize("packager_installStateDownloading");
@@ -192,27 +225,43 @@ function startupLatestEditsController($scope) {
}
angular.module("umbraco").controller("Umbraco.Dashboard.StartupLatestEditsController", startupLatestEditsController);
function MediaFolderBrowserDashboardController($rootScope, $scope, contentTypeResource) {
function MediaFolderBrowserDashboardController($rootScope, $scope, $location, contentTypeResource, userService) {
//get the system media listview
contentTypeResource.getPropertyTypeScaffold(-96)
.then(function(dt) {
var currentUser = {};
$scope.fakeProperty = {
alias: "contents",
config: dt.config,
description: "",
editor: dt.editor,
hideLabel: true,
id: 1,
label: "Contents:",
validation: {
mandatory: false,
pattern: null
},
value: "",
view: dt.view
};
userService.getCurrentUser().then(function (user) {
currentUser = user;
// check if the user start node is the dashboard
if(currentUser.startMediaId === -1) {
//get the system media listview
contentTypeResource.getPropertyTypeScaffold(-96)
.then(function(dt) {
$scope.fakeProperty = {
alias: "contents",
config: dt.config,
description: "",
editor: dt.editor,
hideLabel: true,
id: 1,
label: "Contents:",
validation: {
mandatory: false,
pattern: null
},
value: "",
view: dt.view
};
});
} else {
// redirect to start node
$location.path("/media/media/edit/" + currentUser.startMediaId);
}
});
@@ -1,44 +1,95 @@
<div class="umb-dashboard-grid" ng-controller="Umbraco.Dashboard.StartUpDynamicContentController as vm">
<div style="max-width: 1200px">
<h3><strong>Welcome to The Friendly CMS</strong></h3>
<p style="font-size: 16px; line-height: 1.5; margin-bottom: 30px; max-width: 760px;">Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible:</p>
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
<div class="row">
<div class="span4">
<a href="http://umbraco.tv/?utm_source=core&utm_medium=dashboard&utm_content=image&utm_campaign=tv" target="_blank" class="nounderline">
<img src="views/dashboard/default/umbracotv.png" alt="Umbraco.TV - Hours of Umbraco Video Tutorials" style="margin: 10px 0 10px 0"/>
</a>
<div class="row clearfix" ng-if="vm.dashboard">
<!-- Sections -->
<div class="grid-section" ng-repeat="section in vm.dashboard.sections">
<div class="{{'span' + section.grid + ' column dash-section'}}">
<!-- rows -->
<div class="row clearfix dash-row" ng-repeat="row in section.rows">
<div class="dash-inner-row">
<a href="http://umbraco.tv/?utm_source=core&utm_medium=dashboard&utm_content=header&utm_campaign=tv" target="_blank" class="btn-link -underline">
<h4> <strong>Umbraco.TV - Learn from the source!</strong> </h4>
</a>
<!-- areas -->
<div ng-repeat="area in row.areas"
class="{{'span' + area.grid + ' column dash-area'}}">
<div class="dash-inner-area">
<p style="line-height: 1.5;">
Umbraco.TV will help you go from zero to Umbraco
hero at a pace that suits you. Our easy to follow
online training videos will give you the fundamental
knowledge to start building awesome Umbraco websites.
</p>
<!-- Controls -->
<div ng-repeat="control in area.controls" class="dash-control dash-control-{{control.alias}}">
<div class="dash-inner-control">
<div ng-bind-html-unsafe="control.html"></div>
</div>
</div>
<!-- Controls end -->
</div>
</div>
<!-- Area end -->
</div>
</div>
</div>
<!-- Section end -->
</div>
</div>
<!-- grid container end -->
<div class="span4 offset1">
<a href="http://our.umbraco.org/?utm_source=core&utm_medium=dashboard&utm_content=image&utm_campaign=our" target="_blank" class="nounderline">
<img src="views/dashboard/default/ourumbraco.png" alt="Our Umbraco" style="margin: 10px 0 10px 0"/>
</a>
<!-- Default content in case we cannot fetch content from the outside -->
<div style="max-width: 1200px" ng-if="vm.showDefault">
<h3><strong>Welcome to The Friendly CMS</strong></h3>
<p style="font-size: 16px; line-height: 1.5; margin-bottom: 30px; max-width: 760px;">
<span>Thank you for choosing Umbraco - we think this could be the beginning of something beautiful. While it may feel overwhelming at first, we've done a lot to make the learning curve as smooth and fast as possible.</span>
</p>
<h4>Find out more:</h4>
<ul>
<li>Find the answers to your Umbraco questions in <a href="https://our.umbraco.org/documentation/" target="_blank" class="btn-link-underline">our Documentation</a></li>
<li>Ask a question in the <a href="https://our.umbraco.org" target="_blank" class="btn-link-underline">Community Forum</a></li>
<li>Find <a href="https://our.umbraco.org/projects" target="_blank" class="btn-link-underline">an add-on package</a> to help you get going quickly</li>
<li>Watch <a href="https://umbraco.tv" class="btn-link-underline">our tutorial videos</a> (some are free, some require a subscription)</li>
<li>Find out about <a href="https://umbraco.com/products-and-support" target="_blank" class="btn-link-underline">our productivity boosting tools and commercial support</a></li>
<li>Find out about <a href="https://umbraco.com/products/training" target="_blank" class="btn-link-underline">real-life training and certification opportunities</a></li>
</ul>
<a href="http://our.umbraco.org/?utm_source=core&utm_medium=dashboard&utm_content=header&utm_campaign=our" target="_blank" class="btn-link -underline">
<h4><strong>Our Umbraco - The Friendliest Community</strong></h4>
</a>
<div class="row">
<div class="span4">
<a href="http://umbraco.tv/?utm_source=core&utm_medium=dashboard&utm_content=image&utm_campaign=tv" target="_blank" class="nounderline">
<img src="views/dashboard/default/umbracotv.png" alt="Umbraco.TV - Hours of Umbraco Video Tutorials" style="margin: 10px 0 10px 0" />
</a>
<p style="line-height: 1.5;">
Our Umbraco - the official community site is your one
stop for everything Umbraco. Whether you need a
question answered or looking for cool plugins, the
worlds best community is just a click away.
</p>
</div>
</div>
</div>
<a href="http://umbraco.tv/?utm_source=core&utm_medium=dashboard&utm_content=header&utm_campaign=tv" target="_blank" class="btn-link -underline">
<h4> <strong>Umbraco.TV - Learn from the source!</strong> </h4>
</a>
<p style="line-height: 1.5;">
Umbraco.TV will help you go from zero to Umbraco
hero at a pace that suits you. Our easy to follow
online training videos will give you the fundamental
knowledge to start building awesome Umbraco websites.
</p>
</div>
<div class="span4 offset1">
<a href="http://our.umbraco.org/?utm_source=core&utm_medium=dashboard&utm_content=image&utm_campaign=our" target="_blank" class="nounderline">
<img src="views/dashboard/default/ourumbraco.png" alt="Our Umbraco" style="margin: 10px 0 10px 0" />
</a>
<a href="http://our.umbraco.org/?utm_source=core&utm_medium=dashboard&utm_content=header&utm_campaign=our" target="_blank" class="btn-link -underline">
<h4><strong>Our Umbraco - The Friendliest Community</strong></h4>
</a>
<p style="line-height: 1.5;">
Our Umbraco - the official community site is your one
stop for everything Umbraco. Whether you need a
question answered or looking for cool plugins, the
worlds best community is just a click away.
</p>
</div>
</div>
</div>
</div>
@@ -77,7 +77,7 @@
<a class="umb-table-body__link" href="{{redirectUrl.destinationUrl}}" target="_blank" title="{{redirectUrl.destinationUrl}}">{{redirectUrl.destinationUrl}}</a>
</div>
<button type="button" class="umb-era-button -gray umb-button--s" ng-click="vm.removeRedirect(redirectUrl)"><localize key="redirectUrls_removeButton">Remove</localize></button>
<button type="button" class="umb-era-button umb-button--s -red" ng-click="vm.removeRedirect(redirectUrl)"><localize key="redirectUrls_removeButton">Remove</localize></button>
</div>
</div>
@@ -199,7 +199,7 @@
<div class="umb-package-details__information-item" ng-if="vm.package.created">
<div class="umb-package-details__information-item-label">Created:</div>
<div class="umb-package-details__information-item-content">{{vm.package.created}}</div>
<div class="umb-package-details__information-item-content">{{vm.package.created | date:'yyyy-MM-dd HH:mm:ss'}}</div>
</div>
<div class="umb-package-details__information-item" ng-if="vm.package.latestVersion">
@@ -1,7 +1,7 @@
<ul class="unstyled">
<li ng-repeat="preval in model.prevalues">
<label class="checkbox">
<input type="radio" ng-model="model.value" value="{{preval}}" /> {{preval}}
</label>
<label class="checkbox">
<input type="radio" ng-model="model.value" value="{{preval.value || preval}}" /> {{preval.label || preval.value || preval}}
</label>
</li>
</ul>
@@ -16,7 +16,7 @@ angular.module("umbraco")
};
$scope.scaleDown = function(section){
var remove = (section.grid > 1) ? 1 : section.grid;
var remove = (section.grid > 1) ? 1 : 0;
section.grid = section.grid-remove;
};
@@ -49,9 +49,12 @@ angular.module("umbraco")
$scope.currentSection = section;
};
$scope.deleteSection = function(index){
$scope.currentTemplate.sections.splice(index, 1);
$scope.deleteSection = function(section, template) {
if ($scope.currentSection === section) {
$scope.currentSection = undefined;
}
var index = template.sections.indexOf(section)
template.sections.splice(index, 1);
};
$scope.closeSection = function(){
@@ -35,17 +35,24 @@
<div ng-if="currentSection" style="padding-bottom: 50px;">
<umb-control-group label="@general_width">
<div class="grid-size-scaler" >
<div class="grid-size-scaler">
<a href ng-click="scaleDown(currentSection)">
<i class="icon icon-navigation-down"></i>
<i class="icon icon-remove"></i>
</a>
{{currentSection.grid}}
<a href ng-click="scaleUp(currentSection, availableLayoutSpace)">
<i class="icon icon-navigation-up"></i>
<i class="icon icon-add"></i>
</a>
</div>
</umb-control-group>
<umb-control-group hide-label="true">
<i class="icon-delete red"></i>
<a class="btn btn-small btn-link" href="" ng-click="deleteSection(currentSection, currentLayout)">
<localize key="general_delete" class="ng-isolate-scope ng-scope">Delete</localize>
</a>
</umb-control-group>
<umb-control-group hide-label="true">
<ul class="unstyled">
@@ -14,7 +14,7 @@ function RowConfigController($scope) {
};
$scope.scaleDown = function(section) {
var remove = (section.grid > 1) ? 1 : section.grid;
var remove = (section.grid > 1) ? 1 : 0;
section.grid = section.grid - remove;
};
@@ -58,9 +58,14 @@ function RowConfigController($scope) {
}
};
$scope.deleteArea = function(index) {
$scope.currentRow.areas.splice(index, 1);
$scope.deleteArea = function (cell, row) {
if ($scope.currentCell === cell) {
$scope.currentCell = undefined;
}
var index = row.areas.indexOf(cell)
row.areas.splice(index, 1);
};
$scope.closeArea = function() {
$scope.currentCell = undefined;
};
@@ -6,9 +6,14 @@
<p><localize key="grid_addRowConfigurationDetail" /></p>
<div class="alert alert-warn ng-scope" ng-show="nameChanged">
Modifying a row configuration name will result in loss of
data for any existing content that is based on this configuration.
<p>Modifying a row configuration name will result in loss of
data for any existing content that is based on this configuration.</p>
<p><strong>Modifying only the label will not result in data loss.</strong></p>
</div>
<umb-control-group label="@general_label">
<input type="text" ng-model="currentRow.label" placeholder="Overrides name" />
</umb-control-group>
<umb-control-group label="@general_name">
<input type="text" ng-model="currentRow.name" />
@@ -39,19 +44,23 @@
<div ng-if="currentCell" style="padding-bottom: 50px;">
<umb-control-group label="@general_width">
<div class="grid-size-scaler" >
<div class="grid-size-scaler">
<a href ng-click="scaleDown(currentCell)">
<i class="icon icon-remove"></i>
</a>
<div class="grid-size-scaler">
<a href ng-click="scaleDown(currentCell)">
<i class="icon icon-remove"></i>
</a>
{{currentCell.grid}}
<a href ng-click="scaleUp(currentCell, availableRowSpace, true)">
<i class="icon icon-add"></i>
</a>
</div>
</div>
<a href ng-click="scaleUp(currentCell, availableRowSpace, true)">
<i class="icon icon-add"></i>
</a>
</div>
</umb-control-group>
<umb-control-group hide-label="true">
<i class="icon-delete red"></i>
<a class="btn btn-small btn-link" href="" ng-click="deleteArea(currentCell, currentRow)">
<localize key="general_delete" class="ng-isolate-scope ng-scope">Delete</localize>
</a>
</umb-control-group>
<umb-control-group hide-label="true">
<ul class="unstyled">
@@ -343,6 +343,37 @@ angular.module("umbraco")
}
};
var shouldApply = function(item, itemType, gridItem) {
if (item.applyTo === undefined || item.applyTo === null || item.applyTo === "") {
return true;
}
if (typeof (item.applyTo) === "string") {
return item.applyTo === itemType;
}
if (itemType === "row") {
if (item.applyTo.row === undefined) {
return false;
}
if (item.applyTo.row === null || item.applyTo.row === "") {
return true;
}
var rows = item.applyTo.row.split(',');
return _.indexOf(rows, gridItem.name) !== -1;
} else if (itemType === "cell") {
if (item.applyTo.cell === undefined) {
return false;
}
if (item.applyTo.cell === null || item.applyTo.cell === "") {
return true;
}
var cells = item.applyTo.cell.split(',');
var cellSize = gridItem.grid.toString();
return _.indexOf(cells, cellSize) !== -1;
}
}
$scope.editGridItemSettings = function (gridItem, itemType) {
placeHolder = "{0}";
@@ -352,8 +383,8 @@ angular.module("umbraco")
styles = null;
config = angular.copy(gridItem.editor.config.settings);
} else {
styles = _.filter(angular.copy($scope.model.config.items.styles), function (item) { return (item.applyTo === undefined || item.applyTo === itemType); });
config = _.filter(angular.copy($scope.model.config.items.config), function (item) { return (item.applyTo === undefined || item.applyTo === itemType); });
styles = _.filter(angular.copy($scope.model.config.items.styles), function (item) { return shouldApply(item, itemType, gridItem); });
config = _.filter(angular.copy($scope.model.config.items.config), function (item) { return shouldApply(item, itemType, gridItem); });
}
if(angular.isObject(gridItem.config)){
@@ -80,7 +80,7 @@
<div class="umb-row-title-bar">
<div class=".umb-grid-right">
<div class="umb-row-title">{{row.name}}</div>
<div class="umb-row-title">{{row.label || row.name}}</div>
<div class="umb-grid-has-config" ng-if="row.hasConfig && !sortMode">
<localize key="grid_settingsApplied" />
@@ -282,7 +282,7 @@
<div class="preview-overlay">
</div>
<small>{{layout.name}}</small>
<small>{{layout.label || layout.name}}</small>
</div> <!-- .templates-preview-rows -->
@@ -48,6 +48,7 @@ angular.module("umbraco")
layouts:[
{
label: "Headline",
name: "Headline",
areas: [
{
@@ -57,6 +58,7 @@ angular.module("umbraco")
]
},
{
label: "Article",
name: "Article",
areas: [
{
@@ -72,7 +72,7 @@
</div>
<div>
{{layout.name}}<br />
{{layout.label || layout.name}}<br />
<i class="icon-delete red"></i>
<a class="btn btn-small btn-link" href ng-click="deleteLayout($index)">
<localize key="general_delete" />
@@ -118,7 +118,7 @@ angular.module('umbraco')
//NOTE: The 'entity' can be either a normal media entity or an "entity" returned from the entityResource
// they contain different data structures so if we need to query against it we need to be aware of this.
mediaHelper.registerFileResolver("Umbraco.ImageCropper", function (property, entity, thumbnail) {
if (property.value.src) {
if (property.value && property.value.src) {
if (thumbnail === true) {
return property.value.src + "?width=500&mode=max&animationprocessmode=first";
@@ -44,7 +44,7 @@
center="model.value.focalPoint"
on-image-loaded="imageLoaded">
</umb-image-gravity>
<a href class="btn btn-link btn-crop-delete" ng-show="imageIsLoaded" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
<a href class="btn btn-link btn-crop-delete" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
</div>
<ul class="umb-sortable-thumbnails cropList clearfix">
@@ -36,7 +36,8 @@
}
function clickItem(item) {
$location.path($scope.entityType + '/' +$scope.entityType + '/edit/' +item.id);
// if item.id is 2147483647 (int.MaxValue) use item.key
$location.path($scope.entityType + '/' +$scope.entityType + '/edit/' + (item.id === 2147483647 ? item.key : item.id));
}
function isSortDirection(col, direction) {
@@ -4,10 +4,10 @@
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
<!-- IMAGE -->
<img ng-src="{{image.thumbnail}}" alt="" ng-show="image.thumbnail" />
<img ng-src="{{image.thumbnail}}" alt="" ng-show="image.thumbnail" title="{{image.name}}" />
<!-- SVG -->
<img ng-if="image.metaData.umbracoExtension.Value === 'svg'" ng-src="{{image.metaData.umbracoFile.Value}}" alt="" />
<img ng-if="image.metaData.umbracoExtension.Value === 'svg'" ng-src="{{image.metaData.umbracoFile.Value}}" alt="" title="{{image.name}}" />
<img ng-if="image.extension === 'svg'" ng-src="{{image.file}}" alt="" />
<!-- FILE -->
+13 -12
View File
@@ -107,12 +107,12 @@
<Project>{07fbc26b-2927-4a22-8d96-d644c667fecc}</Project>
<Name>UmbracoExamine</Name>
</ProjectReference>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.9.1.0, Culture=neutral, processorArchitecture=MSIL">
@@ -127,20 +127,20 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.69.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.69.0\lib\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor, Version=2.4.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.4.4.0\lib\net45\ImageProcessor.dll</HintPath>
<Reference Include="ImageProcessor, Version=2.4.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.4.5.0\lib\net45\ImageProcessor.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ImageProcessor.Web, Version=4.6.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.Web.4.6.4.0\lib\net45\ImageProcessor.Web.dll</HintPath>
<Reference Include="ImageProcessor.Web, Version=4.6.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.Web.4.6.6.0\lib\net45\ImageProcessor.Web.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
@@ -2412,9 +2412,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7530</DevelopmentServerPort>
<DevelopmentServerPort>7540</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7530</IISUrl>
<IISUrl>http://localhost:7540</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -2453,4 +2453,5 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
</ReadLinesFromFile>
<Exec WorkingDirectory="$(ProjectDir)\..\..\build\" Command="BuildBelle.bat $(VersionNumber)" ConsoleToMSBuild="true" IgnoreExitCode="true" ContinueOnError="WarnAndContinue" />
</Target>
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
</Project>
@@ -2,32 +2,9 @@
<urlrewritingnet xmlns="http://www.urlrewriting.net/schemas/config/2006/07">
<rewrites>
<!--
Urlrewriting.Net is a cool tool, what can make your urls look nice.
The rewriting is controlled with regular expressions. To get more help
look at http://www.urlrewriting.net/.
Remember to read the manual!
http://our.umbraco.org/wiki/recommendations/recommended-reading-for-web-developers
The sample below rewrites a url from
"/product/someproductid.aspx" to
"/product.aspx?productid=someproductid"
The user will not see the rewritten path! The page that will be
loaded from umbraco will instead be:
"/product.aspx?productid=someproductid"
<add name="produktidrewrite"
virtualUrl="^~/product/(.*).aspx"
rewriteUrlParameter="ExcludeFromClientQueryString"
destinationUrl="~/product.aspx?productid=$1"
ignoreCase="true" />
This sample is usefull for a productpage, where the product comes from a
dynamic datasource, e.g. a database. The querystring "productid" can be loaded
from the template, into a macro, that then loads the product!
Any bugs or problems with the rewriter, contact Anders/Duckie
-->
URLRewriting.net is obsolete and will be removed from Umbraco in the future.
If you want to do rewrites, make sure to use IIS URL rewrite: https://www.iis.net/downloads/microsoft/url-rewrite
The advantage of using IIS rewrite is that it is much faster, much less CPU intensive and much less memory intensive.
-->
</rewrites>
</urlrewritingnet>
+5 -28
View File
@@ -2,32 +2,9 @@
<urlrewritingnet xmlns="http://www.urlrewriting.net/schemas/config/2006/07">
<rewrites>
<!--
Urlrewriting.Net is a cool tool, what can make your urls look nice.
The rewriting is controlled with regular expressions. To get more help
look at http://www.urlrewriting.net/.
Remember to read the manual!
http://our.umbraco.org/wiki/recommendations/recommended-reading-for-web-developers
The sample below rewrites a url from
"/product/someproductid.aspx" to
"/product.aspx?productid=someproductid"
The user will not see the rewritten path! The page that will be
loaded from umbraco will instead be:
"/product.aspx?productid=someproductid"
<add name="produktidrewrite"
virtualUrl="^~/product/(.*).aspx"
rewriteUrlParameter="ExcludeFromClientQueryString"
destinationUrl="~/product.aspx?productid=$1"
ignoreCase="true" />
This sample is usefull for a productpage, where the product comes from a
dynamic datasource, e.g. a database. The querystring "productid" can be loaded
from the template, into a macro, that then loads the product!
Any bugs or problems with the rewriter, contact Anders/Duckie
-->
URLRewriting.net is obsolete and will be removed from Umbraco in the future.
If you want to do rewrites, make sure to use IIS URL rewrite: https://www.iis.net/downloads/microsoft/url-rewrite
The advantage of using IIS rewrite is that it is much faster, much less CPU intensive and much less memory intensive.
-->
</rewrites>
</urlrewritingnet>
</urlrewritingnet>
@@ -39,7 +39,7 @@
"view": "textstring",
"icon": "icon-quote",
"config": {
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px",
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-style: italic; font-size: 18px",
"markup": "<blockquote>#value#</blockquote>"
}
}
@@ -27,7 +27,7 @@
<div class="logo"></div>
<h1>Welcome to your Umbraco installation</h1>
<h3>You're seeing the wonderful page because your website doesn't contain any published content yet.</h3>
<h3>You're seeing this wonderful page because your website doesn't contain any published content yet.</h3>
<div class="cta">
<a href="<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>" class="button">Open Umbraco</a>
@@ -44,7 +44,7 @@
<div class="col">
<h2>Be a part of the community</h2>
<p>The Umbraco community is the best of its kind, be sure to visit, and if you have any questions, were sure that you can get your answers from the community.</p>
<p>The Umbraco community is the best of its kind, be sure to visit, and if you have any questions, were sure that you can get your answers from the community.</p>
<a href="http://our.umbraco.org?ref=ourFromInstaller" target="_blank">our.Umbraco &rarr;</a>
</div>
@@ -58,4 +58,4 @@
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
</body>
</html>
</html>
+314 -314
View File
@@ -1,319 +1,319 @@
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<content>
<imaging>
<!-- what file extension that should cause umbraco to create thumbnails -->
<imageFileTypes>jpeg,jpg,gif,bmp,png,tiff,tif</imageFileTypes>
<!-- what attributes that are allowed in the editor on an img tag -->
<allowedAttributes>src,alt,border,class,style,align,id,name,onclick,usemap</allowedAttributes>
<!-- automatically updates dimension, filesize and extension attributes on upload -->
<autoFillImageProperties>
<uploadField alias="umbracoFile">
<widthFieldAlias>umbracoWidth</widthFieldAlias>
<heightFieldAlias>umbracoHeight</heightFieldAlias>
<lengthFieldAlias>umbracoBytes</lengthFieldAlias>
<extensionFieldAlias>umbracoExtension</extensionFieldAlias>
</uploadField>
</autoFillImageProperties>
</imaging>
<scripteditor>
<!-- Path to script folder - no ending "/" -->
<scriptFolderPath>/scripts</scriptFolderPath>
<!-- what files can be opened/created in the script editor -->
<scriptFileTypes>js,xml</scriptFileTypes>
<!-- disable the codemirror editor and use a simple textarea instead -->
<scriptDisableEditor>false</scriptDisableEditor>
</scripteditor>
<!-- should umbraco store the uploaded files like /media/xxx/filename.ext or like /media/xxx-filename.ext
should be set to false if the application pool's user account hasn't got readrights of the driveroot up to the /media directory -->
<UploadAllowDirectories>True</UploadAllowDirectories>
<errors>
<!-- the id of the page that should be shown if the page is not found -->
<!--<error404>
<errorPage culture="default">1</errorPage>
<errorPage culture="en-US">200</errorPage>
</error404>-->
<error404>
<errorPage culture="default">1</errorPage>
<errorPage culture="fr-FR">1079</errorPage>
<errorPage culture="en-US">1080</errorPage>
</error404>
</errors>
<notifications>
<!-- the email that should be used as from mail when umbraco sends a notification -->
<email>your@email.here</email>
</notifications>
<!-- if true umbraco will ensure that no page under the same parent has an identical name -->
<ensureUniqueNaming>True</ensureUniqueNaming>
<!-- clean editor content with use of tidy -->
<TidyEditorContent>False</TidyEditorContent>
<!-- the encoding type for tidy. Default is UTF8, options are ASCII, Raw, Latin1, UTF8, ISO2022, MacroMan-->
<TidyCharEncoding>UTF8</TidyCharEncoding>
<!-- to enable new content schema, this needs to be false -->
<UseLegacyXmlSchema>false</UseLegacyXmlSchema>
<!-- Whether to force safe aliases (no spaces, no special characters) at businesslogic level on contenttypes and propertytypes -->
<!-- HIGHLY recommend to keep this to true to ensure valid and beautiful XML Schemas -->
<ForceSafeAliases>true</ForceSafeAliases>
<!-- Enable / disable xml content cache -->
<XmlCacheEnabled>True</XmlCacheEnabled>
<!-- Update disk cache every time content has changed -->
<ContinouslyUpdateXmlDiskCache>True</ContinouslyUpdateXmlDiskCache>
<!-- Update in-memory cache if xml file is changed -->
<XmlContentCheckForDiskChanges>False</XmlContentCheckForDiskChanges>
<!-- Show the /config/splashes/booting.aspx page while initializing content -->
<EnableSplashWhileLoading>False</EnableSplashWhileLoading>
<!-- Show property descriptions in editing view "icon|text|none" -->
<PropertyContextHelpOption>text</PropertyContextHelpOption>
<!-- The html injected into a (x)html page if Umbraco is running in preview mode -->
<PreviewBadge>
<![CDATA[<a id="umbracoPreviewBadge" style="position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={2}'"><span style="display:none;">In Preview Mode - click to end</span></a>
]]></PreviewBadge>
<!-- Cache cycle of Media and Member data fetched from the umbraco.library methods -->
<!-- In seconds. 0 will disable cache -->
<UmbracoLibraryCacheDuration>1800</UmbracoLibraryCacheDuration>
<!-- Url Resolving ensures that all links works if you run Umbraco in virtual directories -->
<!-- Setting this to true can increase render time for pages with a large number of links -->
<!-- If running Umbraco in virtual directory this *must* be set to true! -->
<ResolveUrlsFromTextString>false</ResolveUrlsFromTextString>
<!-- How Umbraco should handle errors during macro execution. Can be one of the following values:
- inline - show an inline error within the macro but allow the page to continue rendering. Historial Umbraco behaviour.
- silent - Silently suppress the error and do not render the offending macro.
- throw - 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.
Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. -->
<MacroErrors>throw</MacroErrors>
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
</content>
<security>
<!-- set to true to auto update login interval (and there by disabling the lock screen -->
<keepUserLoggedIn>true</keepUserLoggedIn>
<!-- change in 4.8: Disabled users are now showed dimmed and last in the tree. If you prefer not to display them set this to true -->
<hideDisabledUsersInBackoffice>false</hideDisabledUsersInBackoffice>
<!-- set to true to enable the UI and API to allow back-office users to reset their passwords -->
<allowPasswordReset>true</allowPasswordReset>
</security>
<requestHandler>
<!-- this will ensure that urls are unique when running with multiple root nodes -->
<useDomainPrefixes>false</useDomainPrefixes>
<!-- this will add a trailing slash (/) to urls when in directory url mode -->
<addTrailingSlash>true</addTrailingSlash>
<urlReplacing removeDoubleDashes="true">
<char org=" ">-</char>
<char org="&quot;"></char>
<char org="'"></char>
<char org="%"></char>
<char org="."></char>
<char org=";"></char>
<char org="/"></char>
<char org="\"></char>
<char org=":"></char>
<char org="#"></char>
<char org="+">plus</char>
<char org="*">star</char>
<char org="&amp;"></char>
<char org="?"></char>
<char org="æ">ae</char>
<char org="ø">oe</char>
<char org="Ã¥">aa</char>
<char org="ä">ae</char>
<char org="ö">oe</char>
<char org="ü">ue</char>
<char org="ß">ss</char>
<char org="Ä">ae</char>
<char org="Ö">oe</char>
<char org="|">-</char>
<char org="&lt;"></char>
<char org="&gt;"></char>
</urlReplacing>
</requestHandler>
<templates>
<!-- If you want to switch to Mvc then do NOT change useAspNetMasterPages to false -->
<!-- This (old!) setting is still used to control how macros are inserted into your pages -->
<useAspNetMasterPages>true</useAspNetMasterPages>
<!-- To switch the default rendering engine to MVC, change this value from WebForms to Mvc -->
<!-- Do not set useAspNetMasterPages to false, it is not relevant to MVC usage -->
<defaultRenderingEngine>Mvc</defaultRenderingEngine>
</templates>
<!-- this is used by Umbraco to determine if there's valid classes in the /App_Code folder to be used for Rest/XSLT extensions -->
<developer>
<appCodeFileExtensions>
<ext>cs</ext>
<ext>vb</ext>
</appCodeFileExtensions>
</developer>
<scripting>
<razor>
<!-- razor DynamicNode typecasting detects XML and returns DynamicXml - Root elements that won't convert to DynamicXml -->
<notDynamicXmlDocumentElements>
<element>p</element>
<element>div</element>
<element>ul</element>
<element>span</element>
</notDynamicXmlDocumentElements>
<dataTypeModelStaticMappings>
<!--
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping documentTypeAlias="textPage" nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000" documentTypeAlias="textPage" nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000" documentTypeAlias="textPage">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000" nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
-->
</dataTypeModelStaticMappings>
</razor>
</scripting>
<!-- This moves the asp.net viewstate data to the end of the html document instead of having it in the beginning-->
<viewstateMoverModule enable="false" />
<!--
Now that we have Log4Net logging enabled, this section is only used for what gets logged to the umbracoLog table
which currently logs items used in the audit trail and roll back scenarios.
-->
<logging>
<enableLogging>true</enableLogging>
<enableAsyncLogging>true</enableAsyncLogging>
<disabledLogTypes>
<!-- <logTypeAlias>[alias-of-log-type-in-lowercase]</logTypeAlias> -->
</disabledLogTypes>
<!-- You can add your own logging tool by implementing the umbraco.BusinessLogic.Interfaces.ILog interface and add the reference here -->
<!-- The external logger can also act as the audit trail storage by setting the logAuditTrail attribute to true -->
<!--<externalLogger assembly="~/bin/assemblyFileName.dll" type="fully.qualified.namespace.and.type" logAuditTrail="false" /> -->
</logging>
<scheduledTasks>
<!-- add tasks that should be called with an interval (seconds) -->
<!-- <task log="true" alias="test60" interval="60" url="http://localhost/umbraco/test.aspx"/>-->
</scheduledTasks>
<!-- distributed calls must be enabled when using Umbraco in a load balanced environment -->
<distributedCall enable="false">
<!-- the id of the user who's making the calls -->
<!-- needed for security, umbraco will automatically look up correct login and passwords -->
<user>0</user>
<!--
When distributed call is enabled, you need to add all of the servers part taking in load balancing
to the server list below.
-->
<servers>
<!--
Add ip number or hostname, make sure that it can be reached from all servers
you can also add optional attributes to force a protocol or port number.
Examples:
<server>127.0.0.1</server>
<server forceProtocol="http|https" forcePortnumber="80|443">127.0.0.1</server>
Generally when setting up load balancing you will designate a 'master' server,
Umbraco will always assume that the FIRST server listed in this list is the 'master'.
(NOTE: Not all load balancing scenarios have a 'master', depends on how you are setting it up)
In order for scheduled tasks (including scheduled publishing) to work properly when load balancing, each
server in the load balanced environment needs to know if it is the 'master'. In order for servers
to know this or not, they need to compare some values against the servers listed. These values
are either: serverName or appId. You should not enter both values but appId will always supersede serverName.
The serverName is the easiest and will work so long as you are not load balancing your site on the same server.
If you are doing this, then you will need to use appId which is equivalent to the value returned from
HttpRuntime.AppDomainAppId. It is recommended that you set either the serverName or appId for all servers
registered here if possible, not just the first one.
Examples:
<server serverName="MyServer">server1.mysite.com</server>
<server appId="/LM/W3SVC/69/ROOT">server1.mysite.com</server>
-->
</servers>
</distributedCall>
<!-- Configuration for repositories -->
<!-- Add or remove repositories here. You will need the repository's unique key to be able to connect to it.-->
<repositories>
<repository name="Umbraco package Repository" guid="65194810-1f85-11dd-bd0b-0800200c9a66" />
</repositories>
<providers>
<users>
<!-- if you wish to use your own membershipprovider for authenticating to the umbraco back office -->
<!-- specify it here (remember to add it to the web.config as well) -->
<DefaultBackofficeProvider>UsersMembershipProvider</DefaultBackofficeProvider>
</users>
</providers>
<!-- Maps language, usertype, application and application_url to help pages -->
<help defaultUrl="http://our.umbraco.org/wiki/umbraco-help/{0}/{1}">
<!-- Add links that should open custom help pages -->
<!--<link application="content" applicationUrl="dashboard.aspx" language="en" userType="Administrators" helpUrl="http://www.xyz.no?{0}/{1}/{2}/{3}" /> -->
</help>
<!--
web.routing
@trySkipIisCustomErrors
Tries to skip IIS custom errors.
Starting with IIS 7.5, this must be set to true for Umbraco 404 pages to show. Else, IIS will take
over and render its built-in error page. See MS doc for HttpResponseBase.TrySkipIisCustomErrors.
The default value is false, for backward compatibility reasons, which means that IIS _will_ take
over, and _prevent_ Umbraco 404 pages to show.
@internalRedirectPreservesTemplate
By default as soon as we're not displaying the initial document, we reset the template set by the
finder or by the alt. template. Set this option to true to preserve the template set by the finder
or by the alt. template, in case of an internal redirect.
(false by default, and in fact should remain false unless you know what you're doing)
@disableAlternativeTemplates
By default you can add a altTemplate querystring or append a template name to the current URL which
will make Umbraco render the content on the current page with the template you requested, for example:
http://mysite.com/about-us/?altTemplate=Home and http://mysite.com/about-us/Home would render the
"About Us" page with a template with the alias Home. Setting this setting to true stops that behavior
@disableFindContentByIdPath
By default you can call any content Id in the url and show the content with that id, for example:
http://mysite.com/1092 or http://mysite.com/1092.aspx would render the content with id 1092. Setting
this setting to true stops that behavior
@umbracoApplicationUrl
The url of the Umbraco application. By default, Umbraco will figure it out from the first request.
Configure it here if you need anything specific. Needs to be a complete url with scheme and umbraco
path, eg http://mysite.com/umbraco. NOT just "mysite.com" or "mysite.com/umbraco" or "http://mysite.com".
-->
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<content>
<imaging>
<!-- what file extension that should cause umbraco to create thumbnails -->
<imageFileTypes>jpeg,jpg,gif,bmp,png,tiff,tif</imageFileTypes>
<!-- what attributes that are allowed in the editor on an img tag -->
<allowedAttributes>src,alt,border,class,style,align,id,name,onclick,usemap</allowedAttributes>
<!-- automatically updates dimension, filesize and extension attributes on upload -->
<autoFillImageProperties>
<uploadField alias="umbracoFile">
<widthFieldAlias>umbracoWidth</widthFieldAlias>
<heightFieldAlias>umbracoHeight</heightFieldAlias>
<lengthFieldAlias>umbracoBytes</lengthFieldAlias>
<extensionFieldAlias>umbracoExtension</extensionFieldAlias>
</uploadField>
</autoFillImageProperties>
</imaging>
<scripteditor>
<!-- Path to script folder - no ending "/" -->
<scriptFolderPath>/scripts</scriptFolderPath>
<!-- what files can be opened/created in the script editor -->
<scriptFileTypes>js,xml</scriptFileTypes>
<!-- disable the codemirror editor and use a simple textarea instead -->
<scriptDisableEditor>false</scriptDisableEditor>
</scripteditor>
<!-- should umbraco store the uploaded files like /media/xxx/filename.ext or like /media/xxx-filename.ext
should be set to false if the application pool's user account hasn't got readrights of the driveroot up to the /media directory -->
<UploadAllowDirectories>True</UploadAllowDirectories>
<errors>
<!-- the id of the page that should be shown if the page is not found -->
<!--<error404>
<errorPage culture="default">1</errorPage>
<errorPage culture="en-US">200</errorPage>
</error404>-->
<error404>
<errorPage culture="default">1</errorPage>
<errorPage culture="fr-FR">1079</errorPage>
<errorPage culture="en-US">1080</errorPage>
</error404>
</errors>
<notifications>
<!-- the email that should be used as from mail when umbraco sends a notification -->
<email>your@email.here</email>
</notifications>
<!-- if true umbraco will ensure that no page under the same parent has an identical name -->
<ensureUniqueNaming>True</ensureUniqueNaming>
<!-- clean editor content with use of tidy -->
<TidyEditorContent>False</TidyEditorContent>
<!-- the encoding type for tidy. Default is UTF8, options are ASCII, Raw, Latin1, UTF8, ISO2022, MacroMan-->
<TidyCharEncoding>UTF8</TidyCharEncoding>
<!-- to enable new content schema, this needs to be false -->
<UseLegacyXmlSchema>false</UseLegacyXmlSchema>
<!-- Whether to force safe aliases (no spaces, no special characters) at businesslogic level on contenttypes and propertytypes -->
<!-- HIGHLY recommend to keep this to true to ensure valid and beautiful XML Schemas -->
<ForceSafeAliases>true</ForceSafeAliases>
<!-- Enable / disable xml content cache -->
<XmlCacheEnabled>True</XmlCacheEnabled>
<!-- Update disk cache every time content has changed -->
<ContinouslyUpdateXmlDiskCache>True</ContinouslyUpdateXmlDiskCache>
<!-- Update in-memory cache if xml file is changed -->
<XmlContentCheckForDiskChanges>False</XmlContentCheckForDiskChanges>
<!-- Show the /config/splashes/booting.aspx page while initializing content -->
<EnableSplashWhileLoading>False</EnableSplashWhileLoading>
<!-- Show property descriptions in editing view "icon|text|none" -->
<PropertyContextHelpOption>text</PropertyContextHelpOption>
<!-- The html injected into a (x)html page if Umbraco is running in preview mode -->
<PreviewBadge>
<![CDATA[<a id="umbracoPreviewBadge" style="position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={2}'"><span style="display:none;">In Preview Mode - click to end</span></a>
]]></PreviewBadge>
<!-- Cache cycle of Media and Member data fetched from the umbraco.library methods -->
<!-- In seconds. 0 will disable cache -->
<UmbracoLibraryCacheDuration>1800</UmbracoLibraryCacheDuration>
<!-- Url Resolving ensures that all links works if you run Umbraco in virtual directories -->
<!-- Setting this to true can increase render time for pages with a large number of links -->
<!-- If running Umbraco in virtual directory this *must* be set to true! -->
<ResolveUrlsFromTextString>false</ResolveUrlsFromTextString>
<!-- How Umbraco should handle errors during macro execution. Can be one of the following values:
- inline - show an inline error within the macro but allow the page to continue rendering. Historial Umbraco behaviour.
- silent - Silently suppress the error and do not render the offending macro.
- throw - 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.
Note the error can also be handled by the umbraco.macro.Error event, where you can log/alarm with your own code and change the behaviour per event. -->
<MacroErrors>throw</MacroErrors>
<!-- These file types will not be allowed to be uploaded via the upload control for media and content -->
<disallowedUploadFiles>ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,html,htm,svg,php,htaccess</disallowedUploadFiles>
<!-- Defines the default document type property used when adding properties in the back-office (if missing or empty, defaults to Textstring -->
<defaultDocumentTypeProperty>Textstring</defaultDocumentTypeProperty>
</content>
<security>
<!-- set to true to auto update login interval (and there by disabling the lock screen -->
<keepUserLoggedIn>true</keepUserLoggedIn>
<!-- change in 4.8: Disabled users are now showed dimmed and last in the tree. If you prefer not to display them set this to true -->
<hideDisabledUsersInBackoffice>false</hideDisabledUsersInBackoffice>
<!-- set to true to enable the UI and API to allow back-office users to reset their passwords -->
<allowPasswordReset>true</allowPasswordReset>
</security>
<requestHandler>
<!-- this will ensure that urls are unique when running with multiple root nodes -->
<useDomainPrefixes>false</useDomainPrefixes>
<!-- this will add a trailing slash (/) to urls when in directory url mode -->
<addTrailingSlash>true</addTrailingSlash>
<urlReplacing removeDoubleDashes="true">
<char org=" ">-</char>
<char org="&quot;"></char>
<char org="'"></char>
<char org="%"></char>
<char org="."></char>
<char org=";"></char>
<char org="/"></char>
<char org="\"></char>
<char org=":"></char>
<char org="#"></char>
<char org="+">plus</char>
<char org="*">star</char>
<char org="&amp;"></char>
<char org="?"></char>
<char org="æ">ae</char>
<char org="ø">oe</char>
<char org="Ã¥">aa</char>
<char org="ä">ae</char>
<char org="ö">oe</char>
<char org="ü">ue</char>
<char org="ß">ss</char>
<char org="Ä">ae</char>
<char org="Ö">oe</char>
<char org="|">-</char>
<char org="&lt;"></char>
<char org="&gt;"></char>
</urlReplacing>
</requestHandler>
<templates>
<!-- If you want to switch to Mvc then do NOT change useAspNetMasterPages to false -->
<!-- This (old!) setting is still used to control how macros are inserted into your pages -->
<useAspNetMasterPages>true</useAspNetMasterPages>
<!-- To switch the default rendering engine to MVC, change this value from WebForms to Mvc -->
<!-- Do not set useAspNetMasterPages to false, it is not relevant to MVC usage -->
<defaultRenderingEngine>Mvc</defaultRenderingEngine>
</templates>
<!-- this is used by Umbraco to determine if there's valid classes in the /App_Code folder to be used for Rest/XSLT extensions -->
<developer>
<appCodeFileExtensions>
<ext>cs</ext>
<ext>vb</ext>
</appCodeFileExtensions>
</developer>
<scripting>
<razor>
<!-- razor DynamicNode typecasting detects XML and returns DynamicXml - Root elements that won't convert to DynamicXml -->
<notDynamicXmlDocumentElements>
<element>p</element>
<element>div</element>
<element>ul</element>
<element>span</element>
</notDynamicXmlDocumentElements>
<dataTypeModelStaticMappings>
<!--
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping documentTypeAlias="textPage" nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000" documentTypeAlias="textPage" nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000" documentTypeAlias="textPage">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping dataTypeGuid="00000000-0000-0000-0000-000000000000" nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
<mapping nodeTypeAlias="propertyAlias">Fully.Qualified.Type.Name.For.ModelBinder,Assembly.Name.Excluding.Dot.Dll</mapping>
-->
</dataTypeModelStaticMappings>
</razor>
</scripting>
<!-- This moves the asp.net viewstate data to the end of the html document instead of having it in the beginning-->
<viewstateMoverModule enable="false" />
<!--
Now that we have Log4Net logging enabled, this section is only used for what gets logged to the umbracoLog table
which currently logs items used in the audit trail and roll back scenarios.
-->
<logging>
<enableLogging>true</enableLogging>
<enableAsyncLogging>true</enableAsyncLogging>
<disabledLogTypes>
<!-- <logTypeAlias>[alias-of-log-type-in-lowercase]</logTypeAlias> -->
</disabledLogTypes>
<!-- You can add your own logging tool by implementing the umbraco.BusinessLogic.Interfaces.ILog interface and add the reference here -->
<!-- The external logger can also act as the audit trail storage by setting the logAuditTrail attribute to true -->
<!--<externalLogger assembly="~/bin/assemblyFileName.dll" type="fully.qualified.namespace.and.type" logAuditTrail="false" /> -->
</logging>
<scheduledTasks>
<!-- add tasks that should be called with an interval (seconds) -->
<!-- <task log="true" alias="test60" interval="60" url="http://localhost/umbraco/test.aspx"/>-->
</scheduledTasks>
<!-- distributed calls must be enabled when using Umbraco in a load balanced environment -->
<distributedCall enable="false">
<!-- the id of the user who's making the calls -->
<!-- needed for security, umbraco will automatically look up correct login and passwords -->
<user>0</user>
<!--
When distributed call is enabled, you need to add all of the servers part taking in load balancing
to the server list below.
-->
<servers>
<!--
Add ip number or hostname, make sure that it can be reached from all servers
you can also add optional attributes to force a protocol or port number.
Examples:
<server>127.0.0.1</server>
<server forceProtocol="http|https" forcePortnumber="80|443">127.0.0.1</server>
Generally when setting up load balancing you will designate a 'master' server,
Umbraco will always assume that the FIRST server listed in this list is the 'master'.
(NOTE: Not all load balancing scenarios have a 'master', depends on how you are setting it up)
In order for scheduled tasks (including scheduled publishing) to work properly when load balancing, each
server in the load balanced environment needs to know if it is the 'master'. In order for servers
to know this or not, they need to compare some values against the servers listed. These values
are either: serverName or appId. You should not enter both values but appId will always supersede serverName.
The serverName is the easiest and will work so long as you are not load balancing your site on the same server.
If you are doing this, then you will need to use appId which is equivalent to the value returned from
HttpRuntime.AppDomainAppId. It is recommended that you set either the serverName or appId for all servers
registered here if possible, not just the first one.
Examples:
<server serverName="MyServer">server1.mysite.com</server>
<server appId="/LM/W3SVC/69/ROOT">server1.mysite.com</server>
-->
</servers>
</distributedCall>
<!-- Configuration for repositories -->
<!-- Add or remove repositories here. You will need the repository's unique key to be able to connect to it.-->
<repositories>
<repository name="Umbraco package Repository" guid="65194810-1f85-11dd-bd0b-0800200c9a66" />
</repositories>
<providers>
<users>
<!-- if you wish to use your own membershipprovider for authenticating to the umbraco back office -->
<!-- specify it here (remember to add it to the web.config as well) -->
<DefaultBackofficeProvider>UsersMembershipProvider</DefaultBackofficeProvider>
</users>
</providers>
<!-- Maps language, usertype, application and application_url to help pages -->
<help defaultUrl="http://our.umbraco.org/wiki/umbraco-help/{0}/{1}">
<!-- Add links that should open custom help pages -->
<!--<link application="content" applicationUrl="dashboard.aspx" language="en" userType="Administrators" helpUrl="http://www.xyz.no?{0}/{1}/{2}/{3}" /> -->
</help>
<!--
web.routing
@trySkipIisCustomErrors
Tries to skip IIS custom errors.
Starting with IIS 7.5, this must be set to true for Umbraco 404 pages to show. Else, IIS will take
over and render its built-in error page. See MS doc for HttpResponseBase.TrySkipIisCustomErrors.
The default value is false, for backward compatibility reasons, which means that IIS _will_ take
over, and _prevent_ Umbraco 404 pages to show.
@internalRedirectPreservesTemplate
By default as soon as we're not displaying the initial document, we reset the template set by the
finder or by the alt. template. Set this option to true to preserve the template set by the finder
or by the alt. template, in case of an internal redirect.
(false by default, and in fact should remain false unless you know what you're doing)
@disableAlternativeTemplates
By default you can add a altTemplate querystring or append a template name to the current URL which
will make Umbraco render the content on the current page with the template you requested, for example:
http://mysite.com/about-us/?altTemplate=Home and http://mysite.com/about-us/Home would render the
"About Us" page with a template with the alias Home. Setting this setting to true stops that behavior
@disableFindContentByIdPath
By default you can call any content Id in the url and show the content with that id, for example:
http://mysite.com/1092 or http://mysite.com/1092.aspx would render the content with id 1092. Setting
this setting to true stops that behavior
@umbracoApplicationUrl
The url of the Umbraco application. By default, Umbraco will figure it out from the first request.
Configure it here if you need anything specific. Needs to be a complete url with scheme and umbraco
path, eg http://mysite.com/umbraco. NOT just "mysite.com" or "mysite.com/umbraco" or "http://mysite.com".
-->
<web.routing
trySkipIisCustomErrors="false"
internalRedirectPreservesTemplate="false" disableAlternativeTemplates="false" disableFindContentByIdPath="false"
umbracoApplicationUrl="">
</web.routing>
</web.routing>
</settings>
+4 -4
View File
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="ClientDependency" version="1.9.1" targetFramework="net45" />
<package id="ClientDependency-Mvc5" version="1.8.0.0" targetFramework="net45" />
<package id="dotless" version="1.4.1.0" targetFramework="net45" />
<package id="Examine" version="0.1.69.0" targetFramework="net45" />
<package id="ImageProcessor" version="2.4.4.0" targetFramework="net45" />
<package id="ImageProcessor.Web" version="4.6.4.0" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="ImageProcessor" version="2.4.5.0" targetFramework="net45" />
<package id="ImageProcessor.Web" version="4.6.6.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
@@ -147,9 +147,9 @@
<key alias="nodeName">Page Title</key>
<key alias="otherElements">Properties</key>
<key alias="parentNotPublished">This document is published but is not visible because the parent '%0%' is unpublished</key>
<key alias="parentNotPublishedAnomaly">Oops: this document is published but is not in the cache (internal error - see log)</key>
<key alias="getUrlException">Oops: could not get the url (internal error - see log)</key>
<key alias="routeError">Oops: this document is published but its url would collide with content %0%</key>
<key alias="parentNotPublishedAnomaly">This document is published but is not in the cache</key>
<key alias="getUrlException">Could not get the url</key>
<key alias="routeError">This document is published but its url would collide with content %0%</key>
<key alias="publish">Publish</key>
<key alias="publishStatus">Publication Status</key>
<key alias="releaseDate">Publish at</key>
@@ -1356,6 +1356,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="xmlDataIntegrityCheckMedia">Media - Total XML: %0%, Total: %1%, Total invalid %2%</key>
<key alias="xmlDataIntegrityCheckContent">Content - Total XML: %0%, Total published: %1%, Total invalid %2%</key>
<key alias="httpsCheckValidCertificate">Your site certificate was marked as valid.</key>
<key alias="httpsCheckInvalidCertificate">Certificate validation error: '%0%'</key>
<key alias="httpsCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">You are currently %0% viewing the site using the HTTPS scheme.</key>
@@ -148,9 +148,9 @@
<key alias="nodeName">Page Title</key>
<key alias="otherElements">Properties</key>
<key alias="parentNotPublished">This document is published but is not visible because the parent '%0%' is unpublished</key>
<key alias="parentNotPublishedAnomaly">Oops: this document is published but is not in the cache (internal error - see log)</key>
<key alias="getUrlException">Oops: could not get the url (internal error - see log)</key>
<key alias="routeError">Oops: this document is published but its url would collide with content %0%</key>
<key alias="parentNotPublishedAnomaly">This document is published but is not in the cache</key>
<key alias="getUrlException">Could not get the url</key>
<key alias="routeError">This document is published but its url would collide with content %0%</key>
<key alias="publish">Publish</key>
<key alias="publishStatus">Publication Status</key>
<key alias="releaseDate">Publish at</key>
@@ -460,6 +460,7 @@
<key alias="install">Install</key>
<key alias="invalid">Invalid</key>
<key alias="justify">Justify</key>
<key alias="label">Label</key>
<key alias="language">Language</key>
<key alias="layout">Layout</key>
<key alias="loading">Loading</key>
@@ -1360,6 +1361,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="xmlDataIntegrityCheckMedia">Media - Total XML: %0%, Total: %1%, Total invalid: %2%</key>
<key alias="xmlDataIntegrityCheckContent">Content - Total XML: %0%, Total published: %1%, Total invalid: %2%</key>
<key alias="httpsCheckValidCertificate">Your site certificate was marked as valid.</key>
<key alias="httpsCheckInvalidCertificate">Certificate validation error: '%0%'</key>
<key alias="httpsCheckInvalidUrl">Error pinging the URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">You are currently %0% viewing the site using the HTTPS scheme.</key>
@@ -499,6 +499,7 @@
<key alias="install">Установить</key>
<key alias="invalid">Неверно</key>
<key alias="justify">Выравнивание</key>
<key alias="label">Название</key>
<key alias="language">Язык</key>
<key alias="layout">Макет</key>
<key alias="loading">Загрузка</key>
@@ -654,6 +655,7 @@
<key alias="xmlDataIntegrityCheckMedia">Медиа - всего в XML: %0%, всего: %1%Б с ошибками: %2%</key>
<key alias="xmlDataIntegrityCheckContent">Содержимое - всего в XML: %0%, всего опубликовано: %1%, с ошибками: %2%</key>
<key alias="httpsCheckValidCertificate">Сертификат Вашего сайта отмечен как проверенный.</key>
<key alias="httpsCheckInvalidCertificate">Ошибка проверки сертификата: '%0%'</key>
<key alias="httpsCheckInvalidUrl">Ошибка проверки адреса URL %0% - '%1%'</key>
<key alias="httpsCheckIsCurrentSchemeHttps">Сейчас Вы %0% просматриваете сайт, используя протокол HTTPS.</key>
@@ -1065,6 +1067,23 @@
Чтобы опубликовать ранее неопубликованные документы среди дочерних, отметьте опцию <em>Включая неопубликованные дочерние документы</em>.
]]></key>
</area>
<area alias="redirectUrls">
<key alias="disableUrlTracker">Остановить отслеживание URL</key>
<key alias="enableUrlTracker">Запустить отслеживание URL</key>
<key alias="originalUrl">Первоначальный URL</key>
<key alias="redirectedTo">Перенаправлен в</key>
<key alias="noRedirects">На данный момент нет ни одного перенаправления</key>
<key alias="noRedirectsDescription">Если опубликованный документ переименовывается или меняет свое расположение в дереве, а следовательно, меняется адрес (URL), автоматически создается перенаправление на новое местоположение этого документа.</key>
<key alias="removeButton">Удалить</key>
<key alias="confirmRemove">Вы уверены, что хотите удалить перенаправление с '%0%' на '%1%'?</key>
<key alias="redirectRemoved">Перенаправление удалено.</key>
<key alias="redirectRemoveError">Ошибка удаления перенаправления.</key>
<key alias="confirmDisable">Вы уверены, что хотите остановить отслеживание URL?</key>
<key alias="disabledConfirm">Отслеживание URL в настоящий момент остановлено.</key>
<key alias="disableError">Ошибка остановки отслеживания URL, более подробные сведения находятся в системном журнале.</key>
<key alias="enabledConfirm">Отслеживание URL в настоящий момент запущено.</key>
<key alias="enableError">Ошибка запуска отслеживания URL, более подробные сведения находятся в системном журнале.</key>
</area>
<area alias="relatedlinks">
<key alias="caption">Заголовок</key>
<key alias="captionPlaceholder">Укажите заголовок</key>
@@ -108,16 +108,14 @@
</div>
</asp:PlaceHolder>
<asp:PlaceHolder ID="SaveAndCancelPlaceholder" runat="server">
<br />
<p>
<div class="btn-toolbar umb-btn-toolbar">
<asp:PlaceHolder ID="SaveAndCancelPlaceholder" runat="server">
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
<asp:PlaceHolder ID="SavePlaceholder" runat="server">
<asp:Button ID="ValidateAndSave" runat="server" OnClick="ValidateAndSave_Click" />
<em> <%= umbraco.ui.Text("or") %> </em>
</asp:PlaceHolder>
<a href="#" style="color: blue" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("general", "cancel", Security.CurrentUser)%></a>
</p>
</asp:PlaceHolder>
<asp:Button ID="ValidateAndSave" runat="server" CssClass="btn btn-primary" Text="Create" OnClick="ValidateAndSave_Click"></asp:Button>
</asp:PlaceHolder>
</asp:Placeholder>
</div>
</asp:Content>
@@ -389,12 +389,12 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
processData: false,
success: function (data, textStatus) {
if (textStatus == "error") {
alert("Oops. Could not update sort order");
alert("Could not update sort order");
self._getChildNodes();
}
},
error: function(data) {
alert("Oops. Could not update sort order. Err: " + data.statusText);
alert("Could not update sort order. Err: " + data.statusText);
self._getChildNodes();
}
});
+5
View File
@@ -381,6 +381,11 @@
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="AutoMapper" publicKeyToken="be96cd2c38ef1005" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.3.1.0" newVersion="3.3.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
@@ -77,6 +77,8 @@ namespace Umbraco.Web.Cache
public override void RefreshAll()
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
ClearAllIsolatedCacheByEntityType<IContent>();
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
@@ -85,6 +87,8 @@ namespace Umbraco.Web.Cache
public override void Refresh(int id)
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
ClearRepositoryCacheItemById(id);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
content.Instance.UpdateSortOrder(id);
@@ -94,6 +98,8 @@ namespace Umbraco.Web.Cache
public override void Remove(int id)
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
ClearRepositoryCacheItemById(id);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
@@ -103,6 +109,8 @@ namespace Umbraco.Web.Cache
public override void Refresh(IContent instance)
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
ClearRepositoryCacheItemById(instance.Id);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
content.Instance.UpdateSortOrder(instance);
@@ -112,6 +120,8 @@ namespace Umbraco.Web.Cache
public override void Remove(IContent instance)
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
ClearRepositoryCacheItemById(instance.Id);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
DistributedCache.Instance.ClearDomainCacheOnCurrentServer();
@@ -124,6 +134,8 @@ namespace Umbraco.Web.Cache
/// <param name="jsonPayload"></param>
public void Refresh(string jsonPayload)
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
foreach (var payload in DeserializeFromJsonPayload(jsonPayload))
@@ -215,7 +215,7 @@ namespace Umbraco.Web.Editors
if (user != null && user.IsLockedOut == false)
{
var code = await UserManager.GeneratePasswordResetTokenAsync(identityUser.Id);
var callbackUrl = ConstuctCallbackUrl(identityUser.Id, code);
var callbackUrl = ConstructCallbackUrl(identityUser.Id, code);
var message = Services.TextService.Localize("resetPasswordEmailCopyFormat",
//Ensure the culture of the found user is used for the email!
@@ -233,12 +233,11 @@ namespace Umbraco.Web.Editors
return Request.CreateResponse(HttpStatusCode.OK);
}
private string ConstuctCallbackUrl(int userId, string code)
private string ConstructCallbackUrl(int userId, string code)
{
//get an mvc helper to get the url
// Get an mvc helper to get the url
var http = EnsureHttpContext();
var urlHelper = new UrlHelper(http.Request.RequestContext);
var action = urlHelper.Action("ValidatePasswordResetCode", "BackOffice",
new
{
@@ -247,12 +246,10 @@ namespace Umbraco.Web.Editors
r = code
});
//TODO: Virtual path?
return string.Format("{0}://{1}{2}",
http.Request.Url.Scheme,
http.Request.Url.Host + (http.Request.Url.Port == 80 ? string.Empty : ":" + http.Request.Url.Port),
action);
// Construct full URL using configured application URL (which will fall back to request)
var applicationUri = new Uri(ApplicationContext.UmbracoApplicationUrl);
var callbackUri = new Uri(applicationUri, action);
return callbackUri.ToString();
}
/// <summary>
+8 -7
View File
@@ -467,7 +467,7 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Change the sort order for media
/// Change the sort order for content
/// </summary>
/// <param name="sorted"></param>
/// <returns></returns>
@@ -485,23 +485,24 @@ namespace Umbraco.Web.Editors
return Request.CreateResponse(HttpStatusCode.OK);
}
var contentService = Services.ContentService;
var sortedContent = new List<IContent>();
try
{
sortedContent.AddRange(Services.ContentService.GetByIds(sorted.IdSortOrder));
var contentService = Services.ContentService;
// content service GetByIds does order the content items based on the order of Ids passed in
var content = contentService.GetByIds(sorted.IdSortOrder);
// Save content with new sort order and update content xml in db accordingly
if (contentService.Sort(sortedContent) == false)
if (contentService.Sort(content) == false)
{
LogHelper.Warn<MediaController>("Content sorting failed, this was probably caused by an event being cancelled");
LogHelper.Warn<ContentController>("Content sorting failed, this was probably caused by an event being cancelled");
return Request.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled");
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception ex)
{
LogHelper.Error<MediaController>("Could not update content sort order", ex);
LogHelper.Error<ContentController>("Could not update content sort order", ex);
throw;
}
}
+142 -36
View File
@@ -4,16 +4,125 @@ using Umbraco.Core.Configuration;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using System.Linq;
using System.Xml;
using Umbraco.Core.IO;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using System.Web.Http;
using System;
using System.Net;
using System.Text;
using Umbraco.Core.Cache;
using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Logging;
namespace Umbraco.Web.Editors
{
//we need to fire up the controller like this to enable loading of remote css directly from this controller
[PluginController("UmbracoApi")]
public class DashboardController : UmbracoAuthorizedJsonController
[ValidationFilter]
[AngularJsonOnlyConfiguration]
[IsBackOffice]
[WebApi.UmbracoAuthorize]
public class DashboardController : UmbracoApiController
{
//we have baseurl as a param to make previewing easier, so we can test with a dev domain from client side
[ValidateAngularAntiForgeryToken]
public async Task<JObject> GetRemoteDashboardContent(string section, string baseUrl = "https://dashboard.umbraco.org/")
{
var context = UmbracoContext.Current;
if (context == null)
throw new HttpResponseException(HttpStatusCode.InternalServerError);
var user = Security.CurrentUser;
var userType = user.UserType.Alias;
var allowedSections = string.Join(",", user.AllowedSections);
var language = user.Language;
var version = UmbracoVersion.GetSemanticVersion().ToSemanticString();
var url = string.Format(baseUrl + "{0}?section={0}&type={1}&allowed={2}&lang={3}&version={4}", section, userType, allowedSections, language, version);
var key = "umbraco-dynamic-dashboard-" + userType + language + allowedSections.Replace(",", "-") + section;
var content = ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<JObject>(key);
var result = new JObject();
if (content != null)
{
result = content;
}
else
{
//content is null, go get it
try
{
using (var web = new HttpClient())
{
//fetch dashboard json and parse to JObject
var json = await web.GetStringAsync(url);
content = JObject.Parse(json);
result = content;
}
ApplicationContext.ApplicationCache.RuntimeCache.InsertCacheItem<JObject>(key, () => result, new TimeSpan(0, 30, 0));
}
catch (HttpRequestException ex)
{
LogHelper.Debug<DashboardController>(string.Format("Error getting dashboard content from '{0}': {1}\n{2}", url, ex.Message, ex.InnerException));
//it's still new JObject() - we return it like this to avoid error codes which triggers UI warnings
ApplicationContext.ApplicationCache.RuntimeCache.InsertCacheItem<JObject>(key, () => result, new TimeSpan(0, 5, 0));
}
}
return result;
}
public async Task<HttpResponseMessage> GetRemoteDashboardCss(string section, string baseUrl = "https://dashboard.umbraco.org/")
{
var url = string.Format(baseUrl + "css/dashboard.css?section={0}", section);
var key = "umbraco-dynamic-dashboard-css-" + section;
var content = ApplicationContext.ApplicationCache.RuntimeCache.GetCacheItem<string>(key);
var result = string.Empty;
if (content != null)
{
result = content;
}
else
{
//content is null, go get it
try
{
using (var web = new HttpClient())
{
//fetch remote css
content = await web.GetStringAsync(url);
//can't use content directly, modified closure problem
result = content;
//save server content for 30 mins
ApplicationContext.ApplicationCache.RuntimeCache.InsertCacheItem<string>(key, () => result, new TimeSpan(0, 30, 0));
}
}
catch (HttpRequestException ex)
{
LogHelper.Debug<DashboardController>(string.Format("Error getting dashboard CSS from '{0}': {1}\n{2}", url, ex.Message, ex.InnerException));
//it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings
ApplicationContext.ApplicationCache.RuntimeCache.InsertCacheItem<string>(key, () => result, new TimeSpan(0, 5, 0));
}
}
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(result, Encoding.UTF8, "text/css")
};
}
[ValidateAngularAntiForgeryToken]
public IEnumerable<Tab<DashboardControl>> GetDashboard(string section)
{
var tabs = new List<Tab<DashboardControl>>();
@@ -23,50 +132,47 @@ namespace Umbraco.Web.Editors
foreach( var dashboardSection in UmbracoConfig.For.DashboardSettings().Sections.Where(x => x.Areas.Contains(section)))
{
//we need to validate access to this section
if (DashboardSecurity.AuthorizeAccess(dashboardSection, Security.CurrentUser, Services.SectionService))
if (DashboardSecurity.AuthorizeAccess(dashboardSection, Security.CurrentUser, Services.SectionService) == false)
continue;
//User is authorized
foreach (var tab in dashboardSection.Tabs)
{
//User is authorized
foreach (var dashTab in dashboardSection.Tabs)
//we need to validate access to this tab
if (DashboardSecurity.AuthorizeAccess(tab, Security.CurrentUser, Services.SectionService) == false)
continue;
var dashboardControls = new List<DashboardControl>();
foreach (var control in tab.Controls)
{
//we need to validate access to this tab
if (DashboardSecurity.AuthorizeAccess(dashTab, Security.CurrentUser, Services.SectionService))
{
var props = new List<DashboardControl>();
if (DashboardSecurity.AuthorizeAccess(control, Security.CurrentUser, Services.SectionService) == false)
continue;
foreach (var dashCtrl in dashTab.Controls)
{
if (DashboardSecurity.AuthorizeAccess(dashCtrl, Security.CurrentUser,
Services.SectionService))
{
var ctrl = new DashboardControl();
var controlPath = dashCtrl.ControlPath.Trim(' ', '\r', '\n');
ctrl.Path = IOHelper.FindFile(controlPath);
if (controlPath.ToLower().EndsWith(".ascx"))
{
ctrl.ServerSide = true;
}
props.Add(ctrl);
}
}
var dashboardControl = new DashboardControl();
var controlPath = control.ControlPath.Trim();
dashboardControl.Path = IOHelper.FindFile(controlPath);
if (controlPath.ToLowerInvariant().EndsWith(".ascx".ToLowerInvariant()))
dashboardControl.ServerSide = true;
tabs.Add(new Tab<DashboardControl>
{
Id = i,
Alias = dashTab.Caption.ToSafeAlias(),
IsActive = i == 1,
Label = dashTab.Caption,
Properties = props
});
i++;
}
dashboardControls.Add(dashboardControl);
}
tabs.Add(new Tab<DashboardControl>
{
Id = i,
Alias = tab.Caption.ToSafeAlias(),
IsActive = i == 1,
Label = tab.Caption,
Properties = dashboardControls
});
i++;
}
}
//In case there are no tabs or a user doesn't have access the empty tabs list is returned
return tabs;
}
}
}
+12 -12
View File
@@ -65,7 +65,7 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Gets an empty content item for the
/// Gets an empty content item for the
/// </summary>
/// <param name="contentTypeAlias"></param>
/// <param name="parentId"></param>
@@ -213,7 +213,7 @@ namespace Umbraco.Web.Editors
/// Moves an item to the recycle bin, if it is already there then it will permanently delete it
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <returns></returns>
[EnsureUserPermissionForMedia("id")]
[HttpPost]
public HttpResponseMessage DeleteById(int id)
@@ -231,7 +231,7 @@ namespace Umbraco.Web.Editors
var moveResult = Services.MediaService.WithResult().MoveToRecycleBin(foundMedia, (int)Security.CurrentUser.Id);
if (moveResult == false)
{
//returning an object of INotificationModel will ensure that any pending
//returning an object of INotificationModel will ensure that any pending
// notification messages are added to the response.
return Request.CreateValidationErrorResponse(new SimpleNotificationModel());
}
@@ -241,7 +241,7 @@ namespace Umbraco.Web.Editors
var deleteResult = Services.MediaService.WithResult().Delete(foundMedia, (int)Security.CurrentUser.Id);
if (deleteResult == false)
{
//returning an object of INotificationModel will ensure that any pending
//returning an object of INotificationModel will ensure that any pending
// notification messages are added to the response.
return Request.CreateValidationErrorResponse(new SimpleNotificationModel());
}
@@ -270,7 +270,7 @@ namespace Umbraco.Web.Editors
/// <summary>
/// Saves content
/// </summary>
/// <returns></returns>
/// <returns></returns>
[FileUploadCleanupFilter]
[MediaPostValidate]
public MediaItemDisplay PostSave(
@@ -290,7 +290,7 @@ namespace Umbraco.Web.Editors
// * We still need to save the entity even if there are validation value errors
// * Depending on if the entity is new, and if there are non property validation errors (i.e. the name is null)
// then we cannot continue saving, we can only display errors
// * If there are validation errors and they were attempting to publish, we can only save, NOT publish and display
// * If there are validation errors and they were attempting to publish, we can only save, NOT publish and display
// a message indicating this
if (ModelState.IsValid == false)
{
@@ -314,7 +314,7 @@ namespace Umbraco.Web.Editors
//lasty, if it is not valid, add the modelstate to the outgoing object and throw a 403
HandleInvalidModelState(display);
//put the correct msgs in
//put the correct msgs in
switch (contentItem.Action)
{
case ContentSaveAction.Save:
@@ -461,7 +461,7 @@ namespace Umbraco.Web.Editors
Services.MediaService, parentId) == false)
{
return Request.CreateResponse(
HttpStatusCode.Unauthorized,
HttpStatusCode.Forbidden,
new SimpleNotificationModel(new Notification(
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
Services.TextService.Localize("speechBubbles/invalidUserPermissionsText"),
@@ -534,7 +534,7 @@ namespace Umbraco.Web.Editors
if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.Contains(ext))
mediaType = Constants.Conventions.MediaTypes.Image;
//TODO: make the media item name "nice" since file names could be pretty ugly, we have
//TODO: make the media item name "nice" since file names could be pretty ugly, we have
// string extensions to do much of this but we'll need:
// * Pascalcase the name (use string extensions)
// * strip the file extension
@@ -595,7 +595,7 @@ namespace Umbraco.Web.Editors
return Request.CreateResponse(HttpStatusCode.OK, tempFiles);
}
/// <summary>
/// Ensures the item can be moved/copied to the new location
/// </summary>
@@ -654,7 +654,7 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Performs a permissions check for the user to check if it has access to the node based on
/// Performs a permissions check for the user to check if it has access to the node based on
/// start node and/or permissions for the node
/// </summary>
/// <param name="storage">The storage to add the content item to so it can be reused</param>
@@ -668,7 +668,7 @@ namespace Umbraco.Web.Editors
if (media == null && nodeId != Constants.System.Root && nodeId != Constants.System.RecycleBinMedia)
{
media = mediaService.GetById(nodeId);
//put the content item into storage so it can be retreived
//put the content item into storage so it can be retreived
// in the controller (saves a lookup)
storage[typeof(IMedia).ToString()] = media;
}
@@ -2,31 +2,22 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Linq;
using umbraco;
using Umbraco.Core.Auditing;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.packager;
using umbraco.cms.businesslogic.packager.repositories;
using umbraco.cms.businesslogic.web;
using umbraco.cms.presentation.Trees;
using umbraco.presentation.developer.packages;
using umbraco.webservices;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Packaging.Models;
using Umbraco.Core.Services;
using Umbraco.Web.Models;
using Umbraco.Web.Models.ContentEditing;
@@ -36,7 +27,6 @@ using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
using File = System.IO.File;
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
using Settings = umbraco.cms.businesslogic.packager.Settings;
using Version = System.Version;
namespace Umbraco.Web.Editors
@@ -212,6 +202,9 @@ namespace Umbraco.Web.Editors
var file = IOHelper.FindFile(item);
if (file != null)
{
if (file.StartsWith("/") == false)
file = string.Format("/{0}", file);
var filePath = IOHelper.MapPath(file);
if (File.Exists(filePath))
{
@@ -6,6 +6,7 @@ using System.Net;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Services;
@@ -63,7 +64,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
var url = HealthCheckContext.HttpContext.Request.Url;
// Access the site home page and check for the click-jack protection header or meta tag
var address = string.Format("http://{0}:{1}", url.Host.ToLower(), url.Port);
var useSsl = GlobalSettings.UseSSL || HealthCheckContext.HttpContext.Request.ServerVariables["SERVER_PORT"] == "443";
var address = string.Format("http{0}://{1}:{2}", useSsl ? "s" : "", url.Host.ToLower(), url.Port);
var request = WebRequest.Create(address);
request.Method = "GET";
try
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core.Services;
namespace Umbraco.Web.HealthCheck.Checks.Security
@@ -45,10 +46,11 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
{
var message = string.Empty;
var success = false;
var url = HealthCheckContext.HttpContext.Request.Url;
// Access the site home page and check for the headers
var address = string.Format("http://{0}:{1}", url.Host.ToLower(), url.Port);
var url = HealthCheckContext.HttpContext.Request.Url;
// Access the site home page and check for the headers
var useSsl = GlobalSettings.UseSSL || HealthCheckContext.HttpContext.Request.ServerVariables["SERVER_PORT"] == "443";
var address = string.Format("http{0}://{1}:{2}", useSsl ? "s" : "", url.Host.ToLower(), url.Port);
var request = WebRequest.Create(address);
request.Method = "HEAD";
try
@@ -84,6 +84,9 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
var actions = new List<HealthCheckAction>();
if (success)
message = _textService.Localize("healthcheck/httpsCheckValidCertificate");
return
new HealthCheckStatus(message)
{
+5 -1
View File
@@ -6,6 +6,10 @@
Top,
Right,
Bottom,
Left
Left,
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
}
+3 -1
View File
@@ -5,6 +5,8 @@ namespace Umbraco.Web.Models
Crop,
Max,
Stretch,
Pad
Pad,
BoxPad,
Min
}
}
@@ -37,7 +37,7 @@ namespace Umbraco.Web.Models.Mapping
//FROM MembershipUser TO IMember - used when using a non-umbraco membership provider
config.CreateMap<MembershipUser, IMember>()
.ConstructUsing(user => MemberService.CreateGenericMembershipProviderMember(user.UserName, user.Email, user.UserName, ""))
//we're giving this entity an ID - we cannot really map it but it needs an id so the system knows it's not a new entity
//we're giving this entity an ID of 0 - we cannot really map it but it needs an id so the system knows it's not a new entity
.ForMember(member => member.Id, expression => expression.MapFrom(user => int.MaxValue))
.ForMember(member => member.Comments, expression => expression.MapFrom(user => user.Comment))
.ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate))
@@ -118,7 +118,7 @@ namespace Umbraco.Web.Models.Mapping
//FROM MembershipUser TO MemberBasic
config.CreateMap<MembershipUser, MemberBasic>()
//we're giving this entity an ID - we cannot really map it but it needs an id so the system knows it's not a new entity
//we're giving this entity an ID of 0 - we cannot really map it but it needs an id so the system knows it's not a new entity
.ForMember(member => member.Id, expression => expression.MapFrom(user => int.MaxValue))
.ForMember(member => member.CreateDate, expression => expression.MapFrom(user => user.CreationDate))
.ForMember(member => member.UpdateDate, expression => expression.MapFrom(user => user.LastActivityDate))
@@ -183,7 +183,7 @@ namespace Umbraco.Web.Models.Mapping
var url = urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(display.Key.ToString("N"), null));
display.TreeNodeUrl = url;
}
var genericProperties = new List<ContentPropertyDisplay>
{
new ContentPropertyDisplay
@@ -234,7 +234,7 @@ namespace Umbraco.Web.Models.Mapping
TabsAndPropertiesResolver.MapGenericProperties(member, display, localizedText, genericProperties);
//check if there's an approval field
var provider = membersProvider as global::umbraco.providers.members.UmbracoMembershipProvider;
if (member.HasIdentity == false && provider != null)
@@ -258,7 +258,7 @@ namespace Umbraco.Web.Models.Mapping
/// <returns></returns>
/// <remarks>
/// If the membership provider installed is the umbraco membership provider, then we will allow changing the username, however if
/// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively
/// the membership provider is a custom one, we cannot allow chaning the username because MembershipProvider's do not actually natively
/// allow that.
/// </remarks>
internal static ContentPropertyDisplay GetLoginProperty(IMemberService memberService, IMember member, MemberDisplay display, ILocalizedTextService localizedText)
@@ -267,11 +267,11 @@ namespace Umbraco.Web.Models.Mapping
{
Alias = string.Format("{0}login", Constants.PropertyEditors.InternalGenericPropertiesPrefix),
Label = localizedText.Localize("login"),
Value = display.Username
Value = display.Username
};
var scenario = memberService.GetMembershipScenario();
//only allow editing if this is a new member, or if the membership provider is the umbraco one
if (member.HasIdentity == false || scenario == MembershipScenario.NativeUmbraco)
{
@@ -287,20 +287,21 @@ namespace Umbraco.Web.Models.Mapping
internal static IDictionary<string, bool> GetMemberGroupValue(string username)
{
var result = new Dictionary<string, bool>();
foreach (var role in Roles.GetAllRoles().Distinct())
{
var userRoles = username.IsNullOrWhiteSpace() ? null : Roles.GetRolesForUser(username);
// create a dictionary of all roles (except internal roles) + "false"
var result = Roles.GetAllRoles().Distinct()
// if a role starts with __umbracoRole we won't show it as it's an internal role used for public access
if (role.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false)
{
result.Add(role, false);
if (username.IsNullOrWhiteSpace()) continue;
if (Roles.IsUserInRole(username, role))
{
result[role] = true;
}
}
}
.Where(x => x.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false)
.ToDictionary(x => x, x => false);
// if user has no roles, just return the dictionary
if (userRoles == null) return result;
// else update the dictionary to "true" for the user roles (except internal roles)
foreach (var userRole in userRoles.Where(x => x.StartsWith(Constants.Conventions.Member.InternalRolePrefix) == false))
result[userRole] = true;
return result;
}
@@ -318,7 +319,7 @@ namespace Umbraco.Web.Models.Mapping
//remove all membership properties, these values are set with the membership provider.
var exclude = defaultProps.Select(x => x.Value.Alias).ToArray();
return source.Properties
.Where(x => exclude.Contains(x.Alias) == false)
.Select(Mapper.Map<Property, ContentPropertyDto>);
@@ -331,7 +332,7 @@ namespace Umbraco.Web.Models.Mapping
/// </summary>
/// <remarks>
/// This also ensures that the IsLocked out property is readonly when the member is not locked out - this is because
/// an admin cannot actually set isLockedOut = true, they can only unlock.
/// an admin cannot actually set isLockedOut = true, they can only unlock.
/// </remarks>
internal class MemberTabsAndPropertiesResolver : TabsAndPropertiesResolver
{
@@ -370,7 +371,7 @@ namespace Umbraco.Web.Models.Mapping
isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
}
return result;
return result;
}
else
{
@@ -386,10 +387,10 @@ namespace Umbraco.Web.Models.Mapping
isLockedOutProperty.Value = _localizedTextService.Localize("general/no");
}
return result;
return result;
}
}
}
@@ -433,7 +434,7 @@ namespace Umbraco.Web.Models.Mapping
{Constants.Conventions.Member.IsLockedOut, Constants.Conventions.Member.IsLockedOut},
{Constants.Conventions.Member.IsApproved, Constants.Conventions.Member.IsApproved},
{Constants.Conventions.Member.Comments, Constants.Conventions.Member.Comments}
};
};
}
else
{
@@ -444,12 +445,12 @@ namespace Umbraco.Web.Models.Mapping
{Constants.Conventions.Member.IsLockedOut, umbracoProvider.LockPropertyTypeAlias},
{Constants.Conventions.Member.IsApproved, umbracoProvider.ApprovedPropertyTypeAlias},
{Constants.Conventions.Member.Comments, umbracoProvider.CommentPropertyTypeAlias}
};
};
}
}
}
}
}
}
@@ -0,0 +1,14 @@
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors.ParameterEditors
{
[ParameterEditor(Constants.PropertyEditors.MultiNodeTreePickerAlias, "Multiple Content Picker", "contentpicker")]
public class MultipleContentPickerParameterEditor : ParameterEditor
{
public MultipleContentPickerParameterEditor()
{
Configuration.Add("multiPicker", "1");
}
}
}
@@ -8,7 +8,16 @@ namespace Umbraco.Web.Security.Identity
{
public static class AuthenticationOptionsExtensions
{
/// <summary>
/// When trying to implement an Azure AD B2C provider or other OAuth provider that requires a customized Challenge Result in order to work then
/// this must be used.
/// </summary>
/// <param name="authOptions"></param>
/// <param name="authProperties"></param>
/// <remarks>
/// See: http://issues.umbraco.org/issue/U4-7353
/// </remarks>
public static void SetSignInChallengeResultCallback(
this AuthenticationOptions authOptions,
Func<IOwinContext, AuthenticationProperties> authProperties)
@@ -1,36 +0,0 @@
using System;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Services;
using umbraco.interfaces;
using Umbraco.Core.Configuration;
namespace Umbraco.Web.Strategies.Migrations
{
/// <summary>
/// This will execute after upgrading to rebuild the xml cache
/// </summary>
/// <remarks>
/// This cannot execute as part of a db migration since we need access to the services/repos.
///
/// This will execute for specific versions -
///
/// * If current is less than or equal to 7.0.0
/// </remarks>
public class RebuildMediaXmlCacheAfterUpgrade : MigrationStartupHander
{
protected override void AfterMigration(MigrationRunner sender, MigrationEventArgs e)
{
if (e.ProductName != GlobalSettings.UmbracoMigrationName) return;
var target70 = new Version(7, 0, 0);
if (e.ConfiguredVersion <= target70)
{
var mediasvc = (MediaService)ApplicationContext.Current.Services.MediaService;
mediasvc.RebuildXmlStructures();
}
}
}
}
@@ -0,0 +1,52 @@
using System;
using umbraco;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Services;
using GlobalSettings = Umbraco.Core.Configuration.GlobalSettings;
namespace Umbraco.Web.Strategies.Migrations
{
/// <summary>
/// Rebuilds the Xml caches after upgrading.
/// This will execute after upgrading to rebuild the xml cache
/// </summary>
/// <remarks>
/// <para>This cannot execute as part of a DB migration since it needs access to services and repositories.</para>
/// <para>Executes for:
/// - Media Xml : if current is less than, or equal to, 7.0.0 (superceeded by the next rule)
/// - Media & Content Xml : if current is less than, or equal to, 7.3.0 - because 7.3.0 adds .Key to cached items
/// </para>
/// </remarks>
public class RebuildXmlCachesAfterUpgrade : MigrationStartupHander
{
protected override void AfterMigration(MigrationRunner sender, MigrationEventArgs e)
{
if (e.ProductName != GlobalSettings.UmbracoMigrationName) return;
var v730 = new Semver.SemVersion(new Version(7, 3, 0));
var doMedia = e.ConfiguredSemVersion < v730;
var doContent = e.ConfiguredSemVersion < v730;
if (doMedia)
{
var mediaService = (MediaService) ApplicationContext.Current.Services.MediaService;
mediaService.RebuildXmlStructures();
// note: not re-indexing medias?
}
if (doContent)
{
// rebuild Xml in database
var contentService = (ContentService) ApplicationContext.Current.Services.ContentService;
contentService.RebuildXmlStructures();
// refresh the Xml cache
content.Instance.RefreshContentFromDatabase();
}
}
}
}
+9 -9
View File
@@ -97,14 +97,12 @@
<Project>{07fbc26b-2927-4a22-8d96-d644c667fecc}</Project>
<Name>UmbracoExamine</Name>
</ProjectReference>
<Reference Include="AutoMapper, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
<SpecificVersion>False</SpecificVersion>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.9.1.0, Culture=neutral, processorArchitecture=MSIL">
@@ -118,8 +116,8 @@
<Reference Include="dotless.Core">
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.69.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.69.0\lib\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
@@ -389,6 +387,7 @@
<Compile Include="PropertyEditors\DatePreValueEditor.cs" />
<Compile Include="PropertyEditors\DateTimePreValueEditor.cs" />
<Compile Include="PropertyEditors\DecimalPropertyEditor.cs" />
<Compile Include="PropertyEditors\ParameterEditors\MultipleContentPickerParameterEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\ImageCropDataSetConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\ImageCropperValueConverter.cs" />
<Compile Include="Routing\RedirectTrackingEventHandler.cs" />
@@ -916,7 +915,7 @@
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="UI\JavaScript\ServerVariablesParser.cs" />
<Compile Include="Strategies\Migrations\RebuildMediaXmlCacheAfterUpgrade.cs" />
<Compile Include="Strategies\Migrations\RebuildXmlCachesAfterUpgrade.cs" />
<Compile Include="Strategies\PublicAccessEventHandler.cs" />
<Compile Include="UI\Bundles\JsApplicationLib.cs" />
<Compile Include="UI\Bundles\JsJQueryCore.cs" />
@@ -2265,4 +2264,5 @@
<!--<PostBuildEvent>xcopy "$(ProjectDir)..\..\lib\*.dll" "$(TargetDir)*.dll" /Y</PostBuildEvent>-->
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
</Project>
+2 -2
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="ClientDependency" version="1.9.1" targetFramework="net45" />
<package id="dotless" version="1.4.1.0" targetFramework="net45" />
<package id="Examine" version="0.1.69.0" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Markdown" version="1.14.7" targetFramework="net45" />
+2 -2
View File
@@ -82,8 +82,8 @@
<AssemblyOriginatorKeyFile>..\Solution Items\TheFARM-Public.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Examine, Version=0.1.69.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.69.0\lib\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Examine" version="0.1.69.0" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
</packages>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Examine" version="0.1.69.0" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />

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