Пример #1
0
        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));
        }
Пример #2
0
        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));
        }
Пример #3
0
        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());
        }
Пример #4
0
        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));
        }
Пример #5
0
        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));
        }
Пример #6
0
        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));
        }
Пример #7
0
        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));
        }
Пример #8
0
        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));
        }
Пример #9
0
        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));
        }
Пример #10
0
        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));
        }
Пример #11
0
        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());
        }
Пример #12
0
        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());
        }
Пример #13
0
        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));
        }
Пример #14
0
        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"
            });
        }