Browse Source

Language generation

pull/1/head
Sebastian 9 years ago
parent
commit
4d7e26491f
  1. 94
      src/Squidex.Core/Contents/ContentData.cs
  2. 17
      src/Squidex.Core/Contents/ContentFieldData.cs
  3. 66
      src/Squidex.Core/Schemas/Schema.cs
  4. 6
      src/Squidex.Core/project.json
  5. 2
      src/Squidex.Events/project.json
  6. 8
      src/Squidex.Infrastructure.MongoDb/project.json
  7. 8
      src/Squidex.Infrastructure.RabbitMq/project.json
  8. 28
      src/Squidex.Infrastructure/CollectionExtensions.cs
  9. 88
      src/Squidex.Infrastructure/Language.cs
  10. 198
      src/Squidex.Infrastructure/Languages.cs
  11. 4
      src/Squidex.Infrastructure/PropertyValue.cs
  12. 11
      src/Squidex.Infrastructure/project.json
  13. 4
      src/Squidex.Read.MongoDb/project.json
  14. 2
      src/Squidex.Read/project.json
  15. 2
      src/Squidex.Write/Apps/AppDomainObject.cs
  16. 14
      src/Squidex.Write/Contents/Commands/PatchContent.cs
  17. 7
      src/Squidex.Write/Contents/ContentCommandHandler.cs
  18. 48
      src/Squidex.Write/Contents/ContentDomainObject.cs
  19. 2
      src/Squidex.Write/project.json
  20. 2
      src/Squidex/Config/MyUrlsOptions.cs
  21. 1
      src/Squidex/Config/Web/WebUsages.cs
  22. 11
      src/Squidex/Controllers/ContentApi/ContentsController.cs
  23. 16
      src/Squidex/Controllers/ContentApi/Generator/SchemasSwaggerGenerator.cs
  24. 2
      src/Squidex/Controllers/ContentApi/Models/ContentDto.cs
  25. 63
      src/Squidex/Pipeline/SingleUrlsMiddleware.cs
  26. 4
      src/Squidex/Startup.cs
  27. 12
      src/Squidex/project.json
  28. 237
      tests/Squidex.Core.Tests/Contents/ContentDataTests.cs
  29. 4
      tests/Squidex.Core.Tests/Schemas/SchemaTests.cs
  30. 137
      tests/Squidex.Core.Tests/Schemas/SchemaValidationTests.cs
  31. 4
      tests/Squidex.Core.Tests/project.json
  32. 34
      tests/Squidex.Infrastructure.Tests/CollectionExtensionsTests.cs
  33. 27
      tests/Squidex.Infrastructure.Tests/LanguageTests.cs
  34. 4
      tests/Squidex.Infrastructure.Tests/project.json
  35. 4
      tests/Squidex.Read.Tests/MongoDb/Contents/ODataQueryTests.cs
  36. 4
      tests/Squidex.Read.Tests/project.json
  37. 2
      tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs
  38. 36
      tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs
  39. 30
      tests/Squidex.Write.Tests/Contents/ContentCommandHandlerTests.cs
  40. 82
      tests/Squidex.Write.Tests/Contents/ContentDomainObjectTests.cs
  41. 4
      tests/Squidex.Write.Tests/project.json
  42. 66
      tools/GenerateLanguages/Program.cs
  43. 19
      tools/GenerateLanguages/project.json

94
src/Squidex.Core/Contents/ContentData.cs

@ -12,16 +12,22 @@ using System.Linq;
using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
// ReSharper disable InvertIf
namespace Squidex.Core.Contents
{
public sealed class ContentData : Dictionary<string, ContentFieldData>
public sealed class ContentData : Dictionary<string, ContentFieldData>, IEquatable<ContentData>
{
public ContentData()
: base(StringComparer.OrdinalIgnoreCase)
{
}
public ContentData(IDictionary<string, ContentFieldData> copy)
: base(copy, StringComparer.OrdinalIgnoreCase)
{
}
public ContentData AddField(string fieldName, ContentFieldData data)
{
Guard.ValidPropertyName(fieldName, nameof(fieldName));
@ -31,7 +37,31 @@ namespace Squidex.Core.Contents
return this;
}
public ContentData ToNameModel(Schema schema)
public ContentData MergeInto(ContentData other)
{
Guard.NotNull(other, nameof(other));
var result = new ContentData(this);
if (ReferenceEquals(other, this))
{
return result;
}
foreach (var otherValue in other)
{
var fieldValue = result.GetOrAdd(otherValue.Key, x => new ContentFieldData());
foreach (var value in otherValue.Value)
{
fieldValue[value.Key] = value.Value;
}
}
return result;
}
public ContentData ToIdModel(Schema schema)
{
Guard.NotNull(schema, nameof(schema));
@ -39,22 +69,20 @@ namespace Squidex.Core.Contents
foreach (var fieldValue in this)
{
long fieldId;
Field field;
if (!long.TryParse(fieldValue.Key, out fieldId) || !schema.Fields.TryGetValue(fieldId, out field))
if (!schema.FieldsByName.TryGetValue(fieldValue.Key, out field))
{
continue;
}
result[field.Name] = fieldValue.Value;
result[field.Id.ToString()] = fieldValue.Value;
}
return result;
}
public ContentData ToIdModel(Schema schema)
public ContentData ToNameModel(Schema schema)
{
Guard.NotNull(schema, nameof(schema));
@ -62,14 +90,16 @@ namespace Squidex.Core.Contents
foreach (var fieldValue in this)
{
long fieldId;
Field field;
if (!schema.FieldsByName.TryGetValue(fieldValue.Key, out field))
if (!long.TryParse(fieldValue.Key, out fieldId) || !schema.Fields.TryGetValue(fieldId, out field))
{
continue;
}
result[field.Id.ToString()] = fieldValue.Value;
result[field.Name] = fieldValue.Value;
}
return result;
@ -134,5 +164,51 @@ namespace Squidex.Core.Contents
return result;
}
public object ToLanguageModel(IReadOnlyCollection<Language> languagePreferences = null)
{
if (languagePreferences == null)
{
return this;
}
var result = new Dictionary<string, JToken>();
foreach (var fieldValue in this)
{
var fieldValues = fieldValue.Value;
foreach (var language in languagePreferences)
{
var languageCode = language.Iso2Code;
JToken value;
if (fieldValues.TryGetValue(languageCode, out value) && value != null)
{
result[fieldValue.Key] = value;
break;
}
}
}
return result;
}
public override bool Equals(object obj)
{
return Equals(obj as ContentData);
}
public bool Equals(ContentData other)
{
return other != null && (ReferenceEquals(this, other) || this.EqualsDictionary(other));
}
public override int GetHashCode()
{
return this.DictionaryHashCode();
}
}
}

17
src/Squidex.Core/Contents/ContentFieldData.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure;
namespace Squidex.Core.Contents
{
public sealed class ContentFieldData : Dictionary<string, JToken>
public sealed class ContentFieldData : Dictionary<string, JToken>, IEquatable<ContentFieldData>
{
public ContentFieldData()
: base(StringComparer.OrdinalIgnoreCase)
@ -35,5 +35,20 @@ namespace Squidex.Core.Contents
return this;
}
public override bool Equals(object obj)
{
return Equals(obj as ContentFieldData);
}
public bool Equals(ContentFieldData other)
{
return other != null && (ReferenceEquals(this, other) || this.EqualsDictionary(other));
}
public override int GetHashCode()
{
return this.DictionaryHashCode();
}
}
}

66
src/Squidex.Core/Schemas/Schema.cs

