diff --git a/.vscode/launch.json b/.vscode/launch.json
index 2f75cee9..e660d983 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -4,6 +4,17 @@
// Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
+ {
+ "name": "cli .NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ "program": "${workspaceFolder}/src/cli/bin/Debug/net9.0/cli.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ "stopAtEntry": false,
+ "console": "internalConsole"
+ },
{
"name": "C#: sampleWebAsWebApiClient Debug",
"type": "dotnet",
@@ -120,7 +131,7 @@
"name": "web core",
"type": "coreclr",
"request": "launch",
- "program": "${workspaceFolder}/src/Yavsc/bin/Debug/net8.0/Yavsc.dll",
+ "program": "${workspaceFolder}/src/Yavsc/bin/Debug/net9.0/Yavsc.dll",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 60c5ad84..297c6816 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -22,12 +22,16 @@
+
+
+
+
@@ -40,6 +44,7 @@
+
@@ -47,4 +52,4 @@
-
+
\ No newline at end of file
diff --git a/src/Yavsc.Abstract/Authentication/OAuthenticator.cs b/src/Yavsc.Abstract/Authentication/OAuthenticator.cs
deleted file mode 100644
index 20c44546..00000000
--- a/src/Yavsc.Abstract/Authentication/OAuthenticator.cs
+++ /dev/null
@@ -1,482 +0,0 @@
-
-using System;
-using System.Threading.Tasks;
-using System.Collections.Generic;
-using System.Net;
-using System.Text;
-using GetUsernameAsyncFunc=System.Func, System.Threading.Tasks.Task>;
-using System.IO;
-using Newtonsoft.Json;
-
-namespace Yavsc.Authentication
-{
- public class OAuthenticator
- {
- public OAuthenticator()
- {
-
- }
-
- readonly string clientId;
- readonly string clientSecret;
- readonly string scope;
- readonly Uri authorizeUrl;
- readonly Uri accessTokenUrl;
- readonly Uri redirectUrl;
- readonly GetUsernameAsyncFunc getUsernameAsync;
- readonly string requestState;
- bool reportedForgery = false;
-
- ///
- /// Gets the client identifier.
- ///
- /// The client identifier.
- public string ClientId
- {
- get { return this.clientId; }
- }
-
- ///
- /// Gets the client secret.
- ///
- /// The client secret.
- public string ClientSecret
- {
- get { return this.clientSecret; }
- }
-
- ///
- /// Gets the authorization scope.
- ///
- /// The authorization scope.
- public string Scope
- {
- get { return this.scope; }
- }
-
- ///
- /// Gets the authorize URL.
- ///
- /// The authorize URL.
- public Uri AuthorizeUrl
- {
- get { return this.authorizeUrl; }
- }
-
- ///
- /// Gets the access token URL.
- ///
- /// The URL used to request access tokens after an authorization code was received.
- public Uri AccessTokenUrl
- {
- get { return this.accessTokenUrl; }
- }
-
- ///
- /// Redirect Url
- ///
- public Uri RedirectUrl
- {
- get { return this.redirectUrl; }
- }
-
- ///
- /// Initializes a new
- /// that authenticates using implicit granting (token).
- ///
- ///
- /// Client identifier.
- ///
- ///
- /// Authorization scope.
- ///
- ///
- /// Authorize URL.
- ///
- ///
- /// Redirect URL.
- ///
- ///
- /// Method used to fetch the username of an account
- /// after it has been successfully authenticated.
- ///
- public OAuthenticator(string clientId, string scope, Uri authorizeUrl, Uri redirectUrl, GetUsernameAsyncFunc getUsernameAsync = null)
- : this(redirectUrl)
- {
- if (string.IsNullOrEmpty(clientId))
- {
- throw new ArgumentException("clientId must be provided", "clientId");
- }
- if (authorizeUrl==null)
- throw new ArgumentNullException("authorizeUrl");
-
- this.clientId = clientId;
- this.scope = scope ?? "";
- this.authorizeUrl = authorizeUrl ;
- this.getUsernameAsync = getUsernameAsync;
- this.accessTokenUrl = null;
- }
-
- ///
- /// Initializes a new instance
- /// that authenticates using authorization codes (code).
- ///
- ///
- /// Client identifier.
- ///
- ///
- /// Client secret.
- ///
- ///
- /// Authorization scope.
- ///
- ///
- /// Authorize URL.
- ///
- ///
- /// Redirect URL.
- ///
- ///
- /// URL used to request access tokens after an authorization code was received.
- ///
- ///
- /// Method used to fetch the username of an account
- /// after it has been successfully authenticated.
- ///
- public OAuthenticator(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null)
- : this(redirectUrl, clientSecret, accessTokenUrl)
- {
- if (string.IsNullOrEmpty(clientId))
- {
- throw new ArgumentException("clientId must be provided", "clientId");
- }
- this.clientId = clientId;
-
- if (string.IsNullOrEmpty(clientSecret))
- {
- throw new ArgumentException("clientSecret must be provided", "clientSecret");
- }
- this.clientSecret = clientSecret;
-
- this.scope = scope ?? "";
-
- if (authorizeUrl == null)
- {
- throw new ArgumentNullException("authorizeUrl");
- }
- this.authorizeUrl = authorizeUrl;
-
- if (accessTokenUrl == null)
- {
- throw new ArgumentNullException("accessTokenUrl");
- }
- this.accessTokenUrl = accessTokenUrl;
-
- if (redirectUrl == null)
- throw new Exception("redirectUrl is null");
-
- this.redirectUrl = redirectUrl;
-
- this.getUsernameAsync = getUsernameAsync;
- }
-
-
- OAuthenticator(Uri redirectUrl, string clientSecret = null, Uri accessTokenUrl = null)
-
- {
- this.redirectUrl = redirectUrl;
-
- this.clientSecret = clientSecret;
-
- this.accessTokenUrl = accessTokenUrl;
-
- //
- // Generate a unique state string to check for forgeries
- //
- var chars = new char[16];
- var rand = new Random();
- for (var i = 0; i < chars.Length; i++)
- {
- chars[i] = (char)rand.Next((int)'a', (int)'z' + 1);
- }
- this.requestState = new string(chars);
- }
-
- bool IsImplicit { get { return accessTokenUrl == null; } }
-
- ///
- /// Method that returns the initial URL to be displayed in the web browser.
- ///
- ///
- /// A task that will return the initial URL.
- ///
- public Task GetInitialUrlAsync()
- {
- var url = new Uri(string.Format(
- "{0}?client_id={1}&redirect_uri={2}&response_type={3}&scope={4}&state={5}",
- authorizeUrl.AbsoluteUri,
- Uri.EscapeDataString(clientId),
- Uri.EscapeDataString(RedirectUrl.AbsoluteUri),
- IsImplicit ? "token" : "code",
- Uri.EscapeDataString(scope),
- Uri.EscapeDataString(requestState)));
-
- var tcs = new TaskCompletionSource();
- tcs.SetResult(url);
- return tcs.Task;
- }
-
- ///
- /// Raised when a new page has been loaded.
- ///
- ///
- /// URL of the page.
- ///
- ///
- /// The parsed query of the URL.
- ///
- ///
- /// The parsed fragment of the URL.
- ///
- protected void OnPageEncountered(Uri url, IDictionary query, IDictionary fragment)
- {
-
- if (url.AbsoluteUri.StartsWith(this.redirectUrl.AbsoluteUri))
- {
- if (!this.redirectUrl.Equals(url)) {
-
- // this is not our redirect page,
- // but perhaps one one the third party identity providers
- // One don't check for a state here.
- //
- if (fragment.ContainsKey("continue")) {
- var cont = fragment["continue"];
- // TODO continue browsing this address
-
- var tcs = new TaskCompletionSource();
- tcs.SetResult(new Uri(cont));
- tcs.Task.RunSynchronously();
- }
- return;
- }
-
- var all = new Dictionary(query);
- foreach (var kv in fragment)
- all[kv.Key] = kv.Value;
-
- //
- // Check for forgeries
- //
- if (all.ContainsKey("state"))
- {
- if (all["state"] != requestState && !reportedForgery)
- {
- reportedForgery = true;
- OnError("Invalid state from server. Possible forgery!");
- return;
- }
- }
- }
- }
-
- private void OnError(string v)
- {
- throw new NotImplementedException();
- }
- private void OnError(AggregateException ex)
- {
- throw new NotImplementedException();
- }
- ///
- /// Raised when a new page has been loaded.
- ///
- ///
- /// URL of the page.
- ///
- ///
- /// The parsed query string of the URL.
- ///
- ///
- /// The parsed fragment of the URL.
- ///
- protected void OnRedirectPageLoaded(Uri url, IDictionary query, IDictionary fragment)
- {
- //
- // Look for the access_token
- //
- if (fragment.ContainsKey("access_token"))
- {
- //
- // We found an access_token
- //
- OnRetrievedAccountProperties(fragment);
- }
- else if (!IsImplicit)
- {
- //
- // Look for the code
- //
- if (query.ContainsKey("code"))
- {
- var code = query["code"];
- RequestAccessTokenAsync(code).ContinueWith(task =>
- {
- if (task.IsFaulted)
- {
- OnError(task.Exception);
- }
- else
- {
- OnRetrievedAccountProperties(task.Result);
- }
- }, TaskScheduler.FromCurrentSynchronizationContext());
- }
- else
- {
- OnError("Expected code in response, but did not receive one.");
- return;
- }
- }
- else
- {
- OnError("Expected access_token in response, but did not receive one.");
- return;
- }
- }
-
- ///
- /// Asynchronously requests an access token with an authorization .
- ///
- ///
- /// A dictionary of data returned from the authorization request.
- ///
- /// The authorization code.
- /// Implements: http://tools.ietf.org/html/rfc6749#section-4.1
- Task> RequestAccessTokenAsync(string code)
- {
- var queryValues = new Dictionary {
- { "grant_type", "authorization_code" },
- { "code", code },
- { "redirect_uri", RedirectUrl.AbsoluteUri },
- { "client_id", clientId }
- };
- if (!string.IsNullOrEmpty(clientSecret))
- {
- queryValues["client_secret"] = clientSecret;
- }
-
- return RequestAccessTokenAsync(queryValues);
- }
-
- ///
- /// Asynchronously makes a request to the access token URL with the given parameters.
- ///
- /// The parameters to make the request with.
- /// The data provided in the response to the access token request.
- public async Task> RequestAccessTokenAsync(IDictionary queryValues)
- {
- StringBuilder postData = new StringBuilder();
- if (!queryValues.ContainsKey("client_id"))
- {
- postData.Append("client_id="+Uri.EscapeDataString($"{this.clientId}")+"&");
- }
- if (!queryValues.ContainsKey("client_secret"))
- {
- postData.Append("client_secret="+Uri.EscapeDataString($"{this.clientSecret}")+"&");
- }
- if (!queryValues.ContainsKey("scope"))
- {
- postData.Append("scope="+Uri.EscapeDataString($"{this.scope}")+"&");
- }
- foreach (string key in queryValues.Keys)
- {
- postData.Append($"{key}="+Uri.EscapeDataString($"{queryValues[key]}")+"&");
- }
- var req = WebRequest.Create(accessTokenUrl);
- (req as HttpWebRequest).Accept = "application/json";
- req.Method = "POST";
- var body = Encoding.UTF8.GetBytes(postData.ToString());
- req.ContentLength = body.Length;
- req.ContentType = "application/x-www-form-urlencoded";
- var s = req.GetRequestStream();
-
- s.Write(body, 0, body.Length);
-
- var auth = await req.GetResponseAsync();
-
- var repstream = auth.GetResponseStream();
-
- var respReader = new StreamReader(repstream);
-
- var text = await respReader.ReadToEndAsync();
-
- req.Abort();
- // Parse the response
- var data = text.Contains("{") ? JsonDecode(text) : FormDecode(text);
-
- if (data.ContainsKey("error"))
- {
- OnError("Error authenticating: " + data["error"]);
- }
- else if (data.ContainsKey("access_token"))
- {
- return data;
- }
- else
- {
- OnError("Expected access_token in access token response, but did not receive one.");
- }
- return data;
- }
-
- private IDictionary FormDecode(string text)
- {
-
- throw new NotImplementedException();
- }
-
- private IDictionary JsonDecode(string text)
- {
- return JsonConvert.DeserializeObject>(text);
- }
-
- ///
- /// Event handler that is fired when an access token has been retreived.
- ///
- ///
- /// The retrieved account properties
- ///
- protected virtual void OnRetrievedAccountProperties(IDictionary accountProperties)
- {
- //
- // Now we just need a username for the account
- //
- if (getUsernameAsync != null)
- {
- getUsernameAsync(accountProperties).ContinueWith(task =>
- {
- if (task.IsFaulted)
- {
- OnError(task.Exception);
- }
- else
- {
- OnSucceeded(task.Result, accountProperties);
- }
- }, TaskScheduler.FromCurrentSynchronizationContext());
- }
- else
- {
- OnSucceeded("", accountProperties);
- }
- }
-
- private void OnSucceeded(string v, IDictionary accountProperties)
- {
- throw new NotImplementedException();
- }
- }
-
-}
-
-
diff --git a/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs b/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs
index 63c69cb4..76a48149 100644
--- a/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs
+++ b/src/Yavsc.Abstract/FileSystem/FsOperationInfo.cs
@@ -12,7 +12,7 @@ namespace Yavsc.Abstract.Helpers
public bool Done { get; set; } = false;
public ErrorCode ErrorCode { get; set; }
- public string ErrorMessage { get; set; }
+ public string? ErrorMessage { get; set; }
}
}
diff --git a/src/Yavsc.Server/Migrations/20250715211745_test.Designer.cs b/src/Yavsc.Server/Migrations/20250715211745_test.Designer.cs
new file mode 100644
index 00000000..0dd5acab
--- /dev/null
+++ b/src/Yavsc.Server/Migrations/20250715211745_test.Designer.cs
@@ -0,0 +1,3445 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+using Yavsc.Models;
+
+#nullable disable
+
+namespace Yavsc.Migrations
+{
+ [DbContext(typeof(ApplicationDbContext))]
+ [Migration("20250715211745_test")]
+ partial class test
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "9.0.7")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property("RoleId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetRoleClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("ClaimType")
+ .HasColumnType("text");
+
+ b.Property("ClaimValue")
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserClaims", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
+ {
+ b.Property("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property("ProviderKey")
+ .HasColumnType("text");
+
+ b.Property("ProviderDisplayName")
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("LoginProvider", "ProviderKey");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AspNetUserLogins", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("text");
+
+ b.Property("RoleId")
+ .HasColumnType("text");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles", (string)null);
+ });
+
+ modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("text");
+
+ b.Property("LoginProvider")
+ .HasColumnType("text");
+
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("Value")
+ .HasColumnType("text");
+
+ b.HasKey("UserId", "LoginProvider", "Name");
+
+ b.ToTable("AspNetUserTokens", (string)null);
+ });
+
+ modelBuilder.Entity("Yavsc.Abstract.Identity.ClientProviderInfo", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("text");
+
+ b.Property("Avatar")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BillingAddressId")
+ .HasColumnType("bigint");
+
+ b.Property("EMail")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Phone")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserName")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("UserId");
+
+ b.ToTable("ClientProviderInfo");
+ });
+
+ modelBuilder.Entity("Yavsc.Abstract.Models.Messaging.Notification", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Target")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("body")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("click_action")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("color")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("icon")
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)")
+ .HasDefaultValue("exclam");
+
+ b.Property("sound")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("tag")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("title")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Notification");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Access.Ban", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("TargetId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserCreated")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserModified")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TargetId");
+
+ b.ToTable("Ban");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Access.BlackListed", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("OwnerId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("OwnerId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("BlackListed");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Access.CircleAuthorizationToBlogPost", b =>
+ {
+ b.Property("CircleId")
+ .HasColumnType("bigint");
+
+ b.Property("BlogPostId")
+ .HasColumnType("bigint");
+
+ b.Property("Comment")
+ .HasColumnType("boolean");
+
+ b.HasKey("CircleId", "BlogPostId");
+
+ b.HasIndex("BlogPostId");
+
+ b.ToTable("CircleAuthorizationToBlogPost");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.AccountBalance", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("text");
+
+ b.Property("ContactCredits")
+ .HasColumnType("bigint");
+
+ b.Property("Credits")
+ .HasColumnType("numeric");
+
+ b.HasKey("UserId");
+
+ b.ToTable("BankStatus");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.ApplicationUser", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("integer");
+
+ b.Property("AllowMonthlyEmail")
+ .HasColumnType("boolean");
+
+ b.Property("Avatar")
+ .ValueGeneratedOnAdd()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)")
+ .HasDefaultValue("/images/Users/icon_user.png");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("text");
+
+ b.Property("DedicatedGoogleCalendar")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("DiskQuota")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint")
+ .HasDefaultValue(524288000L);
+
+ b.Property("DiskUsage")
+ .HasColumnType("bigint");
+
+ b.Property("Email")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("FullName")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("MaxFileSize")
+ .HasColumnType("bigint");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("PasswordHash")
+ .HasColumnType("text");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("text");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("boolean");
+
+ b.Property("PostalAddressId")
+ .HasColumnType("bigint");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("text");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("boolean");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.HasKey("Id");
+
+ b.HasAlternateKey("Email");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.HasIndex("PostalAddressId");
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Auth.Client", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("text");
+
+ b.Property("AccessTokenLifetime")
+ .HasColumnType("integer");
+
+ b.Property("Active")
+ .HasColumnType("boolean");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("character varying(128)");
+
+ b.Property("LogoutRedirectUri")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("RedirectUri")
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("RefreshTokenLifeTime")
+ .HasColumnType("integer");
+
+ b.Property("Secret")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("Type")
+ .HasColumnType("integer");
+
+ b.HasKey("Id");
+
+ b.ToTable("Client");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Auth.Scope", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.HasKey("Id");
+
+ b.ToTable("Scopes");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.BalanceImpact", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("BalanceId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ExecDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Impact")
+ .HasColumnType("numeric");
+
+ b.Property("Reason")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("BalanceId");
+
+ b.ToTable("BalanceImpact");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Bank.BankIdentity", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AccountNumber")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BIC")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BankCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("BankedKey")
+ .HasColumnType("integer");
+
+ b.Property("IBAN")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("WicketCode")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("BankIdentity");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Billing.CommandLine", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Count")
+ .HasColumnType("integer");
+
+ b.Property("Currency")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("character varying(512)");
+
+ b.Property("EstimateId")
+ .HasColumnType("bigint");
+
+ b.Property("EstimateTemplateId")
+ .HasColumnType("bigint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("character varying(256)");
+
+ b.Property("UnitaryCost")
+ .HasColumnType("numeric");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EstimateId");
+
+ b.HasIndex("EstimateTemplateId");
+
+ b.ToTable("CommandLine");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Billing.Estimate", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AttachedFilesString")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("AttachedGraphicsString")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ClientId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ClientValidationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("CommandId")
+ .HasColumnType("bigint");
+
+ b.Property("CommandType")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OwnerId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("ProviderValidationDate")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("CommandId");
+
+ b.HasIndex("OwnerId");
+
+ b.ToTable("Estimates");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Billing.EstimateTemplate", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("OwnerId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("EstimateTemplates");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Billing.ExceptionSIREN", b =>
+ {
+ b.Property("SIREN")
+ .HasColumnType("text");
+
+ b.HasKey("SIREN");
+
+ b.ToTable("ExceptionsSIREN");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Blog.BlogPost", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AuthorId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Content")
+ .HasMaxLength(56224)
+ .HasColumnType("character varying(56224)");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Photo")
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.Property("Title")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("character varying(1024)");
+
+ b.Property("UserCreated")
+ .HasColumnType("text");
+
+ b.Property("UserModified")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorId");
+
+ b.ToTable("BlogSpot");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Blog.BlogTag", b =>
+ {
+ b.Property("PostId")
+ .HasColumnType("bigint");
+
+ b.Property("TagId")
+ .HasColumnType("bigint");
+
+ b.HasKey("PostId", "TagId");
+
+ b.HasIndex("TagId");
+
+ b.ToTable("BlogTag");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Blog.Comment", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("AuthorId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Content")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("ParentId")
+ .HasColumnType("bigint");
+
+ b.Property("ReceiverId")
+ .HasColumnType("bigint");
+
+ b.Property("UserCreated")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserModified")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Visible")
+ .HasColumnType("boolean");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorId");
+
+ b.HasIndex("ParentId");
+
+ b.HasIndex("ReceiverId");
+
+ b.ToTable("Comment");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.BlogSpotPublication", b =>
+ {
+ b.Property("BlogpostId")
+ .HasColumnType("bigint");
+
+ b.HasKey("BlogpostId");
+
+ b.ToTable("blogSpotPublications");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Calendar.Schedule", b =>
+ {
+ b.Property("OwnerId")
+ .HasColumnType("text");
+
+ b.HasKey("OwnerId");
+
+ b.ToTable("Schedule");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Calendar.ScheduledEvent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("PeriodEnd")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("PeriodStart")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Reccurence")
+ .HasColumnType("integer");
+
+ b.Property("ScheduleOwnerId")
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ScheduleOwnerId");
+
+ b.HasIndex("PeriodStart", "PeriodEnd");
+
+ b.ToTable("ScheduledEvent");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Chat.ChatConnection", b =>
+ {
+ b.Property("ConnectionId")
+ .HasColumnType("text");
+
+ b.Property("ApplicationUserId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Connected")
+ .HasColumnType("boolean");
+
+ b.Property("UserAgent")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("ConnectionId");
+
+ b.HasIndex("ApplicationUserId");
+
+ b.ToTable("ChatConnection");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Chat.ChatRoom", b =>
+ {
+ b.Property("Name")
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("LatestJoinPart")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("OwnerId")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Topic")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserCreated")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserModified")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Name");
+
+ b.HasIndex("OwnerId");
+
+ b.ToTable("ChatRoom");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Chat.ChatRoomAccess", b =>
+ {
+ b.Property("ChannelName")
+ .HasColumnType("text");
+
+ b.Property("UserId")
+ .HasColumnType("text");
+
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Level")
+ .HasColumnType("integer");
+
+ b.HasKey("ChannelName", "UserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("ChatRoomAccess");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Cratie.Option", b =>
+ {
+ b.Property("Code")
+ .HasColumnType("text");
+
+ b.Property("CodeScrutin")
+ .HasColumnType("text");
+
+ b.Property("DateCreated")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("DateModified")
+ .HasColumnType("timestamp with time zone");
+
+ b.Property("Description")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserCreated")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("UserModified")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Code", "CodeScrutin");
+
+ b.ToTable("Option");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Drawing.Color", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id"));
+
+ b.Property("Blue")
+ .HasColumnType("smallint");
+
+ b.Property("Green")
+ .HasColumnType("smallint");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.Property("Red")
+ .HasColumnType("smallint");
+
+ b.HasKey("Id");
+
+ b.ToTable("Color");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Forms.Form", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("text");
+
+ b.Property("Summary")
+ .IsRequired()
+ .HasColumnType("text");
+
+ b.HasKey("Id");
+
+ b.ToTable("Form");
+ });
+
+ modelBuilder.Entity("Yavsc.Models.Haircut.BrusherProfile", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("text");
+
+ b.Property("ActionDistance")
+ .HasColumnType("integer");
+
+ b.Property("CarePrice")
+ .HasColumnType("numeric");
+
+ b.Property("FlatFeeDiscount")
+ .HasColumnType("numeric");
+
+ b.Property("HalfBalayagePrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfBrushingPrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfColorPrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfDefrisPrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfFoldingPrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfMechPrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfMultiColorPrice")
+ .HasColumnType("numeric");
+
+ b.Property("HalfPermanentPrice")
+ .HasColumnType("numeric");
+
+ b.Property("KidCutPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongBalayagePrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongBrushingPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongColorPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongDefrisPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongFoldingPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongMechPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongMultiColorPrice")
+ .HasColumnType("numeric");
+
+ b.Property("LongPermanentPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ManBrushPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ManCutPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ScheduleOwnerId")
+ .HasColumnType("text");
+
+ b.Property("ShampooPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortBalayagePrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortBrushingPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortColorPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortDefrisPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortFoldingPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortMechPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortMultiColorPrice")
+ .HasColumnType("numeric");
+
+ b.Property("ShortPermanentPrice")
+ .HasColumnType("numeric");
+
+ b.Property