This commit is contained in:
2023-07-29 16:25:16 +03:00
parent 90f0386bfe
commit 4312a5c084
34 changed files with 1998 additions and 61 deletions
+35
View File
@@ -0,0 +1,35 @@
namespace MyOffice.Core.Attributes;
using System;
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class LinkAttribute : Attribute
{
public LinkAttribute(Type type)
{
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class LinkFromAttribute : Attribute
{
public LinkFromAttribute(Type type)
{
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class LinkToAttribute : Attribute
{
public LinkToAttribute(Type type)
{
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class LinkWithAttribute : Attribute
{
public LinkWithAttribute(Type type)
{
}
}
+20 -10
View File
@@ -24,6 +24,26 @@ public static class StringExtensions
return str != null && str.Equals(value, StringComparison.OrdinalIgnoreCase); return str != null && str.Equals(value, StringComparison.OrdinalIgnoreCase);
} }
public static string? SafeTrim(this string? str)
{
return str == null ? str : str!.Trim();
}
public static string? MaxOf(this string? str, int maxLength)
{
if (str == null)
{
return null;
}
if (str.Length < maxLength)
{
return str;
}
return str.Substring(0, maxLength);
}
public static bool AsBool(this string? str, bool defaultValue = false) public static bool AsBool(this string? str, bool defaultValue = false)
{ {
return true.ToString().Equals(str, StringComparison.OrdinalIgnoreCase) || defaultValue; return true.ToString().Equals(str, StringComparison.OrdinalIgnoreCase) || defaultValue;
@@ -31,21 +51,11 @@ public static class StringExtensions
public static Guid AsGuid(this string str) public static Guid AsGuid(this string str)
{ {
/*str = str
.Replace("_", "/")
.Replace("-", "+");
byte[] buffer = Convert.FromBase64String(str + "==");
return new Guid(buffer);*/
return Guid.Parse(str); return Guid.Parse(str);
} }
public static Guid? AsGuidNull(this string str) public static Guid? AsGuidNull(this string str)
{ {
/*str = str
.Replace("_", "/")
.Replace("-", "+");
byte[] buffer = Convert.FromBase64String(str + "==");
return new Guid(buffer);*/
if (Guid.TryParse(str, out var guid)) if (Guid.TryParse(str, out var guid))
{ {
return guid; return guid;
+1
View File
@@ -14,6 +14,7 @@ public class Account
public IEnumerable<AccountAccess>? AccessRights { get; set; } public IEnumerable<AccountAccess>? AccessRights { get; set; }
public IEnumerable<Motion>? Motions { get; set; } public IEnumerable<Motion>? Motions { get; set; }
public IEnumerable<AccountAccountCategory>? Categories { get; set; } public IEnumerable<AccountAccountCategory>? Categories { get; set; }
public IEnumerable<AccountAccessInvite>? Invites { get; set; }
} }
public class AccountDetailed public class AccountDetailed
@@ -1,12 +1,15 @@
namespace MyOffice.Data.Models.Accounts; namespace MyOffice.Data.Models.Accounts;
using Core.Attributes;
using Users; using Users;
public class AccountAccessInvite public class AccountAccessInvite
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid UserId { get; set; } public Guid UserId { get; set; }
public User User { get; set; } public User? User { get; set; }
public Guid AccountId { get; set; }
public Account? Account { get; set; }
public DateTime CreatedOn { get; set; } public DateTime CreatedOn { get; set; }
public DateTime? AcceptedOn { get; set; } public DateTime? AcceptedOn { get; set; }
public DateTime? RejectedOn { get; set; } public DateTime? RejectedOn { get; set; }
@@ -6,4 +6,8 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MyOffice.Core\MyOffice.Core.csproj" />
</ItemGroup>
</Project> </Project>
@@ -1,5 +1,6 @@
namespace MyOffice.Data.Repositories.Account; namespace MyOffice.Data.Repositories.Account;
using Microsoft.EntityFrameworkCore;
using Models.Accounts; using Models.Accounts;
using MyOffice.Data.Repositories; using MyOffice.Data.Repositories;
@@ -24,4 +25,18 @@ public class AccountAccessInviteRepository : AppRepository<AccountAccessInvite>,
{ {
return UpdateBase(invite) > 0; return UpdateBase(invite) > 0;
} }
public IEnumerable<AccountAccessInvite> GetActive(string email)
{
return _context
.AccountAccessInvites
.Include(x => x.Account)
.Where(x => x.Email == email && !x.AcceptedOn.HasValue && !x.RejectedOn.HasValue);
}
public AccountAccessInvite? Get(Guid id)
{
return _context.AccountAccessInvites.FirstOrDefault(x => x.Id == id);
}
} }
@@ -5,6 +5,10 @@ using MyOffice.Data.Repositories;
public class AccountAccessRepository : AppRepository<AccountAccess>, IAccountAccessRepository public class AccountAccessRepository : AppRepository<AccountAccess>, IAccountAccessRepository
{ {
public bool Add(AccountAccess accountAccess)
{
return AddBase(accountAccess) > 0;
}
public bool Update(AccountAccess accountAccess) public bool Update(AccountAccess accountAccess)
{ {
@@ -90,7 +90,7 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
public Account? Get(Guid userId, Guid id) public Account? Get(Guid userId, Guid id)
{ {
return _context.Accounts! return _context.Accounts!
.Include(x => x.Categories)! .Include(x => x.Categories!.Where(c => c.Category.UserId == userId))!
.ThenInclude(x => x.Category) .ThenInclude(x => x.Category)
.Include(x => x.AccessRights)! .Include(x => x.AccessRights)!
.ThenInclude(x => x.User) .ThenInclude(x => x.User)
@@ -5,6 +5,8 @@ using Models.Accounts;
public interface IAccountAccessInviteRepository public interface IAccountAccessInviteRepository
{ {
AccountAccessInvite? Get(Guid userId, string email); AccountAccessInvite? Get(Guid userId, string email);
IEnumerable<AccountAccessInvite> GetActive(string email);
AccountAccessInvite? Get(Guid id);
bool Add(AccountAccessInvite invite); bool Add(AccountAccessInvite invite);
bool Update(AccountAccessInvite invite); bool Update(AccountAccessInvite invite);
} }
@@ -4,6 +4,7 @@ using Models.Accounts;
public interface IAccountAccessRepository public interface IAccountAccessRepository
{ {
bool Add(AccountAccess accountAccess);
bool Update(AccountAccess accountAccess); bool Update(AccountAccess accountAccess);
bool Delete(AccountAccess accountAccess); bool Delete(AccountAccess accountAccess);
} }
+5
View File
@@ -176,6 +176,11 @@ public class AppDbContext : DbContext
.WithMany(x => x.AccountAccessInvites) .WithMany(x => x.AccountAccessInvites)
.HasForeignKey(x => x.UserId); .HasForeignKey(x => x.UserId);
modelBuilder.Entity<AccountAccessInvite>()
.HasOne(x => x.Account)
.WithMany(x => x.Invites)
.HasForeignKey(x => x.AccountId);
modelBuilder.Entity<Motion>() modelBuilder.Entity<Motion>()
.HasOne(x => x.Account) .HasOne(x => x.Account)
.WithMany(x => x.Motions) .WithMany(x => x.Motions)
@@ -0,0 +1,713 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MyOffice.DbContext;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20230728181916_AccountAccessInvites2")]
partial class AccountAccessInvites2
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("OwnerId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("OwnerId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<Guid>("OwnerId")
.HasColumnType("uuid");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("OwnerId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime?>("AcceptedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<DateTime?>("RejectedOn")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountAccessInvites");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("CurrentRateId");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "Owner")
.WithMany("Accounts")
.HasForeignKey("OwnerId");
b.Navigation("CurrencyGlobal");
b.Navigation("Owner");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "Owner")
.WithMany("AccountAccessOwners")
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Owner");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccessInvites")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("Currencies")
.HasForeignKey("CurrentRateId");
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("CurrentRate");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountAccessInvites");
b.Navigation("AccountAccessOwners");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Accounts");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,51 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class AccountAccessInvites2 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "UserId",
table: "AccountAccessInvites",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateIndex(
name: "IX_AccountAccessInvites_UserId",
table: "AccountAccessInvites",
column: "UserId");
migrationBuilder.AddForeignKey(
name: "FK_AccountAccessInvites_Users_UserId",
table: "AccountAccessInvites",
column: "UserId",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AccountAccessInvites_Users_UserId",
table: "AccountAccessInvites");
migrationBuilder.DropIndex(
name: "IX_AccountAccessInvites_UserId",
table: "AccountAccessInvites");
migrationBuilder.DropColumn(
name: "UserId",
table: "AccountAccessInvites");
}
}
}
@@ -0,0 +1,728 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using MyOffice.DbContext;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20230728192017_AccountAccessInvites3")]
partial class AccountAccessInvites3
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:CollationDefinition:my_ci_collation", "en-u-ks-primary,en-u-ks-primary,icu,False")
.HasAnnotation("ProductVersion", "7.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid?>("OwnerId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("OwnerId");
b.ToTable("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<bool>("IsAllowManage")
.HasColumnType("boolean");
b.Property<bool>("IsAllowRead")
.HasColumnType("boolean");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<string>("Name")
.HasColumnType("text");
b.Property<Guid>("OwnerId")
.HasColumnType("uuid");
b.Property<string>("Type")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("OwnerId");
b.HasIndex("UserId");
b.ToTable("AccountAccesses");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<DateTime?>("AcceptedOn")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsAllowWrite")
.HasColumnType("boolean");
b.Property<DateTime?>("RejectedOn")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccessInvites");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("CategoryId");
b.ToTable("AccountAccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AccountCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<decimal>("AmountMinus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<decimal>("AmountPlus")
.HasPrecision(18, 6)
.HasColumnType("numeric(18,6)");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DeletedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Description")
.HasColumnType("text");
b.Property<int>("ItemId")
.HasColumnType("integer");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("ItemId");
b.HasIndex("UserId");
b.ToTable("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyGlobalId")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("CurrentRateId")
.HasColumnType("integer");
b.Property<bool>("IsPrimary")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ShortName")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CurrencyGlobalId");
b.HasIndex("CurrentRateId");
b.HasIndex("UserId");
b.ToTable("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("DefaultQuantity")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CurrencyId")
.HasColumnType("uuid");
b.Property<DateTime>("DateTime")
.HasColumnType("timestamp with time zone");
b.Property<int>("Quantity")
.HasColumnType("integer");
b.Property<decimal>("Rate")
.HasColumnType("numeric");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("CurrencyRates");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<Guid>("CategoryId")
.HasColumnType("uuid");
b.Property<Guid>("ItemGlobalId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("CategoryId");
b.HasIndex("ItemGlobalId");
b.ToTable("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsInternal")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("ItemCategories");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("ItemGlobals");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("CurrencyId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("FirstName")
.HasColumnType("text");
b.Property<string>("FullName")
.HasColumnType("text");
b.Property<bool>("IsEmailConfirmed")
.HasColumnType("boolean");
b.Property<string>("LastName")
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Phone")
.HasColumnType("text");
b.Property<string>("UserName")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.ToTable("Users");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Provider")
.IsRequired()
.HasColumnType("text")
.UseCollation("my_ci_collation");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("UserClaims");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Accounts")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "Owner")
.WithMany("Accounts")
.HasForeignKey("OwnerId");
b.Navigation("CurrencyGlobal");
b.Navigation("Owner");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccess", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("AccessRights")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "Owner")
.WithMany("AccountAccessOwners")
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccess")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Owner");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Invites")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccessInvites")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Categories")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Accounts.AccountCategory", "Category")
.WithMany("Accounts")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("Category");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Motion", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Motions")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.Item", "Item")
.WithMany("Motions")
.HasForeignKey("ItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", null)
.WithMany("AccountMotions")
.HasForeignKey("UserId");
b.Navigation("Account");
b.Navigation("Item");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "CurrencyGlobal")
.WithMany("Currencies")
.HasForeignKey("CurrencyGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyRate", "CurrentRate")
.WithMany("Currencies")
.HasForeignKey("CurrentRateId");
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("Currencies")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CurrencyGlobal");
b.Navigation("CurrentRate");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.Currency", "Currency")
.WithMany("Rates")
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.HasOne("MyOffice.Data.Models.Items.ItemCategory", "Category")
.WithMany("Items")
.HasForeignKey("CategoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Items.ItemGlobal", "ItemGlobal")
.WithMany("Items")
.HasForeignKey("ItemGlobalId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Category");
b.Navigation("ItemGlobal");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("ItemCategories")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.HasOne("MyOffice.Data.Models.Currencies.CurrencyGlobal", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.UserExternal", b =>
{
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("UserClaims")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.Account", b =>
{
b.Navigation("AccessRights");
b.Navigation("Categories");
b.Navigation("Invites");
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountCategory", b =>
{
b.Navigation("Accounts");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.Currency", b =>
{
b.Navigation("Rates");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyGlobal", b =>
{
b.Navigation("Accounts");
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Currencies.CurrencyRate", b =>
{
b.Navigation("Currencies");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.Item", b =>
{
b.Navigation("Motions");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemCategory", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Items.ItemGlobal", b =>
{
b.Navigation("Items");
});
modelBuilder.Entity("MyOffice.Data.Models.Users.User", b =>
{
b.Navigation("AccountAccess");
b.Navigation("AccountAccessInvites");
b.Navigation("AccountAccessOwners");
b.Navigation("AccountCategories");
b.Navigation("AccountMotions");
b.Navigation("Accounts");
b.Navigation("Currencies");
b.Navigation("ItemCategories");
b.Navigation("UserClaims");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,51 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace MyOffice.Migrations.Postgres.Migrations
{
/// <inheritdoc />
public partial class AccountAccessInvites3 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "AccountId",
table: "AccountAccessInvites",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateIndex(
name: "IX_AccountAccessInvites_AccountId",
table: "AccountAccessInvites",
column: "AccountId");
migrationBuilder.AddForeignKey(
name: "FK_AccountAccessInvites_Accounts_AccountId",
table: "AccountAccessInvites",
column: "AccountId",
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AccountAccessInvites_Accounts_AccountId",
table: "AccountAccessInvites");
migrationBuilder.DropIndex(
name: "IX_AccountAccessInvites_AccountId",
table: "AccountAccessInvites");
migrationBuilder.DropColumn(
name: "AccountId",
table: "AccountAccessInvites");
}
}
}
@@ -102,6 +102,9 @@ namespace MyOffice.Migrations.Postgres.Migrations
b.Property<DateTime?>("AcceptedOn") b.Property<DateTime?>("AcceptedOn")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<Guid>("AccountId")
.HasColumnType("uuid");
b.Property<DateTime>("CreatedOn") b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
@@ -115,8 +118,15 @@ namespace MyOffice.Migrations.Postgres.Migrations
b.Property<DateTime?>("RejectedOn") b.Property<DateTime?>("RejectedOn")
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<Guid>("UserId")
.HasColumnType("uuid");
b.HasKey("Id"); b.HasKey("Id");
b.HasIndex("AccountId");
b.HasIndex("UserId");
b.ToTable("AccountAccessInvites"); b.ToTable("AccountAccessInvites");
}); });
@@ -481,6 +491,25 @@ namespace MyOffice.Migrations.Postgres.Migrations
b.Navigation("User"); b.Navigation("User");
}); });
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccessInvite", b =>
{
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
.WithMany("Invites")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("MyOffice.Data.Models.Users.User", "User")
.WithMany("AccountAccessInvites")
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
b.Navigation("User");
});
modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b => modelBuilder.Entity("MyOffice.Data.Models.Accounts.AccountAccountCategory", b =>
{ {
b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account") b.HasOne("MyOffice.Data.Models.Accounts.Account", "Account")
@@ -628,6 +657,8 @@ namespace MyOffice.Migrations.Postgres.Migrations
b.Navigation("Categories"); b.Navigation("Categories");
b.Navigation("Invites");
b.Navigation("Motions"); b.Navigation("Motions");
}); });
@@ -672,6 +703,8 @@ namespace MyOffice.Migrations.Postgres.Migrations
{ {
b.Navigation("AccountAccess"); b.Navigation("AccountAccess");
b.Navigation("AccountAccessInvites");
b.Navigation("AccountAccessOwners"); b.Navigation("AccountAccessOwners");
b.Navigation("AccountCategories"); b.Navigation("AccountCategories");
+3
View File
@@ -18,6 +18,9 @@ export class ApiRoutes {
static SettingsAccountAccesses = '/api/settings/accounts/:id/access'; static SettingsAccountAccesses = '/api/settings/accounts/:id/access';
static SettingsAccountAccess = '/api/settings/accounts/:id/access/:access'; static SettingsAccountAccess = '/api/settings/accounts/:id/access/:access';
static SettingsAccountAccountCategory = '/api/settings/accounts/:id/category/:categoryId'; static SettingsAccountAccountCategory = '/api/settings/accounts/:id/category/:categoryId';
static SettingsAccountInvites = '/api/settings/accounts/invites';
static SettingsAccountInviteAccept = '/api/settings/accounts/invites/:id/accept';
static SettingsAccountInviteReject = '/api/settings/accounts/invites/:id/reject';
static SettingsItemCategories = '/api/settings/item-categories'; static SettingsItemCategories = '/api/settings/item-categories';
static SettingsItemCategory = '/api/settings/item-categories/:id'; static SettingsItemCategory = '/api/settings/item-categories/:id';
@@ -24,8 +24,12 @@ export class ErrorInterceptor implements HttpInterceptor {
this.authenticationService.logout(); this.authenticationService.logout();
location.reload(); location.reload();
} }
console.log(err); let error = err.message || err.statusText;
const error = err.message || err.error.message || err.statusText; error = !err.error ? error : err.error.message || err.error.title;
if (!error) {
console.log('not parsed error', err);
}
return throwError(error); return throwError(error);
//return throwError(err.error || err); //return throwError(err.error || err);
}) })
@@ -0,0 +1,5 @@
export interface AccountInviteModel {
id?: string,
account?: string,
allowWrite: boolean,
}
@@ -21,6 +21,7 @@ import { NgxCurrencyModule } from "ngx-currency";
import { MatExpansionModule } from '@angular/material/expansion'; import { MatExpansionModule } from '@angular/material/expansion';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatMenuModule } from '@angular/material/menu';
// app // app
import { PagesRoutingModule } from './pages-routing.module'; import { PagesRoutingModule } from './pages-routing.module';
@@ -88,6 +89,7 @@ import { SettingsItemCategoryEditComponent } from './settings/item/edit.item.cat
NgxMaskModule, NgxMaskModule,
NgxCurrencyModule, NgxCurrencyModule,
MatCheckboxModule, MatCheckboxModule,
MatMenuModule,
], ],
providers: [ providers: [
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' }, { provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
@@ -17,13 +17,19 @@
</mat-card-subtitle> </mat-card-subtitle>
</mat-card-title-group> </mat-card-title-group>
<div fxFlex></div> <div fxFlex></div>
<div *ngIf="invites && invites.length > 0" class="m-r-10">
<button mat-raised-button color="warn" [matMenuTriggerFor]="menu">Invites</button>
<mat-menu #menu="matMenu">
<button *ngFor="let invite of invites" mat-menu-item (click)="startInvite(invite)">{{invite.account}}</button>
</mat-menu>
</div>
<button class="btn-space " (click)="add()" mat-raised-button color="primary"> <button class="btn-space " (click)="add()" mat-raised-button color="primary">
Add Add
</button> </button>
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<div class="body table-responsive"> <div class="body table-responsive">
<mat-tab-group mat-stretch-tabs="false" mat-align-tabs="start"> <mat-tab-group mat-stretch-tabs="false" mat-align-tabs="start" [(selectedIndex)]="tabIndex">
<mat-tab *ngFor="let category of accountCategories" label="{{category.name}}"> <mat-tab *ngFor="let category of accountCategories" label="{{category.name}}">
<table class="table"> <table class="table">
<tbody> <tbody>
@@ -10,6 +10,7 @@ import { MatDialog } from '@angular/material/dialog';
import { ApiRoutes } from '../../../api-routes'; import { ApiRoutes } from '../../../api-routes';
import { AccountModel } from '../../../model/account.model'; import { AccountModel } from '../../../model/account.model';
import { AccountCategoryModel } from '../../../model/account.category.model'; import { AccountCategoryModel } from '../../../model/account.category.model';
import { AccountInviteModel } from '../../../model/account.invite.model';
import { SettingsAccountAddComponent } from './add.account.component'; import { SettingsAccountAddComponent } from './add.account.component';
import { SettingsAccountEditComponent } from './edit.account.component'; import { SettingsAccountEditComponent } from './edit.account.component';
import { SettingsAccountAccessComponent } from './access.account.component'; import { SettingsAccountAccessComponent } from './access.account.component';
@@ -22,6 +23,8 @@ import { AccountCategoryService } from '../../../services/account.category.servi
export class SettingsAccountComponent { export class SettingsAccountComponent {
public accountCategories?: AccountCategoryModel[]; public accountCategories?: AccountCategoryModel[];
public accounts?: AccountModel[]; public accounts?: AccountModel[];
public invites?: AccountInviteModel[];
public tabIndex = 0;
constructor( constructor(
private httpClient: HttpClient, private httpClient: HttpClient,
@@ -32,13 +35,35 @@ export class SettingsAccountComponent {
ngOnInit(): void { ngOnInit(): void {
this.loadCategories(); this.loadCategories();
this.loadInvites();
} }
private loadAccounts() { private loadAccounts(accountToShow?: string) {
this.httpClient this.httpClient
.get<AccountModel[]>(ApiRoutes.SettingsAccounts) .get<AccountModel[]>(ApiRoutes.SettingsAccounts)
.subscribe(data => { .subscribe(data => {
this.accounts = data; this.accounts = data;
if (accountToShow) {
var idx = -1;
var account = this.accounts.find(x => x.id === accountToShow);
if (account && account.categories && account.categories.length > 0) {
for (var i = 0; i < this.accountCategories!.length; i++) {
if (account!.categories!.find(c => c.id === this.accountCategories![i].id)) {
idx = i;
break;
}
}
}
this.tabIndex = idx === -1 ? this.accountCategories!.length : idx;
}
});
}
private loadInvites() {
return this.httpClient
.get<AccountInviteModel[]>(ApiRoutes.SettingsAccountInvites)
.subscribe(response => {
this.invites = response;
}); });
} }
@@ -118,6 +143,57 @@ export class SettingsAccountComponent {
this.loadAccounts(); this.loadAccounts();
} }
}); });
}
public startInvite(invite: AccountInviteModel) {
Swal.fire({
title: 'Accept to invite the account "' + invite.account + '"',
input: 'text',
inputLabel: 'Accept with name',
inputValue: invite.account,
showDenyButton: true,
showCancelButton: true,
confirmButtonText: 'Accept',
denyButtonText: 'Reject',
showLoaderOnConfirm: true,
preConfirm: (input) => {
return new Promise((resolve, reject) => {
this.httpClient.post(ApiRoutes.SettingsAccountInviteAccept.replace(':id', invite.id!), { name: input })
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error);
reject();
});
}).catch(x => {
return false;
});
},
preDeny: (x) => {
return new Promise((resolve, reject) => {
this.httpClient.post(ApiRoutes.SettingsAccountInviteReject.replace(':id', invite.id!), null)
.subscribe(data => {
resolve(data);
}, error => {
Swal.showValidationMessage(error.detail);
reject();
});
}).catch(x => {
return false;
});
},
allowOutsideClick: () => !Swal.isLoading(),
}).then((result) => {
var id;
if (result.value) {
var account = result.value as AccountModel;
id = account.id;
}
this.loadInvites();
this.loadAccounts(id);
});
} }
} }
+79 -4
View File
@@ -14,6 +14,7 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using MyOffice.Services.Account.Domain; using MyOffice.Services.Account.Domain;
using System.Collections.Generic; using System.Collections.Generic;
using Identity;
public class AccountService public class AccountService
{ {
@@ -29,6 +30,7 @@
private readonly IItemRepository _itemRepository; private readonly IItemRepository _itemRepository;
private readonly IItemGlobalRepository _itemGlobalRepository; private readonly IItemGlobalRepository _itemGlobalRepository;
private readonly ItemService _itemService; private readonly ItemService _itemService;
private readonly IContextProvider _contextProvider;
public AccountService( public AccountService(
ILogger<AccountService> logger, ILogger<AccountService> logger,
@@ -42,7 +44,8 @@
IMotionRepository motionRepository, IMotionRepository motionRepository,
IItemRepository itemRepository, IItemRepository itemRepository,
IItemGlobalRepository itemGlobalRepository, IItemGlobalRepository itemGlobalRepository,
ItemService itemService ItemService itemService,
IContextProvider contextProvider
) )
{ {
_logger = logger; _logger = logger;
@@ -57,6 +60,7 @@
_itemRepository = itemRepository; _itemRepository = itemRepository;
_itemGlobalRepository = itemGlobalRepository; _itemGlobalRepository = itemGlobalRepository;
_itemService = itemService; _itemService = itemService;
_contextProvider = contextProvider;
} }
public List<AccountCategoryDto> GetAllCategories(Guid userId) public List<AccountCategoryDto> GetAllCategories(Guid userId)
@@ -528,13 +532,13 @@
if (account.AccessRights!.Any(x => x.User!.Email.EqualsIgnoreCase(email))) if (account.AccessRights!.Any(x => x.User!.Email.EqualsIgnoreCase(email)))
{ {
return result.Set(AccessInviteStatus.account_not_found); return result.Set(AccessInviteStatus.access_exists);
} }
var access = _accountAccessInviteRepository.Get(userId, email); var access = _accountAccessInviteRepository.Get(userId, email);
if (access != null) if (access != null)
{ {
return result.Set(AccessInviteStatus.access_exists); return result.Set(AccessInviteStatus.invite_exists);
} }
var invite = new AccountAccessInvite var invite = new AccountAccessInvite
@@ -542,7 +546,8 @@
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
CreatedOn = DateTime.UtcNow, CreatedOn = DateTime.UtcNow,
UserId = userId, UserId = userId,
Email = email, AccountId = account.Id,
Email = email.SafeTrim()!,
IsAllowWrite = isAllowWrite, IsAllowWrite = isAllowWrite,
}; };
@@ -606,5 +611,75 @@
return result.Set(_mapper.Map<AccountDto>(account)); return result.Set(_mapper.Map<AccountDto>(account));
} }
public List<AccountAccessInviteDto> InvitesGet(string email)
{
return _mapper.Map<List<AccountAccessInviteDto>>(_accountAccessInviteRepository.GetActive(email).ToList());
}
public Exec<AccountDto, InviteAcceptStatus> InviteAccept(Guid userId, Guid id, string name)
{
var result = new Exec<AccountDto, InviteAcceptStatus>(InviteAcceptStatus.success);
var invite = _accountAccessInviteRepository.Get(id);
if (invite == null
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|| invite.AcceptedOn.HasValue
|| invite.RejectedOn.HasValue
)
{
return result.Set(InviteAcceptStatus.invite_not_found);
}
var account = _accountRepository.Get(invite.UserId, invite.AccountId);
if (account == null)
{
return result.Set(InviteAcceptStatus.account_not_found);
}
if (account.AccessRights!.Any(x => x.UserId == userId))
{
result.Set(InviteAcceptStatus.already_accepted);
}
else
{
_accountAccessRepository.Add(new AccountAccess
{
UserId = userId,
AccountId = account.Id,
OwnerId = invite.UserId,
Name = name,
IsAllowWrite = invite.IsAllowWrite,
Type = AccountAccessTypeEnum.external,
});
}
invite.AcceptedOn = DateTime.UtcNow;
_accountAccessInviteRepository.Update(invite);
account = _accountRepository.Get(userId, account.Id);
return result.Set(_mapper.Map<AccountDto>(account));
}
public Exec<AccountAccessInviteDto, GeneralExecStatus> InviteReject(Guid id)
{
var result = new Exec<AccountAccessInviteDto, GeneralExecStatus>(GeneralExecStatus.success);
var invite = _accountAccessInviteRepository.Get(id);
if (invite == null
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|| invite.AcceptedOn.HasValue
|| invite.RejectedOn.HasValue
)
{
return result.Set(GeneralExecStatus.not_found);
}
invite.RejectedOn = DateTime.UtcNow;
_accountAccessInviteRepository.Update(invite);
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
}
} }
} }
@@ -1,8 +1,12 @@
namespace MyOffice.Services.Account.Domain; namespace MyOffice.Services.Account.Domain;
using Core.Attributes;
using Data.Models.Accounts; using Data.Models.Accounts;
using Data.Models.Users; using Data.Models.Users;
using Mapper;
[Link(typeof(AccountAccess))]
[Link(typeof(AccountServiceProfile))]
public class AccountAccessDto public class AccountAccessDto
{ {
/// <summary> /// <summary>
@@ -0,0 +1,12 @@
namespace MyOffice.Services.Account.Domain;
using Core.Attributes;
using Data.Models.Accounts;
[Link(typeof(AccountAccessInvite))]
public class AccountAccessInviteDto
{
public string Id { get; set; } = null!;
public string Account { get; set; } = null!;
public bool IsAllowWrite { get; set; }
}
@@ -2,11 +2,11 @@
using MyOffice.Data.Models.Currencies; using MyOffice.Data.Models.Currencies;
using System; using System;
using Data.Models.Accounts;
public class AccountDto public class AccountDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid CurrentUserId { get; set; }
public string CurrencyGlobalId { get; set; } = null!; public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; } public CurrencyGlobal? CurrencyGlobal { get; set; }
public Guid CurrencyId { get; set; } public Guid CurrencyId { get; set; }
@@ -20,4 +20,8 @@ public class AccountDto
public string Type { get; set; } = null!; public string Type { get; set; } = null!;
public List<AccountAccessDto>? AccessRights { get; set; } public List<AccountAccessDto>? AccessRights { get; set; }
public List<AccountAccountCategoryDto>? Categories { get; set; } public List<AccountAccountCategoryDto>? Categories { get; set; }
public Guid CurrentUserId { get; set; }
public AccountAccess? AccountAccess { get; set; }
} }
@@ -0,0 +1,10 @@
namespace MyOffice.Services.Account.Domain
{
public enum InviteAcceptStatus
{
success,
invite_not_found,
account_not_found,
already_accepted,
}
}
@@ -14,7 +14,20 @@ public class AccountServiceProfile : Profile
CreateMap<Account, AccountDto>() CreateMap<Account, AccountDto>()
.ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions!.Any())) .ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions!.Any()))
.ForMember(x => x.CurrentUserId, o => o.MapFrom<UserIdResolver>()) .ForMember(x => x.CurrentUserId, o => o.MapFrom<UserIdResolver>())
.ForMember(x => x.Type, o => o.MapFrom((src, dst) => src.AccessRights!.FirstOrDefault(x => x.UserId == dst.CurrentUserId)!.Type.ToString())) .ForMember(x => x.AccountAccess, o =>
{
o.MapFrom((src, dst) => src.AccessRights!.FirstOrDefault(x => x.UserId == dst.CurrentUserId));
})
.ForMember(x => x.Type, o =>
{
o.SetMappingOrder(1);
o.MapFrom((src, dst) => dst.AccountAccess?.Type.ToString());
})
.ForMember(x => x.Name, o =>
{
o.SetMappingOrder(1);
o.MapFrom((src, dst) => dst.AccountAccess?.Name ?? src.Name);
})
; ;
CreateMap<AccountDetailed, AccountDetailedDto>(); CreateMap<AccountDetailed, AccountDetailedDto>();
@@ -27,5 +40,9 @@ public class AccountServiceProfile : Profile
.ForMember(x => x.Id, o => o.MapFrom(x => x.Id)) .ForMember(x => x.Id, o => o.MapFrom(x => x.Id))
.ForMember(x => x.AllowDelete, o => o.MapFrom(x => !x.Accounts!.Any())) .ForMember(x => x.AllowDelete, o => o.MapFrom(x => !x.Accounts!.Any()))
; ;
CreateMap<AccountAccessInvite, AccountAccessInviteDto>()
.ForMember(x => x.Account, o => o.MapFrom(x => x.Account!.Name))
;
} }
} }
@@ -10,6 +10,7 @@ using Models.Account;
using Services.Account; using Services.Account;
using Services.Account.Domain; using Services.Account.Domain;
using MyOffice.Web.Infrastructure.Attributes; using MyOffice.Web.Infrastructure.Attributes;
using Services.Identity;
[Authorize] [Authorize]
[ApiController] [ApiController]
@@ -19,16 +20,19 @@ public class SettingsAccountController : BaseApiController
private readonly ILogger<SettingsAccountController> _logger; private readonly ILogger<SettingsAccountController> _logger;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly AccountService _accountService; private readonly AccountService _accountService;
private readonly IContextProvider _contextProvider;
public SettingsAccountController( public SettingsAccountController(
ILogger<SettingsAccountController> logger, ILogger<SettingsAccountController> logger,
IMapper mapper, IMapper mapper,
AccountService accountService AccountService accountService,
IContextProvider contextProvider
) )
{ {
_logger = logger; _logger = logger;
_mapper = mapper; _mapper = mapper;
_accountService = accountService; _accountService = accountService;
_contextProvider = contextProvider;
} }
[HttpGet("~/api/settings/account-categories")] [HttpGet("~/api/settings/account-categories")]
@@ -251,8 +255,6 @@ public class SettingsAccountController : BaseApiController
return ProblemBadRequest("Account not found."); return ProblemBadRequest("Account not found.");
case AccessInviteStatus.access_exists: case AccessInviteStatus.access_exists:
return ProblemBadRequest("Access allowed.");
case AccessInviteStatus.invite_exists: case AccessInviteStatus.invite_exists:
case AccessInviteStatus.success: case AccessInviteStatus.success:
return exec.Result!; return exec.Result!;
@@ -279,6 +281,53 @@ public class SettingsAccountController : BaseApiController
default: default:
throw new NotSupportedException(exec.Status.ToString()); throw new NotSupportedException(exec.Status.ToString());
} }
}
[HttpGet("~/api/settings/accounts/invites")]
public List<AccountAccessInviteViewModel> AccountInvites()
{
var invites = _accountService.InvitesGet(_contextProvider.User.Email);
return _mapper.Map<List<AccountAccessInviteViewModel>>(invites);
}
[HttpPost("~/api/settings/accounts/invites/{id}/accept")]
public object AccountInviteAccept([AsGuid]string id, AccountInviteAcceptRequest request)
{
var exec = _accountService.InviteAccept(UserId, id.AsGuid(), request.Name);
switch (exec.Status)
{
case InviteAcceptStatus.invite_not_found:
return ProblemBadRequest("Invite not found.");
case InviteAcceptStatus.account_not_found:
return ProblemBadRequest("Account not found.");
case InviteAcceptStatus.already_accepted:
case InviteAcceptStatus.success:
return _mapper.Map<AccountViewModel>(exec.Result!);
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpPost("~/api/settings/accounts/invites/{id}/reject")]
public object AccountInviteReject([AsGuid] string id)
{
var exec = _accountService.InviteReject(id.AsGuid());
switch (exec.Status)
{
case GeneralExecStatus.not_found:
case GeneralExecStatus.failure:
return ProblemBadRequest("Invite not found.");
case GeneralExecStatus.success:
return _mapper.Map<AccountAccessInviteViewModel>(exec.Result!);
default:
throw new NotSupportedException(exec.Status.ToString());
}
} }
} }
@@ -0,0 +1,13 @@
namespace MyOffice.Web.Models.Account;
using Core.Attributes;
using Services.Account.Domain;
[LinkFrom(typeof(AccountAccessInviteDto))]
[LinkWith(typeof(AccountViewModelProfile))]
public class AccountAccessInviteViewModel
{
public string? Id { get; set; }
public string? Account { get; set; }
public bool? AllowWrite { get; set; }
}
@@ -1,9 +1,10 @@
namespace MyOffice.Web.Models.Account namespace MyOffice.Web.Models.Account;
{
using System.ComponentModel.DataAnnotations;
using Core.Extensions;
using Data.Models.Accounts;
using MyOffice.Core.Attributes;
using MyOffice.Services.Account.Domain;
using System.ComponentModel.DataAnnotations;
[Link(typeof(AccountCategoryDto))]
public class AccountCategoryViewModel public class AccountCategoryViewModel
{ {
public string? Id { get; set; } public string? Id { get; set; }
@@ -13,17 +14,3 @@
public bool? AllowDelete { get; set; } public bool? AllowDelete { get; set; }
} }
public static class AccountCategoryViewModelExtensions
{
public static AccountCategoryViewModel ToModel(this AccountCategory input)
{
return new AccountCategoryViewModel
{
Id = input.Id.ToShort(),
Name = input.Name,
AllowDelete = !input.Accounts?.Any(),
};
}
}
}
@@ -0,0 +1,6 @@
namespace MyOffice.Web.Models.Account;
public class AccountInviteAcceptRequest
{
public string Name { get; set; } = null!;
}
@@ -3,11 +3,7 @@
using AutoMapper; using AutoMapper;
using MyOffice.Services.Identity; using MyOffice.Services.Identity;
using Services.Account.Domain; using Services.Account.Domain;
using Services.Mapper;
using System.Security.Cryptography;
using Core.Extensions;
using User; using User;
using static MyOffice.Web.Models.Account.AccountAccessViewModel;
public class CustomResolver : IValueResolver<AccountAccessDto, AccessRightsViewModel, bool> public class CustomResolver : IValueResolver<AccountAccessDto, AccessRightsViewModel, bool>
{ {
@@ -61,11 +57,15 @@ public class AccountViewModelProfile : Profile
(src, dst) => src.OwnerId == src.UserId)) (src, dst) => src.OwnerId == src.UserId))
; ;
CreateMap<AccountAccessItemViewModel, AccountAccessDto>() CreateMap<AccountAccessViewModel.AccountAccessItemViewModel, AccountAccessDto>()
.ForMember(x => x.IsAllowWrite, o => o.MapFrom(x => x.AllowWrite)) .ForMember(x => x.IsAllowWrite, o => o.MapFrom(x => x.AllowWrite))
; ;
CreateMap<AccountCategoryDto, AccountCategoryViewModel>() CreateMap<AccountCategoryDto, AccountCategoryViewModel>()
; ;
CreateMap<AccountAccessInviteDto, AccountAccessInviteViewModel>()
.ForMember(x => x.AllowWrite, o => o.MapFrom(x => x.IsAllowWrite))
;
} }
} }
+8
View File
@@ -64,6 +64,13 @@ using MyOffice.Services.Mapper;
//TODO: Response model from base type //TODO: Response model from base type
//TODO: XXXResult -> XXXStatus //TODO: XXXResult -> XXXStatus
//TODO: SPA isAllowDelete -> allowDelete (remove is) //TODO: SPA isAllowDelete -> allowDelete (remove is)
//TODO: Repository auto registration
//TODO: Services auto registration
//TODO: openid-configuration failed - lock login
//TODO: BUG some times after login redirect to dashboard but exists return url
//TODO: email confirmation
//TODO: email password reset
//TODO: automapper -> Extension ToModel() ToDbo() FromModel() FromDbo()
public class Program public class Program
{ {
@@ -262,6 +269,7 @@ public class Program
builder.Services.AddScoped<IAccountCategoryRepository, AccountCategoryRepository>(); builder.Services.AddScoped<IAccountCategoryRepository, AccountCategoryRepository>();
builder.Services.AddScoped<IAccountRepository, AccountRepository>(); builder.Services.AddScoped<IAccountRepository, AccountRepository>();
builder.Services.AddScoped<IAccountAccessRepository, AccountAccessRepository>(); builder.Services.AddScoped<IAccountAccessRepository, AccountAccessRepository>();
builder.Services.AddScoped<IAccountAccessInviteRepository, AccountAccessInviteRepository>();
builder.Services.AddScoped<IAccountAccountCategoryRepository, AccountAccountCategoryRepository>(); builder.Services.AddScoped<IAccountAccountCategoryRepository, AccountAccountCategoryRepository>();
builder.Services.AddScoped<IItemCategoryRepository, ItemCategoryRepository>(); builder.Services.AddScoped<IItemCategoryRepository, ItemCategoryRepository>();