Skip to content

Commit

Permalink
Fixes #100 🎉🎉🎉 and more
Browse files Browse the repository at this point in the history
- Limited email length to an RFC-compatible value
- Limited username length on the database to what it is already limited to in validation
  • Loading branch information
Atulin committed Aug 7, 2024
1 parent 98a9817 commit 3752588
Show file tree
Hide file tree
Showing 15 changed files with 4,730 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.6",
"version": "8.0.7",
"commands": [
"dotnet-ef"
],
Expand Down
24 changes: 16 additions & 8 deletions Ogma3/CompiledModels/ApplicationDbContextModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3373,7 +3373,7 @@ private IRelationalModel CreateRelationalModel()
IsNullable = true
};
ogma3DataUsersOgmaUserTableBase.Columns.Add("DeletedAt", deletedAtColumnBase0);
var emailColumnBase = new ColumnBase<ColumnMappingBase>("Email", "character varying(256)", ogma3DataUsersOgmaUserTableBase);
var emailColumnBase = new ColumnBase<ColumnMappingBase>("Email", "character varying(254)", ogma3DataUsersOgmaUserTableBase);
ogma3DataUsersOgmaUserTableBase.Columns.Add("Email", emailColumnBase);
var emailConfirmedColumnBase = new ColumnBase<ColumnMappingBase>("EmailConfirmed", "boolean", ogma3DataUsersOgmaUserTableBase);
ogma3DataUsersOgmaUserTableBase.Columns.Add("EmailConfirmed", emailConfirmedColumnBase);
Expand All @@ -3390,9 +3390,9 @@ private IRelationalModel CreateRelationalModel()
IsNullable = true
};
ogma3DataUsersOgmaUserTableBase.Columns.Add("LockoutEnd", lockoutEndColumnBase);
var normalizedEmailColumnBase = new ColumnBase<ColumnMappingBase>("NormalizedEmail", "character varying(256)", ogma3DataUsersOgmaUserTableBase);
var normalizedEmailColumnBase = new ColumnBase<ColumnMappingBase>("NormalizedEmail", "character varying(254)", ogma3DataUsersOgmaUserTableBase);
ogma3DataUsersOgmaUserTableBase.Columns.Add("NormalizedEmail", normalizedEmailColumnBase);
var normalizedUserNameColumnBase = new ColumnBase<ColumnMappingBase>("NormalizedUserName", "character varying(256)", ogma3DataUsersOgmaUserTableBase);
var normalizedUserNameColumnBase = new ColumnBase<ColumnMappingBase>("NormalizedUserName", "character varying(20)", ogma3DataUsersOgmaUserTableBase);
ogma3DataUsersOgmaUserTableBase.Columns.Add("NormalizedUserName", normalizedUserNameColumnBase);
var passwordHashColumnBase = new ColumnBase<ColumnMappingBase>("PasswordHash", "text", ogma3DataUsersOgmaUserTableBase)
{
Expand All @@ -3413,7 +3413,7 @@ private IRelationalModel CreateRelationalModel()
ogma3DataUsersOgmaUserTableBase.Columns.Add("Title", titleColumnBase4);
var twoFactorEnabledColumnBase = new ColumnBase<ColumnMappingBase>("TwoFactorEnabled", "boolean", ogma3DataUsersOgmaUserTableBase);
ogma3DataUsersOgmaUserTableBase.Columns.Add("TwoFactorEnabled", twoFactorEnabledColumnBase);
var userNameColumnBase = new ColumnBase<ColumnMappingBase>("UserName", "character varying(256)", ogma3DataUsersOgmaUserTableBase);
var userNameColumnBase = new ColumnBase<ColumnMappingBase>("UserName", "character varying(20)", ogma3DataUsersOgmaUserTableBase);
ogma3DataUsersOgmaUserTableBase.Columns.Add("UserName", userNameColumnBase);
relationalModel.DefaultTables.Add("Ogma3.Data.Users.OgmaUser", ogma3DataUsersOgmaUserTableBase);
var ogma3DataUsersOgmaUserMappingBase = new TableMappingBase<ColumnMappingBase>(ogmaUser, ogma3DataUsersOgmaUserTableBase, true);
Expand Down Expand Up @@ -3471,7 +3471,7 @@ private IRelationalModel CreateRelationalModel()
IsNullable = true
};
aspNetUsersTable.Columns.Add("DeletedAt", deletedAtColumn0);
var emailColumn = new Column("Email", "character varying(256)", aspNetUsersTable);
var emailColumn = new Column("Email", "character varying(254)", aspNetUsersTable);
aspNetUsersTable.Columns.Add("Email", emailColumn);
var emailConfirmedColumn = new Column("EmailConfirmed", "boolean", aspNetUsersTable);
aspNetUsersTable.Columns.Add("EmailConfirmed", emailConfirmedColumn);
Expand All @@ -3486,9 +3486,9 @@ private IRelationalModel CreateRelationalModel()
IsNullable = true
};
aspNetUsersTable.Columns.Add("LockoutEnd", lockoutEndColumn);
var normalizedEmailColumn = new Column("NormalizedEmail", "character varying(256)", aspNetUsersTable);
var normalizedEmailColumn = new Column("NormalizedEmail", "character varying(254)", aspNetUsersTable);
aspNetUsersTable.Columns.Add("NormalizedEmail", normalizedEmailColumn);
var normalizedUserNameColumn = new Column("NormalizedUserName", "character varying(256)", aspNetUsersTable);
var normalizedUserNameColumn = new Column("NormalizedUserName", "character varying(20)", aspNetUsersTable);
aspNetUsersTable.Columns.Add("NormalizedUserName", normalizedUserNameColumn);
var passwordHashColumn = new Column("PasswordHash", "text", aspNetUsersTable)
{
Expand All @@ -3509,7 +3509,7 @@ private IRelationalModel CreateRelationalModel()
aspNetUsersTable.Columns.Add("Title", titleColumn4);
var twoFactorEnabledColumn = new Column("TwoFactorEnabled", "boolean", aspNetUsersTable);
aspNetUsersTable.Columns.Add("TwoFactorEnabled", twoFactorEnabledColumn);
var userNameColumn = new Column("UserName", "character varying(256)", aspNetUsersTable);
var userNameColumn = new Column("UserName", "character varying(20)", aspNetUsersTable);
aspNetUsersTable.Columns.Add("UserName", userNameColumn);
var pK_AspNetUsers = new UniqueConstraint("PK_AspNetUsers", aspNetUsersTable, new[] { idColumn25 });
aspNetUsersTable.PrimaryKey = pK_AspNetUsers;
Expand All @@ -3527,6 +3527,14 @@ private IRelationalModel CreateRelationalModel()
emailIndex.MappedIndexes.Add(emailIndexIx);
RelationalModel.GetOrCreateTableIndexes(emailIndexIx).Add(emailIndex);
aspNetUsersTable.Indexes.Add("EmailIndex", emailIndex);
var iX_AspNetUsers_LastActive = new TableIndex(
"IX_AspNetUsers_LastActive", aspNetUsersTable, new[] { lastActiveColumn }, false);
var iX_AspNetUsers_LastActiveIx = RelationalModel.GetIndex(this,
"Ogma3.Data.Users.OgmaUser",
new[] { "LastActive" });
iX_AspNetUsers_LastActive.MappedIndexes.Add(iX_AspNetUsers_LastActiveIx);
RelationalModel.GetOrCreateTableIndexes(iX_AspNetUsers_LastActiveIx).Add(iX_AspNetUsers_LastActive);
aspNetUsersTable.Indexes.Add("IX_AspNetUsers_LastActive", iX_AspNetUsers_LastActive);
var userNameIndex = new TableIndex(
"UserNameIndex", aspNetUsersTable, new[] { normalizedUserNameColumn }, true);
var userNameIndexIx = RelationalModel.GetIndex(this,
Expand Down
2 changes: 1 addition & 1 deletion Ogma3/CompiledModels/ClubMemberEntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
propertyInfo: typeof(ClubMember).GetProperty("Role", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(ClubMember).GetField("<Role>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: (EClubMemberRoles)0);
sentinel: EClubMemberRoles.Invalid);
role.TypeMapping = NpgsqlEnumTypeMapping.Default.Clone(
comparer: new ValueComparer<EClubMemberRoles>(
(EClubMemberRoles v1, EClubMemberRoles v2) => object.Equals((object)v1, (object)v2),
Expand Down
2 changes: 1 addition & 1 deletion Ogma3/CompiledModels/FolderEntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
propertyInfo: typeof(Folder).GetProperty("AccessLevel", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(Folder).GetField("<AccessLevel>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
valueGenerated: ValueGenerated.OnAdd,
sentinel: (EClubMemberRoles)0);
sentinel: EClubMemberRoles.Invalid);
accessLevel.TypeMapping = NpgsqlEnumTypeMapping.Default.Clone(
comparer: new ValueComparer<EClubMemberRoles>(
(EClubMemberRoles v1, EClubMemberRoles v2) => object.Equals((object)v1, (object)v2),
Expand Down
33 changes: 18 additions & 15 deletions Ogma3/CompiledModels/OgmaUserEntityType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
typeof(string),
propertyInfo: typeof(OgmaUser).GetProperty("Email", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(IdentityUser<long>).GetField("<Email>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 256);
maxLength: 254);
email.TypeMapping = NpgsqlStringTypeMapping.Default.Clone(
comparer: new ValueComparer<string>(
(string v1, string v2) => v1 == v2,
Expand All @@ -211,8 +211,8 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
(string v) => v.GetHashCode(),
(string v) => v),
mappingInfo: new RelationalTypeMappingInfo(
storeTypeName: "character varying(256)",
size: 256));
storeTypeName: "character varying(254)",
size: 254));
email.TypeMapping = ((NpgsqlStringTypeMapping)email.TypeMapping).Clone(npgsqlDbType: NpgsqlTypes.NpgsqlDbType.Varchar);
email.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);

Expand Down Expand Up @@ -351,7 +351,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
typeof(string),
propertyInfo: typeof(OgmaUser).GetProperty("NormalizedEmail", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(IdentityUser<long>).GetField("<NormalizedEmail>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 256);
maxLength: 254);
normalizedEmail.TypeMapping = NpgsqlStringTypeMapping.Default.Clone(
comparer: new ValueComparer<string>(
(string v1, string v2) => v1 == v2,
Expand All @@ -366,8 +366,8 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
(string v) => v.GetHashCode(),
(string v) => v),
mappingInfo: new RelationalTypeMappingInfo(
storeTypeName: "character varying(256)",
size: 256));
storeTypeName: "character varying(254)",
size: 254));
normalizedEmail.TypeMapping = ((NpgsqlStringTypeMapping)normalizedEmail.TypeMapping).Clone(npgsqlDbType: NpgsqlTypes.NpgsqlDbType.Varchar);
normalizedEmail.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);

Expand All @@ -376,7 +376,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
typeof(string),
propertyInfo: typeof(OgmaUser).GetProperty("NormalizedUserName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(IdentityUser<long>).GetField("<NormalizedUserName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 256);
maxLength: 20);
normalizedUserName.TypeMapping = NpgsqlStringTypeMapping.Default.Clone(
comparer: new ValueComparer<string>(
(string v1, string v2) => v1 == v2,
Expand All @@ -391,8 +391,8 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
(string v) => v.GetHashCode(),
(string v) => v),
mappingInfo: new RelationalTypeMappingInfo(
storeTypeName: "character varying(256)",
size: 256));
storeTypeName: "character varying(20)",
size: 20));
normalizedUserName.TypeMapping = ((NpgsqlStringTypeMapping)normalizedUserName.TypeMapping).Clone(npgsqlDbType: NpgsqlTypes.NpgsqlDbType.Varchar);
normalizedUserName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);

