Merge pull request #209 from usbharu/feature/auto_accept_follow_request

Feature/auto accept follow request
This commit is contained in:
usbharu 2023-12-12 17:04:14 +09:00 committed by GitHub
commit 14149001c9
42 changed files with 649 additions and 163 deletions

View File

@ -1,5 +1,5 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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,8 +43,8 @@ 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); 'http://localhost/users/test-users/followers', null, false);
insert into user_details (actor_id, password, auto_accept_follow_request, auto_accept_followee_follow_request) insert into user_details (actor_id, password, auto_accept_followee_follow_request)
values ( 1730415786666758144 values ( 1730415786666758144
, '$2a$10$/mWC/n7nC7X3l9qCEOKnredxne2zewoqEsJWTOdlKfg2zXKJ0F9Em', true, true) , '$2a$10$/mWC/n7nC7X3l9qCEOKnredxne2zewoqEsJWTOdlKfg2zXKJ0F9Em', true)

View File

@ -1,16 +1,16 @@
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) created_at, key_id, following, followers, instance, locked)
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), 'https://example.com/users/follow-test-user-1/followers', null, false),
(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); 'https://example.com/users/follow-test-user-2/followers', null, false);

View File

@ -1,23 +1,20 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user8/followers', null, false),
(9, 'test-user9', 'follower.example.com', 'Im test-user9.', 'THis account is test-user9.',
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE)
VALUES (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',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
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); 'https://follower.example.com/users/test-user9/followers', null, false);
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,24 +1,20 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user4/followers', null, false),
(5, 'test-user5', 'follower.example.com', 'Im test user5.', 'THis account is test user5.',
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE)
VALUES (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',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
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); 'https://follower.example.com/users/test-user5/followers', null, false);
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,23 +1,20 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user6/followers', null, false),
(7, 'test-user7', 'follower.example.com', 'Im test-user7.', 'THis account is test-user7.',
insert into "actors" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY,
CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE)
VALUES (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',
'-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----',
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); 'https://follower.example.com/users/test-user7/followers', null, false);
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,12 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user11/followers', null, 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)

View File

@ -1,12 +1,12 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user10/followers', null, 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)

View File

@ -1,12 +1,12 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user3/followers', null, 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)

View File

@ -1,12 +1,12 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-users/followers', null, 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)

View File

@ -1,12 +1,12 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user2/followers', null, 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)

View File

@ -1,9 +1,9 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-users/followers', null, false);

View File

@ -1,9 +1,9 @@
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) CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS, INSTANCE, LOCKED)
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); 'https://example.com/users/test-user2s/followers', null, false);

View File

@ -17,10 +17,10 @@ constructor(
var publicKey: Key, var publicKey: Key,
var endpoints: Map<String, String> = emptyMap(), var endpoints: Map<String, String> = emptyMap(),
var followers: String?, var followers: String?,
var following: String? var following: String?,
val manuallyApprovesFollowers: Boolean? = false
) : Object(add(type, "Person")), HasId, HasName { ) : Object(add(type, "Person")), HasId, HasName {
@Suppress("CyclomaticComplexMethod", "CognitiveComplexMethod")
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (javaClass != other?.javaClass) return false if (javaClass != other?.javaClass) return false
@ -40,11 +40,11 @@ constructor(
if (endpoints != other.endpoints) return false if (endpoints != other.endpoints) return false
if (followers != other.followers) return false if (followers != other.followers) return false
if (following != other.following) return false if (following != other.following) return false
if (manuallyApprovesFollowers != other.manuallyApprovesFollowers) return false
return true return true
} }
@Suppress("CyclomaticComplexMethod")
override fun hashCode(): Int { override fun hashCode(): Int {
var result = super.hashCode() var result = super.hashCode()
result = 31 * result + name.hashCode() result = 31 * result + name.hashCode()
@ -59,6 +59,26 @@ constructor(
result = 31 * result + endpoints.hashCode() result = 31 * result + endpoints.hashCode()
result = 31 * result + (followers?.hashCode() ?: 0) result = 31 * result + (followers?.hashCode() ?: 0)
result = 31 * result + (following?.hashCode() ?: 0) result = 31 * result + (following?.hashCode() ?: 0)
result = 31 * result + manuallyApprovesFollowers.hashCode()
return result return result
} }
override fun toString(): String {
return "Person(" +
"name='$name', " +
"id='$id', " +
"preferredUsername=$preferredUsername, " +
"summary=$summary, " +
"inbox='$inbox', " +
"outbox='$outbox', " +
"url='$url', " +
"icon=$icon, " +
"publicKey=$publicKey, " +
"endpoints=$endpoints, " +
"followers=$followers, " +
"following=$following, " +
"manuallyApprovesFollowers=$manuallyApprovesFollowers" +
")" +
" ${super.toString()}"
}
} }

View File

@ -68,7 +68,8 @@ class APUserServiceImpl(
), ),
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox"), endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox"),
followers = userEntity.followers, followers = userEntity.followers,
following = userEntity.following following = userEntity.following,
manuallyApprovesFollowers = userEntity.locked
) )
} }
@ -104,7 +105,8 @@ class APUserServiceImpl(
keyId = person.publicKey.id, keyId = person.publicKey.id,
following = person.following, following = person.following,
followers = person.followers, followers = person.followers,
sharedInbox = person.endpoints["sharedInbox"] sharedInbox = person.endpoints["sharedInbox"],
locked = person.manuallyApprovesFollowers
) )
) )
} }
@ -134,6 +136,7 @@ class APUserServiceImpl(
), ),
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox"), endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox"),
followers = actorEntity.followers, followers = actorEntity.followers,
following = actorEntity.following following = actorEntity.following,
manuallyApprovesFollowers = actorEntity.locked
) )
} }

