Netcore: Get rid of default files in config folder (#9966)

* TourController now uses the core tours from embedded resources

* Moved tinyMceConfig.*.config to IOptions

* Embedded the default grid.editors.config.js

* Fixed issue when saving grid with an empty media cell

* Logviewer now uses sql as database instead of file.

* Remove config folder from build script and nuget pacakges.

* Removing auto-generated Id added to appsettings.json

* Update src/Umbraco.Web.BackOffice/Controllers/TourController.cs

Co-authored-by: Elitsa Marinovska <elm@umbraco.dk>
Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com>
This commit is contained in:
Bjarke Berg
2021-03-11 13:20:46 +01:00
committed by GitHub
parent 91e877cebe
commit 2b89839724
56 changed files with 668 additions and 505 deletions

View File

@@ -125,8 +125,6 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
builder.Services.AddUnique<IImageUrlGenerator, ImageSharpImageUrlGenerator>();
builder.Services.AddUnique<IPublishedSnapshotRebuilder, PublishedSnapshotRebuilder>();
// register *all* checks, except those marked [HideFromTypeFinder] of course
builder.Services.AddUnique<IMarkdownToHtmlConverter, MarkdownToHtmlConverter>();

View File

@@ -55,6 +55,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
builder.Services.AddUnique<IKeyValueRepository, KeyValueRepository>();
builder.Services.AddUnique<IInstallationRepository, InstallationRepository>();
builder.Services.AddUnique<IUpgradeCheckRepository, UpgradeCheckRepository>();
builder.Services.AddUnique<ILogViewerQueryRepository, LogViewerQueryRepository>();
return builder;
}

View File

@@ -1,85 +1,45 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Routing;
using Formatting = Newtonsoft.Json.Formatting;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
namespace Umbraco.Cms.Core.Logging.Viewer
{
public class LogViewerConfig : ILogViewerConfig
{
private readonly IHostingEnvironment _hostingEnvironment;
private static readonly string _pathToSearches = WebPath.Combine(Cms.Core.Constants.SystemDirectories.Config, "logviewer.searches.config.js");
private readonly FileInfo _searchesConfig;
private readonly ILogViewerQueryRepository _logViewerQueryRepository;
private readonly IScopeProvider _scopeProvider;
public LogViewerConfig(IHostingEnvironment hostingEnvironment)
public LogViewerConfig(ILogViewerQueryRepository logViewerQueryRepository, IScopeProvider scopeProvider)
{
_hostingEnvironment = hostingEnvironment;
var trimmedPath = _pathToSearches.TrimStart(Constants.CharArrays.TildeForwardSlash).Replace('/', Path.DirectorySeparatorChar);
var absolutePath = Path.Combine(_hostingEnvironment.ApplicationPhysicalPath, trimmedPath);
_searchesConfig = new FileInfo(absolutePath);
_logViewerQueryRepository = logViewerQueryRepository;
_scopeProvider = scopeProvider;
}
public IReadOnlyList<SavedLogSearch> GetSavedSearches()
{
//Our default implementation
//If file does not exist - lets create it with an empty array
EnsureFileExists();
var rawJson = System.IO.File.ReadAllText(_searchesConfig.FullName);
return JsonConvert.DeserializeObject<SavedLogSearch[]>(rawJson);
using var scope = _scopeProvider.CreateScope(autoComplete: true);
var logViewerQueries = _logViewerQueryRepository.GetMany();
var result = logViewerQueries.Select(x => new SavedLogSearch() { Name = x.Name, Query = x.Query }).ToArray();
return result;
}
public IReadOnlyList<SavedLogSearch> AddSavedSearch(string name, string query)
{
//Get the existing items
var searches = GetSavedSearches().ToList();
using var scope = _scopeProvider.CreateScope(autoComplete: true);
_logViewerQueryRepository.Save(new LogViewerQuery(name, query));
//Add the new item to the bottom of the list
searches.Add(new SavedLogSearch { Name = name, Query = query });
//Serialize to JSON string
var rawJson = JsonConvert.SerializeObject(searches, Formatting.Indented);
//If file does not exist - lets create it with an empty array
EnsureFileExists();
//Write it back down to file
System.IO.File.WriteAllText(_searchesConfig.FullName, rawJson);
//Return the updated object - so we can instantly reset the entire array from the API response
//As opposed to push a new item into the array
return searches;
return GetSavedSearches();
}
public IReadOnlyList<SavedLogSearch> DeleteSavedSearch(string name, string query)
{
//Get the existing items
var searches = GetSavedSearches().ToList();
//Removes the search
searches.RemoveAll(s => s.Name.Equals(name) && s.Query.Equals(query));
//Serialize to JSON string
var rawJson = JsonConvert.SerializeObject(searches, Formatting.Indented);
//Write it back down to file
System.IO.File.WriteAllText(_searchesConfig.FullName, rawJson);
using var scope = _scopeProvider.CreateScope(autoComplete: true);
var item = _logViewerQueryRepository.GetByName(name);
_logViewerQueryRepository.Delete(item);
//Return the updated object - so we can instantly reset the entire array from the API response
return searches;
}
private void EnsureFileExists()
{
if (_searchesConfig.Exists) return;
using (var writer = _searchesConfig.CreateText())
{
writer.Write("[]");
}
return GetSavedSearches();
}
}
}

