Merge pull request #218 from usbharu/feature/actor-count-column

Feature/actor count column
This commit is contained in:
usbharu 2023-12-14 12:53:14 +09:00 committed by GitHub
commit 382fe89142
22 changed files with 241 additions and 154 deletions

View File

@ -1,5 +1,6 @@
insert into actors (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
last_post_at)
VALUES (1730415786666758144, 'test-user', 'localhost', 'Im test user.', 'THis account is test user.', VALUES (1730415786666758144, 'test-user', 'localhost', 'Im test user.', 'THis account is test user.',
'http://localhost/users/test-user/inbox', 'http://localhost/users/test-user/inbox',
'http://localhost/users/test-user/outbox', 'http://localhost/users/test-user', 'http://localhost/users/test-user/outbox', 'http://localhost/users/test-user',
@ -43,7 +44,7 @@ Ja15+ZWbOA4vJA9pOh3x4XM=
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
', 1701398248417, ', 1701398248417,
'http://localhost/users/test-user#pubkey', 'http://localhost/users/test-user/following', 'http://localhost/users/test-user#pubkey', 'http://localhost/users/test-user/following',
'http://localhost/users/test-users/followers', null, false); 'http://localhost/users/test-users/followers', null, false, 0, 0, 0, null);
insert into user_details (actor_id, password, auto_accept_followee_follow_request) insert into user_details (actor_id, password, auto_accept_followee_follow_request)
values ( 1730415786666758144 values ( 1730415786666758144

View File

@ -1,16 +1,17 @@
insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
created_at, key_id, following, followers, instance, locked) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (3733363, 'follow-test-user-1', 'example.com', 'follow-test-user-1-name', '', VALUES (3733363, 'follow-test-user-1', 'example.com', 'follow-test-user-1-name', '',
'https://example.com/users/follow-test-user-1/inbox', 'https://example.com/users/follow-test-user-1/inbox',
'https://example.com/users/follow-test-user-1/outbox', 'https://example.com/users/follow-test-user-1', 'https://example.com/users/follow-test-user-1/outbox', 'https://example.com/users/follow-test-user-1',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/follow-test-user-1#pubkey', 'https://example.com/users/follow-test-user-1/following', 'https://example.com/users/follow-test-user-1#pubkey', 'https://example.com/users/follow-test-user-1/following',
'https://example.com/users/follow-test-user-1/followers', null, false), 'https://example.com/users/follow-test-user-1/followers', null, false, 0, 0, 0, null),
(37335363, 'follow-test-user-2', 'example.com', 'follow-test-user-2-name', '', (37335363, 'follow-test-user-2', 'example.com', 'follow-test-user-2-name', '',
'https://example.com/users/follow-test-user-2/inbox', 'https://example.com/users/follow-test-user-2/inbox',
'https://example.com/users/follow-test-user-2/outbox', 'https://example.com/users/follow-test-user-2', 'https://example.com/users/follow-test-user-2/outbox', 'https://example.com/users/follow-test-user-2',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/follow-test-user-2#pubkey', 'https://example.com/users/follow-test-user-2/following', 'https://example.com/users/follow-test-user-2#pubkey', 'https://example.com/users/follow-test-user-2/following',
'https://example.com/users/follow-test-user-2/followers', null, false); 'https://example.com/users/follow-test-user-2/followers', null, false, 0, 0, 0, null);

View File

@ -1,12 +1,13 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (8, 'test-user8', 'example.com', 'Im test-user8.', 'THis account is test-user8.', VALUES (8, 'test-user8', 'example.com', 'Im test-user8.', 'THis account is test-user8.',
'https://example.com/users/test-user8/inbox', 'https://example.com/users/test-user8/inbox',
'https://example.com/users/test-user8/outbox', 'https://example.com/users/test-user8', 'https://example.com/users/test-user8/outbox', 'https://example.com/users/test-user8',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user8#pubkey', 'https://example.com/users/test-user8/following', 'https://example.com/users/test-user8#pubkey', 'https://example.com/users/test-user8/following',
'https://example.com/users/test-user8/followers', null, false), 'https://example.com/users/test-user8/followers', null, false, 0, 0, 0, null),
(9, 'test-user9', 'follower.example.com', 'Im test-user9.', 'THis account is test-user9.', (9, 'test-user9', 'follower.example.com', 'Im test-user9.', 'THis account is test-user9.',
'https://follower.example.com/users/test-user9/inbox', 'https://follower.example.com/users/test-user9/inbox',
'https://follower.example.com/users/test-user9/outbox', 'https://follower.example.com/users/test-user9', 'https://follower.example.com/users/test-user9/outbox', 'https://follower.example.com/users/test-user9',
@ -14,7 +15,7 @@ VALUES (8, 'test-user8', 'example.com', 'Im test-user8.', 'THis account is test-
null, 12345678, null, 12345678,
'https://follower.example.com/users/test-user9#pubkey', 'https://follower.example.com/users/test-user9#pubkey',
'https://follower.example.com/users/test-user9/following', 'https://follower.example.com/users/test-user9/following',
'https://follower.example.com/users/test-user9/followers', null, false); 'https://follower.example.com/users/test-user9/followers', null, false, 0, 0, 0, null);
insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request, insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request,
ignore_follow_request) ignore_follow_request)

View File