View File

@ -21,7 +21,8 @@ data class Actor private constructor(
val keyId: String, val keyId: String,
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
) { ) {
@ -46,7 +47,8 @@ data class Actor private constructor(
keyId: String, keyId: String,
following: String? = null, following: String? = null,
followers: String? = null, followers: String? = null,
instance: Long? = null instance: Long? = null,
locked: Boolean
): 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." }
@ -137,7 +139,8 @@ data class Actor private constructor(
keyId = keyId, keyId = keyId,
followers = followers, followers = followers,
following = following, following = following,
instance = instance instance = instance,
locked
) )
} }
} }
@ -158,7 +161,10 @@ data class Actor private constructor(
"keyId='$keyId', " + "keyId='$keyId', " +
"followers=$followers, " + "followers=$followers, " +
"following=$following, " + "following=$following, " +
"instance=$instance" + "instance=$instance, " +
"locked=$locked" +
")" ")"
} }
} }

View File

@ -9,7 +9,7 @@ package dev.usbharu.hideout.core.domain.model.relationship
* @property blocking ブロックしているか * @property blocking ブロックしているか
* @property muting ミュートしているか * @property muting ミュートしているか
* @property followRequest フォローリクエストを送っているか * @property followRequest フォローリクエストを送っているか
* @property ignoreFollowRequestFromTarget フォローリクエストを無視しているか * @property ignoreFollowRequestToTarget フォローリクエストを無視しているか
*/ */
data class Relationship( data class Relationship(
val actorId: Long, val actorId: Long,
@ -18,5 +18,5 @@ data class Relationship(
val blocking: Boolean, val blocking: Boolean,
val muting: Boolean, val muting: Boolean,
val followRequest: Boolean, val followRequest: Boolean,
val ignoreFollowRequestFromTarget: Boolean val ignoreFollowRequestToTarget: Boolean
) )

View File

@ -25,7 +25,7 @@ class RelationshipRepositoryImpl : RelationshipRepository {
it[blocking] = relationship.blocking it[blocking] = relationship.blocking
it[muting] = relationship.muting it[muting] = relationship.muting
it[followRequest] = relationship.followRequest it[followRequest] = relationship.followRequest
it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestFromTarget it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestToTarget
} }
} else { } else {
Relationships Relationships
@ -37,7 +37,7 @@ class RelationshipRepositoryImpl : RelationshipRepository {
it[blocking] = relationship.blocking it[blocking] = relationship.blocking
it[muting] = relationship.muting it[muting] = relationship.muting
it[followRequest] = relationship.followRequest it[followRequest] = relationship.followRequest
it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestFromTarget it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestToTarget
} }
} }
return relationship return relationship
@ -66,7 +66,7 @@ fun ResultRow.toRelationships(): Relationship = Relationship(
blocking = this[Relationships.blocking], blocking = this[Relationships.blocking],
muting = this[Relationships.muting], muting = this[Relationships.muting],
followRequest = this[Relationships.followRequest], followRequest = this[Relationships.followRequest],
ignoreFollowRequestFromTarget = this[Relationships.ignoreFollowRequestFromTarget] ignoreFollowRequestToTarget = this[Relationships.ignoreFollowRequestFromTarget]
) )
object Relationships : LongIdTable("relationships") { object Relationships : LongIdTable("relationships") {

View File

@ -3,6 +3,5 @@ package dev.usbharu.hideout.core.domain.model.userdetails
data class UserDetail( data class UserDetail(
val actorId: Long, val actorId: Long,
val password: String, val password: String,
val autoAcceptFollowRequest: Boolean,
val autoAcceptFolloweeFollowRequest: Boolean val autoAcceptFolloweeFollowRequest: Boolean
) )

View File

@ -25,7 +25,8 @@ class UserResultRowMapper(private val actorBuilder: Actor.UserBuilder) : ResultR
keyId = resultRow[Actors.keyId], keyId = resultRow[Actors.keyId],
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]
) )
} }
} }

View File

@ -5,6 +5,7 @@ import dev.usbharu.hideout.core.domain.model.relationship.Relationships
import dev.usbharu.hideout.core.domain.model.relationship.toRelationships import dev.usbharu.hideout.core.domain.model.relationship.toRelationships
import dev.usbharu.hideout.core.query.RelationshipQueryService import dev.usbharu.hideout.core.query.RelationshipQueryService
import org.jetbrains.exposed.sql.and import org.jetbrains.exposed.sql.and
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.select import org.jetbrains.exposed.sql.select
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -13,4 +14,30 @@ class RelationshipQueryServiceImpl : RelationshipQueryService {
override suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship> = override suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship> =
Relationships.select { Relationships.targetActorId eq targetId and (Relationships.following eq following) } Relationships.select { Relationships.targetActorId eq targetId and (Relationships.following eq following) }
.map { it.toRelationships() } .map { it.toRelationships() }
override suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
maxId: Long?,
sinceId: Long?,
limit: Int,
targetId: Long,
followRequest: Boolean,
ignoreFollowRequest: Boolean
): List<Relationship> {
val query = Relationships
.select {
Relationships.targetActorId.eq(targetId)
.and(Relationships.followRequest.eq(followRequest))
.and(Relationships.ignoreFollowRequestFromTarget.eq(ignoreFollowRequest))
}.limit(limit)
if (maxId != null) {
query.andWhere { Relationships.id greater maxId }
}
if (sinceId != null) {
query.andWhere { Relationships.id less sinceId }
}
return query.map { it.toRelationships() }
}
} }

