public async Task <IActionResult> Delete([FromQuery] string dataType, [FromQuery] string id)
        {
            // Validate
            if (string.IsNullOrEmpty(dataType))
            {
                return(BadRequest("Data type not specified"));
            }
            if (string.IsNullOrEmpty(id))
            {
                return(BadRequest("ID not specified"));
            }

            IRdDataStorage rdDataStorage;

            try
            {
                rdDataStorage = await dataRouter.GetSourceSystemAsync(dataType);
            }
            catch (KeyNotFoundException e)
            {
                return(BadRequest(e.Message));
            }

            // Check existance
            var metadata = await GetExistingMetadataAsync(rdDataStorage, dataType, id);

            if (metadata == null) // Object doesn't exist
            {
                return(Ok());     // SECURITY NOTE: Returning OK without authentication allows for brute-force scanning for valid IDs!
            }
            // Authorize
            var loggedInUsername   = UsernameNormalizer.Normalize(HttpContext.User.Identity.Name);
            var overwritingAllowed = await authorizationModule.IsOverwritingAllowedForCollectionAsync(dataType);

            var resourceDescription = new DeleteDataResourceDescription(dataType, metadata.Submitter, overwritingAllowed);
            var authorizationResult = await authorizationModule.AuthorizeAsync(resourceDescription, loggedInUsername);

            if (!authorizationResult.IsAuthorized)
            {
                return(StatusCode((int)HttpStatusCode.Unauthorized, "Not authorized"));
            }

            // Delete
            if (await rdDataStorage.DeleteDataContainerAsync(dataType, id))
            {
                await subscriptionManager.NotifyDataChangedAsync(dataType, id, DataModificationType.Deleted);

                apiEventLogger.Log(LogLevel.Warning, $"User '{authorizationResult.User.UserName}' has deleted data of type '{dataType}' with ID '{id}'");
                return(Ok());
            }
            return(NotFound());
        }
        public async Task <IActionResult> DeleteMany([FromQuery] string dataType, [FromQuery] string whereArguments)
        {
            // Validate
            if (string.IsNullOrWhiteSpace(dataType))
            {
                return(BadRequest("Data type not specified"));
            }

            IRdDataStorage rdDataStorage;

            try
            {
                rdDataStorage = await dataRouter.GetSourceSystemAsync(dataType);
            }
            catch (KeyNotFoundException e)
            {
                return(BadRequest(e.Message));
            }

            var loggedInUsername   = UsernameNormalizer.Normalize(HttpContext.User.Identity.Name);
            var overwritingAllowed = await authorizationModule.IsOverwritingAllowedForCollectionAsync(dataType);

            // Check existance
            var query         = $"SELECT _id, Submitter FROM {dataType} WHERE {whereArguments}";
            var searchResult  = rdDataStorage.SearchAsync(DataApiSqlQueryParser.Parse(query));
            var deleteResults = new List <DeleteResult>();

            await foreach (var doc in searchResult)
            {
                var submitter = doc["Submitter"].AsString;
                var id        = doc["_id"].AsString;

                // Authorize
                var resourceDescription = new DeleteDataResourceDescription(dataType, submitter, overwritingAllowed);
                var authorizationResult = await authorizationModule.AuthorizeAsync(resourceDescription, loggedInUsername);

                if (!authorizationResult.IsAuthorized)
                {
                    deleteResults.Add(DeleteResult.Failed(dataType, id, "Not authorized"));
                    continue;
                }

                // Delete
                if (await rdDataStorage.DeleteDataContainerAsync(dataType, id))
                {
                    await subscriptionManager.NotifyDataChangedAsync(dataType, id, DataModificationType.Deleted);

                    deleteResults.Add(DeleteResult.Success(dataType, id));
                }
                else
                {
                    deleteResults.Add(DeleteResult.Failed(dataType, id, "Not found"));
                }
            }

            apiEventLogger.Log(LogLevel.Warning, $"User '{loggedInUsername}' has deleted data of type '{dataType}' with matching '{whereArguments}'");

            return(new ContentResult
            {
                ContentType = Conventions.JsonContentType,
                Content = JsonConvert.SerializeObject(deleteResults),
                StatusCode = (int)HttpStatusCode.OK
            });
        }