@ -1,12 +1,13 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (4, 'test-user4', 'example.com', 'Im test user4.', 'THis account is test user4.', VALUES (4, 'test-user4', 'example.com', 'Im test user4.', 'THis account is test user4.',
'https://example.com/users/test-user4/inbox', 'https://example.com/users/test-user4/inbox',
'https://example.com/users/test-user4/outbox', 'https://example.com/users/test-user4', 'https://example.com/users/test-user4/outbox', 'https://example.com/users/test-user4',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user4#pubkey', 'https://example.com/users/test-user4/following', 'https://example.com/users/test-user4#pubkey', 'https://example.com/users/test-user4/following',
'https://example.com/users/test-user4/followers', null, false), 'https://example.com/users/test-user4/followers', null, false, 0, 0, 0, null),
(5, 'test-user5', 'follower.example.com', 'Im test user5.', 'THis account is test user5.', (5, 'test-user5', 'follower.example.com', 'Im test user5.', 'THis account is test user5.',
'https://follower.example.com/users/test-user5/inbox', 'https://follower.example.com/users/test-user5/inbox',
'https://follower.example.com/users/test-user5/outbox', 'https://follower.example.com/users/test-user5', 'https://follower.example.com/users/test-user5/outbox', 'https://follower.example.com/users/test-user5',
@ -14,13 +15,13 @@ VALUES (4, 'test-user4', 'example.com', 'Im test user4.', 'THis account is test
null, 12345678, null, 12345678,
'https://follower.example.com/users/test-user5#pubkey', 'https://follower.example.com/users/test-user5#pubkey',
'https://follower.example.com/users/test-user5/following', 'https://follower.example.com/users/test-user5/following',
'https://follower.example.com/users/test-user5/followers', null, false); 'https://follower.example.com/users/test-user5/followers', null, false, 0, 0, 0, null);
insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request, insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request,
ignore_follow_request) ignore_follow_request)
VALUES (5, 4, true, false, false, false, false); VALUES (5, 4, true, false, false, false, false);
insert into POSTS (ID, "actor_ID", OVERVIEW, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", SENSITIVE, insert into POSTS (ID, "actor_id", OVERVIEW, TEXT, "created_at", VISIBILITY, URL, "repost_id", "reply_id", SENSITIVE,
AP_ID) AP_ID)
VALUES (1237, 4, null, 'test post', 12345680, 0, 'https://example.com/users/test-user4/posts/1237', null, null, false, VALUES (1237, 4, null, 'test post', 12345680, 0, 'https://example.com/users/test-user4/posts/1237', null, null, false,
'https://example.com/users/test-user4/posts/1237'); 'https://example.com/users/test-user4/posts/1237');

View File

@ -1,12 +1,13 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (6, 'test-user6', 'example.com', 'Im test-user6.', 'THis account is test-user6.', VALUES (6, 'test-user6', 'example.com', 'Im test-user6.', 'THis account is test-user6.',
'https://example.com/users/test-user6/inbox', 'https://example.com/users/test-user6/inbox',
'https://example.com/users/test-user6/outbox', 'https://example.com/users/test-user6', 'https://example.com/users/test-user6/outbox', 'https://example.com/users/test-user6',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user6#pubkey', 'https://example.com/users/test-user6/following', 'https://example.com/users/test-user6#pubkey', 'https://example.com/users/test-user6/following',
'https://example.com/users/test-user6/followers', null, false), 'https://example.com/users/test-user6/followers', null, false, 0, 0, 0, null),
(7, 'test-user7', 'follower.example.com', 'Im test-user7.', 'THis account is test-user7.', (7, 'test-user7', 'follower.example.com', 'Im test-user7.', 'THis account is test-user7.',
'https://follower.example.com/users/test-user7/inbox', 'https://follower.example.com/users/test-user7/inbox',
'https://follower.example.com/users/test-user7/outbox', 'https://follower.example.com/users/test-user7', 'https://follower.example.com/users/test-user7/outbox', 'https://follower.example.com/users/test-user7',
@ -14,7 +15,7 @@ VALUES (6, 'test-user6', 'example.com', 'Im test-user6.', 'THis account is test-
null, 12345678, null, 12345678,
'https://follower.example.com/users/test-user7#pubkey', 'https://follower.example.com/users/test-user7#pubkey',
'https://follower.example.com/users/test-user7/following', 'https://follower.example.com/users/test-user7/following',
'https://follower.example.com/users/test-user7/followers', null, false); 'https://follower.example.com/users/test-user7/followers', null, false, 0, 0, 0, null);
insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request, insert into relationships (actor_id, target_actor_id, following, blocking, muting, follow_request,
ignore_follow_request) ignore_follow_request)

View File

@ -1,17 +1,18 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (11, 'test-user11', 'example.com', 'Im test-user11.', 'THis account is test-user11.', VALUES (11, 'test-user11', 'example.com', 'Im test-user11.', 'THis account is test-user11.',
'https://example.com/users/test-user11/inbox', 'https://example.com/users/test-user11/inbox',
'https://example.com/users/test-user11/outbox', 'https://example.com/users/test-user11', 'https://example.com/users/test-user11/outbox', 'https://example.com/users/test-user11',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user11#pubkey', 'https://example.com/users/test-user11/following', 'https://example.com/users/test-user11#pubkey', 'https://example.com/users/test-user11/following',
'https://example.com/users/test-user11/followers', null, false); 'https://example.com/users/test-user11/followers', null, false, 0, 0, 0, null);
insert into POSTS (ID, actor_id, OVERVIEW, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", SENSITIVE, insert into POSTS (id, actor_id, overview, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id,
AP_ID) deleted)
VALUES (1242, 11, null, 'test post', 12345680, 0, 'https://example.com/users/test-user11/posts/1242', null, null, false, VALUES (1242, 11, null, 'test post', 12345680, 0, 'https://example.com/users/test-user11/posts/1242', null, null, false,
'https://example.com/users/test-user11/posts/1242'); 'https://example.com/users/test-user11/posts/1242', false);
insert into MEDIA (ID, NAME, URL, REMOTE_URL, THUMBNAIL_URL, TYPE, BLURHASH, MIME_TYPE, DESCRIPTION) insert into MEDIA (ID, NAME, URL, REMOTE_URL, THUMBNAIL_URL, TYPE, BLURHASH, MIME_TYPE, DESCRIPTION)
VALUES (1, 'test-media', 'https://example.com/media/test-media.png', null, null, 0, null, 'image/png', null), VALUES (1, 'test-media', 'https://example.com/media/test-media.png', null, null, 0, null, 'image/png', null),

