示例#1
0
        /// <summary>
        /// Resolves a token to a FileReference, if the token exists for this user.
        /// The action should be called once the calling code can ensure the file is handled ok.
        /// </summary>
        /// <param name="mongoWrapper">For accessing the database</param>
        /// <param name="tokenId">The token ID to search for</param>
        /// <param name="userId">The user ID to correlate with the token</param>
        /// <returns>A Tuple of the FileReference and an async action to expire the token</returns>
        public static async Task <(FileReference, Func <Task>)> GetFileForReferenceToken(MongoWrapper mongoWrapper, string tokenId, ObjectId userId)
        {
            var tokenCollection = mongoWrapper.Database.GetCollection <DataReferenceToken <ConsumableData <ObjectId> > >(nameof(ReferenceToken));

            var tokenFilterBuilder = new FilterDefinitionBuilder <DataReferenceToken <ConsumableData <ObjectId> > >();
            var tokenFilter        = tokenFilterBuilder.And
                                     (
                GeneralUtils.NotDeactivated(tokenFilterBuilder),
                tokenFilterBuilder.Eq(t => t._id, tokenId),
                tokenFilterBuilder.Eq(t => t.UserId, userId)
                                     );

            var tokenUpdateBuilder = new UpdateDefinitionBuilder <DataReferenceToken <ConsumableData <ObjectId> > >();
            var tokenUpdate        = tokenUpdateBuilder
                                     .Set(t => t.DeactivationDate, DateTime.UtcNow)
                                     .Set(t => t.AdditionalData.IsConsumed, true);

            DataReferenceToken <ConsumableData <ObjectId> > token = (await tokenCollection.FindAsync(tokenFilter, new FindOptions <DataReferenceToken <ConsumableData <ObjectId> >, DataReferenceToken <ConsumableData <ObjectId> > >
            {
                Limit = 1,
                AllowPartialResults = false,
            })).SingleOrDefault();

            if (token == null)
            {
                throw new ValidationException("Token de Arquivo não encontrado!");
            }

            var gridFsBucket = new GridFSBucket <ObjectId>(mongoWrapper.Database);

            var fileFilterBuilder = new FilterDefinitionBuilder <GridFSFileInfo <ObjectId> >();
            var fileFilter        = fileFilterBuilder.Eq(finfo => finfo.Id, token.AdditionalData.Data);

            var fileInfo = (await gridFsBucket.FindAsync(fileFilter, new GridFSFindOptions <ObjectId>
            {
                Limit = 1,
            })).SingleOrDefault();

            if (fileInfo == null)
            {
                throw new ApplicationException("Arquivo não encontrado, mas havia um token ativado referenciando-o!");
            }

            var fileReference = new FileReference
            {
                FileInfo = new Models.FileInfo
                {
                    FileMetadata = BsonSerializer.Deserialize <FileMetadata>(fileInfo.Metadata),
                    Size         = fileInfo.Length
                },
                _id = token.AdditionalData.Data
            };

            return
                (
                fileReference,
                async() =>
            {
                var tokenUpdateTask = tokenCollection.UpdateOneAsync
                                      (
                    tokenFilter,
                    tokenUpdate
                                      );

                var userCollection = mongoWrapper.Database.GetCollection <User>(nameof(User));

                var userFilterBuilder = new FilterDefinitionBuilder <User>();
                var userFilter = userFilterBuilder.And
                                 (
                    GeneralUtils.NotDeactivated(userFilterBuilder),
                    userFilterBuilder.Eq(u => u._id, userId)
                                 );

                var userUpdateBuilder = new UpdateDefinitionBuilder <User>();
                var userUpdate = userUpdateBuilder.Inc(u => u.FileBytesOccupied, fileReference.FileInfo.Size);

                var userUpdateTask = userCollection.UpdateOneAsync
                                     (
                    userFilter,
                    userUpdate
                                     );

                await tokenUpdateTask;
                await userUpdateTask;
            }
                );
        }
示例#2
0
        public async Task <dynamic> Put()
        {
            var contentType = Request.Headers["Content-Type"];

            FileType?fileType = FileTypeFromMime(contentType);

            if (!fileType.HasValue)
            {
                throw new ValidationException("Tipo de arquivo desconhecido! Tipo: " + contentType);
            }

            var generatedFileId = ObjectId.GenerateNewId();

            var gridFsBucket = new GridFSBucket <ObjectId>(MongoWrapper.Database);

            var uploadTask = gridFsBucket.UploadFromStreamAsync(generatedFileId, generatedFileId.ToString(), Request.Body, new GridFSUploadOptions
            {
                Metadata = new FileMetadata
                {
                    ContentType = contentType,
                    FileType    = fileType.Value
                }
                .ToBsonDocument()
            });

            var id = this.GetCurrentUserId();

            var confirmationCollection = MongoWrapper.Database.GetCollection <ReferenceToken>(typeof(ReferenceToken).Name);

            var generatedToken = await GeneralUtils.GenerateRandomBase64(256);

            var token = new DataReferenceToken <ConsumableData <ObjectId> >()
            {
                UserId         = new ObjectId(id),
                TokenType      = TokenType.FileUpload,
                _id            = generatedToken,
                AdditionalData = new ConsumableData <ObjectId>
                {
                    Data       = generatedFileId,
                    IsConsumed = false,
                },
                // Auto-Deletion allowed 1 day from now.
                // TODO: Implement job that does auto-deletion
                // TODO: How to check for FileReference? Can't delete file if it is already used,
                // in those cases we should delete only the token!
                // TODO: Maybe a Boolean in AdditionalData which says if this token is being used or not:
                // If it is, the job will delete only the token, and not the file as well. Sounds good.
                // Boolean is implemented, only the job is left.
                DeactivationDate = DateTime.UtcNow + TimeSpan.FromHours(8)
            };

            var insertTokenTask = confirmationCollection.InsertOneAsync(token);

            using (var session = await MongoWrapper.MongoClient.StartSessionAsync())
            {
                session.StartTransaction();

                try
                {
                    await insertTokenTask;
                    await uploadTask;
                }
                catch (Exception e)
                {
                    Logger.LogError("Error while uploading user resource", e);
                    await session.AbortTransactionAsync();

                    throw;
                }

                await session.CommitTransactionAsync();
            }

            return(new ResponseBody
            {
                Code = ResponseCode.GenericSuccess,
                Data = generatedToken,
                Message = "Arquivo enviado com sucesso!",
                Success = true
            });
        }