Port 7.7 - WIP
This commit is contained in:
@@ -70,6 +70,7 @@ src/Umbraco.Web.UI/[Ww]eb.config
|
||||
*.transformed
|
||||
|
||||
node_modules
|
||||
lib-bower
|
||||
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Ll]ib/*
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/umbraco.*
|
||||
|
||||
@@ -9,7 +9,7 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
{
|
||||
/// <summary>
|
||||
/// A utility class for working with CDF config and cache files - use sparingly!
|
||||
/// </summary>
|
||||
|
||||
+1
@@ -4,6 +4,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
|
||||
{
|
||||
[Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
[Migration("8.0.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
public class AddIndexToDictionaryKeyColumn : MigrationBase
|
||||
{
|
||||
public AddIndexToDictionaryKeyColumn(IMigrationContext context)
|
||||
|
||||
+203
-20
@@ -1,20 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
|
||||
{
|
||||
[Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
[Migration("8.0.0", 1, Constants.System.UmbracoMigrationName)]
|
||||
public class AddUserGroupTables : MigrationBase
|
||||
{
|
||||
private readonly string _collateSyntax;
|
||||
|
||||
public AddUserGroupTables(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
{
|
||||
//For some of the migration data inserts we require to use a special MSSQL collate expression since
|
||||
//some databases may have a custom collation specified and if that is the case, when we compare strings
|
||||
//in dynamic SQL it will try to compare strings in different collations and this will yield errors.
|
||||
_collateSyntax = SqlSyntax is MySqlSyntaxProvider || SqlSyntax is SqlCeSyntaxProvider
|
||||
? string.Empty
|
||||
: "COLLATE DATABASE_DEFAULT";
|
||||
}
|
||||
|
||||
public override void Up()
|
||||
{
|
||||
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
|
||||
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToList();
|
||||
var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
|
||||
|
||||
//In some very rare cases, there might alraedy be user group tables that we'll need to remove first
|
||||
//but of course we don't want to remove the tables we will be creating below if they already exist so
|
||||
//need to do some checks first since these old rare tables have a different schema
|
||||
RemoveOldTablesIfExist(tables, columns);
|
||||
|
||||
if (AddNewTables(tables))
|
||||
{
|
||||
@@ -23,6 +42,83 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
DeleteOldTables(tables, constraints);
|
||||
SetDefaultIcons();
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we aren't adding the tables, make sure that the umbracoUserGroup table has the correct FKs - these
|
||||
//were added after the beta release so we need to do some cleanup
|
||||
//if the FK doesn't exist
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUserGroup")
|
||||
&& x.Item2.InvariantEquals("startContentId")
|
||||
&& x.Item3.InvariantEquals("FK_startContentId_umbracoNode_id")) == false)
|
||||
{
|
||||
//before we add any foreign key we need to make sure there's no stale data in there which would have happened in the beta
|
||||
//release if a start node was assigned and then that start node was deleted.
|
||||
Execute.Sql(@"UPDATE umbracoUserGroup SET startContentId = NULL WHERE startContentId NOT IN (SELECT id FROM umbracoNode)");
|
||||
|
||||
Create.ForeignKey("FK_startContentId_umbracoNode_id")
|
||||
.FromTable("umbracoUserGroup")
|
||||
.ForeignColumn("startContentId")
|
||||
.ToTable("umbracoNode")
|
||||
.PrimaryColumn("id")
|
||||
.OnDelete(Rule.None)
|
||||
.OnUpdate(Rule.None);
|
||||
}
|
||||
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUserGroup")
|
||||
&& x.Item2.InvariantEquals("startMediaId")
|
||||
&& x.Item3.InvariantEquals("FK_startMediaId_umbracoNode_id")) == false)
|
||||
{
|
||||
//before we add any foreign key we need to make sure there's no stale data in there which would have happened in the beta
|
||||
//release if a start node was assigned and then that start node was deleted.
|
||||
Execute.Sql(@"UPDATE umbracoUserGroup SET startMediaId = NULL WHERE startMediaId NOT IN (SELECT id FROM umbracoNode)");
|
||||
|
||||
Create.ForeignKey("FK_startMediaId_umbracoNode_id")
|
||||
.FromTable("umbracoUserGroup")
|
||||
.ForeignColumn("startMediaId")
|
||||
.ToTable("umbracoNode")
|
||||
.PrimaryColumn("id")
|
||||
.OnDelete(Rule.None)
|
||||
.OnUpdate(Rule.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In some very rare cases, there might alraedy be user group tables that we'll need to remove first
|
||||
/// but of course we don't want to remove the tables we will be creating below if they already exist so
|
||||
/// need to do some checks first since these old rare tables have a different schema
|
||||
/// </summary>
|
||||
/// <param name="tables"></param>
|
||||
/// <param name="columns"></param>
|
||||
private void RemoveOldTablesIfExist(List<string> tables, ColumnInfo[] columns)
|
||||
{
|
||||
if (tables.Contains("umbracoUser2userGroup", StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
//this column doesn't exist in the 7.7 schema, so if it's there, then this is a super old table
|
||||
var foundOldColumn = columns
|
||||
.FirstOrDefault(x =>
|
||||
x.ColumnName.Equals("user", StringComparison.InvariantCultureIgnoreCase)
|
||||
&& x.TableName.Equals("umbracoUser2userGroup", StringComparison.InvariantCultureIgnoreCase));
|
||||
if (foundOldColumn != null)
|
||||
{
|
||||
Delete.Table("umbracoUser2userGroup");
|
||||
//remove from the tables list since this will be re-checked in further logic
|
||||
tables.Remove("umbracoUser2userGroup");
|
||||
}
|
||||
}
|
||||
|
||||
if (tables.Contains("umbracoUserGroup", StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
//The new schema has several columns, the super old one for this table only had 2 so if it's 2 get rid of it
|
||||
var countOfCols = columns
|
||||
.Count(x => x.TableName.Equals("umbracoUserGroup", StringComparison.InvariantCultureIgnoreCase));
|
||||
if (countOfCols == 2)
|
||||
{
|
||||
Delete.Table("umbracoUserGroup");
|
||||
//remove from the tables list since this will be re-checked in further logic
|
||||
tables.Remove("umbracoUserGroup");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDefaultIcons()
|
||||
@@ -33,7 +129,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
Execute.Sql("UPDATE umbracoUserGroup SET icon = \'icon-globe\' WHERE userGroupAlias = \'translator\'");
|
||||
}
|
||||
|
||||
private bool AddNewTables(string[] tables)
|
||||
private bool AddNewTables(List<string> tables)
|
||||
{
|
||||
var updated = false;
|
||||
if (tables.InvariantContains("umbracoUserGroup") == false)
|
||||
@@ -71,13 +167,15 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
FROM umbracoUserType");
|
||||
|
||||
// Add each user to the group created from their type
|
||||
Execute.Sql(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
|
||||
SELECT u.id, ug.id
|
||||
FROM umbracoUser u
|
||||
INNER JOIN umbracoUserType ut ON ut.id = u.userType
|
||||
INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias = ut.userTypeAlias");
|
||||
INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias {0} = ut.userTypeAlias {0}", _collateSyntax));
|
||||
|
||||
// Add the built-in administrator account to all apps
|
||||
// this will lookup all of the apps that the admin currently has access to in order to assign the sections
|
||||
// instead of use statically assigning since there could be extra sections we don't know about.
|
||||
Execute.Sql(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
|
||||
SELECT ug.id, app
|
||||
FROM umbracoUserGroup ug
|
||||
@@ -86,6 +184,89 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
|
||||
WHERE u.id = 0");
|
||||
|
||||
// Add the default section access to the other built-in accounts
|
||||
// writer:
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
|
||||
SELECT ug.id, 'content' as app
|
||||
FROM umbracoUserGroup ug
|
||||
WHERE ug.userGroupAlias {0} = 'writer' {0}", _collateSyntax));
|
||||
// editor
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
|
||||
SELECT ug.id, 'content' as app
|
||||
FROM umbracoUserGroup ug
|
||||
WHERE ug.userGroupAlias {0} = 'editor' {0}", _collateSyntax));
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
|
||||
SELECT ug.id, 'media' as app
|
||||
FROM umbracoUserGroup ug
|
||||
WHERE ug.userGroupAlias {0} = 'editor' {0}", _collateSyntax));
|
||||
// translator
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
|
||||
SELECT ug.id, 'translation' as app
|
||||
FROM umbracoUserGroup ug
|
||||
WHERE ug.userGroupAlias {0} = 'translator' {0}", _collateSyntax));
|
||||
|
||||
//We need to lookup all distinct combinations of section access and create a group for each distinct collection
|
||||
//and assign groups accordingly. We'll perform the lookup 'now' to then create the queued SQL migrations.
|
||||
var userAppsData = Context.Database.Query<dynamic>(@"SELECT u.id, u2a.app FROM umbracoUser u
|
||||
INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
|
||||
ORDER BY u.id, u2a.app");
|
||||
var usersWithApps = new Dictionary<int, List<string>>();
|
||||
foreach (var userApps in userAppsData)
|
||||
{
|
||||
List<string> apps;
|
||||
if (usersWithApps.TryGetValue(userApps.id, out apps) == false)
|
||||
{
|
||||
apps = new List<string> {userApps.app};
|
||||
usersWithApps.Add(userApps.id, apps);
|
||||
}
|
||||
else
|
||||
{
|
||||
apps.Add(userApps.app);
|
||||
}
|
||||
}
|
||||
//At this stage we have a dictionary of users with a collection of their apps which are sorted
|
||||
//and we need to determine the unique/distinct app collections for each user to create groups with.
|
||||
//We can do this by creating a hash value of all of the app values and since they are already sorted we can get a distinct
|
||||
//collection by this hash.
|
||||
var distinctApps = usersWithApps
|
||||
.Select(x => new {appCollection = x.Value, appsHash = string.Join("", x.Value).GenerateHash()})
|
||||
.DistinctBy(x => x.appsHash)
|
||||
.ToArray();
|
||||
//Now we need to create user groups for each of these distinct app collections, and then assign the corresponding users to those groups
|
||||
for (var i = 0; i < distinctApps.Length; i++)
|
||||
{
|
||||
//create the group
|
||||
var alias = "MigratedSectionAccessGroup_" + (i + 1);
|
||||
Insert.IntoTable("umbracoUserGroup").Row(new
|
||||
{
|
||||
userGroupAlias = "MigratedSectionAccessGroup_" + (i + 1),
|
||||
userGroupName = "Migrated Section Access Group " + (i + 1)
|
||||
});
|
||||
//now assign the apps
|
||||
var distinctApp = distinctApps[i];
|
||||
foreach (var app in distinctApp.appCollection)
|
||||
{
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId, app)
|
||||
SELECT ug.id, '" + app + @"' as app
|
||||
FROM umbracoUserGroup ug
|
||||
WHERE ug.userGroupAlias {0} = '" + alias + "' {0}", _collateSyntax));
|
||||
}
|
||||
//now assign the corresponding users to this group
|
||||
foreach (var userWithApps in usersWithApps)
|
||||
{
|
||||
//check if this user's groups hash matches the current groups hash
|
||||
var hash = string.Join("", userWithApps.Value).GenerateHash();
|
||||
if (hash == distinctApp.appsHash)
|
||||
{
|
||||
//it matches so assign the user to this group
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
|
||||
SELECT " + userWithApps.Key + @", ug.id
|
||||
FROM umbracoUserGroup ug
|
||||
WHERE ug.userGroupAlias {0} = '" + alias + "' {0}", _collateSyntax));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename some groups for consistency (plural form)
|
||||
Execute.Sql("UPDATE umbracoUserGroup SET userGroupName = 'Writers' WHERE userGroupAlias = 'writer'");
|
||||
Execute.Sql("UPDATE umbracoUserGroup SET userGroupName = 'Translators' WHERE userGroupAlias = 'translator'");
|
||||
@@ -105,49 +286,46 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
{
|
||||
// Create user group records for all non-admin users that have specific permissions set
|
||||
Execute.Sql(@"INSERT INTO umbracoUserGroup(userGroupAlias, userGroupName)
|
||||
SELECT userName + 'Group', 'Group for ' + userName
|
||||
SELECT 'permissionGroupFor' + userLogin, 'Migrated Permission Group for ' + userLogin
|
||||
FROM umbracoUser
|
||||
WHERE (id IN (
|
||||
SELECT " + SqlSyntax.GetQuotedColumnName("user") + @"
|
||||
FROM umbracoUser2app
|
||||
) OR id IN (
|
||||
SELECT userid
|
||||
FROM umbracoUser2NodePermission
|
||||
))
|
||||
AND id > 0");
|
||||
|
||||
// Associate those groups with the users
|
||||
Execute.Sql(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUser2UserGroup (userId, userGroupId)
|
||||
SELECT u.id, ug.id
|
||||
FROM umbracoUser u
|
||||
INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias = userName + 'Group'");
|
||||
INNER JOIN umbracoUserGroup ug ON ug.userGroupAlias {0} = 'permissionGroupFor' + userLogin {0}", _collateSyntax));
|
||||
|
||||
// Create node permissions on the groups
|
||||
Execute.Sql(@"INSERT INTO umbracoUserGroup2NodePermission (userGroupId,nodeId,permission)
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2NodePermission (userGroupId,nodeId,permission)
|
||||
SELECT ug.id, nodeId, permission
|
||||
FROM umbracoUserGroup ug
|
||||
INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
|
||||
INNER JOIN umbracoUser u ON u.id = u2ug.userId
|
||||
INNER JOIN umbracoUser2NodePermission u2np ON u2np.userId = u.id
|
||||
WHERE ug.userGroupAlias NOT IN (
|
||||
SELECT userTypeAlias
|
||||
WHERE ug.userGroupAlias {0} NOT IN (
|
||||
SELECT userTypeAlias {0}
|
||||
FROM umbracoUserType
|
||||
)");
|
||||
)", _collateSyntax));
|
||||
|
||||
// Create app permissions on the groups
|
||||
Execute.Sql(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
|
||||
Execute.Sql(string.Format(@"INSERT INTO umbracoUserGroup2app (userGroupId,app)
|
||||
SELECT ug.id, app
|
||||
FROM umbracoUserGroup ug
|
||||
INNER JOIN umbracoUser2UserGroup u2ug ON u2ug.userGroupId = ug.id
|
||||
INNER JOIN umbracoUser u ON u.id = u2ug.userId
|
||||
INNER JOIN umbracoUser2app u2a ON u2a." + SqlSyntax.GetQuotedColumnName("user") + @" = u.id
|
||||
WHERE ug.userGroupAlias NOT IN (
|
||||
SELECT userTypeAlias
|
||||
WHERE ug.userGroupAlias {0} NOT IN (
|
||||
SELECT userTypeAlias {0}
|
||||
FROM umbracoUserType
|
||||
)");
|
||||
)", _collateSyntax));
|
||||
}
|
||||
|
||||
private void DeleteOldTables(string[] tables, Tuple<string, string, string>[] constraints)
|
||||
private void DeleteOldTables(List<string> tables, Tuple<string, string, string>[] constraints)
|
||||
{
|
||||
if (tables.InvariantContains("umbracoUser2App"))
|
||||
{
|
||||
@@ -165,6 +343,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
{
|
||||
Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser");
|
||||
}
|
||||
//This is the super old constraint name of the FK for user type so check this one too
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
|
||||
{
|
||||
Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser");
|
||||
}
|
||||
|
||||
Delete.Column("userType").FromTable("umbracoUser");
|
||||
Delete.Table("umbracoUserType");
|
||||
|
||||
+1
@@ -3,6 +3,7 @@ using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
|
||||
{
|
||||
[Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
[Migration("8.0.0", 2, Constants.System.UmbracoMigrationName)]
|
||||
public class AddUserStartNodeTable : MigrationBase
|
||||
{
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
/// <summary>
|
||||
/// Ensures the built-in user groups have the blueprint permission by default on upgrade
|
||||
/// </summary>
|
||||
[Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
[Migration("8.0.0", 6, Constants.System.UmbracoMigrationName)]
|
||||
public class EnsureContentTemplatePermissions : MigrationBase
|
||||
{
|
||||
|
||||
+1
@@ -3,6 +3,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
|
||||
{
|
||||
[Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
[Migration("8.0.0", 4, Constants.System.UmbracoMigrationName)]
|
||||
public class ReduceDictionaryKeyColumnsSize : MigrationBase
|
||||
{
|
||||
|
||||
+4
@@ -6,6 +6,7 @@ using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
|
||||
{
|
||||
[Migration("7.7.0", 5, Constants.System.UmbracoMigrationName)]
|
||||
[Migration("8.0.0", 0, Constants.System.UmbracoMigrationName)]
|
||||
public class UpdateUserTables : MigrationBase
|
||||
{
|
||||
@@ -30,6 +31,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("invitedDate")) == false)
|
||||
Create.Column("invitedDate").OnTable("umbracoUser").AsDateTime().Nullable();
|
||||
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("avatar")) == false)
|
||||
Create.Column("avatar").OnTable("umbracoUser").AsString(500).Nullable();
|
||||
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("umbracoUser") && x.ColumnName.InvariantEquals("passwordConfig")) == false)
|
||||
{
|
||||
Create.Column("passwordConfig").OnTable("umbracoUser").AsString(500).Nullable();
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
_publishedQuery = work.Query<IContent>().Where(x => x.Published); // fixme not used?
|
||||
|
||||
_contentByGuidReadRepository = new ContentByGuidReadRepository(this, work, cacheHelper, logger, syntaxProvider);
|
||||
_contentByGuidReadRepository = new ContentByGuidReadRepository(this, work, cacheHelper, logger);
|
||||
EnsureUniqueNaming = settings.EnsureUniqueNaming;
|
||||
}
|
||||
|
||||
@@ -760,21 +760,19 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return content.HasPublishedVersion;
|
||||
|
||||
var syntaxUmbracoNode = SqlSyntax.GetQuotedTableName("umbracoNode");
|
||||
var syntaxPath = SqlSyntax.GetQuotedColumnName("path");
|
||||
var syntaxConcat = SqlSyntax.GetConcat(syntaxUmbracoNode + "." + syntaxPath, "',%'");
|
||||
var ids = content.Path.Split(',').Skip(1).Select(int.Parse);
|
||||
|
||||
var sql = string.Format(@"SELECT COUNT({0}.{1})
|
||||
FROM {0}
|
||||
JOIN {2} ON ({0}.{1}={2}.{3} AND {2}.{4}=@published)
|
||||
WHERE (@path LIKE {5})",
|
||||
WHERE {0}.{1} IN (@ids)",
|
||||
syntaxUmbracoNode,
|
||||
SqlSyntax.GetQuotedColumnName("id"),
|
||||
SqlSyntax.GetQuotedTableName("cmsDocument"),
|
||||
SqlSyntax.GetQuotedColumnName("nodeId"),
|
||||
SqlSyntax.GetQuotedColumnName("published"),
|
||||
syntaxConcat);
|
||||
SqlSyntax.GetQuotedColumnName("published"));
|
||||
|
||||
var count = Database.ExecuteScalar<int>(sql, new { @published=true, @path=content.Path });
|
||||
var count = Database.ExecuteScalar<int>(sql, new { published=true, ids });
|
||||
count += 1; // because content does not count
|
||||
return count == content.Level;
|
||||
}
|
||||
@@ -810,54 +808,51 @@ WHERE (@path LIKE {5})",
|
||||
/// TODO: This is ugly and to fix we need to decouple the IRepositoryQueryable -> IRepository -> IReadRepository which should all be separate things!
|
||||
/// Then we can do the same thing with repository instances and we wouldn't need to leave all these methods as not implemented because we wouldn't need to implement them
|
||||
/// </remarks>
|
||||
private class ContentByGuidReadRepository : PetaPocoRepositoryBase<Guid, IContent>
|
||||
private class ContentByGuidReadRepository : NPocoRepositoryBase<Guid, IContent>
|
||||
{
|
||||
private readonly ContentRepository _outerRepo;
|
||||
|
||||
public ContentByGuidReadRepository(ContentRepository outerRepo,
|
||||
IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
public ContentByGuidReadRepository(ContentRepository outerRepo, IScopeUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_outerRepo = outerRepo;
|
||||
}
|
||||
|
||||
protected override IContent PerformGet(Guid id)
|
||||
{
|
||||
var sql = _outerRepo.GetBaseQuery(BaseQueryType.FullSingle)
|
||||
var sql = _outerRepo.GetBaseQuery(QueryType.Single)
|
||||
.Where(GetBaseWhereClause(), new { Id = id })
|
||||
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
.Where<DocumentDto>(x => x.Newest)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
|
||||
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
var dto = Database.Fetch<DocumentDto>(sql.SelectTop(1)).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = _outerRepo.CreateContentFromDto(dto, sql);
|
||||
var content = _outerRepo.CreateContentFromDto(dto, dto.ContentVersionDto.VersionId);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContent> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
Func<Sql, Sql> translate = s =>
|
||||
Sql<SqlContext> Translate(Sql<SqlContext> s)
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
s.Where("umbracoNode.uniqueID in (@ids)", new { ids });
|
||||
}
|
||||
//we only want the newest ones with this method
|
||||
s.Where<DocumentDto>(x => x.Newest, SqlSyntax);
|
||||
s.Where<DocumentDto>(x => x.Newest);
|
||||
return s;
|
||||
};
|
||||
}
|
||||
|
||||
var sqlBaseFull = _outerRepo.GetBaseQuery(BaseQueryType.FullMultiple);
|
||||
var sqlBaseIds = _outerRepo.GetBaseQuery(BaseQueryType.Ids);
|
||||
|
||||
return _outerRepo.ProcessQuery(translate(sqlBaseFull), new PagingSqlQuery(translate(sqlBaseIds)));
|
||||
var sql = Translate(GetBaseQuery(false));
|
||||
return _outerRepo.MapQueryDtos(Database.Fetch<DocumentDto>(sql), many: true);
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
protected override Sql<SqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
return _outerRepo.GetBaseQuery(isCount);
|
||||
}
|
||||
@@ -867,10 +862,7 @@ WHERE (@path LIKE {5})",
|
||||
return "umbracoNode.uniqueID = @Id";
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return _outerRepo.NodeObjectTypeId; }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => _outerRepo.NodeObjectTypeId;
|
||||
|
||||
#region Not needed to implement
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Umbraco.Core.Models;
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
@@ -22,6 +24,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="xml"></param>
|
||||
void AddOrUpdatePreviewXml(IMedia content, Func<IMedia, XElement> xml);
|
||||
void AddOrUpdatePreviewXml(IMedia content, Func<IMedia, XElement> xml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUser> GetPagedResultsByQuery(IQuery<IUser> query, long pageIndex, int pageSize, out long totalRecords,
|
||||
Expression<Func<IUser, object>> orderBy, Direction orderDirection = Direction.Ascending,
|
||||
string[] userGroups = null, UserState[] userState = null, IQuery<IUser> filter = null);
|
||||
string[] includeUserGroups = null, string[] excludeUserGroups = null, UserState[] userState = null,
|
||||
IQuery<IUser> filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a user by username
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
_mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository));
|
||||
_tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository));
|
||||
_mediaByGuidReadRepository = new MediaByGuidReadRepository(this, work, cache, logger, sqlSyntax);
|
||||
_mediaByGuidReadRepository = new MediaByGuidReadRepository(this, work, cache, logger);
|
||||
EnsureUniqueNaming = contentSection.EnsureUniqueNaming;
|
||||
}
|
||||
|
||||
@@ -441,13 +441,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// TODO: This is ugly and to fix we need to decouple the IRepositoryQueryable -> IRepository -> IReadRepository which should all be separate things!
|
||||
/// Then we can do the same thing with repository instances and we wouldn't need to leave all these methods as not implemented because we wouldn't need to implement them
|
||||
/// </remarks>
|
||||
private class MediaByGuidReadRepository : PetaPocoRepositoryBase<Guid, IMedia>
|
||||
private class MediaByGuidReadRepository : NPocoRepositoryBase<Guid, IMedia>
|
||||
{
|
||||
private readonly MediaRepository _outerRepo;
|
||||
|
||||
public MediaByGuidReadRepository(MediaRepository outerRepo,
|
||||
IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
IScopeUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_outerRepo = outerRepo;
|
||||
}
|
||||
@@ -456,14 +456,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
|
||||
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
|
||||
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
var dto = Database.Fetch<ContentVersionDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
||||
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
var content = _outerRepo.CreateMediaFromDto(dto, sql);
|
||||
var content = _outerRepo.CreateMediaFromDto(dto, dto.VersionId);
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -476,10 +476,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
sql.Where("umbracoNode.uniqueID in (@ids)", new { ids = ids });
|
||||
}
|
||||
|
||||
return _outerRepo.ProcessQuery(sql, new PagingSqlQuery(sql));
|
||||
return _outerRepo.MapQueryDtos(Database.Fetch<ContentVersionDto>(sql));
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
protected override Sql<SqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
return _outerRepo.GetBaseQuery(isCount);
|
||||
}
|
||||
@@ -489,10 +489,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return "umbracoNode.uniqueID = @Id";
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { return _outerRepo.NodeObjectTypeId; }
|
||||
}
|
||||
protected override Guid NodeObjectTypeId => _outerRepo.NodeObjectTypeId;
|
||||
|
||||
#region Not needed to implement
|
||||
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
//swallow this exception, we thought it was json but it really isn't so continue returning a string
|
||||
}
|
||||
}
|
||||
return property.Value.ToString();
|
||||
return asString;
|
||||
case DataTypeDatabaseType.Integer:
|
||||
case DataTypeDatabaseType.Decimal:
|
||||
//Decimals need to be formatted with invariant culture (dots, not commas)
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
|
||||
// fall back on normal behaviour
|
||||
return values.Any() == false
|
||||
? sourceString.Split(Environment.NewLine.ToCharArray())
|
||||
? sourceString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)
|
||||
: values.ToArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@@ -6,6 +7,8 @@ using System.Web.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Identity.Owin;
|
||||
using Microsoft.Owin.Security.DataProtection;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
@@ -23,18 +26,43 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the constructor specifying all dependencies instead")]
|
||||
public BackOfficeUserManager(
|
||||
IUserStore<BackOfficeIdentityUser, int> store,
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
MembershipProviderBase membershipProvider)
|
||||
: this(store, options, membershipProvider, UmbracoConfig.For.UmbracoSettings().Content)
|
||||
{
|
||||
}
|
||||
|
||||
public BackOfficeUserManager(
|
||||
IUserStore<BackOfficeIdentityUser, int> store,
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IContentSection contentSectionConfig)
|
||||
: base(store)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");;
|
||||
InitUserManager(this, membershipProvider, options);
|
||||
if (options == null) throw new ArgumentNullException("options"); ;
|
||||
InitUserManager(this, membershipProvider, contentSectionConfig, options);
|
||||
}
|
||||
|
||||
#region Static Create methods
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the overload specifying all dependencies instead")]
|
||||
public static BackOfficeUserManager Create(
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
IUserService userService,
|
||||
IExternalLoginService externalLoginService,
|
||||
MembershipProviderBase membershipProvider)
|
||||
{
|
||||
return Create(options, userService,
|
||||
ApplicationContext.Current.Services.EntityService,
|
||||
externalLoginService, membershipProvider,
|
||||
UmbracoConfig.For.UmbracoSettings().Content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a BackOfficeUserManager instance with all default options and the default BackOfficeUserManager
|
||||
/// </summary>
|
||||
@@ -44,6 +72,7 @@ namespace Umbraco.Core.Security
|
||||
/// <param name="entityService"></param>
|
||||
/// <param name="externalLoginService"></param>
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <param name="contentSectionConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeUserManager Create(
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
@@ -51,7 +80,8 @@ namespace Umbraco.Core.Security
|
||||
IMemberTypeService memberTypeService,
|
||||
IEntityService entityService,
|
||||
IExternalLoginService externalLoginService,
|
||||
MembershipProviderBase membershipProvider)
|
||||
MembershipProviderBase membershipProvider,
|
||||
IContentSection contentSectionConfig)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
if (userService == null) throw new ArgumentNullException("userService");
|
||||
@@ -59,7 +89,18 @@ namespace Umbraco.Core.Security
|
||||
if (externalLoginService == null) throw new ArgumentNullException("externalLoginService");
|
||||
|
||||
var manager = new BackOfficeUserManager(new BackOfficeUserStore(userService, memberTypeService, entityService, externalLoginService, membershipProvider));
|
||||
manager.InitUserManager(manager, membershipProvider, options);
|
||||
manager.InitUserManager(manager, membershipProvider, contentSectionConfig, options);
|
||||
return manager;
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the overload specifying all dependencies instead")]
|
||||
public static BackOfficeUserManager Create(
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
BackOfficeUserStore customUserStore,
|
||||
MembershipProviderBase membershipProvider)
|
||||
{
|
||||
var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider);
|
||||
return manager;
|
||||
}
|
||||
|
||||
@@ -69,31 +110,45 @@ namespace Umbraco.Core.Security
|
||||
/// <param name="options"></param>
|
||||
/// <param name="customUserStore"></param>
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <param name="contentSectionConfig"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeUserManager Create(
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
BackOfficeUserStore customUserStore,
|
||||
MembershipProviderBase membershipProvider)
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options,
|
||||
BackOfficeUserStore customUserStore,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IContentSection contentSectionConfig)
|
||||
{
|
||||
var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider);
|
||||
var manager = new BackOfficeUserManager(customUserStore, options, membershipProvider, contentSectionConfig);
|
||||
return manager;
|
||||
}
|
||||
#endregion
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the overload specifying all dependencies instead")]
|
||||
protected void InitUserManager(
|
||||
BackOfficeUserManager manager,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options)
|
||||
{
|
||||
InitUserManager(manager, membershipProvider, UmbracoConfig.For.UmbracoSettings().Content, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the user manager with the correct options
|
||||
/// </summary>
|
||||
/// <param name="manager"></param>
|
||||
/// <param name="membershipProvider"></param>
|
||||
/// <param name="contentSectionConfig"></param>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
protected void InitUserManager(
|
||||
BackOfficeUserManager manager,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IContentSection contentSectionConfig,
|
||||
IdentityFactoryOptions<BackOfficeUserManager> options)
|
||||
{
|
||||
//NOTE: This method is mostly here for backwards compat
|
||||
base.InitUserManager(manager, membershipProvider, options.DataProtectionProvider);
|
||||
base.InitUserManager(manager, membershipProvider, options.DataProtectionProvider, contentSectionConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +193,16 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
#endregion
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the overload specifying all dependencies instead")]
|
||||
protected void InitUserManager(
|
||||
BackOfficeUserManager<T> manager,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IDataProtectionProvider dataProtectionProvider)
|
||||
{
|
||||
InitUserManager(manager, membershipProvider, dataProtectionProvider, UmbracoConfig.For.UmbracoSettings().Content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the user manager with the correct options
|
||||
/// </summary>
|
||||
@@ -146,11 +211,13 @@ namespace Umbraco.Core.Security
|
||||
/// The <see cref="MembershipProviderBase"/> for the users called UsersMembershipProvider
|
||||
/// </param>
|
||||
/// <param name="dataProtectionProvider"></param>
|
||||
/// <param name="contentSectionConfig"></param>
|
||||
/// <returns></returns>
|
||||
protected void InitUserManager(
|
||||
BackOfficeUserManager<T> manager,
|
||||
MembershipProviderBase membershipProvider,
|
||||
IDataProtectionProvider dataProtectionProvider)
|
||||
IDataProtectionProvider dataProtectionProvider,
|
||||
IContentSection contentSectionConfig)
|
||||
{
|
||||
// Configure validation logic for usernames
|
||||
manager.UserValidator = new BackOfficeUserValidator<T>(manager)
|
||||
@@ -180,7 +247,9 @@ namespace Umbraco.Core.Security
|
||||
//custom identity factory for creating the identity object for which we auth against in the back office
|
||||
manager.ClaimsIdentityFactory = new BackOfficeClaimsIdentityFactory<T>();
|
||||
|
||||
manager.EmailService = new EmailService();
|
||||
manager.EmailService = new EmailService(
|
||||
contentSectionConfig.NotificationEmailAddress,
|
||||
new EmailSender());
|
||||
|
||||
//NOTE: Not implementing these, if people need custom 2 factor auth, they'll need to implement their own UserStore to suport it
|
||||
|
||||
@@ -266,6 +335,24 @@ namespace Umbraco.Core.Security
|
||||
return password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override to check the user approval value as well as the user lock out date, by default this only checks the user's locked out date
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// In the ASP.NET Identity world, there is only one value for being locked out, in Umbraco we have 2 so when checking this for Umbraco we need to check both values
|
||||
/// </remarks>
|
||||
public override async Task<bool> IsLockedOutAsync(int userId)
|
||||
{
|
||||
var user = await FindByIdAsync(userId);
|
||||
if (user == null)
|
||||
throw new InvalidOperationException("No user found by id " + userId);
|
||||
if (user.IsApproved == false)
|
||||
return true;
|
||||
|
||||
return await base.IsLockedOutAsync(userId);
|
||||
}
|
||||
|
||||
#region Overrides for password logic
|
||||
|
||||
|
||||
@@ -548,6 +548,9 @@ namespace Umbraco.Core.Security
|
||||
/// </summary>
|
||||
/// <param name="user"/><param name="lockoutEnd"/>
|
||||
/// <returns/>
|
||||
/// <remarks>
|
||||
/// Currently we do not suport a timed lock out, when they are locked out, an admin will have to reset the status
|
||||
/// </remarks>
|
||||
public Task SetLockoutEndDateAsync(BackOfficeIdentityUser user, DateTimeOffset lockoutEnd)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
|
||||
@@ -1,16 +1,37 @@
|
||||
using System.Net.Mail;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Net.Mail;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IIdentityMessageService"/> implementation for Umbraco
|
||||
/// </summary>
|
||||
public class EmailService : IIdentityMessageService
|
||||
{
|
||||
private readonly string _notificationEmailAddress;
|
||||
private readonly IEmailSender _defaultEmailSender;
|
||||
|
||||
public EmailService(string notificationEmailAddress, IEmailSender defaultEmailSender)
|
||||
{
|
||||
_notificationEmailAddress = notificationEmailAddress;
|
||||
_defaultEmailSender = defaultEmailSender;
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Use the constructor specifying all dependencies")]
|
||||
public EmailService()
|
||||
: this(UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress, new EmailSender())
|
||||
{
|
||||
}
|
||||
|
||||
public async Task SendAsync(IdentityMessage message)
|
||||
{
|
||||
var mailMessage = new MailMessage(
|
||||
UmbracoConfig.For.UmbracoSettings().Content.NotificationEmailAddress,
|
||||
_notificationEmailAddress,
|
||||
message.Destination,
|
||||
message.Subject,
|
||||
message.Body)
|
||||
@@ -21,16 +42,15 @@ namespace Umbraco.Core.Security
|
||||
|
||||
try
|
||||
{
|
||||
using (var client = new SmtpClient())
|
||||
//check if it's a custom message and if so use it's own defined mail sender
|
||||
var umbMsg = message as UmbracoEmailMessage;
|
||||
if (umbMsg != null)
|
||||
{
|
||||
if (client.DeliveryMethod == SmtpDeliveryMethod.Network)
|
||||
{
|
||||
await client.SendMailAsync(mailMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
client.Send(mailMessage);
|
||||
}
|
||||
await umbMsg.MailSender.SendAsync(mailMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _defaultEmailSender.SendAsync(mailMessage);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -67,6 +67,19 @@ namespace Umbraco.Core.Security
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw password value for a given user
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// By default this will return an invalid attempt, inheritors will need to override this to support it
|
||||
/// </remarks>
|
||||
protected virtual Attempt<string> GetRawPassword(string username)
|
||||
{
|
||||
return Attempt<string>.Fail();
|
||||
}
|
||||
|
||||
private string _applicationName;
|
||||
private bool _enablePasswordReset;
|
||||
private bool _enablePasswordRetrieval;
|
||||
@@ -301,7 +314,7 @@ namespace Umbraco.Core.Security
|
||||
/// Processes a request to update the password for a membership user.
|
||||
/// </summary>
|
||||
/// <param name="username">The user to update the password for.</param>
|
||||
/// <param name="oldPassword">This property is ignore for this provider</param>
|
||||
/// <param name="oldPassword">Required to change a user password if the user is not new and AllowManuallyChangingPassword is false</param>
|
||||
/// <param name="newPassword">The new password for the specified user.</param>
|
||||
/// <returns>
|
||||
/// true if the password was updated successfully; otherwise, false.
|
||||
@@ -311,10 +324,17 @@ namespace Umbraco.Core.Security
|
||||
/// </remarks>
|
||||
public override bool ChangePassword(string username, string oldPassword, string newPassword)
|
||||
{
|
||||
string rawPasswordValue = string.Empty;
|
||||
if (oldPassword.IsNullOrWhiteSpace() && AllowManuallyChangingPassword == false)
|
||||
{
|
||||
//If the old password is empty and AllowManuallyChangingPassword is false, than this provider cannot just arbitrarily change the password
|
||||
throw new NotSupportedException("This provider does not support manually changing the password");
|
||||
//we need to lookup the member since this could be a brand new member without a password set
|
||||
var rawPassword = GetRawPassword(username);
|
||||
rawPasswordValue = rawPassword.Success ? rawPassword.Result : string.Empty;
|
||||
if (rawPassword.Success == false || rawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix) == false)
|
||||
{
|
||||
//If the old password is empty and AllowManuallyChangingPassword is false, than this provider cannot just arbitrarily change the password
|
||||
throw new NotSupportedException("This provider does not support manually changing the password");
|
||||
}
|
||||
}
|
||||
|
||||
var args = new ValidatePasswordEventArgs(username, newPassword, false);
|
||||
@@ -327,10 +347,12 @@ namespace Umbraco.Core.Security
|
||||
throw new MembershipPasswordException("Change password canceled due to password validation failure.");
|
||||
}
|
||||
|
||||
//Special case to allow changing password without validating existing credentials
|
||||
//This is used during installation only
|
||||
var installing = Current.RuntimeState.Level == RuntimeLevel.Install;
|
||||
if (AllowManuallyChangingPassword == false && installing && oldPassword == "default")
|
||||
//Special cases to allow changing password without validating existing credentials
|
||||
// * the member is new and doesn't have a password set
|
||||
// * during installation to set the admin password
|
||||
if (AllowManuallyChangingPassword == false
|
||||
&& (rawPasswordValue.StartsWith(Constants.Security.EmptyPasswordPrefix)
|
||||
|| (installing && oldPassword == "default")))
|
||||
{
|
||||
return PerformChangePassword(username, oldPassword, newPassword);
|
||||
}
|
||||
@@ -686,12 +708,12 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
var keyedHashAlgorithm = algorithm;
|
||||
if (keyedHashAlgorithm.Key.Length == saltBytes.Length)
|
||||
{
|
||||
{
|
||||
//if the salt bytes is the required key length for the algorithm, use it as-is
|
||||
keyedHashAlgorithm.Key = saltBytes;
|
||||
}
|
||||
else if (keyedHashAlgorithm.Key.Length < saltBytes.Length)
|
||||
{
|
||||
{
|
||||
//if the salt bytes is too long for the required key length for the algorithm, reduce it
|
||||
var numArray2 = new byte[keyedHashAlgorithm.Key.Length];
|
||||
Buffer.BlockCopy(saltBytes, 0, numArray2, 0, numArray2.Length);
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace Umbraco.Core.Security
|
||||
/// <param name="provider"></param>
|
||||
/// <param name="userService"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// An Admin can always reset the password
|
||||
/// </remarks>
|
||||
internal static bool CanResetPassword(this MembershipProvider provider, IUserService userService)
|
||||
{
|
||||
if (provider == null) throw new ArgumentNullException("provider");
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNet.Identity;
|
||||
|
||||
namespace Umbraco.Core.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom implementation for IdentityMessage that allows the customization of how an email is sent
|
||||
/// </summary>
|
||||
internal class UmbracoEmailMessage : IdentityMessage
|
||||
{
|
||||
public IEmailSender MailSender { get; private set; }
|
||||
|
||||
public UmbracoEmailMessage(IEmailSender mailSender)
|
||||
{
|
||||
MailSender = mailSender;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Core.Serialization
|
||||
{
|
||||
public class KnownTypeUdiJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(Udi).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value.ToString());
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
var jo = JToken.ReadFrom(reader);
|
||||
var val = jo.ToObject<string>();
|
||||
return val == null ? null : Udi.Parse(val, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,11 @@ using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Umbraco.Core.Serialization
|
||||
{
|
||||
|
||||
public class UdiJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(Udi).IsAssignableFrom(objectType);
|
||||
return typeof (Udi).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
|
||||
@@ -24,15 +24,13 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
private readonly MediaFileSystem _mediaFileSystem;
|
||||
private IQuery<IContent> _queryNotTrashed;
|
||||
private readonly IdkMap _idkMap;
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ContentService(IScopeUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, MediaFileSystem mediaFileSystem, IdkMap idkMap)
|
||||
public ContentService(IScopeUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, MediaFileSystem mediaFileSystem)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_mediaFileSystem = mediaFileSystem;
|
||||
_idkMap = idkMap;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -122,8 +120,8 @@ namespace Umbraco.Core.Services
|
||||
repo.AssignEntityPermission(entity, permission, groupIds);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns implicit/inherited permissions assigned to the content item for all user groups
|
||||
/// </summary>
|
||||
@@ -143,6 +141,26 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Create
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
|
||||
/// that this Content should based on.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that using this method will simply return a new IContent without any identity
|
||||
/// as it has not yet been persisted. It is intended as a shortcut to creating new content objects
|
||||
/// that does not invoke a save operation against the database.
|
||||
/// </remarks>
|
||||
/// <param name="name">Name of the Content object</param>
|
||||
/// <param name="parentId">Id of Parent for the new Content</param>
|
||||
/// <param name="contentTypeAlias">Alias of the <see cref="IContentType"/></param>
|
||||
/// <param name="userId">Optional id of the user creating the content</param>
|
||||
/// <returns><see cref="IContent"/></returns>
|
||||
public IContent CreateContent(string name, Guid parentId, string contentTypeAlias, int userId = 0)
|
||||
{
|
||||
var parent = GetById(parentId);
|
||||
return CreateContent(name, parent, contentTypeAlias, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IContent"/> object of a specified content type.
|
||||
/// </summary>
|
||||
@@ -316,7 +334,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (withIdentity)
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IContent>(content), "Saving"))
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(content);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
content.WasCancelled = true;
|
||||
return;
|
||||
@@ -327,14 +346,15 @@ namespace Umbraco.Core.Services
|
||||
|
||||
uow.Flush(); // need everything so we can serialize
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IContent>(content, false), "Saved");
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
uow.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshNode).ToEventArgs());
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(Created, this, new NewEventArgs<IContent>(content, false, content.ContentType.Alias, parent));
|
||||
|
||||
if (withIdentity == false)
|
||||
return;
|
||||
return;
|
||||
|
||||
Audit(uow, AuditType.New, $"Content '{content.Name}' was created with Id {content.Id}", content.CreatorId, content.Id);
|
||||
}
|
||||
@@ -376,7 +396,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var index = items.ToDictionary(x => x.Id, x => x);
|
||||
|
||||
return idsA.Select(x => index.TryGetValue(x, out IContent c) ? c : null).WhereNotNull();
|
||||
return idsA.Select(x => index.TryGetValue(x, out var c) ? c : null).WhereNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,13 +407,34 @@ namespace Umbraco.Core.Services
|
||||
/// <returns><see cref="IContent"/></returns>
|
||||
public IContent GetById(Guid key)
|
||||
{
|
||||
// the repository implements a cache policy on int identifiers, not guids,
|
||||
// and we are not changing it now, but we still would like to rely on caching
|
||||
// instead of running a full query against the database, so relying on the
|
||||
// id-key map, which is fast.
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentRepository>();
|
||||
return repository.Get(key);
|
||||
}
|
||||
}
|
||||
|
||||
var a = _idkMap.GetIdForKey(key, UmbracoObjectTypes.Document);
|
||||
return a.Success ? GetById(a.Result) : null;
|
||||
/// <summary>
|
||||
/// Gets <see cref="IContent"/> objects by Ids
|
||||
/// </summary>
|
||||
/// <param name="ids">Ids of the Content to retrieve</param>
|
||||
/// <returns><see cref="IContent"/></returns>
|
||||
public IEnumerable<IContent> GetByIds(IEnumerable<Guid> ids)
|
||||
{
|
||||
var idsA = ids.ToArray();
|
||||
if (idsA.Length == 0) return Enumerable.Empty<IContent>();
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentRepository>();
|
||||
var items = repository.GetAll(idsA);
|
||||
|
||||
var index = items.ToDictionary(x => x.Key, x => x);
|
||||
|
||||
return idsA.Select(x => index.TryGetValue(x, out var c) ? c : null).WhereNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -626,7 +667,6 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentRepository>();
|
||||
var filterQuery = filter.IsNullOrWhiteSpace()
|
||||
? null
|
||||
: uow.Query<IContent>().Where(x => x.Name.Contains(filter));
|
||||
@@ -660,7 +700,16 @@ namespace Umbraco.Core.Services
|
||||
var query = uow.Query<IContent>();
|
||||
//if the id is System Root, then just get all
|
||||
if (id != Constants.System.Root)
|
||||
query.Where(x => x.Path.SqlContains($",{id},", TextColumnType.NVarchar));
|
||||
{
|
||||
var entityRepository = uow.CreateRepository<IEntityRepository>();
|
||||
var contentPath = entityRepository.GetAllPaths(Constants.ObjectTypes.DocumentGuid, id).ToArray();
|
||||
if (contentPath.Length == 0)
|
||||
{
|
||||
totalChildren = 0;
|
||||
return Enumerable.Empty<IContent>();
|
||||
}
|
||||
query.Where(x => x.Path.SqlStartsWith($"{contentPath[0]},", TextColumnType.NVarchar));
|
||||
}
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
}
|
||||
@@ -895,15 +944,43 @@ namespace Umbraco.Core.Services
|
||||
if (content.Trashed) return false; // trashed content is never publishable
|
||||
|
||||
// not trashed and has a parent: publishable if the parent is path-published
|
||||
|
||||
int[] ids;
|
||||
if (content.HasIdentity)
|
||||
{
|
||||
// get ids from path (we have identity)
|
||||
// skip the first one that has to be -1 - and we don't care
|
||||
// skip the last one that has to be "this" - and it's ok to stop at the parent
|
||||
ids = content.Path.Split(',').Skip(1).SkipLast().Select(int.Parse).ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no path yet (no identity), have to move up to parent
|
||||
// skip the first one that has to be -1 - and we don't care
|
||||
// don't skip the last one that is "parent"
|
||||
var parent = GetById(content.ParentId);
|
||||
if (parent == null) return false;
|
||||
ids = parent.Path.Split(',').Skip(1).Select(int.Parse).ToArray();
|
||||
}
|
||||
if (ids.Length == 0)
|
||||
return false;
|
||||
|
||||
// if the first one is recycle bin, fail fast
|
||||
if (ids[0] == Constants.System.RecycleBinContent)
|
||||
return false;
|
||||
|
||||
// fixme - move to repository?
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repo = uow.CreateRepository<IContentRepository>();
|
||||
var parent = repo.Get(content.ParentId);
|
||||
if (parent == null)
|
||||
throw new Exception("Out of sync."); // causes rollback
|
||||
return repo.IsPathPublished(parent);
|
||||
}
|
||||
var sql = uow.Sql(@"
|
||||
SELECT id
|
||||
FROM umbracoNode
|
||||
JOIN cmsDocument ON umbracoNode.id=cmsDocument.nodeId AND cmsDocument.published=@0
|
||||
WHERE umbracoNode.trashed=@1 AND umbracoNode.id IN (@2)",
|
||||
true, false, ids);
|
||||
var x = uow.Database.Fetch<int>(sql);
|
||||
return ids.Length == x.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPathPublished(IContent content)
|
||||
@@ -943,7 +1020,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IContent>(content, evtMsgs), "Saving"))
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(content, evtMsgs);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
@@ -971,7 +1049,10 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(content);
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IContent>(content, false, evtMsgs), "Saved");
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
}
|
||||
var changeType = isNew ? TreeChangeTypes.RefreshBranch : TreeChangeTypes.RefreshNode;
|
||||
uow.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, changeType).ToEventArgs());
|
||||
Audit(uow, AuditType.Save, "Save Content performed by user", userId, content.Id);
|
||||
@@ -1010,7 +1091,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IContent>(contentsA, evtMsgs), "Saving"))
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(contentsA, evtMsgs);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
@@ -1036,7 +1118,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IContent>(contentsA, false, evtMsgs), "Saved");
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
}
|
||||
uow.Events.Dispatch(TreeChanged, this, treeChanges.ToEventArgs());
|
||||
Audit(uow, AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root);
|
||||
|
||||
@@ -1264,7 +1349,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IContent>(content, evtMsgs)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IContent>(content, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
@@ -1338,7 +1424,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, dateToRetain: versionDate)))
|
||||
var deleteRevisionsEventArgs = new DeleteRevisionsEventArgs(id, dateToRetain: versionDate);
|
||||
if (uow.Events.DispatchCancelable(DeletingVersions, this, deleteRevisionsEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -1348,7 +1435,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IContentRepository>();
|
||||
repository.DeleteVersions(id, versionDate);
|
||||
|
||||
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate));
|
||||
deleteRevisionsEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedVersions, this, deleteRevisionsEventArgs);
|
||||
Audit(uow, AuditType.Delete, "Delete Content by version date performed by user", userId, Constants.System.Root);
|
||||
|
||||
uow.Complete();
|
||||
@@ -1423,7 +1511,9 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IContentRepository>();
|
||||
|
||||
var originalPath = content.Path;
|
||||
if (uow.Events.DispatchCancelable(Trashing, this, new MoveEventArgs<IContent>(new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent))))
|
||||
var moveEventInfo = new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent);
|
||||
var moveEventArgs = new MoveEventArgs<IContent>(evtMsgs, moveEventInfo);
|
||||
if (uow.Events.DispatchCancelable(Trashing, this, moveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs); // causes rollback
|
||||
@@ -1442,7 +1532,9 @@ namespace Umbraco.Core.Services
|
||||
.Select(x => new MoveEventInfo<IContent>(x.Item1, x.Item2, x.Item1.ParentId))
|
||||
.ToArray();
|
||||
|
||||
uow.Events.Dispatch(Trashed, this, new MoveEventArgs<IContent>(false, evtMsgs, moveInfo));
|
||||
moveEventArgs.CanCancel = false;
|
||||
moveEventArgs.MoveInfoCollection = moveInfo;
|
||||
uow.Events.Dispatch(Trashed, this, moveEventArgs);
|
||||
Audit(uow, AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
|
||||
|
||||
uow.Complete();
|
||||
@@ -1482,7 +1574,9 @@ namespace Umbraco.Core.Services
|
||||
if (parentId != Constants.System.Root && (parent == null || parent.Trashed))
|
||||
throw new InvalidOperationException("Parent does not exist or is trashed."); // causes rollback
|
||||
|
||||
if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs<IContent>(new MoveEventInfo<IContent>(content, content.Path, parentId))))
|
||||
var moveEventInfo = new MoveEventInfo<IContent>(content, content.Path, parentId);
|
||||
var moveEventArgs = new MoveEventArgs<IContent>(moveEventInfo);
|
||||
if (uow.Events.DispatchCancelable(Moving, this, moveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return; // causes rollback
|
||||
@@ -1511,7 +1605,9 @@ namespace Umbraco.Core.Services
|
||||
.Select(x => new MoveEventInfo<IContent>(x.Item1, x.Item2, x.Item1.ParentId))
|
||||
.ToArray();
|
||||
|
||||
uow.Events.Dispatch(Moved, this, new MoveEventArgs<IContent>(false, moveInfo));
|
||||
moveEventArgs.MoveInfoCollection = moveInfo;
|
||||
moveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Moved, this, moveEventArgs);
|
||||
Audit(uow, AuditType.Move, "Move Content performed by user", userId, content.Id);
|
||||
|
||||
uow.Complete();
|
||||
@@ -1577,7 +1673,7 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public void EmptyRecycleBin()
|
||||
{
|
||||
var nodeObjectType = new Guid(Constants.ObjectTypes.Document);
|
||||
var nodeObjectType = Constants.ObjectTypes.DocumentGuid;
|
||||
var deleted = new List<IContent>();
|
||||
var evtMsgs = EventMessagesFactory.Get(); // todo - and then?
|
||||
|
||||
@@ -1591,7 +1687,8 @@ namespace Umbraco.Core.Services
|
||||
// are managed by Delete, and not here.
|
||||
|
||||
// no idea what those events are for, keep a simplified version
|
||||
if (uow.Events.DispatchCancelable(EmptyingRecycleBin, this, new RecycleBinEventArgs(nodeObjectType)))
|
||||
var recycleBinEventArgs = new RecycleBinEventArgs(nodeObjectType);
|
||||
if (uow.Events.DispatchCancelable(EmptyingRecycleBin, this, recycleBinEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return; // causes rollback
|
||||
@@ -1606,7 +1703,9 @@ namespace Umbraco.Core.Services
|
||||
deleted.Add(content);
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, true));
|
||||
recycleBinEventArgs.CanCancel = false;
|
||||
recycleBinEventArgs.RecycleBinEmptiedSuccessfully = true; // oh my?!
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, recycleBinEventArgs);
|
||||
uow.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.Remove)).ToEventArgs());
|
||||
Audit(uow, AuditType.Delete, "Empty Content Recycle Bin performed by user", 0, Constants.System.RecycleBinContent);
|
||||
|
||||
@@ -1649,7 +1748,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Copying, this, new CopyEventArgs<IContent>(content, copy, parentId)))
|
||||
var copyEventArgs = new CopyEventArgs<IContent>(content, copy, true, parentId, relateToOriginal);
|
||||
if (uow.Events.DispatchCancelable(Copying, this, copyEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return null;
|
||||
@@ -1745,7 +1845,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SendingToPublish, this, new SendToPublishEventArgs<IContent>(content)))
|
||||
var sendToPublishEventArgs = new SendToPublishEventArgs<IContent>(content);
|
||||
if (uow.Events.DispatchCancelable(SendingToPublish, this, sendToPublishEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return false;
|
||||
@@ -1755,7 +1856,8 @@ namespace Umbraco.Core.Services
|
||||
// fixme - nesting uow?
|
||||
Save(content, userId);
|
||||
|
||||
uow.Events.Dispatch(SentToPublish, this, new SendToPublishEventArgs<IContent>(content, false));
|
||||
sendToPublishEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SentToPublish, this, sendToPublishEventArgs);
|
||||
Audit(uow, AuditType.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id);
|
||||
}
|
||||
|
||||
@@ -1780,7 +1882,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(RollingBack, this, new RollbackEventArgs<IContent>(content)))
|
||||
var rollbackEventArgs = new RollbackEventArgs<IContent>(content);
|
||||
if (uow.Events.DispatchCancelable(RollingBack, this, rollbackEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return content;
|
||||
@@ -1802,7 +1905,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
repository.AddOrUpdate(content);
|
||||
|
||||
uow.Events.Dispatch(RolledBack, this, new RollbackEventArgs<IContent>(content, false));
|
||||
rollbackEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(RolledBack, this, rollbackEventArgs);
|
||||
uow.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshNode).ToEventArgs());
|
||||
Audit(uow, AuditType.RollBack, "Content rollback performed by user", content.WriterId, content.Id);
|
||||
|
||||
@@ -1831,7 +1935,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IContent>(itemsA), "Saving"))
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(itemsA);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
return false;
|
||||
|
||||
var published = new List<IContent>();
|
||||
@@ -1868,7 +1973,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IContent>(saved, false), "Saved");
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(TreeChanged, this, saved.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.RefreshNode)).ToEventArgs());
|
||||
|
||||
@@ -2051,7 +2159,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IContent>(content), "Saving"))
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(content, evtMsgs);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
uow.Complete();
|
||||
return Attempt.Fail(new PublishStatus(PublishStatusType.FailedCancelledByEvent, evtMsgs, content));
|
||||
@@ -2080,7 +2189,10 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(content);
|
||||
|
||||
if (raiseEvents) // always
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IContent>(content, false, evtMsgs), "Saved");
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
}
|
||||
|
||||
if (status.Success == false)
|
||||
{
|
||||
@@ -2256,7 +2368,7 @@ namespace Umbraco.Core.Services
|
||||
/// Occurs after a blueprint has been deleted.
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentService, DeleteEventArgs<IContent>> DeletedBlueprint;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Publishing Strategies
|
||||
@@ -2622,16 +2734,16 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return GetContentType(uow, contentTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Blueprints
|
||||
|
||||
public IContent GetBlueprintById(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentBlueprintRepository>();
|
||||
var blueprint = repository.Get(id);
|
||||
@@ -2643,13 +2755,15 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public IContent GetBlueprintById(Guid id)
|
||||
{
|
||||
// the repository implements a cache policy on int identifiers, not guids,
|
||||
// and we are not changing it now, but we still would like to rely on caching
|
||||
// instead of running a full query against the database, so relying on the
|
||||
// id-key map, which is fast.
|
||||
|
||||
var a = _idkMap.GetIdForKey(id, UmbracoObjectTypes.DocumentBlueprint);
|
||||
return a.Success ? GetBlueprintById(a.Result) : null;
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentBlueprintRepository>();
|
||||
var blueprint = repository.Get(id);
|
||||
if (blueprint != null)
|
||||
((Content) blueprint).IsBlueprint = true;
|
||||
return blueprint;
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveBlueprint(IContent content, int userId = 0)
|
||||
@@ -2662,7 +2776,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(Constants.Locks.ContentTree);
|
||||
uow.WriteLock(Constants.Locks.ContentTree);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(content.Name))
|
||||
{
|
||||
@@ -2688,7 +2802,7 @@ namespace Umbraco.Core.Services
|
||||
public void DeleteBlueprint(IContent content, int userId = 0)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
{
|
||||
uow.WriteLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentBlueprintRepository>();
|
||||
repository.Delete(content);
|
||||
|
||||
@@ -1,10 +1,48 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Content service extension methods
|
||||
/// </summary>
|
||||
public static class ContentServiceExtensions
|
||||
{
|
||||
public static IEnumerable<IContent> GetByIds(this IContentService contentService, IEnumerable<Udi> ids)
|
||||
{
|
||||
var guids = new List<GuidUdi>();
|
||||
foreach (var udi in ids)
|
||||
{
|
||||
var guidUdi = udi as GuidUdi;
|
||||
if (guidUdi == null)
|
||||
throw new InvalidOperationException("The UDI provided isn't of type " + typeof(GuidUdi) + " which is required by content");
|
||||
guids.Add(guidUdi);
|
||||
}
|
||||
|
||||
return contentService.GetByIds(guids.Select(x => x.Guid));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method to create an IContent object based on the Udi of a parent
|
||||
/// </summary>
|
||||
/// <param name="contentService"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="mediaTypeAlias"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public static IContent CreateContent(this IContentService contentService, string name, Udi parentId, string mediaTypeAlias, int userId = 0)
|
||||
{
|
||||
var guidUdi = parentId as GuidUdi;
|
||||
if (guidUdi == null)
|
||||
throw new InvalidOperationException("The UDI provided isn't of type " + typeof(GuidUdi) + " which is required by content");
|
||||
var parent = contentService.GetById(guidUdi.Guid);
|
||||
return contentService.CreateContent(name, parent, mediaTypeAlias, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove all permissions for this user for all nodes
|
||||
/// </summary>
|
||||
|
||||
@@ -112,6 +112,12 @@ namespace Umbraco.Core.Services
|
||||
uow.Events.DispatchCancelable(SavedContainer, This, args);
|
||||
}
|
||||
|
||||
protected void OnRenamedContainer(IScopeUnitOfWork uow, SaveEventArgs<EntityContainer> args)
|
||||
{
|
||||
// fixme changing the name of the event?!
|
||||
uow.Events.DispatchCancelable(SavedContainer, This, args, "RenamedContainer");
|
||||
}
|
||||
|
||||
// fixme what is this?
|
||||
protected void OnDeletingContainer(IScopeUnitOfWork uow, DeleteEventArgs<EntityContainer> args)
|
||||
{
|
||||
|
||||
@@ -385,7 +385,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (OnSavingCancelled(uow, new SaveEventArgs<TItem>(item)))
|
||||
var saveEventArgs = new SaveEventArgs<TItem>(item);
|
||||
if (OnSavingCancelled(uow, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -412,7 +413,8 @@ namespace Umbraco.Core.Services
|
||||
OnUowRefreshedEntity(args);
|
||||
|
||||
OnChanged(uow, args);
|
||||
OnSaved(uow, new SaveEventArgs<TItem>(item, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
OnSaved(uow, saveEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Save, $"Save {typeof(TItem).Name} performed by user", userId, item.Id);
|
||||
uow.Complete();
|
||||
@@ -425,7 +427,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (OnSavingCancelled(uow, new SaveEventArgs<TItem>(itemsA)))
|
||||
var saveEventArgs = new SaveEventArgs<TItem>(itemsA);
|
||||
if (OnSavingCancelled(uow, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -454,7 +457,8 @@ namespace Umbraco.Core.Services
|
||||
OnUowRefreshedEntity(args);
|
||||
|
||||
OnChanged(uow, args);
|
||||
OnSaved(uow, new SaveEventArgs<TItem>(itemsA, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
OnSaved(uow, saveEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Save, $"Save {typeof(TItem).Name} performed by user", userId, -1);
|
||||
uow.Complete();
|
||||
@@ -469,7 +473,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (OnDeletingCancelled(uow, new DeleteEventArgs<TItem>(item)))
|
||||
var deleteEventArgs = new DeleteEventArgs<TItem>(item);
|
||||
if (OnDeletingCancelled(uow, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -511,7 +516,9 @@ namespace Umbraco.Core.Services
|
||||
OnUowRefreshedEntity(args);
|
||||
|
||||
OnChanged(uow, args);
|
||||
OnDeleted(uow, new DeleteEventArgs<TItem>(deleted, false));
|
||||
deleteEventArgs.DeletedEntities = deleted.DistinctBy(x => x.Id);
|
||||
deleteEventArgs.CanCancel = false;
|
||||
OnDeleted(uow, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, $"Delete {typeof(TItem).Name} performed by user", userId, item.Id);
|
||||
uow.Complete();
|
||||
@@ -524,7 +531,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (OnDeletingCancelled(uow, new DeleteEventArgs<TItem>(itemsA)))
|
||||
var deleteEventArgs = new DeleteEventArgs<TItem>(itemsA);
|
||||
if (OnDeletingCancelled(uow, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -563,7 +571,9 @@ namespace Umbraco.Core.Services
|
||||
OnUowRefreshedEntity(args);
|
||||
|
||||
OnChanged(uow, args);
|
||||
OnDeleted(uow, new DeleteEventArgs<TItem>(deleted, false));
|
||||
deleteEventArgs.DeletedEntities = deleted.DistinctBy(x => x.Id);
|
||||
deleteEventArgs.CanCancel = false;
|
||||
OnDeleted(uow, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, $"Delete {typeof(TItem).Name} performed by user", userId, -1);
|
||||
uow.Complete();
|
||||
@@ -692,7 +702,9 @@ namespace Umbraco.Core.Services
|
||||
var moveInfo = new List<MoveEventInfo<TItem>>();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (OnMovingCancelled(uow, new MoveEventArgs<TItem>(evtMsgs, new MoveEventInfo<TItem>(moving, moving.Path, containerId))))
|
||||
var moveEventInfo = new MoveEventInfo<TItem>(moving, moving.Path, containerId);
|
||||
var moveEventArgs = new MoveEventArgs<TItem>(evtMsgs, moveEventInfo);
|
||||
if (OnMovingCancelled(uow, moveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Fail(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs);
|
||||
@@ -725,7 +737,9 @@ namespace Umbraco.Core.Services
|
||||
// has no impact on the published content types - would be entirely different if we were to support
|
||||
// moving a content type under another content type.
|
||||
|
||||
OnMoved(uow, new MoveEventArgs<TItem>(false, evtMsgs, moveInfo.ToArray()));
|
||||
moveEventArgs.MoveInfoCollection = moveInfo;
|
||||
moveEventArgs.CanCancel = false;
|
||||
OnMoved(uow, moveEventArgs);
|
||||
}
|
||||
|
||||
return OperationStatus.Attempt.Succeed(MoveOperationStatusType.Success, evtMsgs);
|
||||
@@ -756,7 +770,8 @@ namespace Umbraco.Core.Services
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (OnSavingContainerCancelled(uow, new SaveEventArgs<EntityContainer>(container, evtMsgs)))
|
||||
var saveEventArgs = new SaveEventArgs<EntityContainer>(container, evtMsgs);
|
||||
if (OnSavingContainerCancelled(uow, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs, container);
|
||||
@@ -765,7 +780,8 @@ namespace Umbraco.Core.Services
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Complete();
|
||||
|
||||
OnSavedContainer(uow, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
saveEventArgs.CanCancel = false;
|
||||
OnSavedContainer(uow, saveEventArgs);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, container);
|
||||
@@ -895,7 +911,8 @@ namespace Umbraco.Core.Services
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCannot, evtMsgs));
|
||||
}
|
||||
|
||||
if (OnDeletingContainerCancelled(uow, new DeleteEventArgs<EntityContainer>(container, evtMsgs)))
|
||||
var deleteEventArgs = new DeleteEventArgs<EntityContainer>(container, evtMsgs);
|
||||
if (OnDeletingContainerCancelled(uow, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
@@ -904,13 +921,45 @@ namespace Umbraco.Core.Services
|
||||
repo.Delete(container);
|
||||
uow.Complete();
|
||||
|
||||
OnDeletedContainer(uow, new DeleteEventArgs<EntityContainer>(container, evtMsgs));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
OnDeletedContainer(uow, deleteEventArgs);
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<OperationStatusType, EntityContainer>> RenameContainer(int id, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
uow.WriteLock(WriteLockIds); // also for containers
|
||||
|
||||
var repository = uow.CreateContainerRepository(ContainerObjectType);
|
||||
try
|
||||
{
|
||||
var container = repository.Get(id);
|
||||
|
||||
//throw if null, this will be caught by the catch and a failed returned
|
||||
if (container == null)
|
||||
throw new InvalidOperationException("No container found with id " + id);
|
||||
|
||||
container.Name = name;
|
||||
repository.AddOrUpdate(container);
|
||||
uow.Complete();
|
||||
|
||||
OnRenamedContainer(uow, new SaveEventArgs<EntityContainer>(container, evtMsgs));
|
||||
|
||||
return OperationStatus.Attempt.Succeed(OperationStatusType.Success, evtMsgs, container);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return OperationStatus.Attempt.Fail<EntityContainer>(evtMsgs, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Audit
|
||||
|
||||
@@ -174,6 +174,38 @@ namespace Umbraco.Core.Services
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<OperationStatusType, EntityContainer>> RenameContainer(int id, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IDataTypeContainerRepository>();
|
||||
|
||||
try
|
||||
{
|
||||
var container = repository.Get(id);
|
||||
|
||||
//throw if null, this will be caught by the catch and a failed returned
|
||||
if (container == null)
|
||||
throw new InvalidOperationException("No container found with id " + id);
|
||||
|
||||
container.Name = name;
|
||||
|
||||
repository.AddOrUpdate(container);
|
||||
uow.Complete();
|
||||
|
||||
// fixme - triggering SavedContainer with a different name?!
|
||||
uow.Events.Dispatch(SavedContainer, this, new SaveEventArgs<EntityContainer>(container, evtMsgs), "RenamedContainer");
|
||||
|
||||
return OperationStatus.Attempt.Succeed(OperationStatusType.Success, evtMsgs, container);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return OperationStatus.Attempt.Fail<EntityContainer>(evtMsgs, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -301,7 +333,9 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs<IDataTypeDefinition>(evtMsgs, new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId))))
|
||||
var moveEventInfo = new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId);
|
||||
var moveEventArgs = new MoveEventArgs<IDataTypeDefinition>(evtMsgs, moveEventInfo);
|
||||
if (uow.Events.DispatchCancelable(Moving, this, moveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Fail(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs);
|
||||
@@ -321,7 +355,9 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
moveInfo.AddRange(repository.Move(toMove, container));
|
||||
|
||||
uow.Events.Dispatch(Moved, this, new MoveEventArgs<IDataTypeDefinition>(false, evtMsgs, moveInfo.ToArray()));
|
||||
moveEventArgs.MoveInfoCollection = moveInfo;
|
||||
moveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Moved, this, moveEventArgs);
|
||||
uow.Complete();
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
@@ -345,7 +381,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition)))
|
||||
var saveEventArgs = new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -359,7 +396,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
repository.AddOrUpdate(dataTypeDefinition);
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
Audit(uow, AuditType.Save, "Save DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
|
||||
uow.Complete();
|
||||
}
|
||||
@@ -384,10 +422,11 @@ namespace Umbraco.Core.Services
|
||||
public void Save(IEnumerable<IDataTypeDefinition> dataTypeDefinitions, int userId, bool raiseEvents)
|
||||
{
|
||||
var dataTypeDefinitionsA = dataTypeDefinitions.ToArray();
|
||||
var saveEventArgs = new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitionsA);
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitionsA)))
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -401,7 +440,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinitionsA, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
Audit(uow, AuditType.Save, "Save DataTypeDefinition performed by user", userId, -1);
|
||||
|
||||
uow.Complete();
|
||||
@@ -486,7 +528,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition)))
|
||||
var saveEventArgs = new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -502,7 +545,8 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(dataTypeDefinition); // definition
|
||||
repository.AddOrUpdatePreValues(dataTypeDefinition, values); //prevalues
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
Audit(uow, AuditType.Save, "Save DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
|
||||
|
||||
uow.Complete();
|
||||
@@ -522,7 +566,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IDataTypeDefinition>(dataTypeDefinition)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IDataTypeDefinition>(dataTypeDefinition);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -531,7 +576,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IDataTypeDefinitionRepository>();
|
||||
repository.Delete(dataTypeDefinition);
|
||||
|
||||
uow.Events.Dispatch(Deleted, this, new DeleteEventArgs<IDataTypeDefinition>(dataTypeDefinition, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
Audit(uow, AuditType.Delete, "Delete DataTypeDefinition performed by user", userId, dataTypeDefinition.Id);
|
||||
|
||||
uow.Complete();
|
||||
|
||||
@@ -33,7 +33,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IDomain>(domain, evtMsgs)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IDomain>(domain, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
@@ -43,8 +44,8 @@ namespace Umbraco.Core.Services
|
||||
repository.Delete(domain);
|
||||
uow.Complete();
|
||||
|
||||
var args = new DeleteEventArgs<IDomain>(domain, false, evtMsgs);
|
||||
uow.Events.Dispatch(Deleted, this, args);
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
}
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
@@ -92,7 +93,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IDomain>(domainEntity, evtMsgs)))
|
||||
var saveEventArgs = new SaveEventArgs<IDomain>(domainEntity, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
@@ -101,8 +103,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IDomainRepository>();
|
||||
repository.AddOrUpdate(domainEntity);
|
||||
uow.Complete();
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IDomain>(domainEntity, false, evtMsgs));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
|
||||
@@ -374,11 +374,22 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
|
||||
|
||||
var query = repository.Query;
|
||||
//if the id is System Root, then just get all
|
||||
if (id != Constants.System.Root)
|
||||
query.Where(x => x.Path.SqlContains($",{id},", TextColumnType.NVarchar));
|
||||
{
|
||||
//lookup the path so we can use it in the prefix query below
|
||||
var itemPaths = repository.GetAllPaths(objectTypeId, id).ToArray();
|
||||
if (itemPaths.Length == 0)
|
||||
{
|
||||
totalRecords = 0;
|
||||
return Enumerable.Empty<IUmbracoEntity>();
|
||||
}
|
||||
var itemPath = itemPaths[0].Path;
|
||||
|
||||
query.Where(x => x.Path.SqlStartsWith(itemPath + ",", TextColumnType.NVarchar));
|
||||
}
|
||||
|
||||
IQuery<IUmbracoEntity> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
@@ -407,15 +418,30 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
|
||||
|
||||
var query = uow.Query<IUmbracoEntity>();
|
||||
if (idsA.All(x => x != Constants.System.Root))
|
||||
{
|
||||
//lookup the paths so we can use it in the prefix query below
|
||||
var itemPaths = repository.GetAllPaths(objectTypeId, idsA).ToArray();
|
||||
if (itemPaths.Length == 0)
|
||||
{
|
||||
totalRecords = 0;
|
||||
return Enumerable.Empty<IUmbracoEntity>();
|
||||
}
|
||||
|
||||
var clauses = new List<Expression<Func<IUmbracoEntity, bool>>>();
|
||||
foreach (var id in idsA)
|
||||
{
|
||||
var qid = id;
|
||||
clauses.Add(x => x.Path.SqlContains(string.Format(",{0},", qid), TextColumnType.NVarchar) || x.Path.SqlEndsWith(string.Format(",{0}", qid), TextColumnType.NVarchar));
|
||||
//if the id is root then don't add any clauses
|
||||
if (id != Constants.System.Root)
|
||||
{
|
||||
var itemPath = itemPaths.FirstOrDefault(x => x.Id == id);
|
||||
if (itemPath == null) continue;
|
||||
var path = itemPath.Path;
|
||||
var qid = id;
|
||||
clauses.Add(x => x.Path.SqlStartsWith(path + ",", TextColumnType.NVarchar) || x.Path.SqlEndsWith("," + qid, TextColumnType.NVarchar));
|
||||
}
|
||||
}
|
||||
query.WhereAny(clauses);
|
||||
}
|
||||
@@ -468,7 +494,7 @@ namespace Umbraco.Core.Services
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of the entities at the root, which corresponds to the entities with a Parent Id of -1.
|
||||
/// </summary>
|
||||
@@ -566,13 +592,13 @@ namespace Umbraco.Core.Services
|
||||
return repository.GetAllPaths(objectTypeId, keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IUmbracoEntity"/>
|
||||
/// Gets a collection of <see cref="T:Umbraco.Core.Models.EntityBase.IUmbracoEntity" />
|
||||
/// </summary>
|
||||
/// <param name="objectTypeId">Guid id of the UmbracoObjectType</param>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns>An enumerable list of <see cref="IUmbracoEntity"/> objects</returns>
|
||||
/// <returns>An enumerable list of <see cref="T:Umbraco.Core.Models.EntityBase.IUmbracoEntity" /> objects</returns>
|
||||
public virtual IEnumerable<IUmbracoEntity> GetAll(Guid objectTypeId, params int[] ids)
|
||||
{
|
||||
var umbracoObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(objectTypeId);
|
||||
@@ -692,5 +718,34 @@ namespace Umbraco.Core.Services
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int ReserveId(Guid key)
|
||||
{
|
||||
NodeDto node;
|
||||
using (var scope = UowProvider.ScopeProvider.CreateScope())
|
||||
{
|
||||
var sql = new Sql("SELECT * FROM umbracoNode WHERE uniqueID=@0 AND nodeObjectType=@1", key, Constants.ObjectTypes.IdReservationGuid);
|
||||
node = scope.Database.SingleOrDefault<NodeDto>(sql);
|
||||
if (node != null) throw new InvalidOperationException("An identifier has already been reserved for this Udi.");
|
||||
node = new NodeDto
|
||||
{
|
||||
UniqueId = key,
|
||||
Text = "RESERVED.ID",
|
||||
NodeObjectType = Constants.ObjectTypes.IdReservationGuid,
|
||||
|
||||
CreateDate = DateTime.Now,
|
||||
UserId = 0,
|
||||
ParentId = -1,
|
||||
Level = 1,
|
||||
Path = "-1",
|
||||
SortOrder = 0,
|
||||
Trashed = false
|
||||
};
|
||||
scope.Database.Insert(node);
|
||||
scope.Complete();
|
||||
}
|
||||
return node.NodeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingStylesheet, this, new SaveEventArgs<Stylesheet>(stylesheet)))
|
||||
var saveEventArgs = new SaveEventArgs<Stylesheet>(stylesheet);
|
||||
if (uow.Events.DispatchCancelable(SavingStylesheet, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -72,8 +73,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IStylesheetRepository>();
|
||||
repository.AddOrUpdate(stylesheet);
|
||||
|
||||
uow.Events.Dispatch(SavedStylesheet, this, new SaveEventArgs<Stylesheet>(stylesheet, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedStylesheet, this, saveEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Save, "Save Stylesheet performed by user", userId, -1);
|
||||
uow.Complete();
|
||||
@@ -97,15 +98,16 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if (uow.Events.DispatchCancelable(DeletingStylesheet, this, new DeleteEventArgs<Stylesheet>(stylesheet)))
|
||||
var deleteEventArgs = new DeleteEventArgs<Stylesheet>(stylesheet);
|
||||
if (uow.Events.DispatchCancelable(DeletingStylesheet, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return; // causes rollback
|
||||
}
|
||||
|
||||
repository.Delete(stylesheet);
|
||||
|
||||
uow.Events.Dispatch(DeletedStylesheet, this, new DeleteEventArgs<Stylesheet>(stylesheet, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedStylesheet, this, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete Stylesheet performed by user", userId, -1);
|
||||
uow.Complete();
|
||||
@@ -194,7 +196,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingScript, this, new SaveEventArgs<Script>(script)))
|
||||
var saveEventArgs = new SaveEventArgs<Script>(script);
|
||||
if (uow.Events.DispatchCancelable(SavingScript, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -202,8 +205,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IScriptRepository>();
|
||||
repository.AddOrUpdate(script);
|
||||
|
||||
uow.Events.Dispatch(SavedScript, this, new SaveEventArgs<Script>(script, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedScript, this, saveEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Save, "Save Script performed by user", userId, -1);
|
||||
uow.Complete();
|
||||
@@ -227,15 +230,16 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if (uow.Events.DispatchCancelable(DeletingScript, this, new DeleteEventArgs<Script>(script)))
|
||||
var deleteEventArgs = new DeleteEventArgs<Script>(script);
|
||||
if (uow.Events.DispatchCancelable(DeletingScript, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
repository.Delete(script);
|
||||
|
||||
uow.Events.Dispatch(DeletedScript, this, new DeleteEventArgs<Script>(script, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedScript, this, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete Script performed by user", userId, -1);
|
||||
uow.Complete();
|
||||
@@ -340,7 +344,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingTemplate, this, new SaveEventArgs<ITemplate>(template, true, evtMsgs, additionalData)))
|
||||
var saveEventArgs = new SaveEventArgs<ITemplate>(template, true, evtMsgs, additionalData);
|
||||
if (uow.Events.DispatchCancelable(SavingTemplate, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Fail<OperationStatusType, ITemplate>(OperationStatusType.FailedCancelledByEvent, evtMsgs, template);
|
||||
@@ -348,8 +353,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<ITemplateRepository>();
|
||||
repository.AddOrUpdate(template);
|
||||
|
||||
uow.Events.Dispatch(SavedTemplate, this, new SaveEventArgs<ITemplate>(template, false, evtMsgs));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedTemplate, this, saveEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Save, "Save Template performed by user", userId, template.Id);
|
||||
uow.Complete();
|
||||
@@ -616,16 +621,18 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
if (uow.Events.DispatchCancelable(DeletingTemplate, this, new DeleteEventArgs<ITemplate>(template)))
|
||||
var args = new DeleteEventArgs<ITemplate>(template);
|
||||
if (uow.Events.DispatchCancelable(DeletingTemplate, this, args))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
repository.Delete(template);
|
||||
|
||||
uow.Events.Dispatch(DeletedTemplate, this, new DeleteEventArgs<ITemplate>(template, false));
|
||||
|
||||
args.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedTemplate, this, args);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete Template performed by user", userId, template.Id);
|
||||
uow.Complete();
|
||||
}
|
||||
@@ -806,7 +813,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(CreatingPartialView, this, new NewEventArgs<IPartialView>(partialView, true, partialView.Alias, -1)))
|
||||
var newEventArgs = new NewEventArgs<IPartialView>(partialView, true, partialView.Alias, -1);
|
||||
if (uow.Events.DispatchCancelable(CreatingPartialView, this, newEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return Attempt<IPartialView>.Fail();
|
||||
@@ -815,8 +823,10 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreatePartialViewRepository(partialViewType);
|
||||
if (partialViewContent != null) partialView.Content = partialViewContent;
|
||||
repository.AddOrUpdate(partialView);
|
||||
|
||||
newEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(CreatedPartialView, this, newEventArgs);
|
||||
|
||||
uow.Events.Dispatch(CreatedPartialView, this, new NewEventArgs<IPartialView>(partialView, false, partialView.Alias, -1));
|
||||
Audit(uow, AuditType.Save, $"Save {partialViewType} performed by user", userId, -1);
|
||||
|
||||
uow.Complete();
|
||||
@@ -847,15 +857,16 @@ namespace Umbraco.Core.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
if (uow.Events.DispatchCancelable(DeletingPartialView, this, new DeleteEventArgs<IPartialView>(partialView)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IPartialView>(partialView);
|
||||
if (uow.Events.DispatchCancelable(DeletingPartialView, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return false; // causes rollback
|
||||
return false;
|
||||
}
|
||||
|
||||
repository.Delete(partialView);
|
||||
|
||||
uow.Events.Dispatch(DeletedPartialView, this, new DeleteEventArgs<IPartialView>(partialView, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedPartialView, this, deleteEventArgs);
|
||||
Audit(uow, AuditType.Delete, $"Delete {partialViewType} performed by user", userId, -1);
|
||||
|
||||
uow.Complete();
|
||||
@@ -878,7 +889,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingPartialView, this, new SaveEventArgs<IPartialView>(partialView)))
|
||||
var saveEventArgs = new SaveEventArgs<IPartialView>(partialView);
|
||||
if (uow.Events.DispatchCancelable(SavingPartialView, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return Attempt<IPartialView>.Fail();
|
||||
@@ -886,9 +898,9 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreatePartialViewRepository(partialViewType);
|
||||
repository.AddOrUpdate(partialView);
|
||||
|
||||
saveEventArgs.CanCancel = false;
|
||||
Audit(uow, AuditType.Save, $"Save {partialViewType} performed by user", userId, -1);
|
||||
uow.Events.Dispatch(SavedPartialView, this, new SaveEventArgs<IPartialView>(partialView, false));
|
||||
uow.Events.Dispatch(SavedPartialView, this, saveEventArgs);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
@@ -137,6 +137,23 @@ namespace Umbraco.Core.Services
|
||||
bool SendToPublication(IContent content, int userId = 0);
|
||||
|
||||
IEnumerable<IContent> GetByIds(IEnumerable<int> ids);
|
||||
IEnumerable<IContent> GetByIds(IEnumerable<Guid> ids);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
|
||||
/// that this Content should based on.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that using this method will simply return a new IContent without any identity
|
||||
/// as it has not yet been persisted. It is intended as a shortcut to creating new content objects
|
||||
/// that does not invoke a save operation against the database.
|
||||
/// </remarks>
|
||||
/// <param name="name">Name of the Content object</param>
|
||||
/// <param name="parentId">Id of Parent for the new Content</param>
|
||||
/// <param name="contentTypeAlias">Alias of the <see cref="IContentType"/></param>
|
||||
/// <param name="userId">Optional id of the user creating the content</param>
|
||||
/// <returns><see cref="IContent"/></returns>
|
||||
IContent CreateContent(string name, Guid parentId, string contentTypeAlias, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IContent"/> object using the alias of the <see cref="IContentType"/>
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace Umbraco.Core.Services
|
||||
IEnumerable<EntityContainer> GetContainers(TItem contentType);
|
||||
IEnumerable<EntityContainer> GetContainers(string folderName, int level);
|
||||
Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0);
|
||||
Attempt<OperationStatus<OperationStatusType, EntityContainer>> RenameContainer(int id, string name, int userId = 0);
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> Move(TItem moving, int containerId);
|
||||
Attempt<OperationStatus<MoveOperationStatusType, TItem>> Copy(TItem copying, int containerId);
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Umbraco.Core.Services
|
||||
IEnumerable<EntityContainer> GetContainers(IDataTypeDefinition dataTypeDefinition);
|
||||
IEnumerable<EntityContainer> GetContainers(int[] containerIds);
|
||||
Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0);
|
||||
Attempt<OperationStatus<OperationStatusType, EntityContainer>> RenameContainer(int id, string name, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IDataTypeDefinition"/> by its Name
|
||||
|
||||
@@ -286,5 +286,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="umbracoObjectType"><see cref="UmbracoObjectTypes"/></param>
|
||||
/// <returns>Type of the entity</returns>
|
||||
Type GetEntityType(UmbracoObjectTypes umbracoObjectType);
|
||||
|
||||
/// <summary>
|
||||
/// Reserves an identifier for a key.
|
||||
/// </summary>
|
||||
/// <param name="key">They key.</param>
|
||||
/// <returns>The identifier.</returns>
|
||||
/// <remarks>When a new content or a media is saved with the key, it will have the reserved identifier.</remarks>
|
||||
int ReserveId(Guid key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,5 +136,11 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="language"><see cref="ILanguage"/> to delete</param>
|
||||
/// <param name="userId">Optional id of the user deleting the language</param>
|
||||
void Delete(ILanguage language, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full dictionary key map.
|
||||
/// </summary>
|
||||
/// <returns>The full dictionary key map.</returns>
|
||||
Dictionary<string, Guid> GetDictionaryItemKeyMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,23 @@ namespace Umbraco.Core.Services
|
||||
int CountDescendants(int parentId, string mediaTypeAlias = null);
|
||||
|
||||
IEnumerable<IMedia> GetByIds(IEnumerable<int> ids);
|
||||
IEnumerable<IMedia> GetByIds(IEnumerable<Guid> ids);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
|
||||
/// that this Media should based on.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that using this method will simply return a new IMedia without any identity
|
||||
/// as it has not yet been persisted. It is intended as a shortcut to creating new media objects
|
||||
/// that does not invoke a save operation against the database.
|
||||
/// </remarks>
|
||||
/// <param name="name">Name of the Media object</param>
|
||||
/// <param name="parentId">Id of Parent for the new Media item</param>
|
||||
/// <param name="mediaTypeAlias">Alias of the <see cref="IMediaType"/></param>
|
||||
/// <param name="userId">Optional id of the user creating the media item</param>
|
||||
/// <returns><see cref="IMedia"/></returns>
|
||||
IMedia CreateMedia(string name, Guid parentId, string mediaTypeAlias, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
|
||||
|
||||
@@ -95,10 +95,16 @@ namespace Umbraco.Core.Services
|
||||
IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType);
|
||||
|
||||
/// <summary>
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method which can be
|
||||
/// used during Member creation.
|
||||
/// </summary>
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// Members if they choose to. </remarks>
|
||||
/// <remarks>
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// this will not work for updating members in most cases (depends on your membership provider settings)
|
||||
///
|
||||
/// It is preferred to use the membership APIs for working with passwords, in the near future this method will be obsoleted
|
||||
/// and the ASP.NET Identity APIs should be used instead.
|
||||
/// </remarks>
|
||||
/// <param name="member">The Member to save the password for</param>
|
||||
/// <param name="password">The password to encrypt and save</param>
|
||||
void SavePassword(IMember member, string password);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -24,14 +26,40 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="userState"></param>
|
||||
/// <param name="userGroups"></param>
|
||||
/// <param name="includeUserGroups">
|
||||
/// A filter to only include user that belong to these user groups
|
||||
/// </param>
|
||||
/// <param name="excludeUserGroups">
|
||||
/// A filter to only include users that do not belong to these user groups
|
||||
/// </param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUser> GetAll(long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection,
|
||||
UserState[] userState = null,
|
||||
string[] includeUserGroups = null,
|
||||
string[] excludeUserGroups = null,
|
||||
IQuery<IUser> filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Get paged users
|
||||
/// </summary>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="userState"></param>
|
||||
/// <param name="userGroups">
|
||||
/// A filter to only include user that belong to these user groups
|
||||
/// </param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IUser> GetAll(long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection,
|
||||
UserState[] userState = null,
|
||||
string[] userGroups = null,
|
||||
string filter = "");
|
||||
string filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
|
||||
|
||||
@@ -10,8 +10,9 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
private readonly IScopeUnitOfWorkProvider _uowProvider;
|
||||
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim();
|
||||
private readonly Dictionary<int, Guid> _id2Key = new Dictionary<int, Guid>();
|
||||
private readonly Dictionary<Guid, int> _key2Id = new Dictionary<Guid, int>();
|
||||
|
||||
private readonly Dictionary<int, TypedId<Guid>> _id2Key = new Dictionary<int, TypedId<Guid>>();
|
||||
private readonly Dictionary<Guid, TypedId<int>> _key2Id = new Dictionary<Guid, TypedId<int>>();
|
||||
|
||||
public IdkMap(IScopeUnitOfWorkProvider uowProvider)
|
||||
{
|
||||
@@ -23,11 +24,11 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public Attempt<int> GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
int id;
|
||||
TypedId<int> id;
|
||||
try
|
||||
{
|
||||
_locker.EnterReadLock();
|
||||
if (_key2Id.TryGetValue(key, out id)) return Attempt.Succeed(id);
|
||||
if (_key2Id.TryGetValue(key, out id) && id.UmbracoObjectType == umbracoObjectType) return Attempt.Succeed(id.Id);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -44,13 +45,16 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (val == null) return Attempt<int>.Fail();
|
||||
id = val.Value;
|
||||
|
||||
// cache reservations, when something is saved this cache is cleared anyways
|
||||
//if (umbracoObjectType == UmbracoObjectTypes.IdReservation)
|
||||
// Attempt.Succeed(val.Value);
|
||||
|
||||
try
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
_id2Key[id] = key;
|
||||
_key2Id[key] = id;
|
||||
_id2Key[val.Value] = new TypedId<Guid>(key, umbracoObjectType);
|
||||
_key2Id[key] = new TypedId<int>(val.Value, umbracoObjectType);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -58,7 +62,7 @@ namespace Umbraco.Core.Services
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
|
||||
return Attempt.Succeed(id);
|
||||
return Attempt.Succeed(val.Value);
|
||||
}
|
||||
|
||||
public Attempt<int> GetIdForUdi(Udi udi)
|
||||
@@ -73,11 +77,11 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public Attempt<Guid> GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
Guid key;
|
||||
TypedId<Guid> key;
|
||||
try
|
||||
{
|
||||
_locker.EnterReadLock();
|
||||
if (_id2Key.TryGetValue(id, out key)) return Attempt.Succeed(key);
|
||||
if (_id2Key.TryGetValue(id, out key) && key.UmbracoObjectType == umbracoObjectType) return Attempt.Succeed(key.Id);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -94,13 +98,16 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (val == null) return Attempt<Guid>.Fail();
|
||||
key = val.Value;
|
||||
|
||||
// cache reservations, when something is saved this cache is cleared anyways
|
||||
//if (umbracoObjectType == UmbracoObjectTypes.IdReservation)
|
||||
// Attempt.Succeed(val.Value);
|
||||
|
||||
try
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
_id2Key[id] = key;
|
||||
_key2Id[key] = id;
|
||||
_id2Key[id] = new TypedId<Guid>(val.Value, umbracoObjectType); ;
|
||||
_key2Id[val.Value] = new TypedId<int>();
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -108,7 +115,7 @@ namespace Umbraco.Core.Services
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
|
||||
return Attempt.Succeed(key);
|
||||
return Attempt.Succeed(val.Value);
|
||||
}
|
||||
|
||||
private static Guid GetNodeObjectTypeGuid(UmbracoObjectTypes umbracoObjectType)
|
||||
@@ -139,10 +146,10 @@ namespace Umbraco.Core.Services
|
||||
try
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
Guid key;
|
||||
TypedId<Guid> key;
|
||||
if (_id2Key.TryGetValue(id, out key) == false) return;
|
||||
_id2Key.Remove(id);
|
||||
_key2Id.Remove(key);
|
||||
_key2Id.Remove(key.Id);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -156,9 +163,9 @@ namespace Umbraco.Core.Services
|
||||
try
|
||||
{
|
||||
_locker.EnterWriteLock();
|
||||
int id;
|
||||
TypedId<int> id;
|
||||
if (_key2Id.TryGetValue(key, out id) == false) return;
|
||||
_id2Key.Remove(id);
|
||||
_id2Key.Remove(id.Id);
|
||||
_key2Id.Remove(key);
|
||||
}
|
||||
finally
|
||||
@@ -167,5 +174,27 @@ namespace Umbraco.Core.Services
|
||||
_locker.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
private struct TypedId<T>
|
||||
{
|
||||
private readonly T _id;
|
||||
private readonly UmbracoObjectTypes _umbracoObjectType;
|
||||
|
||||
public T Id
|
||||
{
|
||||
get { return _id; }
|
||||
}
|
||||
|
||||
public UmbracoObjectTypes UmbracoObjectType
|
||||
{
|
||||
get { return _umbracoObjectType; }
|
||||
}
|
||||
|
||||
public TypedId(T id, UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
_umbracoObjectType = umbracoObjectType;
|
||||
_id = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,8 @@ namespace Umbraco.Core.Services
|
||||
item.Translations = translations;
|
||||
}
|
||||
|
||||
if (uow.Events.DispatchCancelable(SavingDictionaryItem, this, new SaveEventArgs<IDictionaryItem>(item)))
|
||||
var saveEventArgs = new SaveEventArgs<IDictionaryItem>(item);
|
||||
if (uow.Events.DispatchCancelable(SavingDictionaryItem, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return item;
|
||||
@@ -91,8 +92,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
// ensure the lazy Language callback is assigned
|
||||
EnsureDictionaryItemLanguageCallback(item);
|
||||
|
||||
uow.Events.Dispatch(SavedDictionaryItem, this, new SaveEventArgs<IDictionaryItem>(item));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedDictionaryItem, this, saveEventArgs);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -257,7 +258,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingDictionaryItem, this, new DeleteEventArgs<IDictionaryItem>(dictionaryItem)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IDictionaryItem>(dictionaryItem);
|
||||
if (uow.Events.DispatchCancelable(DeletingDictionaryItem, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -265,8 +267,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IDictionaryRepository>();
|
||||
repository.Delete(dictionaryItem);
|
||||
|
||||
uow.Events.Dispatch(DeletedDictionaryItem, this, new DeleteEventArgs<IDictionaryItem>(dictionaryItem, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedDictionaryItem, this, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete DictionaryItem performed by user", userId, dictionaryItem.Id);
|
||||
|
||||
@@ -338,7 +340,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingLanguage, this, new SaveEventArgs<ILanguage>(language)))
|
||||
var saveEventArgs = new SaveEventArgs<ILanguage>(language);
|
||||
if (uow.Events.DispatchCancelable(SavingLanguage, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -346,8 +349,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<ILanguageRepository>();
|
||||
repository.AddOrUpdate(language);
|
||||
|
||||
uow.Events.Dispatch(SavedLanguage, this, new SaveEventArgs<ILanguage>(language, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedLanguage, this, saveEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Save, "Save Language performed by user", userId, language.Id);
|
||||
|
||||
@@ -364,7 +367,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingLanguage, this, new DeleteEventArgs<ILanguage>(language)))
|
||||
var deleteEventArgs = new DeleteEventArgs<ILanguage>(language);
|
||||
if (uow.Events.DispatchCancelable(DeletingLanguage, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -374,7 +378,8 @@ namespace Umbraco.Core.Services
|
||||
//NOTE: There isn't any constraints in the db, so possible references aren't deleted
|
||||
repository.Delete(language);
|
||||
|
||||
uow.Events.Dispatch(DeletedLanguage, this, new DeleteEventArgs<ILanguage>(language, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedLanguage, this, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete Language performed by user", userId, language.Id);
|
||||
|
||||
@@ -404,6 +409,15 @@ namespace Umbraco.Core.Services
|
||||
trans.GetLanguage = GetLanguageById;
|
||||
}
|
||||
|
||||
public Dictionary<string, Guid> GetDictionaryItemKeyMap()
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = RepositoryFactory.CreateDictionaryRepository(uow);
|
||||
return repository.GetDictionaryItemKeyMap();
|
||||
}
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
|
||||
@@ -101,7 +101,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMacro>(macro)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IMacro>(macro);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -109,8 +110,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IMacroRepository>();
|
||||
repository.Delete(macro);
|
||||
|
||||
uow.Events.Dispatch(Deleted, this, new DeleteEventArgs<IMacro>(macro, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
Audit(uow, AuditType.Delete, "Delete Macro performed by user", userId, -1);
|
||||
|
||||
uow.Complete();
|
||||
@@ -126,7 +127,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMacro>(macro)))
|
||||
var saveEventArgs = new SaveEventArgs<IMacro>(macro);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -139,8 +141,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IMacroRepository>();
|
||||
repository.AddOrUpdate(macro);
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMacro>(macro, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
Audit(uow, AuditType.Save, "Save Macro performed by user", userId, -1);
|
||||
|
||||
uow.Complete();
|
||||
|
||||
@@ -22,15 +22,13 @@ namespace Umbraco.Core.Services
|
||||
public class MediaService : ScopeRepositoryService, IMediaService, IMediaServiceOperations
|
||||
{
|
||||
private readonly MediaFileSystem _mediaFileSystem;
|
||||
private readonly IdkMap _idkMap;
|
||||
|
||||
#region Constructors
|
||||
|
||||
public MediaService(IScopeUnitOfWorkProvider provider, MediaFileSystem mediaFileSystem, ILogger logger, IEventMessagesFactory eventMessagesFactory, IdkMap idkMap)
|
||||
public MediaService(IScopeUnitOfWorkProvider provider, MediaFileSystem mediaFileSystem, ILogger logger, IEventMessagesFactory eventMessagesFactory)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_mediaFileSystem = mediaFileSystem;
|
||||
_idkMap = idkMap;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -94,6 +92,26 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Create
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IMedia"/> object using the alias of the <see cref="IMediaType"/>
|
||||
/// that this Media should based on.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that using this method will simply return a new IMedia without any identity
|
||||
/// as it has not yet been persisted. It is intended as a shortcut to creating new media objects
|
||||
/// that does not invoke a save operation against the database.
|
||||
/// </remarks>
|
||||
/// <param name="name">Name of the Media object</param>
|
||||
/// <param name="parentId">Id of Parent for the new Media item</param>
|
||||
/// <param name="mediaTypeAlias">Alias of the <see cref="IMediaType"/></param>
|
||||
/// <param name="userId">Optional id of the user creating the media item</param>
|
||||
/// <returns><see cref="IMedia"/></returns>
|
||||
public IMedia CreateMedia(string name, Guid parentId, string mediaTypeAlias, int userId = 0)
|
||||
{
|
||||
var parent = GetById(parentId);
|
||||
return CreateMedia(name, parent, mediaTypeAlias, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="IMedia"/> object of a specified media type.
|
||||
/// </summary>
|
||||
@@ -266,7 +284,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (withIdentity)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMedia>(media), this))
|
||||
var saveEventArgs = new SaveEventArgs<IMedia>(media);
|
||||
if (Saving.IsRaisedEventCancelled(saveEventArgs, this))
|
||||
{
|
||||
media.WasCancelled = true;
|
||||
return;
|
||||
@@ -275,11 +294,13 @@ namespace Umbraco.Core.Services
|
||||
var repo = uow.CreateRepository<IMediaRepository>();
|
||||
repo.AddOrUpdate(media);
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(media, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
uow.Events.Dispatch(TreeChanged, this, new TreeChange<IMedia>(media, TreeChangeTypes.RefreshNode).ToEventArgs());
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(Created, this, new NewEventArgs<IMedia>(media, false, media.ContentType.Alias, parent));
|
||||
newArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Created, this, newArgs);
|
||||
|
||||
var msg = withIdentity
|
||||
? "Media '{0}' was created with Id {1}"
|
||||
@@ -332,15 +353,32 @@ namespace Umbraco.Core.Services
|
||||
/// <returns><see cref="IMedia"/></returns>
|
||||
public IMedia GetById(Guid key)
|
||||
{
|
||||
// the repository implements a cache policy on int identifiers, not guids,
|
||||
// and we are not changing it now, but we still would like to rely on caching
|
||||
// instead of running a full query against the database, so relying on the
|
||||
// id-key map, which is fast.
|
||||
|
||||
var a = _idkMap.GetIdForKey(key, UmbracoObjectTypes.Media);
|
||||
return a.Success ? GetById(a.Result) : null;
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.MediaTree);
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.Get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMedia"/> object by Id
|
||||
/// </summary>
|
||||
/// <param name="ids">Ids of the Media to retrieve</param>
|
||||
/// <returns><see cref="IMedia"/></returns>
|
||||
public IEnumerable<IMedia> GetByIds(IEnumerable<Guid> ids)
|
||||
{
|
||||
var idsA = ids.ToArray();
|
||||
if (idsA.Length == 0) return Enumerable.Empty<IMedia>();
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.MediaTree);
|
||||
var repository = uow.CreateRepository<IMediaRepository>();
|
||||
return repository.GetAll(idsA);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of <see cref="IMedia"/> objects by the Id of the <see cref="IMediaType"/>
|
||||
/// </summary>
|
||||
@@ -594,7 +632,16 @@ namespace Umbraco.Core.Services
|
||||
var query = uow.Query<IMedia>();
|
||||
//if the id is System Root, then just get all
|
||||
if (id != Constants.System.Root)
|
||||
query.Where(x => x.Path.SqlContains($",{id},", TextColumnType.NVarchar));
|
||||
{
|
||||
var entityRepository = uow.CreateRepository<IEntityRepository>();
|
||||
var mediaPath = entityRepository.GetAllPaths(Constants.ObjectTypes.MediaGuid, id).ToArray();
|
||||
if (mediaPath.Length == 0)
|
||||
{
|
||||
totalChildren = 0;
|
||||
return Enumerable.Empty<IMedia>();
|
||||
}
|
||||
query.Where(x => x.Path.SqlStartsWith(mediaPath[0] + ",", TextColumnType.NVarchar));
|
||||
}
|
||||
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
}
|
||||
@@ -750,7 +797,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(media, evtMsgs)))
|
||||
var saveEventArgs = new SaveEventArgs<IMedia>(media, evtMsgs);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
@@ -770,7 +818,10 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(media);
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(media, false, evtMsgs));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
var changeType = isNew ? TreeChangeTypes.RefreshBranch : TreeChangeTypes.RefreshNode;
|
||||
uow.Events.Dispatch(TreeChanged, this, new TreeChange<IMedia>(media, changeType).ToEventArgs());
|
||||
Audit(uow, AuditType.Save, "Save Media performed by user", userId, media.Id);
|
||||
@@ -805,6 +856,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IMedia>(mediasA, evtMsgs);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(mediasA, evtMsgs)))
|
||||
{
|
||||
uow.Complete();
|
||||
@@ -824,7 +876,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(mediasA, false, evtMsgs));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
uow.Events.Dispatch(TreeChanged, this, treeChanges.ToEventArgs());
|
||||
Audit(uow, AuditType.Save, "Bulk Save media performed by user", userId == -1 ? 0 : userId, Constants.System.Root);
|
||||
|
||||
@@ -954,7 +1009,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
private void DeleteVersions(IScopeUnitOfWork uow, ref IMediaRepository repository, int id, DateTime versionDate, int userId = 0)
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, dateToRetain: versionDate)))
|
||||
var args = new DeleteRevisionsEventArgs(id, dateToRetain: versionDate);
|
||||
if (uow.Events.DispatchCancelable(DeletingVersions, this, args))
|
||||
return;
|
||||
|
||||
if (repository == null)
|
||||
@@ -964,7 +1020,8 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
repository.DeleteVersions(id, versionDate);
|
||||
|
||||
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate));
|
||||
args.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedVersions, this, args);
|
||||
Audit(uow, AuditType.Delete, "Delete Media by version date performed by user", userId, Constants.System.Root);
|
||||
}
|
||||
|
||||
@@ -980,7 +1037,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, /*specificVersion:*/ versionId)))
|
||||
var args = new DeleteRevisionsEventArgs(id, /*specificVersion:*/ versionId);
|
||||
if (uow.Events.DispatchCancelable(DeletingVersions, this, args))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -1000,7 +1058,8 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
repository.DeleteVersion(versionId);
|
||||
|
||||
uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, /*specificVersion:*/ versionId));
|
||||
args.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedVersions, this, args);
|
||||
Audit(uow, AuditType.Delete, "Delete Media by version performed by user", userId, Constants.System.Root);
|
||||
|
||||
uow.Complete();
|
||||
@@ -1089,7 +1148,9 @@ namespace Umbraco.Core.Services
|
||||
if (parentId != Constants.System.Root && (parent == null || parent.Trashed))
|
||||
throw new InvalidOperationException("Parent does not exist or is trashed."); // causes rollback
|
||||
|
||||
if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, media.Path, parentId))))
|
||||
var moveEventInfo = new MoveEventInfo<IMedia>(media, media.Path, parentId);
|
||||
var moveEventArgs = new MoveEventArgs<IMedia>(moveEventInfo);
|
||||
if (uow.Events.DispatchCancelable(Moving, this, moveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -1108,7 +1169,9 @@ namespace Umbraco.Core.Services
|
||||
.Select(x => new MoveEventInfo<IMedia>(x.Item1, x.Item2, x.Item1.ParentId))
|
||||
.ToArray();
|
||||
|
||||
uow.Events.Dispatch(Moved, this, new MoveEventArgs<IMedia>(false, moveInfo));
|
||||
moveEventArgs.MoveInfoCollection = moveInfo;
|
||||
moveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Moved, this, moveEventArgs);
|
||||
Audit(uow, AuditType.Move, "Move Media performed by user", userId, media.Id);
|
||||
uow.Complete();
|
||||
}
|
||||
@@ -1183,7 +1246,8 @@ namespace Umbraco.Core.Services
|
||||
// are managed by Delete, and not here.
|
||||
|
||||
// no idea what those events are for, keep a simplified version
|
||||
if (uow.Events.DispatchCancelable(EmptyingRecycleBin, this, new RecycleBinEventArgs(nodeObjectType)))
|
||||
var args = new RecycleBinEventArgs(nodeObjectType);
|
||||
if (uow.Events.DispatchCancelable(EmptyingRecycleBin, this, args))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -1198,7 +1262,8 @@ namespace Umbraco.Core.Services
|
||||
deleted.Add(media);
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, true));
|
||||
args.CanCancel = false;
|
||||
uow.Events.Dispatch(EmptiedRecycleBin, this, args);
|
||||
uow.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IMedia>(x, TreeChangeTypes.Remove)).ToEventArgs());
|
||||
Audit(uow, AuditType.Delete, "Empty Media Recycle Bin performed by user", 0, Constants.System.RecycleBinMedia);
|
||||
uow.Complete();
|
||||
@@ -1224,7 +1289,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMedia>(itemsA)))
|
||||
var args = new SaveEventArgs<IMedia>(itemsA);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, args))
|
||||
{
|
||||
uow.Complete();
|
||||
return false;
|
||||
@@ -1254,7 +1320,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMedia>(saved, false));
|
||||
{
|
||||
args.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, args);
|
||||
}
|
||||
uow.Events.Dispatch(TreeChanged, this, saved.Select(x => new TreeChange<IMedia>(x, TreeChangeTypes.RefreshNode)).ToEventArgs());
|
||||
Audit(uow, AuditType.Sort, "Sorting Media performed by user", userId, 0);
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Media service extension methods
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Many of these have to do with UDI lookups but we don't need to add these methods to the service interface since a UDI is just a GUID
|
||||
/// and the services already support GUIDs
|
||||
/// </remarks>
|
||||
public static class MediaServiceExtensions
|
||||
{
|
||||
public static IEnumerable<IMedia> GetByIds(this IMediaService mediaService, IEnumerable<Udi> ids)
|
||||
{
|
||||
var guids = new List<GuidUdi>();
|
||||
foreach (var udi in ids)
|
||||
{
|
||||
var guidUdi = udi as GuidUdi;
|
||||
if (guidUdi == null)
|
||||
throw new InvalidOperationException("The UDI provided isn't of type " + typeof(GuidUdi) + " which is required by media");
|
||||
guids.Add(guidUdi);
|
||||
}
|
||||
|
||||
return mediaService.GetByIds(guids.Select(x => x.Guid));
|
||||
}
|
||||
|
||||
public static IMedia CreateMedia(this IMediaService mediaService, string name, Udi parentId, string mediaTypeAlias, int userId = 0)
|
||||
{
|
||||
var guidUdi = parentId as GuidUdi;
|
||||
if (guidUdi == null)
|
||||
throw new InvalidOperationException("The UDI provided isn't of type " + typeof(GuidUdi) + " which is required by media");
|
||||
var parent = mediaService.GetById(guidUdi.Guid);
|
||||
return mediaService.CreateMedia(name, parent, mediaTypeAlias, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMemberGroup>(memberGroup)))
|
||||
var saveEventArgs = new SaveEventArgs<IMemberGroup>(memberGroup);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -89,7 +90,10 @@ namespace Umbraco.Core.Services
|
||||
uow.Complete();
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMemberGroup>(memberGroup, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +101,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMemberGroup>(memberGroup)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IMemberGroup>(memberGroup);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -106,8 +111,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMemberGroupRepository>();
|
||||
repository.Delete(memberGroup);
|
||||
uow.Complete();
|
||||
|
||||
uow.Events.Dispatch(Deleted, this, new DeleteEventArgs<IMemberGroup>(memberGroup, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Umbraco.Core.Services
|
||||
private readonly IMemberGroupService _memberGroupService;
|
||||
private readonly MediaFileSystem _mediaFileSystem;
|
||||
|
||||
//only for unit tests!
|
||||
internal MembershipProviderBase MembershipProvider { get; set; }
|
||||
|
||||
#region Constructor
|
||||
|
||||
public MemberService(IScopeUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService, MediaFileSystem mediaFileSystem)
|
||||
@@ -190,7 +193,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return CreateMemberWithIdentity(username, email, username, "", memberTypeAlias);
|
||||
}
|
||||
|
||||
|
||||
public IMember CreateMemberWithIdentity(string username, string email, string memberTypeAlias, bool isApproved)
|
||||
{
|
||||
return CreateMemberWithIdentity(username, email, username, "", memberTypeAlias, isApproved);
|
||||
@@ -200,11 +203,11 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
return CreateMemberWithIdentity(username, email, name, "", memberTypeAlias);
|
||||
}
|
||||
|
||||
|
||||
public IMember CreateMemberWithIdentity(string username, string email, string name, string memberTypeAlias, bool isApproved)
|
||||
{
|
||||
return CreateMemberWithIdentity(username, email, name, "", memberTypeAlias, isApproved);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
@@ -239,7 +242,7 @@ namespace Umbraco.Core.Services
|
||||
public IMember CreateMemberWithIdentity(string username, string email, IMemberType memberType)
|
||||
{
|
||||
return CreateMemberWithIdentity(username, email, username, "", memberType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
@@ -258,7 +261,7 @@ namespace Umbraco.Core.Services
|
||||
public IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType)
|
||||
{
|
||||
return CreateMemberWithIdentity(username, email, name, "", memberType);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and persists a Member
|
||||
@@ -315,7 +318,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (withIdentity)
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMember>(member)))
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(member);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
member.WasCancelled = true;
|
||||
return;
|
||||
@@ -324,7 +328,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
repository.AddOrUpdate(member);
|
||||
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMember>(member, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
|
||||
uow.Events.Dispatch(Created, this, new NewEventArgs<IMember>(member, false, member.ContentType.Alias, -1));
|
||||
@@ -868,7 +873,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMember>(member)))
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(member);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -885,7 +891,10 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(member);
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMember>(member, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
Audit(uow, AuditType.Save, "Save Member performed by user", 0, member.Id);
|
||||
|
||||
uow.Complete();
|
||||
@@ -904,7 +913,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs<IMember>(membersA)))
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(membersA);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -916,7 +926,10 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdate(member);
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(Saved, this, new SaveEventArgs<IMember>(membersA, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
}
|
||||
Audit(uow, AuditType.Save, "Save Member items performed by user", 0, -1);
|
||||
|
||||
uow.Complete();
|
||||
@@ -935,7 +948,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMember>(member)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IMember>(member);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -943,18 +957,21 @@ namespace Umbraco.Core.Services
|
||||
|
||||
uow.WriteLock(Constants.Locks.MemberTree);
|
||||
var repository = uow.CreateRepository<IMemberRepository>();
|
||||
DeleteLocked(uow, repository, member);
|
||||
DeleteLocked(uow, repository, member, deleteEventArgs);
|
||||
|
||||
Audit(uow, AuditType.Delete, "Delete Member performed by user", 0, member.Id);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteLocked(IScopeUnitOfWork uow, IMemberRepository repository, IMember member)
|
||||
private void DeleteLocked(IScopeUnitOfWork uow, IMemberRepository repository, IMember member, DeleteEventArgs<IMember> args = null)
|
||||
{
|
||||
// a member has no descendants
|
||||
repository.Delete(member);
|
||||
var args = new DeleteEventArgs<IMember>(member, false); // raise event & get flagged files
|
||||
repository.Delete(member);
|
||||
if (args == null)
|
||||
args = new DeleteEventArgs<IMember>(member, false); // raise event & get flagged files
|
||||
else
|
||||
args.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, args);
|
||||
|
||||
// fixme - this is MOOT because the event will not trigger immediately
|
||||
@@ -1179,7 +1196,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
if (member == null) throw new ArgumentNullException(nameof(member));
|
||||
|
||||
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
var provider = MembershipProvider ?? MembershipProviderExtensions.GetMembersMembershipProvider();
|
||||
if (provider.IsUmbracoMembershipProvider())
|
||||
provider.ChangePassword(member.Username, "", password); // this is actually updating the password
|
||||
else
|
||||
@@ -1294,7 +1311,8 @@ namespace Umbraco.Core.Services
|
||||
var query = uow.Query<IMember>().Where(x => x.ContentTypeId == memberTypeId);
|
||||
var members = repository.GetByQuery(query).ToArray();
|
||||
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs<IMember>(members)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IMember>(members);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -1335,12 +1353,12 @@ namespace Umbraco.Core.Services
|
||||
return GetMemberType(uow, memberTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fixme - this should not be here, or???
|
||||
public string GetDefaultMemberType()
|
||||
{
|
||||
return Current.Services.MemberTypeService.GetDefault();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -17,9 +17,8 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
public OperationStatus(TStatusType statusType, EventMessages eventMessages)
|
||||
{
|
||||
if (eventMessages == null) throw new ArgumentNullException(nameof(eventMessages));
|
||||
StatusType = statusType;
|
||||
EventMessages = eventMessages;
|
||||
EventMessages = eventMessages ?? throw new ArgumentNullException(nameof(eventMessages));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,6 +33,7 @@ namespace Umbraco.Core.Services
|
||||
public EventMessages EventMessages { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Represents the status of a service operation that manages (processes, produces...) a value.
|
||||
/// </summary>
|
||||
@@ -42,8 +42,9 @@ namespace Umbraco.Core.Services
|
||||
public class OperationStatus<TStatusType, TValue> : OperationStatus<TStatusType>
|
||||
where TStatusType : struct
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus{TStatusType, TValue}"/> class with a status type and event messages.
|
||||
/// Initializes a new instance of the <see cref="T:Umbraco.Core.Services.OperationStatus`2" /> class with a status type and event messages.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
@@ -51,8 +52,9 @@ namespace Umbraco.Core.Services
|
||||
: base(statusType, eventMessages)
|
||||
{ }
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus{TStatusType, TValue}"/> class with a status type, event messages and a value.
|
||||
/// Initializes a new instance of the <see cref="T:Umbraco.Core.Services.OperationStatus`2" /> class with a status type, event messages and a value.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
@@ -69,14 +71,16 @@ namespace Umbraco.Core.Services
|
||||
public TValue Value { get; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Represents the default operation status.
|
||||
/// </summary>
|
||||
/// <remarks>Also provides static helper methods to create operation statuses.</remarks>
|
||||
public class OperationStatus : OperationStatus<OperationStatusType>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OperationStatus"/> class with a status and event messages.
|
||||
/// Initializes a new instance of the <see cref="T:Umbraco.Core.Services.OperationStatus" /> class with a status and event messages.
|
||||
/// </summary>
|
||||
/// <param name="statusType">The status of the operation.</param>
|
||||
/// <param name="eventMessages">Event messages produced by the operation.</param>
|
||||
|
||||
@@ -129,15 +129,20 @@ namespace Umbraco.Core.Services
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, entry);
|
||||
}
|
||||
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs), this))
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs, entry); // causes rollback
|
||||
var saveEventArgs = new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Commit();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs, entry);
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(entry);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs, entry);
|
||||
}
|
||||
|
||||
@@ -163,14 +168,19 @@ namespace Umbraco.Core.Services
|
||||
|
||||
entry.RemoveRule(existingRule);
|
||||
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs), this))
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs); // causes rollback
|
||||
var saveEventArgs = new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Commit();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(entry);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
@@ -181,21 +191,23 @@ namespace Umbraco.Core.Services
|
||||
public Attempt<OperationStatus> Save(PublicAccessEntry entry)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
if (Saving.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
{
|
||||
uow.Commit();
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
var repo = uow.CreateRepository<IPublicAccessRepository>();
|
||||
repo.AddOrUpdate(entry);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
@@ -206,21 +218,23 @@ namespace Umbraco.Core.Services
|
||||
public Attempt<OperationStatus> Delete(PublicAccessEntry entry)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
if (Deleting.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<PublicAccessEntry>(entry, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Attempt.Cancel(evtMsgs);
|
||||
}
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var deleteEventArgs = new DeleteEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (uow.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
{
|
||||
uow.Commit();
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var repo = uow.CreateRepository<IPublicAccessRepository>();
|
||||
repo.Delete(entry);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
Deleted.RaiseEvent(new DeleteEventArgs<PublicAccessEntry>(entry, false, evtMsgs), this);
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
return OperationStatus.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
|
||||
@@ -55,10 +55,28 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public static bool HasAccess(this IPublicAccessService publicAccessService, string path, MembershipUser member, RoleProvider roleProvider)
|
||||
{
|
||||
return publicAccessService.HasAccess(path, member.UserName, roleProvider.GetRolesForUser);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the member with the specified username has access to the path which is also based on the passed in roles for the member
|
||||
/// </summary>
|
||||
/// <param name="publicAccessService"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="rolesCallback">A callback to retrieve the roles for this member</param>
|
||||
/// <returns></returns>
|
||||
public static bool HasAccess(this IPublicAccessService publicAccessService, string path, string username, Func<string, IEnumerable<string>> rolesCallback)
|
||||
{
|
||||
if (rolesCallback == null) throw new ArgumentNullException("roles");
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
|
||||
if (string.IsNullOrWhiteSpace(path)) throw new ArgumentException("Value cannot be null or whitespace.", "path");
|
||||
|
||||
var entry = publicAccessService.GetEntryForContent(path.EnsureEndsWith(path));
|
||||
if (entry == null) return true;
|
||||
|
||||
var roles = roleProvider.GetRolesForUser(member.UserName);
|
||||
var roles = rolesCallback(username);
|
||||
|
||||
return entry.Rules.Any(x => x.RuleType == Constants.Conventions.PublicAccess.MemberRoleRuleType
|
||||
&& roles.Contains(x.RuleValue));
|
||||
}
|
||||
|
||||
@@ -400,7 +400,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingRelation, this, new SaveEventArgs<IRelation>(relation)))
|
||||
var saveEventArgs = new SaveEventArgs<IRelation>(relation);
|
||||
if (uow.Events.DispatchCancelable(SavingRelation, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return relation; // fixme - returning sth that does not exist here?!
|
||||
@@ -408,7 +409,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
repository.AddOrUpdate(relation);
|
||||
uow.Events.Dispatch(SavedRelation, this, new SaveEventArgs<IRelation>(relation, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedRelation, this, saveEventArgs);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
@@ -432,7 +434,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingRelation, this, new SaveEventArgs<IRelation>(relation)))
|
||||
var saveEventArgs = new SaveEventArgs<IRelation>(relation);
|
||||
if (uow.Events.DispatchCancelable(SavingRelation, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return relation; // fixme - returning sth that does not exist here?!
|
||||
@@ -440,8 +443,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
repository.AddOrUpdate(relation);
|
||||
|
||||
uow.Events.Dispatch(SavedRelation, this, new SaveEventArgs<IRelation>(relation, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedRelation, this, saveEventArgs);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
@@ -560,7 +563,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingRelation, this, new SaveEventArgs<IRelation>(relation)))
|
||||
var saveEventArgs = new SaveEventArgs<IRelation>(relation);
|
||||
if (uow.Events.DispatchCancelable(SavingRelation, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -569,8 +573,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
repository.AddOrUpdate(relation);
|
||||
uow.Complete();
|
||||
|
||||
uow.Events.Dispatch(SavedRelation, this, new SaveEventArgs<IRelation>(relation, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedRelation, this, saveEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -582,7 +586,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(SavingRelationType, this, new SaveEventArgs<IRelationType>(relationType)))
|
||||
var saveEventArgs = new SaveEventArgs<IRelationType>(relationType);
|
||||
if (uow.Events.DispatchCancelable(SavingRelationType, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -591,8 +596,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IRelationTypeRepository>();
|
||||
repository.AddOrUpdate(relationType);
|
||||
uow.Complete();
|
||||
|
||||
uow.Events.Dispatch(SavedRelationType, this, new SaveEventArgs<IRelationType>(relationType, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedRelationType, this, saveEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,7 +609,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingRelation, this, new DeleteEventArgs<IRelation>(relation)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IRelation>(relation);
|
||||
if (uow.Events.DispatchCancelable(DeletingRelation, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -613,8 +619,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IRelationRepository>();
|
||||
repository.Delete(relation);
|
||||
uow.Complete();
|
||||
|
||||
uow.Events.Dispatch(DeletedRelation, this, new DeleteEventArgs<IRelation>(relation, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedRelation, this, deleteEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +632,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingRelationType, this, new DeleteEventArgs<IRelationType>(relationType)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IRelationType>(relationType);
|
||||
if (uow.Events.DispatchCancelable(DeletingRelationType, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -635,8 +642,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IRelationTypeRepository>();
|
||||
repository.Delete(relationType);
|
||||
uow.Complete();
|
||||
|
||||
uow.Events.Dispatch(DeletedRelationType, this, new DeleteEventArgs<IRelationType>(relationType, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedRelationType, this, deleteEventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,8 @@ namespace Umbraco.Core.Services
|
||||
IsApproved = isApproved
|
||||
};
|
||||
|
||||
if (uow.Events.DispatchCancelable(SavingUser, this, new SaveEventArgs<IUser>(user)))
|
||||
var saveEventArgs = new SaveEventArgs<IUser>(user);
|
||||
if (uow.Events.DispatchCancelable(SavingUser, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return user;
|
||||
@@ -132,7 +133,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
repository.AddOrUpdate(user);
|
||||
|
||||
uow.Events.Dispatch(SavedUser, this, new SaveEventArgs<IUser>(user, false));
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
@@ -266,7 +268,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingUser, this, new DeleteEventArgs<IUser>(user)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IUser>(user);
|
||||
if (uow.Events.DispatchCancelable(DeletingUser, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -275,7 +278,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
repository.Delete(user);
|
||||
|
||||
uow.Events.Dispatch(DeletedUser, this, new DeleteEventArgs<IUser>(user, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedUser, this, deleteEventArgs);
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
@@ -291,7 +295,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(SavingUser, this, new SaveEventArgs<IUser>(entity)))
|
||||
var saveEventArgs = new SaveEventArgs<IUser>(entity);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(SavingUser, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -305,7 +310,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
|
||||
//Now we have to check for backwards compat hacks
|
||||
//Now we have to check for backwards compat hacks, we'll need to process any groups
|
||||
//to save first before we update the user since these groups might be new groups.
|
||||
var explicitUser = entity as User;
|
||||
if (explicitUser != null && explicitUser.GroupsToSave.Count > 0)
|
||||
{
|
||||
@@ -320,7 +326,10 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
repository.AddOrUpdate(entity);
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(SavedUser, this, new SaveEventArgs<IUser>(entity, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
}
|
||||
|
||||
// try to flush the unit of work
|
||||
// ie executes the SQL but does not commit the trx yet
|
||||
@@ -355,8 +364,9 @@ namespace Umbraco.Core.Services
|
||||
var entitiesA = entities.ToArray();
|
||||
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(SavingUser, this, new SaveEventArgs<IUser>(entitiesA)))
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IUser>(entitiesA);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(SavingUser, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -386,7 +396,10 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(SavedUser, this, new SaveEventArgs<IUser>(entitiesA, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
}
|
||||
|
||||
//commit the whole lot in one go
|
||||
uow.Complete();
|
||||
@@ -537,7 +550,25 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IUser> GetAll(long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, UserState[] userState = null, string[] userGroups = null, string filter = "")
|
||||
public IEnumerable<IUser> GetAll(long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection,
|
||||
UserState[] userState = null,
|
||||
string[] userGroups = null,
|
||||
string filter = null)
|
||||
{
|
||||
IQuery<IUser> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = UowProvider.DatabaseContext.Query<IUser>().Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
|
||||
}
|
||||
|
||||
return GetAll(pageIndex, pageSize, out totalRecords, orderBy, orderDirection, userState, userGroups, null, filterQuery);
|
||||
}
|
||||
|
||||
public IEnumerable<IUser> GetAll(long pageIndex, int pageSize, out long totalRecords,
|
||||
string orderBy, Direction orderDirection,
|
||||
UserState[] userState = null, string[] includeUserGroups = null, string[] excludeUserGroups = null,
|
||||
IQuery<IUser> filter = null)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
@@ -578,14 +609,8 @@ namespace Umbraco.Core.Services
|
||||
throw new IndexOutOfRangeException("The orderBy parameter " + orderBy + " is not valid");
|
||||
}
|
||||
|
||||
IQuery<IUser> filterQuery = null;
|
||||
if (filter.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
filterQuery = uow.Query<IUser>().Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
|
||||
}
|
||||
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, sort, orderDirection, userGroups, userState, filterQuery);
|
||||
return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, sort, orderDirection, includeUserGroups, excludeUserGroups, userState, filter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,11 +678,10 @@ namespace Umbraco.Core.Services
|
||||
/// <returns><see cref="IProfile"/></returns>
|
||||
public IProfile GetProfileById(int id)
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
|
||||
{
|
||||
var repository = uow.CreateRepository<IUserRepository>();
|
||||
return repository.GetProfile(id);
|
||||
}
|
||||
//This is called a TON. Go get the full user from cache which should already be IProfile
|
||||
var fullUser = GetUserById(id);
|
||||
var asProfile = fullUser as IProfile;
|
||||
return asProfile ?? new UserProfile(fullUser.Id, fullUser.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -798,7 +822,7 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IUserGroupRepository>();
|
||||
var query = uow.Query<IUserGroup>().Where(x => aliases.SqlIn(x.Alias));
|
||||
var contents = repository.GetByQuery(query);
|
||||
return contents.ToArray();
|
||||
return contents.WhereNotNull().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,7 +872,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(SavingUserGroup, this, new SaveEventArgs<IUserGroup>(userGroup)))
|
||||
var saveEventArgs = new SaveEventArgs<IUserGroup>(userGroup);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(SavingUserGroup, this, saveEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -858,7 +883,10 @@ namespace Umbraco.Core.Services
|
||||
repository.AddOrUpdateGroupWithUsers(userGroup, userIds);
|
||||
|
||||
if (raiseEvents)
|
||||
uow.Events.Dispatch(SavedUserGroup, this, new SaveEventArgs<IUserGroup>(userGroup, false));
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(SavedUserGroup, this, saveEventArgs);
|
||||
}
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
@@ -872,7 +900,8 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
if (uow.Events.DispatchCancelable(DeletingUserGroup, this, new DeleteEventArgs<IUserGroup>(userGroup)))
|
||||
var deleteEventArgs = new DeleteEventArgs<IUserGroup>(userGroup);
|
||||
if (uow.Events.DispatchCancelable(DeletingUserGroup, this, deleteEventArgs))
|
||||
{
|
||||
uow.Complete();
|
||||
return;
|
||||
@@ -881,7 +910,8 @@ namespace Umbraco.Core.Services
|
||||
var repository = uow.CreateRepository<IUserGroupRepository>();
|
||||
repository.Delete(userGroup);
|
||||
|
||||
uow.Events.Dispatch(DeletedUserGroup, this, new DeleteEventArgs<IUserGroup>(userGroup, false));
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedUserGroup, this, deleteEventArgs);
|
||||
|
||||
uow.Complete();
|
||||
}
|
||||
|
||||
@@ -127,10 +127,12 @@ namespace Umbraco.Core.Sync
|
||||
|
||||
public static string GetServerHash(string machineName, string appDomainAppId)
|
||||
{
|
||||
var hasher = new HashCodeCombiner();
|
||||
hasher.AddCaseInsensitiveString(appDomainAppId);
|
||||
hasher.AddCaseInsensitiveString(machineName);
|
||||
return hasher.GetCombinedHashCode();
|
||||
using (var generator = new HashGenerator())
|
||||
{
|
||||
generator.AddString(machineName);
|
||||
generator.AddString(appDomainAppId);
|
||||
return generator.GenerateHash();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool RequiresDistributed(IEnumerable<IServerAddress> servers, ICacheRefresher refresher, MessageType messageType)
|
||||
|
||||
@@ -383,6 +383,7 @@
|
||||
<Compile Include="Events\RollbackEventArgs.cs" />
|
||||
<Compile Include="Events\SaveEventArgs.cs" />
|
||||
<Compile Include="Events\ScopeLifetimeMessagesFactory.cs" />
|
||||
<Compile Include="Events\SendEmailEventArgs.cs" />
|
||||
<Compile Include="Events\SendToPublishEventArgs.cs" />
|
||||
<Compile Include="Events\SupersedeEventAttribute.cs" />
|
||||
<Compile Include="Events\TransientEventMessagesFactory.cs" />
|
||||
@@ -1166,7 +1167,7 @@
|
||||
<Compile Include="Persistence\Repositories\RepositoryBaseOfTIdTEntity.cs" />
|
||||
<Compile Include="Persistence\Repositories\ScriptRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ServerRegistrationRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\SimilarNodeNameComparer.cs" />
|
||||
<Compile Include="Persistence\Repositories\SimilarNodeName.cs" />
|
||||
<Compile Include="Persistence\Repositories\SimpleGetRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\StylesheetRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\TagRepository.cs" />
|
||||
@@ -1323,6 +1324,7 @@
|
||||
<Compile Include="Serialization\JsonCreationConverter.cs" />
|
||||
<Compile Include="Serialization\JsonNetSerializer.cs" />
|
||||
<Compile Include="Serialization\JsonToStringConverter.cs" />
|
||||
<Compile Include="Serialization\KnownTypeUdiJsonConverter.cs" />
|
||||
<Compile Include="Serialization\NoTypeConverterJsonConverter.cs" />
|
||||
<Compile Include="Serialization\SerializationExtensions.cs" />
|
||||
<Compile Include="Serialization\SerializationService.cs" />
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace Umbraco.Core.Xml
|
||||
return -1;
|
||||
});
|
||||
|
||||
const string rootXpath = "descendant::*[@id={0}]";
|
||||
const string rootXpath = "id({0})";
|
||||
|
||||
//parseable items:
|
||||
var vars = new Dictionary<string, Func<string, string>>();
|
||||
|
||||
Reference in New Issue
Block a user