Files
Umbraco-CMS/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs

1111 lines
51 KiB
C#
Raw Normal View History

// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
2018-06-29 19:52:40 +02:00
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Netcore: Migrate RepositoryBase and ContentTypeServiceBase events (#10141) * Remove ScopeEntityRemove from ContentRepositoryBase and rely on "ing" notifications * Remove old event handler from ContentEventsTests * Remove ScopedVersionRemove from ContentRepositoryBase and rely on service notifications instead * Remove unused ScopedVersionEventArgs from ContentRepositoryBase * Migrate ScopeEntityRefresh to notification pattern Unfortunately it's still published from the repository base * Add simple content type notifications * Publish Notifications instead of events in ContentTypeServiceBase for simple events * Switch OnChanged to use Notifications for ContentTypeServices * Publish notifications instead of raising ScopedRefreshedEntity on ContentTypeServiceBase * Hook up to the new ContentType notifications * Remove DistributedCacheBinderTests There are no longer any events to really test on. * Remove ContentTypeChange EventArgs * Remove ContentService_Copied from DistributedCacheBinder It's no longer used * Cleanup * Cleanup * Removed uncommented code * Fixed issue with unattented installs * Re-add ContentTreeChangeNotification to DistributedCache * Add new notification for ScopedEntityRemove Marked as obsolete/hidden in editor, since this should only be used for nucache for now, and should really be changed in the future * Mark Refresh notifications as obsolete/hidden These should not be used anywhere outside Nucache, and should be changed to tree change at some point. * Raise ScopedEntityRemoveNotification on repos and use in nucache Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-04-20 12:17:11 +02:00
using Moq;
2018-06-29 19:52:40 +02:00
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Configuration.Models;
Netcore: Migrate RepositoryBase and ContentTypeServiceBase events (#10141) * Remove ScopeEntityRemove from ContentRepositoryBase and rely on "ing" notifications * Remove old event handler from ContentEventsTests * Remove ScopedVersionRemove from ContentRepositoryBase and rely on service notifications instead * Remove unused ScopedVersionEventArgs from ContentRepositoryBase * Migrate ScopeEntityRefresh to notification pattern Unfortunately it's still published from the repository base * Add simple content type notifications * Publish Notifications instead of events in ContentTypeServiceBase for simple events * Switch OnChanged to use Notifications for ContentTypeServices * Publish notifications instead of raising ScopedRefreshedEntity on ContentTypeServiceBase * Hook up to the new ContentType notifications * Remove DistributedCacheBinderTests There are no longer any events to really test on. * Remove ContentTypeChange EventArgs * Remove ContentService_Copied from DistributedCacheBinder It's no longer used * Cleanup * Cleanup * Removed uncommented code * Fixed issue with unattented installs * Re-add ContentTreeChangeNotification to DistributedCache * Add new notification for ScopedEntityRemove Marked as obsolete/hidden in editor, since this should only be used for nucache for now, and should really be changed in the future * Mark Refresh notifications as obsolete/hidden These should not be used anywhere outside Nucache, and should be changed to tree change at some point. * Raise ScopedEntityRemoveNotification on repos and use in nucache Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-04-20 12:17:11 +02:00
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence;
using Umbraco.Cms.Core.Persistence.Querying;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
2018-06-29 19:52:40 +02:00
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories
2018-06-29 19:52:40 +02:00
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
2020-10-09 13:08:23 +02:00
public class DocumentRepositoryTest : UmbracoIntegrationTest
2018-06-29 19:52:40 +02:00
{
2020-10-09 13:08:23 +02:00
private ContentType _contentType;
private Content _textpage;
private Content _subpage;
private Content _subpage2;
private Content _trashed;
private IContentService ContentService => GetRequiredService<IContentService>();
2020-10-09 13:08:23 +02:00
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
2020-10-09 13:08:23 +02:00
private IFileService FileService => GetRequiredService<IFileService>();
2020-10-09 13:08:23 +02:00
private IDataTypeService DataTypeService => GetRequiredService<IDataTypeService>();
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
private FileSystems FileSystems => GetRequiredService<FileSystems>();
private IConfigurationEditorJsonSerializer ConfigurationEditorJsonSerializer => GetRequiredService<IConfigurationEditorJsonSerializer>();
2020-10-09 13:08:23 +02:00
[SetUp]
public void SetUpData()
2018-06-29 19:52:40 +02:00
{
CreateTestData();
ContentRepositoryBase.ThrowOnWarning = true;
}
[TearDown]
public void Teardown() => ContentRepositoryBase.ThrowOnWarning = false;
2018-06-29 19:52:40 +02:00
2020-10-09 13:08:23 +02:00
public void CreateTestData()
{
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
// Create and Save ContentType "umbTextpage" -> (_contentType.Id)
_contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: template.Id);
2020-10-09 13:08:23 +02:00
_contentType.Key = new Guid("1D3A8E6E-2EA9-4CC1-B229-1AEE19821522");
ContentTypeService.Save(_contentType);
// Create and Save Content "Homepage" based on "umbTextpage" -> (_textpage.Id)
2020-10-09 13:08:23 +02:00
_textpage = ContentBuilder.CreateSimpleContent(_contentType);
_textpage.Key = new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0");
ContentService.Save(_textpage, 0);
// Create and Save Content "Text Page 1" based on "umbTextpage" -> (_subpage.Id)
2020-10-09 13:08:23 +02:00
_subpage = ContentBuilder.CreateSimpleContent(_contentType, "Text Page 1", _textpage.Id);
_subpage.Key = new Guid("FF11402B-7E53-4654-81A7-462AC2108059");
ContentService.Save(_subpage, 0);
// Create and Save Content "Text Page 1" based on "umbTextpage" -> (_subpage2.Id)
2020-10-09 13:08:23 +02:00
_subpage2 = ContentBuilder.CreateSimpleContent(_contentType, "Text Page 2", _textpage.Id);
ContentService.Save(_subpage2, 0);
// Create and Save Content "Text Page Deleted" based on "umbTextpage" -> (_trashed.Id)
2020-10-09 13:08:23 +02:00
_trashed = ContentBuilder.CreateSimpleContent(_contentType, "Text Page Deleted", -20);
_trashed.Trashed = true;
ContentService.Save(_trashed, 0);
}
2019-01-17 08:34:29 +01:00
private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out DataTypeRepository dtdRepository, AppCaches appCaches = null)
2018-06-29 19:52:40 +02:00
{
appCaches ??= AppCaches;
2018-06-29 19:52:40 +02:00
DocumentRepository ctRepository = CreateRepository(scopeAccessor, out contentTypeRepository, out TemplateRepository tr);
var editors = new PropertyEditorCollection(new DataEditorCollection(() => Enumerable.Empty<IDataEditor>()));
dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, editors, LoggerFactory.CreateLogger<DataTypeRepository>(), LoggerFactory, ConfigurationEditorJsonSerializer);
2018-06-29 19:52:40 +02:00
return ctRepository;
}
private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, AppCaches appCaches = null) =>
CreateRepository(scopeAccessor, out contentTypeRepository, out TemplateRepository tr, appCaches);
2018-06-29 19:52:40 +02:00
2019-01-17 08:34:29 +01:00
private DocumentRepository CreateRepository(IScopeAccessor scopeAccessor, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository, AppCaches appCaches = null)
2018-06-29 19:52:40 +02:00
{
IOptions<GlobalSettings> globalSettings = Options.Create(new GlobalSettings());
2020-08-24 16:06:09 +02:00
appCaches ??= AppCaches;
2018-06-29 19:52:40 +02:00
templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, Mock.Of<IViewHelper>());
var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TagRepository>());
var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper);
var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<LanguageRepository>(), globalSettings);
contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<ContentTypeRepository>(), commonRepository, languageRepository, ShortStringHelper);
var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger<RelationTypeRepository>());
var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled);
var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger<RelationRepository>(), relationTypeRepository, entityRepository);
var propertyEditors = new PropertyEditorCollection(new DataEditorCollection(() => Enumerable.Empty<IDataEditor>()));
var dataValueReferences = new DataValueReferenceFactoryCollection(() => Enumerable.Empty<IDataValueReferenceFactory>());
var repository = new DocumentRepository(
scopeAccessor,
appCaches,
LoggerFactory.CreateLogger<DocumentRepository>(),
LoggerFactory,
contentTypeRepository,
templateRepository,
tagRepository,
languageRepository,
relationRepository,
relationTypeRepository,
propertyEditors,
dataValueReferences,
DataTypeService,
Netcore: Migrate RepositoryBase and ContentTypeServiceBase events (#10141) * Remove ScopeEntityRemove from ContentRepositoryBase and rely on "ing" notifications * Remove old event handler from ContentEventsTests * Remove ScopedVersionRemove from ContentRepositoryBase and rely on service notifications instead * Remove unused ScopedVersionEventArgs from ContentRepositoryBase * Migrate ScopeEntityRefresh to notification pattern Unfortunately it's still published from the repository base * Add simple content type notifications * Publish Notifications instead of events in ContentTypeServiceBase for simple events * Switch OnChanged to use Notifications for ContentTypeServices * Publish notifications instead of raising ScopedRefreshedEntity on ContentTypeServiceBase * Hook up to the new ContentType notifications * Remove DistributedCacheBinderTests There are no longer any events to really test on. * Remove ContentTypeChange EventArgs * Remove ContentService_Copied from DistributedCacheBinder It's no longer used * Cleanup * Cleanup * Removed uncommented code * Fixed issue with unattented installs * Re-add ContentTreeChangeNotification to DistributedCache * Add new notification for ScopedEntityRemove Marked as obsolete/hidden in editor, since this should only be used for nucache for now, and should really be changed in the future * Mark Refresh notifications as obsolete/hidden These should not be used anywhere outside Nucache, and should be changed to tree change at some point. * Raise ScopedEntityRemoveNotification on repos and use in nucache Co-authored-by: Bjarke Berg <mail@bergmania.dk>
2021-04-20 12:17:11 +02:00
ConfigurationEditorJsonSerializer,
Mock.Of<IEventAggregator>());
2018-06-29 19:52:40 +02:00
return repository;
}
[Test]
public void CacheActiveForIntsAndGuids()
{
2019-01-17 08:34:29 +01:00
var realCache = new AppCaches(
new ObjectCacheAppCache(),
2019-01-18 08:29:16 +01:00
new DictionaryAppCache(),
new IsolatedCaches(t => new ObjectCacheAppCache()));
2018-06-29 19:52:40 +02:00
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository, appCaches: realCache);
2018-06-29 19:52:40 +02:00
IUmbracoDatabase udb = scope.Database;
2018-06-29 19:52:40 +02:00
udb.EnableSqlCount = false;
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id);
2020-10-09 13:08:23 +02:00
2018-06-29 19:52:40 +02:00
contentTypeRepository.Save(contentType);
Content content = ContentBuilder.CreateSimpleContent(contentType);
2018-06-29 19:52:40 +02:00
repository.Save(content);
udb.EnableSqlCount = true;
// go get it, this should already be cached since the default repository key is the INT
2018-06-29 19:52:40 +02:00
repository.Get(content.Id);
Assert.AreEqual(0, udb.SqlCount);
// retrieve again, this should use cache
2018-06-29 19:52:40 +02:00
repository.Get(content.Id);
Assert.AreEqual(0, udb.SqlCount);
// reset counter
2018-06-29 19:52:40 +02:00
udb.EnableSqlCount = false;
udb.EnableSqlCount = true;
// now get by GUID, this won't be cached yet because the default repo key is not a GUID
2018-06-29 19:52:40 +02:00
repository.Get(content.Key);
int sqlCount = udb.SqlCount;
2018-06-29 19:52:40 +02:00
Assert.Greater(sqlCount, 0);
// retrieve again, this should use cache now
2018-06-29 19:52:40 +02:00
repository.Get(content.Key);
Assert.AreEqual(sqlCount, udb.SqlCount);
}
}
[Test]
public void CreateVersions()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository, out DataTypeRepository _);
2018-06-29 19:52:40 +02:00
var versions = new List<int>();
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
ContentType hasPropertiesContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id);
2018-06-29 19:52:40 +02:00
2019-02-05 19:58:33 +01:00
contentTypeRepository.Save(hasPropertiesContentType);
2020-10-09 13:08:23 +02:00
IContent content1 = ContentBuilder.CreateSimpleContent(hasPropertiesContentType);
2018-06-29 19:52:40 +02:00
// save = create the initial version
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // the first version
// publish = new edit version
content1.SetValue("title", "title");
2019-04-02 10:46:37 +02:00
content1.PublishCulture(CultureImpact.Invariant);
content1.PublishedState = PublishedState.Publishing;
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // NEW VERSION
// new edit version has been created
Assert.AreNotEqual(versions[^2], versions[^1]);
2018-06-29 19:52:40 +02:00
Assert.IsTrue(content1.Published);
Assert.AreEqual(PublishedState.Published, ((Content)content1).PublishedState);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(true, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// change something
// save = update the current (draft) version
content1.Name = "name-1";
content1.SetValue("title", "title-1");
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // the same version
// no new version has been created
Assert.AreEqual(versions[^2], versions[^1]);
2018-06-29 19:52:40 +02:00
Assert.IsTrue(content1.Published);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(true, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// unpublish = no impact on versions
((Content)content1).PublishedState = PublishedState.Unpublishing;
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // the same version
// no new version has been created
Assert.AreEqual(versions[^2], versions[^1]);
2018-06-29 19:52:40 +02:00
Assert.IsFalse(content1.Published);
Assert.AreEqual(PublishedState.Unpublished, ((Content)content1).PublishedState);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(false, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// change something
// save = update the current (draft) version
content1.Name = "name-2";
content1.SetValue("title", "title-2");
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // the same version
// no new version has been created
Assert.AreEqual(versions[^2], versions[^1]);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(false, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// publish = version
2019-04-02 10:46:37 +02:00
content1.PublishCulture(CultureImpact.Invariant);
content1.PublishedState = PublishedState.Publishing;
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // NEW VERSION
// new version has been created
Assert.AreNotEqual(versions[^2], versions[^1]);
2018-06-29 19:52:40 +02:00
Assert.IsTrue(content1.Published);
Assert.AreEqual(PublishedState.Published, ((Content)content1).PublishedState);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(true, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// change something
// save = update the current (draft) version
content1.Name = "name-3";
content1.SetValue("title", "title-3");
//// Thread.Sleep(2000); // force date change
2018-06-29 19:52:40 +02:00
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // the same version
// no new version has been created
Assert.AreEqual(versions[^2], versions[^1]);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(true, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// publish = new version
content1.Name = "name-4";
content1.SetValue("title", "title-4");
2019-04-02 10:46:37 +02:00
content1.PublishCulture(CultureImpact.Invariant);
content1.PublishedState = PublishedState.Publishing;
repository.Save(content1);
2018-06-29 19:52:40 +02:00
versions.Add(content1.VersionId); // NEW VERSION
// a new version has been created
Assert.AreNotEqual(versions[^2], versions[^1]);
2018-06-29 19:52:40 +02:00
Assert.IsTrue(content1.Published);
Assert.AreEqual(PublishedState.Published, ((Content)content1).PublishedState);
Assert.AreEqual(versions[^1], repository.Get(content1.Id).VersionId);
2018-06-29 19:52:40 +02:00
// misc checks
Assert.AreEqual(true, scope.Database.ExecuteScalar<bool>($"SELECT published FROM {Constants.DatabaseSchema.Tables.Document} WHERE nodeId=@id", new { id = content1.Id }));
// all versions
IContent[] allVersions = repository.GetAllVersions(content1.Id).ToArray();
2018-06-29 19:52:40 +02:00
Console.WriteLine();
foreach (int v in versions)
{
2018-06-29 19:52:40 +02:00
Console.WriteLine(v);
}
2018-06-29 19:52:40 +02:00
Console.WriteLine();
foreach (IContent v in allVersions)
2018-06-29 19:52:40 +02:00
{
var c = (Content)v;
Console.WriteLine($"{c.Id} {c.VersionId} {(c.Published ? "+" : "-")}pub pk={c.VersionId} ppk={c.PublishedVersionId} name=\"{c.Name}\" pname=\"{c.PublishName}\"");
}
// get older version
IContent content = repository.GetVersion(versions[^4]);
2018-06-29 19:52:40 +02:00
Assert.AreNotEqual(0, content.VersionId);
Assert.AreEqual(versions[^4], content.VersionId);
2018-06-29 19:52:40 +02:00
Assert.AreEqual("name-4", content1.Name);
Assert.AreEqual("title-4", content1.GetValue("title"));
Assert.AreEqual("name-2", content.Name);
Assert.AreEqual("title-2", content.GetValue("title"));
// get all versions - most recent first
allVersions = repository.GetAllVersions(content1.Id).ToArray();
int[] expVersions = versions.Distinct().Reverse().ToArray();
2018-06-29 19:52:40 +02:00
Assert.AreEqual(expVersions.Length, allVersions.Length);
for (int i = 0; i < expVersions.Length; i++)
{
2018-06-29 19:52:40 +02:00
Assert.AreEqual(expVersions[i], allVersions[i].VersionId);
}
2018-06-29 19:52:40 +02:00
}
}
/// <summary>
/// This tests the regression issue of U4-9438
/// </summary>
/// <remarks>
/// The problem was the iteration of the property data in VersionableRepositoryBase when a content item
/// in the list actually doesn't have any property types, it would still skip over a property row.
/// To test, we have 3 content items, the first has properties, the second doesn't and the third does.
/// </remarks>
[Test]
public void PropertyDataAssignedCorrectly()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository, out DataTypeRepository _);
2018-06-29 19:52:40 +02:00
ContentType emptyContentType = ContentTypeBuilder.CreateBasicContentType();
ContentType hasPropertiesContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id);
contentTypeRepository.Save(emptyContentType);
contentTypeRepository.Save(hasPropertiesContentType);
Content content1 = ContentBuilder.CreateSimpleContent(hasPropertiesContentType);
Content content2 = ContentBuilder.CreateBasicContent(emptyContentType);
Content content3 = ContentBuilder.CreateSimpleContent(hasPropertiesContentType);
2018-06-29 19:52:40 +02:00
repository.Save(content1);
repository.Save(content2);
repository.Save(content3);
// this will cause the GetPropertyCollection to execute and we need to ensure that
// all of the properties and property types are all correct
IContent[] result = repository.GetMany(content1.Id, content2.Id, content3.Id).ToArray();
IContent n1 = result[0];
IContent n2 = result[1];
IContent n3 = result[2];
2018-06-29 19:52:40 +02:00
Assert.AreEqual(content1.Id, n1.Id);
Assert.AreEqual(content2.Id, n2.Id);
Assert.AreEqual(content3.Id, n3.Id);
// compare everything including properties and their values
// this ensures that they have been properly retrieved
TestHelper.AssertPropertyValuesAreEqual(content1, n1);
TestHelper.AssertPropertyValuesAreEqual(content2, n2);
TestHelper.AssertPropertyValuesAreEqual(content3, n3);
}
}
//// /// <summary>
//// /// This test ensures that when property values using special database fields are saved, the actual data in the
//// /// object being stored is also transformed in the same way as the data being stored in the database is.
//// /// Before you would see that ex: a decimal value being saved as 100 or "100", would be that exact value in the
//// /// object, but the value saved to the database was actually 100.000000.
//// /// When querying the database for the value again - the value would then differ from what is in the object.
//// /// This caused inconsistencies between saving+publishing and simply saving and then publishing, due to the former
//// /// sending the non-transformed data directly on to publishing.
//// /// </summary>
//// [Test]
//// public void PropertyValuesWithSpecialTypes()
//// {
//// var provider = ScopeProvider;
//// using (var scope = provider.CreateScope())
//// {
//// var repository = CreateRepository((IScopeAccessor)provider, out var contentTypeRepository, out DataTypeRepository dataTypeDefinitionRepository);
////
//// var editor = new DecimalPropertyEditor(LoggerFactory, DataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper);
//// var dtd = new DataType(editor) { Name = "test", DatabaseType = ValueStorageType.Decimal };
//// dataTypeDefinitionRepository.Save(dtd);
////
//// const string decimalPropertyAlias = "decimalProperty";
//// const string intPropertyAlias = "intProperty";
//// const string dateTimePropertyAlias = "datetimeProperty";
//// var dateValue = new DateTime(2016, 1, 6);
////
//// var propertyTypeCollection = new PropertyTypeCollection(true,
//// new List<PropertyType>
//// {
//// MockedPropertyTypes.CreateDecimalProperty(decimalPropertyAlias, "Decimal property", dtd.Id),
//// MockedPropertyTypes.CreateIntegerProperty(intPropertyAlias, "Integer property"),
//// MockedPropertyTypes.CreateDateTimeProperty(dateTimePropertyAlias, "DateTime property")
//// });
//// var contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", propertyTypeCollection);
//// contentTypeRepository.Save(contentType);
////
//// // int and decimal values are passed in as strings as they would be from the backoffice UI
//// var textpage = ContentBuilder.CreateSimpleContentWithSpecialDatabaseTypes(contentType, "test@umbraco.org", -1, "100", "150", dateValue);
////
//// repository.Save(textpage);
//// scope.Complete();
////
//// Assert.That(contentType.HasIdentity, Is.True);
//// Assert.That(textpage.HasIdentity, Is.True);
////
//// var persistedTextpage = repository.Get(textpage.Id);
//// Assert.That(persistedTextpage.Name, Is.EqualTo(textpage.Name));
//// Assert.AreEqual(100m, persistedTextpage.GetValue(decimalPropertyAlias));
//// Assert.AreEqual(persistedTextpage.GetValue(decimalPropertyAlias), textpage.GetValue(decimalPropertyAlias));
//// Assert.AreEqual(150, persistedTextpage.GetValue(intPropertyAlias));
//// Assert.AreEqual(persistedTextpage.GetValue(intPropertyAlias), textpage.GetValue(intPropertyAlias));
//// Assert.AreEqual(dateValue, persistedTextpage.GetValue(dateTimePropertyAlias));
//// Assert.AreEqual(persistedTextpage.GetValue(dateTimePropertyAlias), textpage.GetValue(dateTimePropertyAlias));
//// }
//// }
2018-06-29 19:52:40 +02:00
[Test]
public void SaveContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository);
ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage2", "Textpage", defaultTemplateId: template.Id);
2019-02-05 19:58:33 +01:00
contentTypeRepository.Save(contentType);
2020-10-09 13:08:23 +02:00
IContent textpage = ContentBuilder.CreateSimpleContent(contentType);
2018-06-29 19:52:40 +02:00
repository.Save(textpage);
scope.Complete();
Assert.That(contentType.HasIdentity, Is.True);
Assert.That(textpage.HasIdentity, Is.True);
}
}
2018-06-29 19:52:40 +02:00
[Test]
public void SaveContentWithDefaultTemplate()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository);
2018-06-29 19:52:40 +02:00
var template = new Template(ShortStringHelper, "hello", "hello");
templateRepository.Save(template);
ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage2", "Textpage");
2018-06-29 19:52:40 +02:00
contentType.AllowedTemplates = Enumerable.Empty<ITemplate>(); // because CreateSimpleContentType assigns one already
contentType.SetDefaultTemplate(template);
contentTypeRepository.Save(contentType);
Content textpage = ContentBuilder.CreateSimpleContent(contentType);
repository.Save(textpage);
IContent fetched = repository.Get(textpage.Id);
2018-06-29 19:52:40 +02:00
Assert.True(textpage.TemplateId.HasValue);
Assert.NotZero(textpage.TemplateId.Value);
Assert.AreEqual(textpage.TemplateId, contentType.DefaultTemplate.Id);
2018-06-29 19:52:40 +02:00
scope.Complete();
TestHelper.AssertPropertyValuesAreEqual(textpage, fetched);
2018-06-29 19:52:40 +02:00
}
}
// Covers issue U4-2791 and U4-2607
2018-06-29 19:52:40 +02:00
[Test]
public void SaveContentWithAtSignInName()
{
// Arrange
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository);
ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id);
contentTypeRepository.Save(contentType);
Content textpage = ContentBuilder.CreateSimpleContent(contentType, "test@umbraco.org");
Content anotherTextpage = ContentBuilder.CreateSimpleContent(contentType, "@lightgiants");
2018-06-29 19:52:40 +02:00
repository.Save(textpage);
repository.Save(anotherTextpage);
2018-06-29 19:52:40 +02:00
Assert.That(contentType.HasIdentity, Is.True);
Assert.That(textpage.HasIdentity, Is.True);
IContent content = repository.Get(textpage.Id);
2018-06-29 19:52:40 +02:00
Assert.That(content.Name, Is.EqualTo(textpage.Name));
IContent content2 = repository.Get(anotherTextpage.Id);
2018-06-29 19:52:40 +02:00
Assert.That(content2.Name, Is.EqualTo(anotherTextpage.Name));
scope.Complete();
}
}
[Test]
public void SaveContentMultiple()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository);
ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage1", "Textpage", defaultTemplateId: template.Id);
2019-02-05 19:58:33 +01:00
contentTypeRepository.Save(contentType);
Content textpage = ContentBuilder.CreateSimpleContent(contentType);
2018-06-29 19:52:40 +02:00
repository.Save(textpage);
Content subpage = ContentBuilder.CreateSimpleContent(contentType, "Text Page 1", textpage.Id);
repository.Save(subpage);
2018-06-29 19:52:40 +02:00
Assert.That(contentType.HasIdentity, Is.True);
Assert.That(textpage.HasIdentity, Is.True);
Assert.That(subpage.HasIdentity, Is.True);
Assert.That(textpage.Id, Is.EqualTo(subpage.ParentId));
}
}
[Test]
public void GetContentIsNotDirty()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IContent content = repository.Get(_subpage2.Id);
bool dirty = ((Content)content).IsDirty();
2018-06-29 19:52:40 +02:00
Assert.That(dirty, Is.False);
}
}
[Test]
public void UpdateContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IContent content = repository.Get(_subpage.Id);
2018-06-29 19:52:40 +02:00
content.Name = "About 2";
repository.Save(content);
IContent updatedContent = repository.Get(_subpage.Id);
2018-06-29 19:52:40 +02:00
Assert.AreEqual(content.Id, updatedContent.Id);
Assert.AreEqual(content.Name, updatedContent.Name);
Assert.AreEqual(content.VersionId, updatedContent.VersionId);
Assert.AreEqual(content.GetValue("title"), "Welcome to our Home page");
content.SetValue("title", "toot");
repository.Save(content);
2020-10-09 13:08:23 +02:00
updatedContent = repository.Get(_subpage.Id);
2018-06-29 19:52:40 +02:00
Assert.AreEqual("toot", updatedContent.GetValue("title"));
Assert.AreEqual(content.VersionId, updatedContent.VersionId);
}
}
[Test]
public void UpdateContentWithNullTemplate()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IContent content = repository.Get(_subpage.Id);
2018-11-13 16:20:11 +00:00
content.TemplateId = null;
repository.Save(content);
IContent updatedContent = repository.Get(_subpage.Id);
2018-06-29 19:52:40 +02:00
Assert.False(updatedContent.TemplateId.HasValue);
2018-06-29 19:52:40 +02:00
}
}
[Test]
public void DeleteContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out ContentTypeRepository contentTypeRepository);
IContentType contentType = contentTypeRepository.Get(_contentType.Id);
var content = new Content("Textpage 2 Child Node", _trashed.Id, contentType)
{
CreatorId = 0,
WriterId = 0
};
2018-06-29 19:52:40 +02:00
repository.Save(content);
int id = content.Id;
2018-06-29 19:52:40 +02:00
repository.Delete(content);
IContent content1 = repository.Get(id);
2018-06-29 19:52:40 +02:00
Assert.IsNull(content1);
}
}
[Test]
public void GetContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
IContent content = repository.Get(_subpage2.Id);
2018-06-29 19:52:40 +02:00
2020-10-09 13:08:23 +02:00
Assert.AreEqual(_subpage2.Id, content.Id);
2018-06-29 19:52:40 +02:00
Assert.That(content.CreateDate, Is.GreaterThan(DateTime.MinValue));
Assert.That(content.UpdateDate, Is.GreaterThan(DateTime.MinValue));
Assert.AreNotEqual(0, content.ParentId);
Assert.AreEqual("Text Page 2", content.Name);
Assert.AreNotEqual(0, content.VersionId);
2020-10-09 13:08:23 +02:00
Assert.AreEqual(_contentType.Id, content.ContentTypeId);
2018-06-29 19:52:40 +02:00
Assert.That(content.Path, Is.Not.Empty);
Assert.That(content.Properties.Any(), Is.True);
}
}
[Test]
public void QueryContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
IEnumerable<IContent> result = repository.Get(query);
2018-06-29 19:52:40 +02:00
Assert.GreaterOrEqual(2, result.Count());
}
}
[Test]
public void GetAllContentManyVersions()
{
IContent[] result;
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
result = repository.GetMany().ToArray();
// save them all
foreach (IContent content in result)
2018-06-29 19:52:40 +02:00
{
content.SetValue("title", content.GetValue<string>("title") + "x");
repository.Save(content);
}
// publish them all
foreach (IContent content in result)
2018-06-29 19:52:40 +02:00
{
2019-04-02 10:46:37 +02:00
content.PublishCulture(CultureImpact.Invariant);
2018-06-29 19:52:40 +02:00
repository.Save(content);
}
2018-06-29 19:52:40 +02:00
scope.Complete();
}
// get them all again
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
IContent[] result2 = repository.GetMany().ToArray();
2018-06-29 19:52:40 +02:00
Assert.AreEqual(result.Length, result2.Length);
}
}
[Test]
2018-07-17 17:20:40 +02:00
public void AliasRegexTest()
2018-06-29 19:52:40 +02:00
{
Merge remote-tracking branch 'origin/v8/dev' into netcore/dev # Conflicts: # build/NuSpecs/UmbracoCms.Core.nuspec # build/NuSpecs/UmbracoCms.Web.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/CacheKeys.cs # src/Umbraco.Core/Composing/TypeFinder.cs # src/Umbraco.Core/Configuration/GlobalSettings.cs # src/Umbraco.Core/Configuration/GlobalSettingsExtensions.cs # src/Umbraco.Core/Configuration/IGlobalSettings.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentSectionExtensions.cs # src/Umbraco.Core/Constants-AppSettings.cs # src/Umbraco.Core/Editors/UserEditorAuthorizationHelper.cs # src/Umbraco.Core/Extensions/StringExtensions.cs # src/Umbraco.Core/Extensions/UriExtensions.cs # src/Umbraco.Core/IO/IOHelper.cs # src/Umbraco.Core/IO/PhysicalFileSystem.cs # src/Umbraco.Core/Media/Exif/MathEx.cs # src/Umbraco.Core/Media/UploadAutoFillProperties.cs # src/Umbraco.Core/Models/Mapping/UserMapDefinition.cs # src/Umbraco.Core/Models/Membership/User.cs # src/Umbraco.Core/Models/UserExtensions.cs # src/Umbraco.Core/Packaging/PackageDefinitionXmlParser.cs # src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs # src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs # src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs # src/Umbraco.Core/Routing/AliasUrlProvider.cs # src/Umbraco.Core/Routing/DefaultUrlProvider.cs # src/Umbraco.Core/Routing/UriUtility.cs # src/Umbraco.Core/Routing/UrlProviderExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Security/BackOfficeUserStore.cs # src/Umbraco.Core/Security/ContentPermissions.cs # src/Umbraco.Core/Sync/ApplicationUrlHelper.cs # src/Umbraco.Core/Trees/TreeNode.cs # src/Umbraco.Core/Udi.cs # src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs # src/Umbraco.Infrastructure/Persistence/SqlSyntax/SqlServerSyntaxProvider.cs # src/Umbraco.Infrastructure/Scoping/Scope.cs # src/Umbraco.Infrastructure/Search/ExamineComponent.cs # src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.Infrastructure/Services/Implement/MediaService.cs # src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs # src/Umbraco.Persistence.SqlCe/SqlCeSyntaxProvider.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/LocksTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Core/Models/UserExtensionsTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Editors/UserEditorAuthorizationHelperTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Examine/UmbracoContentValueSetValidatorTests.cs # src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs # src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config # src/Umbraco.Tests/TestHelpers/SettingsForTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Tests/Web/Controllers/ContentControllerUnitTests.cs # src/Umbraco.Tests/Web/Controllers/FilterAllowedOutgoingContentAttributeTests.cs # src/Umbraco.Tests/Web/Controllers/MediaControllerUnitTests.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/CodeFileController.cs # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs # src/Umbraco.Web.BackOffice/Controllers/EntityController.cs # src/Umbraco.Web.BackOffice/Controllers/MacrosController.cs # src/Umbraco.Web.BackOffice/Controllers/MediaController.cs # src/Umbraco.Web.BackOffice/Controllers/PackageInstallController.cs # src/Umbraco.Web.BackOffice/Controllers/TourController.cs # src/Umbraco.Web.BackOffice/Controllers/UserGroupEditorAuthorizationHelper.cs # src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingContentAttribute.cs # src/Umbraco.Web.BackOffice/Filters/FilterAllowedOutgoingMediaAttribute.cs # src/Umbraco.Web.BackOffice/Mapping/ContentMapDefinition.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeController.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs # src/Umbraco.Web.BackOffice/Trees/FileSystemTreeController.cs # src/Umbraco.Web.BackOffice/Trees/MediaTreeController.cs # src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs # src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js # src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html # src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Cache/MemberCacheRefresher.cs # src/Umbraco.Web/Composing/ModuleInjector.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs # src/Umbraco.Web/Editors/Filters/MediaItemSaveValidationAttribute.cs # src/Umbraco.Web/Editors/Filters/UserGroupAuthorizationAttribute.cs # src/Umbraco.Web/Editors/TinyMceController.cs # src/Umbraco.Web/Editors/UserGroupsController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/ImageCropperTemplateExtensions.cs # src/Umbraco.Web/Logging/WebProfiler.cs # src/Umbraco.Web/Logging/WebProfilerProvider.cs # src/Umbraco.Web/Macros/PublishedContentHashtableConverter.cs # src/Umbraco.Web/Mvc/EnsurePublishedContentRequestAttribute.cs # src/Umbraco.Web/Mvc/JsonNetResult.cs # src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs # src/Umbraco.Web/Mvc/RenderRouteHandler.cs # src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs # src/Umbraco.Web/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Web/RoutableDocumentFilter.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Routing/PublishedRouter.cs # src/Umbraco.Web/Runtime/WebInitialComposer.cs # src/Umbraco.Web/Scheduling/KeepAlive.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/BackOfficeClaimsIdentityFactory.cs # src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs # src/Umbraco.Web/Trees/DictionaryTreeController.cs # src/Umbraco.Web/Trees/LanguageTreeController.cs # src/Umbraco.Web/Trees/LogViewerTreeController.cs # src/Umbraco.Web/Trees/PackagesTreeController.cs # src/Umbraco.Web/UmbracoApplication.cs # src/Umbraco.Web/UmbracoApplicationBase.cs # src/Umbraco.Web/UmbracoInjectedModule.cs # src/Umbraco.Web/WebApi/Filters/AdminUsersAuthorizeAttribute.cs # src/Umbraco.Web/WebApi/Filters/CheckIfUserTicketDataIsStaleAttribute.cs # src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs # src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForMediaAttribute.cs # src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs
2021-03-05 15:36:27 +01:00
System.Text.RegularExpressions.Regex regex = new SqlServerSyntaxProvider(Options.Create(new GlobalSettings())).AliasRegex;
2018-06-29 19:52:40 +02:00
Assert.AreEqual(@"(\[\w+]\.\[\w+])\s+AS\s+(\[\w+])", regex.ToString());
const string sql = "SELECT [table].[column1] AS [alias1], [table].[column2] AS [alias2] FROM [table];";
System.Text.RegularExpressions.MatchCollection matches = regex.Matches(sql);
2018-06-29 19:52:40 +02:00
Assert.AreEqual(2, matches.Count);
Assert.AreEqual("[table].[column1]", matches[0].Groups[1].Value);
Assert.AreEqual("[alias1]", matches[0].Groups[2].Value);
Assert.AreEqual("[table].[column2]", matches[1].Groups[1].Value);
Assert.AreEqual("[alias2]", matches[1].Groups[2].Value);
}
[Test]
public void GetPagedResultsByQuery_With_Variant_Names()
{
// One invariant content type named "umbInvariantTextPage"
Template template = TemplateBuilder.CreateTextPageTemplate();
2020-10-09 13:08:23 +02:00
FileService.SaveTemplate(template);
ContentType invariantCt = ContentTypeBuilder.CreateSimpleContentType("umbInvariantTextpage", "Invariant Textpage", defaultTemplateId: template.Id);
2018-06-20 14:18:57 +02:00
invariantCt.Variations = ContentVariation.Nothing;
foreach (IPropertyType p in invariantCt.PropertyTypes)
{
p.Variations = ContentVariation.Nothing;
}
2020-10-09 13:08:23 +02:00
ContentTypeService.Save(invariantCt);
2018-06-29 19:52:40 +02:00
// One variant (by culture) content type named "umbVariantTextPage"
2018-06-20 14:18:57 +02:00
// with properties, every 2nd one being variant (by culture), the other being invariant
ContentType variantCt = ContentTypeBuilder.CreateSimpleContentType("umbVariantTextpage", "Variant Textpage", defaultTemplateId: template.Id);
2018-06-20 14:18:57 +02:00
variantCt.Variations = ContentVariation.Culture;
2018-05-07 08:26:10 +02:00
var propTypes = variantCt.PropertyTypes.ToList();
for (int i = 0; i < propTypes.Count; i++)
{
IPropertyType p = propTypes[i];
2018-06-20 14:18:57 +02:00
p.Variations = i % 2 == 0 ? ContentVariation.Culture : ContentVariation.Nothing;
}
2020-10-09 13:08:23 +02:00
ContentTypeService.Save(variantCt);
2018-05-07 08:26:10 +02:00
invariantCt.AllowedContentTypes = new[] { new ContentTypeSort(invariantCt.Id, 0), new ContentTypeSort(variantCt.Id, 1) };
2020-10-09 13:08:23 +02:00
ContentTypeService.Save(invariantCt);
// Create content
Content root = ContentBuilder.CreateSimpleContent(invariantCt);
2020-10-09 13:08:23 +02:00
ContentService.Save(root);
2018-06-20 14:18:57 +02:00
var children = new List<IContent>();
for (int i = 0; i < 25; i++)
{
bool isInvariant = i % 2 == 0;
string name = (isInvariant ? "INV" : "VAR") + "_" + Guid.NewGuid();
string culture = isInvariant ? null : "en-US";
Content child = ContentBuilder.CreateSimpleContent(
2018-05-07 08:26:10 +02:00
isInvariant ? invariantCt : variantCt,
name,
root,
culture,
setPropertyValues: isInvariant);
if (!isInvariant)
{
// manually set the property values since we have mixed variant/invariant property types
child.SetValue("title", name + " Subpage", culture: culture);
child.SetValue("bodyText", "This is a subpage", culture: null); // this one is invariant
child.SetValue("author", "John Doe", culture: culture);
}
2020-10-09 13:08:23 +02:00
ContentService.Save(child);
2018-06-20 14:18:57 +02:00
children.Add(child);
}
2018-06-29 19:52:40 +02:00
IContent child1 = children[1];
2018-06-20 14:18:57 +02:00
Assert.IsTrue(child1.ContentType.VariesByCulture());
Assert.IsTrue(child1.Name.StartsWith("VAR"));
Assert.IsTrue(child1.GetCultureName("en-US").StartsWith("VAR"));
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IContent child = repository.Get(children[1].Id); // 1 is variant
2018-06-20 14:18:57 +02:00
Assert.IsTrue(child.ContentType.VariesByCulture());
Assert.IsTrue(child.Name.StartsWith("VAR"));
Assert.IsTrue(child.GetCultureName("en-US").StartsWith("VAR"));
2018-06-29 19:52:40 +02:00
try
{
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.ParentId == root.Id);
IEnumerable<IContent> result = repository.GetPage(query, 0, 20, out long totalRecords, null, Ordering.By("UpdateDate"));
Assert.AreEqual(25, totalRecords);
foreach (IContent r in result)
{
bool isInvariant = r.ContentType.Alias == "umbInvariantTextpage";
string name = isInvariant ? r.Name : r.CultureInfos["en-US"].Name;
string namePrefix = isInvariant ? "INV" : "VAR";
// ensure the correct name (invariant vs variant) is in the result
Assert.IsTrue(name.StartsWith(namePrefix));
foreach (IProperty p in r.Properties)
{
// ensure there is a value for the correct variant/invariant property
object value = p.GetValue(p.PropertyType.Variations.VariesByNothing() ? null : "en-US");
Assert.IsNotNull(value);
}
2018-06-29 19:52:40 +02:00
}
}
finally
{
scope.Database.AsUmbracoDatabase().EnableSqlTrace = false;
scope.Database.AsUmbracoDatabase().EnableSqlCount = false;
}
}
}
[Test]
public void GetPagedResultsByQuery_CustomPropertySort()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Name.Contains("Text"));
2018-06-29 19:52:40 +02:00
try
{
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
IEnumerable<IContent> result = repository.GetPage(query, 0, 2, out long totalRecords, null, Ordering.By("title", isCustomField: true));
2018-06-29 19:52:40 +02:00
Assert.AreEqual(3, totalRecords);
Assert.AreEqual(2, result.Count());
result = repository.GetPage(query, 1, 2, out totalRecords, null, Ordering.By("title", isCustomField: true));
2018-06-29 19:52:40 +02:00
Assert.AreEqual(1, result.Count());
}
finally
{
scope.Database.AsUmbracoDatabase().EnableSqlTrace = false;
scope.Database.AsUmbracoDatabase().EnableSqlCount = false;
}
}
}
[Test]
public void GetPagedResultsByQuery_FirstPage()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
2018-06-29 19:52:40 +02:00
try
{
scope.Database.AsUmbracoDatabase().EnableSqlTrace = true;
scope.Database.AsUmbracoDatabase().EnableSqlCount = true;
IEnumerable<IContent> result = repository.GetPage(query, 0, 1, out long totalRecords, null, Ordering.By("Name"));
2018-06-29 19:52:40 +02:00
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
Assert.That(result.First().Name, Is.EqualTo("Text Page 1"));
}
finally
{
scope.Database.AsUmbracoDatabase().EnableSqlTrace = false;
scope.Database.AsUmbracoDatabase().EnableSqlCount = false;
}
}
}
[Test]
public void GetPagedResultsByQuery_SecondPage()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
IEnumerable<IContent> result = repository.GetPage(query, 1, 1, out long totalRecords, null, Ordering.By("Name"));
2018-06-29 19:52:40 +02:00
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
Assert.That(result.First().Name, Is.EqualTo("Text Page 2"));
}
}
[Test]
public void GetPagedResultsByQuery_SinglePage()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
IEnumerable<IContent> result = repository.GetPage(query, 0, 2, out long totalRecords, null, Ordering.By("Name"));
2018-06-29 19:52:40 +02:00
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(2));
Assert.That(result.First().Name, Is.EqualTo("Text Page 1"));
}
}
[Test]
public void GetPagedResultsByQuery_DescendingOrder()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
IEnumerable<IContent> result = repository.GetPage(query, 0, 1, out long totalRecords, null, Ordering.By("Name", Direction.Descending));
2018-06-29 19:52:40 +02:00
Assert.That(totalRecords, Is.GreaterThanOrEqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
Assert.That(result.First().Name, Is.EqualTo("Text Page 2"));
}
}
[Test]
public void GetPagedResultsByQuery_FilterMatchingSome()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
2018-06-29 19:52:40 +02:00
IQuery<IContent> filterQuery = scope.SqlContext.Query<IContent>().Where(x => x.Name.Contains("Page 2"));
IEnumerable<IContent> result = repository.GetPage(query, 0, 1, out long totalRecords, filterQuery, Ordering.By("Name"));
2018-06-29 19:52:40 +02:00
Assert.That(totalRecords, Is.EqualTo(1));
Assert.That(result.Count(), Is.EqualTo(1));
Assert.That(result.First().Name, Is.EqualTo("Text Page 2"));
}
}
[Test]
public void GetPagedResultsByQuery_FilterMatchingAll()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
2018-06-29 19:52:40 +02:00
IQuery<IContent> filterQuery = scope.SqlContext.Query<IContent>().Where(x => x.Name.Contains("text"));
IEnumerable<IContent> result = repository.GetPage(query, 0, 1, out long totalRecords, filterQuery, Ordering.By("Name"));
2018-06-29 19:52:40 +02:00
Assert.That(totalRecords, Is.EqualTo(2));
Assert.That(result.Count(), Is.EqualTo(1));
Assert.That(result.First().Name, Is.EqualTo("Text Page 1"));
}
}
[Test]
public void GetAllContentByIds()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IEnumerable<IContent> contents = repository.GetMany(_subpage.Id, _subpage2.Id);
2018-06-29 19:52:40 +02:00
Assert.That(contents, Is.Not.Null);
Assert.That(contents.Any(), Is.True);
Assert.That(contents.Count(), Is.EqualTo(2));
}
}
[Test]
public void GetAllContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IEnumerable<IContent> contents = repository.GetMany();
2018-06-29 19:52:40 +02:00
Assert.That(contents, Is.Not.Null);
Assert.That(contents.Any(), Is.True);
Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(4));
contents = repository.GetMany(contents.Select(x => x.Id).ToArray());
Assert.That(contents, Is.Not.Null);
Assert.That(contents.Any(), Is.True);
Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(4));
contents = ((IReadRepository<Guid, IContent>)repository).GetMany(contents.Select(x => x.Key).ToArray());
Assert.That(contents, Is.Not.Null);
Assert.That(contents.Any(), Is.True);
Assert.That(contents.Count(), Is.GreaterThanOrEqualTo(4));
}
}
[Test]
public void ExistContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
bool exists = repository.Exists(_subpage.Id);
2018-06-29 19:52:40 +02:00
Assert.That(exists, Is.True);
}
}
[Test]
public void CountContent()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Level == 2);
int result = repository.Count(query);
2018-06-29 19:52:40 +02:00
Assert.That(result, Is.GreaterThanOrEqualTo(2));
}
}
[Test]
public void QueryContentByUniqueId()
{
IScopeProvider provider = ScopeProvider;
using (IScope scope = provider.CreateScope())
2018-06-29 19:52:40 +02:00
{
DocumentRepository repository = CreateRepository((IScopeAccessor)provider, out _);
2018-06-29 19:52:40 +02:00
IQuery<IContent> query = scope.SqlContext.Query<IContent>().Where(x => x.Key == new Guid("B58B3AD4-62C2-4E27-B1BE-837BD7C533E0"));
IContent content = repository.Get(query).SingleOrDefault();
2018-06-29 19:52:40 +02:00
Assert.IsNotNull(content);
2020-10-09 13:08:23 +02:00
Assert.AreEqual(_textpage.Id, content.Id);
2018-06-29 19:52:40 +02:00
}
}
}
}