diff --git a/.gitignore b/.gitignore index 3ae099a82f6d..ebbfe9357662 100644 --- a/.gitignore +++ b/.gitignore @@ -176,3 +176,5 @@ cypress.env.json /src/Umbraco.Tests.AcceptanceTest/cypress/videos/ /src/Umbraco.Tests.AcceptanceTest/cypress/screenshots/ src/Umbraco.Web.UI/Umbraco/telemetrics-id.umb + +/src/Umbraco.Web.UI/config/umbracoSettings.config diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs index 79bff51d0558..a84ae3d31cad 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs @@ -8,5 +8,10 @@ internal class BackOfficeElement : UmbracoConfigurationElement, IBackOfficeSecti internal TourConfigElement Tours => (TourConfigElement)this["tours"]; ITourSection IBackOfficeSection.Tours => Tours; + + [ConfigurationProperty("id", DefaultValue = "")] + internal string Id => (string)base["id"]; + + string IBackOfficeSection.Id => (string)base["id"]; } } diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs index 36dd6a22ed53..32e8e4e3ecb1 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs @@ -1,7 +1,10 @@ -namespace Umbraco.Core.Configuration.UmbracoSettings +using System; + +namespace Umbraco.Core.Configuration.UmbracoSettings { public interface IBackOfficeSection { ITourSection Tours { get; } + string Id { get; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index d33e9dfdfc92..337c97d081e3 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -7,7 +7,7 @@ public class SystemFiles { public static string TinyMceConfig => SystemDirectories.Config + "/tinyMceConfig.config"; - public static string TelemetricsIdentifier => SystemDirectories.Data + "/telemetrics-id.umb"; + public static string UmbracoSettings => SystemDirectories.Config + "/UmbracoSettings.config"; // TODO: Kill this off we don't have umbraco.config XML cache we now have NuCache public static string GetContentCacheXml(IGlobalSettings globalSettings) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 6e4a4b780e69..f2733ad60e83 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -377,6 +377,7 @@ + diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index fa998a9856fa..454da921e7a6 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -41,11 +41,11 @@ Preview mode - + - - Click to end + + Click to end preview mode + ]]> @@ -231,6 +232,14 @@ By default you can call any content Id in the url and show the content with that id, for example: http://mysite.com/1092 or http://mysite.com/1092.aspx would render the content with id 1092. Setting this setting to true stops that behavior + @disableRedirectUrlTracking + When the URL changes for content, redirects are automatically created for redirect handling within the + request pipeline. Setting this setting to true stops the automatic creation of redirects. Note that this + does not stop the request pipeline from handling any previously created redirects. + @urlProviderMode + By default Umbraco automatically figures out if internal URLs should be rendered as relative or absolute, + depending on the current request and the configured domains. By setting this setting to "Relative" or + "Absolute" you can force Umbraco to always render URLs as either relative or absolute. @umbracoApplicationUrl The url of the Umbraco application. By default, Umbraco will figure it out from the first request. Configure it here if you need anything specific. Needs to be a complete url with scheme and umbraco @@ -242,4 +251,17 @@ umbracoApplicationUrl=""> + + diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.config b/src/Umbraco.Web.UI/config/umbracoSettings.config deleted file mode 100644 index 454da921e7a6..000000000000 --- a/src/Umbraco.Web.UI/config/umbracoSettings.config +++ /dev/null @@ -1,267 +0,0 @@ - - - - - - - - - - - - - 1 - - - - - - - - your@email.here - - - - - - Preview mode - - … - - - Click to end preview mode - - - - - ]]> - - - - throw - - - ashx,aspx,ascx,config,cshtml,vbhtml,asmx,air,axd,swf,xml,xhtml,html,htm,php,htaccess - - - assets/img/login.jpg - - - - - - false - - true - - false - - - - - - - - - - - - - - diff --git a/src/Umbraco.Web/Install/InstallStepCollection.cs b/src/Umbraco.Web/Install/InstallStepCollection.cs index 125572fef89c..240a1dae8e4f 100644 --- a/src/Umbraco.Web/Install/InstallStepCollection.cs +++ b/src/Umbraco.Web/Install/InstallStepCollection.cs @@ -21,6 +21,7 @@ public InstallStepCollection(InstallHelper installHelper, IEnumerable().First(), a.OfType().First(), a.OfType().First(), + a.OfType().First(), a.OfType().First(), a.OfType().First(), a.OfType().First(), diff --git a/src/Umbraco.Web/Install/InstallSteps/TelemetryIdentifierStep.cs b/src/Umbraco.Web/Install/InstallSteps/TelemetryIdentifierStep.cs new file mode 100644 index 000000000000..92fe70f7c50d --- /dev/null +++ b/src/Umbraco.Web/Install/InstallSteps/TelemetryIdentifierStep.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using System.Xml.Linq; +using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.IO; +using Umbraco.Core.Logging; +using Umbraco.Web.Install.Models; + +namespace Umbraco.Web.Install.InstallSteps +{ + [InstallSetupStep(InstallationType.NewInstall | InstallationType.Upgrade, + "TelemetryIdConfiguration", 0, "", + PerformsAppRestart = false)] + internal class TelemetryIdentifierStep : InstallSetupStep + { + private readonly IProfilingLogger _logger; + private readonly IUmbracoSettingsSection _settings; + + public TelemetryIdentifierStep(IProfilingLogger logger, IUmbracoSettingsSection settings) + { + _logger = logger; + _settings = settings; + } + + public override Task ExecuteAsync(object model) + { + // Generate GUID + var telemetrySiteIdentifier = Guid.NewGuid(); + + // Modify the XML to add a new GUID site identifier + // hack: ensure this does not trigger a restart + using (ChangesMonitor.Suspended()) + { + var umbracoSettingsPath = IOHelper.MapPath(SystemFiles.UmbracoSettings); + if(File.Exists(umbracoSettingsPath) == false) + { + // Log an error + _logger.Error("Unable to find umbracoSettings.config file to add telemetry site identifier"); + return Task.FromResult(null); + } + + try + { + var umbracoConfigXml = XDocument.Load(umbracoSettingsPath, LoadOptions.PreserveWhitespace); + if (umbracoConfigXml.Root != null) + { + var backofficeElement = umbracoConfigXml.Root.Element("backOffice"); + if (backofficeElement == null) + return Task.FromResult(null); + + // Will add ID attribute if it does not exist + backofficeElement.SetAttributeValue("id", telemetrySiteIdentifier.ToString()); + + // Save file back down + umbracoConfigXml.Save(umbracoSettingsPath, SaveOptions.DisableFormatting); + } + } + catch (Exception ex) + { + _logger.Error(ex, "Couldn't update umbracoSettings.config with a backoffice with a telemetry site identifier"); + } + } + + return Task.FromResult(null); + } + + public override bool RequiresExecution(object model) + { + // Verify that XML attribute is not empty string + // Try & get a value stored in umbracoSettings.config on the backoffice XML element ID attribute + var backofficeIdentifierRaw = _settings.BackOffice.Id; + + // No need to add Id again if already found + return string.IsNullOrEmpty(backofficeIdentifierRaw); + } + } +} diff --git a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs index fcac8570d2ba..24ac7cbf3add 100644 --- a/src/Umbraco.Web/Telemetry/ReportSiteTask.cs +++ b/src/Umbraco.Web/Telemetry/ReportSiteTask.cs @@ -1,6 +1,5 @@ using Newtonsoft.Json; using System; -using System.IO; using System.Net.Http; using System.Runtime.Serialization; using System.Text; @@ -8,7 +7,7 @@ using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Web.Scheduling; @@ -16,62 +15,33 @@ namespace Umbraco.Web.Telemetry { public class ReportSiteTask : RecurringTaskBase { - private IProfilingLogger _logger; + private readonly IProfilingLogger _logger; private static HttpClient _httpClient; + private readonly IUmbracoSettingsSection _settings; - public ReportSiteTask(IBackgroundTaskRunner runner, int delayBeforeWeStart, int howOftenWeRepeat, IProfilingLogger logger) + public ReportSiteTask(IBackgroundTaskRunner runner, int delayBeforeWeStart, int howOftenWeRepeat, IProfilingLogger logger, IUmbracoSettingsSection settings) : base(runner, delayBeforeWeStart, howOftenWeRepeat) { _logger = logger; _httpClient = new HttpClient(); + _settings = settings; } /// - /// Runs the background task to send the anynomous ID + /// Runs the background task to send the anonymous ID /// to telemetry service /// /// A value indicating whether to repeat the task. public override async Task PerformRunAsync(CancellationToken token) { - // Try & find file at '/umbraco/telemetrics-id.umb' - var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); - - if (File.Exists(telemetricsFilePath) == false) - { - // Some users may have decided to not be tracked by deleting/removing the marker file - _logger.Warn("No telemetry marker file found at '{filePath}' and will not report site to telemetry service", telemetricsFilePath); - - // Stop repeating this task (no need to keep checking) - // The only time it will recheck when the site is recycled - return false; - } - - - var telemetricsFileContents = string.Empty; - try - { - // Open file & read its contents - // It may throw due to file permissions or file locking - telemetricsFileContents = File.ReadAllText(telemetricsFilePath); - } - catch (Exception ex) - { - // Silently swallow ex - but lets log it (ReadAllText throws a ton of different types of ex) - // Hence the use of general exception type - _logger.Error(ex, "Error in reading file contents of telemetry marker file found at '{filePath}'", telemetricsFilePath); - - // Exit out early, but mark this task to be repeated in case its a file lock so it can be rechecked the next time round - return true; - } - + // Try & get a value stored in umbracoSettings.config on the backoffice XML element ID attribute + var backofficeIdentifierRaw = _settings.BackOffice.Id; // Parse as a GUID & verify its a GUID and not some random string // In case of users may have messed or decided to empty the file contents or put in something random - if (Guid.TryParse(telemetricsFileContents, out var telemetrySiteIdentifier) == false) + if (Guid.TryParse(backofficeIdentifierRaw, out var telemetrySiteIdentifier) == false) { - // Some users may have decided to mess with file contents - _logger.Warn("The telemetry marker file found at '{filePath}' with '{telemetrySiteId}' is not a valid identifier for the telemetry service", telemetricsFilePath, telemetrySiteIdentifier); - + // Some users may have decided to mess with the XML attribute and put in something else // Stop repeating this task (no need to keep checking) // The only time it will recheck when the site is recycled return false; @@ -79,7 +49,6 @@ public override async Task PerformRunAsync(CancellationToken token) try { - // Send data to LIVE telemetry _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); @@ -101,14 +70,14 @@ public override async Task PerformRunAsync(CancellationToken token) // Make a HTTP Post to telemetry service // https://telemetry.umbraco.com/installs/ // Fire & Forget, do not need to know if its a 200, 500 etc - var result = await _httpClient.SendAsync(request); + var result = await _httpClient.SendAsync(request, token); } } catch { // Silently swallow // The user does not need the logs being polluted if our service has fallen over or is down etc - // Hence only loggigng this at a more verbose level (Which users should not be using in prod) + // Hence only logging this at a more verbose level (which users should not be using in production) _logger.Debug("There was a problem sending a request to the Umbraco telemetry service"); } @@ -118,7 +87,6 @@ public override async Task PerformRunAsync(CancellationToken token) public override bool IsAsync => true; - [DataContract] private class TelemetryReportData { diff --git a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs index 4ea4c6573af5..1ae9ad9764ae 100644 --- a/src/Umbraco.Web/Telemetry/TelemetryComponent.cs +++ b/src/Umbraco.Web/Telemetry/TelemetryComponent.cs @@ -1,4 +1,5 @@ using Umbraco.Core.Composing; +using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Web.Scheduling; @@ -6,12 +7,14 @@ namespace Umbraco.Web.Telemetry { public class TelemetryComponent : IComponent { - private IProfilingLogger _logger; + private readonly IProfilingLogger _logger; + private readonly IUmbracoSettingsSection _settings; private BackgroundTaskRunner _telemetryReporterRunner; - public TelemetryComponent(IProfilingLogger logger) + public TelemetryComponent(IProfilingLogger logger, IUmbracoSettingsSection settings) { _logger = logger; + _settings = settings; } public void Initialize() @@ -19,11 +22,11 @@ public void Initialize() // backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly _telemetryReporterRunner = new BackgroundTaskRunner("TelemetryReporter", _logger); - int delayBeforeWeStart = 60 * 1000; // 60 * 1000ms = 1min (60,000) - int howOftenWeRepeat = 60 * 1000 * 60 * 24; // 60 * 1000 * 60 * 24 = 24hrs (86400000) + const int delayBeforeWeStart = 60 * 1000; // 60 * 1000ms = 1min (60,000) + const int howOftenWeRepeat = 60 * 1000 * 60 * 24; // 60 * 1000 * 60 * 24 = 24hrs (86400000) // As soon as we add our task to the runner it will start to run (after its delay period) - var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _logger); + var task = new ReportSiteTask(_telemetryReporterRunner, delayBeforeWeStart, howOftenWeRepeat, _logger, _settings); _telemetryReporterRunner.TryAdd(task); } diff --git a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs b/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs deleted file mode 100644 index 36cae322ce81..000000000000 --- a/src/Umbraco.Web/Telemetry/TelemetryMarkerComponent.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.IO; -using Umbraco.Core; -using Umbraco.Core.Composing; -using Umbraco.Core.IO; -using Umbraco.Core.Logging; - -namespace Umbraco.Web.Telemetry -{ - public class TelemetryMarkerComponent : IComponent - { - private IProfilingLogger _logger; - private IRuntimeState _runtime; - - public TelemetryMarkerComponent(IProfilingLogger logger, IRuntimeState runtime) - { - _logger = logger; - _runtime = runtime; - } - - public void Initialize() - { - var telemetricsFilePath = IOHelper.MapPath(SystemFiles.TelemetricsIdentifier); - - // Verify file does not exist already (if we are upgrading) - // In a clean install we know it would not exist - // If the site is upgraded and the file was removed it would re-create one - // NOTE: If user removed the marker file to opt out it would re-create a new guid marker file & potentially skew - if (_runtime.Level == RuntimeLevel.Upgrade && File.Exists(telemetricsFilePath)) - { - _logger.Warn("When upgrading the anonymous telemetry file already existsed on disk at {filePath}", telemetricsFilePath); - return; - } - else if (_runtime.Level == RuntimeLevel.Install && File.Exists(telemetricsFilePath)) - { - // No need to log for when level is install if file exists (As this component hit several times during install process) - return; - } - - // We are a clean install or an upgrade without the marker file - // Generate GUID - var telemetrySiteIdentifier = Guid.NewGuid(); - - // Write file contents - try - { - File.WriteAllText(telemetricsFilePath, telemetrySiteIdentifier.ToString()); - } - catch (Exception ex) - { - _logger.Error(ex, "Unable to create telemetry file at {filePath}", telemetricsFilePath); - } - - } - - public void Terminate() - { - } - } -} diff --git a/src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs b/src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs deleted file mode 100644 index e01b4a7f1097..000000000000 --- a/src/Umbraco.Web/Telemetry/TelemetryMarkerComposer.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Umbraco.Core; -using Umbraco.Core.Composing; - -namespace Umbraco.Web.Telemetry -{ - [RuntimeLevel(MinLevel = RuntimeLevel.Install, MaxLevel = RuntimeLevel.Upgrade)] - public class TelemetryMarkerComposer : ComponentComposer, ICoreComposer - { } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 1f8d4d7881c5..8890d9cf2589 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -173,6 +173,7 @@ + @@ -296,10 +297,8 @@ - -