Compare commits

..

2 Commits

Author SHA1 Message Date
Sebastiaan Janssen 1e2598a3a3 Bumps version to 7.8.2 2018-04-12 16:36:41 +02:00
Sebastiaan Janssen 19241995e8 Cherry picked - Fix scope leaks caused by database messenger [U4-11207] #2580 2018-04-12 16:23:33 +02:00
174 changed files with 2637 additions and 6518 deletions
+1 -1
View File
@@ -2,6 +2,6 @@
<configuration>
<packageSources>
<add key="nuget.org" value="https://www.nuget.org/api/v2/" />
<add key="umbracocore" value="https://www.myget.org/F/umbracocore/api/v3/index.json" />
<add key="umbracocore" value="http://www.myget.org/f/umbracocore/" />
</packageSources>
</configuration>
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.9.0")]
[assembly: AssemblyInformationalVersion("7.9.0")]
[assembly: AssemblyFileVersion("7.8.2")]
[assembly: AssemblyInformationalVersion("7.8.2")]
@@ -1,351 +0,0 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
namespace Umbraco.Core.Auditing
{
public sealed class AuditEventHandler : ApplicationEventHandler
{
private IAuditService _auditServiceInstance;
private IUserService _userServiceInstance;
private IEntityService _entityServiceInstance;
private IUser CurrentPerformingUser
{
get
{
var identity = Thread.CurrentPrincipal?.GetUmbracoIdentity();
return identity == null
? new User { Id = 0, Name = "SYSTEM", Email = "" }
: _userServiceInstance.GetUserById(Convert.ToInt32(identity.Id));
}
}
private IUser GetPerformingUser(int userId)
{
var found = userId >= 0 ? _userServiceInstance.GetUserById(userId) : null;
return found ?? new User {Id = 0, Name = "SYSTEM", Email = ""};
}
private string PerformingIp
{
get
{
var httpContext = HttpContext.Current == null ? (HttpContextBase) null : new HttpContextWrapper(HttpContext.Current);
var ip = httpContext.GetCurrentRequestIpAddress();
if (ip.ToLowerInvariant().StartsWith("unknown")) ip = "";
return ip;
}
}
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
_auditServiceInstance = applicationContext.Services.AuditService;
_userServiceInstance = applicationContext.Services.UserService;
_entityServiceInstance = applicationContext.Services.EntityService;
//BackOfficeUserManager.AccountLocked += ;
//BackOfficeUserManager.AccountUnlocked += ;
BackOfficeUserManager.ForgotPasswordRequested += OnForgotPasswordRequest;
BackOfficeUserManager.ForgotPasswordChangedSuccess += OnForgotPasswordChange;
BackOfficeUserManager.LoginFailed += OnLoginFailed;
//BackOfficeUserManager.LoginRequiresVerification += ;
BackOfficeUserManager.LoginSuccess += OnLoginSuccess;
BackOfficeUserManager.LogoutSuccess += OnLogoutSuccess;
BackOfficeUserManager.PasswordChanged += OnPasswordChanged;
BackOfficeUserManager.PasswordReset += OnPasswordReset;
//BackOfficeUserManager.ResetAccessFailedCount += ;
UserService.SavedUserGroup2 += OnSavedUserGroupWithUsers;
UserService.SavedUser += OnSavedUser;
UserService.DeletedUser += OnDeletedUser;
UserService.UserGroupPermissionsAssigned += UserGroupPermissionAssigned;
MemberService.Saved += OnSavedMember;
MemberService.Deleted += OnDeletedMember;
MemberService.AssignedRoles += OnAssignedRoles;
MemberService.RemovedRoles += OnRemovedRoles;
MemberService.Exported += OnMemberExported;
}
private string FormatEmail(IMember member)
{
return member == null ? string.Empty : member.Email.IsNullOrWhiteSpace() ? "" : $"<{member.Email}>";
}
private string FormatEmail(IUser user)
{
return user == null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? "" : $"<{user.Email}>";
}
private void OnRemovedRoles(IMemberService sender, RolesEventArgs args)
{
var performingUser = CurrentPerformingUser;
var roles = string.Join(", ", args.Roles);
var members = sender.GetAllMembers(args.MemberIds).ToDictionary(x => x.Id, x => x);
foreach (var id in args.MemberIds)
{
members.TryGetValue(id, out var member);
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"Member {id} \"{member?.Name ?? "(unknown)"}\" {FormatEmail(member)}",
"umbraco/member/roles/removed", $"roles modified, removed {roles}");
}
}
private void OnAssignedRoles(IMemberService sender, RolesEventArgs args)
{
var performingUser = CurrentPerformingUser;
var roles = string.Join(", ", args.Roles);
var members = sender.GetAllMembers(args.MemberIds).ToDictionary(x => x.Id, x => x);
foreach (var id in args.MemberIds)
{
members.TryGetValue(id, out var member);
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"Member {id} \"{member?.Name ?? "(unknown)"}\" {FormatEmail(member)}",
"umbraco/member/roles/assigned", $"roles modified, assigned {roles}");
}
}
private void OnMemberExported(IMemberService sender, ExportedMemberEventArgs exportedMemberEventArgs)
{
var performingUser = CurrentPerformingUser;
var member = exportedMemberEventArgs.Member;
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
"umbraco/member/exported", "exported member data");
}
private void OnSavedUserGroupWithUsers(IUserService sender, SaveEventArgs<UserGroupWithUsers> saveEventArgs)
{
var performingUser = CurrentPerformingUser;
foreach (var groupWithUser in saveEventArgs.SavedEntities)
{
var group = groupWithUser.UserGroup;
var dp = string.Join(", ", ((UserGroup)group).GetPreviouslyDirtyProperties());
var sections = ((UserGroup)group).WasPropertyDirty("AllowedSections")
? string.Join(", ", group.AllowedSections)
: null;
var perms = ((UserGroup)group).WasPropertyDirty("Permissions")
? string.Join(", ", group.Permissions)
: null;
var sb = new StringBuilder();
sb.Append($"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)};");
if (sections != null)
sb.Append($", assigned sections: {sections}");
if (perms != null)
{
if (sections != null)
sb.Append(", ");
sb.Append($"default perms: {perms}");
}
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"User Group {group.Id} \"{group.Name}\" ({group.Alias})",
"umbraco/user-group/save", $"{sb}");
// now audit the users that have changed
foreach (var user in groupWithUser.RemovedUsers)
{
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
user.Id, $"User \"{user.Name}\" {FormatEmail(user)}",
"umbraco/user-group/save", $"Removed user \"{user.Name}\" {FormatEmail(user)} from group {group.Id} \"{group.Name}\" ({group.Alias})");
}
foreach (var user in groupWithUser.AddedUsers)
{
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
user.Id, $"User \"{user.Name}\" {FormatEmail(user)}",
"umbraco/user-group/save", $"Added user \"{user.Name}\" {FormatEmail(user)} to group {group.Id} \"{group.Name}\" ({group.Alias})");
}
}
}
private void UserGroupPermissionAssigned(IUserService sender, SaveEventArgs<EntityPermission> saveEventArgs)
{
var performingUser = CurrentPerformingUser;
var perms = saveEventArgs.SavedEntities;
foreach (var perm in perms)
{
var group = sender.GetUserGroupById(perm.UserGroupId);
var assigned = string.Join(", ", perm.AssignedPermissions);
var entity = _entityServiceInstance.Get(perm.EntityId);
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"User Group {group.Id} \"{group.Name}\" ({group.Alias})",
"umbraco/user-group/permissions-change", $"assigning {(string.IsNullOrWhiteSpace(assigned) ? "(nothing)" : assigned)} on id:{perm.EntityId} \"{entity.Name}\"");
}
}
private void OnSavedMember(IMemberService sender, SaveEventArgs<IMember> saveEventArgs)
{
var performingUser = CurrentPerformingUser;
var members = saveEventArgs.SavedEntities;
foreach (var member in members)
{
var dp = string.Join(", ", ((Member) member).GetPreviouslyDirtyProperties());
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
"umbraco/member/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}");
}
}
private void OnDeletedMember(IMemberService sender, DeleteEventArgs<IMember> deleteEventArgs)
{
var performingUser = CurrentPerformingUser;
var members = deleteEventArgs.DeletedEntities;
foreach (var member in members)
{
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
"umbraco/member/delete", $"delete member id:{member.Id} \"{member.Name}\" {FormatEmail(member)}");
}
}
private void OnSavedUser(IUserService sender, SaveEventArgs<IUser> saveEventArgs)
{
var performingUser = CurrentPerformingUser;
var affectedUsers = saveEventArgs.SavedEntities;
foreach (var affectedUser in affectedUsers)
{
var groups = affectedUser.WasPropertyDirty("Groups")
? string.Join(", ", affectedUser.Groups.Select(x => x.Alias))
: null;
var dp = string.Join(", ", ((User)affectedUser).GetPreviouslyDirtyProperties());
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}{(groups == null ? "" : "; groups assigned: " + groups)}");
}
}
private void OnDeletedUser(IUserService sender, DeleteEventArgs<IUser> deleteEventArgs)
{
var performingUser = CurrentPerformingUser;
var affectedUsers = deleteEventArgs.DeletedEntities;
foreach (var affectedUser in affectedUsers)
_auditServiceInstance.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
DateTime.UtcNow,
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
"umbraco/user/delete", "delete user");
}
private void OnLoginSuccess(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs)
{
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/login", "login success");
}
}
private void OnLogoutSuccess(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs)
{
var performingUser = GetPerformingUser(identityArgs.PerformingUser);
WriteAudit(performingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/sign-in/logout", "logout success");
}
}
private void OnPasswordReset(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/reset", "password reset");
}
}
private void OnPasswordChanged(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/change", "password change");
}
}
private void OnLoginFailed(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, 0, identityArgs.IpAddress, "umbraco/user/sign-in/failed", "login failed", affectedDetails: "");
}
}
private void OnForgotPasswordChange(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/change", "password forgot/change");
}
}
private void OnForgotPasswordRequest(object sender, EventArgs args)
{
if (args is IdentityAuditEventArgs identityArgs && identityArgs.PerformingUser >= 0)
{
WriteAudit(identityArgs.PerformingUser, identityArgs.AffectedUser, identityArgs.IpAddress, "umbraco/user/password/forgot/request", "password forgot/request");
}
}
private void WriteAudit(int performingId, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
{
var performingUser = _userServiceInstance.GetUserById(performingId);
var performingDetails = performingUser == null
? $"User UNKNOWN:{performingId}"
: $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}";
WriteAudit(performingId, performingDetails, affectedId, ipAddress, eventType, eventDetails, affectedDetails);
}
private void WriteAudit(IUser performingUser, int affectedId, string ipAddress, string eventType, string eventDetails)
{
var performingDetails = performingUser == null
? $"User UNKNOWN"
: $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}";
WriteAudit(performingUser?.Id ?? 0, performingDetails, affectedId, ipAddress, eventType, eventDetails);
}
private void WriteAudit(int performingId, string performingDetails, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
{
if (affectedDetails == null)
{
var affectedUser = _userServiceInstance.GetUserById(affectedId);
affectedDetails = affectedUser == null
? $"User UNKNOWN:{affectedId}"
: $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}";
}
_auditServiceInstance.Write(performingId, performingDetails,
ipAddress,
DateTime.UtcNow,
affectedId, affectedDetails,
eventType, eventDetails);
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.ComponentModel;
using System.Threading;
using System.Web;
using Umbraco.Core.Security;
@@ -46,8 +45,12 @@ namespace Umbraco.Core.Auditing
/// </summary>
public string Username { get; private set; }
[Obsolete("Use the method that has the affectedUser parameter instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
/// <summary>
/// Sets the properties on the event being raised, all parameters are optional except for the action being performed
/// </summary>
/// <param name="action">An action based on the AuditEvent enum</param>
/// <param name="ipAddress">The client's IP address. This is usually automatically set but could be overridden if necessary</param>
/// <param name="performingUser">The Id of the user performing the action (if different from the user affected by the action)</param>
public IdentityAuditEventArgs(AuditEvent action, string ipAddress, int performingUser = -1)
{
DateTimeUtc = DateTime.UtcNow;
@@ -60,35 +63,6 @@ namespace Umbraco.Core.Auditing
: performingUser;
}
/// <summary>
/// Default constructor
/// </summary>
/// <param name="action"></param>
/// <param name="ipAddress"></param>
/// <param name="comment"></param>
/// <param name="performingUser"></param>
/// <param name="affectedUser"></param>
public IdentityAuditEventArgs(AuditEvent action, string ipAddress, string comment = null, int performingUser = -1, int affectedUser = -1)
{
DateTimeUtc = DateTime.UtcNow;
Action = action;
IpAddress = ipAddress;
Comment = comment;
AffectedUser = affectedUser;
PerformingUser = performingUser == -1
? GetCurrentRequestBackofficeUserId()
: performingUser;
}
/// <summary>
/// Creates an instance without a performing or affected user (the id will be set to -1)
/// </summary>
/// <param name="action"></param>
/// <param name="ipAddress"></param>
/// <param name="username"></param>
/// <param name="comment"></param>
public IdentityAuditEventArgs(AuditEvent action, string ipAddress, string username, string comment)
{
DateTimeUtc = DateTime.UtcNow;
@@ -97,22 +71,6 @@ namespace Umbraco.Core.Auditing
IpAddress = ipAddress;
Username = username;
Comment = comment;
PerformingUser = -1;
}
public IdentityAuditEventArgs(AuditEvent action, string ipAddress, string username, string comment, int performingUser)
{
DateTimeUtc = DateTime.UtcNow;
Action = action;
IpAddress = ipAddress;
Username = username;
Comment = comment;
PerformingUser = performingUser == -1
? GetCurrentRequestBackofficeUserId()
: performingUser;
}
/// <summary>
@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml.Linq;
using ClientDependency.Core.CompositeFiles.Providers;
using ClientDependency.Core.Config;
using Semver;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
@@ -28,74 +24,10 @@ namespace Umbraco.Core.Configuration
_logger = logger;
_fileName = IOHelper.MapPath(string.Format("{0}/ClientDependency.config", SystemDirectories.Config));
}
/// <summary>
/// Changes the version number in ClientDependency.config to a hashed value for the version and the DateTime.Day
/// </summary>
/// <param name="version">The <see cref="SemVersion">version</see> of Umbraco we're upgrading to</param>
/// <param name="date">A <see cref="DateTime">date</see> value to use in the hash to prevent this method from updating the version on each startup</param>
/// <param name="dateFormat">Allows the developer to specify the <see cref="string">date precision</see> for the hash (i.e. "yyyyMMdd" would be a precision for the day)</param>
/// <returns>Boolean to indicate succesful update of the ClientDependency.config file</returns>
public bool UpdateVersionNumber(SemVersion version, DateTime date, string dateFormat)
{
var byteContents = Encoding.Unicode.GetBytes(version + date.ToString(dateFormat));
//This is a way to convert a string to a long
//see https://www.codeproject.com/Articles/34309/Convert-String-to-bit-Integer
//We could much more easily use MD5 which would create us an INT but since that is not compliant with
//hashing standards we have to use SHA
int intHash;
using (var hash = SHA256.Create())
{
var bytes = hash.ComputeHash(byteContents);
var longResult = new[] { 0, 8, 16, 24 }
.Select(i => BitConverter.ToInt64(bytes, i))
.Aggregate((x, y) => x ^ y);
//CDF requires an INT, and although this isn't fail safe, it will work for our purposes. We are not hashing for crypto purposes
//so there could be some collisions with this conversion but it's not a problem for our purposes
//It's also important to note that the long.GetHashCode() implementation in .NET is this: return (int) this ^ (int) (this >> 32);
//which means that this value will not change per appdomain like some GetHashCode implementations.
intHash = longResult.GetHashCode();
}
try
{
var clientDependencyConfigXml = XDocument.Load(_fileName, LoadOptions.PreserveWhitespace);
if (clientDependencyConfigXml.Root != null)
{
var versionAttribute = clientDependencyConfigXml.Root.Attribute("version");
//Set the new version to the hashcode of now
var oldVersion = versionAttribute.Value;
var newVersion = Math.Abs(intHash).ToString();
//don't update if it's the same version
if (oldVersion == newVersion)
return false;
versionAttribute.SetValue(newVersion);
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
_logger.Info<ClientDependencyConfiguration>(string.Format("Updated version number from {0} to {1}", oldVersion, newVersion));
return true;
}
}
catch (Exception ex)
{
_logger.Error<ClientDependencyConfiguration>("Couldn't update ClientDependency version number", ex);
}
return false;
}
/// <summary>
/// Changes the version number in ClientDependency.config to a random value to avoid stale caches
/// </summary>
/// <seealso cref="UpdateVersionNumber(SemVersion, DateTime, string)" />
[Obsolete("Use the UpdateVersionNumber method specifying the version, date and dateFormat instead")]
public bool IncreaseVersionNumber()
{
try
@@ -175,4 +107,4 @@ namespace Umbraco.Core.Configuration
return success;
}
}
}
}
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.9.0");
private static readonly Version Version = new Version("7.8.2");
/// <summary>
/// Gets the current version of Umbraco.
+1 -2
View File
@@ -9,7 +9,6 @@ namespace Umbraco.Core
{
public const string AdminGroupAlias = "admin";
public const string SensitiveDataGroupAlias = "sensitiveData";
public const string TranslatorGroupAlias = "translator";
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
@@ -37,4 +36,4 @@ namespace Umbraco.Core
}
}
}
}
@@ -1,18 +0,0 @@
using System;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Events
{
internal class ExportedMemberEventArgs : EventArgs
{
public IMember Member { get; }
public MemberExportModel Exported { get; }
public ExportedMemberEventArgs(IMember member, MemberExportModel exported)
{
Member = member;
Exported = exported;
}
}
}
-16
View File
@@ -1,16 +0,0 @@
using System;
namespace Umbraco.Core.Events
{
public class RolesEventArgs : EventArgs
{
public RolesEventArgs(int[] memberIds, string[] roles)
{
MemberIds = memberIds;
Roles = roles;
}
public int[] MemberIds { get; set; }
public string[] Roles { get; set; }
}
}
@@ -1,19 +0,0 @@
using System;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Events
{
internal class UserGroupWithUsers
{
public UserGroupWithUsers(IUserGroup userGroup, IUser[] addedUsers, IUser[] removedUsers)
{
UserGroup = userGroup;
AddedUsers = addedUsers;
RemovedUsers = removedUsers;
}
public IUserGroup UserGroup { get; }
public IUser[] AddedUsers { get; }
public IUser[] RemovedUsers { get; }
}
}
-94
View File
@@ -1,94 +0,0 @@
using System;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents an audited event.
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class AuditEntry : Entity, IAuditEntry
{
private static PropertySelectors _selectors;
private int _performingUserId;
private string _performingDetails;
private string _performingIp;
private int _affectedUserId;
private string _affectedDetails;
private string _eventType;
private string _eventDetails;
private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors());
private class PropertySelectors
{
public readonly PropertyInfo PerformingUserId = ExpressionHelper.GetPropertyInfo<AuditEntry, int>(x => x.PerformingUserId);
public readonly PropertyInfo PerformingDetails = ExpressionHelper.GetPropertyInfo<AuditEntry, string>(x => x.PerformingDetails);
public readonly PropertyInfo PerformingIp = ExpressionHelper.GetPropertyInfo<AuditEntry, string>(x => x.PerformingIp);
public readonly PropertyInfo AffectedUserId = ExpressionHelper.GetPropertyInfo<AuditEntry, int>(x => x.AffectedUserId);
public readonly PropertyInfo AffectedDetails = ExpressionHelper.GetPropertyInfo<AuditEntry, string>(x => x.AffectedDetails);
public readonly PropertyInfo EventType = ExpressionHelper.GetPropertyInfo<AuditEntry, string>(x => x.EventType);
public readonly PropertyInfo EventDetails = ExpressionHelper.GetPropertyInfo<AuditEntry, string>(x => x.EventDetails);
}
/// <inheritdoc />
public int PerformingUserId
{
get => _performingUserId;
set => SetPropertyValueAndDetectChanges(value, ref _performingUserId, Selectors.PerformingUserId);
}
/// <inheritdoc />
public string PerformingDetails
{
get => _performingDetails;
set => SetPropertyValueAndDetectChanges(value, ref _performingDetails, Selectors.PerformingDetails);
}
/// <inheritdoc />
public string PerformingIp
{
get => _performingIp;
set => SetPropertyValueAndDetectChanges(value, ref _performingIp, Selectors.PerformingIp);
}
/// <inheritdoc />
public DateTime EventDateUtc
{
get => CreateDate;
set => CreateDate = value;
}
/// <inheritdoc />
public int AffectedUserId
{
get => _affectedUserId;
set => SetPropertyValueAndDetectChanges(value, ref _affectedUserId, Selectors.AffectedUserId);
}
/// <inheritdoc />
public string AffectedDetails
{
get => _affectedDetails;
set => SetPropertyValueAndDetectChanges(value, ref _affectedDetails, Selectors.AffectedDetails);
}
/// <inheritdoc />
public string EventType
{
get => _eventType;
set => SetPropertyValueAndDetectChanges(value, ref _eventType, Selectors.EventType);
}
/// <inheritdoc />
public string EventDetails
{
get => _eventDetails;
set => SetPropertyValueAndDetectChanges(value, ref _eventDetails, Selectors.EventDetails);
}
}
}
-102
View File
@@ -1,102 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a consent.
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
internal class Consent : Entity, IConsent
{
private static PropertySelectors _selector;
private bool _current;
private string _source;
private string _context;
private string _action;
private ConsentState _state;
private string _comment;
// ReSharper disable once ClassNeverInstantiated.Local
private class PropertySelectors
{
public readonly PropertyInfo Current = ExpressionHelper.GetPropertyInfo<Consent, bool>(x => x.Current);
public readonly PropertyInfo Source = ExpressionHelper.GetPropertyInfo<Consent, string>(x => x.Source);
public readonly PropertyInfo Context = ExpressionHelper.GetPropertyInfo<Consent, string>(x => x.Context);
public readonly PropertyInfo Action = ExpressionHelper.GetPropertyInfo<Consent, string>(x => x.Action);
public readonly PropertyInfo State = ExpressionHelper.GetPropertyInfo<Consent, ConsentState>(x => x.State);
public readonly PropertyInfo Comment = ExpressionHelper.GetPropertyInfo<Consent, string>(x => x.Comment);
}
private static PropertySelectors Selectors => _selector ?? (_selector = new PropertySelectors());
/// <inheritdoc />
public bool Current
{
get => _current;
set => SetPropertyValueAndDetectChanges(value, ref _current, Selectors.Current);
}
/// <inheritdoc />
public string Source
{
get => _source;
set
{
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(nameof(value));
SetPropertyValueAndDetectChanges(value, ref _source, Selectors.Source);
}
}
/// <inheritdoc />
public string Context
{
get => _context;
set
{
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(nameof(value));
SetPropertyValueAndDetectChanges(value, ref _context, Selectors.Context);
}
}
/// <inheritdoc />
public string Action
{
get => _action;
set
{
if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException(nameof(value));
SetPropertyValueAndDetectChanges(value, ref _action, Selectors.Action);
}
}
/// <inheritdoc />
public ConsentState State
{
get => _state;
// note: we probably should validate the state here, but since the
// enum is [Flags] with many combinations, this could be expensive
set => SetPropertyValueAndDetectChanges(value, ref _state, Selectors.State);
}
/// <inheritdoc />
public string Comment
{
get => _comment;
set => SetPropertyValueAndDetectChanges(value, ref _comment, Selectors.Comment);
}
/// <inheritdoc />
public IEnumerable<IConsent> History => HistoryInternal;
/// <summary>
/// Gets the previous states of this consent.
/// </summary>
internal List<IConsent> HistoryInternal { get; set; }
}
}
@@ -1,18 +0,0 @@
namespace Umbraco.Core.Models
{
/// <summary>
/// Provides extension methods for the <see cref="IConsent"/> interface.
/// </summary>
public static class ConsentExtensions
{
/// <summary>
/// Determines whether the consent is granted.
/// </summary>
public static bool IsGranted(this IConsent consent) => (consent.State & ConsentState.Granted) > 0;
/// <summary>
/// Determines whether the consent is revoked.
/// </summary>
public static bool IsRevoked(this IConsent consent) => (consent.State & ConsentState.Revoked) > 0;
}
}
-38
View File
@@ -1,38 +0,0 @@
using System;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents the state of a consent.
/// </summary>
[Flags]
public enum ConsentState // : int
{
// note - this is a [Flags] enumeration
// on can create detailed flags such as:
//GrantedOptIn = Granted | 0x0001
//GrandedByForce = Granted | 0x0002
//
// 16 situations for each Pending/Granted/Revoked should be ok
/// <summary>
/// There is no consent.
/// </summary>
None = 0,
/// <summary>
/// Consent is pending and has not been granted yet.
/// </summary>
Pending = 0x10000,
/// <summary>
/// Consent has been granted.
/// </summary>
Granted = 0x20000,
/// <summary>
/// Consent has been revoked.
/// </summary>
Revoked = 0x40000
}
}
+1 -23
View File
@@ -544,28 +544,6 @@ namespace Umbraco.Core.Models
return false;
}
/// <summary>
/// Returns both instance dirty properties and property type properties
/// </summary>
/// <returns></returns>
public override IEnumerable<string> GetDirtyProperties()
{
var instanceProperties = base.GetDirtyProperties();
var propertyTypes = Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
return instanceProperties.Concat(propertyTypes);
}
/// <summary>
/// Returns both instance dirty properties and property type properties
/// </summary>
/// <returns></returns>
internal override IEnumerable<string> GetPreviouslyDirtyProperties()
{
var instanceProperties = base.GetPreviouslyDirtyProperties();
var propertyTypes = Properties.Where(x => x.WasDirty()).Select(x => x.Alias);
return instanceProperties.Concat(propertyTypes);
}
#endregion
}
}
}
@@ -23,13 +23,6 @@ namespace Umbraco.Core.Models.EntityBase
: _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
}
internal virtual IEnumerable<string> GetPreviouslyDirtyProperties()
{
return _lastPropertyChangedInfo == null
? Enumerable.Empty<string>()
: _lastPropertyChangedInfo.Where(x => x.Value).Select(x => x.Key);
}
private bool _changeTrackingEnabled = true;
/// <summary>
@@ -228,4 +221,4 @@ namespace Umbraco.Core.Models.EntityBase
}
}
}
}
}
-60
View File
@@ -1,60 +0,0 @@
using System;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents an audited event.
/// </summary>
/// <remarks>
/// <para>The free-form details properties can be used to capture relevant infos (for example,
/// a user email and identifier) at the time of the audited event, even though they may change
/// later on - but we want to keep a track of their value at that time.</para>
/// <para>Depending on audit loggers, these properties can be purely free-form text, or
/// contain json serialized objects.</para>
/// </remarks>
public interface IAuditEntry : IAggregateRoot, IRememberBeingDirty
{
/// <summary>
/// Gets or sets the identifier of the user triggering the audited event.
/// </summary>
int PerformingUserId { get; set; }
/// <summary>
/// Gets or sets free-form details about the user triggering the audited event.
/// </summary>
string PerformingDetails { get; set; }
/// <summary>
/// Gets or sets the IP address or the request triggering the audited event.
/// </summary>
string PerformingIp { get; set; }
/// <summary>
/// Gets or sets the date and time of the audited event.
/// </summary>
DateTime EventDateUtc { get; set; }
/// <summary>
/// Gets or sets the identifier of the user affected by the audited event.
/// </summary>
/// <remarks>Not used when no single user is affected by the event.</remarks>
int AffectedUserId { get; set; }
/// <summary>
/// Gets or sets free-form details about the entity affected by the audited event.
/// </summary>
/// <remarks>The entity affected by the event can be another user, a member...</remarks>
string AffectedDetails { get; set; }
/// <summary>
/// Gets or sets the type of the audited event.
/// </summary>
string EventType { get; set; }
/// <summary>
/// Gets or sets free-form details about the audited event.
/// </summary>
string EventDetails { get; set; }
}
}
-55
View File
@@ -1,55 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
/// <summary>
/// Represents a consent state.
/// </summary>
/// <remarks>
/// <para>A consent is fully identified by a source (whoever is consenting), a context (for
/// example, an application), and an action (whatever is consented).</para>
/// <para>A consent state registers the state of the consent (granted, revoked...).</para>
/// </remarks>
public interface IConsent : IAggregateRoot, IRememberBeingDirty
{
/// <summary>
/// Determines whether the consent entity represents the current state.
/// </summary>
bool Current { get; }
/// <summary>
/// Gets the unique identifier of whoever is consenting.
/// </summary>
string Source { get; }
/// <summary>
/// Gets the unique identifier of the context of the consent.
/// </summary>
/// <remarks>
/// <para>Represents the domain, application, scope... of the action.</para>
/// <para>When the action is a Udi, this should be the Udi type.</para>
/// </remarks>
string Context { get; }
/// <summary>
/// Gets the unique identifier of the consented action.
/// </summary>
string Action { get; }
/// <summary>
/// Gets the state of the consent.
/// </summary>
ConsentState State { get; }
/// <summary>
/// Gets some additional free text.
/// </summary>
string Comment { get; }
/// <summary>
/// Gets the previous states of this consent.
/// </summary>
IEnumerable<IConsent> History { get; }
}
}
+1 -15
View File
@@ -19,13 +19,6 @@
/// <returns></returns>
bool MemberCanViewProperty(string propertyTypeAlias);
/// <summary>
/// Gets a boolean indicating whether a Property is marked as storing sensitive values on the Members profile.
/// </summary>
/// <param name="propertyTypeAlias">PropertyType Alias of the Property to check</param>
/// <returns></returns>
bool IsSensitiveProperty(string propertyTypeAlias);
/// <summary>
/// Sets a boolean indicating whether a Property is editable by the Member.
/// </summary>
@@ -39,12 +32,5 @@
/// <param name="propertyTypeAlias">PropertyType Alias of the Property to set</param>
/// <param name="value">Boolean value, true or false</param>
void SetMemberCanViewProperty(string propertyTypeAlias, bool value);
/// <summary>
/// Sets a boolean indicating whether a Property is a sensitive value on the Members profile.
/// </summary>
/// <param name="propertyTypeAlias">PropertyType Alias of the Property to set</param>
/// <param name="value">Boolean value, true or false</param>
void SetIsSensitiveProperty(string propertyTypeAlias, bool value);
}
}
}
@@ -34,15 +34,6 @@ namespace Umbraco.Core.Models.Identity
.ForMember(user => user.CalculatedContentStartNodeIds, expression => expression.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(user => user.CalculatedMediaStartNodeIds, expression => expression.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()))
.ForMember(user => user.LockoutEnabled, expression => expression.Ignore())
.ForMember(user => user.Logins, expression => expression.Ignore())
.ForMember(user => user.Roles, expression => expression.Ignore())
.ForMember(user => user.PhoneNumber, expression => expression.Ignore())
.ForMember(user => user.PhoneNumberConfirmed, expression => expression.Ignore())
.ForMember(user => user.TwoFactorEnabled, expression => expression.Ignore())
.ForMember(user => user.Claims, expression => expression.Ignore())
.AfterMap((user, identityUser) =>
{
identityUser.ResetDirtyProperties(true);
@@ -56,4 +47,4 @@ namespace Umbraco.Core.Models.Identity
return storedPass.StartsWith(Constants.Security.EmptyPasswordPrefix) ? null : storedPass;
}
}
}
}
+2 -14
View File
@@ -170,19 +170,7 @@ namespace Umbraco.Core.Models
public string RawPasswordValue
{
get { return _rawPasswordValue; }
set
{
if (value == null)
{
//special case, this is used to ensure that the password is not updated when persisting, in this case
//we don't want to track changes either
_rawPasswordValue = null;
}
else
{
SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, Ps.Value.PasswordSelector);
}
}
set { SetPropertyValueAndDetectChanges(value, ref _rawPasswordValue, Ps.Value.PasswordSelector); }
}
/// <summary>
@@ -640,4 +628,4 @@ namespace Umbraco.Core.Models
}
}
}
}
+13 -49
View File
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Models
}
/// <summary>
/// Gets or Sets a Dictionary of Tuples (MemberCanEdit, VisibleOnProfile, IsSensitive) by the PropertyTypes' alias.
/// Gets or Sets a Dictionary of Tuples (MemberCanEdit, VisibleOnProfile) by the PropertyTypes' alias.
/// </summary>
[DataMember]
internal IDictionary<string, MemberTypePropertyProfileAccess> MemberTypePropertyTypes { get; private set; }
@@ -76,11 +76,11 @@ namespace Umbraco.Core.Models
/// <returns></returns>
public bool MemberCanEditProperty(string propertyTypeAlias)
{
MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
return propertyProfile.IsEditable;
return MemberTypePropertyTypes[propertyTypeAlias].IsEditable;
}
return false;
}
@@ -91,26 +91,11 @@ namespace Umbraco.Core.Models
/// <returns></returns>
public bool MemberCanViewProperty(string propertyTypeAlias)
{
MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
return propertyProfile.IsVisible;
return MemberTypePropertyTypes[propertyTypeAlias].IsVisible;
}
return false;
}
/// <summary>
/// Gets a boolean indicating whether a Property is marked as storing sensitive values on the Members profile.
/// </summary>
/// <param name="propertyTypeAlias">PropertyType Alias of the Property to check</param>
/// <returns></returns>
public bool IsSensitiveProperty(string propertyTypeAlias)
{
MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{
return propertyProfile.IsSensitive;
}
return false;
}
@@ -121,14 +106,13 @@ namespace Umbraco.Core.Models
/// <param name="value">Boolean value, true or false</param>
public void SetMemberCanEditProperty(string propertyTypeAlias, bool value)
{
MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
propertyProfile.IsEditable = value;
MemberTypePropertyTypes[propertyTypeAlias].IsEditable = value;
}
else
{
var tuple = new MemberTypePropertyProfileAccess(false, value, false);
var tuple = new MemberTypePropertyProfileAccess(false, value);
MemberTypePropertyTypes.Add(propertyTypeAlias, tuple);
}
}
@@ -140,35 +124,15 @@ namespace Umbraco.Core.Models
/// <param name="value">Boolean value, true or false</param>
public void SetMemberCanViewProperty(string propertyTypeAlias, bool value)
{
MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
if (MemberTypePropertyTypes.ContainsKey(propertyTypeAlias))
{
propertyProfile.IsVisible = value;
MemberTypePropertyTypes[propertyTypeAlias].IsVisible = value;
}
else
{
var tuple = new MemberTypePropertyProfileAccess(value, false, false);
MemberTypePropertyTypes.Add(propertyTypeAlias, tuple);
}
}
/// <summary>
/// Sets a boolean indicating whether a Property is a sensitive value on the Members profile.
/// </summary>
/// <param name="propertyTypeAlias">PropertyType Alias of the Property to set</param>
/// <param name="value">Boolean value, true or false</param>
public void SetIsSensitiveProperty(string propertyTypeAlias, bool value)
{
MemberTypePropertyProfileAccess propertyProfile;
if (MemberTypePropertyTypes.TryGetValue(propertyTypeAlias, out propertyProfile))
{
propertyProfile.IsSensitive = value;
}
else
{
var tuple = new MemberTypePropertyProfileAccess(false, false, true);
var tuple = new MemberTypePropertyProfileAccess(value, false);
MemberTypePropertyTypes.Add(propertyTypeAlias, tuple);
}
}
}
}
}
@@ -5,15 +5,13 @@ namespace Umbraco.Core.Models
/// </summary>
internal class MemberTypePropertyProfileAccess
{
public MemberTypePropertyProfileAccess(bool isVisible, bool isEditable, bool isSenstive)
public MemberTypePropertyProfileAccess(bool isVisible, bool isEditable)
{
IsVisible = isVisible;
IsEditable = isEditable;
IsSensitive = isSenstive;
}
public bool IsVisible { get; set; }
public bool IsEditable { get; set; }
public bool IsSensitive { get; set; }
}
}
}
@@ -63,4 +63,4 @@ namespace Umbraco.Core.Models.Membership
}
}
}
}
@@ -3,7 +3,7 @@ using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models.Membership
{
public interface IUserGroup : IAggregateRoot, IRememberBeingDirty, ICanBeDirty
public interface IUserGroup : IAggregateRoot
{
string Alias { get; set; }
@@ -41,4 +41,4 @@ namespace Umbraco.Core.Models.Membership
/// </summary>
int UserCount { get; }
}
}
}
@@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core.Models.Membership
{
internal class MemberExportModel
{
public int Id { get; set; }
public Guid Key { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public List<string> Groups { get; set; }
public string ContentTypeAlias { get; set; }
public DateTime CreateDate { get; set; }
public DateTime UpdateDate { get; set; }
public List<MemberExportProperty> Properties { get; set; }
}
}
@@ -1,14 +0,0 @@
using System;
namespace Umbraco.Core.Models.Membership
{
internal class MemberExportProperty
{
public int Id { get; set; }
public string Alias { get; set; }
public string Name { get; set; }
public object Value { get; set; }
public DateTime? CreateDate { get; set; }
public DateTime? UpdateDate { get; set; }
}
}
+1 -2
View File
@@ -706,6 +706,5 @@ namespace Umbraco.Core.Models.Membership
return _user.GetHashCode();
}
}
}
}
}
@@ -152,4 +152,4 @@ namespace Umbraco.Core.Models.Membership
public int UserCount { get; private set; }
}
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
@@ -435,4 +436,4 @@ namespace Umbraco.Core.Models
return clone;
}
}
}
}
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Models.PublishedContent
var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias;
if (constructors.ContainsKey(typeName))
throw new InvalidOperationException(string.Format("More than one type wants to be a model for content type {0}.", typeName));
throw new InvalidOperationException(string.Format("More that one type want to be a model for content type {0}.", typeName));
// should work everywhere, but slow
//_constructors[typeName] = constructor;
@@ -1,60 +0,0 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
[TableName(TableName)]
[PrimaryKey("id")]
[ExplicitColumns]
internal class AuditEntryDto
{
public const string TableName = "umbracoAudit";
public const int IpLength = 64;
public const int EventTypeLength = 256;
public const int DetailsLength = 1024;
[Column("id")]
[PrimaryKeyColumn]
public int Id { get; set; }
// there is NO foreign key to the users table here, neither for performing user nor for
// affected user, so we can delete users and NOT delete the associated audit trails, and
// users can still be identified via the details free-form text fields.
[Column("performingUserId")]
public int PerformingUserId { get; set; }
[Column("performingDetails")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(DetailsLength)]
public string PerformingDetails { get; set; }
[Column("performingIp")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(IpLength)]
public string PerformingIp { get; set; }
[Column("eventDateUtc")]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime EventDateUtc { get; set; }
[Column("affectedUserId")]
public int AffectedUserId { get; set; }
[Column("affectedDetails")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(DetailsLength)]
public string AffectedDetails { get; set; }
[Column("eventType")]
[Length(EventTypeLength)]
public string EventType { get; set; }
[Column("eventDetails")]
[NullSetting(NullSetting = NullSettings.Null)]
[Length(DetailsLength)]
public string EventDetails { get; set; }
}
}
@@ -1,44 +0,0 @@
using System;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
namespace Umbraco.Core.Models.Rdbms
{
[TableName(TableName)]
[PrimaryKey("id")]
[ExplicitColumns]
public class ConsentDto
{
internal const string TableName = "umbracoConsent";
[Column("id")]
[PrimaryKeyColumn]
public int Id { get; set; }
[Column("current")]
public bool Current { get; set; }
[Column("source")]
[Length(512)]
public string Source { get; set; }
[Column("context")]
[Length(128)]
public string Context { get; set; }
[Column("action")]
[Length(512)]
public string Action { get; set; }
[Column("createDate")]
[Constraint(Default = SystemMethods.CurrentDateTime)]
public DateTime CreateDate { get; set; }
[Column("state")]
public int State { get; set; }
[Column("comment")]
public string Comment { get; set; }
}
}
@@ -27,9 +27,5 @@ namespace Umbraco.Core.Models.Rdbms
[Column("viewOnProfile")]
[Constraint(Default = "0")]
public bool ViewOnProfile { get; set; }
[Column("isSensitive")]
[Constraint(Default = "0")]
public bool IsSensitive { get; set; }
}
}
}
@@ -45,9 +45,6 @@ namespace Umbraco.Core.Models.Rdbms
[Column("viewOnProfile")]
public bool ViewOnProfile { get; set; }
[Column("isSensitive")]
public bool IsSensitive { get; set; }
/* cmsDataType */
[Column("propertyEditorAlias")]
public string PropertyEditorAlias { get; set; }
@@ -55,8 +52,7 @@ namespace Umbraco.Core.Models.Rdbms
[Column("dbType")]
public string DbType { get; set; }
[Column("UniqueID")]
[Column("UniqueID")]
public Guid UniqueId { get; set; }
}
}
}
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Models.Rdbms
}
[Column("id")]
[PrimaryKeyColumn(IdentitySeed = 6)]
[PrimaryKeyColumn(IdentitySeed = 5)]
public int Id { get; set; }
[Column("userGroupAlias")]
@@ -68,4 +68,4 @@ namespace Umbraco.Core.Models.Rdbms
[ResultColumn]
public int UserCount { get; set; }
}
}
}
+1 -11
View File
@@ -261,16 +261,6 @@ namespace Umbraco.Core.Models
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.AdminGroupAlias);
}
/// <summary>
/// Determines whether this user has access to view sensitive data
/// </summary>
/// <param name="user"></param>
public static bool HasAccessToSensitiveData(this IUser user)
{
if (user == null) throw new ArgumentNullException("user");
return user.Groups != null && user.Groups.Any(x => x.Alias == Constants.Security.SensitiveDataGroupAlias);
}
// calc. start nodes, combining groups' and user's, and excluding what's in the bin
public static int[] CalculateContentStartNodeIds(this IUser user, IEntityService entityService)
{
@@ -423,4 +413,4 @@ namespace Umbraco.Core.Models
return lsn.ToArray();
}
}
}
}
@@ -1,52 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Factories
{
internal static class AuditEntryFactory
{
public static IEnumerable<IAuditEntry> BuildEntities(IEnumerable<AuditEntryDto> dtos)
{
return dtos.Select(BuildEntity).ToList();
}
public static IAuditEntry BuildEntity(AuditEntryDto dto)
{
var entity = new AuditEntry
{
Id = dto.Id,
PerformingUserId = dto.PerformingUserId,
PerformingDetails = dto.PerformingDetails,
PerformingIp = dto.PerformingIp,
EventDateUtc = dto.EventDateUtc,
AffectedUserId = dto.AffectedUserId,
AffectedDetails = dto.AffectedDetails,
EventType = dto.EventType,
EventDetails = dto.EventDetails
};
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
entity.ResetDirtyProperties(false);
return entity;
}
public static AuditEntryDto BuildDto(IAuditEntry entity)
{
return new AuditEntryDto
{
Id = entity.Id,
PerformingUserId = entity.PerformingUserId,
PerformingDetails = entity.PerformingDetails,
PerformingIp = entity.PerformingIp,
EventDateUtc = entity.EventDateUtc,
AffectedUserId = entity.AffectedUserId,
AffectedDetails = entity.AffectedDetails,
EventType = entity.EventType,
EventDetails = entity.EventDetails
};
}
}
}
@@ -1,65 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Factories
{
internal static class ConsentFactory
{
public static IEnumerable<IConsent> BuildEntities(IEnumerable<ConsentDto> dtos)
{
var ix = new Dictionary<string, Consent>();
var output = new List<Consent>();
foreach (var dto in dtos)
{
var k = dto.Source + "::" + dto.Context + "::" + dto.Action;
var consent = new Consent
{
Id = dto.Id,
Current = dto.Current,
CreateDate = dto.CreateDate,
Source = dto.Source,
Context = dto.Context,
Action = dto.Action,
State = (ConsentState) dto.State, // assume value is valid
Comment = dto.Comment
};
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
consent.ResetDirtyProperties(false);
if (ix.TryGetValue(k, out var current))
{
if (current.HistoryInternal == null)
current.HistoryInternal = new List<IConsent>();
current.HistoryInternal.Add(consent);
}
else
{
ix[k] = consent;
output.Add(consent);
}
}
return output;
}
public static ConsentDto BuildDto(IConsent entity)
{
return new ConsentDto
{
Id = entity.Id,
Current = entity.Current,
CreateDate = entity.CreateDate,
Source = entity.Source,
Context = entity.Context,
Action = entity.Action,
State = (int) entity.State,
Comment = entity.Comment
};
}
}
}
@@ -84,8 +84,7 @@ namespace Umbraco.Core.Persistence.Factories
NodeId = entity.Id,
PropertyTypeId = x.Id,
CanEdit = memberType.MemberCanEditProperty(x.Alias),
ViewOnProfile = memberType.MemberCanViewProperty(x.Alias),
IsSensitive = memberType.IsSensitiveProperty(x.Alias)
ViewOnProfile = memberType.MemberCanViewProperty(x.Alias)
}).ToList();
return dtos;
}
@@ -160,4 +159,4 @@ namespace Umbraco.Core.Persistence.Factories
#endregion
}
}
}
@@ -56,10 +56,10 @@ namespace Umbraco.Core.Persistence.Factories
//Add the standard PropertyType to the current list
propertyTypes.Add(standardPropertyType.Value);
//Internal dictionary for adding "MemberCanEdit", "VisibleOnProfile", "IsSensitive" properties to each PropertyType
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key,
new MemberTypePropertyProfileAccess(false, false, false));
new MemberTypePropertyProfileAccess(false, false));
}
memberType.NoGroupPropertyTypes = propertyTypes;
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Persistence.Factories
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit, typeDto.IsSensitive));
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit));
var tempGroupDto = groupDto;
@@ -157,7 +157,7 @@ namespace Umbraco.Core.Persistence.Factories
{
//Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType
memberType.MemberTypePropertyTypes.Add(typeDto.Alias,
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit, typeDto.IsSensitive));
new MemberTypePropertyProfileAccess(typeDto.ViewOnProfile, typeDto.CanEdit));
//ensures that any built-in membership properties have their correct dbtype assigned no matter
//what the underlying data type is
@@ -198,4 +198,4 @@ namespace Umbraco.Core.Persistence.Factories
}
}
}
}
@@ -1,41 +0,0 @@
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Mappers
{
/// <summary>
/// Represents a mapper for audit entry entities.
/// </summary>
[MapperFor(typeof(IAuditEntry))]
[MapperFor(typeof(AuditEntry))]
public sealed class AuditEntryMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance
= new ConcurrentDictionary<string, DtoMapModel>();
/// <summary>
/// Initializes a new instance of the <see cref="AuditEntryMapper"/> class.
/// </summary>
public AuditEntryMapper()
{
// note: why the base ctor does not invoke BuildMap is a mystery to me
BuildMap();
}
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
internal override void BuildMap()
{
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.Id, dto => dto.Id);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.PerformingUserId, dto => dto.PerformingUserId);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.PerformingDetails, dto => dto.PerformingDetails);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.PerformingIp, dto => dto.PerformingIp);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.EventDateUtc, dto => dto.EventDateUtc);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.AffectedUserId, dto => dto.AffectedUserId);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.AffectedDetails, dto => dto.AffectedDetails);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.EventType, dto => dto.EventType);
CacheMap<AuditEntry, AuditEntryDto>(entity => entity.EventDetails, dto => dto.EventDetails);
}
}
}
@@ -1,40 +0,0 @@
using System.Collections.Concurrent;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
namespace Umbraco.Core.Persistence.Mappers
{
/// <summary>
/// Represents a mapper for consent entities.
/// </summary>
[MapperFor(typeof(IConsent))]
[MapperFor(typeof(Consent))]
public sealed class ConsentMapper : BaseMapper
{
private static readonly ConcurrentDictionary<string, DtoMapModel> PropertyInfoCacheInstance
= new ConcurrentDictionary<string, DtoMapModel>();
/// <summary>
/// Initializes a new instance of the <see cref="ConsentMapper"/> class.
/// </summary>
public ConsentMapper()
{
// note: why the base ctor does not invoke BuildMap is a mystery to me
BuildMap();
}
internal override ConcurrentDictionary<string, DtoMapModel> PropertyInfoCache => PropertyInfoCacheInstance;
internal override void BuildMap()
{
CacheMap<Consent, ConsentDto>(entity => entity.Id, dto => dto.Id);
CacheMap<Consent, ConsentDto>(entity => entity.Current, dto => dto.Current);
CacheMap<Consent, ConsentDto>(entity => entity.CreateDate, dto => dto.CreateDate);
CacheMap<Consent, ConsentDto>(entity => entity.Source, dto => dto.Source);
CacheMap<Consent, ConsentDto>(entity => entity.Context, dto => dto.Context);
CacheMap<Consent, ConsentDto>(entity => entity.Action, dto => dto.Action);
CacheMap<Consent, ConsentDto>(entity => entity.State, dto => dto.State);
CacheMap<Consent, ConsentDto>(entity => entity.Comment, dto => dto.Comment);
}
}
}
@@ -178,13 +178,11 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 2, StartMediaId = -1, StartContentId = -1, Alias = "writer", Name = "Writers", DefaultPermissions = "CAH:F", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-edit" });
_database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 3, StartMediaId = -1, StartContentId = -1, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5Fï", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-tools" });
_database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 4, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.TranslatorGroupAlias, Name = "Translators", DefaultPermissions = "AF", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-globe" });
_database.Insert("umbracoUserGroup", "id", false, new UserGroupDto { Id = 5, StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.SensitiveDataGroupAlias, Name = "Sensitive data", DefaultPermissions = "", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-lock" });
}
private void CreateUmbracoUser2UserGroupData()
{
_database.Insert(new User2UserGroupDto { UserGroupId = 1, UserId = 0 }); //add admin to admins
_database.Insert(new User2UserGroupDto { UserGroupId = 5, UserId = 0 }); //add admin to sensitive data
_database.Insert(new User2UserGroupDto { UserGroupId = 1, UserId = 0 });
}
private void CreateUmbracoUserGroup2AppData()
@@ -339,4 +337,4 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
_database.Insert("umbracoMigration", "pk", false, dto);
}
}
}
}
@@ -92,9 +92,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
{52, typeof (UserGroup2NodePermissionDto) },
{53, typeof (UserGroup2AppDto) },
{54, typeof (UserStartNodeDto) },
{55, typeof (UserLoginDto)},
{56, typeof (ConsentDto)},
{57, typeof (AuditEntryDto)}
{55, typeof (UserLoginDto)}
};
#endregion
@@ -380,4 +378,4 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
#endregion
}
}
}
@@ -154,12 +154,6 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
return new Version(7, 7, 0);
}
//if the error is for isSensitive column it must be the previous version to 7.9 since that is when it is added
if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMemberType,isSensitive"))))
{
return new Version(7, 8, 0);
}
return UmbracoVersion.Current;
}
@@ -220,4 +214,4 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
return sb.ToString();
}
}
}
}
@@ -1,35 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.DatabaseAnnotations;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenEightZero
{
[Migration("7.9.0", 1, Constants.System.UmbracoMigrationName)]
public class AddIsSensitiveMemberTypeColumn : MigrationBase
{
public AddIsSensitiveMemberTypeColumn(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
//Don't exeucte if the column is already there
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).ToArray();
if (columns.Any(x => x.TableName.InvariantEquals("cmsMemberType") && x.ColumnName.InvariantEquals("isSensitive")) == false)
{
Create.Column("isSensitive").OnTable("cmsMemberType").AsBoolean().WithDefaultValue(0).NotNullable();
}
}
public override void Down()
{
}
}
}
@@ -1,29 +0,0 @@
using System;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenNineZero
{
[Migration("7.9.0", 1, Constants.System.UmbracoMigrationName)]
public class AddUmbracoAuditTable : MigrationBase
{
public AddUmbracoAuditTable(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{ }
public override void Up()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains(AuditEntryDto.TableName))
return;
Create.Table<AuditEntryDto>();
}
public override void Down()
{
throw new NotSupportedException();
}
}
}
@@ -1,29 +0,0 @@
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenNineZero
{
[Migration("7.9.0", 1, Constants.System.UmbracoMigrationName)]
public class AddUmbracoConsentTable : MigrationBase
{
public AddUmbracoConsentTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray();
if (tables.InvariantContains(ConsentDto.TableName))
return;
Create.Table<ConsentDto>();
}
public override void Down()
{
}
}
}
@@ -1,37 +0,0 @@
using System;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenNineZero
{
[Migration("7.9.0", 2, Constants.System.UmbracoMigrationName)]
public class CreateSensitiveDataUserGroup : MigrationBase
{
public CreateSensitiveDataUserGroup(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
Execute.Code(database =>
{
//Don't exeucte if the group is already there
var exists = database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoUserGroup WHERE userGroupAlias = @userGroupAlias",
new {userGroupAlias = Constants.Security.SensitiveDataGroupAlias });
if (exists == 0)
{
var resultId = database.Insert("umbracoUserGroup", "id", new UserGroupDto { StartMediaId = -1, StartContentId = -1, Alias = Constants.Security.SensitiveDataGroupAlias, Name = "Sensitive data", DefaultPermissions = "", CreateDate = DateTime.Now, UpdateDate = DateTime.Now, Icon = "icon-lock" });
database.Insert(new User2UserGroupDto { UserGroupId = Convert.ToInt32(resultId), UserId = 0 }); //add admin to sensitive data
}
return string.Empty;
});
}
public override void Down()
{
}
}
}
+7 -8
View File
@@ -402,7 +402,7 @@ namespace Umbraco.Core.Persistence
}
// Helper to handle named parameters from object properties
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
{
return rxParams.Replace(_sql, m =>
@@ -545,7 +545,7 @@ namespace Umbraco.Core.Persistence
}
// Create a command
static Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
static readonly Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args)
{
// Perform named argument replacements
@@ -666,8 +666,8 @@ namespace Umbraco.Core.Persistence
return ExecuteScalar<T>(sql.SQL, sql.Arguments);
}
Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
static readonly Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
string AddSelectClause<T>(string sql)
{
if (sql.StartsWith(";"))
@@ -701,9 +701,9 @@ namespace Umbraco.Core.Persistence
return Fetch<T>(sql.SQL, sql.Arguments);
}
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
static readonly Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
{
sqlSelectRemoved = null;
@@ -2546,5 +2546,4 @@ namespace Umbraco.Core.Persistence
}
}
}
}
@@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Represents the PetaPoco implementatino of <see cref="IAuditEntryRepository"/>.
/// </summary>
internal class AuditEntryRepository : PetaPocoRepositoryBase<int, IAuditEntry>, IAuditEntryRepository
{
/// <summary>
/// Initializes a new instance of the <see cref="AuditEntryRepository"/> class.
/// </summary>
public AuditEntryRepository(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{ }
protected override Guid NodeObjectTypeId => throw new NotSupportedException();
/// <inheritdoc />
protected override IAuditEntry PerformGet(int id)
{
var sql = new Sql()
.Select("*")
.From<AuditEntryDto>(SqlSyntax)
.Where<AuditEntryDto>(x => x.Id == id, SqlSyntax);
var dto = Database.FirstOrDefault<AuditEntryDto>(sql);
return dto == null ? null : AuditEntryFactory.BuildEntity(dto); }
/// <inheritdoc />
protected override IEnumerable<IAuditEntry> PerformGetAll(params int[] ids)
{
if (ids.Length == 0)
{
var sql = new Sql()
.Select("*")
.From<AuditEntryDto>(SqlSyntax);
return Database.Fetch<AuditEntryDto>(sql).Select(AuditEntryFactory.BuildEntity);
}
var entries = new List<IAuditEntry>();
foreach (var group in ids.InGroupsOf(2000))
{
var sql = new Sql()
.Select("*")
.From<AuditEntryDto>(SqlSyntax)
.WhereIn<AuditEntryDto>(x => x.Id, group, SqlSyntax);
entries.AddRange(Database.Fetch<AuditEntryDto>(sql).Select(AuditEntryFactory.BuildEntity));
}
return entries;
}
/// <inheritdoc />
protected override IEnumerable<IAuditEntry> PerformGetByQuery(IQuery<IAuditEntry> query)
{
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IAuditEntry>(sqlClause, query);
var sql = translator.Translate();
return Database.Fetch<AuditEntryDto>(sql).Select(AuditEntryFactory.BuildEntity);
}
/// <inheritdoc />
protected override Sql GetBaseQuery(bool isCount)
{
return new Sql().Select(isCount ? "COUNT(*)" : "*").From<AuditEntryDto>(SqlSyntax);
}
/// <inheritdoc />
protected override string GetBaseWhereClause()
{
return $"{AuditEntryDto.TableName}.id = @Id";
}
/// <inheritdoc />
protected override IEnumerable<string> GetDeleteClauses()
{
throw new NotSupportedException("Audit entries cannot be deleted.");
}
/// <inheritdoc />
protected override void PersistNewItem(IAuditEntry entity)
{
((Entity) entity).AddingEntity();
var dto = AuditEntryFactory.BuildDto(entity);
Database.Insert(dto);
entity.Id = dto.Id;
entity.ResetDirtyProperties();
}
/// <inheritdoc />
protected override void PersistUpdatedItem(IAuditEntry entity)
{
throw new NotSupportedException("Audit entries cannot be updated.");
}
/// <inheritdoc />
public IEnumerable<IAuditEntry> GetPage(long pageIndex, int pageCount, out long records)
{
var sql = new Sql()
.Select("*")
.From<AuditEntryDto>(SqlSyntax)
.OrderByDescending<AuditEntryDto>(x => x.EventDateUtc, SqlSyntax);
var page = Database.Page<AuditEntryDto>(pageIndex + 1, pageCount, sql);
records = page.TotalItems;
return page.Items.Select(AuditEntryFactory.BuildEntity);
}
/// <inheritdoc />
public bool IsAvailable()
{
var tables = SqlSyntax.GetTablesInSchema(Database).ToArray();
return tables.InvariantContains(AuditEntryDto.TableName);
}
}
}
@@ -1,103 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Represents the PetaPoco implementation of <see cref="IConsentRepository"/>.
/// </summary>
internal class ConsentRepository : PetaPocoRepositoryBase<int, IConsent>, IConsentRepository
{
/// <summary>
/// Initializes a new instance of the <see cref="ConsentRepository"/> class.
/// </summary>
public ConsentRepository(IScopeUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
: base(work, cache, logger, sqlSyntax)
{ }
/// <inheritdoc />
protected override Guid NodeObjectTypeId => throw new NotSupportedException();
/// <inheritdoc />
public void ClearCurrent(string source, string context, string action)
{
var sql = new Sql($@"UPDATE {SqlSyntax.GetQuotedTableName(ConsentDto.TableName)}
SET {SqlSyntax.GetQuotedColumnName("current")} = @0
WHERE {SqlSyntax.GetQuotedColumnName("source")} = @1 AND {SqlSyntax.GetQuotedColumnName("context")} = @2 AND {SqlSyntax.GetQuotedColumnName("action")} = @3
AND {SqlSyntax.GetQuotedColumnName("current")} <> @0 ", false, source, context, action);
Database.Execute(sql);
}
/// <inheritdoc />
protected override IConsent PerformGet(int id)
{
throw new NotImplementedException();
}
/// <inheritdoc />
protected override IEnumerable<IConsent> PerformGetAll(params int[] ids)
{
throw new NotImplementedException();
}
/// <inheritdoc />
protected override IEnumerable<IConsent> PerformGetByQuery(IQuery<IConsent> query)
{
var sqlClause = new Sql().Select("*").From<ConsentDto>(SqlSyntax);
var translator = new SqlTranslator<IConsent>(sqlClause, query);
var sql = translator.Translate().OrderByDescending<ConsentDto>(x => x.CreateDate, SqlSyntax);
return ConsentFactory.BuildEntities(Database.Fetch<ConsentDto>(sql));
}
/// <inheritdoc />
protected override Sql GetBaseQuery(bool isCount)
{
throw new NotImplementedException();
}
/// <inheritdoc />
protected override string GetBaseWhereClause()
{
throw new NotImplementedException();
}
/// <inheritdoc />
protected override IEnumerable<string> GetDeleteClauses()
{
throw new NotImplementedException();
}
/// <inheritdoc />
protected override void PersistNewItem(IConsent entity)
{
((Entity) entity).AddingEntity();
var dto = ConsentFactory.BuildDto(entity);
Database.Insert(dto);
entity.Id = dto.Id;
entity.ResetDirtyProperties();
}
/// <inheritdoc />
protected override void PersistUpdatedItem(IConsent entity)
{
((Entity) entity).UpdatingEntity();
var dto = ConsentFactory.BuildDto(entity);
Database.Update(dto);
entity.ResetDirtyProperties();
IsolatedCache.ClearCacheItem(GetCacheIdKey<IConsent>(entity.Id));
}
}
}
@@ -1,22 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Represents a repository for <see cref="IAuditEntry"/> entities.
/// </summary>
public interface IAuditEntryRepository : IRepositoryQueryable<int, IAuditEntry>
{
/// <summary>
/// Gets a page of entries.
/// </summary>
IEnumerable<IAuditEntry> GetPage(long pageIndex, int pageCount, out long records);
/// <summary>
/// Determines whether the repository is available.
/// </summary>
/// <remarks>During an upgrade, the repository may not be available, until the table has been created.</remarks>
bool IsAvailable();
}
}
@@ -1,15 +0,0 @@
using Umbraco.Core.Models;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Represents a repository for <see cref="IConsent"/> entities.
/// </summary>
public interface IConsentRepository : IRepositoryQueryable<int, IConsent>
{
/// <summary>
/// Clears the current flag.
/// </summary>
void ClearCurrent(string source, string context, string action);
}
}
@@ -39,7 +39,5 @@ namespace Umbraco.Core.Persistence.Repositories
void AssignRoles(int[] memberIds, string[] roleNames);
void DissociateRoles(int[] memberIds, string[] roleNames);
int[] GetMemberIds(string[] names);
}
}
}
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
public IEnumerable<IMemberGroup> GetMemberGroupsForMember(string username)
{
{
var sql = new Sql()
.Select("un.*")
.From("umbracoNode AS un")
@@ -192,15 +192,16 @@ namespace Umbraco.Core.Persistence.Repositories
.InnerJoin("cmsMember")
.On("cmsMember.nodeId = cmsMember2MemberGroup.Member")
.Where("un.nodeObjectType=@objectType", new { objectType = NodeObjectTypeId })
.Where("cmsMember.LoginName=@loginName", new { loginName = username });
.Where("cmsMember.LoginName=@loginName", new { loginName = username });
return Database.Fetch<NodeDto>(sql)
.DistinctBy(dto => dto.NodeId)
.Select(x => _modelFactory.BuildEntity(x));
}
public int[] GetMemberIds(string[] names)
public void AssignRoles(string[] usernames, string[] roleNames)
{
//first get the member ids based on the usernames
var memberSql = new Sql();
var memberObjectType = new Guid(Constants.ObjectTypes.Member);
memberSql.Select("umbracoNode.id")
@@ -208,19 +209,25 @@ namespace Umbraco.Core.Persistence.Repositories
.InnerJoin<MemberDto>()
.On<NodeDto, MemberDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == memberObjectType)
.Where("cmsMember.LoginName in (@names)", new { names });
return Database.Fetch<int>(memberSql).ToArray();
}
.Where("cmsMember.LoginName in (@usernames)", new { usernames = usernames });
var memberIds = Database.Fetch<int>(memberSql).ToArray();
public void AssignRoles(string[] usernames, string[] roleNames)
{
var memberIds = GetMemberIds(usernames);
AssignRolesInternal(memberIds, roleNames);
}
public void DissociateRoles(string[] usernames, string[] roleNames)
{
var memberIds = GetMemberIds(usernames);
//first get the member ids based on the usernames
var memberSql = new Sql();
var memberObjectType = new Guid(Constants.ObjectTypes.Member);
memberSql.Select("umbracoNode.id")
.From<NodeDto>()
.InnerJoin<MemberDto>()
.On<NodeDto, MemberDto>(dto => dto.NodeId, dto => dto.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == memberObjectType)
.Where("cmsMember.LoginName in (@usernames)", new { usernames = usernames });
var memberIds = Database.Fetch<int>(memberSql).ToArray();
DissociateRolesInternal(memberIds, roleNames);
}
@@ -330,4 +337,4 @@ namespace Umbraco.Core.Persistence.Repositories
/// </summary>
internal static event TypedEventHandler<IMemberGroupRepository, SaveEventArgs<IMemberGroup>> SavedMemberGroup;
}
}
}
@@ -90,8 +90,7 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Select("umbracoNode.*", "cmsContentType.*", "cmsPropertyType.id AS PropertyTypeId", "cmsPropertyType.Alias",
"cmsPropertyType.Name", "cmsPropertyType.Description", "cmsPropertyType.mandatory", "cmsPropertyType.UniqueID",
"cmsPropertyType.validationRegExp", "cmsPropertyType.dataTypeId", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder",
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId",
"cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsMemberType.isSensitive",
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId", "cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile",
"cmsDataType.propertyEditorAlias", "cmsDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
"cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID",
"cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId")
@@ -363,4 +362,4 @@ namespace Umbraco.Core.Persistence.Repositories
return Attempt<Guid>.Fail(propertyEditor);
}
}
}
}
@@ -308,9 +308,6 @@ namespace Umbraco.Core.Persistence.Repositories
public virtual void PersistNewItem(IEntity entity)
{
CachePolicy.Create((TEntity) entity, PersistNewItem);
//TODO: In v8 we should automatically reset dirty properties so they don't have to be manually reset in all of the implemented repositories
//if (entity is ICanBeDirty dirty) dirty.ResetDirtyProperties();
}
/// <summary>
@@ -320,8 +317,6 @@ namespace Umbraco.Core.Persistence.Repositories
public virtual void PersistUpdatedItem(IEntity entity)
{
CachePolicy.Update((TEntity) entity, PersistUpdatedItem);
//TODO: In v8 we should automatically reset dirty properties so they don't have to be manually reset in all of the implemented repositories
//if (entity is ICanBeDirty dirty) dirty.ResetDirtyProperties();
}
/// <summary>
@@ -348,4 +343,4 @@ namespace Umbraco.Core.Persistence.Repositories
UnitOfWork.DisposeIfDisposable();
}
}
}
}
@@ -285,7 +285,7 @@ umbracoUserGroup.userGroupName, umbracoUserGroup2App.app, umbracoUserGroup2App.u
protected override void PersistNewItem(IUserGroup entity)
{
((UserGroup)entity).AddingEntity();
((UserGroup)entity).AddingEntity();
var userGroupDto = UserGroupFactory.BuildDto(entity);
@@ -293,8 +293,6 @@ umbracoUserGroup.userGroupName, umbracoUserGroup2App.app, umbracoUserGroup2App.u
entity.Id = id;
PersistAllowedSections(entity);
entity.ResetDirtyProperties();
}
protected override void PersistUpdatedItem(IUserGroup entity)
@@ -306,8 +304,6 @@ umbracoUserGroup.userGroupName, umbracoUserGroup2App.app, umbracoUserGroup2App.u
Database.Update(userGroupDto);
PersistAllowedSections(entity);
entity.ResetDirtyProperties();
}
private void PersistAllowedSections(IUserGroup entity)
@@ -460,4 +456,4 @@ umbracoUserGroup.userGroupName, umbracoUserGroup2App.app, umbracoUserGroup2App.u
}
}
}
}
}
@@ -54,8 +54,8 @@ namespace Umbraco.Core.Persistence
//if the result is already a DeepCloneRuntimeCacheProvider then return it, otherwise
//wrap the result with a DeepCloneRuntimeCacheProvider
return cache is DeepCloneRuntimeCacheProvider
? cache
return cache is DeepCloneRuntimeCacheProvider
? cache
: new DeepCloneRuntimeCacheProvider(cache);
};
}
@@ -158,11 +158,11 @@ namespace Umbraco.Core.Persistence
CreateTemplateRepository(uow),
CreateTagRepository(uow),
_settings.Content)
{
{
//duplicates are allowed
EnsureUniqueNaming = false
};
}
}
public virtual IContentTypeRepository CreateContentTypeRepository(IScopeUnitOfWork uow)
{
@@ -319,13 +319,13 @@ namespace Umbraco.Core.Persistence
var userMembershipProvider = MembershipProviderExtensions.GetUsersMembershipProvider();
var passwordConfig = userMembershipProvider == null || userMembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed
? null
: new System.Collections.Generic.Dictionary<string, string> {{"hashAlgorithm", Membership.HashAlgorithmType}};
: new System.Collections.Generic.Dictionary<string, string> {{"hashAlgorithm", Membership.HashAlgorithmType}};
return new UserRepository(
uow,
//Need to cache users - we look up user information more than anything in the back office!
_cacheHelper,
_logger,
_logger,
_sqlSyntax,
passwordConfig);
}
@@ -397,15 +397,5 @@ namespace Umbraco.Core.Persistence
_logger,
_sqlSyntax);
}
public IConsentRepository CreateConsentRepository(IScopeUnitOfWork uow)
{
return new ConsentRepository(uow, _cacheHelper, _logger, _sqlSyntax);
}
public IAuditEntryRepository CreateAuditEntryRepository(IScopeUnitOfWork uow)
{
return new AuditEntryRepository(uow, _cacheHelper, _logger, _sqlSyntax);
}
}
}
@@ -21,7 +21,7 @@ namespace Umbraco.Core.PropertyEditors
public PropertyEditorResolver(IServiceProvider serviceProvider, ILogger logger, Func<IEnumerable<Type>> typeListProducerList, IRuntimeCacheProvider runtimeCache)
: base(serviceProvider, logger, typeListProducerList, ObjectLifetimeScope.Application)
{
var builder = new ManifestBuilder(
var builder = new ManifestBuilder(
runtimeCache,
new ManifestParser(new DirectoryInfo(IOHelper.MapPath("~/App_Plugins")), runtimeCache));
@@ -49,10 +49,7 @@ namespace Umbraco.Core.PropertyEditors
{
var nestedContentEditorFromPackage = editors.FirstOrDefault(x => x.Alias == "Our.Umbraco.NestedContent");
if (nestedContentEditorFromPackage != null)
{
nestedContentEditorFromPackage.Name = "(Obsolete) " + nestedContentEditorFromPackage.Name;
nestedContentEditorFromPackage.IsDeprecated = true;
}
return editors;
}
@@ -77,4 +74,4 @@ namespace Umbraco.Core.PropertyEditors
return PropertyEditors.SingleOrDefault(x => x.Alias == alias);
}
}
}
}
+3
View File
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Scoping
public NoScope(ScopeProvider scopeProvider)
{
_scopeProvider = scopeProvider;
Timestamp = DateTime.Now;
#if DEBUG_SCOPES
_scopeProvider.RegisterScope(this);
#endif
@@ -28,6 +29,8 @@ namespace Umbraco.Core.Scoping
private readonly Guid _instanceId = Guid.NewGuid();
public Guid InstanceId { get { return _instanceId; } }
public DateTime Timestamp { get; }
/// <inheritdoc />
public bool CallContext { get { return false; } }
+1 -1
View File
@@ -374,7 +374,7 @@ namespace Umbraco.Core.Scoping
}
var parent = ParentScope;
_scopeProvider.AmbientScope = parent;
_scopeProvider.AmbientScope = parent; // might be null = this is how scopes are removed from context objects
#if DEBUG_SCOPES
_scopeProvider.Disposed(this);
+51 -6
View File
@@ -2,10 +2,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Web;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
#if DEBUG_SCOPES
using System.Linq;
@@ -66,22 +68,38 @@ namespace Umbraco.Core.Scoping
// tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
// but we don't want to make all of our objects serializable since they are *not* meant to be
// used in cross-AppDomain scenario anyways.
//
// in addition, whatever goes into the logical call context is serialized back and forth any
// time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
// "object" instance - and so we cannot use a random object as a key.
// time cross-AppDomain code executes, so if we put an "object" there, we'll get *another*
// "object" instance back - and so we cannot use a random object as a key.
//
// so what we do is: we register a guid in the call context, and we keep a table mapping those
// guids to the actual objects. the guid serializes back and forth without causing any issue,
// and we can retrieve the actual objects from the table.
// only issue: how are we supposed to clear the table? we can't, really. objects should take
// care of de-registering themselves from context.
// everything we use does, except the NoScope scope, which just stays there
//
// during tests, NoScope can to into call context... nothing much we can do about it
// so far, the only objects that go into this table are scopes (using ScopeItemKey) and
// scope contexts (using ContextItemKey).
private static readonly object StaticCallContextObjectsLock = new object();
private static readonly Dictionary<Guid, object> StaticCallContextObjects
= new Dictionary<Guid, object>();
// normal scopes and scope contexts take greate care removing themselves when disposed, so it
// is all safe. OTOH the NoScope *CANNOT* remove itself, this is by design, it *WILL* leak and
// there is little (nothing) we can do about it - NoScope exists for backward compatibility
// reasons and relying on it is greatly discouraged.
//
// however... we can *try* at protecting the app against memory leaks, by collecting NoScope
// instances that are too old. if anything actually *need* to retain a NoScope instance for
// a long time, it will break. but that's probably ok. so: the constants below define how
// long a NoScope instance can stay in the table before being removed, and how often we should
// collect the table - and collecting happens anytime SetCallContextObject is invoked
private static readonly TimeSpan StaticCallContextNoScopeLifeSpan = TimeSpan.FromMinutes(30);
private static readonly TimeSpan StaticCallContextCollectPeriod = TimeSpan.FromMinutes(4);
private static DateTime _staticCallContextLastCollect = DateTime.MinValue;
#if DEBUG_SCOPES
public Dictionary<Guid, object> CallContextObjects
{
@@ -156,6 +174,7 @@ namespace Umbraco.Core.Scoping
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Remove(objectKey);
CollectStaticCallContextObjectsLocked();
}
}
else
@@ -171,11 +190,37 @@ namespace Umbraco.Core.Scoping
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
#endif
StaticCallContextObjects.Add(objectKey, value);
CollectStaticCallContextObjectsLocked();
}
CallContext.LogicalSetData(key, objectKey);
}
}
private static void CollectStaticCallContextObjectsLocked()
{
// is it time to collect?
var now = DateTime.Now;
if (now - _staticCallContextLastCollect <= StaticCallContextCollectPeriod)
return;
// disable warning: this method is invoked from within a lock
// ReSharper disable InconsistentlySynchronizedField
var threshold = now.Add(-StaticCallContextNoScopeLifeSpan);
var guids = StaticCallContextObjects
.Where(x => x.Value is NoScope noScope && noScope.Timestamp < threshold)
.Select(x => x.Key)
.ToList();
if (guids.Count > 0)
{
LogHelper.Warn<ScopeProvider>($"Collected {guids.Count} NoScope instances from StaticCallContextObjects.");
foreach (var guid in guids)
StaticCallContextObjects.Remove(guid);
}
// ReSharper restore InconsistentlySynchronizedField
_staticCallContextLastCollect = now;
}
// this is for tests exclusively until we have a proper accessor in v8
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
@@ -420,33 +420,6 @@ namespace Umbraco.Core.Security
return await base.CheckPasswordAsync(user, password);
}
public override Task<IdentityResult> ResetPasswordAsync(int userId, string token, string newPassword)
{
var result = base.ResetPasswordAsync(userId, token, newPassword);
if (result.Result.Succeeded)
RaisePasswordResetEvent(userId);
return result;
}
/// <summary>
/// This is a special method that will reset the password but will raise the Password Changed event instead of the reset event
/// </summary>
/// <param name="userId"></param>
/// <param name="token"></param>
/// <param name="newPassword"></param>
/// <returns></returns>
/// <remarks>
/// We use this because in the back office the only way an admin can change another user's password without first knowing their password
/// is to generate a token and reset it, however, when we do this we want to track a password change, not a password reset
/// </remarks>
public Task<IdentityResult> ChangePasswordWithResetAsync(int userId, string token, string newPassword)
{
var result = base.ResetPasswordAsync(userId, token, newPassword);
if (result.Result.Succeeded)
RaisePasswordChangedEvent(userId);
return result;
}
public override Task<IdentityResult> ChangePasswordAsync(int userId, string currentPassword, string newPassword)
{
var result = base.ChangePasswordAsync(userId, currentPassword, newPassword);
@@ -581,27 +554,27 @@ namespace Umbraco.Core.Security
internal void RaiseAccountLockedEvent(int userId)
{
OnAccountLocked(new IdentityAuditEventArgs(AuditEvent.AccountLocked, GetCurrentRequestIpAddress(), affectedUser: userId));
OnAccountLocked(new IdentityAuditEventArgs(AuditEvent.AccountLocked, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseAccountUnlockedEvent(int userId)
{
OnAccountUnlocked(new IdentityAuditEventArgs(AuditEvent.AccountUnlocked, GetCurrentRequestIpAddress(), affectedUser: userId));
OnAccountUnlocked(new IdentityAuditEventArgs(AuditEvent.AccountUnlocked, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseForgotPasswordRequestedEvent(int userId)
{
OnForgotPasswordRequested(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordRequested, GetCurrentRequestIpAddress(), affectedUser: userId));
OnForgotPasswordRequested(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordRequested, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseForgotPasswordChangedSuccessEvent(int userId)
{
OnForgotPasswordChangedSuccess(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordChangedSuccess, GetCurrentRequestIpAddress(), affectedUser: userId));
OnForgotPasswordChangedSuccess(new IdentityAuditEventArgs(AuditEvent.ForgotPasswordChangedSuccess, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseLoginFailedEvent(int userId)
{
OnLoginFailed(new IdentityAuditEventArgs(AuditEvent.LoginFailed, GetCurrentRequestIpAddress(), affectedUser: userId));
OnLoginFailed(new IdentityAuditEventArgs(AuditEvent.LoginFailed, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseInvalidLoginAttemptEvent(string username)
@@ -611,33 +584,31 @@ namespace Umbraco.Core.Security
internal void RaiseLoginRequiresVerificationEvent(int userId)
{
OnLoginRequiresVerification(new IdentityAuditEventArgs(AuditEvent.LoginRequiresVerification, GetCurrentRequestIpAddress(), affectedUser: userId));
OnLoginRequiresVerification(new IdentityAuditEventArgs(AuditEvent.LoginRequiresVerification, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseLoginSuccessEvent(int userId)
{
OnLoginSuccess(new IdentityAuditEventArgs(AuditEvent.LoginSucces, GetCurrentRequestIpAddress(), affectedUser: userId));
OnLoginSuccess(new IdentityAuditEventArgs(AuditEvent.LoginSucces, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseLogoutSuccessEvent(int userId)
{
OnLogoutSuccess(new IdentityAuditEventArgs(AuditEvent.LogoutSuccess, GetCurrentRequestIpAddress(), affectedUser: userId));
OnLogoutSuccess(new IdentityAuditEventArgs(AuditEvent.LogoutSuccess, GetCurrentRequestIpAddress(), userId));
}
internal void RaisePasswordChangedEvent(int userId)
{
OnPasswordChanged(new IdentityAuditEventArgs(AuditEvent.PasswordChanged, GetCurrentRequestIpAddress(), affectedUser: userId));
OnPasswordChanged(new IdentityAuditEventArgs(AuditEvent.PasswordChanged, GetCurrentRequestIpAddress(), userId));
}
//TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense.
internal void RaisePasswordResetEvent(int userId)
{
OnPasswordReset(new IdentityAuditEventArgs(AuditEvent.PasswordReset, GetCurrentRequestIpAddress(), affectedUser: userId));
OnPasswordReset(new IdentityAuditEventArgs(AuditEvent.PasswordReset, GetCurrentRequestIpAddress(), userId));
}
internal void RaiseResetAccessFailedCountEvent(int userId)
{
OnResetAccessFailedCount(new IdentityAuditEventArgs(AuditEvent.ResetAccessFailedCount, GetCurrentRequestIpAddress(), affectedUser: userId));
OnResetAccessFailedCount(new IdentityAuditEventArgs(AuditEvent.ResetAccessFailedCount, GetCurrentRequestIpAddress(), userId));
}
public static event EventHandler AccountLocked;
+2 -92
View File
@@ -4,7 +4,6 @@ using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
@@ -14,13 +13,9 @@ namespace Umbraco.Core.Services
{
public sealed class AuditService : ScopeRepositoryService, IAuditService
{
private readonly Lazy<bool> _isAvailable;
public AuditService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory)
: base(provider, repositoryFactory, logger, eventMessagesFactory)
{
_isAvailable = new Lazy<bool>(DetermineIsAvailable);
}
{ }
public void Add(AuditType type, string comment, int userId, int objectId)
{
@@ -112,90 +107,5 @@ namespace Umbraco.Core.Services
return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, orderDirection, auditTypeFilter, customFilter);
}
}
/// <inheritdoc />
public IAuditEntry Write(int performingUserId, string perfomingDetails, string performingIp, DateTime eventDateUtc, int affectedUserId, string affectedDetails, string eventType, string eventDetails)
{
if (performingUserId < 0) throw new ArgumentOutOfRangeException(nameof(performingUserId));
if (string.IsNullOrWhiteSpace(perfomingDetails)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(perfomingDetails));
if (string.IsNullOrWhiteSpace(eventType)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(eventType));
if (string.IsNullOrWhiteSpace(eventDetails)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(eventDetails));
//we need to truncate the data else we'll get SQL errors
affectedDetails = affectedDetails?.Substring(0, Math.Min(affectedDetails.Length, AuditEntryDto.DetailsLength));
eventDetails = eventDetails.Substring(0, Math.Min(eventDetails.Length, AuditEntryDto.DetailsLength));
//validate the eventType - must contain a forward slash, no spaces, no special chars
var eventTypeParts = eventType.ToCharArray();
if (eventTypeParts.Contains('/') == false || eventTypeParts.All(c => char.IsLetterOrDigit(c) || c == '/' || c == '-') == false)
throw new ArgumentException(nameof(eventType) + " must contain only alphanumeric characters, hyphens and at least one '/' defining a category");
if (eventType.Length > AuditEntryDto.EventTypeLength)
throw new ArgumentException($"Must be max {AuditEntryDto.EventTypeLength} chars.", nameof(eventType));
if (performingIp != null && performingIp.Length > AuditEntryDto.IpLength)
throw new ArgumentException($"Must be max {AuditEntryDto.EventTypeLength} chars.", nameof(performingIp));
var entry = new AuditEntry
{
PerformingUserId = performingUserId,
PerformingDetails = perfomingDetails,
PerformingIp = performingIp,
EventDateUtc = eventDateUtc,
AffectedUserId = affectedUserId,
AffectedDetails = affectedDetails,
EventType = eventType,
EventDetails = eventDetails
};
if (_isAvailable.Value == false) return entry;
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateAuditEntryRepository(uow);
repository.AddOrUpdate(entry);
uow.Commit();
}
return entry;
}
//TODO: Currently used in testing only, not part of the interface, need to add queryable methods to the interface instead
internal IEnumerable<IAuditEntry> GetAll()
{
if (_isAvailable.Value == false) return Enumerable.Empty<IAuditEntry>();
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateAuditEntryRepository(uow);
return repository.GetAll();
}
}
//TODO: Currently used in testing only, not part of the interface, need to add queryable methods to the interface instead
internal IEnumerable<IAuditEntry> GetPage(long pageIndex, int pageCount, out long records)
{
if (_isAvailable.Value == false)
{
records = 0;
return Enumerable.Empty<IAuditEntry>();
}
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateAuditEntryRepository(uow);
return repository.GetPage(pageIndex, pageCount, out records);
}
}
/// <summary>
/// Determines whether the repository is available.
/// </summary>
private bool DetermineIsAvailable()
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateAuditEntryRepository(uow);
return repository.IsAvailable();
}
}
}
}
}
@@ -1,81 +0,0 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
/// <summary>
/// Implements <see cref="IContentService"/>.
/// </summary>
internal class ConsentService : ScopeRepositoryService, IConsentService
{
/// <summary>
/// Initializes a new instance of the <see cref="ContentService"/> class.
/// </summary>
public ConsentService(IScopeUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory)
: base(provider, repositoryFactory, logger, eventMessagesFactory)
{ }
/// <inheritdoc />
public IConsent RegisterConsent(string source, string context, string action, ConsentState state, string comment = null)
{
// prevent stupid states
var v = 0;
if ((state & ConsentState.Pending) > 0) v++;
if ((state & ConsentState.Granted) > 0) v++;
if ((state & ConsentState.Revoked) > 0) v++;
if (v != 1)
throw new ArgumentException("Invalid state.", nameof(state));
var consent = new Consent
{
Current = true,
Source = source,
Context = context,
Action = action,
CreateDate = DateTime.Now,
State = state,
Comment = comment
};
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateConsentRepository(uow);
repository.ClearCurrent(source, context, action);
repository.AddOrUpdate(consent);
uow.Commit();
}
return consent;
}
/// <inheritdoc />
public IEnumerable<IConsent> LookupConsent(string source = null, string context = null, string action = null,
bool sourceStartsWith = false, bool contextStartsWith = false, bool actionStartsWith = false,
bool includeHistory = false)
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateConsentRepository(uow);
IQuery<IConsent> query = new Query<IConsent>();
if (string.IsNullOrWhiteSpace(source) == false)
query = sourceStartsWith ? query.Where(x => x.Source.StartsWith(source)) : query.Where(x => x.Source == source);
if (string.IsNullOrWhiteSpace(context) == false)
query = contextStartsWith ? query.Where(x => x.Context.StartsWith(context)) : query.Where(x => x.Context == context);
if (string.IsNullOrWhiteSpace(action) == false)
query = actionStartsWith ? query.Where(x => x.Action.StartsWith(action)) : query.Where(x => x.Action == action);
if (includeHistory == false)
query = query.Where(x => x.Current);
return repository.GetByQuery(query);
}
}
}
}
+1 -26
View File
@@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Core.Services
{
/// <summary>
/// Represents a service for handling audit.
/// </summary>
public interface IAuditService : IService
{
void Add(AuditType type, string comment, int userId, int objectId);
@@ -59,25 +54,5 @@ namespace Umbraco.Core.Services
Direction orderDirection = Direction.Descending,
AuditType[] auditTypeFilter = null,
IQuery<IAuditItem> customFilter = null);
/// <summary>
/// Writes an audit entry for an audited event.
/// </summary>
/// <param name="performingUserId">The identifier of the user triggering the audited event.</param>
/// <param name="perfomingDetails">Free-form details about the user triggering the audited event.</param>
/// <param name="performingIp">The IP address or the request triggering the audited event.</param>
/// <param name="eventDateUtc">The date and time of the audited event.</param>
/// <param name="affectedUserId">The identifier of the user affected by the audited event.</param>
/// <param name="affectedDetails">Free-form details about the entity affected by the audited event.</param>
/// <param name="eventType">
/// The type of the audited event - must contain only alphanumeric chars and hyphens with forward slashes separating categories.
/// <example>
/// The eventType will generally be formatted like: {application}/{entity-type}/{category}/{sub-category}
/// Example: umbraco/user/sign-in/failed
/// </example>
/// </param>
/// <param name="eventDetails">Free-form details about the audited event.</param>
IAuditEntry Write(int performingUserId, string perfomingDetails, string performingIp, DateTime eventDateUtc, int affectedUserId, string affectedDetails, string eventType, string eventDetails);
}
}
}
@@ -1,45 +0,0 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Core.Services
{
/// <summary>
/// A service for handling lawful data processing requirements
/// </summary>
/// <remarks>
/// <para>Consent can be given or revoked or changed via the <see cref="RegisterConsent"/> method, which
/// creates a new <see cref="IConsent"/> entity to track the consent. Revoking a consent is performed by
/// registering a revoked consent.</para>
/// <para>A consent can be revoked, by registering a revoked consent, but cannot be deleted.</para>
/// <para>Getter methods return the current state of a consent, i.e. the latest <see cref="IConsent"/>
/// entity that was created.</para>
/// </remarks>
public interface IConsentService : IService
{
/// <summary>
/// Registers consent.
/// </summary>
/// <param name="source">The source, i.e. whoever is consenting.</param>
/// <param name="context"></param>
/// <param name="action"></param>
/// <param name="state">The state of the consent.</param>
/// <param name="comment">Additional free text.</param>
/// <returns>The corresponding consent entity.</returns>
IConsent RegisterConsent(string source, string context, string action, ConsentState state, string comment = null);
/// <summary>
/// Retrieves consents.
/// </summary>
/// <param name="source">The optional source.</param>
/// <param name="context">The optional context.</param>
/// <param name="action">The optional action.</param>
/// <param name="sourceStartsWith">Determines whether <paramref name="source"/> is a start pattern.</param>
/// <param name="contextStartsWith">Determines whether <paramref name="context"/> is a start pattern.</param>
/// <param name="actionStartsWith">Determines whether <paramref name="action"/> is a start pattern.</param>
/// <param name="includeHistory">Determines whether to include the history of consents.</param>
/// <returns>Consents matching the paramters.</returns>
IEnumerable<IConsent> LookupConsent(string source = null, string context = null, string action = null,
bool sourceStartsWith = false, bool contextStartsWith = false, bool actionStartsWith = false,
bool includeHistory = false);
}
}
+2 -3
View File
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Http;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -199,7 +198,7 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="memberTypeId">Id of the MemberType</param>
void DeleteMembersOfType(int memberTypeId);
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
IEnumerable<IMember> FindMembersByDisplayName(string displayNameToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
@@ -250,4 +249,4 @@ namespace Umbraco.Core.Services
/// <returns><see cref="IEnumerable{IMember}"/></returns>
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact);
}
}
}
+14 -104
View File
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Web.Security;
using System.Xml.Linq;
@@ -15,9 +14,6 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using Umbraco.Core.Security;
namespace Umbraco.Core.Services
@@ -29,11 +25,11 @@ namespace Umbraco.Core.Services
{
private readonly IMemberGroupService _memberGroupService;
private readonly EntityXmlSerializer _entitySerializer = new EntityXmlSerializer();
private readonly IDataTypeService _dataTypeService;
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
//only for unit tests!
internal MembershipProviderBase MembershipProvider { get; set; }
private readonly IDataTypeService _dataTypeService;
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
//only for unit tests!
internal MembershipProviderBase MembershipProvider { get; set; }
public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IMemberGroupService memberGroupService, IDataTypeService dataTypeService)
: base(provider, repositoryFactory, logger, eventMessagesFactory)
@@ -42,7 +38,7 @@ namespace Umbraco.Core.Services
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
_memberGroupService = memberGroupService;
_dataTypeService = dataTypeService;
}
}
#region IMemberService Implementation
@@ -98,7 +94,7 @@ namespace Umbraco.Core.Services
{
if (member == null) throw new ArgumentNullException("member");
var provider = MembershipProvider ?? MembershipProviderExtensions.GetMembersMembershipProvider();
var provider = MembershipProvider ?? MembershipProviderExtensions.GetMembersMembershipProvider();
if (provider.IsUmbracoMembershipProvider())
{
provider.ChangePassword(member.Username, "", password);
@@ -592,7 +588,7 @@ namespace Umbraco.Core.Services
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
using (var uow = UowProvider.GetUnitOfWork(readOnly:true))
{
var repository = RepositoryFactory.CreateMemberRepository(uow);
return repository.GetPagedXmlEntriesByPath("-1", pageIndex, pageSize, null, out totalRecords);
@@ -990,10 +986,10 @@ namespace Umbraco.Core.Services
/// <param name="raiseEvents">Optional parameter to raise events.
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
public void Save(IMember entity, bool raiseEvents = true)
{
{
//trimming username and email to make sure we have no trailing space
entity.Username = entity.Username.Trim();
entity.Email = entity.Email.Trim();
entity.Email = entity.Email.Trim();
using (var uow = UowProvider.GetUnitOfWork())
{
@@ -1070,7 +1066,7 @@ namespace Umbraco.Core.Services
if (raiseEvents)
{
saveEventArgs.CanCancel = false;
saveEventArgs.CanCancel = false;
uow.Events.Dispatch(Saved, this, saveEventArgs);
}
}
@@ -1177,16 +1173,12 @@ namespace Umbraco.Core.Services
public void AssignRoles(string[] usernames, string[] roleNames)
{
int[] memberIds;
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
memberIds = repository.GetMemberIds(usernames);
repository.AssignRoles(memberIds, roleNames);
repository.AssignRoles(usernames, roleNames);
uow.Commit();
}
AssignedRoles?.Invoke(this, new RolesEventArgs(memberIds, roleNames));
}
public void DissociateRole(string username, string roleName)
@@ -1196,16 +1188,12 @@ namespace Umbraco.Core.Services
public void DissociateRoles(string[] usernames, string[] roleNames)
{
int[] memberIds;
using (var uow = UowProvider.GetUnitOfWork())
{
var repository = RepositoryFactory.CreateMemberGroupRepository(uow);
memberIds = repository.GetMemberIds(usernames);
repository.DissociateRoles(memberIds, roleNames);
repository.DissociateRoles(usernames, roleNames);
uow.Commit();
}
RemovedRoles?.Invoke(this, new RolesEventArgs(memberIds, roleNames));
}
public void AssignRole(int memberId, string roleName)
@@ -1221,8 +1209,6 @@ namespace Umbraco.Core.Services
repository.AssignRoles(memberIds, roleNames);
uow.Commit();
}
AssignedRoles?.Invoke(this, new RolesEventArgs(memberIds, roleNames));
}
public void DissociateRole(int memberId, string roleName)
@@ -1238,83 +1224,12 @@ namespace Umbraco.Core.Services
repository.DissociateRoles(memberIds, roleNames);
uow.Commit();
}
RemovedRoles?.Invoke(this, new RolesEventArgs(memberIds, roleNames));
}
#endregion
/// <summary>
/// Used to export a member
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
/// <remarks>
/// This is internal for now and is used to export a member in the member editor, it will raise an event so that auditing
/// logs can be created
/// </remarks>
internal MemberExportModel ExportMember(Guid key)
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
{
var repository = RepositoryFactory.CreateMemberRepository(uow);
var query = Query<IMember>.Builder.Where(x => x.Key == key);
var member = repository.GetByQuery(query).FirstOrDefault();
if (member == null) return null;
var model = new MemberExportModel
{
Id = member.Id,
Key = member.Key,
Name = member.Name,
Username = member.Username,
Email = member.Email,
Groups = GetAllRoles(member.Id).ToList(),
ContentTypeAlias = member.ContentTypeAlias,
CreateDate = member.CreateDate,
UpdateDate = member.UpdateDate,
Properties = new List<MemberExportProperty>(GetPropertyExportItems(member))
};
uow.Events.Dispatch(Exported, this, new ExportedMemberEventArgs(member, model));
return model;
}
}
private static IEnumerable<MemberExportProperty> GetPropertyExportItems(IMember member)
{
if (member == null) throw new ArgumentNullException(nameof(member));
var exportProperties = new List<MemberExportProperty>();
foreach (var property in member.Properties)
{
//ignore list
switch (property.Alias)
{
case Constants.Conventions.Member.PasswordQuestion:
continue;
}
var propertyExportModel = new MemberExportProperty
{
Id = property.Id,
Alias = property.Alias,
Name = property.PropertyType.Name,
Value = property.Value,
CreateDate = property.CreateDate,
UpdateDate = property.UpdateDate
};
exportProperties.Add(propertyExportModel);
}
return exportProperties;
}
private IMemberType FindMemberTypeByAlias(string memberTypeAlias)
{
using (var uow = UowProvider.GetUnitOfWork())
@@ -1374,11 +1289,6 @@ namespace Umbraco.Core.Services
/// </summary>
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saved;
public static event TypedEventHandler<IMemberService, RolesEventArgs> AssignedRoles;
public static event TypedEventHandler<IMemberService, RolesEventArgs> RemovedRoles;
internal static event TypedEventHandler<IMemberService, ExportedMemberEventArgs> Exported;
#endregion
/// <summary>
@@ -1451,4 +1361,4 @@ namespace Umbraco.Core.Services
return member;
}
}
}
}
@@ -832,21 +832,21 @@ namespace Umbraco.Core.Services
foreach (var element in structureElement.Elements("DocumentType"))
{
var alias = element.Value;
if (_importedContentTypes.ContainsKey(alias))
{
var allowedChild = _importedContentTypes[alias];
if (allowedChild == null || allowedChildren.Any(x => x.Id.IsValueCreated && x.Id.Value == allowedChild.Id)) continue;
var allowedChild = _importedContentTypes.ContainsKey(alias) ? _importedContentTypes[alias] : _contentTypeService.GetContentType(alias);
if (allowedChild == null)
allowedChildren.Add(new ContentTypeSort(new Lazy<int>(() => allowedChild.Id), sortOrder, allowedChild.Alias));
sortOrder++;
}
else
{
_logger.Warn<PackagingService>(
string.Format(
"Packager: Error handling DocumentType structure. DocumentType with alias '{0}' could not be found and was not added to the structure for '{1}'.",
alias, contentType.Alias));
continue;
}
if (allowedChildren.Any(x => x.Id.IsValueCreated && x.Id.Value == allowedChild.Id)) continue;
allowedChildren.Add(new ContentTypeSort(new Lazy<int>(() => allowedChild.Id), sortOrder, allowedChild.Alias));
sortOrder++;
}
contentType.AllowedContentTypes = allowedChildren;
+28 -13
View File
@@ -62,13 +62,38 @@ namespace Umbraco.Core.Services
private Lazy<INotificationService> _notificationService;
private Lazy<IExternalLoginService> _externalLoginService;
private Lazy<IRedirectUrlService> _redirectUrlService;
private Lazy<IConsentService> _consentService;
internal IdkMap IdkMap { get; private set; }
/// <summary>
/// public ctor - will generally just be used for unit testing all items are optional and if not specified, the defaults will be used
/// </summary>
/// <param name="contentService"></param>
/// <param name="mediaService"></param>
/// <param name="contentTypeService"></param>
/// <param name="dataTypeService"></param>
/// <param name="fileService"></param>
/// <param name="localizationService"></param>
/// <param name="packagingService"></param>
/// <param name="entityService"></param>
/// <param name="relationService"></param>
/// <param name="memberGroupService"></param>
/// <param name="memberTypeService"></param>
/// <param name="memberService"></param>
/// <param name="userService"></param>
/// <param name="sectionService"></param>
/// <param name="treeService"></param>
/// <param name="tagService"></param>
/// <param name="notificationService"></param>
/// <param name="localizedTextService"></param>
/// <param name="auditService"></param>
/// <param name="domainService"></param>
/// <param name="taskService"></param>
/// <param name="macroService"></param>
/// <param name="publicAccessService"></param>
/// <param name="externalLoginService"></param>
/// <param name="migrationEntryService"></param>
/// <param name="redirectUrlService"></param>
public ServiceContext(
IContentService contentService = null,
IMediaService mediaService = null,
@@ -95,8 +120,7 @@ namespace Umbraco.Core.Services
IPublicAccessService publicAccessService = null,
IExternalLoginService externalLoginService = null,
IMigrationEntryService migrationEntryService = null,
IRedirectUrlService redirectUrlService = null,
IConsentService consentService = null)
IRedirectUrlService redirectUrlService = null)
{
if (migrationEntryService != null) _migrationEntryService = new Lazy<IMigrationEntryService>(() => migrationEntryService);
if (externalLoginService != null) _externalLoginService = new Lazy<IExternalLoginService>(() => externalLoginService);
@@ -124,7 +148,6 @@ namespace Umbraco.Core.Services
if (macroService != null) _macroService = new Lazy<IMacroService>(() => macroService);
if (publicAccessService != null) _publicAccessService = new Lazy<IPublicAccessService>(() => publicAccessService);
if (redirectUrlService != null) _redirectUrlService = new Lazy<IRedirectUrlService>(() => redirectUrlService);
if (consentService != null) _consentService = new Lazy<IConsentService>(() => consentService);
}
/// <summary>
@@ -287,9 +310,6 @@ namespace Umbraco.Core.Services
if (_redirectUrlService == null)
_redirectUrlService = new Lazy<IRedirectUrlService>(() => new RedirectUrlService(provider, repositoryFactory, logger, eventMessagesFactory));
if (_consentService == null)
_consentService = new Lazy<IConsentService>(() => new ConsentService(provider, repositoryFactory, logger, eventMessagesFactory));
}
internal IEventMessagesFactory EventMessagesFactory { get; private set; }
@@ -506,10 +526,5 @@ namespace Umbraco.Core.Services
{
get { return _redirectUrlService.Value; }
}
/// <summary>
/// Gets the <see cref="IConsentService"/> implementation.
/// </summary>
public IConsentService ConsentService => _consentService.Value;
}
}
}
+19 -46
View File
@@ -838,9 +838,13 @@ namespace Umbraco.Core.Services
repository.ReplaceGroupPermissions(groupId, permissions, entityIds);
uow.Commit();
var assigned = permissions.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray();
uow.Events.Dispatch(UserGroupPermissionsAssigned, this,
new SaveEventArgs<EntityPermission>(entityIds.Select(x => new EntityPermission(groupId, x, assigned)).ToArray(), false));
uow.Events.Dispatch(UserGroupPermissionsAssigned, this, new SaveEventArgs<EntityPermission>(
entityIds.Select(
x => new EntityPermission(
groupId,
x,
permissions.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray()))
.ToArray(), false));
}
}
@@ -861,9 +865,13 @@ namespace Umbraco.Core.Services
repository.AssignGroupPermission(groupId, permission, entityIds);
uow.Commit();
var assigned = new[] { permission.ToString(CultureInfo.InvariantCulture) };
uow.Events.Dispatch(UserGroupPermissionsAssigned, this,
new SaveEventArgs<EntityPermission>(entityIds.Select(x => new EntityPermission(groupId, x, assigned)).ToArray(), false));
uow.Events.Dispatch(UserGroupPermissionsAssigned, this, new SaveEventArgs<EntityPermission>(
entityIds.Select(
x => new EntityPermission(
groupId,
x,
new[] { permission.ToString(CultureInfo.InvariantCulture) }))
.ToArray(), false));
}
}
@@ -933,7 +941,7 @@ namespace Umbraco.Core.Services
/// </summary>
/// <param name="userGroup">UserGroup to save</param>
/// <param name="userIds">
/// If null than no changes are made to the users who are assigned to this group, however if a value is passed in
/// If null than no changes are made to the users who are assigned to this group, however if a value is passed in
/// than all users will be removed from this group and only these users will be added
/// </param>
/// <param name="raiseEvents">Optional parameter to raise events.
@@ -942,28 +950,8 @@ namespace Umbraco.Core.Services
{
using (var uow = UowProvider.GetUnitOfWork())
{
// we need to figure out which users have been added / removed, for audit purposes
var empty = new IUser[0];
var addedUsers = empty;
var removedUsers = empty;
if (userIds != null)
{
var urepository = RepositoryFactory.CreateUserRepository(uow);
var groupUsers = userGroup.HasIdentity ? urepository.GetAllInGroup(userGroup.Id).ToArray() : empty;
var xGroupUsers = groupUsers.ToDictionary(x => x.Id, x => x);
var groupIds = groupUsers.Select(x => x.Id).ToArray();
addedUsers = urepository.GetAll(userIds.Except(groupIds).ToArray()).Where(x => x.Id != 0).ToArray();
removedUsers = groupIds.Except(userIds).Select(x => xGroupUsers[x]).Where(x => x.Id != 0).ToArray();
}
//raise 2x events - the old and new one for backwards compat reasons
var saveEventArgs = new SaveEventArgs<IUserGroup>(userGroup);
var saveEventArgs2 = new SaveEventArgs<UserGroupWithUsers>(new UserGroupWithUsers(userGroup, addedUsers, removedUsers));
if (raiseEvents &&
(uow.Events.DispatchCancelable(SavingUserGroup, this, saveEventArgs) || uow.Events.DispatchCancelable(SavingUserGroup2, this, saveEventArgs2)))
if (raiseEvents && uow.Events.DispatchCancelable(SavingUserGroup, this, saveEventArgs))
{
uow.Commit();
return;
@@ -977,10 +965,7 @@ namespace Umbraco.Core.Services
if (raiseEvents)
{
saveEventArgs.CanCancel = false;
//raise 2x events - the old and new one for backwards compat reasons
uow.Events.Dispatch(SavedUserGroup, this, saveEventArgs);
uow.Events.Dispatch(SavedUserGroup2, this, saveEventArgs2);
}
}
}
@@ -1176,8 +1161,8 @@ namespace Umbraco.Core.Services
if (byGroup.Value.TryGetValue(pathId, out permissionsForNodeAndGroup) == false)
continue;
//In theory there will only be one EntityPermission in this group
// but there's nothing stopping the logic of this method
//In theory there will only be one EntityPermission in this group
// but there's nothing stopping the logic of this method
// from having more so we deal with it here
foreach (var entityPermission in permissionsForNodeAndGroup)
{
@@ -1213,7 +1198,7 @@ namespace Umbraco.Core.Services
/// Returns the resulting permission set for a group for the path based on all permissions provided for the branch
/// </summary>
/// <param name="pathPermissions">
/// The collective set of permissions provided to calculate the resulting permissions set for the path
/// The collective set of permissions provided to calculate the resulting permissions set for the path
/// based on a single group
/// </param>
/// <param name="pathIds">Must be ordered deepest to shallowest (right to left)</param>
@@ -1311,25 +1296,13 @@ namespace Umbraco.Core.Services
/// <summary>
/// Occurs before Save
/// </summary>
//TODO: In v8, change this event to be SaveEventArgs<UserGroupWithUsers> and remove SavingUserGroup2
public static event TypedEventHandler<IUserService, SaveEventArgs<IUserGroup>> SavingUserGroup;
/// <summary>
/// Occurs after Save
/// </summary>
//TODO: In v8, change this event to be SaveEventArgs<UserGroupWithUsers> and remove SavedUserGroup2
public static event TypedEventHandler<IUserService, SaveEventArgs<IUserGroup>> SavedUserGroup;
/// <summary>
/// Occurs after Save
/// </summary>
internal static event TypedEventHandler<IUserService, SaveEventArgs<UserGroupWithUsers>> SavingUserGroup2;
/// <summary>
/// Occurs after Save
/// </summary>
internal static event TypedEventHandler<IUserService, SaveEventArgs<UserGroupWithUsers>> SavedUserGroup2;
/// <summary>
/// Occurs before Delete
/// </summary>
+1 -31
View File
@@ -15,7 +15,6 @@
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<TargetFrameworkProfile />
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -26,7 +25,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -139,7 +137,6 @@
<Compile Include="AsyncLock.cs" />
<Compile Include="Attempt{T}.cs" />
<Compile Include="Auditing\Audit.cs" />
<Compile Include="Auditing\AuditEventHandler.cs" />
<Compile Include="Auditing\AuditTypes.cs" />
<Compile Include="Auditing\IdentityAuditEventArgs.cs" />
<Compile Include="BindingRedirects.cs" />
@@ -355,9 +352,7 @@
<Compile Include="DisposableObjectSlim.cs" />
<Compile Include="EmailSender.cs" />
<Compile Include="Events\EventDefinitionFilter.cs" />
<Compile Include="Events\ExportedMemberEventArgs.cs" />
<Compile Include="Events\IDeletingMediaFilesEventArgs.cs" />
<Compile Include="Events\UserGroupWithUsers.cs" />
<Compile Include="Events\ScopeEventDispatcherBase.cs" />
<Compile Include="Events\ScopeLifespanMessagesFactory.cs" />
<Compile Include="Events\SendEmailEventArgs.cs" />
@@ -368,30 +363,20 @@
<Compile Include="IEmailSender.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
<Compile Include="Models\AuditEntry.cs" />
<Compile Include="Models\Consent.cs" />
<Compile Include="Models\ConsentExtensions.cs" />
<Compile Include="Models\ConsentState.cs" />
<Compile Include="Models\EntityBase\EntityPath.cs" />
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
<Compile Include="Models\IAuditEntry.cs" />
<Compile Include="Models\IAuditItem.cs" />
<Compile Include="Models\IConsent.cs" />
<Compile Include="Models\IUserControl.cs" />
<Compile Include="Models\Membership\ContentPermissionSet.cs" />
<Compile Include="Models\Membership\EntityPermissionCollection.cs" />
<Compile Include="Models\Membership\IReadOnlyUserGroup.cs" />
<Compile Include="Models\Membership\IUserType.cs" />
<Compile Include="Models\Membership\MemberExportModel.cs" />
<Compile Include="Models\Membership\MemberExportProperty.cs" />
<Compile Include="Models\Membership\ReadOnlyUserGroup.cs" />
<Compile Include="Models\Membership\UserGroupExtensions.cs" />
<Compile Include="Models\Membership\UserProfile.cs" />
<Compile Include="Models\Membership\UserState.cs" />
<Compile Include="Models\Membership\UserType.cs" />
<Compile Include="Models\PublishedContent\PublishedContentTypeConverter.cs" />
<Compile Include="Models\Rdbms\AuditEntryDto.cs" />
<Compile Include="Models\Rdbms\ConsentDto.cs" />
<Compile Include="Models\Rdbms\MediaDto.cs" />
<Compile Include="Models\Rdbms\UserLoginDto.cs" />
<Compile Include="Models\Rdbms\UserStartNodeDto.cs" />
@@ -545,7 +530,6 @@
<Compile Include="Persistence\Constants-Locks.cs" />
<Compile Include="Persistence\DatabaseNodeLockExtensions.cs" />
<Compile Include="Persistence\DatabaseDebugHelper.cs" />
<Compile Include="Persistence\Factories\AuditEntryFactory.cs" />
<Compile Include="Persistence\Factories\ExternalLoginFactory.cs" />
<Compile Include="Persistence\Factories\MigrationEntryFactory.cs" />
<Compile Include="Persistence\Factories\PublicAccessEntryFactory.cs" />
@@ -556,9 +540,7 @@
<Compile Include="Persistence\LockedRepository.cs" />
<Compile Include="Persistence\LockingRepository.cs" />
<Compile Include="Persistence\Mappers\AccessMapper.cs" />
<Compile Include="Persistence\Mappers\AuditEntryMapper.cs" />
<Compile Include="Persistence\Mappers\AuditMapper.cs" />
<Compile Include="Persistence\Mappers\ConsentMapper.cs" />
<Compile Include="Persistence\Mappers\DomainMapper.cs" />
<Compile Include="Persistence\Mappers\ExternalLoginMapper.cs" />
<Compile Include="Persistence\Mappers\MigrationEntryMapper.cs" />
@@ -570,10 +552,6 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddInstructionCountColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddCmsMediaTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddUserLoginTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddUmbracoAuditTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddUmbracoConsentTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddIsSensitiveMemberTypeColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\CreateSensitiveDataUserGroup.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSevenZero\AddIndexToDictionaryKeyColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSevenZero\EnsureContentTemplatePermissions.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSevenZero\ReduceDictionaryKeyColumnsSize.cs" />
@@ -644,17 +622,12 @@
<Compile Include="Persistence\Relators\AccessRulesRelator.cs" />
<Compile Include="Persistence\Relators\UserGroupRelator.cs" />
<Compile Include="Persistence\Relators\UserGroupSectionRelator.cs" />
<Compile Include="Persistence\Repositories\AuditEntryRepository.cs" />
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
<Compile Include="Persistence\Repositories\BaseQueryType.cs" />
<Compile Include="Persistence\Factories\ConsentFactory.cs" />
<Compile Include="Persistence\Repositories\ConsentRepository.cs" />
<Compile Include="Persistence\Repositories\ContentBlueprintRepository.cs" />
<Compile Include="Persistence\Repositories\EntityContainerRepository.cs" />
<Compile Include="Persistence\Repositories\DomainRepository.cs" />
<Compile Include="Persistence\Repositories\ExternalLoginRepository.cs" />
<Compile Include="Persistence\Repositories\IAuditEntryRepository.cs" />
<Compile Include="Persistence\Repositories\IConsentRepository.cs" />
<Compile Include="Persistence\Repositories\Interfaces\IAuditRepository.cs" />
<Compile Include="Persistence\Repositories\Interfaces\IContentTypeCompositionRepository.cs" />
<Compile Include="Persistence\Repositories\Interfaces\IDomainRepository.cs" />
@@ -751,10 +724,8 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\CreateCacheInstructionTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\MigrateStylesheetDataToFile.cs" />
<Compile Include="Services\AuditService.cs" />
<Compile Include="Services\ConsentService.cs" />
<Compile Include="Services\ContentTypeServiceExtensions.cs" />
<Compile Include="Models\RedirectUrl.cs" />
<Compile Include="Services\IConsentService.cs" />
<Compile Include="Services\IContentServiceBase.cs" />
<Compile Include="Services\IdkMap.cs" />
<Compile Include="Services\MediaServiceExtensions.cs" />
@@ -778,7 +749,6 @@
<Compile Include="Services\RepositoryService.cs" />
<Compile Include="Services\OperationStatus.cs" />
<Compile Include="Services\OperationStatusType.cs" />
<Compile Include="Events\RolesEventArgs.cs" />
<Compile Include="Services\ScopeRepositoryService.cs" />
<Compile Include="Services\TaskService.cs" />
<Compile Include="Strings\Css\StylesheetHelper.cs" />
@@ -1673,7 +1643,7 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets" Condition="Exists('..\packages\AutoMapper.3.3.1\tools\AutoMapper.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp50</s:String></wpf:ResourceDictionary>
@@ -120,7 +120,6 @@ namespace Umbraco.Tests.Models.Mapping
Assert.AreEqual(propTypes.ElementAt(j).DataTypeId, result.PropertyTypes.ElementAt(j).DataTypeDefinitionId);
Assert.AreEqual(propTypes.ElementAt(j).MemberCanViewProperty, result.MemberCanViewProperty(result.PropertyTypes.ElementAt(j).Alias));
Assert.AreEqual(propTypes.ElementAt(j).MemberCanEditProperty, result.MemberCanEditProperty(result.PropertyTypes.ElementAt(j).Alias));
Assert.AreEqual(propTypes.ElementAt(j).IsSensitiveData, result.IsSensitiveProperty(result.PropertyTypes.ElementAt(j).Alias));
}
}
@@ -336,7 +335,7 @@ namespace Umbraco.Tests.Models.Mapping
.Returns(new[] { new TextboxPropertyEditor() });
var memberType = MockedContentTypes.CreateSimpleMemberType();
memberType.MemberTypePropertyTypes[memberType.PropertyTypes.Last().Alias] = new MemberTypePropertyProfileAccess(true, true, true);
memberType.MemberTypePropertyTypes[memberType.PropertyTypes.Last().Alias] = new MemberTypePropertyProfileAccess(true, true);
MockedContentTypes.EnsureAllIds(memberType, 8888);
@@ -540,7 +539,6 @@ namespace Umbraco.Tests.Models.Mapping
{
MemberCanEditProperty = true,
MemberCanViewProperty = true,
IsSensitiveData = true,
Id = 33,
SortOrder = 1,
Alias = "prop1",
@@ -558,7 +556,6 @@ namespace Umbraco.Tests.Models.Mapping
{
MemberCanViewProperty = false,
MemberCanEditProperty = false,
IsSensitiveData = false,
Id = 34,
SortOrder = 2,
Alias = "prop2",
@@ -947,7 +944,6 @@ namespace Umbraco.Tests.Models.Mapping
Label = "Prop 1",
MemberCanViewProperty = true,
MemberCanEditProperty = true,
IsSensitiveData = true,
Validation = new PropertyTypeValidation()
{
Mandatory = true,
@@ -967,7 +963,6 @@ namespace Umbraco.Tests.Models.Mapping
Assert.AreEqual(basic.Validation, result.Validation);
Assert.AreEqual(basic.MemberCanViewProperty, result.MemberCanViewProperty);
Assert.AreEqual(basic.MemberCanEditProperty, result.MemberCanEditProperty);
Assert.AreEqual(basic.IsSensitiveData, result.IsSensitiveData);
}
[Test]
@@ -1034,7 +1029,6 @@ namespace Umbraco.Tests.Models.Mapping
{
MemberCanEditProperty = true,
MemberCanViewProperty = true,
IsSensitiveData = true,
Alias = "property1",
Description = "this is property 1",
Inherited = false,
+2 -2
View File
@@ -277,7 +277,7 @@ namespace Umbraco.Tests
[Test]
public void ConvertToDateTimeTest()
{
var conv = "2016-06-07".TryConvertTo<DateTime>();
var conv = "2016-06-07".TryConvertTo<DateTime?>();
Assert.IsTrue(conv);
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
}
@@ -285,7 +285,7 @@ namespace Umbraco.Tests
[Test]
public void ConvertToNullableDateTimeTest()
{
var conv = "2016-06-07".TryConvertTo<DateTime?>();
var conv = "2016-06-07".TryConvertTo<DateTime>();
Assert.IsTrue(conv);
Assert.AreEqual(new DateTime(2016, 6, 7), conv.Result);
}
@@ -271,7 +271,7 @@ AnotherContentFinder
public void Resolves_Assigned_Mappers()
{
var foundTypes1 = _manager.ResolveAssignedMapperTypes();
Assert.AreEqual(31, foundTypes1.Count());
Assert.AreEqual(29, foundTypes1.Count());
}
[Test]
@@ -390,4 +390,4 @@ AnotherContentFinder
}
}
}
}
+3 -3
View File
@@ -79,8 +79,8 @@ namespace Umbraco.Tests.Plugins
var originalTypesFound = TypeFinderOriginal.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
Assert.AreEqual(10, typesFound.Count());
Assert.AreEqual(10, originalTypesFound.Count());
Assert.AreEqual(9, typesFound.Count());
Assert.AreEqual(9, originalTypesFound.Count());
}
[Test]
@@ -632,4 +632,4 @@ namespace Umbraco.Tests.Plugins
}
}
}
@@ -21,7 +21,7 @@ namespace Umbraco.Tests.PropertyEditors
[TestFixture]
public class ImageCropperTest
{
private const string cropperJson1 = "{\"focalPoint\": {\"left\": 0.96,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}";
private const string cropperJson1 = "{\"focalPoint\": {\"left\": 0.96,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0671.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}";
private const string cropperJson2 = "{\"focalPoint\": {\"left\": 0.98,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0672.jpg\",\"crops\": [{\"alias\":\"thumb\",\"width\": 100,\"height\": 100,\"coordinates\": {\"x1\": 0.58729977382575338,\"y1\": 0.055768992440203169,\"x2\": 0,\"y2\": 0.32457553600198386}}]}";
private const string cropperJson3 = "{\"focalPoint\": {\"left\": 0.98,\"top\": 0.80827067669172936},\"src\": \"/media/1005/img_0672.jpg\",\"crops\": []}";
private const string mediaPath = "/media/1005/img_0671.jpg";
@@ -56,7 +56,7 @@ namespace Umbraco.Tests.PropertyEditors
index++;
}
Assert.AreEqual(index, 1);
Assert.AreEqual(index, 1);
}
[Test]
@@ -136,7 +136,7 @@ namespace Umbraco.Tests.PropertyEditors
}
[TestCase(cropperJson1, cropperJson1, true)]
[TestCase(cropperJson1, cropperJson2, false)]
[TestCase(cropperJson1, cropperJson2, false)]
public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool expected)
{
try
@@ -266,7 +266,7 @@ namespace Umbraco.Tests.PropertyEditors
var urlStringPad = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Pad);
var urlStringMax = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Max);
var urlStringStretch = mediaPath.GetCropUrl(imageCropperValue: cropperJson1, width: 300, height: 150, imageCropMode: ImageCropMode.Stretch);
Assert.AreEqual(mediaPath + "?mode=min&width=300&height=150", urlStringMin);
Assert.AreEqual(mediaPath + "?mode=boxpad&width=300&height=150", urlStringBoxPad);
Assert.AreEqual(mediaPath + "?mode=pad&width=300&height=150", urlStringPad);
@@ -380,4 +380,4 @@ namespace Umbraco.Tests.PropertyEditors
Assert.AreEqual(mediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString);
}
}
}
}
@@ -1,56 +0,0 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Services
{
[TestFixture]
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerFixture)]
public class AuditServiceTests : BaseServiceTest
{
[Test]
public void CanCrudAuditEntry()
{
// fixme - why isn't this set by the test base class?
Database.Mapper = new PetaPocoMapper();
var yesterday = DateTime.UtcNow.AddDays(-1);
var entry = ServiceContext.AuditService.Write(123, "user 123, bob@example.com", null, yesterday, 456, "user 456, alice@example.com", "umbraco/user", "change property whatever value");
Assert.AreEqual(123, entry.PerformingUserId);
Assert.AreEqual("user 123, bob@example.com", entry.PerformingDetails);
Assert.AreEqual(yesterday, entry.EventDateUtc);
Assert.AreEqual(456, entry.AffectedUserId);
Assert.AreEqual("user 456, alice@example.com", entry.AffectedDetails);
Assert.AreEqual("umbraco/user", entry.EventType);
Assert.AreEqual("change property whatever value", entry.EventDetails);
var entries = ((AuditService)ServiceContext.AuditService).GetAll().ToArray();
Assert.IsNotNull(entries);
Assert.AreEqual(1, entries.Length);
Assert.AreEqual(123, entries[0].PerformingUserId);
for (var i = 0; i < 10; i++)
{
yesterday = yesterday.AddMinutes(1);
entry = ServiceContext.AuditService.Write(123 + i, "user 123, bob@example.com", null, yesterday, 456 + i, "user 456, alice@example.com", "umbraco/user", "change property whatever value");
}
//
// page 0 contains 123+9, 123+8
// page 1 contains 123+7, 123+6
// page 2 contains 123+5, 123+4
// ...
entries = ((AuditService)ServiceContext.AuditService).GetPage(2, 2, out var count).ToArray();
Assert.AreEqual(2, entries.Length);
Assert.AreEqual(123 + 5, entries[0].PerformingUserId);
Assert.AreEqual(123 + 4, entries[1].PerformingUserId);
}
}
}
@@ -1,125 +0,0 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Services
{
[TestFixture]
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerFixture)]
public class ConsentServiceTests : BaseServiceTest
{
[SetUp]
public override void Initialize()
{
base.Initialize();
}
[TearDown]
public override void TearDown()
{
base.TearDown();
}
[Test]
public void CanCrudConsent()
{
// fixme - why isn't this set by the test base class?
Database.Mapper = new PetaPocoMapper();
var consentService = ServiceContext.ConsentService;
// can register
var consent = consentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Granted, "no comment");
Assert.AreNotEqual(0, consent.Id);
Assert.IsTrue(consent.Current);
Assert.AreEqual("user/1234", consent.Source);
Assert.AreEqual("app1", consent.Context);
Assert.AreEqual("do-something", consent.Action);
Assert.AreEqual(ConsentState.Granted, consent.State);
Assert.AreEqual("no comment", consent.Comment);
Assert.IsTrue(consent.IsGranted());
// can register more
consentService.RegisterConsent("user/1234", "app1", "do-something-else", ConsentState.Granted, "no comment");
consentService.RegisterConsent("user/1236", "app1", "do-something", ConsentState.Granted, "no comment");
consentService.RegisterConsent("user/1237", "app2", "do-something", ConsentState.Granted, "no comment");
// can get by source
var consents = consentService.LookupConsent(source: "user/1235").ToArray();
Assert.IsEmpty(consents);
consents = consentService.LookupConsent(source: "user/1234").ToArray();
Assert.AreEqual(2, consents.Length);
Assert.IsTrue(consents.All(x => x.Source == "user/1234"));
Assert.IsTrue(consents.Any(x => x.Action == "do-something"));
Assert.IsTrue(consents.Any(x => x.Action == "do-something-else"));
// can get by context
consents = consentService.LookupConsent(context: "app3").ToArray();
Assert.IsEmpty(consents);
consents = consentService.LookupConsent(context: "app2").ToArray();
Assert.AreEqual(1, consents.Length);
consents = consentService.LookupConsent(context: "app1").ToArray();
Assert.AreEqual(3, consents.Length);
Assert.IsTrue(consents.Any(x => x.Action == "do-something"));
Assert.IsTrue(consents.Any(x => x.Action == "do-something-else"));
// can get by action
consents = consentService.LookupConsent(action: "do-whatever").ToArray();
Assert.IsEmpty(consents);
consents = consentService.LookupConsent(context: "app1", action: "do-something").ToArray();
Assert.AreEqual(2, consents.Length);
Assert.IsTrue(consents.All(x => x.Action == "do-something"));
Assert.IsTrue(consents.Any(x => x.Source == "user/1234"));
Assert.IsTrue(consents.Any(x => x.Source == "user/1236"));
// can revoke
consent = consentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Revoked, "no comment");
consents = consentService.LookupConsent(source: "user/1234", context: "app1", action: "do-something").ToArray();
Assert.AreEqual(1, consents.Length);
Assert.IsTrue(consents[0].Current);
Assert.AreEqual(ConsentState.Revoked, consents[0].State);
// can filter
consents = consentService.LookupConsent(context: "app1", action: "do-", actionStartsWith: true).ToArray();
Assert.AreEqual(3, consents.Length);
Assert.IsTrue(consents.All(x => x.Context == "app1"));
Assert.IsTrue(consents.All(x => x.Action.StartsWith("do-")));
// can get history
consents = consentService.LookupConsent(source: "user/1234", context: "app1", action: "do-something", includeHistory: true).ToArray();
Assert.AreEqual(1, consents.Length);
Assert.IsTrue(consents[0].Current);
Assert.AreEqual(ConsentState.Revoked, consents[0].State);
Assert.IsTrue(consents[0].IsRevoked());
Assert.IsNotNull(consents[0].History);
var history = consents[0].History.ToArray();
Assert.AreEqual(1, history.Length);
Assert.IsFalse(history[0].Current);
Assert.AreEqual(ConsentState.Granted, history[0].State);
// cannot be stupid
Assert.Throws<ArgumentException>(() =>
consentService.RegisterConsent("user/1234", "app1", "do-something", ConsentState.Granted | ConsentState.Revoked, "no comment"));
}
}
}
@@ -108,9 +108,8 @@ namespace Umbraco.Tests.TestHelpers
var mappers = PluginManager.Current.FindAndCreateInstances<IMapperConfiguration>(
specificAssemblies: new[]
{
typeof(ApplicationContext).Assembly, //Umbraco.Core
typeof(ContentModelMapper).Assembly, //Umbraco.Web
typeof(ApplicationRegistrar).Assembly //umbraco.businesslogic
typeof(ContentModelMapper).Assembly,
typeof(ApplicationRegistrar).Assembly
});
foreach (var mapper in mappers)
{
@@ -219,4 +218,4 @@ namespace Umbraco.Tests.TestHelpers
protected CacheHelper CacheHelper { get; private set; }
}
}
}
@@ -47,10 +47,6 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var mockedContentService = Mock.Of<IContentService>();
var mockedMediaService = Mock.Of<IMediaService>();
var mockedEntityService = Mock.Of<IEntityService>();
var mockedMemberService = Mock.Of<IMemberService>();
var mockedMemberTypeService = Mock.Of<IMemberTypeService>();
var mockedDataTypeService = Mock.Of<IDataTypeService>();
var mockedContentTypeService = Mock.Of<IContentTypeService>();
var mockedMigrationService = new Mock<IMigrationEntryService>();
//set it up to return anything so that the app ctx is 'Configured'
@@ -61,10 +57,6 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
contentService: mockedContentService,
mediaService: mockedMediaService,
entityService: mockedEntityService,
memberService: mockedMemberService,
memberTypeService: mockedMemberTypeService,
dataTypeService: mockedDataTypeService,
contentTypeService: mockedContentTypeService,
migrationEntryService: mockedMigrationService.Object,
localizedTextService:Mock.Of<ILocalizedTextService>(),
sectionService:Mock.Of<ISectionService>());
@@ -164,4 +156,4 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
protected abstract ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoHelper helper);
}
}
}
+1 -3
View File
@@ -31,7 +31,6 @@
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
<NugetPackages Condition="$(NugetPackages) == '' Or $(NugetPackages) == '*Undefined*'">$(SolutionDir)\packages</NugetPackages>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -42,6 +41,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>5</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -190,8 +190,6 @@
<Compile Include="Models\Mapping\UserModelMapperTests.cs" />
<Compile Include="Packaging\PackageExtractionTests.cs" />
<Compile Include="Persistence\Repositories\SimilarNodeNameTests.cs" />
<Compile Include="Services\AuditServiceTests.cs" />
<Compile Include="Services\ConsentServiceTests.cs" />
<Compile Include="TestHelpers\ControllerTesting\AuthenticateEverythingExtensions.cs" />
<Compile Include="TestHelpers\ControllerTesting\AuthenticateEverythingMiddleware.cs" />
<Compile Include="TestHelpers\ControllerTesting\SpecificAssemblyResolver.cs" />
+1 -10
View File
@@ -22,21 +22,12 @@ var packages = angular.module("umbraco.packages", []);
//module is initilized.
angular.module("umbraco.views", ["umbraco.viewcache"]);
angular.module("umbraco.viewcache", [])
.run(function ($rootScope, $templateCache, localStorageService) {
.run(function($rootScope, $templateCache) {
/** For debug mode, always clear template cache to cut down on
dev frustration and chrome cache on templates */
if (Umbraco.Sys.ServerVariables.isDebuggingEnabled) {
$templateCache.removeAll();
}
else {
var storedVersion = localStorageService.get("umbVersion");
if (!storedVersion || storedVersion !== Umbraco.Sys.ServerVariables.application.cacheBuster) {
//if the stored version doesn't match our cache bust version, clear the template cache
$templateCache.removeAll();
//store the current version
localStorageService.set("umbVersion", Umbraco.Sys.ServerVariables.application.cacheBuster);
}
}
})
.config([
//This ensures that all of our angular views are cache busted, if the path starts with views/ and ends with .html, then
@@ -115,9 +115,7 @@ angular.module("umbraco.directives")
toolbar: toolbar,
content_css: stylesheets,
style_formats: styleFormats,
autoresize_bottom_margin: 0,
//see http://archive.tinymce.com/wiki.php/Configuration:cache_suffix
cache_suffix: "?umb__rnd=" + Umbraco.Sys.ServerVariables.application.cacheBuster
autoresize_bottom_margin: 0
};
@@ -4,32 +4,29 @@
* @restrict E
**/
angular.module("umbraco.directives")
.directive('umbProperty', function (umbPropEditorHelper, userService) {
.directive('umbProperty', function (umbPropEditorHelper) {
return {
scope: {
property: "="
},
transclude: true,
restrict: 'E',
replace: true,
replace: true,
templateUrl: 'views/components/property/umb-property.html',
link: function (scope) {
userService.getCurrentUser().then(function (u) {
var isAdmin = u.userGroups.indexOf('admin') !== -1;
scope.propertyAlias = (Umbraco.Sys.ServerVariables.isDebuggingEnabled === true || isAdmin) ? scope.property.alias : null;
});
link: function(scope) {
scope.propertyAlias = Umbraco.Sys.ServerVariables.isDebuggingEnabled === true ? scope.property.alias : null;
},
//Define a controller for this directive to expose APIs to other directives
controller: function ($scope, $timeout) {
var self = this;
//set the API properties/methods
self.property = $scope.property;
self.setPropertyError = function (errorMsg) {
self.setPropertyError = function(errorMsg) {
$scope.property.propertyErrorMessage = errorMsg;
};
}
};
});
});
@@ -489,7 +489,7 @@
scope.editPropertyTypeSettings = function(property, group) {
if (!property.inherited) {
if (!property.inherited && !property.locked) {
scope.propertySettingsDialogModel = {};
scope.propertySettingsDialogModel.title = "Property settings";
@@ -547,7 +547,6 @@
property.validation.pattern = oldModel.property.validation.pattern;
property.showOnMemberProfile = oldModel.property.showOnMemberProfile;
property.memberCanEdit = oldModel.property.memberCanEdit;
property.isSensitiveValue = oldModel.property.isSensitiveValue;
// because we set state to active, to show a preview, we have to check if has been filled out
// label is required so if it is not filled we know it is a placeholder
@@ -493,7 +493,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @methodOf umbraco.resources.mediaResource
*
* @description
* Paginated search for media items starting on the supplied nodeId
* Empties the media recycle bin
*
* ##usage
* <pre>
@@ -506,7 +506,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @param {string} query The search query
* @param {int} pageNumber The page number
* @param {int} pageSize The number of media items on a page
* @param {int} searchFrom NodeId to search from (-1 for root)
* @param {int} searchFrom Id to search from
* @returns {Promise} resourcePromise object.
*
*/
@@ -10,8 +10,8 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
return umbRequestHelper.postSaveContent({
restApiUrl: umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"PostSave"),
"memberApiBaseUrl",
"PostSave"),
content: content,
action: action,
files: files,
@@ -22,7 +22,8 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
}
return {
getPagedResults: function(memberTypeAlias, options) {
getPagedResults: function (memberTypeAlias, options) {
if (memberTypeAlias === 'all-members') {
memberTypeAlias = null;
@@ -66,35 +67,35 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
}
var params = [
{ pageNumber: options.pageNumber },
{ pageSize: options.pageSize },
{ orderBy: options.orderBy },
{ orderDirection: options.orderDirection },
{ orderBySystemField: toBool(options.orderBySystemField) },
{ filter: options.filter }
{ pageNumber: options.pageNumber },
{ pageSize: options.pageSize },
{ orderBy: options.orderBy },
{ orderDirection: options.orderDirection },
{ orderBySystemField: toBool(options.orderBySystemField) },
{ filter: options.filter }
];
if (memberTypeAlias != null) {
params.push({ memberTypeAlias: memberTypeAlias });
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetPagedResults",
params)),
'Failed to retrieve member paged result');
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetPagedResults",
params)),
'Failed to retrieve member paged result');
},
getListNode: function(listName) {
getListNode: function (listName) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetListNodeDisplay",
[{ listName: listName }])),
'Failed to retrieve data for member list ' + listName);
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetListNodeDisplay",
[{ listName: listName }])),
'Failed to retrieve data for member list ' + listName);
},
/**
@@ -118,15 +119,15 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the member item.
*
*/
getByKey: function(key) {
getByKey: function (key) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetByKey",
[{ key: key }])),
'Failed to retrieve data for member id ' + key);
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetByKey",
[{ key: key }])),
'Failed to retrieve data for member id ' + key);
},
/**
@@ -149,14 +150,14 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @returns {Promise} resourcePromise object.
*
*/
deleteByKey: function(key) {
deleteByKey: function (key) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"DeleteByKey",
[{ key: key }])),
'Failed to delete item ' + key);
$http.post(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"DeleteByKey",
[{ key: key }])),
'Failed to delete item ' + key);
},
/**
@@ -189,24 +190,24 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the member scaffold.
*
*/
getScaffold: function(alias) {
getScaffold: function (alias) {
if (alias) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetEmpty",
[{ contentTypeAlias: alias }])),
'Failed to retrieve data for empty member item type ' + alias);
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetEmpty",
[{ contentTypeAlias: alias }])),
'Failed to retrieve data for empty member item type ' + alias);
}
else {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetEmpty")),
'Failed to retrieve data for empty member item type ' + alias);
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetEmpty")),
'Failed to retrieve data for empty member item type ' + alias);
}
},
@@ -239,7 +240,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the saved media item.
*
*/
save: function(member, isNew, files) {
save: function (member, isNew, files) {
return saveMember(member, "save" + (isNew ? "New" : ""), files);
}
};
@@ -8,27 +8,9 @@
* @description
* Defines the methods that are called when menu items declare only an action to execute
*/
function umbracoMenuActions($q, treeService, $location, navigationService, appState, umbRequestHelper, notificationsService, localizationService) {
function umbracoMenuActions($q, treeService, $location, navigationService, appState) {
return {
"ExportMember": function(args) {
var url = umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"ExportMemberData",
[{ key: args.entity.id }]);
umbRequestHelper.downloadFile(url).then(function() {
localizationService.localize("speechBubbles_memberExportedSuccess").then(function (value) {
notificationsService.success(value);
})
}, function(data) {
localizationService.localize("speechBubbles_memberExportedError").then(function (value) {
notificationsService.error(value);
})
});
},
/**
* @ngdoc method
@@ -92,4 +74,4 @@ function umbracoMenuActions($q, treeService, $location, navigationService, appSt
};
}
angular.module('umbraco.services').factory('umbracoMenuActions', umbracoMenuActions);
angular.module('umbraco.services').factory('umbracoMenuActions', umbracoMenuActions);
@@ -56,7 +56,7 @@
});
var saveProperties = _.map(realProperties, function (p) {
var saveProperty = _.pick(p, 'id', 'alias', 'description', 'validation', 'label', 'sortOrder', 'dataTypeId', 'groupId', 'memberCanEdit', 'showOnMemberProfile', 'isSensitiveData');
var saveProperty = _.pick(p, 'id', 'alias', 'description', 'validation', 'label', 'sortOrder', 'dataTypeId', 'groupId', 'memberCanEdit', 'showOnMemberProfile');
return saveProperty;
});
@@ -304,14 +304,14 @@
_.each(tab.properties, function (prop) {
//don't include the custom generic tab properties
//don't include a property that is marked readonly
if (!prop.alias.startsWith("_umb_") && !prop.readonly) {
if (!prop.alias.startsWith("_umb_")) {
saveModel.properties.push({
id: prop.id,
alias: prop.alias,
value: prop.value
});
}
});
});
@@ -338,4 +338,4 @@
}
angular.module('umbraco.services').factory('umbDataFormatter', umbDataFormatter);
})();
})();
@@ -333,122 +333,6 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
failureCallback.apply(this, [data, status, headers, config]);
}
});
},
/**
* Downloads a file to the client using AJAX/XHR
* Based on an implementation here: web.student.tuwien.ac.at/~e0427417/jsdownload.html
* See https://stackoverflow.com/a/24129082/694494
*/
downloadFile : function (httpPath) {
var deferred = $q.defer();
// Use an arraybuffer
$http.get(httpPath, { responseType: 'arraybuffer' })
.success(function (data, status, headers) {
var octetStreamMime = 'application/octet-stream';
var success = false;
// Get the headers
headers = headers();
// Get the filename from the x-filename header or default to "download.bin"
var filename = headers['x-filename'] || 'download.bin';
// Determine the content type from the header or default to "application/octet-stream"
var contentType = headers['content-type'] || octetStreamMime;
try {
// Try using msSaveBlob if supported
console.log("Trying saveBlob method ...");
var blob = new Blob([data], { type: contentType });
if (navigator.msSaveBlob)
navigator.msSaveBlob(blob, filename);
else {
// Try using other saveBlob implementations, if available
var saveBlob = navigator.webkitSaveBlob || navigator.mozSaveBlob || navigator.saveBlob;
if (saveBlob === undefined) throw "Not supported";
saveBlob(blob, filename);
}
console.log("saveBlob succeeded");
success = true;
} catch (ex) {
console.log("saveBlob method failed with the following exception:");
console.log(ex);
}
if (!success) {
// Get the blob url creator
var urlCreator = window.URL || window.webkitURL || window.mozURL || window.msURL;
if (urlCreator) {
// Try to use a download link
var link = document.createElement('a');
if ('download' in link) {
// Try to simulate a click
try {
// Prepare a blob URL
console.log("Trying download link method with simulated click ...");
var blob = new Blob([data], { type: contentType });
var url = urlCreator.createObjectURL(blob);
link.setAttribute('href', url);
// Set the download attribute (Supported in Chrome 14+ / Firefox 20+)
link.setAttribute("download", filename);
// Simulate clicking the download link
var event = document.createEvent('MouseEvents');
event.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
link.dispatchEvent(event);
console.log("Download link method with simulated click succeeded");
success = true;
} catch (ex) {
console.log("Download link method with simulated click failed with the following exception:");
console.log(ex);
}
}
if (!success) {
// Fallback to window.location method
try {
// Prepare a blob URL
// Use application/octet-stream when using window.location to force download
console.log("Trying download link method with window.location ...");
var blob = new Blob([data], { type: octetStreamMime });
var url = urlCreator.createObjectURL(blob);
window.location = url;
console.log("Download link method with window.location succeeded");
success = true;
} catch (ex) {
console.log("Download link method with window.location failed with the following exception:");
console.log(ex);
}
}
}
}
if (!success) {
// Fallback to window.open method
console.log("No methods worked for saving the arraybuffer, using last resort window.open");
window.open(httpPath, '_blank', '');
}
deferred.resolve();
})
.error(function (data, status) {
console.log("Request failed with status: " + status);
deferred.reject({
errorMsg: "An error occurred downloading the file",
data: data,
status: status
});
});
return deferred.promise;
}
};
}
@@ -1,7 +1,7 @@
angular.module("umbraco.install").controller("Umbraco.Install.UserController", function($scope, installerService) {
$scope.passwordPattern = /.*/;
$scope.installer.current.model.subscribeToNewsLetter = false;
$scope.installer.current.model.subscribeToNewsLetter = true;
if ($scope.installer.current.model.minNonAlphaNumericLength > 0) {
var exp = "";
@@ -426,114 +426,103 @@ input.umb-group-builder__group-title-input {
.content-type-editor-dialog.edit-property-settings {
.validation-wrapper {
position: relative;
.validation-wrapper {
position: relative;
}
.validation-label {
position: absolute;
top: 50%;
right: 0;
font-size: 12px;
color: @red;
transform: translate(0, -50%);
}
textarea.editor-label {
border-color:transparent;
box-shadow: none;
width: 100%;
box-sizing: border-box;
margin-bottom: 0;
font-size: 16px;
font-weight: bold;
resize: none;
line-height: 1.5em;
padding-left: 0;
border: none;
&:focus {
outline: none;
box-shadow: none !important;
}
}
.validation-label {
position: absolute;
top: 50%;
right: 0;
font-size: 12px;
color: @red;
transform: translate(0, -50%);
.editor-placeholder {
border: 1px dashed @gray-8;
width: 100%;
height: 80px;
line-height: 80px;
text-align: center;
display: block;
border-radius: 5px;
color: @gray-3;
font-weight: bold;
font-size: 14px;
color: @turquoise-d1;
&:hover {
text-decoration: none;
}
}
textarea.editor-label {
border-color: transparent;
box-shadow: none;
width: 100%;
box-sizing: border-box;
margin-bottom: 0;
font-size: 16px;
font-weight: bold;
resize: none;
line-height: 1.5em;
padding-left: 0;
border: none;
&:focus {
outline: none;
box-shadow: none !important;
}
.editor {
margin-bottom: 10px;
.editor-icon-wrapper {
border: 1px solid @gray-8;
width: 60px;
height: 60px;
text-align: center;
line-height: 60px;
border-radius: 5px;
float: left;
margin-right: 20px;
.icon {
font-size: 26px;
}
}
.editor-placeholder {
border: 1px dashed @gray-8;
width: 100%;
height: 80px;
line-height: 80px;
text-align: center;
.editor-details {
float: left;
margin-top: 10px;
.editor-name {
display: block;
border-radius: 5px;
color: @gray-3;
font-weight: bold;
font-size: 14px;
color: @turquoise-d1;
&:hover {
text-decoration: none;
}
}
.editor-editor {
display: block;
font-size: 12px;
}
}
.editor-settings-icon {
font-size: 18px;
margin-top: 8px;
}
}
.editor {
margin-bottom: 10px;
.checkbox {
margin-bottom: 20px;
}
.editor-icon-wrapper {
border: 1px solid @gray-8;
width: 60px;
height: 60px;
text-align: center;
line-height: 60px;
border-radius: 5px;
float: left;
margin-right: 20px;
.editor-description,
.editor-validation-pattern {
min-width: 100%;
min-height: 25px;
resize: none;
box-sizing: border-box;
border: none;
overflow: hidden;
}
.icon {
font-size: 26px;
}
}
.umb-dropdown {
width: 100%;
}
.editor-details {
float: left;
margin-top: 10px;
.editor-name {
display: block;
font-weight: bold;
}
.editor-editor {
display: block;
font-size: 12px;
}
}
.editor-settings-icon {
font-size: 18px;
margin-top: 8px;
}
}
.checkbox {
margin-bottom: 20px;
}
.editor-description,
.editor-validation-pattern {
min-width: 100%;
min-height: 25px;
resize: none;
box-sizing: border-box;
border: none;
overflow: hidden;
}
.umb-dropdown {
width: 100%;
}
label.checkbox.no-indent {
width: 100%;
}
}
@@ -181,7 +181,7 @@
width: 640px !important;
}
.umb-modal i {
font-size: 20px;
font-size: 14px;
}
.umb-modal .breadcrumb {
background: none;
@@ -74,6 +74,10 @@
padding-right: 10px;
}
.login-overlay .btn-success {
padding: 12px 24px;
}
.login-overlay .form label {
font-weight: bold;
}

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