@ -203,17 +203,77 @@ namespace Squidex.Core.Schemas
return schema;
}
public async Task ValidatePartialAsync(ContentData data, IList<ValidationError> errors, HashSet<Language> languages)
{
Guard.NotNull(data, nameof(data));
Guard.NotNull(errors, nameof(errors));
foreach (var fieldData in data)
{
Field field;
if (!fieldsByName.TryGetValue(fieldData.Key, out field))
{
errors.Add(new ValidationError($"{fieldData.Key} is not a known field", fieldData.Key));
}
else
{
var fieldErrors = new List<string>();
if (field.RawProperties.IsLocalizable)
{
foreach (var languageValue in fieldData.Value)
{
Language language;
if (!Language.TryGetLanguage(languageValue.Key, out language))
{
fieldErrors.Add($"{field.Name} has an invalid language '{languageValue.Key}'");
}
else if (!languages.Contains(language))
{
fieldErrors.Add($"{field.Name} has an unsupported language '{languageValue.Key}'");
}
else
{
await field.ValidateAsync(languageValue.Value, fieldErrors, language);
}
}
}
else
{
if (fieldData.Value.Keys.Any(x => x != Language.Invariant.Iso2Code))
{
fieldErrors.Add($"{field.Name} can only contain a single entry for invariant language ({Language.Invariant.Iso2Code})");
}
JToken value;
if (fieldData.Value.TryGetValue(Language.Invariant.Iso2Code, out value))
{
await field.ValidateAsync(value, fieldErrors);
}
}
foreach (var error in fieldErrors)
{
errors.Add(new ValidationError(error, field.Name));
}
}
}
}
public async Task ValidateAsync(ContentData data, IList<ValidationError> errors, HashSet<Language> languages)
{
Guard.NotNull(data, nameof(data));
Guard.NotNull(errors, nameof(errors));
Guard.NotEmpty(languages, nameof(languages));
foreach (var fieldValue in data)
foreach (var fieldData in data)
{
if (!fieldsByName.ContainsKey(fieldValue.Key))
if (!fieldsByName.ContainsKey(fieldData.Key))
{
errors.Add(new ValidationError($"{fieldValue.Key} is not a known field", fieldValue.Key));
errors.Add(new ValidationError($"{fieldData.Key} is not a known field", fieldData.Key));
}
}

6
src/Squidex.Core/project.json

@ -1,10 +1,10 @@
{
"dependencies": {
"NodaTime": "2.0.0-alpha20160729",
"Squidex.Infrastructure": "1.0.0-*",
"protobuf-net": "2.1.0",
"NJsonSchema": "7.3.6214.20986",
"System.Collections.Immutable": "1.3.1"
"System.Collections.Immutable": "1.3.1",
"NodaTime": "2.0.0-beta20170123",
"NJsonSchema": "7.10.6235.25398"
},
"frameworks": {
"netstandard1.6": {

2
src/Squidex.Events/project.json

@ -1,6 +1,6 @@
{
"dependencies": {
"NodaTime": "2.0.0-alpha20160729",
"NodaTime": "2.0.0-beta20170123",
"Squidex.Core": "1.0.0-*",
"Squidex.Infrastructure": "1.0.0-*"
},

8
src/Squidex.Infrastructure.MongoDb/project.json

@ -1,11 +1,11 @@
{
{
"version": "1.0.0-*",
"dependencies": {
"Autofac": "4.2.1",
"Autofac": "4.3.0",
"Microsoft.Extensions.Logging": "1.1.0",
"MongoDB.Driver": "2.4.1",
"Newtonsoft.Json": "9.0.2-beta1",
"NodaTime": "2.0.0-alpha20160729",
"Newtonsoft.Json": "9.0.2-beta2",
"NodaTime": "2.0.0-beta20170123",
"Squidex.Infrastructure": "1.0.0-*",
"System.Linq": "4.3.0",
"System.Reactive": "3.1.1",

8
src/Squidex.Infrastructure.RabbitMq/project.json

@ -1,10 +1,10 @@
{
{
"version": "1.0.0-*",
"dependencies": {
"Autofac": "4.2.1",
"Autofac": "4.3.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Newtonsoft.Json": "9.0.2-beta1",
"NodaTime": "2.0.0-alpha20160729",
"Newtonsoft.Json": "9.0.2-beta2",
"NodaTime": "2.0.0-beta20170123",
"RabbitMQ.Client": "5.0.0-pre2",
"Squidex.Infrastructure": "1.0.0-*",
"System.Linq": "4.3.0",

28
src/Squidex.Infrastructure/CollectionExtensions.cs

@ -43,6 +43,8 @@ namespace Squidex.Infrastructure
public static int OrderedHashCode<T>(this IEnumerable<T> collection, IEqualityComparer<T> comparer)
{
Guard.NotNull(comparer, nameof(comparer));
var hashCodes = collection.Where(x => x != null).Select(x => x.GetHashCode()).OrderBy(x => x).ToArray();
var hashCode = 17;
@ -55,9 +57,33 @@ namespace Squidex.Infrastructure
return hashCode;
}
public static int DictionaryHashCode<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
{
return DictionaryHashCode(dictionary, EqualityComparer<TValue>.Default);
}
public static int DictionaryHashCode<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, IEqualityComparer<TValue> comparer)
{
Guard.NotNull(comparer, nameof(comparer));
var hashCode = 17;
foreach (var kvp in dictionary.OrderBy(x => x.Key))
{
hashCode = hashCode * 23 + kvp.Key.GetHashCode();
if (kvp.Value != null)
{
hashCode = hashCode * 23 + comparer.GetHashCode(kvp.Value);
}
}
return hashCode;
}
public static bool EqualsDictionary<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, IDictionary<TKey, TValue> other)
{
return Equals(dictionary, other) || (other != null && dictionary.Count == other.Count && !dictionary.Except(other).Any());
return other != null && dictionary.Count == other.Count && !dictionary.Except(other).Any();
}
public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)

88
src/Squidex.Infrastructure/Language.cs

@ -8,38 +8,27 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
// ReSharper disable ConvertIfStatementToReturnStatement
namespace Squidex.Infrastructure
{
public sealed class Language
public sealed partial class Language
{
private static readonly Regex CultureRegex = new Regex("([a-z]{2})(\\-[a-z]{2})?");
private readonly string iso2Code;
private readonly string englishName;
private static readonly Dictionary<string, Language> allLanguages = new Dictionary<string, Language>();
public static readonly Language Invariant = new Language("iv", "Invariant");
public static readonly Language Invariant = AddLanguage("iv", "Invariant");
static Language()
private static Language AddLanguage(string iso2Code, string englishName)
{
var resourceAssembly = typeof(Language).GetTypeInfo().Assembly;
var resourceStream = resourceAssembly.GetManifestResourceStream("Squidex.Infrastructure.language-codes.csv");
var language = new Language(iso2Code, englishName);
using (var reader = new StreamReader(resourceStream, Encoding.UTF8))
{
reader.ReadLine();
while (!reader.EndOfStream)
{
var languageLine = reader.ReadLine();
var languageIso2Code = languageLine.Substring(1, 2);
var languageEnglishName = languageLine.Substring(6, languageLine.Length - 7);
allLanguages[iso2Code] = language;
allLanguages[languageIso2Code] = new Language(languageIso2Code, languageEnglishName);
}
}
return language;
}
public static Language GetLanguage(string iso2Code)
@ -56,20 +45,6 @@ namespace Squidex.Infrastructure
}
}
public static bool TryGetLanguage(string iso2Code, out Language language)
{
Guard.NotNullOrEmpty(iso2Code, nameof(iso2Code));
return allLanguages.TryGetValue(iso2Code, out language);
}
public static bool IsValidLanguage(string iso2Code)
{
Guard.NotNullOrEmpty(iso2Code, nameof(iso2Code));
return allLanguages.ContainsKey(iso2Code);
}
public static IEnumerable<Language> AllLanguages
{
get { return allLanguages.Values; }
@ -91,5 +66,50 @@ namespace Squidex.Infrastructure
this.englishName = englishName;
}
public static bool IsValidLanguage(string iso2Code)
{
Guard.NotNullOrEmpty(iso2Code, nameof(iso2Code));
return allLanguages.ContainsKey(iso2Code);
}
public static bool TryGetLanguage(string iso2Code, out Language language)
{
Guard.NotNullOrEmpty(iso2Code, nameof(iso2Code));
return allLanguages.TryGetValue(iso2Code, out language);
}
public static Language TryParse(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
return null;
}
input = input.Trim();
if (input.Length != 2)
{
var match = CultureRegex.Match(input);
if (!match.Success)
{
return null;
}
input = match.Groups[0].Value;
}
Language result;
if (TryGetLanguage(input.ToLowerInvariant(), out result))
{
return result;
}
return null;
}
}
}

198
src/Squidex.Infrastructure/Languages.cs

@ -0,0 +1,198 @@
// ==========================================================================
// Langauges.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Infrastructure
{
partial class Language
{
public static Language AA = AddLanguage("aa", "Afar");
public static Language AB = AddLanguage("ab", "Abkhazian");
public static Language AE = AddLanguage("ae", "Avestan");
public static Language AF = AddLanguage("af", "Afrikaans");
public static Language AK = AddLanguage("ak", "Akan");
public static Language AM = AddLanguage("am", "Amharic");
public static Language AN = AddLanguage("an", "Aragonese");
public static Language AR = AddLanguage("ar", "Arabic");
public static Language AS = AddLanguage("as", "Assamese");
public static Language AV = AddLanguage("av", "Avaric");
public static Language AY = AddLanguage("ay", "Aymara");
public static Language AZ = AddLanguage("az", "Azerbaijani");
public static Language BA = AddLanguage("ba", "Bashkir");
public static Language BE = AddLanguage("be", "Belarusian");
public static Language BG = AddLanguage("bg", "Bulgarian");
public static Language BH = AddLanguage("bh", "Bihari languages");
public static Language BI = AddLanguage("bi", "Bislama");
public static Language BM = AddLanguage("bm", "Bambara");
public static Language BN = AddLanguage("bn", "Bengali");
public static Language BO = AddLanguage("bo", "Tibetan");
public static Language BR = AddLanguage("br", "Breton");
public static Language BS = AddLanguage("bs", "Bosnian");
public static Language CA = AddLanguage("ca", "Catalan; Valencian");
public static Language CE = AddLanguage("ce", "Chechen");
public static Language CH = AddLanguage("ch", "Chamorro");
public static Language CO = AddLanguage("co", "Corsican");
public static Language CR = AddLanguage("cr", "Cree");
public static Language CS = AddLanguage("cs", "Czech");
public static Language CU = AddLanguage("cu", "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic");
public static Language CV = AddLanguage("cv", "Chuvash");
public static Language CY = AddLanguage("cy", "Welsh");
public static Language DA = AddLanguage("da", "Danish");
public static Language DE = AddLanguage("de", "German");
public static Language DV = AddLanguage("dv", "Divehi; Dhivehi; Maldivian");
public static Language DZ = AddLanguage("dz", "Dzongkha");
public static Language EE = AddLanguage("ee", "Ewe");
public static Language EL = AddLanguage("el", "Greek, Modern (1453-)");
public static Language EN = AddLanguage("en", "English");
public static Language EO = AddLanguage("eo", "Esperanto");
public static Language ES = AddLanguage("es", "Spanish; Castilian");
public static Language ET = AddLanguage("et", "Estonian");
public static Language EU = AddLanguage("eu", "Basque");
public static Language FA = AddLanguage("fa", "Persian");
public static Language FF = AddLanguage("ff", "Fulah");
public static Language FI = AddLanguage("fi", "Finnish");
public static Language FJ = AddLanguage("fj", "Fijian");
public static Language FO = AddLanguage("fo", "Faroese");
public static Language FR = AddLanguage("fr", "French");
public static Language FY = AddLanguage("fy", "Western Frisian");
public static Language GA = AddLanguage("ga", "Irish");
public static Language GD = AddLanguage("gd", "Gaelic; Scottish Gaelic");
public static Language GL = AddLanguage("gl", "Galician");
public static Language GN = AddLanguage("gn", "Guarani");
public static Language GU = AddLanguage("gu", "Gujarati");
public static Language GV = AddLanguage("gv", "Manx");
public static Language HA = AddLanguage("ha", "Hausa");
public static Language HE = AddLanguage("he", "Hebrew");
public static Language HI = AddLanguage("hi", "Hindi");
public static Language HO = AddLanguage("ho", "Hiri Motu");
public static Language HR = AddLanguage("hr", "Croatian");
public static Language HT = AddLanguage("ht", "Haitian; Haitian Creole");
public static Language HU = AddLanguage("hu", "Hungarian");
public static Language HY = AddLanguage("hy", "Armenian");
public static Language HZ = AddLanguage("hz", "Herero");
public static Language IA = AddLanguage("ia", "Interlingua (International Auxiliary Language Association)");
public static Language ID = AddLanguage("id", "Indonesian");
public static Language IE = AddLanguage("ie", "Interlingue; Occidental");
public static Language IG = AddLanguage("ig", "Igbo");
public static Language II = AddLanguage("ii", "Sichuan Yi; Nuosu");
public static Language IK = AddLanguage("ik", "Inupiaq");
public static Language IO = AddLanguage("io", "Ido");
public static Language IS = AddLanguage("is", "Icelandic");
public static Language IT = AddLanguage("it", "Italian");
public static Language IU = AddLanguage("iu", "Inuktitut");
public static Language JA = AddLanguage("ja", "Japanese");
public static Language JV = AddLanguage("jv", "Javanese");
public static Language KA = AddLanguage("ka", "Georgian");
public static Language KG = AddLanguage("kg", "Kongo");
public static Language KI = AddLanguage("ki", "Kikuyu; Gikuyu");
public static Language KJ = AddLanguage("kj", "Kuanyama; Kwanyama");
public static Language KK = AddLanguage("kk", "Kazakh");
public static Language KL = AddLanguage("kl", "Kalaallisut; Greenlandic");
public static Language KM = AddLanguage("km", "Central Khmer");
public static Language KN = AddLanguage("kn", "Kannada");
public static Language KO = AddLanguage("ko", "Korean");
public static Language KR = AddLanguage("kr", "Kanuri");
public static Language KS = AddLanguage("ks", "Kashmiri");
public static Language KU = AddLanguage("ku", "Kurdish");
public static Language KV = AddLanguage("kv", "Komi");
public static Language KW = AddLanguage("kw", "Cornish");
public static Language KY = AddLanguage("ky", "Kirghiz; Kyrgyz");
public static Language LA = AddLanguage("la", "Latin");
public static Language LB = AddLanguage("lb", "Luxembourgish; Letzeburgesch");
public static Language LG = AddLanguage("lg", "Ganda");
public static Language LI = AddLanguage("li", "Limburgan; Limburger; Limburgish");
public static Language LN = AddLanguage("ln", "Lingala");
public static Language LO = AddLanguage("lo", "Lao");
public static Language LT = AddLanguage("lt", "Lithuanian");
public static Language LU = AddLanguage("lu", "Luba-Katanga");
public static Language LV = AddLanguage("lv", "Latvian");
public static Language MG = AddLanguage("mg", "Malagasy");
public static Language MH = AddLanguage("mh", "Marshallese");
public static Language MI = AddLanguage("mi", "Maori");
public static Language MK = AddLanguage("mk", "Macedonian");
public static Language ML = AddLanguage("ml", "Malayalam");
public static Language MN = AddLanguage("mn", "Mongolian");
public static Language MR = AddLanguage("mr", "Marathi");
public static Language MS = AddLanguage("ms", "Malay");
public static Language MT = AddLanguage("mt", "Maltese");
public static Language MY = AddLanguage("my", "Burmese");
public static Language NA = AddLanguage("na", "Nauru");
public static Language NB = AddLanguage("nb", "Bokmål, Norwegian; Norwegian Bokmål");
public static Language ND = AddLanguage("nd", "Ndebele, North; North Ndebele");
public static Language NE = AddLanguage("ne", "Nepali");
public static Language NG = AddLanguage("ng", "Ndonga");
public static Language NL = AddLanguage("nl", "Dutch; Flemish");
public static Language NN = AddLanguage("nn", "Norwegian Nynorsk; Nynorsk, Norwegian");
public static Language NO = AddLanguage("no", "Norwegian");
public static Language NR = AddLanguage("nr", "Ndebele, South; South Ndebele");
public static Language NV = AddLanguage("nv", "Navajo; Navaho");
public static Language NY = AddLanguage("ny", "Chichewa; Chewa; Nyanja");
public static Language OC = AddLanguage("oc", "Occitan (post 1500); Provençal");
public static Language OJ = AddLanguage("oj", "Ojibwa");
public static Language OM = AddLanguage("om", "Oromo");
public static Language OR = AddLanguage("or", "Oriya");
public static Language OS = AddLanguage("os", "Ossetian; Ossetic");
public static Language PA = AddLanguage("pa", "Panjabi; Punjabi");
public static Language PI = AddLanguage("pi", "Pali");
public static Language PL = AddLanguage("pl", "Polish");
public static Language PS = AddLanguage("ps", "Pushto; Pashto");
public static Language PT = AddLanguage("pt", "Portuguese");
public static Language QU = AddLanguage("qu", "Quechua");
public static Language RM = AddLanguage("rm", "Romansh");
public static Language RN = AddLanguage("rn", "Rundi");
public static Language RO = AddLanguage("ro", "Romanian; Moldavian; Moldovan");
public static Language RU = AddLanguage("ru", "Russian");
public static Language RW = AddLanguage("rw", "Kinyarwanda");
public static Language SA = AddLanguage("sa", "Sanskrit");
public static Language SC = AddLanguage("sc", "Sardinian");
public static Language SD = AddLanguage("sd", "Sindhi");
public static Language SE = AddLanguage("se", "Northern Sami");
public static Language SG = AddLanguage("sg", "Sango");
public static Language SI = AddLanguage("si", "Sinhala; Sinhalese");
public static Language SK = AddLanguage("sk", "Slovak");
public static Language SL = AddLanguage("sl", "Slovenian");
public static Language SM = AddLanguage("sm", "Samoan");
public static Language SN = AddLanguage("sn", "Shona");
public static Language SO = AddLanguage("so", "Somali");
public static Language SQ = AddLanguage("sq", "Albanian");
public static Language SR = AddLanguage("sr", "Serbian");
public static Language SS = AddLanguage("ss", "Swati");
public static Language ST = AddLanguage("st", "Sotho, Southern");
public static Language SU = AddLanguage("su", "Sundanese");
public static Language SV = AddLanguage("sv", "Swedish");
public static Language SW = AddLanguage("sw", "Swahili");
public static Language TA = AddLanguage("ta", "Tamil");
public static Language TE = AddLanguage("te", "Telugu");
public static Language TG = AddLanguage("tg", "Tajik");
public static Language TH = AddLanguage("th", "Thai");
public static Language TI = AddLanguage("ti", "Tigrinya");
public static Language TK = AddLanguage("tk", "Turkmen");
public static Language TL = AddLanguage("tl", "Tagalog");
public static Language TN = AddLanguage("tn", "Tswana");
public static Language TO = AddLanguage("to", "Tonga (Tonga Islands)");
public static Language TR = AddLanguage("tr", "Turkish");
public static Language TS = AddLanguage("ts", "Tsonga");
public static Language TT = AddLanguage("tt", "Tatar");
public static Language TW = AddLanguage("tw", "Twi");
public static Language TY = AddLanguage("ty", "Tahitian");
public static Language UG = AddLanguage("ug", "Uighur; Uyghur");
public static Language UK = AddLanguage("uk", "Ukrainian");
public static Language UR = AddLanguage("ur", "Urdu");
public static Language UZ = AddLanguage("uz", "Uzbek");
public static Language VE = AddLanguage("ve", "Venda");
public static Language VI = AddLanguage("vi", "Vietnamese");
public static Language VO = AddLanguage("vo", "Volapük");
public static Language WA = AddLanguage("wa", "Walloon");
public static Language WO = AddLanguage("wo", "Wolof");
public static Language XH = AddLanguage("xh", "Xhosa");
public static Language YI = AddLanguage("yi", "Yiddish");
public static Language YO = AddLanguage("yo", "Yoruba");
public static Language ZA = AddLanguage("za", "Zhuang; Chuang");
public static Language ZH = AddLanguage("zh", "Chinese");
public static Language ZU = AddLanguage("zu", "Zulu");
}
}

4
src/Squidex.Infrastructure/PropertyValue.cs

@ -127,12 +127,12 @@ namespace Squidex.Infrastructure
public Instant ToInstant(CultureInfo culture)
{
return ToOrParseValue(culture, x => InstantPattern.GeneralPattern.Parse(x).Value);
return ToOrParseValue(culture, x => InstantPattern.General.Parse(x).Value);
}
public Instant? ToNullableInstant(CultureInfo culture)
{
return ToNullableOrParseValue(culture, x => InstantPattern.GeneralPattern.Parse(x).Value);
return ToNullableOrParseValue(culture, x => InstantPattern.General.Parse(x).Value);
}
public Guid ToGuid(CultureInfo culture)

11
src/Squidex.Infrastructure/project.json

@ -1,10 +1,10 @@
{
"version": "1.0.0-*",
"dependencies": {
"Autofac": "4.2.1",
"Autofac": "4.3.0",
"Microsoft.Extensions.Logging": "1.1.0",
"Newtonsoft.Json": "9.0.2-beta1",
"NodaTime": "2.0.0-alpha20160729",
"Newtonsoft.Json": "9.0.2-beta2",
"NodaTime": "2.0.0-beta20170123",
"protobuf-net": "2.1.0",
"System.Linq": "4.3.0",
"System.Reactive": "3.1.1",
@ -19,11 +19,6 @@
"imports": "dnxcore50"
}
},
"buildOptions": {
"embed": [
"*.csv"
]
},
"tooling": {
"defaultNamespace": "Squidex.Infrastructure"
}

4
src/Squidex.Read.MongoDb/project.json

@ -1,7 +1,7 @@
{
"dependencies": {
"Autofac": "4.2.1",
"IdentityServer4": "1.0.0",
"Autofac": "4.3.0",
"IdentityServer4": "1.0.2",
"Microsoft.AspNetCore.Identity": "1.1.0",
"Microsoft.AspNetCore.Identity.MongoDB": "1.0.2",
"MongoDB.Driver": "2.4.1",

2
src/Squidex.Read/project.json

@ -2,7 +2,7 @@
"dependencies": {
"Microsoft.Extensions.Caching.Memory": "1.1.0",
"MongoDB.Driver": "2.4.1",
"NodaTime": "2.0.0-alpha20160729",
"NodaTime": "2.0.0-beta20170123",
"Squidex.Core": "1.0.0-*",
"Squidex.Events": "1.0.0-*",
"Squidex.Infrastructure": "1.0.0-*"

2
src/Squidex.Write/Apps/AppDomainObject.cs

@ -23,7 +23,7 @@ namespace Squidex.Write.Apps
{
public class AppDomainObject : DomainObject
{
private static readonly Language DefaultLanguage = Language.GetLanguage("en");
private static readonly Language DefaultLanguage = Language.EN;
private readonly AppContributors contributors = new AppContributors();
private readonly AppLanguages languages = new AppLanguages();
private readonly AppClients clients = new AppClients();

14
src/Squidex.Write/Contents/Commands/PatchContent.cs

@ -0,0 +1,14 @@
// ==========================================================================
// PatchContent.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Write.Contents.Commands
{
public class PatchContent : ContentDataCommand
{
}
}

7
src/Squidex.Write/Contents/ContentCommandHandler.cs

@ -57,6 +57,13 @@ namespace Squidex.Write.Contents
await handler.UpdateAsync<ContentDomainObject>(command, s => s.Update(command));
}
protected async Task On(PatchContent command, CommandContext context)
{
await ValidateAsync(command, () => "Failed to patch content");
await handler.UpdateAsync<ContentDomainObject>(command, s => s.Patch(command));
}
protected Task On(PublishContent command, CommandContext context)
{
return handler.UpdateAsync<ContentDomainObject>(command, s => s.Publish(command));

48
src/Squidex.Write/Contents/ContentDomainObject.cs

@ -7,6 +7,7 @@
// ==========================================================================
using System;
using Squidex.Core.Contents;
using Squidex.Events.Contents;
using Squidex.Infrastructure;
using Squidex.Infrastructure.CQRS;
@ -22,6 +23,7 @@ namespace Squidex.Write.Contents
private bool isDeleted;
private bool isCreated;
private bool isPublished;
private ContentData data;
public bool IsDeleted
{
@ -41,6 +43,13 @@ namespace Squidex.Write.Contents
protected void On(ContentCreated @event)
{
isCreated = true;
data = @event.Data;
}
protected void On(ContentUpdated @event)
{
data = @event.Data;
}
protected void On(ContentPublished @event)
@ -69,46 +78,65 @@ namespace Squidex.Write.Contents
return this;
}
public ContentDomainObject Update(UpdateContent command)
public ContentDomainObject Delete(DeleteContent command)
{
Guard.Valid(command, nameof(command), () => "Cannot update content");
Guard.NotNull(command, nameof(command));
VerifyCreatedAndNotDeleted();
RaiseEvent(SimpleMapper.Map(command, new ContentUpdated()));
RaiseEvent(SimpleMapper.Map(command, new ContentDeleted()));
return this;
}
public ContentDomainObject Delete(DeleteContent command)
public ContentDomainObject Publish(PublishContent command)
{
Guard.NotNull(command, nameof(command));
VerifyCreatedAndNotDeleted();
RaiseEvent(SimpleMapper.Map(command, new ContentDeleted()));
RaiseEvent(SimpleMapper.Map(command, new ContentPublished()));
return this;
}
public ContentDomainObject Publish(PublishContent command)
public ContentDomainObject Unpublish(UnpublishContent command)
{
Guard.NotNull(command, nameof(command));
VerifyCreatedAndNotDeleted();
RaiseEvent(SimpleMapper.Map(command, new ContentPublished()));
RaiseEvent(SimpleMapper.Map(command, new ContentUnpublished()));
return this;
}
public ContentDomainObject Unpublish(UnpublishContent command)
public ContentDomainObject Update(UpdateContent command)
{
Guard.NotNull(command, nameof(command));
Guard.Valid(command, nameof(command), () => "Cannot update content");
VerifyCreatedAndNotDeleted();
RaiseEvent(SimpleMapper.Map(command, new ContentUnpublished()));
if (!command.Data.Equals(data))
{
RaiseEvent(SimpleMapper.Map(command, new ContentUpdated()));
}
return this;
}
public ContentDomainObject Patch(PatchContent command)
{
Guard.Valid(command, nameof(command), () => "Cannot patch content");
VerifyCreatedAndNotDeleted();
var newData = data.MergeInto(command.Data);
if (!newData.Equals(data))
{
RaiseEvent(new ContentUpdated { Data = newData });
}
return this;
}

2
src/Squidex.Write/project.json

@ -1,7 +1,7 @@
{
"dependencies": {
"Microsoft.AspNetCore.Identity": "1.1.0",
"NodaTime": "2.0.0-alpha20160729",
"NodaTime": "2.0.0-beta20170123",
"Squidex.Core": "1.0.0-*",
"Squidex.Events": "1.0.0-*",
"Squidex.Infrastructure": "1.0.0-*",

2
src/Squidex/Config/MyUrlsOptions.cs

@ -12,6 +12,8 @@ namespace Squidex.Config
{
public sealed class MyUrlsOptions
{
public bool EnforceSSL { get; set; }
public string BaseUrl { get; set; }
public string BuildUrl(string path, bool trailingSlash = true)

1
src/Squidex/Config/Web/WebUsages.cs

@ -22,6 +22,7 @@ namespace Squidex.Config.Web
{
OnPrepareResponse = context =>
{
context.Context.Request.GetTypedHeaders();
var response = context.Context.Response;
var headers = response.GetTypedHeaders();

11
src/Squidex/Controllers/ContentApi/ContentsController.cs

@ -130,6 +130,17 @@ namespace Squidex.Controllers.ContentApi
return NoContent();
}
[HttpPatch]
[Route("content/{app}/{name}/{id}")]
public async Task<IActionResult> PatchContent(Guid id, [FromBody] ContentData request)
{
var command = new PatchContent { AggregateId = id, Data = request };
await CommandBus.PublishAsync(command);
return NoContent();
}
[HttpPut]
[Route("content/{app}/{name}/{id}/publish")]
public async Task<IActionResult> PublishContent(Guid id)

16
src/Squidex/Controllers/ContentApi/Generator/SchemasSwaggerGenerator.cs

@ -185,6 +185,7 @@ When you change the field to be localizable the value will become the value for
GenerateSchemaCreateOperation(schema, schemaName),
GenerateSchemaGetOperation(schema, schemaName),
GenerateSchemaUpdateOperation(schema, schemaName),
GenerateSchemaPatchOperation(schema, schemaName),
GenerateSchemaPublishOperation(schema, schemaName),
GenerateSchemaUnpublishOperation(schema, schemaName),
GenerateSchemaDeleteOperation(schema, schemaName)
@ -257,6 +258,21 @@ When you change the field to be localizable the value will become the value for
});
}
private SwaggerOperations GenerateSchemaPatchOperation(Schema schema, string schemaName)
{
return AddOperation(SwaggerOperationMethod.Patch, schemaName, $"{appBasePath}/{schema.Name}/{{id}}", operation =>
{
operation.Summary = $"Update a {schemaName} content element partially.";
var bodySchema = AppendSchema($"{schema.Name}Dto", schema.BuildSchema(languages, AppendSchema));
operation.Parameters.AddBodyParameter(bodySchema, "data", string.Format(BodyDescription, schemaName));
operation.Responses.Add("204",
new SwaggerResponse { Description = $"{schemaName} element updated." });
});
}
private SwaggerOperations GenerateSchemaPublishOperation(Schema schema, string schemaName)
{
return AddOperation(SwaggerOperationMethod.Put, schemaName, $"{appBasePath}/{schema.Name}/{{id}}/publish", operation =>

2
src/Squidex/Controllers/ContentApi/Models/ContentDto.cs

@ -36,7 +36,7 @@ namespace Squidex.Controllers.ContentApi.Models
/// The data of the content item.
/// </summary>
[Required]
public ContentData Data { get; set; }
public object Data { get; set; }
/// <summary>
/// The date and time when the content element has been created.

63
src/Squidex/Pipeline/SingleUrlsMiddleware.cs

@ -0,0 +1,63 @@
// ==========================================================================
// SingleUrlsMiddleware.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Squidex.Config;
namespace Squidex.Pipeline
{
public sealed class SingleUrlsMiddleware
{
private readonly RequestDelegate next;
private readonly IOptions<MyUrlsOptions> urls;
private readonly ILogger<SingleUrlsMiddleware> logger;
public SingleUrlsMiddleware(RequestDelegate next, ILoggerFactory factory, IOptions<MyUrlsOptions> urls)
{
this.next = next;
this.urls = urls;
logger = factory.CreateLogger<SingleUrlsMiddleware>();
}
public async Task Invoke(HttpContext context)
{
if (!urls.Value.EnforceSSL)
{
await next(context);
}
else
{
var currentUrl = string.Concat(context.Request.Scheme, "://", context.Request.Host, context.Request.Path);
var hostName = context.Request.Host.ToString().ToLowerInvariant();
if (hostName.StartsWith("www."))
{
hostName = hostName.Substring(4);
}
var newUrl = string.Concat("https://", hostName, context.Request.Path);
if (!string.Equals(newUrl, currentUrl, StringComparison.OrdinalIgnoreCase))
{
logger.LogError("Invalid url: {0} instead {1}", currentUrl, newUrl);
context.Response.Redirect(newUrl + context.Request.QueryString, true);
}
else
{
await next(context);
}
}
}
}
}

4
src/Squidex/Startup.cs

@ -80,6 +80,7 @@ namespace Squidex
Configuration.GetSection("identity"));
var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterModule<InfrastructureModule>();
builder.RegisterModule<MongoDbEventStoreModule>();
builder.RegisterModule<MongoDbModule>();
@ -87,7 +88,6 @@ namespace Squidex
builder.RegisterModule<ReadModule>();
builder.RegisterModule<WebModule>();
builder.RegisterModule<WriteModule>();
builder.Populate(services);
var container = builder.Build();
@ -104,6 +104,8 @@ namespace Squidex
loggerFactory.AddConsole(LogLevel.Debug);
loggerFactory.AddDebug();
app.UseMiddleware<SingleUrlsMiddleware>();
MapAndUseIdentity(app);
MapAndUseApi(app);
MapAndUseFrontend(app);

12
src/Squidex/project.json

@ -1,16 +1,16 @@
{
"dependencies": {
"Autofac": "4.2.1",
"Autofac": "4.3.0",
"Autofac.Extensions.DependencyInjection": "4.0.0",
"IdentityServer4": "1.0.0",
"IdentityServer4.AccessTokenValidation": "1.0.2",
"IdentityServer4": "1.0.2",
"IdentityServer4.AccessTokenValidation": "1.0.4",
"IdentityServer4.AspNetIdentity": "1.0.0",
"Microsoft.AspNetCore.Authentication.Cookies": "1.1.0",
"Microsoft.AspNetCore.Authentication.Google": "1.1.0",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.1.0",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Identity": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Mvc": "1.1.1",
"Microsoft.AspNetCore.Razor.Tools": "1.1.0-preview4-final",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final",
@ -23,8 +23,8 @@
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
"MongoDB.Driver": "2.4.1",
"NJsonSchema": "7.3.6214.20986",
"NSwag.AspNetCore": "8.5.0",
"NJsonSchema": "7.10.6235.25398",
"NSwag.AspNetCore": "8.8.0",
"OpenCover": "4.6.519",
"ReportGenerator": "2.5.2",
"Squidex.Core": "1.0.0-*",

237
tests/Squidex.Core.Tests/Contents/ContentDataTests.cs

@ -7,7 +7,6 @@
// ==========================================================================
using System.Collections.Generic;
using FluentAssertions;
using Newtonsoft.Json.Linq;
using Squidex.Core.Schemas;
using Squidex.Infrastructure;
@ -26,8 +25,8 @@ namespace Squidex.Core.Contents
.AddOrUpdateField(
new NumberField(3, "field3", new NumberFieldProperties { IsLocalizable = false }))
.HideField(3);
private readonly Language[] languages = { Language.GetLanguage("de"), Language.GetLanguage("en") };
private readonly Language masterLanguage = Language.GetLanguage("en");
private readonly Language[] languages = { Language.DE, Language.EN };
private readonly Language masterLanguage = Language.EN;
[Fact]
public void Should_convert_to_id_model()
@ -56,10 +55,10 @@ namespace Squidex.Core.Contents
.AddField("2",
new ContentFieldData()
.AddValue("iv", 3));
actual.ShouldBeEquivalentTo(expected);
}
Assert.Equal(expected, actual);
}
[Fact]
public void Should_convert_to_from_id_model()
{
@ -87,22 +86,18 @@ namespace Squidex.Core.Contents
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 3));
actual.ShouldBeEquivalentTo(expected);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_cleanup_old_fields()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field1"] = new Dictionary<string, JToken>
{
["en"] = "en_string",
["de"] = "de_string"
}
};
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("en", "en_string")
.AddValue("de", "de_string"));
var input =
new ContentData()
@ -114,23 +109,19 @@ namespace Squidex.Core.Contents
.AddValue("en", "en_string")
.AddValue("de", "de_string"));
var output = input.ToApiModel(schema, languages, masterLanguage);
var actual = input.ToApiModel(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_cleanup_old_languages()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field1"] = new Dictionary<string, JToken>
{
["en"] = "en_string",
["de"] = "de_string"
}
};
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("en", "en_string")
.AddValue("de", "de_string"));
var input =
new ContentData()
@ -140,22 +131,19 @@ namespace Squidex.Core.Contents
.AddValue("de", "de_string")
.AddValue("it", "it_string"));
var output = input.ToApiModel(schema, languages, masterLanguage);
var actual = input.ToApiModel(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_provide_invariant_from_master_language()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field2"] = new Dictionary<string, JToken>
{
["iv"] = 3
}
};
new ContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 3));
var input =
new ContentData()
@ -164,22 +152,19 @@ namespace Squidex.Core.Contents
.AddValue("de", 2)
.AddValue("en", 3));
var output = input.ToApiModel(schema, languages, masterLanguage);
var actual = input.ToApiModel(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_provide_invariant_from_first_language()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field2"] = new Dictionary<string, JToken>
{
["iv"] = 2
}
};
new ContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
var input =
new ContentData()
@ -188,35 +173,167 @@ namespace Squidex.Core.Contents
.AddValue("de", 2)
.AddValue("it", 3));
var output = input.ToApiModel(schema, languages, masterLanguage);
var actual = input.ToApiModel(schema, languages, masterLanguage);
output.ShouldBeEquivalentTo(expected);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_not_include_hidden_field()
{
var expected =
new Dictionary<string, Dictionary<string, JToken>>
{
["field2"] = new Dictionary<string, JToken>
{
["iv"] = 2
}
};
new ContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 5));
var input =
new ContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2))
.AddValue("iv", 5))
.AddField("field3",
new ContentFieldData()
.AddValue("iv", 2));
var actual = input.ToApiModel(schema, languages, masterLanguage);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_return_original_when_no_language_preferences_defined()
{
var data =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 1));
Assert.Same(data, data.ToLanguageModel());
}
[Fact]
public void Should_return_flat_list_when_languages_specified()
{
var data =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("de", 1)
.AddValue("en", 2))
.AddField("field2",
new ContentFieldData()
.AddValue("de", null)
.AddValue("en", 4))
.AddField("field3",
new ContentFieldData()
.AddValue("en", 6))
.AddField("field4",
new ContentFieldData()
.AddValue("it", 7));
var output = (Dictionary<string, JToken>)data.ToLanguageModel(new List<Language> { Language.DE, Language.EN });
var expected = new Dictionary<string, JToken>
{
{ "field1", 1 },
{ "field2", 4 },
{ "field3", 6 },
};
Assert.True(expected.EqualsDictionary(output));
}
[Fact]
public void Should_merge_two_data()
{
var lhs =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 1))
.AddField("field2",
new ContentFieldData()
.AddValue("de", 2));
var rhs =
new ContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("en", 3))
.AddField("field3",
new ContentFieldData()
.AddValue("iv", 4));
var expected =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 1))
.AddField("field2",
new ContentFieldData()
.AddValue("de", 2)
.AddValue("en", 3))
.AddField("field3",
new ContentFieldData()
.AddValue("iv", 4));
var actual = lhs.MergeInto(rhs);
Assert.Equal(expected, actual);
}
[Fact]
public void Should_be_equal_when_data_have_same_structure()
{
var lhs =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 2))
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
var rhs =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 2))
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
Assert.True(lhs.Equals(rhs));
Assert.True(lhs.Equals((object)rhs));
Assert.Equal(lhs.GetHashCode(), rhs.GetHashCode());
}
[Fact]
public void Should_not_be_equal_when_data_have_not_same_structure()
{
var lhs =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 2))
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
var output = input.ToApiModel(schema, languages, masterLanguage);
var rhs =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("en", 2))
.AddField("field3",
new ContentFieldData()
.AddValue("iv", 2));
output.ShouldBeEquivalentTo(expected);
Assert.False(lhs.Equals(rhs));
Assert.False(lhs.Equals((object)rhs));
Assert.NotEqual(lhs.GetHashCode(), rhs.GetHashCode());
}
}
}

