summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/UserBlockingService.ts
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2022-09-18 03:27:08 +0900
committerGitHub <noreply@github.com>2022-09-18 03:27:08 +0900
commitb75184ec8e3436200bacdcd832e3324702553d20 (patch)
tree8b7e316f29e95df921db57289c8b8da476d18f07 /packages/backend/src/core/UserBlockingService.ts
parentUpdate ROADMAP.md (diff)
downloadsharkey-b75184ec8e3436200bacdcd832e3324702553d20.tar.gz
sharkey-b75184ec8e3436200bacdcd832e3324702553d20.tar.bz2
sharkey-b75184ec8e3436200bacdcd832e3324702553d20.zip
なんかもうめっちゃ変えた
Diffstat (limited to 'packages/backend/src/core/UserBlockingService.ts')
-rw-r--r--packages/backend/src/core/UserBlockingService.ts199
1 files changed, 199 insertions, 0 deletions
diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts
new file mode 100644
index 0000000000..a9396fcbba
--- /dev/null
+++ b/packages/backend/src/core/UserBlockingService.ts
@@ -0,0 +1,199 @@
+
+import { Inject, Injectable } from '@nestjs/common';
+import { IdService } from '@/core/IdService.js';
+import type { CacheableUser, User } from '@/models/entities/User.js';
+import type { Blocking } from '@/models/entities/Blocking.js';
+import { QueueService } from '@/core/QueueService.js';
+import { GlobalEventService } from '@/core/GlobalEventService.js';
+import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
+import { DI } from '@/di-symbols.js';
+import { UserEntityService } from './entities/UserEntityService.js';
+import { WebhookService } from './WebhookService.js';
+import { ApRendererService } from './remote/activitypub/ApRendererService.js';
+
+@Injectable()
+export class UserBlockingService {
+ constructor(
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+
+ @Inject(DI.followingsRepository)
+ private followingsRepository: FollowingsRepository,
+
+ @Inject(DI.followRequestsRepository)
+ private followRequestsRepository: FollowRequestsRepository,
+
+ @Inject(DI.blockingsRepository)
+ private blockingsRepository: BlockingsRepository,
+
+ @Inject(DI.userListsRepository)
+ private userListsRepository: UserListsRepository,
+
+ @Inject(DI.userListJoiningsRepository)
+ private userListJoiningsRepository: UserListJoiningsRepository,
+
+ private userEntityService: UserEntityService,
+ private idService: IdService,
+ private queueService: QueueService,
+ private globalEventServie: GlobalEventService,
+ private webhookService: WebhookService,
+ private apRendererService: ApRendererService,
+ private perUserFollowingChart: PerUserFollowingChart,
+ ) {
+ }
+
+ public async block(blocker: User, blockee: User) {
+ await Promise.all([
+ this.#cancelRequest(blocker, blockee),
+ this.#cancelRequest(blockee, blocker),
+ this.#unFollow(blocker, blockee),
+ this.#unFollow(blockee, blocker),
+ this.#removeFromList(blockee, blocker),
+ ]);
+
+ const blocking = {
+ id: this.idService.genId(),
+ createdAt: new Date(),
+ blocker,
+ blockerId: blocker.id,
+ blockee,
+ blockeeId: blockee.id,
+ } as Blocking;
+
+ await this.blockingsRepository.insert(blocking);
+
+ if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
+ const content = this.apRendererService.renderActivity(this.apRendererService.renderBlock(blocking));
+ this.queueService.deliver(blocker, content, blockee.inbox);
+ }
+ }
+
+ async #cancelRequest(follower: User, followee: User) {
+ const request = await this.followRequestsRepository.findOneBy({
+ followeeId: followee.id,
+ followerId: follower.id,
+ });
+
+ if (request == null) {
+ return;
+ }
+
+ await this.followRequestsRepository.delete({
+ followeeId: followee.id,
+ followerId: follower.id,
+ });
+
+ if (this.userEntityService.isLocalUser(followee)) {
+ this.userEntityService.pack(followee, followee, {
+ detail: true,
+ }).then(packed => this.globalEventServie.publishMainStream(followee.id, 'meUpdated', packed));
+ }
+
+ if (this.userEntityService.isLocalUser(follower)) {
+ this.userEntityService.pack(followee, follower, {
+ detail: true,
+ }).then(async packed => {
+ this.globalEventServie.publishUserEvent(follower.id, 'unfollow', packed);
+ this.globalEventServie.publishMainStream(follower.id, 'unfollow', packed);
+
+ const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
+ for (const webhook of webhooks) {
+ this.queueService.webhookDeliver(webhook, 'unfollow', {
+ user: packed,
+ });
+ }
+ });
+ }
+
+ // リモートにフォローリクエストをしていたらUndoFollow送信
+ if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
+ const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
+ this.queueService.deliver(follower, content, followee.inbox);
+ }
+
+ // リモートからフォローリクエストを受けていたらReject送信
+ if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
+ const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee));
+ this.queueService.deliver(followee, content, follower.inbox);
+ }
+ }
+
+ async #unFollow(follower: User, followee: User) {
+ const following = await this.followingsRepository.findOneBy({
+ followerId: follower.id,
+ followeeId: followee.id,
+ });
+
+ if (following == null) {
+ return;
+ }
+
+ await Promise.all([
+ this.followingsRepository.delete(following.id),
+ this.usersRepository.decrement({ id: follower.id }, 'followingCount', 1),
+ this.usersRepository.decrement({ id: followee.id }, 'followersCount', 1),
+ this.perUserFollowingChart.update(follower, followee, false),
+ ]);
+
+ // Publish unfollow event
+ if (this.userEntityService.isLocalUser(follower)) {
+ this.userEntityService.pack(followee, follower, {
+ detail: true,
+ }).then(async packed => {
+ this.globalEventServie.publishUserEvent(follower.id, 'unfollow', packed);
+ this.globalEventServie.publishMainStream(follower.id, 'unfollow', packed);
+
+ const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
+ for (const webhook of webhooks) {
+ this.queueService.webhookDeliver(webhook, 'unfollow', {
+ user: packed,
+ });
+ }
+ });
+ }
+
+ // リモートにフォローをしていたらUndoFollow送信
+ if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
+ const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
+ this.queueService.deliver(follower, content, followee.inbox);
+ }
+ }
+
+ async #removeFromList(listOwner: User, user: User) {
+ const userLists = await this.userListsRepository.findBy({
+ userId: listOwner.id,
+ });
+
+ for (const userList of userLists) {
+ await this.userListJoiningsRepository.delete({
+ userListId: userList.id,
+ userId: user.id,
+ });
+ }
+ }
+
+ public async unblock(blocker: CacheableUser, blockee: CacheableUser) {
+ const blocking = await this.blockingsRepository.findOneBy({
+ blockerId: blocker.id,
+ blockeeId: blockee.id,
+ });
+
+ if (blocking == null) {
+ logger.warn('ブロック解除がリクエストされましたがブロックしていませんでした');
+ return;
+ }
+
+ // Since we already have the blocker and blockee, we do not need to fetch
+ // them in the query above and can just manually insert them here.
+ blocking.blocker = blocker;
+ blocking.blockee = blockee;
+
+ await this.blockingsRepository.delete(blocking.id);
+
+ // deliver if remote bloking
+ if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
+ const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
+ this.queueService.deliver(blocker, content, blockee.inbox);
+ }
+ }
+}