View File

@ -34,6 +34,7 @@ class ActorRepositoryImpl(
it[following] = actor.following it[following] = actor.following
it[followers] = actor.followers it[followers] = actor.followers
it[instance] = actor.instance it[instance] = actor.instance
it[locked] = actor.locked
} }
} else { } else {
Actors.update({ Actors.id eq actor.id }) { Actors.update({ Actors.id eq actor.id }) {
@ -51,6 +52,7 @@ class ActorRepositoryImpl(
it[following] = actor.following it[following] = actor.following
it[followers] = actor.followers it[followers] = actor.followers
it[instance] = actor.instance it[instance] = actor.instance
it[locked] = actor.locked
} }
} }
return actor return actor
@ -88,6 +90,7 @@ object Actors : Table("actors") {
val following = varchar("following", length = 1000).nullable() val following = varchar("following", length = 1000).nullable()
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")
override val primaryKey: PrimaryKey = PrimaryKey(id) override val primaryKey: PrimaryKey = PrimaryKey(id)

View File

@ -18,13 +18,11 @@ class UserDetailRepositoryImpl : UserDetailRepository {
UserDetails.insert { UserDetails.insert {
it[actorId] = userDetail.actorId it[actorId] = userDetail.actorId
it[password] = userDetail.password it[password] = userDetail.password
it[autoAcceptFollowRequest] = userDetail.autoAcceptFollowRequest
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
} }
} else { } else {
UserDetails.update({ UserDetails.actorId eq userDetail.actorId }) { UserDetails.update({ UserDetails.actorId eq userDetail.actorId }) {
it[password] = userDetail.password it[password] = userDetail.password
it[autoAcceptFollowRequest] = userDetail.autoAcceptFollowRequest
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
} }
} }
@ -43,7 +41,6 @@ class UserDetailRepositoryImpl : UserDetailRepository {
UserDetail( UserDetail(
it[UserDetails.actorId], it[UserDetails.actorId],
it[UserDetails.password], it[UserDetails.password],
it[UserDetails.autoAcceptFollowRequest],
it[UserDetails.autoAcceptFolloweeFollowRequest] it[UserDetails.autoAcceptFolloweeFollowRequest]
) )
} }
@ -55,6 +52,5 @@ class UserDetailRepositoryImpl : UserDetailRepository {
object UserDetails : LongIdTable("user_details") { object UserDetails : LongIdTable("user_details") {
val actorId = long("actor_id").references(Actors.id) val actorId = long("actor_id").references(Actors.id)
val password = varchar("password", 255) val password = varchar("password", 255)
val autoAcceptFollowRequest = bool("auto_accept_follow_request")
val autoAcceptFolloweeFollowRequest = bool("auto_accept_followee_follow_request") val autoAcceptFolloweeFollowRequest = bool("auto_accept_followee_follow_request")
} }

View File

@ -5,4 +5,12 @@ import dev.usbharu.hideout.core.domain.model.relationship.Relationship
interface RelationshipQueryService { interface RelationshipQueryService {
suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship> suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship>
suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
maxId: Long?,
sinceId: Long?,
limit: Int,
targetId: Long,
followRequest: Boolean,
ignoreFollowRequest: Boolean
): List<Relationship>
} }

View File

