using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Umbraco.Core.Auditing;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
///
/// Represents the Media Service, which is an easy access to operations involving
///
public class MediaService : IMediaService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IMediaRepository _mediaRepository;
private readonly IMediaTypeRepository _mediaTypeRepository;
private readonly IUserService _userService;
private HttpContextBase _httpContext;
public MediaService() : this(new PetaPocoUnitOfWorkProvider())
{
}
public MediaService(IUnitOfWorkProvider provider)
{
_unitOfWork = provider.GetUnitOfWork();
_mediaRepository = RepositoryResolver.Current.Factory.CreateMediaRepository(_unitOfWork);
_mediaTypeRepository = RepositoryResolver.Current.Factory.CreateMediaTypeRepository(_unitOfWork);
}
internal MediaService(IUnitOfWorkProvider provider, IUserService userService)
{
_unitOfWork = provider.GetUnitOfWork();
_mediaRepository = RepositoryResolver.Current.Factory.CreateMediaRepository(_unitOfWork);
_mediaTypeRepository = RepositoryResolver.Current.Factory.CreateMediaTypeRepository(_unitOfWork);
_userService = userService;
}
///
/// Creates an object using the alias of the
/// that this Media is based on.
///
/// Id of Parent for the new Media item
/// Alias of the
/// Optional id of the user creating the media item
///
public IMedia CreateContent(int parentId, string mediaTypeAlias, int userId = -1)
{
var repository = _mediaTypeRepository;
var query = Query.Builder.Where(x => x.Alias == mediaTypeAlias);
var mediaTypes = repository.GetByQuery(query);
if (!mediaTypes.Any())
throw new Exception(string.Format("No ContentType matching the passed in Alias: '{0}' was found", mediaTypeAlias));
var contentType = mediaTypes.First();
if (contentType == null)
throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null", mediaTypeAlias));
IMedia media = null;
var e = new NewEventArgs { Alias = mediaTypeAlias, ParentId = parentId };
if (Creating != null)
Creating(media, e);
if (!e.Cancel)
{
media = new Models.Media(parentId, contentType);
SetUser(media, userId);
if (Created != null)
Created(media, e);
Audit.Add(AuditTypes.New, "", media.CreatorId, media.Id);
}
return media;
}
///
/// Gets an object by Id
///
/// Id of the Content to retrieve
///
public IMedia GetById(int id)
{
var repository = _mediaRepository;
return repository.Get(id);
}
///
/// Gets a collection of objects by Parent Id
///
/// Id of the Parent to retrieve Children from
/// An Enumerable list of objects
public IEnumerable GetChildren(int id)
{
var repository = _mediaRepository;
var query = Query.Builder.Where(x => x.ParentId == id);
var medias = repository.GetByQuery(query);
return medias;
}
///
/// Gets descendants of a object by its Id
///
/// Id of the Parent to retrieve descendants from
/// An Enumerable flat list of objects
public IEnumerable GetDescendants(int id)
{
var repository = _mediaRepository;
var media = repository.Get(id);
var query = Query.Builder.Where(x => x.Path.StartsWith(media.Path));
var medias = repository.GetByQuery(query);
return medias;
}
///
/// Gets a collection of objects by the Id of the
///
/// Id of the
/// An Enumerable list of objects
public IEnumerable GetMediaOfMediaType(int id)
{
var repository = _mediaRepository;
var query = Query.Builder.Where(x => x.ContentTypeId == id);
var medias = repository.GetByQuery(query);
return medias;
}
///
/// Gets a collection of objects, which reside at the first level / root
///
/// An Enumerable list of objects
public IEnumerable GetRootMedia()
{
var repository = _mediaRepository;
var query = Query.Builder.Where(x => x.ParentId == -1);
var medias = repository.GetByQuery(query);
return medias;
}
///
/// Gets a collection of an objects, which resides in the Recycle Bin
///
/// An Enumerable list of objects
public IEnumerable GetMediaInRecycleBin()
{
var repository = _mediaRepository;
var query = Query.Builder.Where(x => x.ParentId == -20);
var medias = repository.GetByQuery(query);
return medias;
}
///
/// Moves an object to a new location
///
/// The to move
/// Id of the Media's new Parent
/// Id of the User moving the Media
public void Move(IMedia media, int parentId, int userId = -1)
{
var e = new MoveEventArgs { ParentId = parentId };
if (Moving != null)
Moving(media, e);
if (!e.Cancel)
{
media.ParentId = parentId;
Save(media, userId);
if (Moved != null)
Moved(media, e);
Audit.Add(AuditTypes.Move, "Move Media performed by user", userId == -1 ? 0 : userId, media.Id);
}
}
///
/// Deletes an object by moving it to the Recycle Bin
///
/// The to delete
/// Id of the User deleting the Media
public void MoveToRecycleBin(IMedia media, int userId = -1)
{
//TODO If media item has children those should also be moved to the recycle bin as well
var e = new MoveEventArgs { ParentId = -20 };
if (Trashing != null)
Trashing(media, e);
if (!e.Cancel)
{
var repository = _mediaRepository;
((Core.Models.Media) media).ChangeTrashedState(true);
repository.AddOrUpdate(media);
_unitOfWork.Commit();
if (Trashed != null)
Trashed(media, e);
Audit.Add(AuditTypes.Move, "Move Media to Recycle Bin performed by user", userId == -1 ? 0 : userId, media.Id);
}
}
///
/// Empties the Recycle Bin by deleting all that resides in the bin
///
public void EmptyRecycleBin()
{
var repository = _mediaRepository;
var query = Query.Builder.Where(x => x.ParentId == -20);
var contents = repository.GetByQuery(query);
foreach (var content in contents)
{
repository.Delete(content);
}
_unitOfWork.Commit();
Audit.Add(AuditTypes.Delete, "Empty Recycle Bin performed by user", 0, -20);
}
///
/// Deletes all media of specified type. All children of deleted media is moved to Recycle Bin.
///
/// This needs extra care and attention as its potentially a dangerous and extensive operation
/// Id of the
/// Optional id of the user deleting the media
public void DeleteMediaOfType(int mediaTypeId, int userId = -1)
{
var repository = _mediaRepository;
//NOTE What about media that has the contenttype as part of its composition?
//The ContentType has to be removed from the composition somehow as it would otherwise break
//Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table
var query = Query.Builder.Where(x => x.ContentTypeId == mediaTypeId);
var contents = repository.GetByQuery(query);
var e = new DeleteEventArgs { Id = mediaTypeId };
if (Deleting != null)
Deleting(contents, e);
if (!e.Cancel)
{
foreach (var content in contents)
{
((Core.Models.Media) content).ChangeTrashedState(true);
repository.AddOrUpdate(content);
}
_unitOfWork.Commit();
if (Deleted != null)
Deleted(contents, e);
Audit.Add(AuditTypes.Delete, "Delete Media items by Type performed by user", userId == -1 ? 0 : userId, -1);
}
}
///
/// Permanently deletes an object
///
///
/// Please note that this method will completely remove the Media from the database,
/// but current not from the file system.
///
/// The to delete
/// Id of the User deleting the Media
public void Delete(IMedia media, int userId = -1)
{
var e = new DeleteEventArgs { Id = media.Id };
if (Deleting != null)
Deleting(media, e);
if (!e.Cancel)
{
_mediaRepository.Delete(media);
_unitOfWork.Commit();
if (Deleted != null)
Deleted(media, e);
Audit.Add(AuditTypes.Delete, "Delete Media performed by user", userId == -1 ? 0 : userId, media.Id);
}
}
///
/// Saves a single object
///
/// The to save
/// Id of the User saving the Content
public void Save(IMedia media, int userId = -1)
{
var e = new SaveEventArgs();
if (Saving != null)
Saving(media, e);
if (!e.Cancel)
{
SetUser(media, userId);
_mediaRepository.AddOrUpdate(media);
_unitOfWork.Commit();
if (Saved != null)
Saved(media, e);
Audit.Add(AuditTypes.Save, "Save Media performed by user", media.CreatorId, media.Id);
}
}
///
/// Saves a collection of objects
///
/// Collection of to save
/// Id of the User saving the Content
public void Save(IEnumerable medias, int userId = -1)
{
var e = new SaveEventArgs();
if (Saving != null)
Saving(medias, e);
if (!e.Cancel)
{
foreach (var media in medias)
{
SetUser(media, userId);
_mediaRepository.AddOrUpdate(media);
}
_unitOfWork.Commit();
if (Saved != null)
Saved(medias, e);
Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId == -1 ? 0 : userId, -1);
}
}
///
/// Internal method to set the HttpContextBase for testing.
///
///
internal void SetHttpContext(HttpContextBase httpContext)
{
_httpContext = httpContext;
}
///
/// Updates a media object with the User (id), who created the content.
///
/// object to update
/// Optional Id of the User
private void SetUser(IMedia media, int userId)
{
if (userId > -1)
{
//If a user id was passed in we use that
media.CreatorId = userId;
}
else if (UserServiceOrContext())
{
var profile = _httpContext == null
? _userService.GetCurrentBackOfficeUser()
: _userService.GetCurrentBackOfficeUser(_httpContext);
media.CreatorId = profile.Id.SafeCast();
}
else
{
//Otherwise we default to Admin user, which should always exist (almost always)
media.CreatorId = 0;
}
}
private bool UserServiceOrContext()
{
return _userService != null && (HttpContext.Current != null || _httpContext != null);
}
#region Event Handlers
///
/// Occurs before Delete
///
public static event EventHandler Deleting;
///
/// Occurs after Delete
///
public static event EventHandler Deleted;
///
/// Occurs before Save
///
public static event EventHandler Saving;
///
/// Occurs after Save
///
public static event EventHandler Saved;
///
/// Occurs before Create
///
public static event EventHandler Creating;
///
/// Occurs after Create
///
public static event EventHandler Created;
///
/// Occurs before Content is moved to Recycle Bin
///
public static event EventHandler Trashing;
///
/// Occurs after Content is moved to Recycle Bin
///
public static event EventHandler Trashed;
///
/// Occurs before Move
///
public static event EventHandler Moving;
///
/// Occurs after Move
///
public static event EventHandler Moved;
#endregion
}
}