4
tests/Squidex.Core.Tests/Schemas/SchemaTests.cs

@ -258,7 +258,7 @@ namespace Squidex.Core.Schemas
.AddOrUpdateField(new NumberField(4, "age",
new NumberFieldProperties { MinValue = 1, MaxValue = 10 }));
var languages = new HashSet<Language>(new[] { Language.GetLanguage("de"), Language.GetLanguage("en") });
var languages = new HashSet<Language>(new[] { Language.DE, Language.EN });
var json = schema.BuildSchema(languages, (n, s) => s).ToJson();
@ -279,7 +279,7 @@ namespace Squidex.Core.Schemas
.AddOrUpdateField(new NumberField(4, "age",
new NumberFieldProperties { MinValue = 1, MaxValue = 10 }));
var languages = new HashSet<Language>(new[] { Language.GetLanguage("de"), Language.GetLanguage("en") });
var languages = new HashSet<Language>(new[] { Language.DE, Language.EN });
var edmModel = schema.BuildEdmType(languages, x => x);

137
tests/Squidex.Core.Tests/Schemas/SchemaValidationTests.cs

@ -17,7 +17,7 @@ namespace Squidex.Core.Schemas
{
public class SchemaValidationTests
{
private readonly HashSet<Language> languages = new HashSet<Language>(new[] { Language.GetLanguage("de"), Language.GetLanguage("en") });
private readonly HashSet<Language> languages = new HashSet<Language>(new[] { Language.DE, Language.EN });
private readonly List<ValidationError> errors = new List<ValidationError>();
private Schema sut = Schema.Create("my-name", new SchemaProperties());
@ -59,7 +59,7 @@ namespace Squidex.Core.Schemas
}
[Fact]
public async Task Should_add_error_non_localizable_field_contains_language()
public async Task Should_add_error_non_localizable_data_field_contains_language()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties()));
@ -98,7 +98,7 @@ namespace Squidex.Core.Schemas
}
[Fact]
public async Task Should_add_error_if_required_field_is_not_in_bag()
public async Task Should_add_error_if_required_data_field_is_not_in_bag()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsRequired = true }));
@ -115,7 +115,7 @@ namespace Squidex.Core.Schemas
}
[Fact]
public async Task Should_add_error_if_value_contains_invalid_language()
public async Task Should_add_error_if_data_contains_invalid_language()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsLocalizable = true }));
@ -136,7 +136,7 @@ namespace Squidex.Core.Schemas
}
[Fact]
public async Task Should_add_error_if_value_contains_unsupported_language()
public async Task Should_add_error_if_data_contains_unsupported_language()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsLocalizable = true }));
@ -156,5 +156,132 @@ namespace Squidex.Core.Schemas
new ValidationError("my-field has an unsupported language 'it'", "my-field")
});
}
[Fact]
public async Task Should_add_error_if_validating_partial_data_with_unknown_field()
{
var data =
new ContentData()
.AddField("unknown",
new ContentFieldData());
await sut.ValidatePartialAsync(data, errors, languages);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("unknown is not a known field", "unknown")
});
}
[Fact]
public async Task Should_add_error_if_validating_partial_data_with_invalid_field()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { MaxValue = 100 }));
var data =
new ContentData()
.AddField("my-field",
new ContentFieldData()
.SetValue(1000));
await sut.ValidatePartialAsync(data, errors, languages);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field must be less than '100'", "my-field")
});
}
[Fact]
public async Task Should_add_error_non_localizable_partial_data_field_contains_language()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties()));
var data =
new ContentData()
.AddField("my-field",
new ContentFieldData()
.AddValue("es", 1)
.AddValue("it", 1));
await sut.ValidatePartialAsync(data, errors, languages);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field can only contain a single entry for invariant language (iv)", "my-field")
});
}
[Fact]
public async Task Should_not_add_error_if_validating_partial_data_with_invalid_localizable_field()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsRequired = true, IsLocalizable = true }));
var data =
new ContentData();
await sut.ValidatePartialAsync(data, errors, languages);
Assert.Equal(0, errors.Count);
}
[Fact]
public async Task Should_not_add_error_if_required_partial_data_field_is_not_in_bag()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsRequired = true }));
var data =
new ContentData();
await sut.ValidatePartialAsync(data, errors, languages);
Assert.Equal(0, errors.Count);
}
[Fact]
public async Task Should_add_error_if_partial_data_contains_invalid_language()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsLocalizable = true }));
var data =
new ContentData()
.AddField("my-field",
new ContentFieldData()
.AddValue("de", 1)
.AddValue("xx", 1));
await sut.ValidatePartialAsync(data, errors, languages);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an invalid language 'xx'", "my-field")
});
}
[Fact]
public async Task Should_add_error_if_partial_data_contains_unsupported_language()
{
sut = sut.AddOrUpdateField(new NumberField(1, "my-field", new NumberFieldProperties { IsLocalizable = true }));
var data =
new ContentData()
.AddField("my-field",
new ContentFieldData()
.AddValue("es", 1)
.AddValue("it", 1));
await sut.ValidatePartialAsync(data, errors, languages);
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("my-field has an unsupported language 'es'", "my-field"),
new ValidationError("my-field has an unsupported language 'it'", "my-field")
});
}
}
}

