public async Task <IActionResult> GetEntityList(string type, [FromQuery(Name = "$filter")] string filter, [FromQuery] PaginationRequest request, [FromQuery(Name = "$projection"), ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable <string> fields) { Log.Information($"Getting entities fields '{string.Join(",", fields ?? new[] { "all" }) }' from collection '{type}' for userId '{UserId}' with filter: \"{filter}\""); BsonDocument filterDocument = null; try { filterDocument = new OrganizeFilter(UserId.Value).ByQueryString(filter); } catch (Exception e) { Log.Error($"Filter error '{filter}' {e}"); return(BadRequest()); } var result = await Database.GetCollection <BsonDocument>(type.ToPascalCase()) .Find(filterDocument) .Project <dynamic>(fields?.ToMongoDBProjection()) .ToPagedListAsync(request.PageNumber, request.PageSize); this.AddPaginationHeader(request, result, nameof(GetEntityList), null, filter, fields); return(Ok(result)); }
public async Task <IActionResult> Get(Guid id, [FromQuery(Name = "$projection"), ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable <string> fields) { Log.Information($"Getting node {id}"); var filter = new OrganizeFilter().ById(id); if (fields is null) { fields = Array.Empty <string>(); } var node = await GetNodeAggregation(filter).Project <dynamic>(fields?.ToMongoDBProjection()).FirstOrDefaultAsync(); if (node is null) { Log.Information($"Node {id} not found."); return(NotFound()); } var breadcrumbs = _dataProvider.GetBreadcrumbs(id).Reverse(); breadcrumbs.AsParallel() .ForAll(p => p.Name = WebUtility.UrlEncode(p.Name)?.Replace("+", "%20")); Response.Headers["Access-Control-Expose-Headers"] += breadcrumbsHeaderName; Response.Headers.Add(breadcrumbsHeaderName, JsonConvert.SerializeObject(breadcrumbs)); return(Ok(node)); }
public async Task <IActionResult> DeleteAll() { BsonDocument filter = new OrganizeFilter(UserId.Value); var notifications = await Database.GetCollection <dynamic>("UserNotifications").Find(filter).ToListAsync(); notifications.AsParallel() .ForAll(n => _bus.Publish <DeleteUserNotification>(new { Id = n._id }).Wait()); return(Accepted()); }
public async Task <IActionResult> GetEntitiesPublic(string type, [FromQuery(Name = "$filter")] string filter, [FromQuery] PaginationRequest request, [FromQuery(Name = "$projection"), ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable <string> fields) { //IMongoCollection<BsonDocument> collection = null; type = type.ToPascalCase(); var foreignKeyForLookup = ""; switch (type) { case "Records": foreignKeyForLookup = "FileId"; break; case "Files": foreignKeyForLookup = "_id"; break; case "Folders": foreignKeyForLookup = "_id"; break; case "Models": foreignKeyForLookup = "_id"; break; } if (string.IsNullOrEmpty(type)) { return(BadRequest()); } BsonDocument filterDocument = null; try { filterDocument = new OrganizeFilter().ByQueryString(filter); } catch { Log.Error($"Filter syntax error '{filter}'"); return(BadRequest()); } var projection = fields.ToMongoDBProjection(); var aggregation = _accessPermissions.Aggregate() .Match(new BsonDocument("IsPublic", true)) .Lookup(type, "_id", foreignKeyForLookup, "Parents") .Unwind("Parents") .ReplaceRoot(new BsonValueAggregateExpressionDefinition <BsonDocument, BsonDocument>("$Parents")) .Match(filterDocument) .Project <dynamic>(projection); var list = await aggregation.ToPagedListAsync(request.PageNumber, request.PageSize); this.AddPaginationHeader(request, list, nameof(GetEntitiesPublic), null, filter, fields); return(Ok(list)); }
public async Task <IActionResult> UpdateRecord(Guid id, int version, [FromBody] JsonPatchDocument <dynamic> request) { BsonDocument filter = new OrganizeFilter(UserId.Value).ById(id); var record = await Database.GetCollection <dynamic>("Records").Aggregate().Match(filter) .Lookup <BsonDocument, BsonDocument>(nameof(AccessPermissions), "_id", "_id", nameof(AccessPermissions)) .Unwind(nameof(AccessPermissions), new AggregateUnwindOptions <BsonDocument> { PreserveNullAndEmptyArrays = true }) .Project <dynamic>("{AccessPermissions:1, Properties:1}") .FirstOrDefaultAsync(); if (record is null) { return(NotFound()); } if (!((IDictionary <string, object>)record).ContainsKey("Permissions")) { ((IDictionary <string, object>)record).Add("Permissions", new AccessPermissions { Users = new HashSet <Guid>(), Groups = new HashSet <Guid>() }); } request.ApplyTo(record); if (request.Operations.Select(o => o.path).Any(p => p.Equals("/Properties/Fields"))) { await _bus.Publish <UpdateFields>(new { Id = id, UserId, ExpectedVersion = version, record.Properties.Fields }); } if (request.Operations.Any(o => o.path.Contains("/Permissions"))) { Log.Information($"Grant access to folder {id}"); await _bus.Publish <RecordsFile.Domain.Commands.Records.SetAccessPermissions>(new { Id = id, UserId, record.Permissions }); } return(AcceptedAtRoute("GetSingleEntity", new { type = "records", id = id }, null)); }
public async Task <IActionResult> GetList([FromQuery] PaginationRequest request, [FromQuery] bool unreadOnly = true) { BsonDocument filter = new OrganizeFilter(UserId.Value); if (unreadOnly) { filter.Add("IsRead", new BsonDocument("$ne", true)); } var notifications = await Database.GetCollection <dynamic>("UserNotifications").Find(filter).Sort("{TimeStamp:-1}").ToPagedListAsync(request.PageNumber, request.PageSize); this.AddPaginationHeader(request, notifications, "GetUserNotifications"); return(Ok(notifications)); }
public async Task <IActionResult> GetById(Guid id) { var filter = new OrganizeFilter().ById(id); var user = await _users.Find(new BsonDocument("_id", id)).FirstOrDefaultAsync(); if (user is null) { Log.Error($"User {id} not found"); return(NotFound()); } else if (((IDictionary <String, Object>)user)["_id"].ToString() != UserId.ToString()) { return(Forbid()); } ((IDictionary <string, object>)user).Remove("_id"); ((IDictionary <string, object>)user)["id"] = id; return(Ok(user)); }
public async Task <IActionResult> Get(string type, Guid id, [FromQuery(Name = "$projection"), ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable <string> fields) { if (!acceptableEntitites.Contains(type.ToLower())) { return(BadRequest("Unacceptable entity type")); } Log.Information($"Getting entity '{id}' from collection '{type}'"); BsonDocument filter = new OrganizeFilter().ById(id); var result = await Database.GetCollection <dynamic>(type.ToPascalCase()).Aggregate() .Match(filter) .Project <dynamic>((fields ?? new string[] { }).ToMongoDBProjection()) .FirstOrDefaultAsync(); if (result is null) { return(NotFound()); } return(Ok(result)); }
private async Task <Responses.PagedList <dynamic> > GetNodesPagedList(Guid parentId, string types, PaginationRequest request, string status) { BsonDocument filter = new OrganizeFilter().ByParent(parentId); if (status != null) { filter.Add("Status", status); } if (!string.IsNullOrEmpty(types)) { var bsonArray = new BsonArray(); foreach (var type in types.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) { bsonArray.Add(BsonRegularExpression.Create(new Regex($"^{type}$", RegexOptions.IgnoreCase))); } filter.Set("Type", new BsonDocument("$in", bsonArray)); } var aggregation = GetNodeAggregation(filter); return(await aggregation.ToPagedListAsync(request.PageNumber, request.PageSize)); }
public async Task <IActionResult> GetNodeList([FromQuery(Name = "$filter")] string filter, [FromQuery] PaginationRequest request, [FromQuery(Name = "$projection"), ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable <string> fields) { //if (fields is null) // fields = typeof(Node).GetProperties().Select(p => p.Name); if (!fields?.Select(s => s.ToLower()).Contains("id") ?? false) { var fieldList = new List <string>(); fieldList.AddRange(fields); fieldList.Add("Id"); fields = fieldList; } BsonDocument filterDocument = null; try { filterDocument = new OrganizeFilter(UserId.Value).ByQueryString(filter); } catch { Log.Error($"Filter syntax error '{filter}'"); return(BadRequest()); } var projection = fields.ToMongoDBProjection(); var aggregation = GetNodeAggregation(filterDocument).Project <dynamic>(projection); var list = await aggregation.ToPagedListAsync(request.PageNumber, request.PageSize); this.AddPaginationHeader(request, list, nameof(GetNodeList), null, filter, fields); return(Ok(list)); }
public async Task <IActionResult> PatchModel(Guid id, [FromBody] JsonPatchDocument <UpdateEntityRequest> request, int version) { Log.Information($"Updating model {id}"); BsonDocument filter = new OrganizeFilter(UserId.Value).ById(id); var modelToUpdate = await Database.GetCollection <dynamic>("Models").Aggregate().Match(filter) .Lookup <BsonDocument, BsonDocument>(nameof(AccessPermissions), "_id", "_id", nameof(AccessPermissions)) .Unwind(nameof(AccessPermissions), new AggregateUnwindOptions <BsonDocument> { PreserveNullAndEmptyArrays = true }) .Project("{AccessPermissions:1}") .FirstOrDefaultAsync(); if (modelToUpdate is null) { return(NotFound()); } var model = new UpdateEntityRequest() { Id = id }; if (modelToUpdate.Contains(nameof(AccessPermissions))) { model.Permissions = BsonSerializer.Deserialize <AccessPermissions>(modelToUpdate[nameof(AccessPermissions)].AsBsonDocument); } request.ApplyTo(model); if (!string.IsNullOrEmpty(model.Name)) { if (_invalidName.IsMatch(model.Name?.Trim() ?? string.Empty)) { Log.Error($"Invalid model name {model.Name}"); return(BadRequest()); } Log.Information($"Rename model {id} to { model.Name}"); await _bus.Publish <UpdateModelName>(new { Id = id, UserId = UserId, ModelName = model.Name.Trim(), ExpectedVersion = version }); } if (model.ParentId != Guid.Empty) { Log.Information($"Move model {id} to {model.ParentId}"); await _bus.Publish <MoveModel>(new { Id = id, UserId = UserId, NewParentId = model.ParentId, ExpectedVersion = version }); } if (request.Operations.Any(o => o.path.Contains("/Permissions"))) { Log.Information($"Grant access to model {id}"); await _bus.Publish <MachineLearning.Domain.Commands.GrantAccess>(new { Id = id, UserId, model.Permissions }); } return(Accepted()); }
public async Task <IActionResult> PatchFile(Guid id, [FromBody] JsonPatchDocument <UpdateEntityRequest> request, int version) { BsonDocument filter = new OrganizeFilter(UserId.Value).ById(id); var permissions = await Database.GetCollection <dynamic>("Files").Aggregate().Match(filter) .Lookup <BsonDocument, BsonDocument>(nameof(AccessPermissions), "_id", "_id", nameof(AccessPermissions)) .Unwind(nameof(AccessPermissions), new AggregateUnwindOptions <BsonDocument> { PreserveNullAndEmptyArrays = true }) .Project("{AccessPermissions:1}") .FirstOrDefaultAsync(); if (permissions is null) { return(NotFound()); } var file = new UpdateEntityRequest() { Id = id }; if (permissions.Contains(nameof(AccessPermissions))) { file.Permissions = BsonSerializer.Deserialize <AccessPermissions>(permissions[nameof(AccessPermissions)].AsBsonDocument); } request.ApplyTo(file); if (!string.IsNullOrEmpty(file.Name)) { if (_invalidName.IsMatch(file.Name?.Trim() ?? string.Empty)) { Log.Error($"Invalid file name {file.Name}"); return(BadRequest()); } Log.Information($"Renaming file {id} to { file.Name}"); await _bus.Publish <RenameFile>(new { Id = id, UserId = UserId.Value, NewName = file.Name.Trim(), ExpectedVersion = version }); } if (file.Metadata.Any()) { Log.Information($"Update metadata for file {id}"); await _bus.Publish <UpdateMetadata>(new { file.Metadata, Id = id, UserId = UserId.Value, ExpectedVersion = version }); } if (file.ParentId != Guid.Empty) { Log.Information($"Move file {id} to {file.ParentId}"); await _bus.Publish <MoveFile>(new { Id = id, UserId = UserId.Value, NewParentId = file.ParentId, ExpectedVersion = version }); } if (request.Operations.Any(o => o.path.Contains("/Permissions"))) { Log.Information($"Grant access to file {id}"); await _bus.Publish <Generic.Domain.Commands.Files.GrantAccess>(new { Id = id, UserId = UserId.Value, file.Permissions }); } return(Accepted()); }
public async Task <IActionResult> NodesPublic([FromQuery(Name = "$filter")] string filter, [FromQuery] PaginationRequest request, [FromQuery(Name = "$projection"), ModelBinder(BinderType = typeof(ArrayModelBinder))] IEnumerable <string> fields) { if (!fields?.Select(s => s.ToLower()).Contains("id") ?? false) { var fieldList = new List <string>(); fieldList.AddRange(fields); fieldList.Add("Id"); fields = fieldList; } BsonDocument filterDocument = null; try { filterDocument = new OrganizeFilter().ByQueryString(filter); } catch { Log.Error($"Filter syntax error '{filter}'"); return(BadRequest()); } var projection = fields.ToMongoDBProjection(); var aggregation = _accessPermissions.Aggregate() .Match(new BsonDocument("IsPublic", true)) .Lookup <BsonDocument, BsonDocument>("Nodes", "_id", "_id", "Nodes") .Unwind("Nodes", new AggregateUnwindOptions <BsonDocument> { PreserveNullAndEmptyArrays = true }) .GraphLookup(_nodes, "Nodes.ParentId", "_id", "$Nodes.ParentId", "Parents") .Match(new BsonDocument("$or", new BsonArray( new[] { new BsonDocument("Parents", new BsonDocument("$size", 0)), new BsonDocument("Parents.IsDeleted", new BsonDocument("$ne", true)) }))) .AppendStage <BsonDocument>(BsonDocument.Parse(@" { $addFields: { 'Nodes.Order': { $cond: { if: { $eq: ['$Type', 'Folder'] }, then: 1, else: 100 } }, 'Nodes.AccessPermissions._id': ""$_id"", 'Nodes.AccessPermissions.IsPublic': ""$IsPublic"", 'Nodes.AccessPermissions.Users': ""$Users"", 'Nodes.AccessPermissions.Groups': ""$Groups"" } }")) .ReplaceRoot(new BsonValueAggregateExpressionDefinition <BsonDocument, BsonDocument>(@"$Nodes")) .Sort("{ Order:1, Name:1 }") .Project("{ Order: 0 }") .Match(filterDocument) .Project <dynamic>(projection); var list = await aggregation.ToPagedListAsync(request.PageNumber, request.PageSize); this.AddPaginationHeader(request, list, nameof(NodesPublic), null, filter, fields); return(Ok(list)); }
public async Task <IActionResult> Download(Guid id) { const string mongoDBProjection = "{Name:1, Blob:1, Type:1}"; var entitiesForDownlaod = new Dictionary <Blob, string>(); async Task FindChaildItemsAsync(dynamic node, BsonDocument f, string path = "") { if (((IDictionary <string, object>)node).ContainsKey("Blob")) { if (!(node.Blob is null)) { if (!entitiesForDownlaod.Keys.Any(k => k.Id == node.Blob._id)) { entitiesForDownlaod.Add( new Blob { Id = node.Blob._id, Bucket = node.Blob.Bucket }, $"{path}{node.Name}" ); } } } f.Set("ParentId", node._id); f.Remove("_id"); path += node.Type != "Folder" ? $"{node.Name}_{node._id}" : node.Name; foreach (var chaildNode in await _nodes.Find(f).Project <dynamic>(mongoDBProjection).ToListAsync()) { await FindChaildItemsAsync(chaildNode, f, $"{path}\\"); } } BsonDocument filter = new OrganizeFilter(UserId.Value).ById(id); var startNode = await _nodes.Find(filter) .Project <dynamic>(mongoDBProjection) .FirstOrDefaultAsync(); await FindChaildItemsAsync(startNode, filter); foreach (var group in entitiesForDownlaod.GroupBy(ent => ent.Value).Where(g => g.Count() > 1)) { int count = -1; foreach (var item in group) { if (++count > 0) { entitiesForDownlaod[item.Key] = $"{Path.GetDirectoryName(item.Value)}\\{Path.GetFileNameWithoutExtension(item.Value)}({count}){Path.GetExtension(item.Value)}"; } } } return(new FileCallbackResult(new MediaTypeHeaderValue("application/zip"), async(outputStream, _) => { using (var zipArchive = new ZipArchive(new WriteOnlyStreamWrapper(outputStream), ZipArchiveMode.Create)) { foreach (var blob in entitiesForDownlaod) { var zipEntry = zipArchive.CreateEntry(blob.Value); using (var zipStream = zipEntry.Open()) using (var stream = (await _blobStorage.GetFileAsync(blob.Key.Id, blob.Key.Bucket)).GetContentAsStream()) await stream.CopyToAsync(zipStream); } } }) { FileDownloadName = $"{id}_{DateTime.Now}.zip" }); }