using FluentValidation; using FluentValidation.Results; using Raven.Client.Documents; using Raven.Client.Documents.Linq; using Raven.Client.Documents.Session; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using zero.Core.Attributes; using zero.Core.Entities; using zero.Core.Extensions; using zero.Core.Utils; namespace zero.Core.Api { public class BackofficeStore : IBackofficeStore { public bool IsAppAware => this.Is(); public string AppId { get; protected set; } public IDocumentStore Raven { get; private set; } IMediaUpload Media { get; set; } protected string[] CurrentAppIds { get => GetAppIds(); } const string NEW_ID = "new:"; public BackofficeStore(IDocumentStore raven, IMediaUpload media) { Raven = raven; Media = media; } /// public async Task GetById(string id) where T : IZeroIdEntity { using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) { if (typeof(T).Is()) { return await session.Query() .Where(x => x.Id == id) .ForApp(AppId, true) .FirstOrDefaultAsync(); } return await session.LoadAsync(id); } } /// public async Task> Save(T model, IValidator validator = null) where T : IZeroIdEntity { // check for alias //if (model is IUrlAliasEntity) //{ // IUrlAliasEntity entity = operation.Model as IUrlAliasEntity; // entity.Alias = entity.Alias?.ToLower().ToUrlSegment(); //} // get specifics IAppAwareEntity appAwareEntity = model as IAppAwareEntity; IZeroEntity zeroEntity = model as IZeroEntity; // run validator if (validator != null) { ValidationResult validation = await validator.ValidateAsync(model); if (!validation.IsValid) { return EntityResult.Fail(validation); } } // check if current app id is valid if (!model.Id.IsNullOrEmpty() && IsAppAware && appAwareEntity != null) { if (!CurrentAppIds.Contains(appAwareEntity.AppId)) { return EntityResult.Fail("@errors.onsave.notallowed"); } } // find all media items in model //List> media = ObjectTraverser.Find(model); // upload media items //Dictionary mediaItems = new Dictionary(); //foreach (ObjectTraverser.Result item in media) //{ // string id = item.Item?.Id; // if (!Media.Upload(item.Item, out bool uploaded, out string uploadError)) // { // return EntityResult.Fail(item.Path, uploadError); // } // else // { // mediaItems.Add(id, item.Item); // } //} //if (operation.Media != null) //{ // operation.Media?.Invoke(operation.Model, mediaItems); //} // find all Raven Ids List> ravenIds = ObjectTraverser.FindAttribute(model); // set unset Raven Ids foreach (ObjectTraverser.Result item in ravenIds) { string id = item.Property.GetValue(item.Parent, null) as string; if (String.IsNullOrWhiteSpace(id) || id.StartsWith(NEW_ID)) { item.Property.SetValue(item.Parent, item.Item.Length.HasValue ? Raven.Id(item.Item.Length.Value) : Raven.Id()); } } // set default properties if (model.Id.IsNullOrEmpty()) { if (zeroEntity != null) { zeroEntity.CreatedDate = DateTimeOffset.Now; } if (appAwareEntity != null) { appAwareEntity.AppId = "zero.applications.1-A"; // Constants.Database.SharedAppId; // TODO correct app id } if (model is ILanguageAwareEntity) { (model as ILanguageAwareEntity).LanguageId = "zero.languages.1-A"; // TODO correct language id } } // update name alias if (zeroEntity != null) { zeroEntity.Alias = Alias.Generate(zeroEntity.Name); } using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) { // store entity await session.StoreAsync(model); // store media await session.SaveChangesAsync(); } return EntityResult.Success(model); } /// public async Task> DeleteById(string id) where T : IZeroIdEntity { using (IAsyncDocumentSession session = Raven.OpenAsyncSession()) { T entity = await session.LoadAsync(id); IAppAwareEntity appAwareEntity = entity as IAppAwareEntity; if (entity == null) { return EntityResult.Fail("@errors.ondelete.idnotfound"); } if (IsAppAware && appAwareEntity != null && !CurrentAppIds.Contains(appAwareEntity.AppId)) { return EntityResult.Fail("@errors.ondelete.idnotfound"); } session.Delete(entity); await session.SaveChangesAsync(); return EntityResult.Success(); } } /// /// Get current app id + shared id /// string[] GetAppIds() { return new string[2] { AppId, Constants.Database.SharedAppId }; } } public interface IBackofficeStore { IDocumentStore Raven { get; } bool IsAppAware { get; } string AppId { get; } /// /// Get an entity by Id. /// If the requested entity is an IAppAwareEntity it will only return entities for the currently selected app + shared app /// Task GetById(string id) where T : IZeroIdEntity; /// /// Updates or creates an entity with an optional validator /// Task> Save(T model, IValidator validator = null) where T : IZeroIdEntity; /// /// Deletes an entity by Id /// Task> DeleteById(string id) where T : IZeroIdEntity; } public interface IAppAwareBackofficeStore : IBackofficeStore { } public class AppAwareBackofficeStore : BackofficeStore, IAppAwareBackofficeStore { public AppAwareBackofficeStore(IDocumentStore raven, IMediaUpload media) : base(raven, media) { AppId = "zero.applications.1-A"; // TODO } } }