4
tests/Squidex.Core.Tests/project.json

@ -12,7 +12,7 @@
"Moq": "4.6.38-alpha",
"Squidex.Core": "1.0.0-*",
"Squidex.Infrastructure": "1.0.0-*",
"xunit": "2.2.0-beta4-build3444"
"xunit": "2.2.0-beta5-build3474"
},
"frameworks": {
"netcoreapp1.1": {
@ -30,7 +30,7 @@
"defaultNamespace": "Squidex.Core"
},
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final"
"Microsoft.DotNet.Watcher.Tools": "1.1.0-preview4-final"
},
"version": "1.0.0-*"
}

34
tests/Squidex.Infrastructure.Tests/CollectionExtensionsTests.cs

@ -223,5 +223,39 @@ namespace Squidex.Infrastructure
Assert.False(lhs.EqualsDictionary(rhs));
}
[Fact]
public void Dictionary_should_return_same_hashcode_for_equal_dictionaries()
{
var lhs = new Dictionary<int, int>
{
[1] = 1,
[2] = 2
};
var rhs = new Dictionary<int, int>
{
[1] = 1,
[2] = 2
};
Assert.Equal(lhs.DictionaryHashCode(), rhs.DictionaryHashCode());
}
[Fact]
public void Dictionary_should_return_different_hashcode_for_different_dictionaries()
{
var lhs = new Dictionary<int, int>
{
[1] = 1,
[2] = 2
};
var rhs = new Dictionary<int, int>
{
[1] = 1,
[3] = 3
};
Assert.NotEqual(lhs.DictionaryHashCode(), rhs.DictionaryHashCode());
}
}
}

