diff --git a/zero.Core/Api/BackofficeApi.cs b/zero.Core/Api/BackofficeApi.cs index f42dfe94..098e8a94 100644 --- a/zero.Core/Api/BackofficeApi.cs +++ b/zero.Core/Api/BackofficeApi.cs @@ -257,7 +257,7 @@ namespace zero.Core.Api /// - public async Task Purge(string querySuffix = null, Parameters parameters = null) + public async Task> Purge(string querySuffix = null, Parameters parameters = null) { var collectionName = Raven.Conventions.FindCollectionName(typeof(T)); @@ -270,6 +270,8 @@ namespace zero.Core.Api Operation operation = await Raven.Operations.SendAsync(operationQuery); await operation.WaitForCompletionAsync(TimeSpan.FromSeconds(30)); + + return EntityResult.Success(); } } @@ -306,7 +308,7 @@ namespace zero.Core.Api /// /// Delete a whole collection (with an optional query suffix, i.e. a where statement) /// - Task Purge(string querySuffix = null, Parameters parameters = null); + Task> Purge(string querySuffix = null, Parameters parameters = null); } diff --git a/zero.Core/Api/PagesApi.cs b/zero.Core/Api/PagesApi.cs index 5c9fc536..af0ca272 100644 --- a/zero.Core/Api/PagesApi.cs +++ b/zero.Core/Api/PagesApi.cs @@ -204,24 +204,64 @@ namespace zero.Core.Api /// public async Task> Restore(string id, bool includeDescendants = false) { - IRecycledEntity entity = await RecycleBinApi.GetById(id); + EntityResult result = new EntityResult(); + IRecycledEntity recycledEntity = await RecycleBinApi.GetById(id); + List entities = new List() { recycledEntity }; - if (entity == null || entity.Group != RECYCLE_BIN_GROUP || !(entity.Content is IPage)) + if (recycledEntity == null) { return EntityResult.Fail(); // TODO correct error message } - IPage page = entity.Content as IPage; - page.IsActive = false; - - EntityResult result = await SaveModel(page); - - if (includeDescendants && !entity.OperationId.IsNullOrEmpty()) + // get descendants from the operation + if (includeDescendants && !recycledEntity.OperationId.IsNullOrEmpty()) { - IList operationEntities = await RecycleBinApi.GetByOperation(entity.OperationId); + entities = (await RecycleBinApi.GetByOperation(recycledEntity.OperationId)).ToList(); } - return null; + // fill ids + string[] ids = entities.Select(x => x.OriginalId).ToArray(); + + // check if parents are available + string[] parentIds = entities.Select(x => x.Content as IPage).Where(x => x != null).Select(x => x.ParentId).ToArray(); + parentIds = (await GetByIds(parentIds)).Where(x => x.Value != null).Select(x => x.Value.Id).ToArray(); + + // validate and restore all items + foreach (IRecycledEntity entity in entities) + { + // check if it contains page data + if (entity.Group != RECYCLE_BIN_GROUP || !(entity.Content is IPage)) + { + //result.AddError("Cannot parse recycled entity as an IPage in group \"" + RECYCLE_BIN_GROUP + "\""); // TODO correct error message + continue; + } + + // get page + IPage page = entity.Content as IPage; + page.IsActive = false; + + // validate app and parent + if (!Scope.IsAllowed(page.AppId) || (!page.ParentId.IsNullOrEmpty() && !ids.Contains(page.ParentId) && !parentIds.Contains(page.ParentId))) + { + // TODO correct error message + continue; + } + + // restore to pages + EntityResult saveResult = await SaveModel(page); + } + + // delete affected entities from recycle bin + if (!recycledEntity.OperationId.IsNullOrEmpty()) + { + await RecycleBinApi.DeleteByOperation(recycledEntity.OperationId); + } + + // set result + result.Model = ids; + result.IsSuccess = true; + + return result; } diff --git a/zero.Core/Api/RecycleBinApi.cs b/zero.Core/Api/RecycleBinApi.cs index 8ccde758..0e21c311 100644 --- a/zero.Core/Api/RecycleBinApi.cs +++ b/zero.Core/Api/RecycleBinApi.cs @@ -107,31 +107,31 @@ namespace zero.Core.Api /// - public async Task Delete(string id) + public async Task> Delete(string id) { - await DeleteById(id); + return await DeleteById(id); } /// - public async Task DeleteAll() + public async Task> DeleteAll() { // TODO make Purge operations app-aware - await Purge(); + return await Purge(); } /// - public async Task DeleteByOperation(string operationId) + public async Task> DeleteByOperation(string operationId) { - await Purge("where c.OperationId = $id", new Raven.Client.Parameters() { { "id", operationId } }); + return await Purge("where c.OperationId = $id", new Raven.Client.Parameters() { { "id", operationId } }); } /// - public async Task DeleteByGroup(string group) + public async Task> DeleteByGroup(string group) { - await Purge("where c.Group = $group", new Raven.Client.Parameters() { { "group", group } }); + return await Purge("where c.Group = $group", new Raven.Client.Parameters() { { "group", group } }); } } @@ -170,21 +170,21 @@ namespace zero.Core.Api // /// Deletes a recycled entity by Id /// - Task Delete(string id); + Task> Delete(string id); /// /// Purges the recycle bin /// - Task DeleteAll(); + Task> DeleteAll(); /// /// Deletes all recycled items from a specific operation /// - Task DeleteByOperation(string operationId); + Task> DeleteByOperation(string operationId); /// /// Deletes all recycled items from a specific group /// - Task DeleteByGroup(string group); + Task> DeleteByGroup(string group); } } diff --git a/zero.Core/Entities/Pages/Page.cs b/zero.Core/Entities/Pages/Page.cs index 79f263db..dbc3e493 100644 --- a/zero.Core/Entities/Pages/Page.cs +++ b/zero.Core/Entities/Pages/Page.cs @@ -1,4 +1,5 @@ using System; +using zero.Core.Attributes; namespace zero.Core.Entities { @@ -25,6 +26,7 @@ namespace zero.Core.Entities } + [Collection("Pages")] public interface IPage : IZeroEntity, IAppAwareEntity, IZeroDbConventions { /// diff --git a/zero.Core/Extensions/ObjectExtensions.cs b/zero.Core/Extensions/ObjectExtensions.cs index 3a55baa8..4ed05921 100644 --- a/zero.Core/Extensions/ObjectExtensions.cs +++ b/zero.Core/Extensions/ObjectExtensions.cs @@ -19,7 +19,8 @@ namespace zero.Core.Extensions public static T Clone(this T obj) { - return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj)); + Type type = obj.GetType(); + return (T)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj), type); } } } diff --git a/zero.Debug/Controllers/TestController.cs b/zero.Debug/Controllers/TestController.cs index eb71c8b7..30be5b1a 100644 --- a/zero.Debug/Controllers/TestController.cs +++ b/zero.Debug/Controllers/TestController.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading.Tasks; using zero.Core.Api; using zero.Core.Entities; +using zero.Core.Extensions; using zero.Core.Utils; namespace zero.Debug.Controllers @@ -65,7 +66,16 @@ namespace zero.Debug.Controllers } - + + [HttpGet] + public IActionResult Clone([FromServices] IRecycledEntity blueprint) + { + IRecycledEntity entity = blueprint.Clone(); + return Json(entity); + } + + + [HttpGet] public IActionResult Routes() diff --git a/zero.Web.UI/App/pages/pages/recyclebin-actions.vue b/zero.Web.UI/App/pages/pages/recyclebin-actions.vue index 0e241e71..21777f00 100644 --- a/zero.Web.UI/App/pages/pages/recyclebin-actions.vue +++ b/zero.Web.UI/App/pages/pages/recyclebin-actions.vue @@ -7,7 +7,7 @@ - -