@ -38,7 +38,7 @@ class RelationshipServiceImpl(
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId) ?: Relationship( val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId) ?: Relationship(
@ -48,7 +48,7 @@ class RelationshipServiceImpl(
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
if (inverseRelationship.blocking) { if (inverseRelationship.blocking) {
@ -60,7 +60,7 @@ class RelationshipServiceImpl(
logger.debug("FAILED Blocking user. userId: {} targetId: {}", actorId, targetId) logger.debug("FAILED Blocking user. userId: {} targetId: {}", actorId, targetId)
return return
} }
if (inverseRelationship.ignoreFollowRequestFromTarget) { if (relationship.ignoreFollowRequestToTarget) {
logger.debug("SUCCESS Ignore Follow Request. userId: {} targetId: {}", actorId, targetId) logger.debug("SUCCESS Ignore Follow Request. userId: {} targetId: {}", actorId, targetId)
return return
} }
@ -73,14 +73,17 @@ class RelationshipServiceImpl(
relationshipRepository.save(relationship) relationshipRepository.save(relationship)
val remoteUser = isRemoteUser(targetId) val remoteUser = isRemoteUser(targetId)
if (remoteUser != null) { if (remoteUser != null) {
val user = actorQueryService.findById(actorId) val user = actorQueryService.findById(actorId)
apSendFollowService.sendFollow(SendFollowDto(user, remoteUser)) apSendFollowService.sendFollow(SendFollowDto(user, remoteUser))
} else { } else {
// TODO: フォロー許可制ユーザーを実装したら消す val target = actorQueryService.findById(targetId)
acceptFollowRequest(targetId, actorId) if (target.locked.not()) {
acceptFollowRequest(targetId, actorId)
}
} }
logger.info("SUCCESS Follow Request userId: {} targetId: {}", actorId, targetId) logger.info("SUCCESS Follow Request userId: {} targetId: {}", actorId, targetId)
@ -95,7 +98,7 @@ class RelationshipServiceImpl(
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId) val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId)
@ -126,7 +129,7 @@ class RelationshipServiceImpl(
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
if (relationship == null) { if (relationship == null) {
@ -191,16 +194,16 @@ class RelationshipServiceImpl(
} }
override suspend fun ignoreFollowRequest(actorId: Long, targetId: Long) { override suspend fun ignoreFollowRequest(actorId: Long, targetId: Long) {
val relationship = relationshipRepository.findByUserIdAndTargetUserId(actorId, targetId) val relationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, actorId)
?.copy(ignoreFollowRequestFromTarget = true) ?.copy(ignoreFollowRequestToTarget = true)
?: Relationship( ?: Relationship(
actorId = actorId, actorId = targetId,
targetActorId = targetId, targetActorId = actorId,
following = false, following = false,
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = true ignoreFollowRequestToTarget = true
) )
relationshipRepository.save(relationship) relationshipRepository.save(relationship)
@ -263,7 +266,7 @@ class RelationshipServiceImpl(
blocking = false, blocking = false,
muting = true, muting = true,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
relationshipRepository.save(relationship) relationshipRepository.save(relationship)

View File

@ -12,5 +12,6 @@ data class RemoteUserCreateDto(
val keyId: String, val keyId: String,
val followers: String?, val followers: String?,
val following: String?, val following: String?,
val sharedInbox: String? val sharedInbox: String?,
val locked: Boolean?
) )

View File

@ -0,0 +1,12 @@
package dev.usbharu.hideout.core.service.user
import dev.usbharu.hideout.core.domain.model.media.Media
data class UpdateUserDto(
val screenName: String,
val description: String,
val avatarMedia: Media?,
val headerMedia: Media?,
val locked: Boolean,
val autoAcceptFolloweeFollowRequest: Boolean
)

View File

@ -11,4 +11,6 @@ interface UserService {
suspend fun createLocalUser(user: UserCreateDto): Actor suspend fun createLocalUser(user: UserCreateDto): Actor
suspend fun createRemoteUser(user: RemoteUserCreateDto): Actor suspend fun createRemoteUser(user: RemoteUserCreateDto): Actor
suspend fun updateUser(userId: Long, updateUserDto: UpdateUserDto)
} }

View File

@ -49,10 +49,11 @@ class UserServiceImpl(
createdAt = Instant.now(), createdAt = Instant.now(),
following = "$userUrl/following", following = "$userUrl/following",
followers = "$userUrl/followers", followers = "$userUrl/followers",
keyId = "$userUrl#pubkey" keyId = "$userUrl#pubkey",
locked = false
) )
val save = actorRepository.save(userEntity) val save = actorRepository.save(userEntity)
userDetailRepository.save(UserDetail(nextId, hashedPassword, true, true)) userDetailRepository.save(UserDetail(nextId, hashedPassword, true))
return save return save
} }
@ -82,7 +83,8 @@ class UserServiceImpl(
followers = user.followers, followers = user.followers,
following = user.following, following = user.following,
keyId = user.keyId, keyId = user.keyId,
instance = instance?.id instance = instance?.id,
locked = user.locked ?: false
) )
return try { return try {
val save = actorRepository.save(userEntity) val save = actorRepository.save(userEntity)
@ -94,6 +96,27 @@ class UserServiceImpl(
} }
} }
override suspend fun updateUser(userId: Long, updateUserDto: UpdateUserDto) {
val userDetail = userDetailRepository.findByActorId(userId)
?: throw IllegalArgumentException("userId: $userId was not found.")
val actor = actorRepository.findById(userId) ?: throw IllegalArgumentException("userId $userId was not found.")
actorRepository.save(
actor.copy(
screenName = updateUserDto.screenName,
description = updateUserDto.description,
locked = updateUserDto.locked
)
)
userDetailRepository.save(
userDetail.copy(
autoAcceptFolloweeFollowRequest = updateUserDto.autoAcceptFolloweeFollowRequest
)
)
}
companion object { companion object {
private val logger = LoggerFactory.getLogger(UserServiceImpl::class.java) private val logger = LoggerFactory.getLogger(UserServiceImpl::class.java)
} }

View File