27
tests/Squidex.Infrastructure.Tests/LanguageTests.cs

@ -63,7 +63,7 @@ namespace Squidex.Infrastructure
[Fact]
public void Should_serialize_and_deserialize_valid_language()
{
var input = Tuple.Create(Language.GetLanguage("de"));
var input = Tuple.Create(Language.DE);
var json = JsonConvert.SerializeObject(input, serializerSettings);
var output = JsonConvert.DeserializeObject<Tuple<Language>>(json, serializerSettings);
@ -82,5 +82,30 @@ namespace Squidex.Infrastructure
Assert.Equal(key, language.Iso2Code);
Assert.Equal(englishName, language.EnglishName);
}
[Theory]
[InlineData("iv", "iv")]
[InlineData("en", "en")]
[InlineData("EN", "en")]
[InlineData("en ", "en")]
public void Should_parse_valid_languages(string input, string languageCode)
{
var language = Language.TryParse(input);
Assert.Equal(language, Language.GetLanguage(languageCode));
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("xx")]
[InlineData("invalid")]
[InlineData(null)]
public void Should_parse_invalid_languages(string input)
{
var language = Language.TryParse(input);
Assert.Null(language);
}
}
}

4
tests/Squidex.Infrastructure.Tests/project.json

@ -10,7 +10,7 @@
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"Moq": "4.6.38-alpha",
"Squidex.Infrastructure": "1.0.0-*",
"xunit": "2.2.0-beta4-build3444"
"xunit": "2.2.0-beta5-build3474"
},
"frameworks": {
"netcoreapp1.1": {
@ -28,7 +28,7 @@
"defaultNamespace": "Squidex.Core.Tests"
},
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final"
"Microsoft.DotNet.Watcher.Tools": "1.1.0-preview4-final"
},
"version": "1.0.0-*"
}