Expand Down Expand Up @@ -517,7 +517,7 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
typeof(string),
propertyInfo: typeof(OgmaUser).GetProperty("UserName", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly),
fieldInfo: typeof(IdentityUser<long>).GetField("<UserName>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly),
maxLength: 256);
maxLength: 20);
userName.TypeMapping = NpgsqlStringTypeMapping.Default.Clone(
comparer: new ValueComparer<string>(
(string v1, string v2) => v1 == v2,
Expand All @@ -532,8 +532,8 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
(string v) => v.GetHashCode(),
(string v) => v),
mappingInfo: new RelationalTypeMappingInfo(
storeTypeName: "character varying(256)",
size: 256));
storeTypeName: "character varying(20)",
size: 20));
userName.TypeMapping = ((NpgsqlStringTypeMapping)userName.TypeMapping).Clone(npgsqlDbType: NpgsqlTypes.NpgsqlDbType.Varchar);
userName.AddAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.None);

Expand All @@ -542,13 +542,16 @@ public static RuntimeEntityType Create(RuntimeModel model, RuntimeEntityType bas
runtimeEntityType.SetPrimaryKey(key);

var index = runtimeEntityType.AddIndex(
new[] { normalizedEmail });
index.AddAnnotation("Relational:Name", "EmailIndex");
new[] { lastActive });

