Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: フォロー/フォロリクの履歴 #49

Merged
merged 2 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10852,6 +10852,174 @@ export interface Locale extends ILocale {
* 予約投稿一覧
*/
"schedulePostList": string;
"_followRequestHistory": {
/**
* フォロリクの履歴
*/
"title": string;
/**
* {user} へフォローリクエストを送信
*/
"sent": ParameterizedString<"user">;
/**
* {user} からフォローリクエストを受信
*/
"received": ParameterizedString<"user">;
/**
* {user} のフォローリクエストを許可
*/
"approved": ParameterizedString<"user">;
/**
* {user} のフォローリクエストを拒否
*/
"rejected": ParameterizedString<"user">;
/**
* {user} にフォローリクエストが許可された
*/
"wasApproved": ParameterizedString<"user">;
/**
* {user} にフォローリクエストが拒否された
*/
"wasRejected": ParameterizedString<"user">;
/**
* 履歴はありません
*/
"empty": string;
/**
* フィルター
*/
"filter": string;
/**
* 履歴をすべて削除
*/
"deleteAll": string;
/**
* すべてのフォローリクエスト履歴を削除してもよろしいですか? この操作は元に戻せません。
*/
"deleteConfirm": string;
"types": {
/**
* すべて
*/
"all": string;
/**
* 送信済み
*/
"sent": string;
/**
* 受信済み
*/
"received": string;
/**
* 許可済み
*/
"approved": string;
/**
* 拒否済み
*/
"rejected": string;
/**
* 許可された
*/
"wasApproved": string;
/**
* 拒否された
*/
"wasRejected": string;
};
};
"_followHistory": {
/**
* フォローの履歴
*/
"title": string;
/**
* {user} をフォローした
*/
"follow": ParameterizedString<"user">;
/**
* {user} のフォローを解除
*/
"unFollow": ParameterizedString<"user">;
/**
* {user} にフォローされた
*/
"wasFollow": ParameterizedString<"user">;
/**
* {user} からフォロー解除された
*/
"wasUnFollow": ParameterizedString<"user">;
/**
* {user} をブロックした
*/
"blocked": ParameterizedString<"user">;
/**
* {user} のブロックを解除した
*/
"unBlocked": ParameterizedString<"user">;
/**
* {user} にブロックされた
*/
"wasBlocked": ParameterizedString<"user">;
/**
* {user} にブロックが解除された
*/
"wasUnBlocked": ParameterizedString<"user">;
/**
* 履歴はありません
*/
"empty": string;
/**
* フィルター
*/
"filter": string;
/**
* 履歴をすべて削除
*/
"deleteAll": string;
/**
* すべてのフォロー関連の履歴を削除してもよろしいですか? この操作は元に戻せません。
*/
"deleteConfirm": string;
"types": {
/**
* すべて
*/
"all": string;
/**
* フォローした
*/
"follow": string;
/**
* フォロー解除した
*/
"unFollow": string;
/**
* フォローされた
*/
"wasFollow": string;
/**
* フォロー解除された
*/
"wasUnFollow": string;
/**
* ブロックした
*/
"blocked": string;
/**
* ブロック解除した
*/
"unBlocked": string;
/**
* ブロックされた
*/
"wasBlocked": string;
/**
* ブロックが解除された
*/
"wasUnBlocked": string;
};
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
46 changes: 46 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2894,3 +2894,49 @@ _hideReactionCount:
schedulePost: "予約投稿"
schedulePostList: "予約投稿一覧"


_followRequestHistory:
title: "フォロリクの履歴"
sent: "{user} へフォローリクエストを送信"
received: "{user} からフォローリクエストを受信"
approved: "{user} のフォローリクエストを許可"
rejected: "{user} のフォローリクエストを拒否"
wasApproved: "{user} にフォローリクエストが許可された"
wasRejected: "{user} にフォローリクエストが拒否された"
empty: "履歴はありません"
filter: "フィルター"
deleteAll: "履歴をすべて削除"
deleteConfirm: "すべてのフォローリクエスト履歴を削除してもよろしいですか? この操作は元に戻せません。"
types:
all: "すべて"
sent: "送信済み"
received: "受信済み"
approved: "許可済み"
rejected: "拒否済み"
wasApproved: "許可された"
wasRejected: "拒否された"

_followHistory:
title: "フォローの履歴"
follow: "{user} をフォローした"
unFollow: "{user} のフォローを解除"
wasFollow: "{user} にフォローされた"
wasUnFollow: "{user} からフォロー解除された"
blocked: "{user} をブロックした"
unBlocked: "{user} のブロックを解除した"
wasBlocked: "{user} にブロックされた"
wasUnBlocked: "{user} にブロックが解除された"
empty: "履歴はありません"
filter: "フィルター"
deleteAll: "履歴をすべて削除"
deleteConfirm: "すべてのフォロー関連の履歴を削除してもよろしいですか? この操作は元に戻せません。"
types:
all: "すべて"
follow: "フォローした"
unFollow: "フォロー解除した"
wasFollow: "フォローされた"
wasUnFollow: "フォロー解除された"
blocked: "ブロックした"
unBlocked: "ブロック解除した"
wasBlocked: "ブロックされた"
wasUnBlocked: "ブロックが解除された"
31 changes: 31 additions & 0 deletions packages/backend/migration/1732925378001-FollowRequestHistory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* SPDX-FileCopyrightText: lqvp
* SPDX-License-Identifier: AGPL-3.0-only
*/

export class FollowRequestHistory1732925378001 {
name = 'FollowRequestHistory1732925378001'

async up(queryRunner) {
await queryRunner.query(`
CREATE TABLE "follow_request_history" (
"id" character varying(32) NOT NULL,
"type" character varying(32) NOT NULL,
"fromUserId" character varying(32) NOT NULL,
"toUserId" character varying(32) NOT NULL,
"timestamp" TIMESTAMP WITH TIME ZONE NOT NULL,
CONSTRAINT "PK_follow_request_history_id" PRIMARY KEY ("id")
)`);

await queryRunner.query(`CREATE INDEX "IDX_follow_request_history_from_user" ON "follow_request_history" ("fromUserId")`);
await queryRunner.query(`CREATE INDEX "IDX_follow_request_history_to_user" ON "follow_request_history" ("toUserId")`);
await queryRunner.query(`CREATE INDEX "IDX_follow_request_history_timestamp" ON "follow_request_history" ("timestamp")`);
}

async down(queryRunner) {
await queryRunner.query(`DROP INDEX "IDX_follow_request_history_timestamp"`);
await queryRunner.query(`DROP INDEX "IDX_follow_request_history_to_user"`);
await queryRunner.query(`DROP INDEX "IDX_follow_request_history_from_user"`);
await queryRunner.query(`DROP TABLE "follow_request_history"`);
}
}
27 changes: 27 additions & 0 deletions packages/backend/migration/1733272213376-FollowHistory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: lqvp
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class FollowHistory1733272213376 {
name = 'FollowHistory1733272213376';
async up(queryRunner) {
await queryRunner.query(`
CREATE TABLE "follow_history" (
"id" character varying(32) NOT NULL,
"type" character varying(32) NOT NULL,
"fromUserId" character varying(32) NOT NULL,
"toUserId" character varying(32) NOT NULL,
"timestamp" TIMESTAMP WITH TIME ZONE NOT NULL,
CONSTRAINT "PK_follow_history_id" PRIMARY KEY ("id")
)`);
await queryRunner.query('CREATE INDEX "IDX_follow_history_from_user" ON "follow_history" ("fromUserId")');
await queryRunner.query('CREATE INDEX "IDX_follow_history_to_user" ON "follow_history" ("toUserId")');
await queryRunner.query('CREATE INDEX "IDX_follow_history_timestamp" ON "follow_history" ("timestamp")');
}
async down(queryRunner) {
await queryRunner.query('DROP INDEX "IDX_follow_history_timestamp"');
await queryRunner.query('DROP INDEX "IDX_follow_history_to_user"');
await queryRunner.query('DROP INDEX "IDX_follow_history_from_user"');
await queryRunner.query('DROP TABLE "follow_history"');
}
}
49 changes: 48 additions & 1 deletion packages/backend/src/core/UserBlockingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { MiBlocking } from '@/models/Blocking.js';
import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { DI } from '@/di-symbols.js';
import type { FollowRequestsRepository, BlockingsRepository, UserListsRepository, UserListMembershipsRepository } from '@/models/_.js';
import type { FollowRequestsRepository, FollowHistoryRepository, BlockingsRepository, UserListsRepository, UserListMembershipsRepository } from '@/models/_.js';
import Logger from '@/logger.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
Expand All @@ -32,6 +32,9 @@ export class UserBlockingService implements OnModuleInit {
@Inject(DI.followRequestsRepository)
private followRequestsRepository: FollowRequestsRepository,

@Inject(DI.followHistoryRepository)
private followHistoryRepository: FollowHistoryRepository,

@Inject(DI.blockingsRepository)
private blockingsRepository: BlockingsRepository,

Expand Down Expand Up @@ -89,6 +92,28 @@ export class UserBlockingService implements OnModuleInit {
const content = this.apRendererService.addContext(this.apRendererService.renderBlock(blocking));
this.queueService.deliver(blocker, content, blockee.inbox, false);
}

// フォロー履歴に「blocked」を保存
if (this.userEntityService.isLocalUser(blocker)) {
await this.followHistoryRepository.insert({
id: this.idService.gen(),
type: 'blocked', // ブロックした側の履歴
fromUserId: blocker.id, // ブロックした側のID
toUserId: blockee.id, // ブロックされた側のID
timestamp: new Date(),
});
}

// フォローリクエスト履歴に「wasBlocked」を保存
if (this.userEntityService.isLocalUser(blockee)) {
await this.followHistoryRepository.insert({
id: this.idService.gen(),
type: 'wasBlocked', // ブロックされた側の履歴
fromUserId: blocker.id, // ブロックされた側のID
toUserId: blockee.id, // ブロックした側のID
timestamp: new Date(),
});
}
}

@bindThis
Expand Down Expand Up @@ -187,6 +212,28 @@ export class UserBlockingService implements OnModuleInit {
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
this.queueService.deliver(blocker, content, blockee.inbox, false);
}

// フォロー履歴に「unBlocked」を保存
if (this.userEntityService.isLocalUser(blocker)) {
await this.followHistoryRepository.insert({
id: this.idService.gen(),
type: 'unBlocked', // アンブロックした側の履歴
fromUserId: blocker.id, // アンブロックした側のID
toUserId: blockee.id, // アンブロックされた側のID
timestamp: new Date(),
});
}

// フォローリクエスト履歴に「wasUnBlocked」を保存
if (this.userEntityService.isLocalUser(blockee)) {
await this.followHistoryRepository.insert({
id: this.idService.gen(),
type: 'wasUnBlocked', // アンブロックされた側の履歴
fromUserId: blocker.id, // アンブロックされた側のID
toUserId: blockee.id, // アンブロックした側のID
timestamp: new Date(),
});
}
}

@bindThis
Expand Down
Loading
Loading