4
tests/Squidex.Read.Tests/MongoDb/Contents/ODataQueryTests.cs

@ -38,8 +38,8 @@ namespace Squidex.Read.MongoDb.Contents
private readonly IBsonSerializer<MongoContentEntity> serializer = BsonSerializer.SerializerRegistry.GetSerializer<MongoContentEntity>();
private readonly HashSet<Language> languages = new HashSet<Language>
{
Language.GetLanguage("en"),
Language.GetLanguage("de")
Language.EN,
Language.DE
};
[Fact]

4
tests/Squidex.Read.Tests/project.json

@ -15,7 +15,7 @@
"Squidex.Infrastructure": "1.0.0-*",
"Squidex.Read": "1.0.0-*",
"Squidex.Read.MongoDb": "1.0.0-*",
"xunit": "2.2.0-beta4-build3444"
"xunit": "2.2.0-beta5-build3474"
},
"frameworks": {
"netcoreapp1.1": {
@ -33,7 +33,7 @@
"defaultNamespace": "Squidex.Read"
},
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final"
"Microsoft.DotNet.Watcher.Tools": "1.1.0-preview4-final"
},
"version": "1.0.0-*"
}

2
tests/Squidex.Write.Tests/Apps/AppCommandHandlerTests.cs

@ -33,7 +33,7 @@ namespace Squidex.Write.Apps
private readonly AppDomainObject app;
private readonly RefToken subjectId = new RefToken("subject", Guid.NewGuid().ToString());
private readonly DateTime expiresUtc = DateTime.UtcNow.AddYears(1);
private readonly Language language = Language.GetLanguage("de");
private readonly Language language = Language.DE;
private readonly string contributorId = Guid.NewGuid().ToString();
private readonly string clientSecret = Guid.NewGuid().ToString();
private readonly string clientName = "client";

