public async Task HandleAsync_(string title, string description, string groupName, string version, string owner, string fileName, string extension, ulong sizeInBytes, string contentHash) { var cancellationToken = CancellationToken.None; var file = FutureNHS.WOPIHost.File.With(fileName, version); var services = new ServiceCollection(); var endpointForFileExtension = new Uri("https://domain.com/path?param=value", UriKind.Absolute); var wopiDiscoveryDocument = new Moq.Mock <IWopiDiscoveryDocument>(); wopiDiscoveryDocument.Setup(o => o.GetEndpointForFileExtension(extension, "view", Moq.It.IsAny <Uri>())).Returns(endpointForFileExtension); wopiDiscoveryDocument.Setup(o => o.IsEmpty).Returns(false); wopiDiscoveryDocument.Setup(o => o.IsTainted).Returns(false); var wopiDiscoveryDocumentFactory = new Moq.Mock <IWopiDiscoveryDocumentFactory>(); wopiDiscoveryDocumentFactory.Setup(o => o.CreateDocumentAsync(cancellationToken)).Returns(Task.FromResult(wopiDiscoveryDocument.Object)); var fileId = Guid.NewGuid(); var fileMetadata = new UserFileMetadata() { FileId = fileId, Title = title, Description = description, GroupName = groupName, FileVersion = version, OwnerUserName = owner, Name = fileName, Extension = extension, BlobName = fileName, SizeInBytes = sizeInBytes, LastWriteTimeUtc = DateTimeOffset.UtcNow, ContentHash = Convert.FromBase64String("aGFzaA == "), UserHasViewPermission = true, UserHasEditPermission = false }; var authenticatedUser = new AuthenticatedUser(Guid.NewGuid(), default) { FileMetadata = fileMetadata }; var wopiConfiguration = new WopiConfiguration { HostFilesUrl = new Uri("https://hostfiles.net/path", UriKind.Absolute) }; var wopiConfigurationSnapshot = new Moq.Mock <IOptionsSnapshot <WopiConfiguration> >(); wopiConfigurationSnapshot.Setup(o => o.Value).Returns(wopiConfiguration); var userAuthenticationService = new Moq.Mock <IUserAuthenticationService>(); var permission = FileAccessPermission.View; var userFileAccessToken = new UserFileAccessToken(Guid.NewGuid(), authenticatedUser, permission, DateTimeOffset.UtcNow.AddDays(1)); userAuthenticationService.Setup(x => x.GenerateAccessToken(authenticatedUser, file, permission, cancellationToken)).Returns(Task.FromResult(userFileAccessToken)); services.AddScoped(sp => wopiDiscoveryDocumentFactory.Object); services.AddScoped(sp => wopiConfigurationSnapshot.Object); services.AddScoped(sp => new Moq.Mock <IAzureTableStoreClient>().Object); services.AddScoped(sp => userAuthenticationService.Object); services.AddScoped(sp => new Moq.Mock <IUserFileAccessTokenRepository>().Object); var httpContext = new DefaultHttpContext { RequestServices = services.BuildServiceProvider() }; using var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; var postAuthoriseUserRequestHandler = AuthoriseUserRequestHandler.With(authenticatedUser, permission, file); await postAuthoriseUserRequestHandler.HandleAsync(httpContext, cancellationToken); Assert.AreEqual((int)HttpStatusCode.OK, httpContext.Response.StatusCode); Assert.AreEqual("application/json; charset=utf-8", httpContext.Response.ContentType); Assert.AreSame(responseBodyStream, httpContext.Response.Body); responseBodyStream.Position = 0; dynamic responseBody = await JsonSerializer.DeserializeAsync <ExpandoObject>(responseBodyStream, cancellationToken : cancellationToken); Assert.IsNotNull(responseBody); var accessToken = ((JsonElement)(responseBody.accessToken)).GetString(); Assert.IsNotNull(accessToken); var wopiClientUrlForFile = ((JsonElement)(responseBody.wopiClientUrlForFile)).GetString(); Assert.IsTrue(Uri.IsWellFormedUriString(wopiClientUrlForFile, UriKind.Absolute)); Assert.AreEqual(endpointForFileExtension, new Uri(wopiClientUrlForFile, UriKind.Absolute)); } }
async Task <FileContentMetadata> IFileContentMetadataRepository.GetDetailsAndPutContentIntoStreamAsync(UserFileMetadata fileMetadata, Stream streamToWriteTo, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (fileMetadata is null) { throw new ArgumentNullException(nameof(fileMetadata)); } Debug.Assert(!string.IsNullOrWhiteSpace(fileMetadata.BlobName)); Debug.Assert(fileMetadata.ContentHash is not null); if (streamToWriteTo is null) { throw new ArgumentNullException(nameof(streamToWriteTo)); } Debug.Assert(streamToWriteTo.CanWrite); var downloadDetails = await _azureBlobStoreClient.FetchBlobAndWriteToStream(_blobContainerName, fileMetadata.BlobName, fileMetadata.FileVersion, fileMetadata.ContentHash, streamToWriteTo, cancellationToken); return(new FileContentMetadata( contentVersion: downloadDetails.VersionId, contentHash: downloadDetails.ContentHash, contentEncoding: downloadDetails.ContentEncoding, contentLanguage: downloadDetails.ContentLanguage, contentType: downloadDetails.ContentType, contentLength: 0 > downloadDetails.ContentLength ? 0 : (ulong)downloadDetails.ContentLength, lastAccessed: DateTimeOffset.MinValue == downloadDetails.LastAccessed ? default : downloadDetails.LastAccessed, lastModified: downloadDetails.LastModified, fileMetadata: fileMetadata )); }
public FileContentMetadata(string contentVersion, string contentType, byte[] contentHash, ulong contentLength, string?contentEncoding, string?contentLanguage, DateTimeOffset?lastAccessed, DateTimeOffset lastModified, UserFileMetadata fileMetadata) { if (string.IsNullOrWhiteSpace(contentVersion)) { throw new ArgumentNullException(nameof(contentVersion)); } if (string.IsNullOrWhiteSpace(contentType)) { throw new ArgumentNullException(nameof(contentType)); } if (0 > contentLength) { throw new ArgumentOutOfRangeException(nameof(contentLength), "Must be greater than zero"); } ContentVersion = contentVersion; ContentLength = contentLength; ContentType = contentType; ContentEncoding = contentEncoding; ContentLanguage = contentLanguage; LastAccessed = lastAccessed; LastModified = lastModified; ContentHash = Convert.ToBase64String(contentHash); FileMetadata = fileMetadata ?? throw new ArgumentNullException(nameof(fileMetadata)); }
public async Task HandleAsync_FormsWOPICompliantResponseUsingFileMetadataAndUserContextAndFeatures(string title, string description, string groupName, string owner, string fileName, string extension, ulong sizeInBytes, string contentHash) { var cancellationToken = new CancellationToken(); var services = new ServiceCollection(); var fileMetadataRepository = new Moq.Mock <IUserFileMetadataProvider>(); var fileRepositoryInvoked = false; services.AddScoped(sp => fileMetadataRepository.Object); var httpContext = new DefaultHttpContext { RequestServices = services.BuildServiceProvider() }; using var responseBodyStream = new MemoryStream(); httpContext.Response.Body = responseBodyStream; var authenticatedUser = new AuthenticatedUser(Guid.NewGuid(), default); var fileId = Guid.NewGuid(); var fileVersion = Guid.NewGuid().ToString(); var file = FutureNHS.WOPIHost.File.With(fileName, fileVersion); var fileMetadata = new UserFileMetadata() { FileId = fileId, Title = title, Description = description, GroupName = groupName, FileVersion = fileVersion, OwnerUserName = owner, Name = fileName, Extension = extension, BlobName = fileId.ToString() + extension, SizeInBytes = sizeInBytes, LastWriteTimeUtc = DateTimeOffset.UtcNow, ContentHash = Convert.FromBase64String("aGFzaA == "), UserHasViewPermission = true, UserHasEditPermission = false }; fileMetadataRepository. Setup(x => x.GetForFileAsync(Moq.It.IsAny <FutureNHS.WOPIHost.File>(), Moq.It.IsAny <AuthenticatedUser>(), Moq.It.IsAny <CancellationToken>())). Callback((FutureNHS.WOPIHost.File givenFile, AuthenticatedUser givenAuthenticatedUser, CancellationToken givenCancellationToken) => { Assert.IsFalse(givenFile.IsEmpty); Assert.IsFalse(givenCancellationToken.IsCancellationRequested, "Expected the cancellation token to not be cancelled"); Assert.AreEqual(file.Id, givenFile.Id, "Expected the SUT to request the file from the repository whose id it was provided with"); Assert.AreEqual(fileName, givenFile.Name, "Expected the SUT to request the file from the repository whose name it was provided with"); Assert.AreEqual(fileVersion, givenFile.Version, "Expected the SUT to request the file version from the repository that it was provided with"); Assert.AreEqual(authenticatedUser, givenAuthenticatedUser, "Expected the SUT to pass to the repository the authenticated user that it was provided with"); Assert.AreEqual(cancellationToken, givenCancellationToken, "Expected the same cancellation token to propagate between service interfaces"); fileRepositoryInvoked = true; }). Returns(Task.FromResult(fileMetadata)); var features = new Features(); var checkFileInfoWopiRequestHandler = CheckFileInfoWopiRequestHandler.With(authenticatedUser, file, features); await checkFileInfoWopiRequestHandler.HandleAsync(httpContext, cancellationToken); Assert.IsTrue(fileRepositoryInvoked); Assert.AreEqual("application/json; charset=utf-8", httpContext.Response.ContentType); Assert.AreSame(responseBodyStream, httpContext.Response.Body); responseBodyStream.Position = 0; dynamic responseBody = await JsonSerializer.DeserializeAsync <ExpandoObject>(responseBodyStream, cancellationToken : cancellationToken); Assert.IsNotNull(responseBody); Assert.AreEqual(fileMetadata.Title, ((JsonElement)(responseBody.BaseFileName)).GetString()); Assert.AreEqual(fileMetadata.FileVersion, ((JsonElement)(responseBody.Version)).GetString()); Assert.AreEqual(fileMetadata.OwnerUserName, ((JsonElement)(responseBody.OwnerId)).GetString()); Assert.AreEqual(fileMetadata.Extension, ((JsonElement)(responseBody.FileExtension)).GetString()); Assert.AreEqual(fileMetadata.SizeInBytes, ((JsonElement)(responseBody.Size)).GetUInt64()); Assert.AreEqual(fileMetadata.LastWriteTimeUtc.ToIso8601(), ((JsonElement)(responseBody.LastModifiedTime)).GetString()); Assert.AreEqual(FutureNHS.WOPIHost.File.FILENAME_MAXIMUM_LENGTH, ((JsonElement)(responseBody.FileNameMaxLength)).GetInt32()); }