View File

@@ -1,9 +1,11 @@
using System;
using System.Linq;
using Microsoft.Extensions.Logging;
using NPoco;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Extensions;
@@ -76,6 +78,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
if (tableName.Equals(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue))
CreateKeyValueData();
if (tableName.Equals(Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery))
CreateLogViewerQueryData();
_logger.LogInformation("Done creating table {TableName} data.", tableName);
}
@@ -345,5 +350,17 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.KeyValue, "key", false, new KeyValueDto { Key = stateValueKey, Value = finalState, UpdateDate = DateTime.Now });
}
private void CreateLogViewerQueryData()
{
var defaultData = MigrateLogViewerQueriesFromFileToDb.DefaultLogQueries.ToArray();
for (int i = 0; i < defaultData.Length; i++)
{
var dto = defaultData[i];
dto.Id = i+1;
_database.Insert(Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery, "id", false, dto);
}
}
}
}

View File

@@ -91,7 +91,8 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install
typeof (AuditEntryDto),
typeof (ContentVersionCultureVariationDto),
typeof (DocumentCultureVariationDto),
typeof (ContentScheduleDto)
typeof (ContentScheduleDto),
typeof (LogViewerQueryDto)
};
/// <summary>

View File

@@ -0,0 +1,34 @@
using System.IO;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Migrations;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0;
namespace Umbraco.Cms.Infrastructure.Migrations.PostMigrations
{
/// <summary>
/// Deletes the old file that saved log queries
/// </summary>
public class DeleteLogViewerQueryFile : IMigration
{
private readonly IHostingEnvironment _hostingEnvironment;
/// <summary>
/// Initializes a new instance of the <see cref="DeleteLogViewerQueryFile"/> class.
/// </summary>
public DeleteLogViewerQueryFile(IMigrationContext context, IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
/// <inheritdoc />
public void Migrate()
{
var logViewerQueryFile = MigrateLogViewerQueriesFromFileToDb.GetLogViewerQueryFile(_hostingEnvironment);
if(File.Exists(logViewerQueryFile))
{
File.Delete(logViewerQueryFile);
}
}
}
}

View File

@@ -9,6 +9,7 @@ using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_10_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_6_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_7_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_8_9_0;
using Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade
@@ -197,6 +198,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade
To<ExternalLoginTableUserData>("{B5838FF5-1D22-4F6C-BCEB-F83ACB14B575}");
// to 8.10.0
To<AddPropertyTypeLabelOnTopColumn>("{D6A8D863-38EC-44FB-91EC-ACD6A668BD18}");
// to 8.10.0
To<MigrateLogViewerQueriesFromFileToDb>("{22D801BA-A1FF-4539-BFCC-2139B55594F8}");
//FINAL
}
}

View File