@ -0,0 +1,100 @@
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.application.config.ApplicationConfig
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.Posts
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
import dev.usbharu.hideout.mastodon.query.AccountQueryService
import dev.usbharu.hideout.util.singleOr
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.springframework.stereotype.Repository
import java.time.Instant
@Repository
class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService {
override suspend fun findById(accountId: Long): Account {
val followingCount = Count(Relationships.actorId.eq(Actors.id), true).alias("following_count")
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
.singleOr { FailedToGetResourcesException("accountId: $accountId wad not exist or duplicate", it) }
.let { toAccount(it, followingCount, followersCount, postsCount, lastCreated) }
}
override suspend fun findByIds(accountIds: List<Long>): List<Account> {
val followingCount = Count(Relationships.actorId.eq(Actors.id), true).alias("following_count")
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
.map { toAccount(it, followingCount, followersCount, postsCount, lastCreated) }
}
private fun toAccount(
resultRow: ResultRow,
followingCount: ExpressionAlias<Long>,
followersCount: ExpressionAlias<Long>,
postsCount: ExpressionAlias<Long>,
lastCreated: ExpressionAlias<Long?>
): Account {
val userUrl = "${applicationConfig.url}/users/${resultRow[Actors.id]}"
return Account(
id = resultRow[Actors.id].toString(),
username = resultRow[Actors.name],
acct = "${resultRow[Actors.name]}@${resultRow[Actors.domain]}",
url = resultRow[Actors.url],
displayName = resultRow[Actors.screenName],
note = resultRow[Actors.description],
avatar = userUrl + "/icon.jpg",
avatarStatic = userUrl + "/icon.jpg",
header = userUrl + "/header.jpg",
headerStatic = userUrl + "/header.jpg",
locked = resultRow[Actors.locked],
fields = emptyList(),
emojis = emptyList(),
bot = false,
group = false,
discoverable = true,
createdAt = Instant.ofEpochMilli(resultRow[Actors.createdAt]).toString(),
lastStatusAt = resultRow[lastCreated]?.let { Instant.ofEpochMilli(it).toString() },
statusesCount = resultRow[postsCount].toInt(),
followersCount = resultRow[followersCount].toInt(),
followingCount = resultRow[followingCount].toInt(),
)
}
}

View File

@ -143,4 +143,46 @@ class MastodonAccountApiController(
return ResponseEntity.ok(removeFromFollowers) return ResponseEntity.ok(removeFromFollowers)
} }
override suspend fun apiV1AccountsUpdateCredentialsPatch(updateCredentials: UpdateCredentials?): ResponseEntity<Account> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt
val userid = principal.getClaim<String>("uid").toLong()
val removeFromFollowers = accountApiService.updateProfile(userid, updateCredentials)
return ResponseEntity.ok(removeFromFollowers)
}
override suspend fun apiV1FollowRequestsAccountIdAuthorizePost(accountId: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt
val userid = principal.getClaim<String>("uid").toLong()
val acceptFollowRequest = accountApiService.acceptFollowRequest(userid, accountId.toLong())
return ResponseEntity.ok(acceptFollowRequest)
}
override suspend fun apiV1FollowRequestsAccountIdRejectPost(accountId: String): ResponseEntity<Relationship> {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt
val userid = principal.getClaim<String>("uid").toLong()
val rejectFollowRequest = accountApiService.rejectFollowRequest(userid, accountId.toLong())
return ResponseEntity.ok(rejectFollowRequest)
}
override fun apiV1FollowRequestsGet(maxId: String?, sinceId: String?, limit: Int?): ResponseEntity<Flow<Account>> =
runBlocking {
val principal = SecurityContextHolder.getContext().getAuthentication().principal as Jwt
val userid = principal.getClaim<String>("uid").toLong()
val accountFlow =
accountApiService.followRequests(userid, maxId?.toLong(), sinceId?.toLong(), limit ?: 20, false)
.asFlow()
ResponseEntity.ok(accountFlow)
}
} }

View File

@ -0,0 +1,8 @@
package dev.usbharu.hideout.mastodon.query
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
interface AccountQueryService {
suspend fun findById(accountId: Long): Account
suspend fun findByIds(accountIds: List<Long>): List<Account>
}

View File

