diff --git a/DysonNetwork.Drive/Billing/UsageService.cs b/DysonNetwork.Drive/Billing/UsageService.cs new file mode 100644 index 0000000..87ac4b1 --- /dev/null +++ b/DysonNetwork.Drive/Billing/UsageService.cs @@ -0,0 +1,6 @@ +namespace DysonNetwork.Drive.Billing; + +public class UsageService +{ + +} \ No newline at end of file diff --git a/DysonNetwork.Drive/Client/src/views/index.vue b/DysonNetwork.Drive/Client/src/views/index.vue index fd02bf1..3f615b4 100644 --- a/DysonNetwork.Drive/Client/src/views/index.vue +++ b/DysonNetwork.Drive/Client/src/views/index.vue @@ -149,7 +149,8 @@ const renderSingleSelectTag: SelectRenderTag = ({ option }) => { ) } -function renderPoolSelectLabel(option: SelectOption & SnFilePool, selected: boolean) { +function renderPoolSelectLabel(option: SelectOption & SnFilePool) { + const policy: any = option.policy_config return h( 'div', { @@ -171,7 +172,7 @@ function renderPoolSelectLabel(option: SelectOption & SnFilePool, selected: bool }, }, [ - option.public_usable && + policy.public_usable && h( NTag, { @@ -181,7 +182,7 @@ function renderPoolSelectLabel(option: SelectOption & SnFilePool, selected: bool }, { default: () => 'Public Shared' }, ), - option.public_indexable && + policy.public_indexable && h( NTag, { @@ -191,7 +192,7 @@ function renderPoolSelectLabel(option: SelectOption & SnFilePool, selected: bool }, { default: () => 'Public Indexable' }, ), - option.allow_encryption && + policy.allow_encryption && h( NTag, { diff --git a/DysonNetwork.Drive/Migrations/20250725051034_UpdateCloudFileThumbnail.Designer.cs b/DysonNetwork.Drive/Migrations/20250725051034_UpdateCloudFileThumbnail.Designer.cs deleted file mode 100644 index a962603..0000000 --- a/DysonNetwork.Drive/Migrations/20250725051034_UpdateCloudFileThumbnail.Designer.cs +++ /dev/null @@ -1,194 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Drive; -using DysonNetwork.Shared.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250725051034_UpdateCloudFileThumbnail")] - partial class UpdateCloudFileThumbnail - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.Property("Id") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("uuid") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("HasCompression") - .HasColumnType("boolean") - .HasColumnName("has_compression"); - - b.Property("HasThumbnail") - .HasColumnType("boolean") - .HasColumnName("has_thumbnail"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("IsMarkedRecycle") - .HasColumnType("boolean") - .HasColumnName("is_marked_recycle"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property>("SensitiveMarks") - .HasColumnType("jsonb") - .HasColumnName("sensitive_marks"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("StorageId") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("storage_id"); - - b.Property("StorageUrl") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("storage_url"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("FileId") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("file_id"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("resource_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Usage") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("usage"); - - b.HasKey("Id") - .HasName("pk_file_references"); - - b.HasIndex("FileId") - .HasDatabaseName("ix_file_references_file_id"); - - b.ToTable("file_references", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.HasOne("DysonNetwork.Drive.Storage.CloudFile", "File") - .WithMany() - .HasForeignKey("FileId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_file_references_files_file_id"); - - b.Navigation("File"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725051034_UpdateCloudFileThumbnail.cs b/DysonNetwork.Drive/Migrations/20250725051034_UpdateCloudFileThumbnail.cs deleted file mode 100644 index 369dcd9..0000000 --- a/DysonNetwork.Drive/Migrations/20250725051034_UpdateCloudFileThumbnail.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - /// - public partial class UpdateCloudFileThumbnail : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "has_thumbnail", - table: "files", - type: "boolean", - nullable: false, - defaultValue: false); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "has_thumbnail", - table: "files"); - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725163615_AddCloudFilePool.Designer.cs b/DysonNetwork.Drive/Migrations/20250725163615_AddCloudFilePool.Designer.cs deleted file mode 100644 index a771bdc..0000000 --- a/DysonNetwork.Drive/Migrations/20250725163615_AddCloudFilePool.Designer.cs +++ /dev/null @@ -1,253 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Drive; -using DysonNetwork.Drive.Storage; -using DysonNetwork.Shared.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250725163615_AddCloudFilePool")] - partial class AddCloudFilePool - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.Property("Id") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("uuid") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("HasCompression") - .HasColumnType("boolean") - .HasColumnName("has_compression"); - - b.Property("HasThumbnail") - .HasColumnType("boolean") - .HasColumnName("has_thumbnail"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("IsMarkedRecycle") - .HasColumnType("boolean") - .HasColumnName("is_marked_recycle"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("PoolId") - .HasColumnType("uuid") - .HasColumnName("pool_id"); - - b.Property>("SensitiveMarks") - .HasColumnType("jsonb") - .HasColumnName("sensitive_marks"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("StorageId") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("storage_id"); - - b.Property("StorageUrl") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("storage_url"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("PoolId") - .HasDatabaseName("ix_files_pool_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("FileId") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("file_id"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("resource_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Usage") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("usage"); - - b.HasKey("Id") - .HasName("pk_file_references"); - - b.HasIndex("FileId") - .HasDatabaseName("ix_file_references_file_id"); - - b.ToTable("file_references", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.FilePool", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("BillingConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("billing_config"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("StorageConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("storage_config"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_pools"); - - b.ToTable("pools", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Drive.Storage.FilePool", "Pool") - .WithMany() - .HasForeignKey("PoolId") - .HasConstraintName("fk_files_pools_pool_id"); - - b.Navigation("Pool"); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.HasOne("DysonNetwork.Drive.Storage.CloudFile", "File") - .WithMany() - .HasForeignKey("FileId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_file_references_files_file_id"); - - b.Navigation("File"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725170254_AddCloudFileEncrypt.cs b/DysonNetwork.Drive/Migrations/20250725170254_AddCloudFileEncrypt.cs deleted file mode 100644 index dcc5a80..0000000 --- a/DysonNetwork.Drive/Migrations/20250725170254_AddCloudFileEncrypt.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - /// - public partial class AddCloudFileEncrypt : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "is_encrypted", - table: "files", - type: "boolean", - nullable: false, - defaultValue: false); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "is_encrypted", - table: "files"); - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725183846_EnrichCloudPoolConfigure.Designer.cs b/DysonNetwork.Drive/Migrations/20250725183846_EnrichCloudPoolConfigure.Designer.cs deleted file mode 100644 index f098e3e..0000000 --- a/DysonNetwork.Drive/Migrations/20250725183846_EnrichCloudPoolConfigure.Designer.cs +++ /dev/null @@ -1,277 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Drive; -using DysonNetwork.Drive.Storage; -using DysonNetwork.Shared.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250725183846_EnrichCloudPoolConfigure")] - partial class EnrichCloudPoolConfigure - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.Property("Id") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("uuid") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("HasCompression") - .HasColumnType("boolean") - .HasColumnName("has_compression"); - - b.Property("HasThumbnail") - .HasColumnType("boolean") - .HasColumnName("has_thumbnail"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("IsEncrypted") - .HasColumnType("boolean") - .HasColumnName("is_encrypted"); - - b.Property("IsMarkedRecycle") - .HasColumnType("boolean") - .HasColumnName("is_marked_recycle"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("PoolId") - .HasColumnType("uuid") - .HasColumnName("pool_id"); - - b.Property>("SensitiveMarks") - .HasColumnType("jsonb") - .HasColumnName("sensitive_marks"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("StorageId") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("storage_id"); - - b.Property("StorageUrl") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("storage_url"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("PoolId") - .HasDatabaseName("ix_files_pool_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("FileId") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("file_id"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("resource_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Usage") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("usage"); - - b.HasKey("Id") - .HasName("pk_file_references"); - - b.HasIndex("FileId") - .HasDatabaseName("ix_file_references_file_id"); - - b.ToTable("file_references", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.FilePool", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AllowAnonymous") - .HasColumnType("boolean") - .HasColumnName("allow_anonymous"); - - b.Property("AllowEncryption") - .HasColumnType("boolean") - .HasColumnName("allow_encryption"); - - b.Property("BillingConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("billing_config"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("NoMetadata") - .HasColumnType("boolean") - .HasColumnName("no_metadata"); - - b.Property("NoOptimization") - .HasColumnType("boolean") - .HasColumnName("no_optimization"); - - b.Property("RequirePrivilege") - .HasColumnType("integer") - .HasColumnName("require_privilege"); - - b.Property("StorageConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("storage_config"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_pools"); - - b.ToTable("pools", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Drive.Storage.FilePool", "Pool") - .WithMany() - .HasForeignKey("PoolId") - .HasConstraintName("fk_files_pools_pool_id"); - - b.Navigation("Pool"); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.HasOne("DysonNetwork.Drive.Storage.CloudFile", "File") - .WithMany() - .HasForeignKey("FileId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_file_references_files_file_id"); - - b.Navigation("File"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725183846_EnrichCloudPoolConfigure.cs b/DysonNetwork.Drive/Migrations/20250725183846_EnrichCloudPoolConfigure.cs deleted file mode 100644 index fe6463b..0000000 --- a/DysonNetwork.Drive/Migrations/20250725183846_EnrichCloudPoolConfigure.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - /// - public partial class EnrichCloudPoolConfigure : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "allow_anonymous", - table: "pools", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "allow_encryption", - table: "pools", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "no_metadata", - table: "pools", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "no_optimization", - table: "pools", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "require_privilege", - table: "pools", - type: "integer", - nullable: false, - defaultValue: 0); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "allow_anonymous", - table: "pools"); - - migrationBuilder.DropColumn( - name: "allow_encryption", - table: "pools"); - - migrationBuilder.DropColumn( - name: "no_metadata", - table: "pools"); - - migrationBuilder.DropColumn( - name: "no_optimization", - table: "pools"); - - migrationBuilder.DropColumn( - name: "require_privilege", - table: "pools"); - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725184107_NullableFileMeta.Designer.cs b/DysonNetwork.Drive/Migrations/20250725184107_NullableFileMeta.Designer.cs deleted file mode 100644 index 8f18dd3..0000000 --- a/DysonNetwork.Drive/Migrations/20250725184107_NullableFileMeta.Designer.cs +++ /dev/null @@ -1,276 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Drive; -using DysonNetwork.Drive.Storage; -using DysonNetwork.Shared.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250725184107_NullableFileMeta")] - partial class NullableFileMeta - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.Property("Id") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("uuid") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("HasCompression") - .HasColumnType("boolean") - .HasColumnName("has_compression"); - - b.Property("HasThumbnail") - .HasColumnType("boolean") - .HasColumnName("has_thumbnail"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("IsEncrypted") - .HasColumnType("boolean") - .HasColumnName("is_encrypted"); - - b.Property("IsMarkedRecycle") - .HasColumnType("boolean") - .HasColumnName("is_marked_recycle"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("PoolId") - .HasColumnType("uuid") - .HasColumnName("pool_id"); - - b.Property>("SensitiveMarks") - .HasColumnType("jsonb") - .HasColumnName("sensitive_marks"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("StorageId") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("storage_id"); - - b.Property("StorageUrl") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("storage_url"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("PoolId") - .HasDatabaseName("ix_files_pool_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("FileId") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("file_id"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("resource_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Usage") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("usage"); - - b.HasKey("Id") - .HasName("pk_file_references"); - - b.HasIndex("FileId") - .HasDatabaseName("ix_file_references_file_id"); - - b.ToTable("file_references", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.FilePool", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AllowAnonymous") - .HasColumnType("boolean") - .HasColumnName("allow_anonymous"); - - b.Property("AllowEncryption") - .HasColumnType("boolean") - .HasColumnName("allow_encryption"); - - b.Property("BillingConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("billing_config"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("NoMetadata") - .HasColumnType("boolean") - .HasColumnName("no_metadata"); - - b.Property("NoOptimization") - .HasColumnType("boolean") - .HasColumnName("no_optimization"); - - b.Property("RequirePrivilege") - .HasColumnType("integer") - .HasColumnName("require_privilege"); - - b.Property("StorageConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("storage_config"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_pools"); - - b.ToTable("pools", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Drive.Storage.FilePool", "Pool") - .WithMany() - .HasForeignKey("PoolId") - .HasConstraintName("fk_files_pools_pool_id"); - - b.Navigation("Pool"); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.HasOne("DysonNetwork.Drive.Storage.CloudFile", "File") - .WithMany() - .HasForeignKey("FileId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_file_references_files_file_id"); - - b.Navigation("File"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725184107_NullableFileMeta.cs b/DysonNetwork.Drive/Migrations/20250725184107_NullableFileMeta.cs deleted file mode 100644 index d71f8e6..0000000 --- a/DysonNetwork.Drive/Migrations/20250725184107_NullableFileMeta.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - /// - public partial class NullableFileMeta : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn>( - name: "file_meta", - table: "files", - type: "jsonb", - nullable: true, - oldClrType: typeof(Dictionary), - oldType: "jsonb"); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn>( - name: "file_meta", - table: "files", - type: "jsonb", - nullable: false, - oldClrType: typeof(Dictionary), - oldType: "jsonb", - oldNullable: true); - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250726034305_FilePoolAuthorize.Designer.cs b/DysonNetwork.Drive/Migrations/20250726034305_FilePoolAuthorize.Designer.cs deleted file mode 100644 index 0232deb..0000000 --- a/DysonNetwork.Drive/Migrations/20250726034305_FilePoolAuthorize.Designer.cs +++ /dev/null @@ -1,288 +0,0 @@ -// -using System; -using System.Collections.Generic; -using DysonNetwork.Drive; -using DysonNetwork.Drive.Storage; -using DysonNetwork.Shared.Data; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using NodaTime; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - [DbContext(typeof(AppDatabase))] - [Migration("20250726034305_FilePoolAuthorize")] - partial class FilePoolAuthorize - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "9.0.7") - .HasAnnotation("Relational:MaxIdentifierLength", 63); - - NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); - NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.Property("Id") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("uuid") - .HasColumnName("account_id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Description") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("description"); - - b.Property>("FileMeta") - .HasColumnType("jsonb") - .HasColumnName("file_meta"); - - b.Property("HasCompression") - .HasColumnType("boolean") - .HasColumnName("has_compression"); - - b.Property("HasThumbnail") - .HasColumnType("boolean") - .HasColumnName("has_thumbnail"); - - b.Property("Hash") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("hash"); - - b.Property("IsEncrypted") - .HasColumnType("boolean") - .HasColumnName("is_encrypted"); - - b.Property("IsMarkedRecycle") - .HasColumnType("boolean") - .HasColumnName("is_marked_recycle"); - - b.Property("MimeType") - .HasMaxLength(256) - .HasColumnType("character varying(256)") - .HasColumnName("mime_type"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("PoolId") - .HasColumnType("uuid") - .HasColumnName("pool_id"); - - b.Property>("SensitiveMarks") - .HasColumnType("jsonb") - .HasColumnName("sensitive_marks"); - - b.Property("Size") - .HasColumnType("bigint") - .HasColumnName("size"); - - b.Property("StorageId") - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("storage_id"); - - b.Property("StorageUrl") - .HasMaxLength(4096) - .HasColumnType("character varying(4096)") - .HasColumnName("storage_url"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("UploadedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("uploaded_at"); - - b.Property("UploadedTo") - .HasMaxLength(128) - .HasColumnType("character varying(128)") - .HasColumnName("uploaded_to"); - - b.Property>("UserMeta") - .HasColumnType("jsonb") - .HasColumnName("user_meta"); - - b.HasKey("Id") - .HasName("pk_files"); - - b.HasIndex("PoolId") - .HasDatabaseName("ix_files_pool_id"); - - b.ToTable("files", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("ExpiredAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("expired_at"); - - b.Property("FileId") - .IsRequired() - .HasMaxLength(32) - .HasColumnType("character varying(32)") - .HasColumnName("file_id"); - - b.Property("ResourceId") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("resource_id"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.Property("Usage") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("usage"); - - b.HasKey("Id") - .HasName("pk_file_references"); - - b.HasIndex("FileId") - .HasDatabaseName("ix_file_references_file_id"); - - b.ToTable("file_references", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.FilePool", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("uuid") - .HasColumnName("id"); - - b.Property("AccountId") - .HasColumnType("uuid") - .HasColumnName("account_id"); - - b.Property("AllowAnonymous") - .HasColumnType("boolean") - .HasColumnName("allow_anonymous"); - - b.Property("AllowEncryption") - .HasColumnType("boolean") - .HasColumnName("allow_encryption"); - - b.Property("BillingConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("billing_config"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("created_at"); - - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("deleted_at"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(1024) - .HasColumnType("character varying(1024)") - .HasColumnName("name"); - - b.Property("NoMetadata") - .HasColumnType("boolean") - .HasColumnName("no_metadata"); - - b.Property("NoOptimization") - .HasColumnType("boolean") - .HasColumnName("no_optimization"); - - b.Property("PublicIndexable") - .HasColumnType("boolean") - .HasColumnName("public_indexable"); - - b.Property("PublicUsable") - .HasColumnType("boolean") - .HasColumnName("public_usable"); - - b.Property("RequirePrivilege") - .HasColumnType("integer") - .HasColumnName("require_privilege"); - - b.Property("StorageConfig") - .IsRequired() - .HasColumnType("jsonb") - .HasColumnName("storage_config"); - - b.Property("UpdatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_at"); - - b.HasKey("Id") - .HasName("pk_pools"); - - b.ToTable("pools", (string)null); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFile", b => - { - b.HasOne("DysonNetwork.Drive.Storage.FilePool", "Pool") - .WithMany() - .HasForeignKey("PoolId") - .HasConstraintName("fk_files_pools_pool_id"); - - b.Navigation("Pool"); - }); - - modelBuilder.Entity("DysonNetwork.Drive.Storage.CloudFileReference", b => - { - b.HasOne("DysonNetwork.Drive.Storage.CloudFile", "File") - .WithMany() - .HasForeignKey("FileId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired() - .HasConstraintName("fk_file_references_files_file_id"); - - b.Navigation("File"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250726034305_FilePoolAuthorize.cs b/DysonNetwork.Drive/Migrations/20250726034305_FilePoolAuthorize.cs deleted file mode 100644 index cae21fc..0000000 --- a/DysonNetwork.Drive/Migrations/20250726034305_FilePoolAuthorize.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace DysonNetwork.Drive.Migrations -{ - /// - public partial class FilePoolAuthorize : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "account_id", - table: "pools", - type: "uuid", - nullable: true); - - migrationBuilder.AddColumn( - name: "public_indexable", - table: "pools", - type: "boolean", - nullable: false, - defaultValue: false); - - migrationBuilder.AddColumn( - name: "public_usable", - table: "pools", - type: "boolean", - nullable: false, - defaultValue: false); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "account_id", - table: "pools"); - - migrationBuilder.DropColumn( - name: "public_indexable", - table: "pools"); - - migrationBuilder.DropColumn( - name: "public_usable", - table: "pools"); - } - } -} diff --git a/DysonNetwork.Drive/Migrations/20250725170254_AddCloudFileEncrypt.Designer.cs b/DysonNetwork.Drive/Migrations/20250726103203_AddCloudFilePool.Designer.cs similarity index 96% rename from DysonNetwork.Drive/Migrations/20250725170254_AddCloudFileEncrypt.Designer.cs rename to DysonNetwork.Drive/Migrations/20250726103203_AddCloudFilePool.Designer.cs index bcb7d8e..b08c290 100644 --- a/DysonNetwork.Drive/Migrations/20250725170254_AddCloudFileEncrypt.Designer.cs +++ b/DysonNetwork.Drive/Migrations/20250726103203_AddCloudFilePool.Designer.cs @@ -16,8 +16,8 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace DysonNetwork.Drive.Migrations { [DbContext(typeof(AppDatabase))] - [Migration("20250725170254_AddCloudFileEncrypt")] - partial class AddCloudFileEncrypt + [Migration("20250726103203_AddCloudFilePool")] + partial class AddCloudFilePool { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -55,7 +55,6 @@ namespace DysonNetwork.Drive.Migrations .HasColumnName("description"); b.Property>("FileMeta") - .IsRequired() .HasColumnType("jsonb") .HasColumnName("file_meta"); @@ -196,6 +195,10 @@ namespace DysonNetwork.Drive.Migrations .HasColumnType("uuid") .HasColumnName("id"); + b.Property("AccountId") + .HasColumnType("uuid") + .HasColumnName("account_id"); + b.Property("BillingConfig") .IsRequired() .HasColumnType("jsonb") @@ -215,6 +218,11 @@ namespace DysonNetwork.Drive.Migrations .HasColumnType("character varying(1024)") .HasColumnName("name"); + b.Property("PolicyConfig") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("policy_config"); + b.Property("StorageConfig") .IsRequired() .HasColumnType("jsonb") diff --git a/DysonNetwork.Drive/Migrations/20250725163615_AddCloudFilePool.cs b/DysonNetwork.Drive/Migrations/20250726103203_AddCloudFilePool.cs similarity index 62% rename from DysonNetwork.Drive/Migrations/20250725163615_AddCloudFilePool.cs rename to DysonNetwork.Drive/Migrations/20250726103203_AddCloudFilePool.cs index 64ee4ab..d06532f 100644 --- a/DysonNetwork.Drive/Migrations/20250725163615_AddCloudFilePool.cs +++ b/DysonNetwork.Drive/Migrations/20250726103203_AddCloudFilePool.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using DysonNetwork.Drive.Storage; using Microsoft.EntityFrameworkCore.Migrations; using NodaTime; @@ -13,6 +14,28 @@ namespace DysonNetwork.Drive.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { + migrationBuilder.AlterColumn>( + name: "file_meta", + table: "files", + type: "jsonb", + nullable: true, + oldClrType: typeof(Dictionary), + oldType: "jsonb"); + + migrationBuilder.AddColumn( + name: "has_thumbnail", + table: "files", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.AddColumn( + name: "is_encrypted", + table: "files", + type: "boolean", + nullable: false, + defaultValue: false); + migrationBuilder.AddColumn( name: "pool_id", table: "files", @@ -27,6 +50,8 @@ namespace DysonNetwork.Drive.Migrations name = table.Column(type: "character varying(1024)", maxLength: 1024, nullable: false), storage_config = table.Column(type: "jsonb", nullable: false), billing_config = table.Column(type: "jsonb", nullable: false), + policy_config = table.Column(type: "jsonb", nullable: false), + account_id = table.Column(type: "uuid", nullable: true), created_at = table.Column(type: "timestamp with time zone", nullable: false), updated_at = table.Column(type: "timestamp with time zone", nullable: false), deleted_at = table.Column(type: "timestamp with time zone", nullable: true) @@ -63,9 +88,26 @@ namespace DysonNetwork.Drive.Migrations name: "ix_files_pool_id", table: "files"); + migrationBuilder.DropColumn( + name: "has_thumbnail", + table: "files"); + + migrationBuilder.DropColumn( + name: "is_encrypted", + table: "files"); + migrationBuilder.DropColumn( name: "pool_id", table: "files"); + + migrationBuilder.AlterColumn>( + name: "file_meta", + table: "files", + type: "jsonb", + nullable: false, + oldClrType: typeof(Dictionary), + oldType: "jsonb", + oldNullable: true); } } } diff --git a/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs b/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs index 4328b3b..44cedb3 100644 --- a/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs +++ b/DysonNetwork.Drive/Migrations/AppDatabaseModelSnapshot.cs @@ -196,14 +196,6 @@ namespace DysonNetwork.Drive.Migrations .HasColumnType("uuid") .HasColumnName("account_id"); - b.Property("AllowAnonymous") - .HasColumnType("boolean") - .HasColumnName("allow_anonymous"); - - b.Property("AllowEncryption") - .HasColumnType("boolean") - .HasColumnName("allow_encryption"); - b.Property("BillingConfig") .IsRequired() .HasColumnType("jsonb") @@ -223,25 +215,10 @@ namespace DysonNetwork.Drive.Migrations .HasColumnType("character varying(1024)") .HasColumnName("name"); - b.Property("NoMetadata") - .HasColumnType("boolean") - .HasColumnName("no_metadata"); - - b.Property("NoOptimization") - .HasColumnType("boolean") - .HasColumnName("no_optimization"); - - b.Property("PublicIndexable") - .HasColumnType("boolean") - .HasColumnName("public_indexable"); - - b.Property("PublicUsable") - .HasColumnType("boolean") - .HasColumnName("public_usable"); - - b.Property("RequirePrivilege") - .HasColumnType("integer") - .HasColumnName("require_privilege"); + b.Property("PolicyConfig") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("policy_config"); b.Property("StorageConfig") .IsRequired() diff --git a/DysonNetwork.Drive/Startup/ServiceCollectionExtensions.cs b/DysonNetwork.Drive/Startup/ServiceCollectionExtensions.cs index c848be3..0dc0459 100644 --- a/DysonNetwork.Drive/Startup/ServiceCollectionExtensions.cs +++ b/DysonNetwork.Drive/Startup/ServiceCollectionExtensions.cs @@ -138,6 +138,7 @@ public static class ServiceCollectionExtensions { services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/DysonNetwork.Drive/Storage/FileController.cs b/DysonNetwork.Drive/Storage/FileController.cs index 036f55a..c07835f 100644 --- a/DysonNetwork.Drive/Storage/FileController.cs +++ b/DysonNetwork.Drive/Storage/FileController.cs @@ -1,4 +1,5 @@ using DysonNetwork.Shared.Proto; +using Grpc.Core; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -45,7 +46,14 @@ public class FileController( return PhysicalFile(filePath, file.MimeType ?? "application/octet-stream", file.Name); } - var dest = await fs.GetRemoteStorageConfig(file.PoolId.Value); + var pool = await fs.GetPoolAsync(file.PoolId.Value); + if (pool is null) return StatusCode(StatusCodes.Status410Gone, "The pool of the file no longer exists or not accessible."); + var dest = pool.StorageConfig; + + if (!pool.PolicyConfig.AllowAnonymous) + if(HttpContext.Items["CurrentUser"] is not Account currentUser) return Unauthorized(); + // TODO: Provide ability to add access log + var fileName = string.IsNullOrWhiteSpace(file.StorageId) ? file.Id : file.StorageId; if (!original && file.HasCompression) @@ -115,7 +123,7 @@ public class FileController( [HttpGet("{id}/info")] public async Task> GetFileInfo(string id) { - var file = await db.Files.FindAsync(id); + var file = await fs.GetFileAsync(id); if (file is null) return NotFound(); return file; diff --git a/DysonNetwork.Drive/Storage/FilePool.cs b/DysonNetwork.Drive/Storage/FilePool.cs index 0054984..47c3522 100644 --- a/DysonNetwork.Drive/Storage/FilePool.cs +++ b/DysonNetwork.Drive/Storage/FilePool.cs @@ -24,19 +24,26 @@ public class BillingConfig public double CostMultiplier { get; set; } = 1.0; } -public class FilePool : ModelBase, IIdentifiedResource +public class PolicyConfig { - public Guid Id { get; set; } = Guid.NewGuid(); - [MaxLength(1024)] public string Name { get; set; } = string.Empty; - [Column(TypeName = "jsonb")] public RemoteStorageConfig StorageConfig { get; set; } = new(); - [Column(TypeName = "jsonb")] public BillingConfig BillingConfig { get; set; } = new(); public bool PublicIndexable { get; set; } = false; public bool PublicUsable { get; set; } = false; public bool NoOptimization { get; set; } = false; public bool NoMetadata { get; set; } = false; public bool AllowEncryption { get; set; } = true; public bool AllowAnonymous { get; set; } = true; - public int RequirePrivilege { get; set; } = 0; + public List? AcceptTypes { get; set; } + public long? MaxFileSize { get; set; } + public int RequirePrivilege { get; set; } = 0; +} + +public class FilePool : ModelBase, IIdentifiedResource +{ + public Guid Id { get; set; } = Guid.NewGuid(); + [MaxLength(1024)] public string Name { get; set; } = string.Empty; + [Column(TypeName = "jsonb")] public RemoteStorageConfig StorageConfig { get; set; } = new(); + [Column(TypeName = "jsonb")] public BillingConfig BillingConfig { get; set; } = new(); + [Column(TypeName = "jsonb")] public PolicyConfig PolicyConfig { get; set; } = new(); public Guid? AccountId { get; set; } diff --git a/DysonNetwork.Drive/Storage/FilePoolController.cs b/DysonNetwork.Drive/Storage/FilePoolController.cs index 515f054..5fed999 100644 --- a/DysonNetwork.Drive/Storage/FilePoolController.cs +++ b/DysonNetwork.Drive/Storage/FilePoolController.cs @@ -17,7 +17,7 @@ public class FilePoolController(AppDatabase db) : ControllerBase var accountId = Guid.Parse(currentUser.Id); var pools = await db.Pools - .Where(p => p.PublicUsable || p.AccountId == accountId) + .Where(p => p.PolicyConfig.PublicUsable || p.AccountId == accountId) .ToListAsync(); return Ok(pools); diff --git a/DysonNetwork.Drive/Storage/FileService.cs b/DysonNetwork.Drive/Storage/FileService.cs index a0b01bf..289eab7 100644 --- a/DysonNetwork.Drive/Storage/FileService.cs +++ b/DysonNetwork.Drive/Storage/FileService.cs @@ -45,6 +45,7 @@ public class FileService( var file = await db.Files .Where(f => f.Id == fileId) + .Include(f => f.Pool) .FirstOrDefaultAsync(); if (file != null) @@ -75,6 +76,7 @@ public class FileService( { var dbFiles = await db.Files .Where(f => uncachedIds.Contains(f.Id)) + .Include(f => f.Pool) .ToListAsync(); // Add to cache @@ -118,7 +120,7 @@ public class FileService( if (!string.IsNullOrWhiteSpace(encryptPassword)) { - if (!pool.AllowEncryption) throw new InvalidOperationException("Encryption is not allowed in this pool"); + if (!pool.PolicyConfig.AllowEncryption) throw new InvalidOperationException("Encryption is not allowed in this pool"); var encryptedPath = Path.Combine(Path.GetTempPath(), $"{fileId}.encrypted"); FileEncryptor.EncryptFile(ogFilePath, encryptedPath, encryptPassword); File.Delete(ogFilePath); // Delete original unencrypted @@ -136,7 +138,7 @@ public class FileService( Size = fileSize, Hash = hash, AccountId = Guid.Parse(account.Id), - IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.AllowEncryption + IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.PolicyConfig.AllowEncryption }; var existingFile = await db.Files.AsNoTracking().FirstOrDefaultAsync(f => f.Hash == hash); @@ -160,7 +162,7 @@ public class FileService( } // Extract metadata on the current thread for a faster initial response - if (!pool.NoMetadata) + if (!pool.PolicyConfig.NoMetadata) await ExtractMetadataAsync(file, ogFilePath, stream); db.Files.Add(file); @@ -302,7 +304,7 @@ public class FileService( { logger.LogInformation("Processing file {FileId} in background...", fileId); - if (!pool.NoOptimization) + if (!pool.PolicyConfig.NoOptimization) switch (contentType.Split('/')[0]) { case "image" when !AnimatedImageTypes.Contains(contentType): diff --git a/DysonNetwork.Drive/Storage/TusService.cs b/DysonNetwork.Drive/Storage/TusService.cs index 5475e76..93fd74e 100644 --- a/DysonNetwork.Drive/Storage/TusService.cs +++ b/DysonNetwork.Drive/Storage/TusService.cs @@ -1,12 +1,14 @@ using System.Net; using System.Text; using System.Text.Json; +using DysonNetwork.Shared.Auth; using DysonNetwork.Shared.Proto; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using tusdotnet.Interfaces; using tusdotnet.Models; using tusdotnet.Models.Configuration; +using tusdotnet.Stores; namespace DysonNetwork.Drive.Storage; @@ -29,25 +31,63 @@ public abstract class TusService } var httpContext = eventContext.HttpContext; - if (httpContext.Items["CurrentUser"] is not Account user) + if (httpContext.Items["CurrentUser"] is not Account currentUser) { eventContext.FailRequest(HttpStatusCode.Unauthorized); return; } - if (!user.IsSuperuser) + if (eventContext.Intent != IntentType.CreateFile) return; + + using var scope = httpContext.RequestServices.CreateScope(); + + if (!currentUser.IsSuperuser) { - using var scope = httpContext.RequestServices.CreateScope(); var pm = scope.ServiceProvider.GetRequiredService(); var allowed = await pm.HasPermissionAsync(new HasPermissionRequest - { Actor = $"user:{user.Id}", Area = "global", Key = "files.create" }); + { Actor = $"user:{currentUser.Id}", Area = "global", Key = "files.create" }); if (!allowed.HasPermission) eventContext.FailRequest(HttpStatusCode.Forbidden); } var filePool = httpContext.Request.Headers["X-FilePool"].FirstOrDefault(); - if (!string.IsNullOrEmpty(filePool) && !Guid.TryParse(filePool, out _)) + if (string.IsNullOrEmpty(filePool)) filePool = configuration["Storage:PreferredRemote"]; + if (!Guid.TryParse(filePool, out _)) + { eventContext.FailRequest(HttpStatusCode.BadRequest, "Invalid file pool id"); + return; + } + + var fs = scope.ServiceProvider.GetRequiredService(); + var pool = await fs.GetPoolAsync(Guid.Parse(filePool!)); + if (pool is null) + { + eventContext.FailRequest(HttpStatusCode.BadRequest, "Pool not found"); + return; + } + + if (pool.PolicyConfig.RequirePrivilege > 0) + { + if (currentUser.PerkSubscription is null) + { + eventContext.FailRequest( + HttpStatusCode.Forbidden, + $"You need to have join the Stellar Program tier {pool.PolicyConfig.RequirePrivilege} to use this pool" + ); + return; + } + + var privilege = + PerkSubscriptionPrivilege.GetPrivilegeFromIdentifier(currentUser.PerkSubscription.Identifier); + if (privilege < pool.PolicyConfig.RequirePrivilege) + { + eventContext.FailRequest( + HttpStatusCode.Forbidden, + $"You need to have join the Stellar Program tier {pool.PolicyConfig.RequirePrivilege} to use this pool" + ); + return; + } + } }, OnFileCompleteAsync = async eventContext => { @@ -72,25 +112,101 @@ public abstract class TusService if (string.IsNullOrEmpty(filePool)) filePool = configuration["Storage:PreferredRemote"]; - var fileService = services.GetRequiredService(); - var info = await fileService.ProcessNewFileAsync( - user, - file.Id, - filePool, - fileStream, - fileName, - contentType, - encryptPassword - ); + try + { + var fileService = services.GetRequiredService(); + var info = await fileService.ProcessNewFileAsync( + user, + file.Id, + filePool!, + fileStream, + fileName, + contentType, + encryptPassword + ); - using var finalScope = eventContext.HttpContext.RequestServices.CreateScope(); - var jsonOptions = finalScope.ServiceProvider.GetRequiredService>().Value - .JsonSerializerOptions; - var infoJson = JsonSerializer.Serialize(info, jsonOptions); - eventContext.HttpContext.Response.Headers.Append("X-FileInfo", infoJson); + using var finalScope = eventContext.HttpContext.RequestServices.CreateScope(); + var jsonOptions = finalScope.ServiceProvider.GetRequiredService>().Value + .JsonSerializerOptions; + var infoJson = JsonSerializer.Serialize(info, jsonOptions); + eventContext.HttpContext.Response.Headers.Append("X-FileInfo", infoJson); + } + catch (Exception ex) + { + eventContext.HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; + await eventContext.HttpContext.Response.WriteAsync(ex.Message); + if (eventContext.Store is TusDiskStore disk) + await disk.DeleteFileAsync(file.Id, eventContext.CancellationToken); + } + finally + { + // Dispose the stream after all processing is complete + await fileStream.DisposeAsync(); + } + }, + OnBeforeCreateAsync = async eventContext => + { + var filePool = eventContext.HttpContext.Request.Headers["X-FilePool"].FirstOrDefault(); + if (string.IsNullOrEmpty(filePool)) filePool = configuration["Storage:PreferredRemote"]; + if (!Guid.TryParse(filePool, out _)) + { + eventContext.FailRequest(HttpStatusCode.BadRequest, "Invalid file pool id"); + return; + } - // Dispose the stream after all processing is complete - await fileStream.DisposeAsync(); + var metadata = eventContext.Metadata; + var contentType = metadata.TryGetValue("content-type", out var ct) ? ct.GetString(Encoding.UTF8) : null; + + var scope = eventContext.HttpContext.RequestServices.CreateScope(); + + var rejected = false; + + var fs = scope.ServiceProvider.GetRequiredService(); + var pool = await fs.GetPoolAsync(Guid.Parse(filePool!)); + if (pool is null) + { + eventContext.FailRequest(HttpStatusCode.BadRequest, "Pool not found"); + rejected = true; + } + + var logger = scope.ServiceProvider.GetRequiredService>(); + + // Do the policy check + var policy = pool!.PolicyConfig; + if (!rejected && policy.AcceptTypes is not null) + { + if (contentType is null) + { + eventContext.FailRequest( + HttpStatusCode.BadRequest, + "Content type is required by the pool's policy" + ); + rejected = true; + } + else if (!policy.AcceptTypes.Contains(contentType)) + { + eventContext.FailRequest( + HttpStatusCode.Forbidden, + $"Content type {contentType} is not allowed by the pool's policy" + ); + rejected = true; + } + } + + if (!rejected && policy.MaxFileSize is not null) + { + if (eventContext.UploadLength > policy.MaxFileSize) + { + eventContext.FailRequest( + HttpStatusCode.Forbidden, + $"File size {eventContext.UploadLength} is larger than the pool's maximum file size {policy.MaxFileSize}" + ); + rejected = true; + } + } + + if (rejected) + logger.LogInformation("File rejected #{FileId}", eventContext.FileId); }, OnCreateCompleteAsync = eventContext => { diff --git a/DysonNetwork.Shared/Auth/PerkSubscriptionPrivilege.cs b/DysonNetwork.Shared/Auth/PerkSubscriptionPrivilege.cs new file mode 100644 index 0000000..74f40ea --- /dev/null +++ b/DysonNetwork.Shared/Auth/PerkSubscriptionPrivilege.cs @@ -0,0 +1,16 @@ +namespace DysonNetwork.Shared.Auth; + +public static class PerkSubscriptionPrivilege +{ + public static int GetPrivilegeFromIdentifier(string identifier) + { + // Reference from the DysonNetwork.Pass + return identifier switch + { + "solian.stellar.primary" => 1, + "solian.stellar.nova" => 2, + "solian.stellar.supernova" => 3, + _ => 0 + }; + } +} \ No newline at end of file diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index d087cad..f6e0c99 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -41,6 +41,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -65,6 +66,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded