This commit is contained in:
tamaina 2025-07-24 02:53:54 +09:00
parent 1cc6159442
commit 665c9dc38d
4 changed files with 37 additions and 48 deletions

View File

@ -56,7 +56,10 @@ export class UserSuspendService {
isRemoteSuspended: true, isRemoteSuspended: true,
}); });
this.postSuspend(user, true); (async () => {
await this.postSuspend(user, true).catch((e: any) => { });
await this.suspendFollowings(user).catch((e: any) => { });
})();
} }
@bindThis @bindThis
@ -73,7 +76,7 @@ export class UserSuspendService {
(async () => { (async () => {
await this.postUnsuspend(user, false).catch((e: any) => { }); await this.postUnsuspend(user, false).catch((e: any) => { });
await this.restoreFollowings(user).catch((e: any) => { console.error(e); }); await this.restoreFollowings(user).catch((e: any) => { });
})(); })();
} }
@ -83,7 +86,10 @@ export class UserSuspendService {
isRemoteSuspended: false, isRemoteSuspended: false,
}); });
this.postUnsuspend(user, true); (async () => {
await this.postUnsuspend(user, true).catch((e: any) => { });
await this.restoreFollowings(user).catch((e: any) => { });
})();
} }
@bindThis @bindThis

View File

@ -38,6 +38,7 @@ import { RoleService } from '@/core/RoleService.js';
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
import type { AccountMoveService } from '@/core/AccountMoveService.js'; import type { AccountMoveService } from '@/core/AccountMoveService.js';
import { checkHttps } from '@/misc/check-https.js'; import { checkHttps } from '@/misc/check-https.js';
import { UserSuspendService } from '@/core/UserSuspendService.js';
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js'; import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
import { extractApHashtags } from './tag.js'; import { extractApHashtags } from './tag.js';
import type { OnModuleInit } from '@nestjs/common'; import type { OnModuleInit } from '@nestjs/common';
@ -48,7 +49,6 @@ import type { ApLoggerService } from '../ApLoggerService.js';
import type { ApImageService } from './ApImageService.js'; import type { ApImageService } from './ApImageService.js';
import type { IActor, ICollection, IObject, IOrderedCollection } from '../type.js'; import type { IActor, ICollection, IObject, IOrderedCollection } from '../type.js';
import { UserSuspendService } from '@/core/UserSuspendService.js';
const nameLength = 128; const nameLength = 128;
const summaryLength = 2048; const summaryLength = 2048;
@ -606,10 +606,12 @@ export class ApPersonService implements OnModuleInit {
//#region suspend //#region suspend
if (exist.isRemoteSuspended === false && person.suspended === true) { if (exist.isRemoteSuspended === false && person.suspended === true) {
// リモートサーバーでアカウントが凍結された // リモートサーバーでアカウントが凍結された
this.logger.info(`Remote User Suspended: acct=${exist.username}@${exist.host} id=${exist.id} uri=${exist.uri}`);
this.userSuspendService.suspendFromRemote({ id: exist.id, host: exist.host }); this.userSuspendService.suspendFromRemote({ id: exist.id, host: exist.host });
} }
if (exist.isRemoteSuspended === true && person.suspended === false) { if (exist.isRemoteSuspended === true && person.suspended === false) {
// リモートサーバーでアカウントが解凍された // リモートサーバーでアカウントが解凍された
this.logger.info(`Remote User Unsuspended: acct=${exist.username}@${exist.host} id=${exist.id} uri=${exist.uri}`);
this.userSuspendService.unsuspendFromRemote({ id: exist.id, host: exist.host }); this.userSuspendService.unsuspendFromRemote({ id: exist.id, host: exist.host });
} }
//#endregion //#endregion

View File

@ -137,13 +137,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate) const query = this.queryService.makePaginationQuery(this.followingsRepository.createQueryBuilder('following'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('following.followeeId = :userId', { userId: user.id }) .andWhere('following.followeeId = :userId', { userId: user.id })
.andWhere('following.isFollowerSuspended = false') .andWhere('following.isFollowerSuspended = FALSE')
.innerJoinAndSelect('following.follower', 'follower'); .innerJoinAndSelect('following.follower', 'follower');
const followings = await query const followings = await query
.limit(ps.limit) .limit(ps.limit)
.getMany(); .getMany();
console.log(followings);
return await this.followingEntityService.packMany(followings, me, { populateFollower: true }); return await this.followingEntityService.packMany(followings, me, { populateFollower: true });
}); });
} }

View File

@ -35,13 +35,15 @@ describe('User Suspension', () => {
await aAdmin.client.request('admin/suspend-user', { userId: alice.id }); await aAdmin.client.request('admin/suspend-user', { userId: alice.id });
await sleep(); await sleep();
const following = await bob.client.request('users/following', { userId: bob.id }); const aliceInBRaw = await bAdmin.client.request('admin/show-user', { userId: aliceInB.id });
strictEqual(following.length, 0); // no following relation strictEqual(aliceInBRaw.isRemoteSuspended, true);
const renewedAliceInB = await bob.client.request('users/show', { userId: aliceInB.id });
strictEqual(renewedAliceInB.isSuspended, true);
await rejects( await rejects(
async () => await bob.client.request('following/create', { userId: aliceInB.id }), async () => await bob.client.request('following/create', { userId: aliceInB.id }),
(err: any) => { (err: any) => {
strictEqual(err.code, 'NO_SUCH_USER'); strictEqual(err.code, 'ALREADY_FOLLOWING');
return true; return true;
}, },
); );
@ -51,35 +53,18 @@ describe('User Suspension', () => {
await aAdmin.client.request('admin/unsuspend-user', { userId: alice.id }); await aAdmin.client.request('admin/unsuspend-user', { userId: alice.id });
await sleep(); await sleep();
const followers = await alice.client.request('users/followers', { userId: alice.id }); const aliceInBRenewed = await bAdmin.client.request('admin/show-user', { userId: aliceInB.id });
strictEqual(followers.length, 1); // FIXME: followers are not deleted?? strictEqual(aliceInBRenewed.isRemoteSuspended, false);
/**
* FIXME: still rejected!
* seems to can't process Undo Delete activity because it is not implemented
* related @see https://github.com/misskey-dev/misskey/issues/13273
*/
await rejects( await rejects(
async () => await bob.client.request('following/create', { userId: aliceInB.id }), async () => await bob.client.request('following/create', { userId: aliceInB.id }),
(err: any) => { (err: any) => {
strictEqual(err.code, 'NO_SUCH_USER'); strictEqual(err.code, 'ALREADY_FOLLOWING');
return true;
},
);
// FIXME: resolving also fails
await rejects(
async () => await resolveRemoteUser('a.test', alice.id, bob),
(err: any) => {
strictEqual(err.code, 'INTERNAL_ERROR');
return true; return true;
}, },
); );
}); });
/**
* instead of simple unsuspension, let's tell existence by following from Alice
*/
test('Alice can follow Bob', async () => { test('Alice can follow Bob', async () => {
await alice.client.request('following/create', { userId: bobInA.id }); await alice.client.request('following/create', { userId: bobInA.id });
await sleep(); await sleep();
@ -87,29 +72,23 @@ describe('User Suspension', () => {
const bobFollowers = await bob.client.request('users/followers', { userId: bob.id }); const bobFollowers = await bob.client.request('users/followers', { userId: bob.id });
strictEqual(bobFollowers.length, 1); // followed by Alice strictEqual(bobFollowers.length, 1); // followed by Alice
assert(bobFollowers[0].follower != null); assert(bobFollowers[0].follower != null);
const renewedaliceInB = bobFollowers[0].follower; const renewedAliceInB = bobFollowers[0].follower;
assert(aliceInB.username === renewedaliceInB.username); assert(aliceInB.username === renewedAliceInB.username);
assert(aliceInB.host === renewedaliceInB.host); assert(aliceInB.host === renewedAliceInB.host);
assert(aliceInB.id !== renewedaliceInB.id); // TODO: Same username and host, but their ids are different! Is it OK? assert(aliceInB.id === renewedAliceInB.id);
});
const following = await bob.client.request('users/following', { userId: bob.id }); test('Alice follows Bob, and Alice gets suspended, the following relation hidden', async () => {
strictEqual(following.length, 0); // following are deleted await aAdmin.client.request('admin/suspend-user', { userId: alice.id });
await sleep(1000);
// Bob tries to follow Alice const renewedAliceInB = await bob.client.request('users/show', { userId: aliceInB.id });
await bob.client.request('following/create', { userId: renewedaliceInB.id }); strictEqual(renewedAliceInB.isSuspended, true);
await sleep(); const aliceInBRaw = await bAdmin.client.request('admin/show-user', { userId: aliceInB.id });
strictEqual(aliceInBRaw.isRemoteSuspended, true);
const aliceFollowers = await alice.client.request('users/followers', { userId: alice.id }); const bobFollowers = await bob.client.request('users/followers', { userId: bob.id });
strictEqual(aliceFollowers.length, 1); strictEqual(bobFollowers.length, 0); // Relation is hidden
// FIXME: but resolving still fails ...
await rejects(
async () => await resolveRemoteUser('a.test', alice.id, bob),
(err: any) => {
strictEqual(err.code, 'INTERNAL_ERROR');
return true;
},
);
}); });
}); });
}); });