View File

@ -1,16 +1,17 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (10, 'test-user10', 'example.com', 'Im test-user10.', 'THis account is test-user10.', VALUES (10, 'test-user10', 'example.com', 'Im test-user10.', 'THis account is test-user10.',
'https://example.com/users/test-user10/inbox', 'https://example.com/users/test-user10/inbox',
'https://example.com/users/test-user10/outbox', 'https://example.com/users/test-user10', 'https://example.com/users/test-user10/outbox', 'https://example.com/users/test-user10',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user10#pubkey', 'https://example.com/users/test-user10/following', 'https://example.com/users/test-user10#pubkey', 'https://example.com/users/test-user10/following',
'https://example.com/users/test-user10/followers', null, false); 'https://example.com/users/test-user10/followers', null, false, 0, 0, 0, null);
insert into POSTS (ID, actor_id, OVERVIEW, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", SENSITIVE, insert into POSTS (id, actor_id, overview, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id,
AP_ID) deleted)
VALUES (1240, 10, null, 'test post', 12345680, 0, 'https://example.com/users/test-user10/posts/1240', null, null, false, VALUES (1240, 10, null, 'test post', 12345680, 0, 'https://example.com/users/test-user10/posts/1240', null, null, false,
'https://example.com/users/test-user10/posts/1240'), 'https://example.com/users/test-user10/posts/1240', false),
(1241, 10, null, 'test post', 12345680, 0, 'https://example.com/users/test-user10/posts/1241', null, 1240, false, (1241, 10, null, 'test post', 12345680, 0, 'https://example.com/users/test-user10/posts/1241', null, 1240, false,
'https://example.com/users/test-user10/posts/1241'); 'https://example.com/users/test-user10/posts/1241', false);

View File

@ -1,14 +1,15 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (3, 'test-user3', 'example.com', 'Im test user3.', 'THis account is test user3.', VALUES (3, 'test-user3', 'example.com', 'Im test user3.', 'THis account is test user3.',
'https://example.com/users/test-user3/inbox', 'https://example.com/users/test-user3/inbox',
'https://example.com/users/test-user3/outbox', 'https://example.com/users/test-user3', 'https://example.com/users/test-user3/outbox', 'https://example.com/users/test-user3',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user3#pubkey', 'https://example.com/users/test-user3/following', 'https://example.com/users/test-user3#pubkey', 'https://example.com/users/test-user3/following',
'https://example.com/users/test-user3/followers', null, false); 'https://example.com/users/test-user3/followers', null, false, 0, 0, 0, null);
insert into POSTS (ID, actor_id, OVERVIEW, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", SENSITIVE, insert into POSTS (id, actor_id, overview, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id,
AP_ID) deleted)
VALUES (1236, 3, null, 'test post', 12345680, 2, 'https://example.com/users/test-user3/posts/1236', null, null, false, VALUES (1236, 3, null, 'test post', 12345680, 2, 'https://example.com/users/test-user3/posts/1236', null, null, false,
'https://example.com/users/test-user3/posts/1236') 'https://example.com/users/test-user3/posts/1236', false)

View File

@ -1,14 +1,15 @@
insert into actors (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
last_post_at)
VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.', VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.',
'https://example.com/users/test-user/inbox', 'https://example.com/users/test-user/inbox',
'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user', 'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following', 'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following',
'https://example.com/users/test-users/followers', null, false); 'https://example.com/users/test-users/followers', null, false, 0, 0, 0, null);
insert into POSTS (ID, actor_id, OVERVIEW, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", SENSITIVE, insert into POSTS (id, actor_id, overview, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id,
AP_ID) deleted)
VALUES (1234, 1, null, 'test post', 12345680, 0, 'https://example.com/users/test-user/posts/1234', null, null, false, VALUES (1234, 1, null, 'test post', 12345680, 0, 'https://example.com/users/test-user/posts/1234', null, null, false,
'https://example.com/users/test-user/posts/1234') 'https://example.com/users/test-user/posts/1234', false)

View File

@ -1,14 +1,15 @@
insert into actors (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
last_post_at)
VALUES (2, 'test-user2', 'example.com', 'Im test user2.', 'THis account is test user2.', VALUES (2, 'test-user2', 'example.com', 'Im test user2.', 'THis account is test user2.',
'https://example.com/users/test-user2/inbox', 'https://example.com/users/test-user2/inbox',
'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2', 'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following', 'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following',
'https://example.com/users/test-user2/followers', null, false); 'https://example.com/users/test-user2/followers', null, false, 0, 0, 0, null);
insert into POSTS (ID, actor_id, OVERVIEW, TEXT, "CREATED_AT", VISIBILITY, URL, "REPOST_ID", "REPLY_ID", SENSITIVE, insert into POSTS (id, actor_id, overview, text, created_at, visibility, url, repost_id, reply_id, sensitive, ap_id,
AP_ID) deleted)
VALUES (1235, 2, null, 'test post', 12345680, 1, 'https://example.com/users/test-user2/posts/1235', null, null, false, VALUES (1235, 2, null, 'test post', 12345680, 1, 'https://example.com/users/test-user2/posts/1235', null, null, false,
'https://example.com/users/test-user2/posts/1235') 'https://example.com/users/test-user2/posts/1235', false)

View File

