Fixes #29 by generating valid keys
This commit is contained in:
		
							parent
							
								
									d36a258392
								
							
						
					
					
						commit
						0e4a99332b
					
				| @ -42,21 +42,10 @@ public static class SectionProcessor | |||||||
|     public static async Task<ProcessorResult<Section>> AddSection(string text, string? parentKey) |     public static async Task<ProcessorResult<Section>> AddSection(string text, string? parentKey) | ||||||
|     { |     { | ||||||
|         await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>(); |         await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>(); | ||||||
|          |  | ||||||
|         // Remove any whitespaces from the section name, regardless of how many e.g. spaces the user typed: |  | ||||||
|         var key = string.Join('_', text.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant(); |  | ||||||
|          |  | ||||||
|         // Check, if this key already exists: |  | ||||||
|         if (await db.Sections.AnyAsync(n => n.DataKey == key)) |  | ||||||
|         { |  | ||||||
|             var rng = new Random(); |  | ||||||
|             while (await db.Sections.AnyAsync(n => n.DataKey == key)) |  | ||||||
|             { |  | ||||||
|                 // Add a random number to the end of the key: |  | ||||||
|                 key += $"_{rng.Next(1, 10_000)}"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|  |         // Generate the key: | ||||||
|  |         var key = await Utils.GenerateCode(text, db.Sections, (n, key) => n.DataKey == key); | ||||||
|  |          | ||||||
|         // In the case, when the user adds a section to the root, handle the insert differently: |         // In the case, when the user adds a section to the root, handle the insert differently: | ||||||
|         if (string.IsNullOrWhiteSpace(parentKey)) |         if (string.IsNullOrWhiteSpace(parentKey)) | ||||||
|         { |         { | ||||||
|  | |||||||
| @ -23,20 +23,9 @@ public static class TextElementProcessor | |||||||
|         var currentSection = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == currentSectionKey); |         var currentSection = await db.Sections.FirstOrDefaultAsync(n => n.DataKey == currentSectionKey); | ||||||
|         if (currentSection is null) |         if (currentSection is null) | ||||||
|             throw new ArgumentOutOfRangeException(nameof(currentSectionKey)); |             throw new ArgumentOutOfRangeException(nameof(currentSectionKey)); | ||||||
| 
 |  | ||||||
|         // Remove any whitespaces from the element name, regardless of how many e.g. spaces the user typed: |  | ||||||
|         var code = string.Join('_', elementName.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant(); |  | ||||||
|          |          | ||||||
|         // Check, if this key already exists: |         // Generate a code: | ||||||
|         if (await db.TextElements.AnyAsync(n => n.Section == currentSection && n.Code == code)) |         var code = await Utils.GenerateCode(elementName, db.TextElements, (n, code) => n.Section == currentSection && n.Code == code); | ||||||
|         { |  | ||||||
|             var rng = new Random(); |  | ||||||
|             while (await db.TextElements.AnyAsync(n => n.Section == currentSection && n.Code == code)) |  | ||||||
|             { |  | ||||||
|                 // Add a random number to the end of the key: |  | ||||||
|                 code += $"_{rng.Next(1, 10_000)}"; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|          |          | ||||||
|         var textElement = new TextElement |         var textElement = new TextElement | ||||||
|         { |         { | ||||||
|  | |||||||
							
								
								
									
										49
									
								
								I18N Commander/Processor/Utils.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								I18N Commander/Processor/Utils.cs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | using System.Linq.Expressions; | ||||||
|  | using Microsoft.EntityFrameworkCore; | ||||||
|  | 
 | ||||||
|  | namespace Processor; | ||||||
|  | 
 | ||||||
|  | internal static class Utils | ||||||
|  | { | ||||||
|  |     private static readonly Random RNG = new(); | ||||||
|  | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Generates a code out of this name. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="name">The name where the code based on</param> | ||||||
|  |     /// <param name="db">The data class</param> | ||||||
|  |     /// <param name="selector">The selector to check, if that key already exists. The string parameter is the current code to check.</param> | ||||||
|  |     /// <returns>The generated code</returns> | ||||||
|  |     internal static async Task<string> GenerateCode<TDbSet>(string name, DbSet<TDbSet> db, Expression<Func<TDbSet, string, bool>> selector) where TDbSet : class | ||||||
|  |     { | ||||||
|  |         // Filter all non-alphanumeric characters from the name by allowing only A-Z, a-z, 0-9, and spaces from the ASCII table: | ||||||
|  |         name = new string(name.Where(c => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '0' and <= '9' or ' ').ToArray()); | ||||||
|  | 
 | ||||||
|  |         // Remove any whitespaces from the element name, regardless of how many e.g. spaces the user typed: | ||||||
|  |         var code = string.Join('_', name.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)).ToUpperInvariant(); | ||||||
|  |          | ||||||
|  |         // | ||||||
|  |         // The Any() query want's an Expression<T, bool>, but we have an Expression<T, string, bool>, though. | ||||||
|  |         // Therefore, we have to currying the string away: | ||||||
|  |         var typeDbSet = Expression.Parameter(typeof(TDbSet), null); | ||||||
|  |         var curriedSelector = Expression.Lambda<Func<TDbSet, bool>>( | ||||||
|  |             Expression.Invoke(selector, typeDbSet, Expression.Constant(code)), | ||||||
|  |             typeDbSet | ||||||
|  |         ); | ||||||
|  |          | ||||||
|  |         // Check, if this key already exists. If so, add a random number to the end of the key: | ||||||
|  |         if (await db.AnyAsync(curriedSelector)) | ||||||
|  |             while (await db.AnyAsync(curriedSelector)) | ||||||
|  |             { | ||||||
|  |                 code += $"_{RNG.Next(1, 10_000)}"; | ||||||
|  |                  | ||||||
|  |                 // Due to the changed code & since the string is a constant, we have to re-currying the string away: | ||||||
|  |                 curriedSelector = Expression.Lambda<Func<TDbSet, bool>>( | ||||||
|  |                     Expression.Invoke(selector, typeDbSet, Expression.Constant(code)), | ||||||
|  |                     typeDbSet | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         return code; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user