diff --git a/AGENTS.md b/AGENTS.md index f4225826..f0cf142c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -343,6 +343,11 @@ in *drizzle/* directory. This compares *src/schema.ts* with the current database state and generates a SQL migration file. +Schema migrations MUST be generated with `pnpm migrate:generate`. Do not +hand-write schema migration SQL files; use a generated migration and then +edit only when a custom data backfill or other non-schema operation is +needed. + Optional flags: - `--name `: Custom migration name diff --git a/CHANGES.md b/CHANGES.md index 06a246bb..1d7788f8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,8 +6,8 @@ Version 0.9.0 To be released. - - Added FEP-044f quote authorization and policy support on top of the - Mastodon-compatible quote APIs. [[#457]] + - Added [FEP-044f] quote authorization and policy support on top of the + Mastodon-compatible quote APIs. [[#457], [#459]] - Added persistent quote states for `pending`, `accepted`, `rejected`, `revoked`, and `unauthorized` quotes, plus quote target and @@ -15,7 +15,9 @@ To be released. - Hollo now enforces quote policy, quote target visibility, block relationships, follower-only quote permissions, and direct-message mention requirements when creating a quote through - `POST /api/v1/statuses`. + `POST /api/v1/statuses`. Remote public posts without an advertised + FEP-044f quote policy are treated as legacy quote targets and can be + quoted without waiting for quote authorization. - Implemented `quote_approval_policy` handling on status creation and editing, and added `PUT /api/v1/statuses/:id/interaction_policy` for updating a status' quote policy after publication. @@ -94,8 +96,10 @@ To be released. - Upgraded Fedify to 2.2.0. +[FEP-044f]: https://w3id.org/fep/044f [#457]: https://github.com/fedify-dev/hollo/pull/457 [#458]: https://github.com/fedify-dev/hollo/pull/458 +[#459]: https://github.com/fedify-dev/hollo/pull/459 Version 0.8.1 diff --git a/drizzle/0087_quote_authorization_requirement.sql b/drizzle/0087_quote_authorization_requirement.sql new file mode 100644 index 00000000..795f993d --- /dev/null +++ b/drizzle/0087_quote_authorization_requirement.sql @@ -0,0 +1,13 @@ +ALTER TABLE "posts" +ALTER COLUMN "quote_approval_policy" DROP NOT NULL;--> statement-breakpoint +-- Migration 0086 defaulted every existing post to 'public', so cached remote +-- legacy posts and cached remote FEP-044f public posts are indistinguishable +-- here. Prefer preserving legacy interoperability for old cached remote +-- posts; limited FEP policies such as 'followers' and 'nobody' remain intact. +UPDATE "posts" +SET "quote_approval_policy" = NULL +WHERE "quote_approval_policy" = 'public' +AND "actor_id" NOT IN ( + SELECT "id" + FROM "account_owners" +); diff --git a/drizzle/meta/0087_snapshot.json b/drizzle/meta/0087_snapshot.json new file mode 100644 index 00000000..d9536d24 --- /dev/null +++ b/drizzle/meta/0087_snapshot.json @@ -0,0 +1,4440 @@ +{ + "id": "111f8bf6-721d-40fc-a563-fb07818be081", + "prevId": "9cd821ad-3da6-465b-9b7f-1589a7952b92", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.access_grants": { + "name": "access_grants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_in": { + "name": "expires_in", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "redirect_uri": { + "name": "redirect_uri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "scope[]", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "code_challenge": { + "name": "code_challenge", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "code_challenge_method": { + "name": "code_challenge_method", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "application_id": { + "name": "application_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "resource_owner_id": { + "name": "resource_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "revoked": { + "name": "revoked", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "access_grants_resource_owner_id_index": { + "name": "access_grants_resource_owner_id_index", + "columns": [ + { + "expression": "resource_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "access_grants_application_id_applications_id_fk": { + "name": "access_grants_application_id_applications_id_fk", + "tableFrom": "access_grants", + "tableTo": "applications", + "columnsFrom": [ + "application_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "access_grants_resource_owner_id_account_owners_id_fk": { + "name": "access_grants_resource_owner_id_account_owners_id_fk", + "tableFrom": "access_grants", + "tableTo": "account_owners", + "columnsFrom": [ + "resource_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "access_grants_code_unique": { + "name": "access_grants_code_unique", + "nullsNotDistinct": false, + "columns": [ + "code" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.access_tokens": { + "name": "access_tokens", + "schema": "", + "columns": { + "code": { + "name": "code", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "application_id": { + "name": "application_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "grant_type": { + "name": "grant_type", + "type": "grant_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'authorization_code'" + }, + "scopes": { + "name": "scopes", + "type": "scope[]", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": { + "access_tokens_application_id_applications_id_fk": { + "name": "access_tokens_application_id_applications_id_fk", + "tableFrom": "access_tokens", + "tableTo": "applications", + "columnsFrom": [ + "application_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "access_tokens_account_owner_id_account_owners_id_fk": { + "name": "access_tokens_account_owner_id_account_owners_id_fk", + "tableFrom": "access_tokens", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account_owners": { + "name": "account_owners", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rsa_private_key_jwk": { + "name": "rsa_private_key_jwk", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "rsa_public_key_jwk": { + "name": "rsa_public_key_jwk", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "ed25519_private_key_jwk": { + "name": "ed25519_private_key_jwk", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "ed25519_public_key_jwk": { + "name": "ed25519_public_key_jwk", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "fields": { + "name": "fields", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'::json" + }, + "bio": { + "name": "bio", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "followed_tags": { + "name": "followed_tags", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "visibility": { + "name": "visibility", + "type": "post_visibility", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "language": { + "name": "language", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'en'" + }, + "discoverable": { + "name": "discoverable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "expand_spoilers": { + "name": "expand_spoilers", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "theme_color": { + "name": "theme_color", + "type": "theme_color", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "account_owners_id_accounts_id_fk": { + "name": "account_owners_id_accounts_id_fk", + "tableFrom": "account_owners", + "tableTo": "accounts", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "account_owners_handle_unique": { + "name": "account_owners_handle_unique", + "nullsNotDistinct": false, + "columns": [ + "handle" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.accounts": { + "name": "accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "iri": { + "name": "iri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "account_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(100)", + "primaryKey": false, + "notNull": true + }, + "handle": { + "name": "handle", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bio_html": { + "name": "bio_html", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "protected": { + "name": "protected", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_url": { + "name": "cover_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_url": { + "name": "inbox_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "followers_url": { + "name": "followers_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "shared_inbox_url": { + "name": "shared_inbox_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "featured_url": { + "name": "featured_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "following_count": { + "name": "following_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "followers_count": { + "name": "followers_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "posts_count": { + "name": "posts_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "field_htmls": { + "name": "field_htmls", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'::json" + }, + "emojis": { + "name": "emojis", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "successor_id": { + "name": "successor_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "aliases": { + "name": "aliases", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "(ARRAY[]::text[])" + }, + "instance_host": { + "name": "instance_host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "published": { + "name": "published", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "updated": { + "name": "updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "fetched": { + "name": "fetched", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "accounts_successor_id_accounts_id_fk": { + "name": "accounts_successor_id_accounts_id_fk", + "tableFrom": "accounts", + "tableTo": "accounts", + "columnsFrom": [ + "successor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "accounts_instance_host_instances_host_fk": { + "name": "accounts_instance_host_instances_host_fk", + "tableFrom": "accounts", + "tableTo": "instances", + "columnsFrom": [ + "instance_host" + ], + "columnsTo": [ + "host" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "accounts_iri_unique": { + "name": "accounts_iri_unique", + "nullsNotDistinct": false, + "columns": [ + "iri" + ] + }, + "accounts_handle_unique": { + "name": "accounts_handle_unique", + "nullsNotDistinct": false, + "columns": [ + "handle" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.applications": { + "name": "applications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "scope[]", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "confidential": { + "name": "confidential", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "applications_client_id_unique": { + "name": "applications_client_id_unique", + "nullsNotDistinct": false, + "columns": [ + "client_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.blocks": { + "name": "blocks", + "schema": "", + "columns": { + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "blocked_account_id": { + "name": "blocked_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "blocks_account_id_index": { + "name": "blocks_account_id_index", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "blocks_blocked_account_id_index": { + "name": "blocks_blocked_account_id_index", + "columns": [ + { + "expression": "blocked_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "blocks_account_id_accounts_id_fk": { + "name": "blocks_account_id_accounts_id_fk", + "tableFrom": "blocks", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "blocks_blocked_account_id_accounts_id_fk": { + "name": "blocks_blocked_account_id_accounts_id_fk", + "tableFrom": "blocks", + "tableTo": "accounts", + "columnsFrom": [ + "blocked_account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "blocks_account_id_blocked_account_id_pk": { + "name": "blocks_account_id_blocked_account_id_pk", + "columns": [ + "account_id", + "blocked_account_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.bookmarks": { + "name": "bookmarks", + "schema": "", + "columns": { + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "bookmarks_post_id_account_owner_id_index": { + "name": "bookmarks_post_id_account_owner_id_index", + "columns": [ + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "bookmarks_post_id_posts_id_fk": { + "name": "bookmarks_post_id_posts_id_fk", + "tableFrom": "bookmarks", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "bookmarks_account_owner_id_account_owners_id_fk": { + "name": "bookmarks_account_owner_id_account_owners_id_fk", + "tableFrom": "bookmarks", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "bookmarks_post_id_account_owner_id_pk": { + "name": "bookmarks_post_id_account_owner_id_pk", + "columns": [ + "post_id", + "account_owner_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cleanup_job_items": { + "name": "cleanup_job_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "cleanup_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "cleanup_job_items_job_id_status_index": { + "name": "cleanup_job_items_job_id_status_index", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "cleanup_job_items_job_id_cleanup_jobs_id_fk": { + "name": "cleanup_job_items_job_id_cleanup_jobs_id_fk", + "tableFrom": "cleanup_job_items", + "tableTo": "cleanup_jobs", + "columnsFrom": [ + "job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cleanup_jobs": { + "name": "cleanup_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "category": { + "name": "category", + "type": "cleanup_job_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "cleanup_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "total_items": { + "name": "total_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processed_items": { + "name": "processed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "successful_items": { + "name": "successful_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "failed_items": { + "name": "failed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "cleanup_jobs_status_created_index": { + "name": "cleanup_jobs_status_created_index", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credentials": { + "name": "credentials", + "schema": "", + "columns": { + "email": { + "name": "email", + "type": "varchar(254)", + "primaryKey": true, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_emojis": { + "name": "custom_emojis", + "schema": "", + "columns": { + "shortcode": { + "name": "shortcode", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.featured_tags": { + "name": "featured_tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "featured_tags_account_owner_id_account_owners_id_fk": { + "name": "featured_tags_account_owner_id_account_owners_id_fk", + "tableFrom": "featured_tags", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "featured_tags_account_owner_id_name_unique": { + "name": "featured_tags_account_owner_id_name_unique", + "nullsNotDistinct": false, + "columns": [ + "account_owner_id", + "name" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.follows": { + "name": "follows", + "schema": "", + "columns": { + "iri": { + "name": "iri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "following_id": { + "name": "following_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "follower_id": { + "name": "follower_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "shares": { + "name": "shares", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "notify": { + "name": "notify", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "languages": { + "name": "languages", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "approved": { + "name": "approved", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "follows_following_id_approved_index": { + "name": "follows_following_id_approved_index", + "columns": [ + { + "expression": "following_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "approved", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"follows\".\"approved\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "follows_follower_id_following_id_approved_index": { + "name": "follows_follower_id_following_id_approved_index", + "columns": [ + { + "expression": "follower_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "following_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"follows\".\"approved\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "follows_following_id_created_index": { + "name": "follows_following_id_created_index", + "columns": [ + { + "expression": "following_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "follows_following_id_accounts_id_fk": { + "name": "follows_following_id_accounts_id_fk", + "tableFrom": "follows", + "tableTo": "accounts", + "columnsFrom": [ + "following_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "follows_follower_id_accounts_id_fk": { + "name": "follows_follower_id_accounts_id_fk", + "tableFrom": "follows", + "tableTo": "accounts", + "columnsFrom": [ + "follower_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "follows_following_id_follower_id_pk": { + "name": "follows_following_id_follower_id_pk", + "columns": [ + "following_id", + "follower_id" + ] + } + }, + "uniqueConstraints": { + "follows_iri_unique": { + "name": "follows_iri_unique", + "nullsNotDistinct": false, + "columns": [ + "iri" + ] + } + }, + "policies": {}, + "checkConstraints": { + "ck_follows_self": { + "name": "ck_follows_self", + "value": "\"follows\".\"following_id\" != \"follows\".\"follower_id\"" + } + }, + "isRLSEnabled": false + }, + "public.import_job_items": { + "name": "import_job_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "import_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "import_job_items_job_id_status_index": { + "name": "import_job_items_job_id_status_index", + "columns": [ + { + "expression": "job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "import_job_items_job_id_import_jobs_id_fk": { + "name": "import_job_items_job_id_import_jobs_id_fk", + "tableFrom": "import_job_items", + "tableTo": "import_jobs", + "columnsFrom": [ + "job_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.import_jobs": { + "name": "import_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "import_job_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "import_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "total_items": { + "name": "total_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processed_items": { + "name": "processed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "successful_items": { + "name": "successful_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "failed_items": { + "name": "failed_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "import_jobs_account_owner_id_status_index": { + "name": "import_jobs_account_owner_id_status_index", + "columns": [ + { + "expression": "account_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "import_jobs_status_created_index": { + "name": "import_jobs_status_created_index", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "import_jobs_account_owner_id_account_owners_id_fk": { + "name": "import_jobs_account_owner_id_account_owners_id_fk", + "tableFrom": "import_jobs", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.instances": { + "name": "instances", + "schema": "", + "columns": { + "host": { + "name": "host", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "software": { + "name": "software", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_version": { + "name": "software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.likes": { + "name": "likes", + "schema": "", + "columns": { + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "likes_account_id_post_id_index": { + "name": "likes_account_id_post_id_index", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "likes_created_index": { + "name": "likes_created_index", + "columns": [ + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "likes_post_id_posts_id_fk": { + "name": "likes_post_id_posts_id_fk", + "tableFrom": "likes", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "likes_account_id_accounts_id_fk": { + "name": "likes_account_id_accounts_id_fk", + "tableFrom": "likes", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "likes_post_id_account_id_pk": { + "name": "likes_post_id_account_id_pk", + "columns": [ + "post_id", + "account_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.list_members": { + "name": "list_members", + "schema": "", + "columns": { + "list_id": { + "name": "list_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": { + "list_members_list_id_lists_id_fk": { + "name": "list_members_list_id_lists_id_fk", + "tableFrom": "list_members", + "tableTo": "lists", + "columnsFrom": [ + "list_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "list_members_account_id_accounts_id_fk": { + "name": "list_members_account_id_accounts_id_fk", + "tableFrom": "list_members", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "list_members_list_id_account_id_pk": { + "name": "list_members_list_id_account_id_pk", + "columns": [ + "list_id", + "account_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.list_posts": { + "name": "list_posts", + "schema": "", + "columns": { + "list_id": { + "name": "list_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "list_posts_list_id_post_id_index": { + "name": "list_posts_list_id_post_id_index", + "columns": [ + { + "expression": "list_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "list_posts_list_id_lists_id_fk": { + "name": "list_posts_list_id_lists_id_fk", + "tableFrom": "list_posts", + "tableTo": "lists", + "columnsFrom": [ + "list_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "list_posts_post_id_posts_id_fk": { + "name": "list_posts_post_id_posts_id_fk", + "tableFrom": "list_posts", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "list_posts_list_id_post_id_pk": { + "name": "list_posts_list_id_post_id_pk", + "columns": [ + "list_id", + "post_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lists": { + "name": "lists", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replies_policy": { + "name": "replies_policy", + "type": "list_replies_policy", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'list'" + }, + "exclusive": { + "name": "exclusive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": { + "lists_account_owner_id_account_owners_id_fk": { + "name": "lists_account_owner_id_account_owners_id_fk", + "tableFrom": "lists", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.markers": { + "name": "markers", + "schema": "", + "columns": { + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "marker_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "last_read_id": { + "name": "last_read_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "updated": { + "name": "updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": { + "markers_account_owner_id_account_owners_id_fk": { + "name": "markers_account_owner_id_account_owners_id_fk", + "tableFrom": "markers", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "markers_account_owner_id_type_pk": { + "name": "markers_account_owner_id_type_pk", + "columns": [ + "account_owner_id", + "type" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.media": { + "name": "media", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "thumbnail_type": { + "name": "thumbnail_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thumbnail_url": { + "name": "thumbnail_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "thumbnail_width": { + "name": "thumbnail_width", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "thumbnail_height": { + "name": "thumbnail_height", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "thumbnail_cleaned": { + "name": "thumbnail_cleaned", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "media_post_id_index": { + "name": "media_post_id_index", + "columns": [ + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "media_post_id_posts_id_fk": { + "name": "media_post_id_posts_id_fk", + "tableFrom": "media", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mentions": { + "name": "mentions", + "schema": "", + "columns": { + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "mentions_post_id_account_id_index": { + "name": "mentions_post_id_account_id_index", + "columns": [ + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mentions_post_id_posts_id_fk": { + "name": "mentions_post_id_posts_id_fk", + "tableFrom": "mentions", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mentions_account_id_accounts_id_fk": { + "name": "mentions_account_id_accounts_id_fk", + "tableFrom": "mentions", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "mentions_post_id_account_id_pk": { + "name": "mentions_post_id_account_id_pk", + "columns": [ + "post_id", + "account_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mutes": { + "name": "mutes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "muted_account_id": { + "name": "muted_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "notifications": { + "name": "notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "duration": { + "name": "duration", + "type": "interval", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "mutes_account_id_index": { + "name": "mutes_account_id_index", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mutes_account_id_accounts_id_fk": { + "name": "mutes_account_id_accounts_id_fk", + "tableFrom": "mutes", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mutes_muted_account_id_accounts_id_fk": { + "name": "mutes_muted_account_id_accounts_id_fk", + "tableFrom": "mutes", + "tableTo": "accounts", + "columnsFrom": [ + "muted_account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mutes_account_id_muted_account_id_unique": { + "name": "mutes_account_id_muted_account_id_unique", + "nullsNotDistinct": false, + "columns": [ + "account_id", + "muted_account_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notification_groups": { + "name": "notification_groups", + "schema": "", + "columns": { + "group_key": { + "name": "group_key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "notification_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "target_post_id": { + "name": "target_post_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notifications_count": { + "name": "notifications_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "most_recent_notification_id": { + "name": "most_recent_notification_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "sample_account_ids": { + "name": "sample_account_ids", + "type": "uuid[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::uuid[]" + }, + "latest_page_notification_at": { + "name": "latest_page_notification_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "page_min_id": { + "name": "page_min_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "page_max_id": { + "name": "page_max_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "updated": { + "name": "updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "notification_groups_account_owner_id_updated_index": { + "name": "notification_groups_account_owner_id_updated_index", + "columns": [ + { + "expression": "account_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notification_groups_account_owner_id_type_index": { + "name": "notification_groups_account_owner_id_type_index", + "columns": [ + { + "expression": "account_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "notification_groups_account_owner_id_account_owners_id_fk": { + "name": "notification_groups_account_owner_id_account_owners_id_fk", + "tableFrom": "notification_groups", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_groups_target_post_id_posts_id_fk": { + "name": "notification_groups_target_post_id_posts_id_fk", + "tableFrom": "notification_groups", + "tableTo": "posts", + "columnsFrom": [ + "target_post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notification_groups_most_recent_notification_id_notifications_id_fk": { + "name": "notification_groups_most_recent_notification_id_notifications_id_fk", + "tableFrom": "notification_groups", + "tableTo": "notifications", + "columnsFrom": [ + "most_recent_notification_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.notifications": { + "name": "notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "account_owner_id": { + "name": "account_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "notification_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "actor_account_id": { + "name": "actor_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "target_post_id": { + "name": "target_post_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "target_account_id": { + "name": "target_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "target_poll_id": { + "name": "target_poll_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "group_key": { + "name": "group_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "read_at": { + "name": "read_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "notifications_account_owner_id_created_index": { + "name": "notifications_account_owner_id_created_index", + "columns": [ + { + "expression": "account_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notifications_account_owner_id_read_at_index": { + "name": "notifications_account_owner_id_read_at_index", + "columns": [ + { + "expression": "account_owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "read_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notifications_group_key_index": { + "name": "notifications_group_key_index", + "columns": [ + { + "expression": "group_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "notifications_created_index": { + "name": "notifications_created_index", + "columns": [ + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "notifications_account_owner_id_account_owners_id_fk": { + "name": "notifications_account_owner_id_account_owners_id_fk", + "tableFrom": "notifications", + "tableTo": "account_owners", + "columnsFrom": [ + "account_owner_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notifications_actor_account_id_accounts_id_fk": { + "name": "notifications_actor_account_id_accounts_id_fk", + "tableFrom": "notifications", + "tableTo": "accounts", + "columnsFrom": [ + "actor_account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notifications_target_post_id_posts_id_fk": { + "name": "notifications_target_post_id_posts_id_fk", + "tableFrom": "notifications", + "tableTo": "posts", + "columnsFrom": [ + "target_post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notifications_target_account_id_accounts_id_fk": { + "name": "notifications_target_account_id_accounts_id_fk", + "tableFrom": "notifications", + "tableTo": "accounts", + "columnsFrom": [ + "target_account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "notifications_target_poll_id_polls_id_fk": { + "name": "notifications_target_poll_id_polls_id_fk", + "tableFrom": "notifications", + "tableTo": "polls", + "columnsFrom": [ + "target_poll_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pinned_posts": { + "name": "pinned_posts", + "schema": "", + "columns": { + "index": { + "name": "index", + "type": "bigserial", + "primaryKey": true, + "notNull": true + }, + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "pinned_posts_account_id_post_id_index": { + "name": "pinned_posts_account_id_post_id_index", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pinned_posts_account_id_accounts_id_fk": { + "name": "pinned_posts_account_id_accounts_id_fk", + "tableFrom": "pinned_posts", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pinned_posts_post_id_account_id_posts_id_actor_id_fk": { + "name": "pinned_posts_post_id_account_id_posts_id_actor_id_fk", + "tableFrom": "pinned_posts", + "tableTo": "posts", + "columnsFrom": [ + "post_id", + "account_id" + ], + "columnsTo": [ + "id", + "actor_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "pinned_posts_post_id_account_id_unique": { + "name": "pinned_posts_post_id_account_id_unique", + "nullsNotDistinct": false, + "columns": [ + "post_id", + "account_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.poll_options": { + "name": "poll_options", + "schema": "", + "columns": { + "poll_id": { + "name": "poll_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "index": { + "name": "index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "votes_count": { + "name": "votes_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "poll_options_poll_id_index_index": { + "name": "poll_options_poll_id_index_index", + "columns": [ + { + "expression": "poll_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "poll_options_poll_id_polls_id_fk": { + "name": "poll_options_poll_id_polls_id_fk", + "tableFrom": "poll_options", + "tableTo": "polls", + "columnsFrom": [ + "poll_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "poll_options_poll_id_index_pk": { + "name": "poll_options_poll_id_index_pk", + "columns": [ + "poll_id", + "index" + ] + } + }, + "uniqueConstraints": { + "poll_options_poll_id_title_unique": { + "name": "poll_options_poll_id_title_unique", + "nullsNotDistinct": false, + "columns": [ + "poll_id", + "title" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.poll_votes": { + "name": "poll_votes", + "schema": "", + "columns": { + "poll_id": { + "name": "poll_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_index": { + "name": "option_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "poll_votes_poll_id_account_id_index": { + "name": "poll_votes_poll_id_account_id_index", + "columns": [ + { + "expression": "poll_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "poll_votes_poll_id_polls_id_fk": { + "name": "poll_votes_poll_id_polls_id_fk", + "tableFrom": "poll_votes", + "tableTo": "polls", + "columnsFrom": [ + "poll_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "poll_votes_account_id_accounts_id_fk": { + "name": "poll_votes_account_id_accounts_id_fk", + "tableFrom": "poll_votes", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "poll_votes_poll_id_option_index_poll_options_poll_id_index_fk": { + "name": "poll_votes_poll_id_option_index_poll_options_poll_id_index_fk", + "tableFrom": "poll_votes", + "tableTo": "poll_options", + "columnsFrom": [ + "poll_id", + "option_index" + ], + "columnsTo": [ + "poll_id", + "index" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "poll_votes_poll_id_option_index_account_id_pk": { + "name": "poll_votes_poll_id_option_index_account_id_pk", + "columns": [ + "poll_id", + "option_index", + "account_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.polls": { + "name": "polls", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "multiple": { + "name": "multiple", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "voters_count": { + "name": "voters_count", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "expires": { + "name": "expires", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.posts": { + "name": "posts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "iri": { + "name": "iri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "post_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "application_id": { + "name": "application_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "reply_target_id": { + "name": "reply_target_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "sharing_id": { + "name": "sharing_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "quote_target_id": { + "name": "quote_target_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "quote_target_iri": { + "name": "quote_target_iri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quote_state": { + "name": "quote_state", + "type": "quote_state", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "quote_authorization_iri": { + "name": "quote_authorization_iri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quote_approval_policy": { + "name": "quote_approval_policy", + "type": "quote_approval_policy", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'public'" + }, + "visibility": { + "name": "visibility", + "type": "post_visibility", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_html": { + "name": "content_html", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "poll_id": { + "name": "poll_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "language": { + "name": "language", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "emojis": { + "name": "emojis", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preview_card": { + "name": "preview_card", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "replies_count": { + "name": "replies_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "shares_count": { + "name": "shares_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "likes_count": { + "name": "likes_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "quotes_count": { + "name": "quotes_count", + "type": "bigint", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "idempotence_key": { + "name": "idempotence_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "published": { + "name": "published", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "updated": { + "name": "updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "posts_sharing_id_index": { + "name": "posts_sharing_id_index", + "columns": [ + { + "expression": "sharing_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_actor_id_index": { + "name": "posts_actor_id_index", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_actor_id_sharing_id_index": { + "name": "posts_actor_id_sharing_id_index", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sharing_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_reply_target_id_index": { + "name": "posts_reply_target_id_index", + "columns": [ + { + "expression": "reply_target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_actor_id_reply_target_id_index": { + "name": "posts_actor_id_reply_target_id_index", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "reply_target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_quote_target_id_index": { + "name": "posts_quote_target_id_index", + "columns": [ + { + "expression": "quote_target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"posts\".\"quote_target_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_visibility_actor_id_index": { + "name": "posts_visibility_actor_id_index", + "columns": [ + { + "expression": "visibility", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_visibility_actor_id_sharing_id_index": { + "name": "posts_visibility_actor_id_sharing_id_index", + "columns": [ + { + "expression": "visibility", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sharing_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"posts\".\"sharing_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "posts_visibility_actor_id_reply_target_id_index": { + "name": "posts_visibility_actor_id_reply_target_id_index", + "columns": [ + { + "expression": "visibility", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "reply_target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"posts\".\"reply_target_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "posts_actor_id_accounts_id_fk": { + "name": "posts_actor_id_accounts_id_fk", + "tableFrom": "posts", + "tableTo": "accounts", + "columnsFrom": [ + "actor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "posts_application_id_applications_id_fk": { + "name": "posts_application_id_applications_id_fk", + "tableFrom": "posts", + "tableTo": "applications", + "columnsFrom": [ + "application_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "posts_reply_target_id_posts_id_fk": { + "name": "posts_reply_target_id_posts_id_fk", + "tableFrom": "posts", + "tableTo": "posts", + "columnsFrom": [ + "reply_target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "posts_sharing_id_posts_id_fk": { + "name": "posts_sharing_id_posts_id_fk", + "tableFrom": "posts", + "tableTo": "posts", + "columnsFrom": [ + "sharing_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "posts_quote_target_id_posts_id_fk": { + "name": "posts_quote_target_id_posts_id_fk", + "tableFrom": "posts", + "tableTo": "posts", + "columnsFrom": [ + "quote_target_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "posts_poll_id_polls_id_fk": { + "name": "posts_poll_id_polls_id_fk", + "tableFrom": "posts", + "tableTo": "polls", + "columnsFrom": [ + "poll_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "posts_iri_unique": { + "name": "posts_iri_unique", + "nullsNotDistinct": false, + "columns": [ + "iri" + ] + }, + "posts_id_actor_id_unique": { + "name": "posts_id_actor_id_unique", + "nullsNotDistinct": false, + "columns": [ + "id", + "actor_id" + ] + }, + "posts_poll_id_unique": { + "name": "posts_poll_id_unique", + "nullsNotDistinct": false, + "columns": [ + "poll_id" + ] + }, + "posts_actor_id_sharing_id_unique": { + "name": "posts_actor_id_sharing_id_unique", + "nullsNotDistinct": false, + "columns": [ + "actor_id", + "sharing_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reactions": { + "name": "reactions", + "schema": "", + "columns": { + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "emoji": { + "name": "emoji", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "custom_emoji": { + "name": "custom_emoji", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "emoji_iri": { + "name": "emoji_iri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "reactions_post_id_index": { + "name": "reactions_post_id_index", + "columns": [ + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "reactions_post_id_account_id_index": { + "name": "reactions_post_id_account_id_index", + "columns": [ + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "reactions_created_index": { + "name": "reactions_created_index", + "columns": [ + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "reactions_post_id_posts_id_fk": { + "name": "reactions_post_id_posts_id_fk", + "tableFrom": "reactions", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "reactions_account_id_accounts_id_fk": { + "name": "reactions_account_id_accounts_id_fk", + "tableFrom": "reactions", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "reactions_post_id_account_id_emoji_pk": { + "name": "reactions_post_id_account_id_emoji_pk", + "columns": [ + "post_id", + "account_id", + "emoji" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.remote_reply_scrape_jobs": { + "name": "remote_reply_scrape_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "post_iri": { + "name": "post_iri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "replies_iri": { + "name": "replies_iri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "origin_host": { + "name": "origin_host", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "depth": { + "name": "depth", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "remote_reply_scrape_job_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "fetched_items": { + "name": "fetched_items", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "updated": { + "name": "updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "remote_reply_scrape_jobs_claim_index": { + "name": "remote_reply_scrape_jobs_claim_index", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "remote_reply_scrape_jobs_origin_claim_index": { + "name": "remote_reply_scrape_jobs_origin_claim_index", + "columns": [ + { + "expression": "origin_host", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "remote_reply_scrape_jobs_stale_processing_index": { + "name": "remote_reply_scrape_jobs_stale_processing_index", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "remote_reply_scrape_jobs_post_id_posts_id_fk": { + "name": "remote_reply_scrape_jobs_post_id_posts_id_fk", + "tableFrom": "remote_reply_scrape_jobs", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "remote_reply_scrape_jobs_replies_iri_unique": { + "name": "remote_reply_scrape_jobs_replies_iri_unique", + "nullsNotDistinct": false, + "columns": [ + "replies_iri" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.remote_reply_scrape_origins": { + "name": "remote_reply_scrape_origins", + "schema": "", + "columns": { + "origin_host": { + "name": "origin_host", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "next_request_at": { + "name": "next_request_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "last_request_at": { + "name": "last_request_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "processing_job_id": { + "name": "processing_job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "updated": { + "name": "updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": { + "remote_reply_scrape_origins_next_request_at_index": { + "name": "remote_reply_scrape_origins_next_request_at_index", + "columns": [ + { + "expression": "next_request_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "remote_reply_scrape_origins_processing_job_id_index": { + "name": "remote_reply_scrape_origins_processing_job_id_index", + "columns": [ + { + "expression": "processing_job_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.reports": { + "name": "reports", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "iri": { + "name": "iri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "target_account_id": { + "name": "target_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "comment": { + "name": "comment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "posts": { + "name": "posts", + "type": "uuid[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::uuid[]" + } + }, + "indexes": {}, + "foreignKeys": { + "reports_account_id_accounts_id_fk": { + "name": "reports_account_id_accounts_id_fk", + "tableFrom": "reports", + "tableTo": "accounts", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "reports_target_account_id_accounts_id_fk": { + "name": "reports_target_account_id_accounts_id_fk", + "tableFrom": "reports", + "tableTo": "accounts", + "columnsFrom": [ + "target_account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "reports_iri_unique": { + "name": "reports_iri_unique", + "nullsNotDistinct": false, + "columns": [ + "iri" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.timeline_posts": { + "name": "timeline_posts", + "schema": "", + "columns": { + "account_id": { + "name": "account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "post_id": { + "name": "post_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "timeline_posts_account_id_post_id_index": { + "name": "timeline_posts_account_id_post_id_index", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "post_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "timeline_posts_account_id_account_owners_id_fk": { + "name": "timeline_posts_account_id_account_owners_id_fk", + "tableFrom": "timeline_posts", + "tableTo": "account_owners", + "columnsFrom": [ + "account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "timeline_posts_post_id_posts_id_fk": { + "name": "timeline_posts_post_id_posts_id_fk", + "tableFrom": "timeline_posts", + "tableTo": "posts", + "columnsFrom": [ + "post_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "timeline_posts_account_id_post_id_pk": { + "name": "timeline_posts_account_id_post_id_pk", + "columns": [ + "account_id", + "post_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.totps": { + "name": "totps", + "schema": "", + "columns": { + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "algorithm": { + "name": "algorithm", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "digits": { + "name": "digits", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "period": { + "name": "period", + "type": "smallint", + "primaryKey": false, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created": { + "name": "created", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.account_type": { + "name": "account_type", + "schema": "public", + "values": [ + "Application", + "Group", + "Organization", + "Person", + "Service" + ] + }, + "public.cleanup_job_category": { + "name": "cleanup_job_category", + "schema": "public", + "values": [ + "cleanup_thumbnails" + ] + }, + "public.cleanup_job_status": { + "name": "cleanup_job_status", + "schema": "public", + "values": [ + "pending", + "processing", + "completed", + "failed", + "cancelled" + ] + }, + "public.grant_type": { + "name": "grant_type", + "schema": "public", + "values": [ + "authorization_code", + "client_credentials" + ] + }, + "public.import_job_category": { + "name": "import_job_category", + "schema": "public", + "values": [ + "following_accounts", + "lists", + "muted_accounts", + "blocked_accounts", + "bookmarks" + ] + }, + "public.import_job_status": { + "name": "import_job_status", + "schema": "public", + "values": [ + "pending", + "processing", + "completed", + "failed", + "cancelled" + ] + }, + "public.list_replies_policy": { + "name": "list_replies_policy", + "schema": "public", + "values": [ + "followed", + "list", + "none" + ] + }, + "public.marker_type": { + "name": "marker_type", + "schema": "public", + "values": [ + "notifications", + "home" + ] + }, + "public.notification_type": { + "name": "notification_type", + "schema": "public", + "values": [ + "mention", + "status", + "reblog", + "follow", + "follow_request", + "favourite", + "emoji_reaction", + "poll", + "update", + "admin.sign_up", + "admin.report", + "quote", + "quoted_update" + ] + }, + "public.post_type": { + "name": "post_type", + "schema": "public", + "values": [ + "Article", + "Note", + "Question" + ] + }, + "public.post_visibility": { + "name": "post_visibility", + "schema": "public", + "values": [ + "public", + "unlisted", + "private", + "direct" + ] + }, + "public.quote_approval_policy": { + "name": "quote_approval_policy", + "schema": "public", + "values": [ + "public", + "followers", + "nobody" + ] + }, + "public.quote_state": { + "name": "quote_state", + "schema": "public", + "values": [ + "pending", + "accepted", + "rejected", + "revoked", + "unauthorized" + ] + }, + "public.remote_reply_scrape_job_status": { + "name": "remote_reply_scrape_job_status", + "schema": "public", + "values": [ + "pending", + "processing", + "completed", + "failed" + ] + }, + "public.scope": { + "name": "scope", + "schema": "public", + "values": [ + "read", + "read:accounts", + "read:blocks", + "read:bookmarks", + "read:favourites", + "read:filters", + "read:follows", + "read:lists", + "read:mutes", + "read:notifications", + "read:search", + "read:statuses", + "write", + "write:accounts", + "write:blocks", + "write:bookmarks", + "write:conversations", + "write:favourites", + "write:filters", + "write:follows", + "write:lists", + "write:media", + "write:mutes", + "write:notifications", + "write:reports", + "write:statuses", + "follow", + "push", + "profile" + ] + }, + "public.theme_color": { + "name": "theme_color", + "schema": "public", + "values": [ + "amber", + "azure", + "blue", + "cyan", + "fuchsia", + "green", + "grey", + "indigo", + "jade", + "lime", + "orange", + "pink", + "pumpkin", + "purple", + "red", + "sand", + "slate", + "violet", + "yellow", + "zinc" + ] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 396151b4..220cee16 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -610,6 +610,13 @@ "when": 1777358526000, "tag": "0086_quote_controls", "breakpoints": true + }, + { + "idx": 87, + "version": "7", + "when": 1777428000000, + "tag": "0087_quote_authorization_requirement", + "breakpoints": true } ] } diff --git a/src/api/v1/statuses.test.ts b/src/api/v1/statuses.test.ts index 8c410292..43e85747 100644 --- a/src/api/v1/statuses.test.ts +++ b/src/api/v1/statuses.test.ts @@ -521,6 +521,135 @@ describe.sequential("/api/v1/statuses quotes", () => { expect(selfQuote.quote.state).toBe("accepted"); }); + it("accepts quotes of remote posts without FEP-044f policy", async () => { + expect.assertions(3); + + const remoteAccountId = uuidv7(); + const quotedPostId = uuidv7(); + const quotedPostIri = `https://remote.test/@legacy/${quotedPostId}`; + + await db.insert(instances).values({ host: "remote.test" }); + await db.insert(accounts).values({ + id: remoteAccountId, + iri: "https://remote.test/@legacy", + type: "Person", + name: "Legacy remote author", + handle: "@legacy@remote.test", + bioHtml: "", + protected: false, + inboxUrl: "https://remote.test/@legacy/inbox", + sharedInboxUrl: "https://remote.test/inbox", + instanceHost: "remote.test", + }); + await db.insert(posts).values({ + id: quotedPostId, + iri: quotedPostIri, + type: "Note", + accountId: remoteAccountId, + visibility: "public", + quoteApprovalPolicy: null, + content: "Legacy remote quoted post", + contentHtml: "

Legacy remote quoted post

\n", + url: quotedPostIri, + published: new Date(), + }); + + const fetch = vi + .spyOn(globalThis, "fetch") + .mockResolvedValue(new Response(null, { status: 202 })); + try { + const quoteResponse = await createStatus(quoterToken, { + status: "Quoting a legacy remote post", + quoted_status_id: quotedPostId, + }); + expect(quoteResponse.status).toBe(200); + const quote = await quoteResponse.json(); + expect(quote.quote.state).toBe("accepted"); + const activities = await Promise.all( + fetch.mock.calls.map(async ([input]) => { + const request = input instanceof Request ? input : null; + return request == null ? null : await request.clone().json(); + }), + ); + expect( + activities.some((activity) => activity?.type === "QuoteRequest"), + ).toBe(false); + } finally { + fetch.mockRestore(); + } + }); + + it("requests authorization for cached remote public policies", async () => { + expect.assertions(3); + + const remoteAccountId = uuidv7(); + const quotedPostId = uuidv7(); + const quotedPostIri = `https://remote.test/@fep-author/${quotedPostId}`; + + await db.insert(instances).values({ host: "remote.test" }); + await db.insert(accounts).values({ + id: remoteAccountId, + iri: "https://remote.test/@fep-author", + type: "Person", + name: "FEP-044f remote author", + handle: "@fep-author@remote.test", + bioHtml: "", + protected: false, + inboxUrl: "https://remote.test/@fep-author/inbox", + followersUrl: "https://remote.test/@fep-author/followers", + sharedInboxUrl: "https://remote.test/inbox", + instanceHost: "remote.test", + }); + await db.insert(follows).values({ + iri: `https://remote.test/follows/${crypto.randomUUID()}`, + followingId: remoteAccountId, + followerId: quoter.id, + approved: new Date(), + }); + await db.insert(posts).values({ + id: quotedPostId, + iri: quotedPostIri, + type: "Note", + accountId: remoteAccountId, + visibility: "public", + quoteApprovalPolicy: "public", + content: "FEP-044f public remote post", + contentHtml: "

FEP-044f public remote post

\n", + url: quotedPostIri, + published: new Date(), + }); + + const fetch = vi + .spyOn(globalThis, "fetch") + .mockResolvedValue(new Response(null, { status: 202 })); + try { + const quoteResponse = await createStatus(quoterToken, { + status: "Quoting a public FEP-044f remote post", + quoted_status_id: quotedPostId, + }); + expect(quoteResponse.status).toBe(200); + const quote = await quoteResponse.json(); + expect(quote.quote.state).toBe("pending"); + + let quoteRequest: unknown; + await vi.waitFor(async () => { + for (const [input] of fetch.mock.calls) { + const request = input instanceof Request ? input : null; + const activity = + request == null ? null : await request.clone().json(); + if (activity?.type === "QuoteRequest") { + quoteRequest = activity; + return; + } + } + throw new Error("QuoteRequest was not sent"); + }); + expect(quoteRequest).toBeDefined(); + } finally { + fetch.mockRestore(); + } + }); + it("returns revoked quote state when a quote is revoked", async () => { expect.assertions(7); diff --git a/src/api/v1/statuses.ts b/src/api/v1/statuses.ts index 4d89a384..7215c31f 100644 --- a/src/api/v1/statuses.ts +++ b/src/api/v1/statuses.ts @@ -389,7 +389,10 @@ app.post("/", tokenRequired, scopeRequired(["write:statuses"]), async (c) => { : await db.query.accountOwners.findFirst({ where: eq(accountOwners.id, quoteTarget.accountId), }); - quoteState = localQuoteTargetOwner == null ? "pending" : "accepted"; + quoteState = + localQuoteTargetOwner == null && quoteTarget.quoteApprovalPolicy != null + ? "pending" + : "accepted"; } await db.transaction(async (tx) => { let poll: Poll | null = null; diff --git a/src/entities/status.ts b/src/entities/status.ts index f7f04497..6d2fc25b 100644 --- a/src/entities/status.ts +++ b/src/entities/status.ts @@ -48,7 +48,7 @@ function getEffectiveQuoteState( } function serializeQuoteApproval( - policy: QuoteApprovalPolicy, + policy: QuoteApprovalPolicy | null, currentAccountOwner: { id: string } | undefined | null, post: Pick, viewerIsApprovedFollower: boolean, @@ -56,7 +56,7 @@ function serializeQuoteApproval( const effectivePolicy = post.visibility === "direct" || post.visibility === "private" ? "nobody" - : policy; + : (policy ?? "public"); const automatic = effectivePolicy === "public" ? ["public"] diff --git a/src/federation/inbox.ts b/src/federation/inbox.ts index 9e8e7ecc..b91c87c2 100644 --- a/src/federation/inbox.ts +++ b/src/federation/inbox.ts @@ -624,7 +624,7 @@ async function canAutomaticallyAcceptQuoteRequest( ), }); if (block != null) return false; - const policy = target.quoteApprovalPolicy; + const policy = target.quoteApprovalPolicy ?? "public"; if (policy === "public") return true; if (policy === "nobody") return false; const follow = await db.query.follows.findFirst({ diff --git a/src/federation/post.test.ts b/src/federation/post.test.ts index dcbb72f2..7ec9720e 100644 --- a/src/federation/post.test.ts +++ b/src/federation/post.test.ts @@ -917,7 +917,7 @@ describe("persistPost quotes", () => { expect(persisted?.contentHtml).toBe("

Updated quote

"); }); - it("defaults quote approval to public when no interaction policy exists", async () => { + it("stores no quote approval policy when no interaction policy exists", async () => { const author = await seedRemoteAccount("quote-author"); const persisted = await persistPost( @@ -931,7 +931,7 @@ describe("persistPost quotes", () => { "https://hollo.test", ); - expect(persisted?.quoteApprovalPolicy).toBe("public"); + expect(persisted?.quoteApprovalPolicy).toBeNull(); }); it("does not treat manual-only quote approval as public", async () => { diff --git a/src/federation/post.ts b/src/federation/post.ts index 1ded7731..eb25e04b 100644 --- a/src/federation/post.ts +++ b/src/federation/post.ts @@ -111,9 +111,9 @@ export function isPost(object?: vocab.Object | Link | null): object is ASPost { function getQuoteApprovalPolicy( object: ASPost, account: Account, -): QuoteApprovalPolicy { +): QuoteApprovalPolicy | null { const canQuote = object.interactionPolicy?.canQuote; - if (canQuote == null) return "public"; + if (canQuote == null) return null; const automaticApprovals = canQuote.automaticApprovals; if (automaticApprovals.length < 1) return "nobody"; if ( @@ -1014,7 +1014,7 @@ function getCanQuoteRule( const policy = post.visibility === "direct" || post.visibility === "private" ? "nobody" - : post.quoteApprovalPolicy; + : (post.quoteApprovalPolicy ?? "public"); if (policy === "public") { return new InteractionRule({ automaticApproval: vocab.PUBLIC_COLLECTION, diff --git a/src/schema.ts b/src/schema.ts index cceafbc1..8810f493 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -461,9 +461,9 @@ export const posts = pgTable( quoteTargetIri: text("quote_target_iri"), quoteState: quoteStateEnum("quote_state"), quoteAuthorizationIri: text("quote_authorization_iri"), - quoteApprovalPolicy: quoteApprovalPolicyEnum("quote_approval_policy") - .notNull() - .default("public"), + quoteApprovalPolicy: quoteApprovalPolicyEnum( + "quote_approval_policy", + ).default("public"), visibility: postVisibilityEnum("visibility").notNull(), summary: text("summary"), contentHtml: text("content_html"),