@ -1,9 +1,10 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.', VALUES (1, 'test-user', 'example.com', 'Im test user.', 'THis account is test user.',
'https://example.com/users/test-user/inbox', 'https://example.com/users/test-user/inbox',
'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user', 'https://example.com/users/test-user/outbox', 'https://example.com/users/test-user',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following', 'https://example.com/users/test-user#pubkey', 'https://example.com/users/test-user/following',
'https://example.com/users/test-users/followers', null, false); 'https://example.com/users/test-users/followers', null, false, 0, 0, 0, null);

View File

@ -1,9 +1,10 @@
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, insert into "actors" (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED) created_at, key_id, following, followers, instance, locked, following_count, followers_count,
posts_count, last_post_at)
VALUES (2, 'test-user2', 'example.com', 'Im test user.', 'THis account is test user.', VALUES (2, 'test-user2', 'example.com', 'Im test user.', 'THis account is test user.',
'https://example.com/users/test-user2/inbox', 'https://example.com/users/test-user2/inbox',
'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2', 'https://example.com/users/test-user2/outbox', 'https://example.com/users/test-user2',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
'-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678,
'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following', 'https://example.com/users/test-user2#pubkey', 'https://example.com/users/test-user2/following',
'https://example.com/users/test-user2s/followers', null, false); 'https://example.com/users/test-user2s/followers', null, false, 0, 0, 0, null);

View File

@ -22,7 +22,11 @@ data class Actor private constructor(
val followers: String? = null, val followers: String? = null,
val following: String? = null, val following: String? = null,
val instance: Long? = null, val instance: Long? = null,
val locked: Boolean val locked: Boolean,
val followersCount: Int = 0,
val followingCount: Int = 0,
val postsCount: Int = 0,
val lastPostDate: Instant? = null
) { ) {
@Component @Component
@ -47,7 +51,11 @@ data class Actor private constructor(
following: String? = null, following: String? = null,
followers: String? = null, followers: String? = null,
instance: Long? = null, instance: Long? = null,
locked: Boolean locked: Boolean,
followersCount: Int = 0,
followingCount: Int = 0,
postsCount: Int = 0,
lastPostDate: Instant? = null
): Actor { ): Actor {
// idは0未満ではいけない // idは0未満ではいけない
require(id >= 0) { "id must be greater than or equal to 0." } require(id >= 0) { "id must be greater than or equal to 0." }
@ -123,6 +131,18 @@ data class Actor private constructor(
"keyId must contain non-blank characters." "keyId must contain non-blank characters."
} }
require(postsCount >= 0) {
"postsCount must be greater than or equal to 0"
}
require(followersCount >= 0) {
"followersCount must be greater than or equal to 0"
}
require(followingCount >= 0) {
"followingCount must be greater than or equal to 0"
}
return Actor( return Actor(
id = id, id = id,
name = limitedName, name = limitedName,
@ -139,11 +159,29 @@ data class Actor private constructor(
followers = followers, followers = followers,
following = following, following = following,
instance = instance, instance = instance,
locked locked = locked,
followersCount = followersCount,
followingCount = followingCount,
postsCount = postsCount,
lastPostDate = lastPostDate
) )
} }
} }
fun incrementFollowing(): Actor = this.copy(followingCount = this.followingCount + 1)
fun decrementFollowing(): Actor = this.copy(followingCount = this.followingCount - 1)
fun incrementFollowers(): Actor = this.copy(followersCount = this.followersCount + 1)
fun decrementFollowers(): Actor = this.copy(followersCount = this.followersCount - 1)
fun incrementPostsCount(): Actor = this.copy(postsCount = this.postsCount + 1)
fun decrementPostsCount(): Actor = this.copy(postsCount = this.postsCount - 1)
fun withLastPostAt(lastPostDate: Instant): Actor = this.copy(lastPostDate = lastPostDate)
override fun toString(): String { override fun toString(): String {
return "Actor(" + return "Actor(" +
"id=$id, " + "id=$id, " +

View File

@ -26,7 +26,11 @@ class UserResultRowMapper(private val actorBuilder: Actor.UserBuilder) : ResultR
followers = resultRow[Actors.followers], followers = resultRow[Actors.followers],
following = resultRow[Actors.following], following = resultRow[Actors.following],
instance = resultRow[Actors.instance], instance = resultRow[Actors.instance],
locked = resultRow[Actors.locked] locked = resultRow[Actors.locked],
followingCount = resultRow[Actors.followingCount],
followersCount = resultRow[Actors.followersCount],
postsCount = resultRow[Actors.postsCount],
lastPostDate = resultRow[Actors.lastPostAt],
) )
} }
} }

View File