@@ -0,0 +1,108 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Infrastructure.Migrations.PostMigrations;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_9_0_0
{
public class MigrateLogViewerQueriesFromFileToDb : MigrationBase
{
private readonly IHostingEnvironment _hostingEnvironment;
internal static readonly IEnumerable<LogViewerQueryDto> DefaultLogQueries = new LogViewerQueryDto[]
{
new (){
Name = "Find all logs where the Level is NOT Verbose and NOT Debug",
Query = "Not(@Level='Verbose') and Not(@Level='Debug')"
},
new (){
Name = "Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)",
Query = "Has(@Exception)"
},
new (){
Name = "Find all logs that have the property 'Duration'",
Query = "Has(Duration)"
},
new (){
Name = "Find all logs that have the property 'Duration' and the duration is greater than 1000ms",
Query = "Has(Duration) and Duration > 1000"
},
new (){
Name = "Find all logs that are from the namespace 'Umbraco.Core'",
Query = "StartsWith(SourceContext, 'Umbraco.Core')"
},
new (){
Name = "Find all logs that use a specific log message template",
Query = "@MessageTemplate = '[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'"
},
new (){
Name = "Find logs where one of the items in the SortedComponentTypes property array is equal to",
Query = "SortedComponentTypes[?] = 'Umbraco.Web.Search.ExamineComponent'"
},
new (){
Name = "Find logs where one of the items in the SortedComponentTypes property array contains",
Query = "Contains(SortedComponentTypes[?], 'DatabaseServer')"
},
new (){
Name = "Find all logs that the message has localhost in it with SQL like",
Query = "@Message like '%localhost%'"
},
new (){
Name = "Find all logs that the message that starts with 'end' in it with SQL like",
Query = "@Message like 'end%'"
}
};
public MigrateLogViewerQueriesFromFileToDb(IMigrationContext context, IHostingEnvironment hostingEnvironment)
: base(context)
{
_hostingEnvironment = hostingEnvironment;
}
public override void Migrate()
{
Debugger.Launch();
Debugger.Break();
CreateDatabaseTable();
MigrateFileContentToDB();
}
private void CreateDatabaseTable()
{
var tables = SqlSyntax.GetTablesInSchema(Context.Database);
if (!tables.InvariantContains(Core.Constants.DatabaseSchema.Tables.LogViewerQuery))
{
Create.Table<LogViewerQueryDto>().Do();
}
}
internal static string GetLogViewerQueryFile(IHostingEnvironment hostingEnvironment)
{
return hostingEnvironment.MapPathContentRoot(
Path.Combine(Cms.Core.Constants.SystemDirectories.Config, "logviewer.searches.config.js"));
}
private void MigrateFileContentToDB()
{
var logViewerQueryFile = GetLogViewerQueryFile(_hostingEnvironment);
var logQueriesInFile = File.Exists(logViewerQueryFile) ?
JsonConvert.DeserializeObject<LogViewerQueryDto[]>(File.ReadAllText(logViewerQueryFile))
: DefaultLogQueries;
var logQueriesInDb = Database.Query<LogViewerQueryDto>().ToArray();
if (logQueriesInDb.Any())
{
return;
}
Database.InsertBulk(logQueriesInFile);
Context.AddPostMigration<DeleteLogViewerQueryFile>();
}
}
}

View File

@@ -0,0 +1,22 @@
using NPoco;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
namespace Umbraco.Cms.Infrastructure.Persistence.Dtos
{
[TableName(Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery)]
[PrimaryKey("id")]
[ExplicitColumns]
internal class LogViewerQueryDto
{
[Column("id")]
[PrimaryKeyColumn]
public int Id { get; set; }
[Column("name")]
[Index(IndexTypes.UniqueNonClustered, Name = "IX_LogViewerQuery_name")]
public string Name { get; set; }
[Column("query")]
public string Query { get; set; }
}
}

View File

@@ -0,0 +1,22 @@
using System;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
namespace Umbraco.Cms.Infrastructure.Persistence.Mappers
{
[MapperFor(typeof(ILogViewerQuery))]
[MapperFor(typeof(LogViewerQuery))]
public sealed class LogViewerQueryMapper : BaseMapper
{
public LogViewerQueryMapper(Lazy<ISqlContext> sqlContext, MapperConfigurationStore maps)
: base(sqlContext, maps)
{ }
protected override void DefineMaps()
{
DefineMap<ILogViewerQuery, LogViewerQueryDto>(nameof(ILogViewerQuery.Id), nameof(LogViewerQueryDto.Id));
DefineMap<ILogViewerQuery, LogViewerQueryDto>(nameof(ILogViewerQuery.Name), nameof(LogViewerQueryDto.Name));
DefineMap<ILogViewerQuery, LogViewerQueryDto>(nameof(ILogViewerQuery.Query), nameof(LogViewerQueryDto.Query));
}
}
}

View File

@@ -53,6 +53,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Mappers
Add<UserGroupMapper>();
Add<AuditEntryMapper>();
Add<ConsentMapper>();
Add<LogViewerQueryMapper>();
return this;
}
}

View File

