forked from xiongyuxing/tiku-backend.net
453 lines
26 KiB
C#
453 lines
26 KiB
C#
using System;
|
|
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
#nullable disable
|
|
|
|
namespace Tiku.Infrastructure.Persistence.Migrations
|
|
{
|
|
/// <inheritdoc />
|
|
public partial class AddContentPlatformOperationsPersistence : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
migrationBuilder.AddColumn<string>(
|
|
name: "security_scan_provider",
|
|
table: "content_assets",
|
|
type: "character varying(100)",
|
|
maxLength: 100,
|
|
nullable: true);
|
|
|
|
migrationBuilder.AddColumn<string>(
|
|
name: "security_scan_status",
|
|
table: "content_assets",
|
|
type: "character varying(32)",
|
|
maxLength: 32,
|
|
nullable: false,
|
|
defaultValue: "not_required");
|
|
|
|
migrationBuilder.AddColumn<JsonElement>(
|
|
name: "security_scan_summary",
|
|
table: "content_assets",
|
|
type: "jsonb",
|
|
nullable: false,
|
|
defaultValueSql: "'{}'::jsonb");
|
|
|
|
migrationBuilder.AddColumn<DateTimeOffset>(
|
|
name: "security_scanned_at",
|
|
table: "content_assets",
|
|
type: "timestamp with time zone",
|
|
nullable: true);
|
|
|
|
migrationBuilder.CreateTable(
|
|
name: "ai_recommendation_reports",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
user_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
region_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
provider = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
model = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
|
prompt_version = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
input_payload = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
context_payload = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
result_payload = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
error_message = table.Column<string>(type: "text", nullable: true),
|
|
generated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
|
tenant_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
|
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_ai_recommendation_reports", x => x.id);
|
|
table.UniqueConstraint("ak_ai_recommendation_reports_tenant_id_id", x => new { x.tenant_id, x.id });
|
|
table.ForeignKey(
|
|
name: "fk_ai_recommendation_reports_regions_tenant_id_region_id",
|
|
columns: x => new { x.tenant_id, x.region_id },
|
|
principalTable: "regions",
|
|
principalColumns: new[] { "tenant_id", "id" },
|
|
onDelete: ReferentialAction.Restrict);
|
|
table.ForeignKey(
|
|
name: "fk_ai_recommendation_reports_tenants_tenant_id",
|
|
column: x => x.tenant_id,
|
|
principalTable: "tenants",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "fk_ai_recommendation_reports_users_user_id",
|
|
column: x => x.user_id,
|
|
principalTable: "users",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
});
|
|
|
|
migrationBuilder.CreateTable(
|
|
name: "content_asset_access_events",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
tenant_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
asset_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
user_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
actor_role = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
access_type = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
visibility = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
asset_type = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
storage_provider = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
|
disposition = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
|
expires_in_seconds = table.Column<int>(type: "integer", nullable: true),
|
|
signature_mode = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
|
result = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
deny_code = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
|
ip_address = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
|
user_agent = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
|
metadata = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_content_asset_access_events", x => x.id);
|
|
table.UniqueConstraint("ak_content_asset_access_events_tenant_id_id", x => new { x.tenant_id, x.id });
|
|
table.CheckConstraint("ck_content_asset_access_events_expiry", "expires_in_seconds is null or expires_in_seconds > 0");
|
|
table.ForeignKey(
|
|
name: "fk_content_asset_access_events_content_assets_tenant_id_asset_~",
|
|
columns: x => new { x.tenant_id, x.asset_id },
|
|
principalTable: "content_assets",
|
|
principalColumns: new[] { "tenant_id", "id" },
|
|
onDelete: ReferentialAction.Restrict);
|
|
table.ForeignKey(
|
|
name: "fk_content_asset_access_events_tenants_tenant_id",
|
|
column: x => x.tenant_id,
|
|
principalTable: "tenants",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "fk_content_asset_access_events_users_user_id",
|
|
column: x => x.user_id,
|
|
principalTable: "users",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.SetNull);
|
|
});
|
|
|
|
migrationBuilder.CreateTable(
|
|
name: "content_asset_security_scan_events",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
tenant_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
asset_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
provider = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
|
scan_status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
risk_level = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
issue_codes = table.Column<string[]>(type: "text[]", nullable: false, defaultValueSql: "'{}'::text[]"),
|
|
details = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_content_asset_security_scan_events", x => x.id);
|
|
table.UniqueConstraint("ak_content_asset_security_scan_events_tenant_id_id", x => new { x.tenant_id, x.id });
|
|
table.ForeignKey(
|
|
name: "fk_content_asset_security_scan_events_content_assets_tenant_id~",
|
|
columns: x => new { x.tenant_id, x.asset_id },
|
|
principalTable: "content_assets",
|
|
principalColumns: new[] { "tenant_id", "id" },
|
|
onDelete: ReferentialAction.Restrict);
|
|
table.ForeignKey(
|
|
name: "fk_content_asset_security_scan_events_tenants_tenant_id",
|
|
column: x => x.tenant_id,
|
|
principalTable: "tenants",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
});
|
|
|
|
migrationBuilder.CreateTable(
|
|
name: "question_bank_grants",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
source_question_bank_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
created_by = table.Column<Guid>(type: "uuid", nullable: true),
|
|
updated_by = table.Column<Guid>(type: "uuid", nullable: true),
|
|
grant_scope = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
allowed_plan_codes = table.Column<string[]>(type: "text[]", nullable: false, defaultValueSql: "'{}'::text[]"),
|
|
allowed_tenant_ids = table.Column<Guid[]>(type: "uuid[]", nullable: false, defaultValueSql: "'{}'::uuid[]"),
|
|
allowed_region_ids = table.Column<Guid[]>(type: "uuid[]", nullable: false, defaultValueSql: "'{}'::uuid[]"),
|
|
allowed_subject_ids = table.Column<Guid[]>(type: "uuid[]", nullable: false, defaultValueSql: "'{}'::uuid[]"),
|
|
status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
starts_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
|
expires_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
|
metadata = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
|
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_question_bank_grants", x => x.id);
|
|
table.ForeignKey(
|
|
name: "fk_question_bank_grants_question_banks_source_question_bank_id",
|
|
column: x => x.source_question_bank_id,
|
|
principalTable: "question_banks",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "fk_question_bank_grants_users_created_by",
|
|
column: x => x.created_by,
|
|
principalTable: "users",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.SetNull);
|
|
table.ForeignKey(
|
|
name: "fk_question_bank_grants_users_updated_by",
|
|
column: x => x.updated_by,
|
|
principalTable: "users",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.SetNull);
|
|
});
|
|
|
|
migrationBuilder.CreateTable(
|
|
name: "tenant_question_bank_adoptions",
|
|
columns: table => new
|
|
{
|
|
id = table.Column<Guid>(type: "uuid", nullable: false, defaultValueSql: "gen_random_uuid()"),
|
|
source_question_bank_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
grant_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
target_question_bank_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
target_entry_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
target_collection_id = table.Column<Guid>(type: "uuid", nullable: true),
|
|
created_by = table.Column<Guid>(type: "uuid", nullable: true),
|
|
updated_by = table.Column<Guid>(type: "uuid", nullable: true),
|
|
adoption_mode = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
sync_status = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
|
source_snapshot = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
copied_question_count = table.Column<int>(type: "integer", nullable: false),
|
|
metadata = table.Column<JsonElement>(type: "jsonb", nullable: false, defaultValueSql: "'{}'::jsonb"),
|
|
last_synced_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
|
|
tenant_id = table.Column<Guid>(type: "uuid", nullable: false),
|
|
created_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()"),
|
|
updated_at = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false, defaultValueSql: "now()")
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("pk_tenant_question_bank_adoptions", x => x.id);
|
|
table.UniqueConstraint("ak_tenant_question_bank_adoptions_tenant_id_id", x => new { x.tenant_id, x.id });
|
|
table.CheckConstraint("ck_tenant_question_bank_adoptions_copied_count", "copied_question_count >= 0");
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_content_entries_tenant_id_ta~",
|
|
columns: x => new { x.tenant_id, x.target_entry_id },
|
|
principalTable: "content_entries",
|
|
principalColumns: new[] { "tenant_id", "id" },
|
|
onDelete: ReferentialAction.Restrict);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_question_bank_grants_grant_id",
|
|
column: x => x.grant_id,
|
|
principalTable: "question_bank_grants",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.SetNull);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_question_banks_source_questi~",
|
|
column: x => x.source_question_bank_id,
|
|
principalTable: "question_banks",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_question_banks_tenant_id_tar~",
|
|
columns: x => new { x.tenant_id, x.target_question_bank_id },
|
|
principalTable: "question_banks",
|
|
principalColumns: new[] { "tenant_id", "id" },
|
|
onDelete: ReferentialAction.Restrict);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_question_collections_tenant_~",
|
|
columns: x => new { x.tenant_id, x.target_collection_id },
|
|
principalTable: "question_collections",
|
|
principalColumns: new[] { "tenant_id", "id" },
|
|
onDelete: ReferentialAction.Restrict);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_tenants_tenant_id",
|
|
column: x => x.tenant_id,
|
|
principalTable: "tenants",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_users_created_by",
|
|
column: x => x.created_by,
|
|
principalTable: "users",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.SetNull);
|
|
table.ForeignKey(
|
|
name: "fk_tenant_question_bank_adoptions_users_updated_by",
|
|
column: x => x.updated_by,
|
|
principalTable: "users",
|
|
principalColumn: "id",
|
|
onDelete: ReferentialAction.SetNull);
|
|
});
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_assets_tenant_id_security_scan_status_upload_status~",
|
|
table: "content_assets",
|
|
columns: new[] { "tenant_id", "security_scan_status", "upload_status", "status", "updated_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_ai_recommendation_reports_tenant_id_region_id_created_at",
|
|
table: "ai_recommendation_reports",
|
|
columns: new[] { "tenant_id", "region_id", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_ai_recommendation_reports_tenant_id_user_id_created_at",
|
|
table: "ai_recommendation_reports",
|
|
columns: new[] { "tenant_id", "user_id", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_ai_recommendation_reports_user_id",
|
|
table: "ai_recommendation_reports",
|
|
column: "user_id");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_asset_access_events_tenant_id_access_type_result_cr~",
|
|
table: "content_asset_access_events",
|
|
columns: new[] { "tenant_id", "access_type", "result", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_asset_access_events_tenant_id_asset_id_created_at",
|
|
table: "content_asset_access_events",
|
|
columns: new[] { "tenant_id", "asset_id", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_asset_access_events_tenant_id_user_id_created_at",
|
|
table: "content_asset_access_events",
|
|
columns: new[] { "tenant_id", "user_id", "created_at" },
|
|
filter: "user_id is not null");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_asset_access_events_user_id",
|
|
table: "content_asset_access_events",
|
|
column: "user_id");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_asset_security_scan_events_tenant_id_asset_id_creat~",
|
|
table: "content_asset_security_scan_events",
|
|
columns: new[] { "tenant_id", "asset_id", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_content_asset_security_scan_events_tenant_id_scan_status_ri~",
|
|
table: "content_asset_security_scan_events",
|
|
columns: new[] { "tenant_id", "scan_status", "risk_level", "created_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_question_bank_grants_allowed_plan_codes",
|
|
table: "question_bank_grants",
|
|
column: "allowed_plan_codes")
|
|
.Annotation("Npgsql:IndexMethod", "gin");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_question_bank_grants_allowed_tenant_ids",
|
|
table: "question_bank_grants",
|
|
column: "allowed_tenant_ids")
|
|
.Annotation("Npgsql:IndexMethod", "gin");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_question_bank_grants_created_by",
|
|
table: "question_bank_grants",
|
|
column: "created_by");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_question_bank_grants_source_question_bank_id_status_starts_~",
|
|
table: "question_bank_grants",
|
|
columns: new[] { "source_question_bank_id", "status", "starts_at", "expires_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_question_bank_grants_updated_by",
|
|
table: "question_bank_grants",
|
|
column: "updated_by");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_created_by",
|
|
table: "tenant_question_bank_adoptions",
|
|
column: "created_by");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_grant_id",
|
|
table: "tenant_question_bank_adoptions",
|
|
column: "grant_id");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_source_question_bank_id",
|
|
table: "tenant_question_bank_adoptions",
|
|
column: "source_question_bank_id");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_tenant_id_source_question_ba~",
|
|
table: "tenant_question_bank_adoptions",
|
|
columns: new[] { "tenant_id", "source_question_bank_id" },
|
|
unique: true);
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_tenant_id_status_updated_at",
|
|
table: "tenant_question_bank_adoptions",
|
|
columns: new[] { "tenant_id", "status", "updated_at" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_tenant_id_target_collection_~",
|
|
table: "tenant_question_bank_adoptions",
|
|
columns: new[] { "tenant_id", "target_collection_id" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_tenant_id_target_entry_id",
|
|
table: "tenant_question_bank_adoptions",
|
|
columns: new[] { "tenant_id", "target_entry_id" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_tenant_id_target_question_ba~",
|
|
table: "tenant_question_bank_adoptions",
|
|
columns: new[] { "tenant_id", "target_question_bank_id" });
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "ix_tenant_question_bank_adoptions_updated_by",
|
|
table: "tenant_question_bank_adoptions",
|
|
column: "updated_by");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
migrationBuilder.DropTable(
|
|
name: "ai_recommendation_reports");
|
|
|
|
migrationBuilder.DropTable(
|
|
name: "content_asset_access_events");
|
|
|
|
migrationBuilder.DropTable(
|
|
name: "content_asset_security_scan_events");
|
|
|
|
migrationBuilder.DropTable(
|
|
name: "tenant_question_bank_adoptions");
|
|
|
|
migrationBuilder.DropTable(
|
|
name: "question_bank_grants");
|
|
|
|
migrationBuilder.DropIndex(
|
|
name: "ix_content_assets_tenant_id_security_scan_status_upload_status~",
|
|
table: "content_assets");
|
|
|
|
migrationBuilder.DropColumn(
|
|
name: "security_scan_provider",
|
|
table: "content_assets");
|
|
|
|
migrationBuilder.DropColumn(
|
|
name: "security_scan_status",
|
|
table: "content_assets");
|
|
|
|
migrationBuilder.DropColumn(
|
|
name: "security_scan_summary",
|
|
table: "content_assets");
|
|
|
|
migrationBuilder.DropColumn(
|
|
name: "security_scanned_at",
|
|
table: "content_assets");
|
|
}
|
|
}
|
|
}
|