From a4248217cde11eee941176a96931927affd45515 Mon Sep 17 00:00:00 2001 From: Nathan Heskew Date: Fri, 8 Apr 2011 15:01:33 -0700 Subject: [PATCH 1/6] Changing how user removal works. --HG-- branch : 1.x --- .../Modules/Orchard.Users/Controllers/AdminController.cs | 1 + src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs index b83896b2e..f6bb9f0bc 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs @@ -264,6 +264,7 @@ namespace Orchard.Users.Controllers { return RedirectToAction("Index"); } + [HttpPost] public ActionResult Delete(int id) { if (!Services.Authorizer.Authorize(StandardPermissions.SiteOwner, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); diff --git a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml index c2152cb8d..f3bd89337 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Users/Views/Admin/Index.cshtml @@ -69,7 +69,7 @@ @Html.ActionLink(T("Edit").ToString(), "Edit", new { entry.User.Id }) | - @Html.ActionLink(T("Delete").ToString(), "Delete", new { entry.User.Id }) | + @Html.ActionLink(T("Delete").ToString(), "Delete", new { entry.User.Id}, new { itemprop = "RemoveUrl UnsafeUrl" }) | @if (entry.User.RegistrationStatus == UserStatus.Pending) { @Html.ActionLink(T("Approve").ToString(), "Approve", new { entry.User.Id }) } else { From 0073fbd1a9b61b96d867d2483d5191d274fd0ce0 Mon Sep 17 00:00:00 2001 From: Andre Rodrigues Date: Fri, 8 Apr 2011 14:44:32 -0700 Subject: [PATCH 2/6] #17691: Possible to create invalid admin account with Turkish collation --HG-- branch : 1.x --- .../Users/Services/UserServiceTests.cs | 19 ++++++++++++++++++- .../RolesBasedAuthorizationService.cs | 2 +- .../Controllers/AdminController.cs | 10 +++++----- .../Services/MembershipService.cs | 6 +++--- .../Orchard.Users/Services/UserService.cs | 6 +++--- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs b/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs index 22b00929e..fa95bb8ee 100644 --- a/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs +++ b/src/Orchard.Tests.Modules/Users/Services/UserServiceTests.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.Threading; using System.Xml.Linq; using Autofac; using Moq; @@ -39,6 +41,7 @@ namespace Orchard.Tests.Modules.Users.Services { private ISessionFactory _sessionFactory; private ISession _session; private IContainer _container; + private CultureInfo _currentCulture; public class TestSessionLocator : ISessionLocator { @@ -55,6 +58,7 @@ namespace Orchard.Tests.Modules.Users.Services { [TestFixtureSetUp] public void InitFixture() { + _currentCulture = Thread.CurrentThread.CurrentCulture; var databaseFileName = System.IO.Path.GetTempFileName(); _sessionFactory = DataUtility.CreateSessionFactory( databaseFileName, @@ -66,7 +70,7 @@ namespace Orchard.Tests.Modules.Users.Services { [TestFixtureTearDown] public void TermFixture() { - + Thread.CurrentThread.CurrentCulture = _currentCulture; } [SetUp] @@ -122,5 +126,18 @@ namespace Orchard.Tests.Modules.Users.Services { Assert.That(username, Is.EqualTo("foo")); Assert.That(validateByUtc, Is.GreaterThan(_clock.UtcNow)); } + + [Test] + public void VerifyUserUnicityTurkishTest() { + CultureInfo turkishCulture = new CultureInfo("tr-TR"); + Thread.CurrentThread.CurrentCulture = turkishCulture; + + // Create user lower case + _membershipService.CreateUser(new CreateUserParams("admin", "66554321", "foo@bar.com", "", "", true)); + _container.Resolve().ContentManager.Flush(); + + // Verify unicity with upper case which with turkish coallition would yeld admin with an i without the dot and therefore generate a different user name + Assert.That(_userService.VerifyUserUnicity("ADMIN", "differentfoo@bar.com"), Is.False); + } } } diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs index d58574bc6..70c68deae 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs @@ -48,7 +48,7 @@ namespace Orchard.Roles.Services { for (var adjustmentLimiter = 0; adjustmentLimiter != 3; ++adjustmentLimiter) { if (!context.Granted && context.User != null) { if (!String.IsNullOrEmpty(_workContextAccessor.GetContext().CurrentSite.SuperUser) && - String.Equals(context.User.UserName, _workContextAccessor.GetContext().CurrentSite.SuperUser, StringComparison.OrdinalIgnoreCase)) { + String.Equals(context.User.UserName, _workContextAccessor.GetContext().CurrentSite.SuperUser, StringComparison.Ordinal)) { context.Granted = true; } } diff --git a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs index f6bb9f0bc..e0cd96257 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Controllers/AdminController.cs @@ -241,11 +241,11 @@ namespace Orchard.Users.Controllers { } else { // also update the Super user if this is the renamed account - if (String.Equals(Services.WorkContext.CurrentSite.SuperUser, previousName, StringComparison.OrdinalIgnoreCase)) { + if (String.Equals(Services.WorkContext.CurrentSite.SuperUser, previousName, StringComparison.Ordinal)) { _siteService.GetSiteSettings().As().SuperUser = editModel.UserName; } - user.NormalizedUserName = editModel.UserName.ToLower(); + user.NormalizedUserName = editModel.UserName.ToLowerInvariant(); } } @@ -272,10 +272,10 @@ namespace Orchard.Users.Controllers { var user = Services.ContentManager.Get(id); if (user != null) { - if (String.Equals(Services.WorkContext.CurrentSite.SuperUser, user.UserName, StringComparison.OrdinalIgnoreCase)) { + if (String.Equals(Services.WorkContext.CurrentSite.SuperUser, user.UserName, StringComparison.Ordinal)) { Services.Notifier.Error(T("The Super user can't be removed. Please disable this account or specify another Super user account")); } - else if (String.Equals(Services.WorkContext.CurrentUser.UserName, user.UserName, StringComparison.OrdinalIgnoreCase)) { + else if (String.Equals(Services.WorkContext.CurrentUser.UserName, user.UserName, StringComparison.Ordinal)) { Services.Notifier.Error(T("You can't remove your own account. Please log in with another account")); } else{ @@ -323,7 +323,7 @@ namespace Orchard.Users.Controllers { var user = Services.ContentManager.Get(id); if (user != null) { - if (String.Equals(Services.WorkContext.CurrentUser.UserName, user.UserName, StringComparison.OrdinalIgnoreCase)) { + if (String.Equals(Services.WorkContext.CurrentUser.UserName, user.UserName, StringComparison.Ordinal)) { Services.Notifier.Error(T("You can't disable your own account. Please log in with another account")); } else { diff --git a/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs b/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs index 163685cc1..6af141c6e 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Services/MembershipService.cs @@ -49,7 +49,7 @@ namespace Orchard.Users.Services { user.Record.UserName = createUserParams.Username; user.Record.Email = createUserParams.Email; - user.Record.NormalizedUserName = createUserParams.Username.ToLower(); + user.Record.NormalizedUserName = createUserParams.Username.ToLowerInvariant(); user.Record.HashAlgorithm = "SHA1"; SetPassword(user.Record, createUserParams.Password); @@ -97,13 +97,13 @@ namespace Orchard.Users.Services { } public IUser GetUser(string username) { - var lowerName = username == null ? "" : username.ToLower(); + var lowerName = username == null ? "" : username.ToLowerInvariant(); return _orchardServices.ContentManager.Query().Where(u => u.NormalizedUserName == lowerName).List().FirstOrDefault(); } public IUser ValidateUser(string userNameOrEmail, string password) { - var lowerName = userNameOrEmail == null ? "" : userNameOrEmail.ToLower(); + var lowerName = userNameOrEmail == null ? "" : userNameOrEmail.ToLowerInvariant(); var user = _orchardServices.ContentManager.Query().Where(u => u.NormalizedUserName == lowerName).List().FirstOrDefault(); diff --git a/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs b/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs index 6b84fb063..5e3212912 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Services/UserService.cs @@ -37,7 +37,7 @@ namespace Orchard.Users.Services { public ILogger Logger { get; set; } public bool VerifyUserUnicity(string userName, string email) { - string normalizedUserName = userName.ToLower(); + string normalizedUserName = userName.ToLowerInvariant(); if (_contentManager.Query() .Where(user => @@ -51,7 +51,7 @@ namespace Orchard.Users.Services { } public bool VerifyUserUnicity(int id, string userName, string email) { - string normalizedUserName = userName.ToLower(); + string normalizedUserName = userName.ToLowerInvariant(); if (_contentManager.Query() .Where(user => @@ -115,7 +115,7 @@ namespace Orchard.Users.Services { } public bool SendLostPasswordEmail(string usernameOrEmail, Func createUrl) { - var lowerName = usernameOrEmail.ToLower(); + var lowerName = usernameOrEmail.ToLowerInvariant(); var user = _contentManager.Query().Where(u => u.NormalizedUserName == lowerName || u.Email == lowerName).List().FirstOrDefault(); if (user != null) { From 7353fe5f581c826683e5956f9105e6e76b841b75 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 8 Apr 2011 14:53:26 -0700 Subject: [PATCH 3/6] Adding CreateFile on IStorageFile --HG-- branch : 1.x --- .../Media/AzureBlobStorageProviderTests.cs | 4 +-- src/Orchard.Azure/AzureFileSystem.cs | 18 +++++++---- .../Media/AzureBlobStorageProvider.cs | 30 +++++++++++++++---- .../Services/RecipeJournalManager.cs | 3 +- .../Media/FileSystemStorageProvider.cs | 26 +++++++++++++--- src/Orchard/FileSystems/Media/IStorageFile.cs | 6 ++++ 6 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs b/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs index acb433b7a..5042ebecd 100644 --- a/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs +++ b/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs @@ -190,9 +190,9 @@ namespace Orchard.Azure.Tests.FileSystems.Media { } [Test] - public void CanCreateAlreadyExistingFolder() { + public void TryCreateFolderShouldReturnFalseIfFolderAlreadyExists() { _azureBlobStorageProvider.CreateFile("folder1/foo.txt"); - Assert.That(_azureBlobStorageProvider.TryCreateFolder("folder1"), Is.True); + Assert.That(_azureBlobStorageProvider.TryCreateFolder("folder1"), Is.False); } [Test] diff --git a/src/Orchard.Azure/AzureFileSystem.cs b/src/Orchard.Azure/AzureFileSystem.cs index b62e0c417..bef682bea 100644 --- a/src/Orchard.Azure/AzureFileSystem.cs +++ b/src/Orchard.Azure/AzureFileSystem.cs @@ -8,8 +8,7 @@ using Microsoft.WindowsAzure.StorageClient; using Orchard.FileSystems.Media; namespace Orchard.Azure { - public class AzureFileSystem - { + public class AzureFileSystem { private const string FolderEntry = "$$$ORCHARD$$$.$$$"; public string ContainerName { get; protected set; } @@ -71,15 +70,13 @@ namespace Orchard.Azure { return path2; } - if ( path2.StartsWith("http://") || path2.StartsWith("https://") ) - { + if ( path2.StartsWith("http://") || path2.StartsWith("https://") ) { return path2; } var ch = path1[path1.Length - 1]; - if (ch != '/') - { + if (ch != '/') { return (path1.TrimEnd('/') + '/' + path2.TrimStart('/')); } @@ -158,6 +155,9 @@ namespace Orchard.Azure { try { if (!Container.DirectoryExists(String.Concat(_root, path))) { CreateFolder(path); + + // return false to be consistent with FileSystemProvider's implementation + return false; } return true; } @@ -302,6 +302,12 @@ namespace Orchard.Azure { return _blob.OpenWrite(); } + public Stream CreateFile() { + // as opposed to the File System implementation, if nothing is done on the stream + // the file will be emptied, because Azure doesn't implement FileMode.Truncate + _blob.DeleteIfExists(); + return OpenWrite(); + } } private class AzureBlobFolderStorage : IStorageFolder { diff --git a/src/Orchard.Azure/FileSystems/Media/AzureBlobStorageProvider.cs b/src/Orchard.Azure/FileSystems/Media/AzureBlobStorageProvider.cs index 341b06938..47281684d 100644 --- a/src/Orchard.Azure/FileSystems/Media/AzureBlobStorageProvider.cs +++ b/src/Orchard.Azure/FileSystems/Media/AzureBlobStorageProvider.cs @@ -1,4 +1,5 @@ -using Microsoft.WindowsAzure; +using System.IO; +using Microsoft.WindowsAzure; using Orchard.Environment.Configuration; using Orchard.FileSystems.Media; @@ -12,12 +13,31 @@ namespace Orchard.Azure.FileSystems.Media { public AzureBlobStorageProvider(ShellSettings shellSettings, CloudStorageAccount storageAccount) : base("media", shellSettings.Name, false, storageAccount) { } - public bool TrySaveStream(string path, System.IO.Stream inputStream) { - throw new System.NotImplementedException(); + public bool TrySaveStream(string path, Stream inputStream) { + try { + SaveStream(path, inputStream); + } + catch { + return false; + } + + return true; } - public void SaveStream(string path, System.IO.Stream inputStream) { - throw new System.NotImplementedException(); + public void SaveStream(string path, Stream inputStream) { + // Create the file. + // The CreateFile method will map the still relative path + var file = CreateFile(path); + + using(var outputStream = file.OpenWrite()) { + var buffer = new byte[8192]; + for (;;) { + var length = inputStream.Read(buffer, 0, buffer.Length); + if (length <= 0) + break; + outputStream.Write(buffer, 0, length); + } + } } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs index 2555711b8..fc9aab235 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs @@ -121,10 +121,9 @@ namespace Orchard.Recipes.Services { private static void WriteJournal(IStorageFile journalFile, XElement journal) { string content = journal.ToString(); - using (var stream = journalFile.OpenWrite()) { + using (var stream = journalFile.CreateFile()) { using (var tw = new StreamWriter(stream)) { tw.Write(content); - stream.SetLength(stream.Position); } } } diff --git a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs index 79a2eb717..980c1fefa 100644 --- a/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs +++ b/src/Orchard/FileSystems/Media/FileSystemStorageProvider.cs @@ -135,8 +135,18 @@ namespace Orchard.FileSystems.Media { /// The relative path to the folder to be created. /// True if success; False otherwise. public bool TryCreateFolder(string path) { - try { CreateFolder(path); } - catch { return false; } + try { + // prevent unnecessary exception + DirectoryInfo directoryInfo = new DirectoryInfo(MapStorage(path)); + if (directoryInfo.Exists) { + return false; + } + + CreateFolder(path); + } + catch { + return false; + } return true; } @@ -250,8 +260,12 @@ namespace Orchard.FileSystems.Media { /// The stream to be saved. /// True if success; False otherwise. public bool TrySaveStream(string path, Stream inputStream) { - try { SaveStream(path, inputStream); } - catch { return false; } + try { + SaveStream(path, inputStream); + } + catch { + return false; + } return true; } @@ -334,6 +348,10 @@ namespace Orchard.FileSystems.Media { return new FileStream(_fileInfo.FullName, FileMode.Open, FileAccess.ReadWrite); } + public Stream CreateFile() { + return new FileStream(_fileInfo.FullName, FileMode.Truncate, FileAccess.ReadWrite); + } + #endregion } diff --git a/src/Orchard/FileSystems/Media/IStorageFile.cs b/src/Orchard/FileSystems/Media/IStorageFile.cs index 1f33ed907..a92359f11 100644 --- a/src/Orchard/FileSystems/Media/IStorageFile.cs +++ b/src/Orchard/FileSystems/Media/IStorageFile.cs @@ -18,5 +18,11 @@ namespace Orchard.FileSystems.Media { /// Creates a stream for writing to the file. /// Stream OpenWrite(); + + /// + /// Creates a stream for writing to the file, and truncates the existing content. + /// + Stream CreateFile(); + } } \ No newline at end of file From c89477eaa281be4b57138f628aeb257ccb3cb952 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 8 Apr 2011 15:31:27 -0700 Subject: [PATCH 4/6] Using StorageProvider.Combine() in Recipe --HG-- branch : 1.x --- .../Orchard.Recipes/Services/RecipeJournalManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs index fc9aab235..9b2953a49 100644 --- a/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs +++ b/src/Orchard.Web/Modules/Orchard.Recipes/Services/RecipeJournalManager.cs @@ -10,7 +10,7 @@ using Orchard.Recipes.Models; namespace Orchard.Recipes.Services { public class RecipeJournalManager : IRecipeJournal { private readonly IStorageProvider _storageProvider; - private readonly string _recipeJournalFolder = "RecipeJournal" + Path.DirectorySeparatorChar; + private const string RecipeJournalFolder = "RecipeJournal"; private const string WebConfig = @" @@ -92,10 +92,10 @@ namespace Orchard.Recipes.Services { private IStorageFile GetJournalFile(string executionId) { IStorageFile journalFile; - var journalPath = Path.Combine(_recipeJournalFolder, executionId); + var journalPath = _storageProvider.Combine(RecipeJournalFolder, executionId); try { - if (_storageProvider.TryCreateFolder(_recipeJournalFolder)) { - var webConfigPath = Path.Combine(_recipeJournalFolder, "web.config"); + if (_storageProvider.TryCreateFolder(RecipeJournalFolder)) { + var webConfigPath = _storageProvider.Combine(RecipeJournalFolder, "web.config"); var webConfigFile = _storageProvider.CreateFile(webConfigPath); WriteWebConfig(webConfigFile); } From ac9d37de3f69dbc10109054ecf5d09f5d403faf4 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 8 Apr 2011 17:14:07 -0700 Subject: [PATCH 5/6] Fixing Azure file system bugs --HG-- branch : 1.x --- .../Media/AzureBlobStorageProviderTests.cs | 28 +++++++++++++++ src/Orchard.Azure/AzureFileSystem.cs | 36 ++++++++++++++----- .../Storage/FileSystemStorageProviderTests.cs | 9 +++++ 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs b/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs index 5042ebecd..0ce78d3b1 100644 --- a/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs +++ b/src/Orchard.Azure.Tests/FileSystems/Media/AzureBlobStorageProviderTests.cs @@ -128,6 +128,14 @@ namespace Orchard.Azure.Tests.FileSystems.Media { Assert.AreEqual("folder", _azureBlobStorageProvider.ListFolders("folder").First().GetName()); } + [Test] + public void FoldersShouldBeCreatedRecursively() { + _azureBlobStorageProvider.CreateFolder("foo/bar/baz"); + Assert.That(_azureBlobStorageProvider.ListFolders("").Count(), Is.EqualTo(1)); + Assert.That(_azureBlobStorageProvider.ListFolders("foo").Count(), Is.EqualTo(1)); + Assert.That(_azureBlobStorageProvider.ListFolders("foo/bar").Count(), Is.EqualTo(1)); + } + [Test] public void ShouldDeleteFiles() { _azureBlobStorageProvider.CreateFile("folder/foo1.txt"); @@ -215,5 +223,25 @@ namespace Orchard.Azure.Tests.FileSystems.Media { Assert.AreEqual(teststring, content); } + + [Test] + public void ShouldTruncateFile() { + var sf = _azureBlobStorageProvider.CreateFile("folder/foo1.txt"); + using (var sw = new StreamWriter(sf.OpenWrite())) { + sw.Write("foo"); + } + + using (var sw = new StreamWriter(sf.CreateFile())) { + sw.Write("fo"); + } + + sf = _azureBlobStorageProvider.GetFile("folder/foo1.txt"); + string content; + using (var sr = new StreamReader(sf.OpenRead())) { + content = sr.ReadToEnd(); + } + + Assert.That(content, Is.EqualTo("fo")); + } } } \ No newline at end of file diff --git a/src/Orchard.Azure/AzureFileSystem.cs b/src/Orchard.Azure/AzureFileSystem.cs index bef682bea..f1b594959 100644 --- a/src/Orchard.Azure/AzureFileSystem.cs +++ b/src/Orchard.Azure/AzureFileSystem.cs @@ -9,7 +9,7 @@ using Orchard.FileSystems.Media; namespace Orchard.Azure { public class AzureFileSystem { - private const string FolderEntry = "$$$ORCHARD$$$.$$$"; + public const string FolderEntry = "$$$ORCHARD$$$.$$$"; public string ContainerName { get; protected set; } @@ -88,7 +88,7 @@ namespace Orchard.Azure { using ( new HttpContextWeaver() ) { Container.EnsureBlobExists(String.Concat(_root, path)); - return new AzureBlobFileStorage(Container.GetBlockBlobReference(path), _absoluteRoot); + return new AzureBlobFileStorage(Container.GetBlockBlobReference(String.Concat(_root, path)), _absoluteRoot); } } @@ -155,11 +155,11 @@ namespace Orchard.Azure { try { if (!Container.DirectoryExists(String.Concat(_root, path))) { CreateFolder(path); - - // return false to be consistent with FileSystemProvider's implementation - return false; + return true; } - return true; + + // return false to be consistent with FileSystemProvider's implementation + return false; } catch { return false; @@ -173,6 +173,14 @@ namespace Orchard.Azure { // Creating a virtually hidden file to make the directory an existing concept CreateFile(Combine(path, FolderEntry)); + + int lastIndex; + while ((lastIndex = path.LastIndexOf('/')) > 0) { + path = path.Substring(0, lastIndex); + if(!Container.DirectoryExists(String.Concat(_root, path))) { + CreateFile(Combine(path, FolderEntry)); + } + } } } @@ -246,11 +254,20 @@ namespace Orchard.Azure { public IStorageFile CreateFile(string path) { EnsurePathIsRelative(path); - + if ( Container.BlobExists(String.Concat(_root, path)) ) { throw new ArgumentException("File " + path + " already exists"); } + // create all folder entries in the hierarchy + int lastIndex; + var localPath = path; + while ((lastIndex = localPath.LastIndexOf('/')) > 0) { + localPath = localPath.Substring(0, lastIndex); + var folder = Container.GetBlockBlobReference(String.Concat(_root, Combine(localPath, FolderEntry))); + folder.OpenWrite().Dispose(); + } + var blob = Container.GetBlockBlobReference(String.Concat(_root, path)); blob.OpenWrite().Dispose(); // force file creation return new AzureBlobFileStorage(blob, _absoluteRoot); @@ -266,7 +283,7 @@ namespace Orchard.Azure { } private class AzureBlobFileStorage : IStorageFile { - private readonly CloudBlockBlob _blob; + private CloudBlockBlob _blob; private readonly string _rootPath; public AzureBlobFileStorage(CloudBlockBlob blob, string rootPath) { @@ -306,6 +323,9 @@ namespace Orchard.Azure { // as opposed to the File System implementation, if nothing is done on the stream // the file will be emptied, because Azure doesn't implement FileMode.Truncate _blob.DeleteIfExists(); + _blob = _blob.Container.GetBlockBlobReference(_blob.Uri.ToString()); + _blob.OpenWrite().Dispose(); // force file creation + return OpenWrite(); } } diff --git a/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs b/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs index 9c3297a25..740af7a5c 100644 --- a/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs +++ b/src/Orchard.Tests/Storage/FileSystemStorageProviderTests.cs @@ -129,6 +129,15 @@ namespace Orchard.Tests.Storage { } } + [Test] + public void ShouldCreateFolders() { + Directory.Delete(_folderPath, true); + _storageProvider.CreateFolder("foo/bar/baz"); + Assert.That(_storageProvider.ListFolders("").Count(), Is.EqualTo(1)); + Assert.That(_storageProvider.ListFolders("foo").Count(), Is.EqualTo(1)); + Assert.That(_storageProvider.ListFolders("foo/bar").Count(), Is.EqualTo(1)); + } + [Test] public void RenameFolderTakesShortPathWithAnyKindOfSlash() { Assert.That(GetFolder(@"SubFolder1/SubSubFolder1"), Is.Not.Null); From 6ad06a5dcfe3fffb7045ecac71280ec36a78aaea Mon Sep 17 00:00:00 2001 From: Suha Can Date: Fri, 8 Apr 2011 17:17:06 -0700 Subject: [PATCH 6/6] Ignore a specflow test. Reason: specflow only simulates no js browser. --HG-- branch : 1.x --- src/Orchard.Specs/Users.feature | 1 + src/Orchard.Specs/Users.feature.cs | 198 +++++++++++++++-------------- 2 files changed, 101 insertions(+), 98 deletions(-) diff --git a/src/Orchard.Specs/Users.feature b/src/Orchard.Specs/Users.feature index a87e49b48..7fcbe9942 100644 --- a/src/Orchard.Specs/Users.feature +++ b/src/Orchard.Specs/Users.feature @@ -151,6 +151,7 @@ Scenario: I should not be able to reuse an existing username or email Then I should see "User with that username and/or email already exists." @management +@ignore Scenario: I should be able to remove an existing user Given I have installed Orchard When I go to "admin/users" diff --git a/src/Orchard.Specs/Users.feature.cs b/src/Orchard.Specs/Users.feature.cs index 002561568..00bd972d5 100644 --- a/src/Orchard.Specs/Users.feature.cs +++ b/src/Orchard.Specs/Users.feature.cs @@ -438,17 +438,19 @@ this.ScenarioSetup(scenarioInfo); [NUnit.Framework.TestAttribute()] [NUnit.Framework.DescriptionAttribute("I should be able to remove an existing user")] [NUnit.Framework.CategoryAttribute("management")] + [NUnit.Framework.IgnoreAttribute()] public virtual void IShouldBeAbleToRemoveAnExistingUser() { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I should be able to remove an existing user", new string[] { - "management"}); -#line 154 -this.ScenarioSetup(scenarioInfo); + "management", + "ignore"}); #line 155 - testRunner.Given("I have installed Orchard"); +this.ScenarioSetup(scenarioInfo); #line 156 + testRunner.Given("I have installed Orchard"); +#line 157 testRunner.When("I go to \"admin/users\""); -#line 158 +#line 159 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table13 = new TechTalk.SpecFlow.Table(new string[] { @@ -466,13 +468,13 @@ this.ScenarioSetup(scenarioInfo); table13.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 159 +#line 160 testRunner.And("I fill in", ((string)(null)), table13); -#line 165 - testRunner.And("I hit \"Save\""); #line 166 - testRunner.And("I am redirected"); + testRunner.And("I hit \"Save\""); #line 167 + testRunner.And("I am redirected"); +#line 168 testRunner.Then("I should see \"]*>user1\""); #line hidden TechTalk.SpecFlow.Table table14 = new TechTalk.SpecFlow.Table(new string[] { @@ -481,19 +483,19 @@ this.ScenarioSetup(scenarioInfo); table14.AddRow(new string[] { "Options.Search", "user1"}); -#line 169 +#line 170 testRunner.When("I fill in", ((string)(null)), table14); -#line 172 - testRunner.And("I hit \"Filter\""); #line 173 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 174 - testRunner.When("I follow \"Delete\""); + testRunner.Then("I should see \"]*>user1\""); #line 175 - testRunner.And("I am redirected"); + testRunner.When("I follow \"Delete\""); #line 176 - testRunner.Then("I should see \"User user1 deleted\""); + testRunner.And("I am redirected"); #line 177 + testRunner.Then("I should see \"User user1 deleted\""); +#line 178 testRunner.And("I should not see \"]*>user1\""); #line hidden testRunner.CollectScenarioErrors(); @@ -506,13 +508,13 @@ this.ScenarioSetup(scenarioInfo); { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I should not be able to filter users by name", new string[] { "filtering"}); -#line 180 -this.ScenarioSetup(scenarioInfo); #line 181 - testRunner.Given("I have installed Orchard"); +this.ScenarioSetup(scenarioInfo); #line 182 + testRunner.Given("I have installed Orchard"); +#line 183 testRunner.When("I go to \"admin/users\""); -#line 184 +#line 185 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table15 = new TechTalk.SpecFlow.Table(new string[] { @@ -530,13 +532,13 @@ this.ScenarioSetup(scenarioInfo); table15.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 185 +#line 186 testRunner.And("I fill in", ((string)(null)), table15); -#line 191 - testRunner.And("I hit \"Save\""); #line 192 + testRunner.And("I hit \"Save\""); +#line 193 testRunner.And("I am redirected"); -#line 194 +#line 195 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table16 = new TechTalk.SpecFlow.Table(new string[] { @@ -554,15 +556,15 @@ this.ScenarioSetup(scenarioInfo); table16.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 195 +#line 196 testRunner.And("I fill in", ((string)(null)), table16); -#line 201 - testRunner.And("I hit \"Save\""); #line 202 - testRunner.And("I am redirected"); + testRunner.And("I hit \"Save\""); #line 203 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I am redirected"); #line 204 + testRunner.Then("I should see \"]*>user1\""); +#line 205 testRunner.And("I should see \"]*>user2\""); #line hidden TechTalk.SpecFlow.Table table17 = new TechTalk.SpecFlow.Table(new string[] { @@ -571,15 +573,15 @@ this.ScenarioSetup(scenarioInfo); table17.AddRow(new string[] { "Options.Search", "user1"}); -#line 205 +#line 206 testRunner.When("I fill in", ((string)(null)), table17); -#line 208 - testRunner.And("I hit \"Filter\""); #line 209 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 210 - testRunner.And("I should not see \"]*>admin\""); + testRunner.Then("I should see \"]*>user1\""); #line 211 + testRunner.And("I should not see \"]*>admin\""); +#line 212 testRunner.And("I should not see \"]*>user2\""); #line hidden TechTalk.SpecFlow.Table table18 = new TechTalk.SpecFlow.Table(new string[] { @@ -588,15 +590,15 @@ this.ScenarioSetup(scenarioInfo); table18.AddRow(new string[] { "Options.Search", "user1@domain.com"}); -#line 212 +#line 213 testRunner.When("I fill in", ((string)(null)), table18); -#line 215 - testRunner.And("I hit \"Filter\""); #line 216 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 217 - testRunner.And("I should not see \"]*>admin\""); + testRunner.Then("I should see \"]*>user1\""); #line 218 + testRunner.And("I should not see \"]*>admin\""); +#line 219 testRunner.And("I should not see \"]*>user2\""); #line hidden TechTalk.SpecFlow.Table table19 = new TechTalk.SpecFlow.Table(new string[] { @@ -605,15 +607,15 @@ this.ScenarioSetup(scenarioInfo); table19.AddRow(new string[] { "Options.Search", "@domain.com"}); -#line 219 +#line 220 testRunner.When("I fill in", ((string)(null)), table19); -#line 222 - testRunner.And("I hit \"Filter\""); #line 223 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 224 - testRunner.And("I should see \"]*>user2\""); + testRunner.Then("I should see \"]*>user1\""); #line 225 + testRunner.And("I should see \"]*>user2\""); +#line 226 testRunner.And("I should not see \"]*>admin\""); #line hidden testRunner.CollectScenarioErrors(); @@ -626,13 +628,13 @@ this.ScenarioSetup(scenarioInfo); { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I should be able to filter users by status", new string[] { "filtering"}); -#line 228 -this.ScenarioSetup(scenarioInfo); #line 229 - testRunner.Given("I have installed Orchard"); +this.ScenarioSetup(scenarioInfo); #line 230 + testRunner.Given("I have installed Orchard"); +#line 231 testRunner.When("I go to \"admin/users\""); -#line 232 +#line 233 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table20 = new TechTalk.SpecFlow.Table(new string[] { @@ -650,13 +652,13 @@ this.ScenarioSetup(scenarioInfo); table20.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 233 +#line 234 testRunner.And("I fill in", ((string)(null)), table20); -#line 239 - testRunner.And("I hit \"Save\""); #line 240 + testRunner.And("I hit \"Save\""); +#line 241 testRunner.And("I am redirected"); -#line 242 +#line 243 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table21 = new TechTalk.SpecFlow.Table(new string[] { @@ -674,15 +676,15 @@ this.ScenarioSetup(scenarioInfo); table21.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 243 +#line 244 testRunner.And("I fill in", ((string)(null)), table21); -#line 249 - testRunner.And("I hit \"Save\""); #line 250 - testRunner.And("I am redirected"); + testRunner.And("I hit \"Save\""); #line 251 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I am redirected"); #line 252 + testRunner.Then("I should see \"]*>user1\""); +#line 253 testRunner.And("I should see \"]*>user2\""); #line hidden TechTalk.SpecFlow.Table table22 = new TechTalk.SpecFlow.Table(new string[] { @@ -691,17 +693,17 @@ this.ScenarioSetup(scenarioInfo); table22.AddRow(new string[] { "Options.Search", "user1"}); -#line 253 +#line 254 testRunner.When("I fill in", ((string)(null)), table22); -#line 256 - testRunner.And("I hit \"Filter\""); #line 257 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 258 - testRunner.When("I follow \"Disable\""); + testRunner.Then("I should see \"]*>user1\""); #line 259 - testRunner.And("I am redirected"); + testRunner.When("I follow \"Disable\""); #line 260 + testRunner.And("I am redirected"); +#line 261 testRunner.Then("I should see \"User user1 disabled\""); #line hidden TechTalk.SpecFlow.Table table23 = new TechTalk.SpecFlow.Table(new string[] { @@ -710,15 +712,15 @@ this.ScenarioSetup(scenarioInfo); table23.AddRow(new string[] { "Options.Filter", "Pending"}); -#line 261 +#line 262 testRunner.When("I fill in", ((string)(null)), table23); -#line 264 - testRunner.And("I hit \"Filter\""); #line 265 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 266 - testRunner.And("I should not see \"]*>user2\""); + testRunner.Then("I should see \"]*>user1\""); #line 267 + testRunner.And("I should not see \"]*>user2\""); +#line 268 testRunner.And("I should not see \"]*>admin\""); #line hidden TechTalk.SpecFlow.Table table24 = new TechTalk.SpecFlow.Table(new string[] { @@ -727,15 +729,15 @@ this.ScenarioSetup(scenarioInfo); table24.AddRow(new string[] { "Options.Filter", "EmailPending"}); -#line 268 +#line 269 testRunner.When("I fill in", ((string)(null)), table24); -#line 271 - testRunner.And("I hit \"Filter\""); #line 272 - testRunner.Then("I should not see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 273 - testRunner.And("I should not see \"]*>user2\""); + testRunner.Then("I should not see \"]*>user1\""); #line 274 + testRunner.And("I should not see \"]*>user2\""); +#line 275 testRunner.And("I should not see \"]*>admin\""); #line hidden TechTalk.SpecFlow.Table table25 = new TechTalk.SpecFlow.Table(new string[] { @@ -744,15 +746,15 @@ this.ScenarioSetup(scenarioInfo); table25.AddRow(new string[] { "Options.Filter", "Approved"}); -#line 275 +#line 276 testRunner.When("I fill in", ((string)(null)), table25); -#line 278 - testRunner.And("I hit \"Filter\""); #line 279 - testRunner.Then("I should not see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 280 - testRunner.And("I should see \"]*>user2\""); + testRunner.Then("I should not see \"]*>user1\""); #line 281 + testRunner.And("I should see \"]*>user2\""); +#line 282 testRunner.And("I should see \"]*>admin\""); #line hidden TechTalk.SpecFlow.Table table26 = new TechTalk.SpecFlow.Table(new string[] { @@ -761,15 +763,15 @@ this.ScenarioSetup(scenarioInfo); table26.AddRow(new string[] { "Options.Filter", "All"}); -#line 282 +#line 283 testRunner.When("I fill in", ((string)(null)), table26); -#line 285 - testRunner.And("I hit \"Filter\""); #line 286 - testRunner.Then("I should see \"]*>user1\""); + testRunner.And("I hit \"Filter\""); #line 287 - testRunner.And("I should see \"]*>user2\""); + testRunner.Then("I should see \"]*>user1\""); #line 288 + testRunner.And("I should see \"]*>user2\""); +#line 289 testRunner.And("I should see \"]*>admin\""); #line hidden testRunner.CollectScenarioErrors(); @@ -782,13 +784,13 @@ this.ScenarioSetup(scenarioInfo); { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I should not be able to add users with invalid email addresses", new string[] { "email"}); -#line 290 -this.ScenarioSetup(scenarioInfo); #line 291 - testRunner.Given("I have installed Orchard"); +this.ScenarioSetup(scenarioInfo); #line 292 - testRunner.When("I go to \"admin/users\""); + testRunner.Given("I have installed Orchard"); #line 293 + testRunner.When("I go to \"admin/users\""); +#line 294 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table27 = new TechTalk.SpecFlow.Table(new string[] { @@ -806,11 +808,11 @@ this.ScenarioSetup(scenarioInfo); table27.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 294 +#line 295 testRunner.And("I fill in", ((string)(null)), table27); -#line 300 - testRunner.And("I hit \"Save\""); #line 301 + testRunner.And("I hit \"Save\""); +#line 302 testRunner.Then("I should see \"You must specify a valid email address.\""); #line hidden testRunner.CollectScenarioErrors(); @@ -823,13 +825,13 @@ this.ScenarioSetup(scenarioInfo); { TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("I should be able to add users with valid email addresses", new string[] { "email"}); -#line 303 -this.ScenarioSetup(scenarioInfo); #line 304 - testRunner.Given("I have installed Orchard"); +this.ScenarioSetup(scenarioInfo); #line 305 - testRunner.When("I go to \"admin/users\""); + testRunner.Given("I have installed Orchard"); #line 306 + testRunner.When("I go to \"admin/users\""); +#line 307 testRunner.And("I follow \"Add a new user\""); #line hidden TechTalk.SpecFlow.Table table28 = new TechTalk.SpecFlow.Table(new string[] { @@ -847,13 +849,13 @@ this.ScenarioSetup(scenarioInfo); table28.AddRow(new string[] { "ConfirmPassword", "a12345!"}); -#line 307 +#line 308 testRunner.And("I fill in", ((string)(null)), table28); -#line 313 - testRunner.And("I hit \"Save\""); #line 314 - testRunner.And("I am redirected"); + testRunner.And("I hit \"Save\""); #line 315 + testRunner.And("I am redirected"); +#line 316 testRunner.Then("I should see \"User created\""); #line hidden testRunner.CollectScenarioErrors();