@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Microsoft.Extensions.Logging;
using NPoco;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Querying;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Infrastructure.Persistence.Dtos;
using Umbraco.Extensions;
namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement
{
internal class LogViewerQueryRepository : EntityRepositoryBase<int, ILogViewerQuery>, ILogViewerQueryRepository
{
public LogViewerQueryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger<LogViewerQueryRepository> logger)
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<ILogViewerQuery, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<ILogViewerQuery, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
protected override IEnumerable<ILogViewerQuery> PerformGetAll(params int[] ids)
{
var sql = GetBaseQuery(false).Where($"{Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery}.id > 0");
if (ids.Any())
{
sql.Where($"{Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery}.id in (@ids)", new { ids = ids });
}
return Database.Fetch<LogViewerQueryDto>(sql).Select(ConvertFromDto);
}
protected override IEnumerable<ILogViewerQuery> PerformGetByQuery(IQuery<ILogViewerQuery> query)
{
throw new NotSupportedException("This repository does not support this method");
}
protected override Sql<ISqlContext> GetBaseQuery(bool isCount)
{
var sql = Sql();
sql = isCount ? sql.SelectCount() : sql.Select<LogViewerQueryDto>();
sql = sql.From<LogViewerQueryDto>();
return sql;
}
protected override string GetBaseWhereClause()
{
return $"{Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery}.id = @id";
}
protected override IEnumerable<string> GetDeleteClauses()
{
var list = new List<string>
{
$"DELETE FROM {Cms.Core.Constants.DatabaseSchema.Tables.LogViewerQuery} WHERE id = @id"
};
return list;
}
protected override Guid NodeObjectTypeId
{
get { throw new NotImplementedException(); }
}
protected override void PersistNewItem(ILogViewerQuery entity)
{
var exists = Database.ExecuteScalar<int>($"SELECT COUNT(*) FROM {Core.Constants.DatabaseSchema.Tables.LogViewerQuery} WHERE name = @name",
new { name = entity.Name });
if (exists > 0) throw new DuplicateNameException($"The log query name '{entity.Name}' is already used");
entity.AddingEntity();
var factory = new LogViewerQueryModelFactory();
var dto = factory.BuildDto(entity);
var id = Convert.ToInt32(Database.Insert(dto));
entity.Id = id;
}
protected override void PersistUpdatedItem(ILogViewerQuery entity)
{
entity.UpdatingEntity();
var exists = Database.ExecuteScalar<int>($"SELECT COUNT(*) FROM {Core.Constants.DatabaseSchema.Tables.LogViewerQuery} WHERE name = @name AND id <> @id",
new { name = entity.Name, id = entity.Id });
//ensure there is no other log query with the same name on another entity
if (exists > 0) throw new DuplicateNameException($"The log query name '{entity.Name}' is already used");
var factory = new LogViewerQueryModelFactory();
var dto = factory.BuildDto(entity);
Database.Update(dto);
}
private ILogViewerQuery ConvertFromDto(LogViewerQueryDto dto)
{
var factory = new LogViewerQueryModelFactory();
var entity = factory.BuildEntity(dto);
return entity;
}
internal class LogViewerQueryModelFactory
{
public ILogViewerQuery BuildEntity(LogViewerQueryDto dto)
{
var logViewerQuery = new LogViewerQuery(dto.Name, dto.Query)
{
Id = dto.Id,
};
return logViewerQuery;
}
public LogViewerQueryDto BuildDto(ILogViewerQuery entity)
{
var dto = new LogViewerQueryDto { Name = entity.Name, Query = entity.Query, Id = entity.Id };
return dto;
}
}
protected override ILogViewerQuery PerformGet(int id)
{
//use the underlying GetAll which will force cache all log queries
return GetMany().FirstOrDefault(x => x.Id == id);
}
public ILogViewerQuery GetByName(string name)
{
//use the underlying GetAll which will force cache all log queries
return GetMany().FirstOrDefault(x => x.Name == name);
}
}
}

View File

@@ -202,7 +202,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
_richTextPropertyValueEditor.GetReferences(x.Value)))
yield return umbracoEntityReference;
foreach (var umbracoEntityReference in mediaValues.SelectMany(x =>
foreach (var umbracoEntityReference in mediaValues.Where(x=>x.Value.HasValues).SelectMany(x =>
_mediaPickerPropertyValueEditor.GetReferences(x.Value["udi"])))
yield return umbracoEntityReference;
}