Port v7@2aa0dfb2c5 - WIP
This commit is contained in:
@@ -24,6 +24,7 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
private int _version;
|
||||
private bool _hasVersion;
|
||||
private string _exe;
|
||||
|
||||
#region Availability & Version
|
||||
|
||||
@@ -84,16 +85,31 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
_hasVersion = true;
|
||||
_version = -1;
|
||||
_exe = null;
|
||||
|
||||
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
|
||||
if (programFiles == null) return;
|
||||
|
||||
// MS SQL Server installs in e.g. "C:\Program Files\Microsoft SQL Server", so
|
||||
// we want to detect it in "%ProgramFiles%\Microsoft SQL Server" - however, if
|
||||
// Umbraco runs as a 32bits process (e.g. IISExpress configured as 32bits)
|
||||
// on a 64bits system, %ProgramFiles% will point to "C:\Program Files (x86)"
|
||||
// and SQL Server cannot be found. But then, %ProgramW6432% will point to
|
||||
// the original "C:\Program Files". Using it to fix the path.
|
||||
// see also: MSDN doc for WOW64 implementation
|
||||
//
|
||||
var programW6432 = Environment.GetEnvironmentVariable("ProgramW6432");
|
||||
if (string.IsNullOrWhiteSpace(programW6432) == false && programW6432 != programFiles)
|
||||
programFiles = programW6432;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(programFiles)) return;
|
||||
|
||||
// detect 14, 13, 12, 11
|
||||
for (var i = 14; i > 10; i--)
|
||||
{
|
||||
var path = Path.Combine(programFiles, string.Format(@"Microsoft SQL Server\{0}0\Tools\Binn\SqlLocalDB.exe", i));
|
||||
if (File.Exists(path) == false) continue;
|
||||
var exe = Path.Combine(programFiles, $@"Microsoft SQL Server\{i}0\Tools\Binn\SqlLocalDB.exe");
|
||||
if (File.Exists(exe) == false) continue;
|
||||
_version = i;
|
||||
_exe = exe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -110,8 +126,7 @@ namespace Umbraco.Core.Persistence
|
||||
public string[] GetInstances()
|
||||
{
|
||||
EnsureAvailable();
|
||||
string output, error;
|
||||
var rc = ExecuteSqlLocalDb("i", out output, out error); // info
|
||||
var rc = ExecuteSqlLocalDb("i", out var output, out var error); // info
|
||||
if (rc != 0 || error != string.Empty) return null;
|
||||
return output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
@@ -138,8 +153,7 @@ namespace Umbraco.Core.Persistence
|
||||
public bool CreateInstance(string instanceName)
|
||||
{
|
||||
EnsureAvailable();
|
||||
string output, error;
|
||||
return ExecuteSqlLocalDb(string.Format("c \"{0}\"", instanceName), out output, out error) == 0 && error == string.Empty;
|
||||
return ExecuteSqlLocalDb($"c \"{instanceName}\"", out _, out var error) == 0 && error == string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -160,9 +174,8 @@ namespace Umbraco.Core.Persistence
|
||||
instance.DropDatabases(); // else the files remain
|
||||
|
||||
// -i force NOWAIT, -k kills
|
||||
string output, error;
|
||||
return ExecuteSqlLocalDb(string.Format("p \"{0}\" -i", instanceName), out output, out error) == 0 && error == string.Empty
|
||||
&& ExecuteSqlLocalDb(string.Format("d \"{0}\"", instanceName), out output, out error) == 0 && error == string.Empty;
|
||||
return ExecuteSqlLocalDb($"p \"{instanceName}\" -i", out _, out var error) == 0 && error == string.Empty
|
||||
&& ExecuteSqlLocalDb($"d \"{instanceName}\"", out _, out error) == 0 && error == string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -180,8 +193,7 @@ namespace Umbraco.Core.Persistence
|
||||
if (InstanceExists(instanceName) == false) return true;
|
||||
|
||||
// -i force NOWAIT, -k kills
|
||||
string output, error;
|
||||
return ExecuteSqlLocalDb(string.Format("p \"{0}\" -i", instanceName), out output, out error) == 0 && error == string.Empty;
|
||||
return ExecuteSqlLocalDb($"p \"{instanceName}\" -i", out _, out var error) == 0 && error == string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -197,8 +209,7 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
EnsureAvailable();
|
||||
if (InstanceExists(instanceName) == false) return false;
|
||||
string output, error;
|
||||
return ExecuteSqlLocalDb(string.Format("s \"{0}\"", instanceName), out output, out error) == 0 && error == string.Empty;
|
||||
return ExecuteSqlLocalDb($"s \"{instanceName}\"", out _, out var error) == 0 && error == string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -230,7 +241,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <summary>
|
||||
/// Gets the name of the instance.
|
||||
/// </summary>
|
||||
public string InstanceName { get; private set; }
|
||||
public string InstanceName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Instance"/> class.
|
||||
@@ -239,7 +250,7 @@ namespace Umbraco.Core.Persistence
|
||||
public Instance(string instanceName)
|
||||
{
|
||||
InstanceName = instanceName;
|
||||
_masterCstr = string.Format(@"Server=(localdb)\{0};Integrated Security=True;", instanceName);
|
||||
_masterCstr = $@"Server=(localdb)\{instanceName};Integrated Security=True;";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -252,7 +263,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// </remarks>
|
||||
public string GetConnectionString(string databaseName)
|
||||
{
|
||||
return _masterCstr + string.Format(@"Database={0};", databaseName);
|
||||
return _masterCstr + $@"Database={databaseName};";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -268,10 +279,9 @@ namespace Umbraco.Core.Persistence
|
||||
/// </remarks>
|
||||
public string GetAttachedConnectionString(string databaseName, string filesPath)
|
||||
{
|
||||
string logName, baseFilename, baseLogFilename, mdfFilename, ldfFilename;
|
||||
GetDatabaseFiles(databaseName, filesPath, out logName, out baseFilename, out baseLogFilename, out mdfFilename, out ldfFilename);
|
||||
GetDatabaseFiles(databaseName, filesPath, out _, out _, out _, out var mdfFilename, out _);
|
||||
|
||||
return _masterCstr + string.Format(@"AttachDbFileName='{0}';", mdfFilename);
|
||||
return _masterCstr + $@"AttachDbFileName='{mdfFilename}';";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -367,8 +377,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// </remarks>
|
||||
public bool CreateDatabase(string databaseName, string filesPath)
|
||||
{
|
||||
string logName, baseFilename, baseLogFilename, mdfFilename, ldfFilename;
|
||||
GetDatabaseFiles(databaseName, filesPath, out logName, out baseFilename, out baseLogFilename, out mdfFilename, out ldfFilename);
|
||||
GetDatabaseFiles(databaseName, filesPath, out var logName, out _, out _, out var mdfFilename, out var ldfFilename);
|
||||
|
||||
using (var conn = new SqlConnection(_masterCstr))
|
||||
using (var cmd = conn.CreateCommand())
|
||||
@@ -380,13 +389,10 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
// cannot use parameters on CREATE DATABASE
|
||||
// ie "CREATE DATABASE @0 ..." does not work
|
||||
SetCommand(cmd, string.Format(@"
|
||||
CREATE DATABASE {0}
|
||||
ON (NAME=N{1}, FILENAME={2})
|
||||
LOG ON (NAME=N{3}, FILENAME={4})",
|
||||
QuotedName(databaseName),
|
||||
QuotedName(databaseName, '\''), QuotedName(mdfFilename, '\''),
|
||||
QuotedName(logName, '\''), QuotedName(ldfFilename, '\'')));
|
||||
SetCommand(cmd, $@"
|
||||
CREATE DATABASE {QuotedName(databaseName)}
|
||||
ON (NAME=N{QuotedName(databaseName, '\'')}, FILENAME={QuotedName(mdfFilename, '\'')})
|
||||
LOG ON (NAME=N{QuotedName(logName, '\'')}, FILENAME={QuotedName(ldfFilename, '\'')})");
|
||||
|
||||
var unused = cmd.ExecuteNonQuery();
|
||||
}
|
||||
@@ -608,9 +614,8 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
// cannot use parameters on ALTER DATABASE
|
||||
// ie "ALTER DATABASE @0 ..." does not work
|
||||
SetCommand(cmd, string.Format(@"
|
||||
ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE",
|
||||
QuotedName(databaseName)));
|
||||
SetCommand(cmd, $@"
|
||||
ALTER DATABASE {QuotedName(databaseName)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
|
||||
|
||||
var unused1 = cmd.ExecuteNonQuery();
|
||||
}
|
||||
@@ -631,9 +636,8 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
// cannot use parameters on DROP DATABASE
|
||||
// ie "DROP DATABASE @0 ..." does not work
|
||||
SetCommand(cmd, string.Format(@"
|
||||
DROP DATABASE {0}",
|
||||
QuotedName(databaseName)));
|
||||
SetCommand(cmd, $@"
|
||||
DROP DATABASE {QuotedName(databaseName)}");
|
||||
|
||||
var unused2 = cmd.ExecuteNonQuery();
|
||||
|
||||
@@ -651,7 +655,7 @@ namespace Umbraco.Core.Persistence
|
||||
private static string GetLogFilename(string mdfFilename)
|
||||
{
|
||||
if (mdfFilename.EndsWith(".mdf") == false)
|
||||
throw new ArgumentException("Not a valid MDF filename (no .mdf extension).", "mdfFilename");
|
||||
throw new ArgumentException("Not a valid MDF filename (no .mdf extension).", nameof(mdfFilename));
|
||||
return mdfFilename.Substring(0, mdfFilename.Length - ".mdf".Length) + "_log.ldf";
|
||||
}
|
||||
|
||||
@@ -664,9 +668,8 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
// cannot use parameters on ALTER DATABASE
|
||||
// ie "ALTER DATABASE @0 ..." does not work
|
||||
SetCommand(cmd, string.Format(@"
|
||||
ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE",
|
||||
QuotedName(databaseName)));
|
||||
SetCommand(cmd, $@"
|
||||
ALTER DATABASE {QuotedName(databaseName)} SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
|
||||
|
||||
var unused1 = cmd.ExecuteNonQuery();
|
||||
|
||||
@@ -685,19 +688,16 @@ namespace Umbraco.Core.Persistence
|
||||
/// <param name="filesPath">The directory containing database files.</param>
|
||||
private static void AttachDatabase(SqlCommand cmd, string databaseName, string filesPath)
|
||||
{
|
||||
string logName, baseFilename, baseLogFilename, mdfFilename, ldfFilename;
|
||||
GetDatabaseFiles(databaseName, filesPath, out logName, out baseFilename, out baseLogFilename, out mdfFilename, out ldfFilename);
|
||||
GetDatabaseFiles(databaseName, filesPath,
|
||||
out var logName, out _, out _, out var mdfFilename, out var ldfFilename);
|
||||
|
||||
// cannot use parameters on CREATE DATABASE
|
||||
// ie "CREATE DATABASE @0 ..." does not work
|
||||
SetCommand(cmd, string.Format(@"
|
||||
CREATE DATABASE {0}
|
||||
ON (NAME=N{1}, FILENAME={2})
|
||||
LOG ON (NAME=N{3}, FILENAME={4})
|
||||
FOR ATTACH",
|
||||
QuotedName(databaseName),
|
||||
QuotedName(databaseName, '\''), QuotedName(mdfFilename, '\''),
|
||||
QuotedName(logName, '\''), QuotedName(ldfFilename, '\'')));
|
||||
SetCommand(cmd, $@"
|
||||
CREATE DATABASE {QuotedName(databaseName)}
|
||||
ON (NAME=N{QuotedName(databaseName, '\'')}, FILENAME={QuotedName(mdfFilename, '\'')})
|
||||
LOG ON (NAME=N{QuotedName(logName, '\'')}, FILENAME={QuotedName(ldfFilename, '\'')})
|
||||
FOR ATTACH");
|
||||
|
||||
var unused = cmd.ExecuteNonQuery();
|
||||
}
|
||||
@@ -790,9 +790,8 @@ namespace Umbraco.Core.Persistence
|
||||
&& (sourceExtension == null && targetExtension == null || sourceExtension == targetExtension);
|
||||
if (nop && delete == false) return;
|
||||
|
||||
string logName, baseFilename, baseLogFilename, mdfFilename, ldfFilename;
|
||||
GetDatabaseFiles(databaseName, filesPath,
|
||||
out logName, out baseFilename, out baseLogFilename, out mdfFilename, out ldfFilename);
|
||||
out _, out _, out _, out var mdfFilename, out var ldfFilename);
|
||||
|
||||
if (sourceExtension != null)
|
||||
{
|
||||
@@ -809,9 +808,8 @@ namespace Umbraco.Core.Persistence
|
||||
else
|
||||
{
|
||||
// copy or copy+delete ie move
|
||||
string targetLogName, targetBaseFilename, targetLogFilename, targetMdfFilename, targetLdfFilename;
|
||||
GetDatabaseFiles(targetDatabaseName ?? databaseName, targetFilesPath ?? filesPath,
|
||||
out targetLogName, out targetBaseFilename, out targetLogFilename, out targetMdfFilename, out targetLdfFilename);
|
||||
out _, out _, out _, out var targetMdfFilename, out var targetLdfFilename);
|
||||
|
||||
if (targetExtension != null)
|
||||
{
|
||||
@@ -846,9 +844,8 @@ namespace Umbraco.Core.Persistence
|
||||
/// </remarks>
|
||||
public bool DatabaseFilesExist(string databaseName, string filesPath, string extension = null)
|
||||
{
|
||||
string logName, baseFilename, baseLogFilename, mdfFilename, ldfFilename;
|
||||
GetDatabaseFiles(databaseName, filesPath,
|
||||
out logName, out baseFilename, out baseLogFilename, out mdfFilename, out ldfFilename);
|
||||
out _, out _, out _, out var mdfFilename, out var ldfFilename);
|
||||
|
||||
if (extension != null)
|
||||
{
|
||||
@@ -897,16 +894,13 @@ namespace Umbraco.Core.Persistence
|
||||
/// </remarks>
|
||||
private int ExecuteSqlLocalDb(string args, out string output, out string error)
|
||||
{
|
||||
var programFiles = Environment.GetEnvironmentVariable("ProgramFiles");
|
||||
if (programFiles == null)
|
||||
if (_exe == null) // should never happen - we should not execute if not available
|
||||
{
|
||||
output = string.Empty;
|
||||
error = "SqlLocalDB.exe not found";
|
||||
return -1;
|
||||
}
|
||||
|
||||
var path = Path.Combine(programFiles, string.Format(@"Microsoft SQL Server\{0}0\Tools\Binn\SqlLocalDB.exe", _version));
|
||||
|
||||
var p = new Process
|
||||
{
|
||||
StartInfo =
|
||||
@@ -914,7 +908,7 @@ namespace Umbraco.Core.Persistence
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
FileName = path,
|
||||
FileName = _exe,
|
||||
Arguments = args,
|
||||
CreateNoWindow = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
|
||||
@@ -40,7 +40,12 @@ namespace Umbraco.Core.Persistence
|
||||
_tableDefinition = DefinitionFactory.GetTableDefinition(pd.Type, sqlSyntaxProvider);
|
||||
if (_tableDefinition == null) throw new InvalidOperationException("No table definition found for type " + pd.Type);
|
||||
|
||||
_readerColumns = pd.Columns.Select(x => x.Value).ToArray();
|
||||
// only real columns, exclude result columns
|
||||
_readerColumns = pd.Columns
|
||||
.Where(x => x.Value.ResultColumn == false)
|
||||
.Select(x => x.Value)
|
||||
.ToArray();
|
||||
|
||||
_sqlSyntaxProvider = sqlSyntaxProvider;
|
||||
_enumerator = dataSource.GetEnumerator();
|
||||
_columnDefinitions = _tableDefinition.Columns.ToArray();
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
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 : IReadWriteQueryRepository<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,9 +1,37 @@
|
||||
using Umbraco.Core.Models;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IAuditRepository : IReadRepository<int, AuditItem>, IWriteRepository<AuditItem>, IQueryRepository<AuditItem>
|
||||
public interface IAuditRepository : IReadRepository<int, IAuditItem>, IWriteRepository<IAuditItem>, IQueryRepository<IAuditItem>
|
||||
{
|
||||
void CleanLogs(int maximumAgeOfLogsInMinutes);
|
||||
|
||||
/// <summary>
|
||||
/// Return the audit items as paged result
|
||||
/// </summary>
|
||||
/// <param name="query">
|
||||
/// The query coming from the service
|
||||
/// </param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="auditTypeFilter">
|
||||
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
|
||||
/// so we need to do that here
|
||||
/// </param>
|
||||
/// <param name="customFilter">
|
||||
/// A user supplied custom filter
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<IAuditItem> GetPagedResultsByQuery(
|
||||
IQuery<IAuditItem> query,
|
||||
long pageIndex, int pageSize, out long totalRecords,
|
||||
Direction orderDirection,
|
||||
AuditType[] auditTypeFilter,
|
||||
IQuery<IAuditItem> customFilter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a repository for <see cref="IConsent"/> entities.
|
||||
/// </summary>
|
||||
public interface IConsentRepository : IReadWriteQueryRepository<int, IConsent>
|
||||
{
|
||||
/// <summary>
|
||||
/// Clears the current flag.
|
||||
/// </summary>
|
||||
void ClearCurrent(string source, string context, string action);
|
||||
}
|
||||
}
|
||||
@@ -39,5 +39,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
void AssignRoles(int[] memberIds, string[] roleNames);
|
||||
|
||||
void DissociateRoles(int[] memberIds, string[] roleNames);
|
||||
|
||||
int[] GetMemberIds(string[] names);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,5 +85,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IProfile GetProfile(string username);
|
||||
IProfile GetProfile(int id);
|
||||
IDictionary<UserState, int> GetUserStates();
|
||||
|
||||
Guid CreateLoginSession(int userId, string requestingIpAddress, bool cleanStaleSessions = true);
|
||||
bool ValidateLoginSession(int userId, Guid sessionId);
|
||||
int ClearLoginSessions(int userId);
|
||||
int ClearLoginSessions(TimeSpan timespan);
|
||||
void ClearLoginSession(Guid sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the NPoco implementation of <see cref="IAuditEntryRepository"/>.
|
||||
/// </summary>
|
||||
internal class AuditEntryRepository : NPocoRepositoryBase<int, IAuditEntry>, IAuditEntryRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuditEntryRepository"/> class.
|
||||
/// </summary>
|
||||
public AuditEntryRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger)
|
||||
: base(scopeAccessor, cache, logger)
|
||||
{ }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Guid NodeObjectTypeId => throw new NotSupportedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IAuditEntry PerformGet(int id)
|
||||
{
|
||||
var sql = Sql()
|
||||
.Select<AuditEntryDto>()
|
||||
.From<AuditEntryDto>()
|
||||
.Where<AuditEntryDto>(x => x.Id == id);
|
||||
|
||||
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 = Sql()
|
||||
.Select<AuditEntryDto>()
|
||||
.From<AuditEntryDto>();
|
||||
|
||||
return Database.Fetch<AuditEntryDto>(sql).Select(AuditEntryFactory.BuildEntity);
|
||||
}
|
||||
|
||||
var entries = new List<IAuditEntry>();
|
||||
|
||||
foreach (var group in ids.InGroupsOf(2000))
|
||||
{
|
||||
var sql = Sql()
|
||||
.Select<AuditEntryDto>()
|
||||
.From<AuditEntryDto>()
|
||||
.WhereIn<AuditEntryDto>(x => x.Id, group);
|
||||
|
||||
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<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = Sql();
|
||||
sql = isCount ? sql.SelectCount() : sql.Select<AuditEntryDto>();
|
||||
sql = sql.From<AuditEntryDto>();
|
||||
return sql;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
return $"{Constants.DatabaseSchema.Tables.AuditEntry}.id = @id";
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new NotSupportedException("Audit entries cannot be deleted.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PersistNewItem(IAuditEntry entity)
|
||||
{
|
||||
((EntityBase) 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 = Sql()
|
||||
.Select<AuditEntryDto>()
|
||||
.From<AuditEntryDto>()
|
||||
.OrderByDescending<AuditEntryDto>(x => x.EventDateUtc);
|
||||
|
||||
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(Constants.DatabaseSchema.Tables.AuditEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,20 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing.CompositionRoots;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
internal class AuditRepository : NPocoRepositoryBase<int, AuditItem>, IAuditRepository
|
||||
internal class AuditRepository : NPocoRepositoryBase<int, IAuditItem>, IAuditRepository
|
||||
{
|
||||
public AuditRepository(IScopeAccessor scopeAccessor, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger)
|
||||
: base(scopeAccessor, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override void PersistNewItem(AuditItem entity)
|
||||
protected override void PersistNewItem(IAuditItem entity)
|
||||
{
|
||||
Database.Insert(new LogDto
|
||||
{
|
||||
@@ -31,8 +32,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
});
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(AuditItem entity)
|
||||
protected override void PersistUpdatedItem(IAuditItem entity)
|
||||
{
|
||||
// wtf?! inserting when updating?!
|
||||
Database.Insert(new LogDto
|
||||
{
|
||||
Comment = entity.Comment,
|
||||
@@ -43,27 +45,26 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
});
|
||||
}
|
||||
|
||||
protected override AuditItem PerformGet(int id)
|
||||
protected override IAuditItem PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
|
||||
var dto = Database.First<LogDto>(sql);
|
||||
if (dto == null)
|
||||
return null;
|
||||
|
||||
return new AuditItem(dto.NodeId, dto.Comment, Enum<AuditType>.Parse(dto.Header), dto.UserId);
|
||||
return dto == null
|
||||
? null
|
||||
: new AuditItem(dto.NodeId, dto.Comment, Enum<AuditType>.Parse(dto.Header), dto.UserId);
|
||||
}
|
||||
|
||||
protected override IEnumerable<AuditItem> PerformGetAll(params int[] ids)
|
||||
protected override IEnumerable<IAuditItem> PerformGetAll(params int[] ids)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override IEnumerable<AuditItem> PerformGetByQuery(IQuery<AuditItem> query)
|
||||
protected override IEnumerable<IAuditItem> PerformGetByQuery(IQuery<IAuditItem> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<AuditItem>(sqlClause, query);
|
||||
var translator = new SqlTranslator<IAuditItem>(sqlClause, query);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<LogDto>(sql);
|
||||
@@ -82,6 +83,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
sql
|
||||
.From<LogDto>();
|
||||
|
||||
if (!isCount)
|
||||
sql.LeftJoin<UserDto>().On<LogDto, UserDto>((left, right) => left.UserId == right.Id);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
@@ -108,5 +112,61 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
"delete from umbracoLog where datestamp < @oldestPermittedLogEntry and logHeader in ('open','system')",
|
||||
new {oldestPermittedLogEntry = oldestPermittedLogEntry});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the audit items as paged result
|
||||
/// </summary>
|
||||
/// <param name="query">
|
||||
/// The query coming from the service
|
||||
/// </param>
|
||||
/// <param name="pageIndex"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="totalRecords"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="auditTypeFilter">
|
||||
/// Since we currently do not have enum support with our expression parser, we cannot query on AuditType in the query or the custom filter
|
||||
/// so we need to do that here
|
||||
/// </param>
|
||||
/// <param name="customFilter">
|
||||
/// A user supplied custom filter
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IAuditItem> GetPagedResultsByQuery(IQuery<IAuditItem> query, long pageIndex, int pageSize,
|
||||
out long totalRecords, Direction orderDirection,
|
||||
AuditType[] auditTypeFilter,
|
||||
IQuery<IAuditItem> customFilter)
|
||||
{
|
||||
if (auditTypeFilter == null) auditTypeFilter = Array.Empty<AuditType>();
|
||||
|
||||
var sql = GetBaseQuery(false);
|
||||
|
||||
var translator = new SqlTranslator<IAuditItem>(sql, query ?? Query<IAuditItem>());
|
||||
sql = translator.Translate();
|
||||
|
||||
if (customFilter != null)
|
||||
foreach (var filterClause in customFilter.GetWhereClauses())
|
||||
sql.Where(filterClause.Item1, filterClause.Item2);
|
||||
|
||||
if (auditTypeFilter.Length > 0)
|
||||
foreach (var type in auditTypeFilter)
|
||||
sql.Where("(logHeader=@0)", type.ToString());
|
||||
|
||||
sql = orderDirection == Direction.Ascending
|
||||
? sql.OrderBy("Datestamp")
|
||||
: sql.OrderByDescending("Datestamp");
|
||||
|
||||
// get page
|
||||
var page = Database.Page<LogDto>(pageIndex + 1, pageSize, sql);
|
||||
totalRecords = page.TotalItems;
|
||||
|
||||
var items = page.Items.Select(
|
||||
dto => new AuditItem(dto.Id, dto.Comment, Enum<AuditType>.Parse(dto.Header), dto.UserId)).ToArray();
|
||||
|
||||
// map the DateStamp
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
items[i].CreateDate = page.Items[i].Datestamp;
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the NPoco implementation of <see cref="IConsentRepository"/>.
|
||||
/// </summary>
|
||||
internal class ConsentRepository : NPocoRepositoryBase<int, IConsent>, IConsentRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConsentRepository"/> class.
|
||||
/// </summary>
|
||||
public ConsentRepository(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger)
|
||||
: base(scopeAccessor, cache, logger)
|
||||
{ }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Guid NodeObjectTypeId => throw new NotSupportedException();
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IConsent PerformGet(int id)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<IConsent> PerformGetAll(params int[] ids)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<IConsent> PerformGetByQuery(IQuery<IConsent> query)
|
||||
{
|
||||
var sqlClause = Sql().Select<ConsentDto>().From<ConsentDto>();
|
||||
var translator = new SqlTranslator<IConsent>(sqlClause, query);
|
||||
var sql = translator.Translate().OrderByDescending<ConsentDto>(x => x.CreateDate);
|
||||
return ConsentFactory.BuildEntities(Database.Fetch<ConsentDto>(sql));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PersistNewItem(IConsent entity)
|
||||
{
|
||||
((EntityBase) entity).AddingEntity();
|
||||
|
||||
var dto = ConsentFactory.BuildDto(entity);
|
||||
Database.Insert(dto);
|
||||
entity.Id = dto.Id;
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void PersistUpdatedItem(IConsent entity)
|
||||
{
|
||||
((EntityBase) entity).UpdatingEntity();
|
||||
|
||||
var dto = ConsentFactory.BuildDto(entity);
|
||||
Database.Update(dto);
|
||||
entity.ResetDirtyProperties();
|
||||
|
||||
IsolatedCache.ClearCacheItem(RepositoryCacheKeys.GetKey<IConsent>(entity.Id));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ClearCurrent(string source, string context, string action)
|
||||
{
|
||||
var sql = Sql()
|
||||
.Update<ConsentDto>(u => u.Set(x => x.Current, false))
|
||||
.Where<ConsentDto>(x => x.Source == source && x.Context == context && x.Action == action && x.Current);
|
||||
Database.Execute(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,10 +80,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
protected override Sql<ISqlContext> GetBaseQuery(QueryType queryType)
|
||||
{
|
||||
return GetBaseQuery(queryType, true);
|
||||
return GetBaseQuery(queryType);
|
||||
}
|
||||
|
||||
protected virtual Sql<ISqlContext> GetBaseQuery(QueryType queryType, bool current)
|
||||
protected virtual Sql<ISqlContext> GetBaseQuery(QueryType queryType, bool current = true, bool joinMediaVersion = false)
|
||||
{
|
||||
var sql = SqlContext.Sql();
|
||||
|
||||
@@ -108,6 +108,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.InnerJoin<NodeDto>().On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.InnerJoin<ContentVersionDto>().On<ContentDto, ContentVersionDto>(left => left.NodeId, right => right.NodeId);
|
||||
|
||||
if (joinMediaVersion)
|
||||
sql.InnerJoin<MediaVersionDto>().On<ContentVersionDto, MediaVersionDto>((left, right) => left.Id == right.Id);
|
||||
|
||||
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
|
||||
|
||||
@@ -143,6 +145,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Relation + " WHERE childId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.TagRelationship + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Document + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.MediaVersion + " WHERE id IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.PropertyData + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id",
|
||||
@@ -157,7 +160,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
public override IEnumerable<IMedia> GetAllVersions(int nodeId)
|
||||
{
|
||||
var sql = GetBaseQuery(QueryType.Many, false)
|
||||
var sql = GetBaseQuery(QueryType.Many, current: false)
|
||||
.Where<NodeDto>(x => x.NodeId == nodeId)
|
||||
.OrderByDescending<ContentVersionDto>(x => x.Current)
|
||||
.AndByDescending<ContentVersionDto>(x => x.VersionDate);
|
||||
@@ -188,29 +191,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
umbracoFileValue = string.Concat(mediaPath.Substring(0, underscoreIndex), mediaPath.Substring(dotIndex));
|
||||
}
|
||||
|
||||
// If the stripped-down url returns null, we try again with the original url.
|
||||
// Previously, the function would fail on e.g. "my_x_image.jpg"
|
||||
var nodeId = GetMediaNodeIdByPath(Sql().Where<PropertyDataDto>(x => x.VarcharValue == umbracoFileValue));
|
||||
if (nodeId < 0) nodeId = GetMediaNodeIdByPath(Sql().Where<PropertyDataDto>(x => x.VarcharValue == mediaPath));
|
||||
var sql = GetBaseQuery(QueryType.Single, joinMediaVersion: true)
|
||||
.Where<MediaVersionDto>(x => x.Path == umbracoFileValue)
|
||||
.SelectTop(1);
|
||||
|
||||
// If no result so far, try getting from a json value stored in the ntext / nvarchar column
|
||||
if (nodeId < 0) nodeId = GetMediaNodeIdByPath(Sql().Where("textValue LIKE @0", "%" + umbracoFileValue + "%"));
|
||||
if (nodeId < 0) nodeId = GetMediaNodeIdByPath(Sql().Where("varcharValue LIKE @0", "%" + umbracoFileValue + "%"));
|
||||
|
||||
return nodeId < 0 ? null : Get(nodeId);
|
||||
}
|
||||
|
||||
private int GetMediaNodeIdByPath(Sql query)
|
||||
{
|
||||
var sql = Sql().Select<ContentVersionDto>(x => x.NodeId)
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>(left => left.PropertyTypeId, right => right.Id)
|
||||
.InnerJoin<ContentVersionDto>().On<PropertyDataDto, ContentVersionDto>((left, right) => left.VersionId == right.Id)
|
||||
.Where<PropertyTypeDto>(x => x.Alias == "umbracoFile")
|
||||
.Append(query);
|
||||
|
||||
var nodeId = Database.Fetch<int?>(sql).FirstOrDefault();
|
||||
return nodeId ?? -1;
|
||||
var dto = Database.Fetch<ContentDto>(sql).FirstOrDefault();
|
||||
return dto == null
|
||||
? null
|
||||
: MapDtoToContent(dto);
|
||||
}
|
||||
|
||||
protected override void PerformDeleteVersion(int id, int versionId)
|
||||
@@ -249,7 +237,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var sortOrder = GetNewChildSortOrder(entity.ParentId, 0);
|
||||
|
||||
// persist the node dto
|
||||
var nodeDto = dto.NodeDto;
|
||||
var nodeDto = dto.ContentDto.NodeDto;
|
||||
nodeDto.Path = parent.Path;
|
||||
nodeDto.Level = Convert.ToInt16(level);
|
||||
nodeDto.SortOrder = sortOrder;
|
||||
@@ -258,21 +246,13 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// and then either update or insert the node dto
|
||||
var id = GetReservedId(nodeDto.UniqueId);
|
||||
if (id > 0)
|
||||
{
|
||||
nodeDto.NodeId = id;
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
nodeDto.ValidatePathWithException();
|
||||
Database.Update(nodeDto);
|
||||
}
|
||||
else
|
||||
{
|
||||
Database.Insert(nodeDto);
|
||||
|
||||
// update path, now that we have an id
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
nodeDto.ValidatePathWithException();
|
||||
Database.Update(nodeDto);
|
||||
}
|
||||
nodeDto.Path = string.Concat(parent.Path, ",", nodeDto.NodeId);
|
||||
nodeDto.ValidatePathWithException();
|
||||
Database.Update(nodeDto);
|
||||
|
||||
// update entity
|
||||
entity.Id = nodeDto.NodeId;
|
||||
@@ -281,17 +261,23 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
entity.Level = level;
|
||||
|
||||
// persist the content dto
|
||||
dto.NodeId = nodeDto.NodeId;
|
||||
Database.Insert(dto);
|
||||
var contentDto = dto.ContentDto;
|
||||
contentDto.NodeId = nodeDto.NodeId;
|
||||
Database.Insert(contentDto);
|
||||
|
||||
// persist the content version dto
|
||||
// assumes a new version id and version date (modified date) has been set
|
||||
var contentVersionDto = dto.ContentVersionDto;
|
||||
var contentVersionDto = dto.MediaVersionDto.ContentVersionDto;
|
||||
contentVersionDto.NodeId = nodeDto.NodeId;
|
||||
contentVersionDto.Current = true;
|
||||
Database.Insert(contentVersionDto);
|
||||
media.VersionId = contentVersionDto.Id;
|
||||
|
||||
// persist the media version dto
|
||||
var mediaVersionDto = dto.MediaVersionDto;
|
||||
mediaVersionDto.Id = media.VersionId;
|
||||
Database.Insert(mediaVersionDto);
|
||||
|
||||
// persist the property data
|
||||
var propertyDataDtos = PropertyFactory.BuildDtos(media.VersionId, 0, entity.Properties, out _);
|
||||
foreach (var propertyDataDto in propertyDataDtos)
|
||||
@@ -333,17 +319,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
var dto = ContentBaseFactory.BuildDto(entity);
|
||||
|
||||
// update the node dto
|
||||
var nodeDto = dto.NodeDto;
|
||||
var nodeDto = dto.ContentDto.NodeDto;
|
||||
nodeDto.ValidatePathWithException();
|
||||
Database.Update(nodeDto);
|
||||
|
||||
// update the content dto
|
||||
Database.Update(dto);
|
||||
Database.Update(dto.ContentDto);
|
||||
|
||||
// update the content version dto
|
||||
var contentVersionDto = dto.ContentVersionDto;
|
||||
// update the content & media version dtos
|
||||
var contentVersionDto = dto.MediaVersionDto.ContentVersionDto;
|
||||
var mediaVersionDto = dto.MediaVersionDto;
|
||||
contentVersionDto.Current = true;
|
||||
Database.Update(contentVersionDto);
|
||||
Database.Update(mediaVersionDto);
|
||||
|
||||
// replace the property data
|
||||
var deletePropertyDataSql = SqlContext.Sql().Delete<PropertyDataDto>().Where<PropertyDataDto>(x => x.VersionId == media.VersionId);
|
||||
|
||||
@@ -173,20 +173,19 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.Select("un.*")
|
||||
.From("umbracoNode AS un")
|
||||
.InnerJoin("cmsMember2MemberGroup")
|
||||
.On("un.id = cmsMember2MemberGroup.MemberGroup")
|
||||
.LeftJoin("(SELECT umbracoNode.id, cmsMember.LoginName FROM umbracoNode INNER JOIN cmsMember ON umbracoNode.id = cmsMember.nodeId) AS member")
|
||||
.On("member.id = cmsMember2MemberGroup.Member")
|
||||
.Where("un.nodeObjectType=@objectType", new {objectType = NodeObjectTypeId })
|
||||
.Where("member.LoginName=@loginName", new {loginName = username});
|
||||
.On("cmsMember2MemberGroup.MemberGroup = un.id")
|
||||
.InnerJoin("cmsMember")
|
||||
.On("cmsMember.nodeId = cmsMember2MemberGroup.Member")
|
||||
.Where("un.nodeObjectType=@objectType", new { objectType = NodeObjectTypeId })
|
||||
.Where("cmsMember.LoginName=@loginName", new { loginName = username });
|
||||
|
||||
return Database.Fetch<NodeDto>(sql)
|
||||
.DistinctBy(dto => dto.NodeId)
|
||||
.Select(x => _modelFactory.BuildEntity(x));
|
||||
}
|
||||
|
||||
public void AssignRoles(string[] usernames, string[] roleNames)
|
||||
public int[] GetMemberIds(string[] usernames)
|
||||
{
|
||||
//first get the member ids based on the usernames
|
||||
var memberObjectType = Constants.ObjectTypes.Member;
|
||||
|
||||
var memberSql = Sql()
|
||||
@@ -196,26 +195,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.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();
|
||||
return Database.Fetch<int>(memberSql).ToArray();
|
||||
}
|
||||
|
||||
AssignRolesInternal(memberIds, roleNames);
|
||||
public void AssignRoles(string[] usernames, string[] roleNames)
|
||||
{
|
||||
AssignRolesInternal(GetMemberIds(usernames), roleNames);
|
||||
}
|
||||
|
||||
public void DissociateRoles(string[] usernames, string[] roleNames)
|
||||
{
|
||||
//first get the member ids based on the usernames
|
||||
var memberObjectType = Constants.ObjectTypes.Member;
|
||||
|
||||
var memberSql = Sql()
|
||||
.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);
|
||||
DissociateRolesInternal(GetMemberIds(usernames), roleNames);
|
||||
}
|
||||
|
||||
public void AssignRoles(int[] memberIds, string[] roleNames)
|
||||
|
||||
@@ -147,7 +147,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
.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",
|
||||
"cmsPropertyType.propertyTypeGroupId AS PropertyTypesGroupId",
|
||||
"cmsMemberType.memberCanEdit", "cmsMemberType.viewOnProfile", "cmsMemberType.isSensitive",
|
||||
"uDataType.propertyEditorAlias", "uDataType.dbType", "cmsPropertyTypeGroup.id AS PropertyTypeGroupId",
|
||||
"cmsPropertyTypeGroup.text AS PropertyGroupName", "cmsPropertyTypeGroup.uniqueID AS PropertyGroupUniqueID",
|
||||
"cmsPropertyTypeGroup.sortorder AS PropertyGroupSortOrder", "cmsPropertyTypeGroup.contenttypeNodeId")
|
||||
|
||||
@@ -20,6 +20,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
var name = Name;
|
||||
|
||||
// cater nodes with no name.
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
return _numPos;
|
||||
|
||||
if (name[name.Length - 1] != ')')
|
||||
return _numPos = -1;
|
||||
|
||||
@@ -106,7 +110,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueing ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
|
||||
return uniqueing || string.IsNullOrWhiteSpace(nodeName)
|
||||
? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")")
|
||||
: nodeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +298,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
entity.Id = id;
|
||||
|
||||
PersistAllowedSections(entity);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(IUserGroup entity)
|
||||
@@ -309,6 +311,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
Database.Update(userGroupDto);
|
||||
|
||||
PersistAllowedSections(entity);
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
private void PersistAllowedSections(IUserGroup entity)
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Web.Security;
|
||||
using Newtonsoft.Json;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -151,14 +152,91 @@ ORDER BY colName";
|
||||
|
||||
return new Dictionary<UserState, int>
|
||||
{
|
||||
{UserState.All, result[0].num},
|
||||
{UserState.Active, result[1].num},
|
||||
{UserState.Disabled, result[2].num},
|
||||
{UserState.LockedOut, result[3].num},
|
||||
{UserState.Invited, result[4].num}
|
||||
{UserState.All, (int) result[0].num},
|
||||
{UserState.Active, (int) result[1].num},
|
||||
{UserState.Disabled, (int) result[2].num},
|
||||
{UserState.LockedOut, (int) result[3].num},
|
||||
{UserState.Invited, (int) result[4].num}
|
||||
};
|
||||
}
|
||||
|
||||
public Guid CreateLoginSession(int userId, string requestingIpAddress, bool cleanStaleSessions = true)
|
||||
{
|
||||
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
|
||||
//and also business logic models for these objects but that's just so overkill for what we are doing
|
||||
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
|
||||
var now = DateTime.UtcNow;
|
||||
var dto = new UserLoginDto
|
||||
{
|
||||
UserId = userId,
|
||||
IpAddress = requestingIpAddress,
|
||||
LoggedInUtc = now,
|
||||
LastValidatedUtc = now,
|
||||
LoggedOutUtc = null,
|
||||
SessionId = Guid.NewGuid()
|
||||
};
|
||||
Database.Insert(dto);
|
||||
|
||||
if (cleanStaleSessions)
|
||||
{
|
||||
ClearLoginSessions(TimeSpan.FromDays(15));
|
||||
}
|
||||
|
||||
return dto.SessionId;
|
||||
}
|
||||
|
||||
public bool ValidateLoginSession(int userId, Guid sessionId)
|
||||
{
|
||||
var found = Database.FirstOrDefault<UserLoginDto>("WHERE sessionId=@sessionId", new {sessionId = sessionId});
|
||||
if (found == null || found.UserId != userId || found.LoggedOutUtc.HasValue)
|
||||
return false;
|
||||
|
||||
//now detect if there's been a timeout
|
||||
if (DateTime.UtcNow - found.LastValidatedUtc > TimeSpan.FromMinutes(GlobalSettings.TimeOutInMinutes))
|
||||
{
|
||||
//timeout detected, update the record
|
||||
ClearLoginSession(sessionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
//update the validate date
|
||||
found.LastValidatedUtc = DateTime.UtcNow;
|
||||
Database.Update(found);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int ClearLoginSessions(int userId)
|
||||
{
|
||||
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
|
||||
//and also business logic models for these objects but that's just so overkill for what we are doing
|
||||
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
|
||||
var count = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoUserLogin WHERE userId=@userId", new { userId = userId });
|
||||
Database.Execute("DELETE FROM umbracoUserLogin WHERE userId=@userId", new {userId = userId});
|
||||
return count;
|
||||
}
|
||||
|
||||
public int ClearLoginSessions(TimeSpan timespan)
|
||||
{
|
||||
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
|
||||
//and also business logic models for these objects but that's just so overkill for what we are doing
|
||||
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
|
||||
|
||||
var fromDate = DateTime.UtcNow - timespan;
|
||||
|
||||
var count = Database.ExecuteScalar<int>("SELECT COUNT(*) FROM umbracoUserLogin WHERE lastValidatedUtc=@fromDate", new { fromDate = fromDate });
|
||||
Database.Execute("DELETE FROM umbracoUserLogin WHERE lastValidatedUtc=@fromDate", new { fromDate = fromDate });
|
||||
return count;
|
||||
}
|
||||
|
||||
public void ClearLoginSession(Guid sessionId)
|
||||
{
|
||||
//TODO: I know this doesn't follow the normal repository conventions which would require us to crete a UserSessionRepository
|
||||
//and also business logic models for these objects but that's just so overkill for what we are doing
|
||||
//and now that everything is properly in a transaction (Scope) there doesn't seem to be much reason for using that anymore
|
||||
Database.Execute("UPDATE umbracoUserLogin SET loggedOutUtc=@now WHERE sessionId=@sessionId",
|
||||
new { now = DateTime.UtcNow, sessionId = sessionId });
|
||||
}
|
||||
|
||||
protected override IEnumerable<IUser> PerformGetAll(params int[] ids)
|
||||
{
|
||||
var dtos = ids.Length == 0
|
||||
@@ -429,7 +507,8 @@ ORDER BY colName";
|
||||
{"updateDate", "UpdateDate"},
|
||||
{"avatar", "Avatar"},
|
||||
{"emailConfirmedDate", "EmailConfirmedDate"},
|
||||
{"invitedDate", "InvitedDate"}
|
||||
{"invitedDate", "InvitedDate"},
|
||||
{"tourData", "TourData"}
|
||||
};
|
||||
|
||||
// create list of properties that have changed
|
||||
|
||||
@@ -373,6 +373,10 @@
|
||||
<Compile Include="Persistence\Mappers\AuditEntryMapper.cs" />
|
||||
<Compile Include="Persistence\Mappers\AuditMapper.cs" />
|
||||
<Compile Include="Persistence\Mappers\ConsentMapper.cs" />
|
||||
<Compile Include="Persistence\Repositories\IAuditEntryRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\IConsentRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\AuditEntryRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Implement\ConsentRepository.cs" />
|
||||
<Compile Include="PropertyEditors\ConfigurationEditorOfTConfiguration.cs" />
|
||||
<Compile Include="PropertyEditors\DataEditorAttribute.cs" />
|
||||
<Compile Include="PropertyEditors\ConfigurationEditor.cs" />
|
||||
|
||||
Reference in New Issue
Block a user