var index0 = runtimeEntityType.AddIndex(
new[] { normalizedEmail });
index0.AddAnnotation("Relational:Name", "EmailIndex");

var index1 = runtimeEntityType.AddIndex(
new[] { normalizedUserName },
unique: true);
index0.AddAnnotation("Relational:Name", "UserNameIndex");
index1.AddAnnotation("Relational:Name", "UserNameIndex");

return runtimeEntityType;
}
Expand Down
6 changes: 6 additions & 0 deletions Ogma3/Data/CTConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ namespace Ogma3.Data;
// ReSharper disable once InconsistentNaming
public static class CTConfig
{
/// <summary>
/// Technically, maximum length is 256 according to <see href="https://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690">RFC 3696 Errata</see>
/// However, two characters of a valid path are angle brackets, which leaves us with 254
/// </summary>
public const int MaxEmailAddressLength = 254;

public static class CFiles
{
public const int AvatarMaxWeight = 1 * 1024 * 1024;
Expand Down
3 changes: 2 additions & 1 deletion Ogma3/Data/Clubs/ClubMemberConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ public void Configure(EntityTypeBuilder<ClubMember> builder)
builder
.Property(cm => cm.Role)
.IsRequired()
.HasDefaultValue(EClubMemberRoles.User);
.HasDefaultValue(EClubMemberRoles.User)
.HasSentinel(EClubMemberRoles.Invalid);

builder
.Property(cm => cm.MemberSince)
Expand Down
3 changes: 2 additions & 1 deletion Ogma3/Data/Clubs/EClubMemberRoles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ namespace Ogma3.Data.Clubs;
[PostgresEnum]
public enum EClubMemberRoles
{
Invalid = 0,
Founder = 1,
Admin = 2,
Moderator = 3,
User = 4
User = 4,
}
3 changes: 2 additions & 1 deletion Ogma3/Data/Folders/FolderConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public override void Configure(EntityTypeBuilder<Folder> builder)
builder
.Property(f => f.AccessLevel)
.IsRequired()
.HasDefaultValue(EClubMemberRoles.User);
.HasDefaultValue(EClubMemberRoles.User)
.HasSentinel(EClubMemberRoles.Invalid);

// NAVIGATION
builder
Expand Down
26 changes: 25 additions & 1 deletion Ogma3/Data/Users/OgmaUserConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,31 @@ public class OgmaUserConfiguration : IEntityTypeConfiguration<OgmaUser>
{
public void Configure(EntityTypeBuilder<OgmaUser> builder)
{
builder
.HasIndex(u => u.LastActive)
.IsDescending();

builder
.HasIndex(u => u.NormalizedUserName)
.IsUnique();

// CONSTRAINTS
builder
.Property(u => u.UserName)
.HasMaxLength(CTConfig.CUser.MaxNameLength);

builder
.Property(u => u.NormalizedUserName)
.HasMaxLength(CTConfig.CUser.MaxNameLength);

builder
.Property(u => u.Email)
.HasMaxLength(CTConfig.MaxEmailAddressLength);

builder
.Property(u => u.NormalizedEmail)
.HasMaxLength(CTConfig.MaxEmailAddressLength);

builder
.Property(u => u.Title)
.HasMaxLength(CTConfig.CUser.MaxTitleLength);
Expand All @@ -23,7 +47,7 @@ public void Configure(EntityTypeBuilder<OgmaUser> builder)
.IsRequired()
.HasMaxLength(CTConfig.CUser.MaxLinksAmount)
.HasDefaultValueSql(PgConstants.EmptyArray);

builder
.Property(u => u.RegistrationDate)
.IsRequired()
Expand Down
Loading

0 comments on commit 3752588

Please sign in to comment.