Implements the auth token retrieval and storage for the identity implementation. This is now automatically done for providers and the back office user manager can be used to retreive and store all tokens. Fixes locking on the config writer. Removes the abstract NodeObjectTypeId from the base repo since it shouldn't be there.
284 lines
12 KiB
C#
284 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Microsoft.Extensions.Logging;
|
|
using NPoco;
|
|
using Umbraco.Cms.Core.Cache;
|
|
using Umbraco.Cms.Core.Models;
|
|
using Umbraco.Cms.Core.Persistence.Querying;
|
|
using Umbraco.Cms.Core.Persistence.Repositories;
|
|
using Umbraco.Cms.Core.Scoping;
|
|
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
|
|
using Umbraco.Extensions;
|
|
|
|
namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
|
|
{
|
|
/// <summary>
|
|
/// An internal repository for managing entity containers such as doc type, media type, data type containers.
|
|
/// </summary>
|
|
internal class EntityContainerRepository : EntityRepositoryBase<int, EntityContainer>, IEntityContainerRepository
|
|
{
|
|
private readonly Guid _containerObjectType;
|
|
|
|
public EntityContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger<EntityContainerRepository> logger, Guid containerObjectType)
|
|
: base(scopeAccessor, cache, logger)
|
|
{
|
|
var allowedContainers = new[] { Cms.Core.Constants.ObjectTypes.DocumentTypeContainer, Cms.Core.Constants.ObjectTypes.MediaTypeContainer, Cms.Core.Constants.ObjectTypes.DataTypeContainer };
|
|
_containerObjectType = containerObjectType;
|
|
if (allowedContainers.Contains(_containerObjectType) == false)
|
|
throw new InvalidOperationException("No container type exists with ID: " + _containerObjectType);
|
|
}
|
|
|
|
// never cache
|
|
protected override IRepositoryCachePolicy<EntityContainer, int> CreateCachePolicy()
|
|
{
|
|
return NoCacheRepositoryCachePolicy<EntityContainer, int>.Instance;
|
|
}
|
|
|
|
protected override EntityContainer PerformGet(int id)
|
|
{
|
|
var sql = GetBaseQuery(false).Where(GetBaseWhereClause(), new { id = id, NodeObjectType = NodeObjectTypeId });
|
|
|
|
var nodeDto = Database.Fetch<NodeDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
|
|
return nodeDto == null ? null : CreateEntity(nodeDto);
|
|
}
|
|
|
|
// temp - so we don't have to implement GetByQuery
|
|
public EntityContainer Get(Guid id)
|
|
{
|
|
var sql = GetBaseQuery(false).Where("UniqueId=@uniqueId", new { uniqueId = id });
|
|
|
|
var nodeDto = Database.Fetch<NodeDto>(sql).FirstOrDefault();
|
|
return nodeDto == null ? null : CreateEntity(nodeDto);
|
|
}
|
|
|
|
public IEnumerable<EntityContainer> Get(string name, int level)
|
|
{
|
|
var sql = GetBaseQuery(false).Where("text=@name AND level=@level AND nodeObjectType=@umbracoObjectTypeId", new { name, level, umbracoObjectTypeId = NodeObjectTypeId });
|
|
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
|
|
}
|
|
|
|
protected override IEnumerable<EntityContainer> PerformGetAll(params int[] ids)
|
|
{
|
|
if (ids.Any())
|
|
{
|
|
return Database.FetchByGroups<NodeDto, int>(ids, 2000, batch =>
|
|
GetBaseQuery(false)
|
|
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId)
|
|
.WhereIn<NodeDto>(x => x.NodeId, batch))
|
|
.Select(CreateEntity);
|
|
}
|
|
|
|
// else
|
|
|
|
var sql = GetBaseQuery(false)
|
|
.Where("nodeObjectType=@umbracoObjectTypeId", new { umbracoObjectTypeId = NodeObjectTypeId })
|
|
.OrderBy<NodeDto>(x => x.Level);
|
|
|
|
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
|
|
}
|
|
|
|
protected override IEnumerable<EntityContainer> PerformGetByQuery(IQuery<EntityContainer> query)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
private static EntityContainer CreateEntity(NodeDto nodeDto)
|
|
{
|
|
if (nodeDto.NodeObjectType.HasValue == false)
|
|
throw new InvalidOperationException("Node with id " + nodeDto.NodeId + " has no object type.");
|
|
|
|
// throws if node is not a container
|
|
var containedObjectType = EntityContainer.GetContainedObjectType(nodeDto.NodeObjectType.Value);
|
|
|
|
var entity = new EntityContainer(nodeDto.NodeId, nodeDto.UniqueId,
|
|
nodeDto.ParentId, nodeDto.Path, nodeDto.Level, nodeDto.SortOrder,
|
|
containedObjectType,
|
|
nodeDto.Text, nodeDto.UserId ?? Cms.Core.Constants.Security.UnknownUserId);
|
|
|
|
// reset dirty initial properties (U4-1946)
|
|
entity.ResetDirtyProperties(false);
|
|
|
|
return entity;
|
|
}
|
|
|
|
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
|
|
{
|
|
var sql = Sql();
|
|
if (isCount)
|
|
sql.SelectCount();
|
|
else
|
|
sql.SelectAll();
|
|
sql.From<NodeDto>();
|
|
return sql;
|
|
}
|
|
|
|
protected override string GetBaseWhereClause() => "umbracoNode.id = @id and nodeObjectType = @NodeObjectType";
|
|
|
|
protected override IEnumerable<string> GetDeleteClauses() => throw new NotImplementedException();
|
|
|
|
protected Guid NodeObjectTypeId => _containerObjectType;
|
|
|
|
protected override void PersistDeletedItem(EntityContainer entity)
|
|
{
|
|
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
|
EnsureContainerType(entity);
|
|
|
|
var nodeDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where<NodeDto>(dto => dto.NodeId == entity.Id && dto.NodeObjectType == entity.ContainerObjectType));
|
|
|
|
if (nodeDto == null) return;
|
|
|
|
// move children to the parent so they are not orphans
|
|
var childDtos = Database.Fetch<NodeDto>(Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where("parentID=@parentID AND (nodeObjectType=@containedObjectType OR nodeObjectType=@containerObjectType)",
|
|
new
|
|
{
|
|
parentID = entity.Id,
|
|
containedObjectType = entity.ContainedObjectType,
|
|
containerObjectType = entity.ContainerObjectType
|
|
}));
|
|
|
|
foreach (var childDto in childDtos)
|
|
{
|
|
childDto.ParentId = nodeDto.ParentId;
|
|
Database.Update(childDto);
|
|
}
|
|
|
|
// delete
|
|
Database.Delete(nodeDto);
|
|
|
|
entity.DeleteDate = DateTime.Now;
|
|
}
|
|
|
|
protected override void PersistNewItem(EntityContainer entity)
|
|
{
|
|
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
|
EnsureContainerType(entity);
|
|
|
|
if (entity.Name == null) throw new InvalidOperationException("Entity name can't be null.");
|
|
if (string.IsNullOrWhiteSpace(entity.Name)) throw new InvalidOperationException("Entity name can't be empty or consist only of white-space characters.");
|
|
entity.Name = entity.Name.Trim();
|
|
|
|
// guard against duplicates
|
|
var nodeDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where<NodeDto>(dto => dto.ParentId == entity.ParentId && dto.Text == entity.Name && dto.NodeObjectType == entity.ContainerObjectType));
|
|
if (nodeDto != null)
|
|
throw new InvalidOperationException("A container with the same name already exists.");
|
|
|
|
// create
|
|
var level = 0;
|
|
var path = "-1";
|
|
if (entity.ParentId > -1)
|
|
{
|
|
var parentDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where<NodeDto>(dto => dto.NodeId == entity.ParentId && dto.NodeObjectType == entity.ContainerObjectType));
|
|
|
|
if (parentDto == null)
|
|
throw new InvalidOperationException("Could not find parent container with id " + entity.ParentId);
|
|
|
|
level = parentDto.Level;
|
|
path = parentDto.Path;
|
|
}
|
|
|
|
// note: sortOrder is NOT managed and always zero for containers
|
|
|
|
nodeDto = new NodeDto
|
|
{
|
|
CreateDate = DateTime.Now,
|
|
Level = Convert.ToInt16(level + 1),
|
|
NodeObjectType = entity.ContainerObjectType,
|
|
ParentId = entity.ParentId,
|
|
Path = path,
|
|
SortOrder = 0,
|
|
Text = entity.Name,
|
|
UserId = entity.CreatorId,
|
|
UniqueId = entity.Key
|
|
};
|
|
|
|
// insert, get the id, update the path with the id
|
|
var id = Convert.ToInt32(Database.Insert(nodeDto));
|
|
nodeDto.Path = nodeDto.Path + "," + nodeDto.NodeId;
|
|
Database.Save<NodeDto>(nodeDto);
|
|
|
|
// refresh the entity
|
|
entity.Id = id;
|
|
entity.Path = nodeDto.Path;
|
|
entity.Level = nodeDto.Level;
|
|
entity.SortOrder = 0;
|
|
entity.CreateDate = nodeDto.CreateDate;
|
|
entity.ResetDirtyProperties();
|
|
}
|
|
|
|
// beware! does NOT manage descendants in case of a new parent
|
|
//
|
|
protected override void PersistUpdatedItem(EntityContainer entity)
|
|
{
|
|
if (entity == null) throw new ArgumentNullException(nameof(entity));
|
|
EnsureContainerType(entity);
|
|
|
|
if (entity.Name == null) throw new InvalidOperationException("Entity name can't be null.");
|
|
if (string.IsNullOrWhiteSpace(entity.Name)) throw new InvalidOperationException("Entity name can't be empty or consist only of white-space characters.");
|
|
entity.Name = entity.Name.Trim();
|
|
|
|
// find container to update
|
|
var nodeDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where<NodeDto>(dto => dto.NodeId == entity.Id && dto.NodeObjectType == entity.ContainerObjectType));
|
|
if (nodeDto == null)
|
|
throw new InvalidOperationException("Could not find container with id " + entity.Id);
|
|
|
|
// guard against duplicates
|
|
var dupNodeDto = Database.FirstOrDefault<NodeDto>(Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where<NodeDto>(dto => dto.ParentId == entity.ParentId && dto.Text == entity.Name && dto.NodeObjectType == entity.ContainerObjectType));
|
|
if (dupNodeDto != null && dupNodeDto.NodeId != nodeDto.NodeId)
|
|
throw new InvalidOperationException("A container with the same name already exists.");
|
|
|
|
// update
|
|
nodeDto.Text = entity.Name;
|
|
if (nodeDto.ParentId != entity.ParentId)
|
|
{
|
|
nodeDto.Level = 0;
|
|
nodeDto.Path = "-1";
|
|
if (entity.ParentId > -1)
|
|
{
|
|
var parent = Database.FirstOrDefault<NodeDto>( Sql().SelectAll()
|
|
.From<NodeDto>()
|
|
.Where<NodeDto>(dto => dto.NodeId == entity.ParentId && dto.NodeObjectType == entity.ContainerObjectType));
|
|
|
|
if (parent == null)
|
|
throw new InvalidOperationException("Could not find parent container with id " + entity.ParentId);
|
|
|
|
nodeDto.Level = Convert.ToInt16(parent.Level + 1);
|
|
nodeDto.Path = parent.Path + "," + nodeDto.NodeId;
|
|
}
|
|
nodeDto.ParentId = entity.ParentId;
|
|
}
|
|
|
|
// note: sortOrder is NOT managed and always zero for containers
|
|
|
|
// update
|
|
Database.Update(nodeDto);
|
|
|
|
// refresh the entity
|
|
entity.Path = nodeDto.Path;
|
|
entity.Level = nodeDto.Level;
|
|
entity.SortOrder = 0;
|
|
entity.ResetDirtyProperties();
|
|
}
|
|
|
|
private void EnsureContainerType(EntityContainer entity)
|
|
{
|
|
if (entity.ContainerObjectType != NodeObjectTypeId)
|
|
{
|
|
throw new InvalidOperationException("The container type does not match the repository object type");
|
|
}
|
|
}
|
|
}
|
|
}
|