-- -- Maintains the modified_at in a table -- create or replace function update_modified_at_column() returns trigger as $$ begin NEW.modified_at = now(); return NEW; end; $$ language 'plpgsql'; -- -- Users, Passwords -- create type user_principal_status_type as enum ( 'Active', 'Suspended', 'Pending Approval' ); create table user_principal ( acct varchar not null primary key, -- user_name@host_name auth_data jsonb not null, last_seen_data jsonb default '[]'::jsonb not null, last_login_data jsonb default '[]'::jsonb not null, system_data jsonb, preferences jsonb, status user_principal_status_type default 'Pending Approval' not null, system_permissions jsonb default '[]'::jsonb not null, created_at timestamptz default now() not null, modified_at timestamptz default now() not null ); create index on user_principal(created_at); -- used for pagination create trigger update_userprincipal_modified_at before update on user_principal for each row execute procedure update_modified_at_column(); -- -- Site Info -- create table site_info ( host_name varchar, site_data jsonb not null, created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key (host_name) ); create trigger update_siteinfo_modified_at before update on site_info for each row execute procedure update_modified_at_column(); -- -- System Roles -- create type system_role_type as enum( 'User Administrator', 'Actor Administrator', 'Content Administrator' ); create table system_role ( role_type system_role_type not null, member varchar not null references user_principal(acct), host_name varchar null references site_info(host_name), created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key(role_type, member, host_name) ); create or replace function make_system_permissions() returns trigger as $$ declare user_acct varchar; user_system_permissions jsonb; begin if (tg_op = 'DELETE') then user_acct = OLD.member; else user_acct = NEW.member; end if; select into user_system_permissions jsonb_agg( jsonb_build_object( 'role', role_type, 'host_name', host_name ) ) from system_role where member=user_acct group by member; if (user_system_permissions IS NULL) then user_system_permissions := '[]'::jsonb; end if; update user_principal set system_permissions=user_system_permissions where acct=user_acct; return null; end $$ language 'plpgsql'; create trigger make_system_permissions after update or insert or delete on system_role for each row execute procedure make_system_permissions(); create index on system_role(role_type, host_name); -- -- Actors -- create type actor_visibility_type as enum ( 'Visible', -- publicly visible and discoverable 'Invisible', -- visible only to the user and administrators 'Banned' -- visible only to the administrators ); -- should mirror activity pub actor types create type actor_type as enum ( 'Application', 'Group', 'Organization', 'Person', 'Service' ); create table actor ( id varchar primary key, type actor_type not null, acct varchar unique, webfinger_json jsonb, activity_pub_json jsonb not null, owner_data jsonb, private_key_pem varchar, visibility actor_visibility_type default 'Visible', system_data jsonb, created_at timestamptz default now() not null, modified_at timestamptz default now() not null ); create index on actor(modified_at); -- used for pagination create trigger update_actor_modified_at before update on actor for each row execute procedure update_modified_at_column(); create table actor_owner ( actor_id varchar references actor(id) not null, user_owner varchar references user_principal(acct) not null, default_actor boolean default false, created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key (actor_id, user_owner) ); -- creates a unique index for the default actor allowing multiple false create unique index on actor_owner(user_owner, default_actor) where (default_actor); create trigger update_actor_owner_modified_at before update on actor_owner for each row execute procedure update_modified_at_column(); -- -- Actor Reference -- -- represents the type of reference create type actor_reference_type as enum ( 'Following', 'Follower', 'Liked', 'Likes', 'Member' ); create table actor_reference ( subject_actor_id varchar references actor(id), object_actor_id varchar references actor(id), reference_type actor_reference_type not null, created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key (subject_actor_id, object_actor_id, reference_type) ); create trigger update_actor_reference_modified_at before update on actor_reference for each row execute procedure update_modified_at_column(); -- -- User Actor Data -- allows users to keep arbitrary data about actors -- create table user_actor_data ( actor_id varchar references actor(id) not null, user_acct varchar references user_principal(acct) not null, owner_data jsonb not null, created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key (actor_id, user_acct) ); create trigger update_user_actor_data_modified_at before update on user_actor_data for each row execute procedure update_modified_at_column(); -- -- Job Queues -- create type job_type as enum ( 'No Operation', 'Make Thumbnail', 'Resize Actor Icon', 'Resize Actor Banner', 'Fetch Remote Icon', 'Fetch Remote Banner', 'Send Activity Pub' ); create table job_queue( id integer generated always as identity primary key, job_type job_type not null, details jsonb not null, attempts_remaining int default 1 not null, no_sooner_than timestamptz default now() not null, created_at timestamptz default now() not null ); create index on job_queue(job_type, attempts_remaining, no_sooner_than); -- -- AP Object - activitypub objects that can be "posted" -- -- these should mirror the ActivityPub object type names create type ap_object_type as enum ( 'Note', 'Article', 'Document', 'Image', 'Video', 'Audio', 'Page' ); create type ap_object_visibility_type as enum ( 'Visible', 'Invisible' ); create table ap_object ( id varchar primary key, type ap_object_type not null, actor_owner varchar references actor(id), received_for_host varchar references site_info(host_name) not null, activity_pub_json jsonb not null, owner_data jsonb, visibility ap_object_visibility_type not null default 'Visible', system_data jsonb, created_at timestamptz default now() not null, modified_at timestamptz default now() not null ); create index on ap_object(modified_at, received_for_host); -- used for pagination create index on ap_object(modified_at, actor_owner); -- used for pagination create index on ap_object(modified_at, actor_owner, type); -- used for pagination -- these expression indexes support queries such as -- select activity_pub_json from ap_object where activity_pub_json -> 'to' ? 'http://example.com/foo'; create index on ap_object USING gin ((activity_pub_json->'to')); create index on ap_object USING gin ((activity_pub_json->'bto')); create index on ap_object USING gin ((activity_pub_json->'cc')); create index on ap_object USING gin ((activity_pub_json->'bcc')); create index on ap_object USING gin ((activity_pub_json->'actor')); create index on ap_object USING gin ((activity_pub_json->'attributedTo')); create trigger update_ap_object_modified_at before update on ap_object for each row execute procedure update_modified_at_column(); -- -- AP Object Reference -- -- represents the type of reference create type ap_object_reference_type as enum ( 'Dislike', 'Flag', 'Like', 'Read' ); create table ap_object_reference ( actor_id varchar references actor(id), ap_object_id varchar references ap_object(id), reference_type ap_object_reference_type not null, created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key (actor_id, ap_object_id, reference_type) ); create trigger update_ap_object_reference_modified_at before update on ap_object_reference for each row execute procedure update_modified_at_column(); -- -- User AP Object Data -- allows users to keep arbitrary data about AP objects -- create table user_ap_object_data ( ap_object_id varchar references ap_object(id) not null, user_acct varchar references user_principal(acct) not null, owner_data jsonb not null, created_at timestamptz default now() not null, modified_at timestamptz default now() not null, primary key (ap_object_id, user_acct) ); create trigger update_user_ap_object_data_modified_at before update on user_ap_object_data for each row execute procedure update_modified_at_column();