@ -2,10 +2,14 @@ package dev.usbharu.hideout.mastodon.service.account
import dev.usbharu.hideout.application.external.Transaction import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.query.RelationshipQueryService
import dev.usbharu.hideout.core.service.media.MediaService
import dev.usbharu.hideout.core.service.relationship.RelationshipService import dev.usbharu.hideout.core.service.relationship.RelationshipService
import dev.usbharu.hideout.core.service.user.UpdateUserDto
import dev.usbharu.hideout.core.service.user.UserCreateDto import dev.usbharu.hideout.core.service.user.UserCreateDto
import dev.usbharu.hideout.core.service.user.UserService import dev.usbharu.hideout.core.service.user.UserService
import dev.usbharu.hideout.domain.mastodon.model.generated.* import dev.usbharu.hideout.domain.mastodon.model.generated.*
import dev.usbharu.hideout.mastodon.interfaces.api.media.MediaRequest
import dev.usbharu.hideout.mastodon.query.StatusQueryService import dev.usbharu.hideout.mastodon.query.StatusQueryService
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -45,6 +49,17 @@ interface AccountApiService {
suspend fun unblock(userid: Long, target: Long): Relationship suspend fun unblock(userid: Long, target: Long): Relationship
suspend fun unfollow(userid: Long, target: Long): Relationship suspend fun unfollow(userid: Long, target: Long): Relationship
suspend fun removeFromFollowers(userid: Long, target: Long): Relationship suspend fun removeFromFollowers(userid: Long, target: Long): Relationship
suspend fun updateProfile(userid: Long, updateCredentials: UpdateCredentials?): Account
suspend fun followRequests(
loginUser: Long,
maxId: Long?,
sinceId: Long?,
limit: Int = 20,
withIgnore: Boolean
): List<Account>
suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship
suspend fun rejectFollowRequest(loginUser: Long, target: Long): Relationship
} }
@Service @Service
@ -54,7 +69,9 @@ class AccountApiServiceImpl(
private val userService: UserService, private val userService: UserService,
private val statusQueryService: StatusQueryService, private val statusQueryService: StatusQueryService,
private val relationshipService: RelationshipService, private val relationshipService: RelationshipService,
private val relationshipRepository: RelationshipRepository private val relationshipRepository: RelationshipRepository,
private val mediaService: MediaService,
private val relationshipQueryService: RelationshipQueryService
) : ) :
AccountApiService { AccountApiService {
override suspend fun accountsStatuses( override suspend fun accountsStatuses(
@ -153,6 +170,84 @@ class AccountApiServiceImpl(
return@transaction fetchRelationship(userid, target) return@transaction fetchRelationship(userid, target)
} }
override suspend fun updateProfile(userid: Long, updateCredentials: UpdateCredentials?): Account =
transaction.transaction {
val avatarMedia = if (updateCredentials?.avatar != null) {
mediaService.uploadLocalMedia(
MediaRequest(
updateCredentials.avatar,
null,
null,
null
)
)
} else {
null
}
val headerMedia = if (updateCredentials?.header != null) {
mediaService.uploadLocalMedia(
MediaRequest(
updateCredentials.header,
null,
null,
null
)
)
} else {
null
}
val account = accountService.findById(userid)
val updateUserDto = UpdateUserDto(
screenName = updateCredentials?.displayName ?: account.displayName,
description = updateCredentials?.note ?: account.note,
avatarMedia = avatarMedia,
headerMedia = headerMedia,
locked = updateCredentials?.locked ?: account.locked,
autoAcceptFolloweeFollowRequest = false
)
userService.updateUser(userid, updateUserDto)
accountService.findById(userid)
}
override suspend fun followRequests(
loginUser: Long,
maxId: Long?,
sinceId: Long?,
limit: Int,
withIgnore: Boolean
): List<Account> = transaction.transaction {
val actorIdList = relationshipQueryService
.findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
maxId = maxId,
sinceId = sinceId,
limit = limit,
targetId = loginUser,
followRequest = true,
ignoreFollowRequest = withIgnore
)
.map { it.actorId }
return@transaction accountService.findByIds(actorIdList)
}
override suspend fun acceptFollowRequest(loginUser: Long, target: Long): Relationship = transaction.transaction {
relationshipService.acceptFollowRequest(loginUser, target)
return@transaction fetchRelationship(loginUser, target)
}
override suspend fun rejectFollowRequest(loginUser: Long, target: Long): Relationship = transaction.transaction {
relationshipService.rejectFollowRequest(loginUser, target)
return@transaction fetchRelationship(loginUser, target)
}
private fun from(account: Account): CredentialAccount { private fun from(account: Account): CredentialAccount {
return CredentialAccount( return CredentialAccount(
id = account.id, id = account.id,
@ -180,10 +275,10 @@ class AccountApiServiceImpl(
suspendex = account.suspendex, suspendex = account.suspendex,
limited = account.limited, limited = account.limited,
followingCount = account.followingCount, followingCount = account.followingCount,
source = CredentialAccountSource( source = AccountSource(
account.note, account.note,
account.fields, account.fields,
CredentialAccountSource.Privacy.public, AccountSource.Privacy.public,
false, false,
0 0
), ),
@ -200,7 +295,7 @@ class AccountApiServiceImpl(
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, userid) val inverseRelationship = relationshipRepository.findByUserIdAndTargetUserId(targetId, userid)
@ -211,7 +306,7 @@ class AccountApiServiceImpl(
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
return Relationship( return Relationship(

View File

@ -1,45 +1,24 @@
package dev.usbharu.hideout.mastodon.service.account package dev.usbharu.hideout.mastodon.service.account
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.core.query.ActorQueryService
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 org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
interface AccountService { interface AccountService {
suspend fun findById(id: Long): Account suspend fun findById(id: Long): Account
suspend fun findByIds(ids: List<Long>): List<Account>
} }
@Service @Service
class AccountServiceImpl( class AccountServiceImpl(
private val actorQueryService: ActorQueryService, private val accountQueryService: AccountQueryService
private val applicationConfig: ApplicationConfig
) : AccountService { ) : AccountService {
override suspend fun findById(id: Long): Account { override suspend fun findById(id: Long): Account {
val findById = actorQueryService.findById(id) return accountQueryService.findById(id)
val userUrl = applicationConfig.url.toString() + "/users/" + findById.id.toString() }
return Account( override suspend fun findByIds(ids: List<Long>): List<Account> {
id = findById.id.toString(), return accountQueryService.findByIds(ids)
username = findById.name,
acct = "${findById.name}@${findById.domain}",
url = findById.url,
displayName = findById.screenName,
note = findById.description,
avatar = "$userUrl/icon.jpg",
avatarStatic = "$userUrl/icon.jpg",
header = "$userUrl/header.jpg",
headerStatic = "$userUrl/header.jpg",
locked = false,
fields = emptyList(),
emojis = emptyList(),
bot = false,
group = false,
discoverable = false,
createdAt = findById.createdAt.toString(),
lastStatusAt = findById.createdAt.toString(),
statusesCount = 0,
followersCount = 0,
)
} }
} }

View File

@ -30,6 +30,7 @@ create table if not exists actors
"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,
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
); );
@ -39,7 +40,6 @@ create table if not exists user_details
id bigserial primary key, id bigserial primary key,
actor_id bigint not null unique, actor_id bigint not null unique,
password varchar(255) not null, password varchar(255) not null,
auto_accept_follow_request boolean not null,
auto_accept_followee_follow_request boolean not null, auto_accept_followee_follow_request boolean not null,
constraint fk_user_details_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict constraint fk_user_details_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict
); );

View File

@ -237,6 +237,27 @@ paths:
items: items:
$ref: "#/components/schemas/Relationship" $ref: "#/components/schemas/Relationship"
/api/v1/accounts/update_credentials:
patch:
tags:
- account
security:
- OAuth2:
- "write:accounts"
requestBody:
required: false
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateCredentials"
responses:
200:
description: 成功
content:
application/json:
schema:
$ref: "#/components/schemas/Account"
/api/v1/accounts/{id}: /api/v1/accounts/{id}:
get: get:
tags: tags:
@ -555,6 +576,86 @@ paths:
schema: schema:
$ref: "#/components/schemas/MediaAttachment" $ref: "#/components/schemas/MediaAttachment"
/api/v1/follow_requests:
get:
tags:
- account
security:
- OAuth2:
- "read:follows"
parameters:
- in: query
name: max_id
schema:
type: string
required: false
- in: query
name: since_id
schema:
type: string
required: false
- in: query
name: limit
schema:
type: integer
required: false
responses:
200:
description: 成功
headers:
Link:
schema:
type: string
description: ページネーション
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Account"
/api/v1/follow_requests/{account_id}/authorize:
post:
tags:
- account
security:
- OAuth2:
- "write:follows"
parameters:
- in: path
name: account_id
schema:
type: string
required: true
responses:
200:
description: 成功
content:
application/json:
schema:
$ref: "#/components/schemas/Relationship"
/api/v1/follow_requests/{account_id}/reject:
post:
tags:
- account
security:
- OAuth2:
- "write:follows"
parameters:
- in: path
name: account_id
schema:
type: string
required: true
responses:
200:
description: 成功
content:
application/json:
schema:
$ref: "#/components/schemas/Relationship"
components: components:
schemas: schemas:
V1MediaRequest: V1MediaRequest:
@ -664,6 +765,9 @@ components:
type: integer type: integer
following_count: following_count:
type: integer type: integer
source:
$ref: "#/components/schemas/AccountSource"
required: required:
- id - id
- username - username
@ -747,7 +851,7 @@ components:
following_count: following_count:
type: integer type: integer
source: source:
$ref: "#/components/schemas/CredentialAccountSource" $ref: "#/components/schemas/AccountSource"
role: role:
$ref: "#/components/schemas/Role" $ref: "#/components/schemas/Role"
required: required:
@ -774,7 +878,7 @@ components:
- followers_count - followers_count
- source - source
CredentialAccountSource: AccountSource:
type: object type: object
properties: properties:
note: note:
@ -1632,6 +1736,58 @@ components:
items: items:
type: string type: string
UpdateCredentials:
type: object
properties:
display_name:
type: string
note:
type: string
avatar:
type: string
format: binary
header:
type: string
format: binary
locked:
type: boolean
bot:
type: boolean
discoverable:
type: boolean
hide_collections:
type: boolean
indexable:
type: boolean
fields_attributes:
type: object
additionalProperties:
$ref: "#/components/schemas/UpdateCredentialsFieldsAttributes"
source:
$ref: "#/components/schemas/UpdateCredentialsSource"
UpdateCredentialsSource:
type: object
properties:
privacy:
type: string
enum:
- public
- unlisted
- private
sensitive:
type: boolean
language:
type: string
UpdateCredentialsFieldsAttributes:
type: object
properties:
name:
type: string
value:
type: string
securitySchemes: securitySchemes:
OAuth2: OAuth2:
type: oauth2 type: oauth2

View File

@ -59,7 +59,8 @@ class ActorAPControllerImplTest {
), ),
endpoints = mapOf("sharedInbox" to "https://example.com/inbox"), endpoints = mapOf("sharedInbox" to "https://example.com/inbox"),
followers = "https://example.com/users/hoge/followers", followers = "https://example.com/users/hoge/followers",
following = "https://example.com/users/hoge/following" following = "https://example.com/users/hoge/following",
manuallyApprovesFollowers = false
) )
whenever(apUserService.getPersonByName(eq("hoge"))).doReturn(person) whenever(apUserService.getPersonByName(eq("hoge"))).doReturn(person)

View File

@ -133,6 +133,7 @@ class APNoteServiceImplTest {
endpoints = mapOf("sharedInbox" to "https://example.com/inbox"), endpoints = mapOf("sharedInbox" to "https://example.com/inbox"),
followers = user.followers, followers = user.followers,
following = user.following, following = user.following,
manuallyApprovesFollowers = false
) )
val apUserService = mock<APUserService> { val apUserService = mock<APUserService> {

View File

@ -67,7 +67,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -91,7 +91,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -110,7 +110,7 @@ class RelationshipServiceImplTest {
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -129,7 +129,7 @@ class RelationshipServiceImplTest {
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -152,7 +152,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -167,7 +167,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -186,7 +186,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = true
) )
) )
@ -198,7 +198,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = true ignoreFollowRequestToTarget = false
) )
) )
@ -222,7 +222,7 @@ class RelationshipServiceImplTest {
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -246,7 +246,7 @@ class RelationshipServiceImplTest {
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -266,7 +266,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -280,7 +280,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -302,7 +302,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -317,7 +317,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -366,7 +366,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -420,7 +420,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -435,7 +435,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -459,7 +459,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = true, followRequest = true,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -474,7 +474,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -500,7 +500,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -516,13 +516,13 @@ class RelationshipServiceImplTest {
verify(relationshipRepository, times(1)).save( verify(relationshipRepository, times(1)).save(
eq( eq(
Relationship( Relationship(
actorId = 1234, actorId = 5678,
targetActorId = 5678, targetActorId = 1234,
following = false, following = false,
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = true ignoreFollowRequestToTarget = true
) )
) )
) )
@ -539,7 +539,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -554,7 +554,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -578,7 +578,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -593,7 +593,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -618,7 +618,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -638,7 +638,7 @@ class RelationshipServiceImplTest {
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -653,7 +653,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -677,7 +677,7 @@ class RelationshipServiceImplTest {
blocking = true, blocking = true,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -717,7 +717,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -739,7 +739,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = true, muting = true,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )
@ -756,7 +756,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = true, muting = true,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -771,7 +771,7 @@ class RelationshipServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
) )

View File

@ -79,7 +79,8 @@ class ActorServiceTest {
keyId = "a", keyId = "a",
following = "", following = "",
followers = "", followers = "",
sharedInbox = null sharedInbox = null,
locked = false
) )
userService.createRemoteUser(user) userService.createRemoteUser(user)
verify(actorRepository, times(1)).save(any()) verify(actorRepository, times(1)).save(any())

View File

@ -1,8 +1,8 @@
package dev.usbharu.hideout.mastodon.interfaces.api.account package dev.usbharu.hideout.mastodon.interfaces.api.account
import dev.usbharu.hideout.application.config.ActivityPubConfig import dev.usbharu.hideout.application.config.ActivityPubConfig
import dev.usbharu.hideout.domain.mastodon.model.generated.AccountSource
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccount
import dev.usbharu.hideout.domain.mastodon.model.generated.CredentialAccountSource
import dev.usbharu.hideout.domain.mastodon.model.generated.Role import dev.usbharu.hideout.domain.mastodon.model.generated.Role
import dev.usbharu.hideout.mastodon.service.account.AccountApiService import dev.usbharu.hideout.mastodon.service.account.AccountApiService
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -74,10 +74,10 @@ class MastodonAccountApiControllerTest {
lastStatusAt = "", lastStatusAt = "",
statusesCount = 0, statusesCount = 0,
followersCount = 0, followersCount = 0,
source = CredentialAccountSource( source = AccountSource(
note = "", note = "",
fields = emptyList(), fields = emptyList(),
privacy = CredentialAccountSource.Privacy.public, privacy = AccountSource.Privacy.public,
sensitive = false, sensitive = false,
followRequestsCount = 0 followRequestsCount = 0
), ),

View File

@ -4,6 +4,8 @@ import dev.usbharu.hideout.application.external.Transaction
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.relationship.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.query.FollowerQueryService import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.hideout.core.query.RelationshipQueryService
import dev.usbharu.hideout.core.service.media.MediaService
import dev.usbharu.hideout.core.service.relationship.RelationshipService import dev.usbharu.hideout.core.service.relationship.RelationshipService
import dev.usbharu.hideout.core.service.user.UserService import dev.usbharu.hideout.core.service.user.UserService
import dev.usbharu.hideout.domain.mastodon.model.generated.Account import dev.usbharu.hideout.domain.mastodon.model.generated.Account
@ -48,6 +50,12 @@ class AccountApiServiceImplTest {
@Mock @Mock
private lateinit var relationshipRepository: RelationshipRepository private lateinit var relationshipRepository: RelationshipRepository
@Mock
private lateinit var relationshipQueryService: RelationshipQueryService
@Mock
private lateinit var mediaService: MediaService
@InjectMocks @InjectMocks
private lateinit var accountApiServiceImpl: AccountApiServiceImpl private lateinit var accountApiServiceImpl: AccountApiServiceImpl
@ -210,7 +218,7 @@ class AccountApiServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
@ -245,7 +253,7 @@ class AccountApiServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )
whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(userId), eq(followeeId))).doReturn( whenever(relationshipRepository.findByUserIdAndTargetUserId(eq(userId), eq(followeeId))).doReturn(
@ -256,7 +264,7 @@ class AccountApiServiceImplTest {
blocking = false, blocking = false,
muting = false, muting = false,
followRequest = false, followRequest = false,
ignoreFollowRequestFromTarget = false ignoreFollowRequestToTarget = false
) )
) )

View File

@ -19,7 +19,6 @@ object UserBuilder {
domain: String = "example.com", domain: String = "example.com",
screenName: String = name, screenName: String = name,
description: String = "This user is test user.", description: String = "This user is test user.",
password: String = "password-$id",
inbox: String = "https://$domain/users/$id/inbox", inbox: String = "https://$domain/users/$id/inbox",
outbox: String = "https://$domain/users/$id/outbox", outbox: String = "https://$domain/users/$id/outbox",
url: String = "https://$domain/users/$id", url: String = "https://$domain/users/$id",
@ -44,7 +43,8 @@ object UserBuilder {
createdAt = createdAt, createdAt = createdAt,
keyId = keyId, keyId = keyId,
followers = followers, followers = followers,
following = following following = following,
locked = false
) )
} }
@ -77,7 +77,8 @@ object UserBuilder {
createdAt = createdAt, createdAt = createdAt,
keyId = keyId, keyId = keyId,
followers = followers, followers = followers,
following = following following = following,
locked = false
) )
} }