36
tests/Squidex.Write.Tests/Apps/AppDomainObjectTests.cs

@ -63,8 +63,8 @@ namespace Squidex.Write.Apps
{
new AppCreated { Name = TestName },
new AppContributorAssigned { ContributorId = user.Identifier, Permission = PermissionLevel.Owner },
new AppLanguageAdded { Language = Language.GetLanguage("en") },
new AppMasterLanguageSet { Language = Language.GetLanguage("en") }
new AppLanguageAdded { Language = Language.EN },
new AppMasterLanguageSet { Language = Language.EN }
});
}
@ -290,7 +290,7 @@ namespace Squidex.Write.Apps
[Fact]
public void AddLanguage_should_throw_if_not_created()
{
Assert.Throws<DomainException>(() => sut.AddLanguage(new AddLanguage { Language = Language.GetLanguage("de") }));
Assert.Throws<DomainException>(() => sut.AddLanguage(new AddLanguage { Language = Language.DE }));
}
[Fact]
@ -306,7 +306,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<ValidationException>(() => sut.AddLanguage(new AddLanguage { Language = Language.GetLanguage("en") }));
Assert.Throws<ValidationException>(() => sut.AddLanguage(new AddLanguage { Language = Language.EN }));
}
[Fact]
@ -314,20 +314,20 @@ namespace Squidex.Write.Apps
{
CreateApp();
sut.AddLanguage(new AddLanguage { Language = Language.GetLanguage("de") });
sut.AddLanguage(new AddLanguage { Language = Language.DE });
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new AppLanguageAdded { Language = Language.GetLanguage("de") }
new AppLanguageAdded { Language = Language.DE }
});
}
[Fact]
public void RemoveLanguage_should_throw_if_not_created()
{
Assert.Throws<DomainException>(() => sut.RemoveLanguage(new RemoveLanguage { Language = Language.GetLanguage("en") }));
Assert.Throws<DomainException>(() => sut.RemoveLanguage(new RemoveLanguage { Language = Language.EN }));
}
[Fact]
@ -343,7 +343,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<DomainObjectNotFoundException>(() => sut.RemoveLanguage(new RemoveLanguage { Language = Language.GetLanguage("de") }));
Assert.Throws<DomainObjectNotFoundException>(() => sut.RemoveLanguage(new RemoveLanguage { Language = Language.DE }));
}
[Fact]
@ -351,7 +351,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<ValidationException>(() => sut.RemoveLanguage(new RemoveLanguage { Language = Language.GetLanguage("en") }));
Assert.Throws<ValidationException>(() => sut.RemoveLanguage(new RemoveLanguage { Language = Language.EN }));
}
[Fact]
@ -359,21 +359,21 @@ namespace Squidex.Write.Apps
{
CreateApp();
sut.AddLanguage(new AddLanguage { Language = Language.GetLanguage("de") });
sut.RemoveLanguage(new RemoveLanguage { Language = Language.GetLanguage("de") });
sut.AddLanguage(new AddLanguage { Language = Language.DE });
sut.RemoveLanguage(new RemoveLanguage { Language = Language.DE });
sut.GetUncomittedEvents().Select(x => x.Payload).Skip(1).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new AppLanguageRemoved { Language = Language.GetLanguage("de") }
new AppLanguageRemoved { Language = Language.DE }
});
}
[Fact]
public void SetMasterLanguage_should_throw_if_not_created()
{
Assert.Throws<DomainException>(() => sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.GetLanguage("en") }));
Assert.Throws<DomainException>(() => sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.EN }));
}
[Fact]
@ -389,7 +389,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<DomainObjectNotFoundException>(() => sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.GetLanguage("de") }));
Assert.Throws<DomainObjectNotFoundException>(() => sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.DE }));
}
[Fact]
@ -397,7 +397,7 @@ namespace Squidex.Write.Apps
{
CreateApp();
Assert.Throws<ValidationException>(() => sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.GetLanguage("en") }));
Assert.Throws<ValidationException>(() => sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.EN }));
}
[Fact]
@ -405,14 +405,14 @@ namespace Squidex.Write.Apps
{
CreateApp();
sut.AddLanguage(new AddLanguage { Language = Language.GetLanguage("de") });
sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.GetLanguage("de") });
sut.AddLanguage(new AddLanguage { Language = Language.DE });
sut.SetMasterLanguage(new SetMasterLanguage { Language = Language.DE });
sut.GetUncomittedEvents().Select(x => x.Payload).Skip(1).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new AppMasterLanguageSet { Language = Language.GetLanguage("de") }
new AppMasterLanguageSet { Language = Language.DE }
});
}

