using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
public class PublicAccessService : ScopeRepositoryService, IPublicAccessService
{
public PublicAccessService(IScopeUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory)
: base(provider, logger, eventMessagesFactory)
{
}
///
/// Gets all defined entries and associated rules
///
///
public IEnumerable GetAll()
{
using (var uow = UowProvider.CreateUnitOfWork(readOnly: true))
{
var repo = uow.CreateRepository();
return repo.GetAll();
}
}
///
/// Gets the entry defined for the content item's path
///
///
/// Returns null if no entry is found
public PublicAccessEntry GetEntryForContent(IContent content)
{
return GetEntryForContent(content.Path.EnsureEndsWith("," + content.Id));
}
///
/// Gets the entry defined for the content item based on a content path
///
///
/// Returns null if no entry is found
///
/// NOTE: This method get's called *very* often! This will return the results from cache
///
public PublicAccessEntry GetEntryForContent(string contentPath)
{
//Get all ids in the path for the content item and ensure they all
// parse to ints that are not -1.
var ids = contentPath.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => int.TryParse(x, out int val) ? val : -1)
.Where(x => x != -1)
.ToList();
//start with the deepest id
ids.Reverse();
using (var uow = UowProvider.CreateUnitOfWork())
{
var repo = uow.CreateRepository();
//This will retrieve from cache!
var entries = repo.GetAll().ToArray();
uow.Complete();
foreach (var id in ids)
{
var found = entries.FirstOrDefault(x => x.ProtectedNodeId == id);
if (found != null) return found;
}
}
return null;
}
///
/// Returns true if the content has an entry for it's path
///
///
///
public Attempt IsProtected(IContent content)
{
var result = GetEntryForContent(content);
return Attempt.If(result != null, result);
}
///
/// Returns true if the content has an entry based on a content path
///
///
///
public Attempt IsProtected(string contentPath)
{
var result = GetEntryForContent(contentPath);
return Attempt.If(result != null, result);
}
///
/// Adds a rule
///
///
///
///
///
public Attempt> AddRule(IContent content, string ruleType, string ruleValue)
{
var evtMsgs = EventMessagesFactory.Get();
PublicAccessEntry entry;
using (var uow = UowProvider.CreateUnitOfWork())
{
var repo = uow.CreateRepository();
entry = repo.GetAll().FirstOrDefault(x => x.ProtectedNodeId == content.Id);
if (entry == null)
return OperationStatus.Attempt.Cannot(evtMsgs); // causes rollback
var existingRule = entry.Rules.FirstOrDefault(x => x.RuleType == ruleType && x.RuleValue == ruleValue);
if (existingRule == null)
{
entry.AddRule(ruleValue, ruleType);
}
else
{
//If they are both the same already then there's nothing to update, exit
return OperationStatus.Attempt.Succeed(evtMsgs, entry);
}
if (Saving.IsRaisedEventCancelled(new SaveEventArgs(entry, evtMsgs), this))
return OperationStatus.Attempt.Cancel(evtMsgs, entry); // causes rollback
repo.AddOrUpdate(entry);
uow.Complete();
}
Saved.RaiseEvent(new SaveEventArgs(entry, false, evtMsgs), this);
return OperationStatus.Attempt.Succeed(evtMsgs, entry);
}
///
/// Removes a rule
///
///
///
///
public Attempt RemoveRule(IContent content, string ruleType, string ruleValue)
{
var evtMsgs = EventMessagesFactory.Get();
PublicAccessEntry entry;
using (var uow = UowProvider.CreateUnitOfWork())
{
var repo = uow.CreateRepository();
entry = repo.GetAll().FirstOrDefault(x => x.ProtectedNodeId == content.Id);
if (entry == null) return Attempt.Fail(); // causes rollback
var existingRule = entry.Rules.FirstOrDefault(x => x.RuleType == ruleType && x.RuleValue == ruleValue);
if (existingRule == null) return Attempt.Fail(); // causes rollback
entry.RemoveRule(existingRule);
if (Saving.IsRaisedEventCancelled(new SaveEventArgs(entry, evtMsgs), this))
return OperationStatus.Attempt.Cancel(evtMsgs); // causes rollback
repo.AddOrUpdate(entry);
uow.Complete();
}
Saved.RaiseEvent(new SaveEventArgs(entry, false, evtMsgs), this);
return OperationStatus.Attempt.Succeed(evtMsgs);
}
///
/// Saves the entry
///
///
public Attempt Save(PublicAccessEntry entry)
{
var evtMsgs = EventMessagesFactory.Get();
if (Saving.IsRaisedEventCancelled(
new SaveEventArgs(entry, evtMsgs),
this))
{
return OperationStatus.Attempt.Cancel(evtMsgs);
}
using (var uow = UowProvider.CreateUnitOfWork())
{
var repo = uow.CreateRepository();
repo.AddOrUpdate(entry);
uow.Complete();
}
Saved.RaiseEvent(new SaveEventArgs(entry, false, evtMsgs), this);
return OperationStatus.Attempt.Succeed(evtMsgs);
}
///
/// Deletes the entry and all associated rules
///
///
public Attempt Delete(PublicAccessEntry entry)
{
var evtMsgs = EventMessagesFactory.Get();
if (Deleting.IsRaisedEventCancelled(
new DeleteEventArgs(entry, evtMsgs),
this))
{
return OperationStatus.Attempt.Cancel(evtMsgs);
}
using (var uow = UowProvider.CreateUnitOfWork())
{
var repo = uow.CreateRepository();
repo.Delete(entry);
uow.Complete();
}
Deleted.RaiseEvent(new DeleteEventArgs(entry, false, evtMsgs), this);
return OperationStatus.Attempt.Succeed(evtMsgs);
}
///
/// Occurs before Save
///
public static event TypedEventHandler> Saving;
///
/// Occurs after Save
///
public static event TypedEventHandler> Saved;
///
/// Occurs before Delete
///
public static event TypedEventHandler> Deleting;
///
/// Occurs after Delete
///
public static event TypedEventHandler> Deleted;
}
}