@ -6,6 +6,7 @@ import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.javatime.timestamp
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
@Repository @Repository
@ -35,6 +36,10 @@ class ActorRepositoryImpl(
it[followers] = actor.followers it[followers] = actor.followers
it[instance] = actor.instance it[instance] = actor.instance
it[locked] = actor.locked it[locked] = actor.locked
it[followersCount] = actor.followersCount
it[followingCount] = actor.followingCount
it[postsCount] = actor.postsCount
it[lastPostAt] = actor.lastPostDate
} }
} else { } else {
Actors.update({ Actors.id eq actor.id }) { Actors.update({ Actors.id eq actor.id }) {
@ -53,6 +58,10 @@ class ActorRepositoryImpl(
it[followers] = actor.followers it[followers] = actor.followers
it[instance] = actor.instance it[instance] = actor.instance
it[locked] = actor.locked it[locked] = actor.locked
it[followersCount] = actor.followersCount
it[followingCount] = actor.followingCount
it[postsCount] = actor.postsCount
it[lastPostAt] = actor.lastPostDate
} }
} }
return actor return actor
@ -91,6 +100,10 @@ object Actors : Table("actors") {
val followers = varchar("followers", length = 1000).nullable() val followers = varchar("followers", length = 1000).nullable()
val instance = long("instance").references(Instance.id).nullable() val instance = long("instance").references(Instance.id).nullable()
val locked = bool("locked") val locked = bool("locked")
val followingCount = integer("following_count")
val followersCount = integer("followers_count")
val postsCount = integer("posts_count")
val lastPostAt = timestamp("last_post_at").nullable()
override val primaryKey: PrimaryKey = PrimaryKey(id) override val primaryKey: PrimaryKey = PrimaryKey(id)

View File

@ -2,6 +2,7 @@ package dev.usbharu.hideout.core.service.post
import dev.usbharu.hideout.activitypub.service.activity.create.ApSendCreateService import dev.usbharu.hideout.activitypub.service.activity.create.ApSendCreateService
import dev.usbharu.hideout.core.domain.exception.UserNotFoundException import dev.usbharu.hideout.core.domain.exception.UserNotFoundException
import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.post.Post import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.domain.model.post.PostRepository import dev.usbharu.hideout.core.domain.model.post.PostRepository
@ -35,7 +36,9 @@ class PostServiceImpl(
override suspend fun createRemote(post: Post): Post { override suspend fun createRemote(post: Post): Post {
logger.info("START Create Remote Post user: {}, remote url: {}", post.actorId, post.apId) logger.info("START Create Remote Post user: {}, remote url: {}", post.actorId, post.apId)
val createdPost = internalCreate(post, false) val actor =
actorRepository.findById(post.actorId) ?: throw UserNotFoundException("${post.actorId} was not found.")
val createdPost = internalCreate(post, false, actor)
logger.info("SUCCESS Create Remote Post url: {}", createdPost.url) logger.info("SUCCESS Create Remote Post url: {}", createdPost.url)
return createdPost return createdPost
} }
@ -46,6 +49,10 @@ class PostServiceImpl(
} }
reactionRepository.deleteByPostId(post.id) reactionRepository.deleteByPostId(post.id)
postRepository.save(post.delete()) postRepository.save(post.delete())
val actor = actorRepository.findById(post.actorId)
?: throw IllegalStateException("actor: ${post.actorId} was not found.")
actorRepository.save(actor.decrementPostsCount())
} }
override suspend fun deleteRemote(post: Post) { override suspend fun deleteRemote(post: Post) {
@ -54,17 +61,28 @@ class PostServiceImpl(
} }
reactionRepository.deleteByPostId(post.id) reactionRepository.deleteByPostId(post.id)
postRepository.save(post.delete()) postRepository.save(post.delete())
val actor = actorRepository.findById(post.actorId)
?: throw IllegalStateException("actor: ${post.actorId} was not found.")
actorRepository.save(actor.decrementPostsCount())
} }
override suspend fun deleteByActor(actorId: Long) { override suspend fun deleteByActor(actorId: Long) {
postQueryService.findByActorId(actorId).filterNot { it.delted }.forEach { postRepository.save(it.delete()) } postQueryService.findByActorId(actorId).filterNot { it.delted }.forEach { postRepository.save(it.delete()) }
val actor = actorRepository.findById(actorId)
?: throw IllegalStateException("actor: $actorId was not found.")
actorRepository.save(actor.copy(postsCount = 0, lastPostDate = null))
} }
private suspend fun internalCreate(post: Post, isLocal: Boolean): Post { private suspend fun internalCreate(post: Post, isLocal: Boolean, actor: Actor): Post {
return try { return try {
if (postRepository.save(post)) { if (postRepository.save(post)) {
try { try {
timelineService.publishTimeline(post, isLocal) timelineService.publishTimeline(post, isLocal)
actorRepository.save(actor.incrementPostsCount())
} catch (e: DuplicateKeyException) { } catch (e: DuplicateKeyException) {
logger.trace("Timeline already exists.", e) logger.trace("Timeline already exists.", e)
} }
@ -91,7 +109,7 @@ class PostServiceImpl(
replyId = post.repolyId, replyId = post.repolyId,
repostId = post.repostId, repostId = post.repostId,
) )
return internalCreate(createPost, isLocal) return internalCreate(createPost, isLocal, user)
} }
companion object { companion object {

View File

@ -8,6 +8,7 @@ import dev.usbharu.hideout.activitypub.service.activity.undo.APSendUndoService
import dev.usbharu.hideout.application.config.ApplicationConfig import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
import dev.usbharu.hideout.core.domain.model.actor.Actor import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.model.relationship.Relationship
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.query.ActorQueryService import dev.usbharu.hideout.core.query.ActorQueryService
@ -24,7 +25,8 @@ class RelationshipServiceImpl(
private val apSendBlockService: APSendBlockService, private val apSendBlockService: APSendBlockService,
private val apSendAcceptService: ApSendAcceptService, private val apSendAcceptService: ApSendAcceptService,
private val apSendRejectService: ApSendRejectService, private val apSendRejectService: ApSendRejectService,
private val apSendUndoService: APSendUndoService private val apSendUndoService: APSendUndoService,
private val actorRepository: ActorRepository
) : RelationshipService { ) : RelationshipService {
override suspend fun followRequest(actorId: Long, targetId: Long) { override suspend fun followRequest(actorId: Long, targetId: Long) {
logger.info("START Follow Request userId: {} targetId: {}", actorId, targetId) logger.info("START Follow Request userId: {} targetId: {}", actorId, targetId)
@ -90,6 +92,15 @@ class RelationshipServiceImpl(
override suspend fun block(actorId: Long, targetId: Long) { override suspend fun block(actorId: Long, targetId: Long) {
val relationship = relationshipRepository.findByUserIdAndTargetUserId(actorId, targetId) val relationship = relationshipRepository.findByUserIdAndTargetUserId(actorId, targetId)
val user = actorQueryService.findById(actorId)
val targetActor = actorQueryService.findById(targetId)
if (relationship?.following == true) {
actorRepository.save(user.decrementFollowing())
actorRepository.save(targetActor.decrementFollowers())
}
val blockedRelationship = relationship
?.copy(blocking = true, followRequest = false, following = false) ?: Relationship( ?.copy(blocking = true, followRequest = false, following = false) ?: Relationship(
actorId = actorId, actorId = actorId,
targetActorId = targetId, targetActorId = targetId,
@ -101,17 +112,23 @@ class RelationshipServiceImpl(
) )
val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId) val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId)
if (inverseRelationship?.following == true) {
actorRepository.save(targetActor.decrementFollowing())
actorRepository.save(user.decrementFollowers())
}
val blockedInverseRelationship = inverseRelationship
?.copy(followRequest = false, following = false) ?.copy(followRequest = false, following = false)
relationshipRepository.save(relationship) relationshipRepository.save(blockedRelationship)
if (inverseRelationship != null) { if (blockedInverseRelationship != null) {
relationshipRepository.save(inverseRelationship) relationshipRepository.save(blockedInverseRelationship)
} }
val remoteUser = isRemoteUser(targetId) val remoteUser = isRemoteUser(targetId)
if (remoteUser != null) { if (remoteUser != null) {
val user = actorQueryService.findById(actorId)
apSendBlockService.sendBlock(user, remoteUser) apSendBlockService.sendBlock(user, remoteUser)
} }
} }
@ -157,13 +174,18 @@ class RelationshipServiceImpl(
val copy = relationship.copy(followRequest = false, following = true, blocking = false) val copy = relationship.copy(followRequest = false, following = true, blocking = false)
val user = actorQueryService.findById(actorId)
actorRepository.save(user.incrementFollowers())
relationshipRepository.save(copy) relationshipRepository.save(copy)
val remoteUser = isRemoteUser(targetId) val remoteActor = actorQueryService.findById(targetId)
if (remoteUser != null) { actorRepository.save(remoteActor.incrementFollowing())
val user = actorQueryService.findById(actorId)
apSendAcceptService.sendAcceptFollow(user, remoteUser) if (isRemoteActor(remoteActor)) {
apSendAcceptService.sendAcceptFollow(user, remoteActor)
} }
} }
@ -216,6 +238,14 @@ class RelationshipServiceImpl(
return return
} }
val user = actorQueryService.findById(actorId)
val targetActor = actorQueryService.findById(targetId)
if (relationship.following) {
actorRepository.save(user.decrementFollowing())
actorRepository.save(targetActor.decrementFollowers())
}
if (relationship.following.not()) { if (relationship.following.not()) {
logger.warn("SUCCESS User already unfollow. userId: {} targetId: {}", actorId, targetId) logger.warn("SUCCESS User already unfollow. userId: {} targetId: {}", actorId, targetId)
return return
@ -228,7 +258,6 @@ class RelationshipServiceImpl(
val remoteUser = isRemoteUser(targetId) val remoteUser = isRemoteUser(targetId)
if (remoteUser != null) { if (remoteUser != null) {
val user = actorQueryService.findById(actorId)
apSendUndoService.sendUndoFollow(user, remoteUser) apSendUndoService.sendUndoFollow(user, remoteUser)
} }
} }
@ -282,6 +311,8 @@ class RelationshipServiceImpl(
relationshipRepository.save(relationship) relationshipRepository.save(relationship)
} }
private fun isRemoteActor(actor: Actor): Boolean = actor.domain != applicationConfig.url.host
private suspend fun isRemoteUser(userId: Long): Actor? { private suspend fun isRemoteUser(userId: Long): Actor? {
logger.trace("isRemoteUser({})", userId) logger.trace("isRemoteUser({})", userId)
val user = try { val user = try {

View File

@ -2,81 +2,34 @@ package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.application.config.ApplicationConfig import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
import dev.usbharu.hideout.core.domain.model.relationship.Relationships
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts
import dev.usbharu.hideout.domain.mastodon.model.generated.Account import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.mastodon.query.AccountQueryService import dev.usbharu.hideout.mastodon.query.AccountQueryService
import dev.usbharu.hideout.util.singleOr import dev.usbharu.hideout.util.singleOr
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.jetbrains.exposed.sql.select
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import java.time.Instant import java.time.Instant
@Repository @Repository
class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService { class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService {
override suspend fun findById(accountId: Long): Account { override suspend fun findById(accountId: Long): Account {
val followingCount = Count(Relationships.actorId.eq(Actors.id), true).alias("following_count") val query = Actors.select { Actors.id eq accountId }
val followersCount = Count(Relationships.targetActorId.eq(Actors.id), true).alias("followers_count")
val postsCount = Posts.id.countDistinct().alias("posts_count")
val lastCreated = Posts.createdAt.max().alias("last_created")
val query = Actors
.join(Relationships, JoinType.LEFT) {
Actors.id eq Relationships.actorId or (Actors.id eq Relationships.targetActorId)
}
.leftJoin(Posts)
.slice(
followingCount,
followersCount,
*(Actors.realFields.toTypedArray()),
lastCreated,
postsCount
)
.select {
(Actors.id.eq(accountId)).and(
Relationships.following.eq(true).or(Relationships.following.isNull())
)
}
.groupBy(Actors.id)
return query return query
.singleOr { FailedToGetResourcesException("accountId: $accountId wad not exist or duplicate", it) } .singleOr { FailedToGetResourcesException("accountId: $accountId wad not exist or duplicate", it) }
.let { toAccount(it, followingCount, followersCount, postsCount, lastCreated) } .let { toAccount(it) }
} }
override suspend fun findByIds(accountIds: List<Long>): List<Account> { override suspend fun findByIds(accountIds: List<Long>): List<Account> {
val followingCount = Count(Relationships.actorId.eq(Actors.id), true).alias("following_count") val query = Actors.select { Actors.id inList accountIds }
val followersCount = Count(Relationships.targetActorId.eq(Actors.id), true).alias("followers_count")
val postsCount = Posts.id.countDistinct().alias("posts_count")
val lastCreated = Posts.createdAt.max().alias("last_created")
val query = Actors
.join(Relationships, JoinType.LEFT) {
Actors.id eq Relationships.actorId or (Actors.id eq Relationships.targetActorId)
}
.leftJoin(Posts)
.slice(
followingCount,
followersCount,
*(Actors.realFields.toTypedArray()),
lastCreated,
postsCount
)
.select {
Actors.id.inList(accountIds)
.and(Relationships.following.eq(true).or(Relationships.following.isNull()))
}
.groupBy(Actors.id)
return query return query
.map { toAccount(it, followingCount, followersCount, postsCount, lastCreated) } .map { toAccount(it) }
} }
private fun toAccount( private fun toAccount(
resultRow: ResultRow, resultRow: ResultRow
followingCount: ExpressionAlias<Long>,
followersCount: ExpressionAlias<Long>,
postsCount: ExpressionAlias<Long>,
lastCreated: ExpressionAlias<Long?>
): Account { ): Account {
val userUrl = "${applicationConfig.url}/users/${resultRow[Actors.id]}" val userUrl = "${applicationConfig.url}/users/${resultRow[Actors.id]}"
@ -98,10 +51,10 @@ class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig)
group = false, group = false,
discoverable = true, discoverable = true,
createdAt = Instant.ofEpochMilli(resultRow[Actors.createdAt]).toString(), createdAt = Instant.ofEpochMilli(resultRow[Actors.createdAt]).toString(),
lastStatusAt = resultRow[lastCreated]?.let { Instant.ofEpochMilli(it).toString() }, lastStatusAt = resultRow[Actors.lastPostAt]?.toString(),
statusesCount = resultRow[postsCount].toInt(), statusesCount = resultRow[Actors.postsCount],
followersCount = resultRow[followersCount].toInt(), followersCount = resultRow[Actors.followersCount],
followingCount = resultRow[followingCount].toInt(), followingCount = resultRow[Actors.followingCount],
) )
} }
} }

View File

@ -151,17 +151,17 @@ private fun toStatus(it: ResultRow) = Status(
avatarStatic = it[Actors.url] + "/icon.jpg", avatarStatic = it[Actors.url] + "/icon.jpg",
header = it[Actors.url] + "/header.jpg", header = it[Actors.url] + "/header.jpg",
headerStatic = it[Actors.url] + "/header.jpg", headerStatic = it[Actors.url] + "/header.jpg",
locked = false, locked = it[Actors.locked],
fields = emptyList(), fields = emptyList(),
emojis = emptyList(), emojis = emptyList(),
bot = false, bot = false,
group = false, group = false,
discoverable = true, discoverable = true,
createdAt = Instant.ofEpochMilli(it[Actors.createdAt]).toString(), createdAt = Instant.ofEpochMilli(it[Actors.createdAt]).toString(),
lastStatusAt = Instant.ofEpochMilli(it[Actors.createdAt]).toString(), lastStatusAt = it[Actors.lastPostAt]?.toString(),
statusesCount = 0, statusesCount = it[Actors.postsCount],
followersCount = 0, followersCount = it[Actors.followersCount],
followingCount = 0, followingCount = it[Actors.followingCount],
noindex = false, noindex = false,
moved = false, moved = false,
suspendex = false, suspendex = false,

View File

@ -15,22 +15,26 @@ create table if not exists instance
); );
create table if not exists actors create table if not exists actors
( (
id bigint primary key, id bigint primary key,
"name" varchar(300) not null, "name" varchar(300) not null,
"domain" varchar(1000) not null, "domain" varchar(1000) not null,
screen_name varchar(300) not null, screen_name varchar(300) not null,
description varchar(10000) not null, description varchar(10000) not null,
inbox varchar(1000) not null unique, inbox varchar(1000) not null unique,
outbox varchar(1000) not null unique, outbox varchar(1000) not null unique,
url varchar(1000) not null unique, url varchar(1000) not null unique,
public_key varchar(10000) not null, public_key varchar(10000) not null,
private_key varchar(10000) null, private_key varchar(10000) null,
created_at bigint not null, created_at bigint not null,
key_id varchar(1000) not null, key_id varchar(1000) not null,
"following" varchar(1000) null, "following" varchar(1000) null,
followers varchar(1000) null, followers varchar(1000) null,
"instance" bigint null, "instance" bigint null,
locked boolean not null, locked boolean not null,
following_count int not null,
followers_count int not null,
posts_count int not null,
last_post_at timestamp null default null,
unique ("name", "domain"), unique ("name", "domain"),
constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict constraint fk_actors_instance__id foreign key ("instance") references instance (id) on delete restrict on update restrict
); );
@ -200,8 +204,9 @@ create table if not exists relationships
); );
insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at, insert into actors (id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at,
key_id, following, followers, instance, locked) key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
values (0, 'ghost', '', '', '', '', '', '', '', null, 0, '', '', '', null, true); last_post_at)
values (0, 'ghost', '', '', '', '', '', '', '', null, 0, '', '', '', null, true, 0, 0, 0, null);
create table if not exists deleted_actors create table if not exists deleted_actors
( (

View File

@ -90,9 +90,11 @@ class PostServiceImplTest {
fun `createRemote 正常にリモートのpostを作成できる`() = runTest { fun `createRemote 正常にリモートのpostを作成できる`() = runTest {
val post = PostBuilder.of() val post = PostBuilder.of()
whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId))
whenever(postRepository.save(eq(post))).doReturn(true) whenever(postRepository.save(eq(post))).doReturn(true)
whenever(timelineService.publishTimeline(eq(post), eq(false))).doReturn(Unit) whenever(timelineService.publishTimeline(eq(post), eq(false))).doReturn(Unit)
val createLocal = postServiceImpl.createRemote(post) val createLocal = postServiceImpl.createRemote(post)
assertThat(createLocal).isEqualTo(post) assertThat(createLocal).isEqualTo(post)
@ -106,6 +108,7 @@ class PostServiceImplTest {
fun `createRemote 既に作成されていた場合はそのまま帰す`() = runTest { fun `createRemote 既に作成されていた場合はそのまま帰す`() = runTest {
val post = PostBuilder.of() val post = PostBuilder.of()
whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId))
whenever(postRepository.save(eq(post))).doReturn(false) whenever(postRepository.save(eq(post))).doReturn(false)
val createLocal = postServiceImpl.createRemote(post) val createLocal = postServiceImpl.createRemote(post)
@ -120,6 +123,7 @@ class PostServiceImplTest {
fun `createRemote 既に作成されていることを検知できず例外が発生した場合はDBから取得して返す`() = runTest { fun `createRemote 既に作成されていることを検知できず例外が発生した場合はDBから取得して返す`() = runTest {
val post = PostBuilder.of() val post = PostBuilder.of()
whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId))
whenever(postRepository.save(eq(post))).doAnswer { throw ExposedSQLException(null, emptyList(), mock()) } whenever(postRepository.save(eq(post))).doAnswer { throw ExposedSQLException(null, emptyList(), mock()) }
whenever(postQueryService.findByApId(eq(post.apId))).doReturn(post) whenever(postQueryService.findByApId(eq(post.apId))).doReturn(post)
@ -135,6 +139,7 @@ class PostServiceImplTest {
fun `createRemote 既に作成されていることを検知出来ずタイムラインにpush出来なかった場合何もしない`() = runTest { fun `createRemote 既に作成されていることを検知出来ずタイムラインにpush出来なかった場合何もしない`() = runTest {
val post = PostBuilder.of() val post = PostBuilder.of()
whenever(actorRepository.findById(eq(post.actorId))).doReturn(UserBuilder.remoteUserOf(id = post.actorId))
whenever(postRepository.save(eq(post))).doReturn(true) whenever(postRepository.save(eq(post))).doReturn(true)
whenever(timelineService.publishTimeline(eq(post), eq(false))).doThrow(DuplicateKeyException::class) whenever(timelineService.publishTimeline(eq(post), eq(false))).doThrow(DuplicateKeyException::class)

View File

@ -6,6 +6,7 @@ import dev.usbharu.hideout.activitypub.service.activity.follow.APSendFollowServi
import dev.usbharu.hideout.activitypub.service.activity.reject.ApSendRejectService import dev.usbharu.hideout.activitypub.service.activity.reject.ApSendRejectService
import dev.usbharu.hideout.activitypub.service.activity.undo.APSendUndoService import dev.usbharu.hideout.activitypub.service.activity.undo.APSendUndoService
import dev.usbharu.hideout.application.config.ApplicationConfig import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.relationship.Relationship import dev.usbharu.hideout.core.domain.model.relationship.Relationship
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.query.ActorQueryService import dev.usbharu.hideout.core.query.ActorQueryService
@ -49,6 +50,9 @@ class RelationshipServiceImplTest {
@Mock @Mock
private lateinit var apSendUndoService: APSendUndoService private lateinit var apSendUndoService: APSendUndoService
@Mock
private lateinit var actorRepository: ActorRepository
@InjectMocks @InjectMocks
private lateinit var relationshipServiceImpl: RelationshipServiceImpl private lateinit var relationshipServiceImpl: RelationshipServiceImpl
@ -209,6 +213,7 @@ class RelationshipServiceImplTest {
@Test @Test
fun `block ローカルユーザーの場合永続化される`() = runTest { fun `block ローカルユーザーの場合永続化される`() = runTest {
whenever(actorQueryService.findById(eq(1234))).doReturn(UserBuilder.localUserOf(domain = "example.com"))
whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com"))
relationshipServiceImpl.block(1234, 5678) relationshipServiceImpl.block(1234, 5678)
@ -256,6 +261,7 @@ class RelationshipServiceImplTest {
@Test @Test
fun `acceptFollowRequest ローカルユーザーの場合永続化される`() = runTest { fun `acceptFollowRequest ローカルユーザーの場合永続化される`() = runTest {
whenever(actorQueryService.findById(eq(1234))).doReturn(UserBuilder.localUserOf(domain = "example.com"))
whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com"))
whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn(
@ -347,6 +353,7 @@ class RelationshipServiceImplTest {
@Test @Test
fun `acceptFollowRequest フォローリクエストが存在せずforceがtrueのときフォローを承認する`() = runTest { fun `acceptFollowRequest フォローリクエストが存在せずforceがtrueのときフォローを承認する`() = runTest {
whenever(actorQueryService.findById(eq(1234))).doReturn(UserBuilder.localUserOf(domain = "example.com"))
whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.remoteUserOf(domain = "remote.example.com")) whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.remoteUserOf(domain = "remote.example.com"))
whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn( whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(5678), eq(1234))).doReturn(
@ -530,6 +537,7 @@ class RelationshipServiceImplTest {
@Test @Test
fun `unfollow ローカルユーザーの場合永続化される`() = runTest { fun `unfollow ローカルユーザーの場合永続化される`() = runTest {
whenever(actorQueryService.findById(eq(1234))).doReturn(UserBuilder.remoteUserOf(domain = "remote.example.com"))
whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com")) whenever(actorQueryService.findById(eq(5678))).doReturn(UserBuilder.localUserOf(domain = "example.com"))
whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn( whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(1234), eq(5678))).doReturn(
Relationship( Relationship(