30
tests/Squidex.Write.Tests/Contents/ContentCommandHandlerTests.cs

@ -47,7 +47,7 @@ namespace Squidex.Write.Contents
sut = new ContentCommandHandler(Handler, appProvider.Object, schemaProvider.Object);
appEntity.Setup(x => x.Languages).Returns(new[] { Language.GetLanguage("de") });
appEntity.Setup(x => x.Languages).Returns(new[] { Language.DE });
appProvider.Setup(x => x.FindAppByIdAsync(appId)).Returns(Task.FromResult(appEntity.Object));
schemaEntity.Setup(x => x.Schema).Returns(schema);
@ -108,6 +108,34 @@ namespace Squidex.Write.Contents
});
}
[Fact]
public async Task Patch_should_throw_exception_if_data_is_not_valid()
{
CreateContent();
var command = new PatchContent { AggregateId = Id, AppId = appId, SchemaId = schemaId, Data = new ContentData() };
var context = new CommandContext(command);
await TestUpdate(content, async _ =>
{
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context));
}, false);
}
[Fact]
public async Task Patch_should_update_domain_object()
{
CreateContent();
var command = new PatchContent { AggregateId = Id, AppId = appId, SchemaId = schemaId, Data = data };
var context = new CommandContext(command);
await TestUpdate(content, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task Publish_should_publish_domain_object()
{

82
tests/Squidex.Write.Tests/Contents/ContentDomainObjectTests.cs

@ -25,7 +25,16 @@ namespace Squidex.Write.Contents
{
private readonly Guid appId = Guid.NewGuid();
private readonly ContentDomainObject sut;
private readonly ContentData data = new ContentData();
private readonly ContentData data =
new ContentData()
.AddField("field1",
new ContentFieldData()
.AddValue("iv", 1));
private readonly ContentData otherData =
new ContentData()
.AddField("field2",
new ContentFieldData()
.AddValue("iv", 2));
public ContentDomainObjectTests()
{
@ -86,17 +95,79 @@ namespace Squidex.Write.Contents
public void Update_should_create_events()
{
CreateContent();
UpdateContent();
sut.Update(new UpdateContent { Data = otherData });
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new ContentUpdated { Data = otherData }
});
}
[Fact]
public void Update_should_not_create_event_for_same_data()
{
CreateContent();
UpdateContent();
sut.Update(new UpdateContent { Data = data });
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray().ShouldBeEquivalentTo(new IEvent[0]);
}
[Fact]
public void Patch_should_throw_if_not_created()
{
Assert.Throws<DomainException>(() => sut.Patch(new PatchContent { Data = data }));
}
[Fact]
public void Patch_should_throw_if_schema_is_deleted()
{
CreateContent();
DeleteContent();
Assert.Throws<ValidationException>(() => sut.Patch(new PatchContent()));
}
[Fact]
public void Patch_should_throw_if_command_is_not_valid()
{
CreateContent();
Assert.Throws<ValidationException>(() => sut.Patch(new PatchContent()));
}
[Fact]
public void Patch_should_create_events()
{
CreateContent();
UpdateContent();
sut.Patch(new PatchContent { Data = otherData });
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()
.ShouldBeEquivalentTo(
new IEvent[]
{
new ContentUpdated { Data = data }
new ContentUpdated { Data = data.MergeInto(otherData) }
});
}
[Fact]
public void Patch_should_not_create_event_for_same_data()
{
CreateContent();
UpdateContent();
sut.Patch(new PatchContent { Data = data });
sut.GetUncomittedEvents().Select(x => x.Payload).ToArray().Should().BeEmpty();
}
[Fact]
public void Publish_should_throw_if_not_created()
{
@ -201,6 +272,13 @@ namespace Squidex.Write.Contents
((IAggregate)sut).ClearUncommittedEvents();
}
private void UpdateContent()
{
sut.Update(new UpdateContent { Data = data, AppId = appId });
((IAggregate)sut).ClearUncommittedEvents();
}
private void PublishContent()
{
sut.Publish(new PublishContent());

4
tests/Squidex.Write.Tests/project.json

@ -13,7 +13,7 @@
"Squidex.Core": "1.0.0-*",
"Squidex.Infrastructure": "1.0.0-*",
"Squidex.Write": "1.0.0-*",
"xunit": "2.2.0-beta4-build3444"
"xunit": "2.2.0-beta5-build3474"
},
"frameworks": {
"netcoreapp1.1": {
@ -31,7 +31,7 @@
"defaultNamespace": "Squidex.Write"
},
"tools": {
"Microsoft.DotNet.Watcher.Tools": "1.0.0-preview2-final"
"Microsoft.DotNet.Watcher.Tools": "1.1.0-preview4-final"
},
"version": "1.0.0-*"
}

66
tools/GenerateLanguages/Program.cs

@ -0,0 +1,66 @@
// ==========================================================================
// Program.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace ConsoleApplication
{
public class Program
{
public static void Main(string[] args)
{
var languageCodesFile = new FileInfo("../../src/Squidex.Infrastructure/language-codes.csv");
var languageFile = Path.Combine(languageCodesFile.DirectoryName, "Languages.cs");
var resourceStream = new FileStream(languageCodesFile.FullName, FileMode.Open);
var writer = new StringWriter();
writer.WriteLine("// ==========================================================================");
writer.WriteLine("// Langauges.cs");
writer.WriteLine("// Squidex Headless CMS");
writer.WriteLine("// ==========================================================================");
writer.WriteLine("// Copyright (c) Squidex Group");
writer.WriteLine("// All rights reserved.");
writer.WriteLine("// ==========================================================================");
writer.WriteLine();
writer.WriteLine("namespace Squidex.Infrastructure");
writer.WriteLine("{");
writer.WriteLine(" partial class Language");
writer.WriteLine(" {");
var uniqueCodes = new HashSet<string>(new [] { "iv" });
using (var reader = new StreamReader(resourceStream, Encoding.UTF8))
{
reader.ReadLine();
while (!reader.EndOfStream)
{
var languageLine = reader.ReadLine();
var languageIso2Code = languageLine.Substring(1, 2);
var languageEnglishName = languageLine.Substring(6, languageLine.Length - 7);
if (!uniqueCodes.Add(languageIso2Code))
{
Console.WriteLine("Languages contains duplicate {0}", languageIso2Code);
}
writer.WriteLine(" public static Language {0} = AddLanguage(\"{1}\", \"{2}\");", languageIso2Code.ToUpperInvariant(), languageIso2Code, languageEnglishName);
}
}
writer.WriteLine(" }");
writer.WriteLine("}");
File.WriteAllText(languageFile, writer.ToString());
}
}
}

19
tools/GenerateLanguages/project.json

@ -0,0 +1,19 @@
{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {},
"frameworks": {
"netcoreapp1.1": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.1.0"
}
},
"imports": "dnxcore50"
}
}
}
Loading…
Cancel
Save