merge: Fix regressions from recent block/mute fixes (!1239)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1239 Approved-by: dakkar <dakkar@thenautilus.net> Approved-by: Marie <github@yuugi.dev>
This commit is contained in:
commit
911f90f95a
17 changed files with 127 additions and 59 deletions
|
|
@ -116,7 +116,10 @@ export class FanoutTimelineEndpointService {
|
|||
|
||||
const parentFilter = filter;
|
||||
filter = (note, populated) => {
|
||||
const { accessible, silence } = this.noteVisibilityService.checkNoteVisibility(populated, me, { data, filters: { includeSilencedAuthor: ps.ignoreAuthorFromUserSilence } });
|
||||
const { accessible, silence } = this.noteVisibilityService.checkNoteVisibility(populated, me, { data, filters: {
|
||||
includeSilencedAuthor: ps.ignoreAuthorFromUserSilence,
|
||||
includeReplies: true, // Include replies because we check them elsewhere
|
||||
} });
|
||||
if (!accessible || silence) return false;
|
||||
|
||||
return parentFilter(note, populated);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { MiUser } from '@/models/User.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
|
||||
export function isReply(note: any, viewerId?: MiUser['id'] | undefined | null): boolean {
|
||||
return note.replyId && note.replyUserId !== note.userId && note.replyUserId !== viewerId;
|
||||
// Should really be named "isReplyToOther"
|
||||
export function isReply(note: MiNote, viewerId?: MiUser['id'] | undefined | null): boolean {
|
||||
return note.replyId != null && note.replyUserId !== note.userId && note.replyUserId !== viewerId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import webpush from 'web-push';
|
||||
const { generateVAPIDKeys } = webpush;
|
||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
|
||||
|
|
@ -15,6 +14,21 @@ export const meta = {
|
|||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
kind: 'write:admin:meta',
|
||||
|
||||
res: {
|
||||
type: 'object',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
public: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
private: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const paramDef = {
|
||||
|
|
@ -28,8 +42,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
constructor(
|
||||
private moderationLogService: ModerationLogService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const keys = await generateVAPIDKeys();
|
||||
super(meta, paramDef, async () => {
|
||||
const keys = webpush.generateVAPIDKeys();
|
||||
|
||||
// TODO add moderation log
|
||||
|
||||
|
|
|
|||
|
|
@ -489,6 +489,10 @@ export const meta = {
|
|||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
about: {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
disableRegistration: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { DI } from '@/di-symbols.js';
|
|||
import { RoleService } from '@/core/RoleService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { InternalEventService } from '@/global/InternalEventService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
|
@ -36,7 +36,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private readonly cacheService: CacheService,
|
||||
private readonly moderationLogService: ModerationLogService,
|
||||
private readonly roleService: RoleService,
|
||||
private readonly globalEventService: GlobalEventService,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const user = await this.cacheService.findUserById(ps.userId);
|
||||
|
|
@ -47,11 +47,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
if (user.isSilenced) return;
|
||||
|
||||
await this.usersRepository.update(user.id, {
|
||||
await this.usersRepository.update({ id: user.id }, {
|
||||
isSilenced: true,
|
||||
});
|
||||
|
||||
this.globalEventService.publishInternalEvent(user.host == null ? 'localUserUpdated' : 'remoteUserUpdated', {
|
||||
await this.internalEventService.emit(user.host == null ? 'localUserUpdated' : 'remoteUserUpdated', {
|
||||
id: user.id,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import type { UsersRepository } from '@/models/_.js';
|
|||
import { DI } from '@/di-symbols.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { InternalEventService } from '@/global/InternalEventService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
|
@ -34,18 +34,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
private readonly usersRepository: UsersRepository,
|
||||
private readonly cacheService: CacheService,
|
||||
private readonly moderationLogService: ModerationLogService,
|
||||
private readonly globalEventService: GlobalEventService,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const user = await this.cacheService.findUserById(ps.userId);
|
||||
|
||||
if (!user.isSilenced) return;
|
||||
|
||||
await this.usersRepository.update(user.id, {
|
||||
await this.usersRepository.update({ id: user.id }, {
|
||||
isSilenced: false,
|
||||
});
|
||||
|
||||
this.globalEventService.publishInternalEvent(user.host == null ? 'localUserUpdated' : 'remoteUserUpdated', {
|
||||
await this.internalEventService.emit(user.host == null ? 'localUserUpdated' : 'remoteUserUpdated', {
|
||||
id: user.id,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import type { UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
|||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||
import { InternalEventService } from '@/global/InternalEventService.js';
|
||||
import { CacheService } from '@/core/CacheService.js';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
|
@ -34,23 +36,23 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
|
||||
@Inject(DI.userProfilesRepository)
|
||||
private userProfilesRepository: UserProfilesRepository,
|
||||
private readonly internalEventService: InternalEventService,
|
||||
private readonly cacheService: CacheService,
|
||||
|
||||
private moderationLogService: ModerationLogService,
|
||||
) {
|
||||
super(meta, paramDef, async (ps, me) => {
|
||||
const user = await this.usersRepository.findOneBy({ id: ps.userId });
|
||||
|
||||
if (user == null) {
|
||||
throw new Error('user not found');
|
||||
}
|
||||
|
||||
const currentProfile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
|
||||
const [user, currentProfile] = await Promise.all([
|
||||
this.cacheService.findUserById(ps.userId),
|
||||
this.cacheService.userProfileCache.fetch(ps.userId),
|
||||
]);
|
||||
|
||||
await this.userProfilesRepository.update({ userId: user.id }, {
|
||||
moderationNote: ps.text,
|
||||
});
|
||||
await this.internalEventService.emit('updateUserProfile', { userId: user.id });
|
||||
|
||||
this.moderationLogService.log(me, 'updateUserNote', {
|
||||
await this.moderationLogService.log(me, 'updateUserNote', {
|
||||
userId: user.id,
|
||||
userUsername: user.username,
|
||||
userHost: user.host,
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
// 2 calls per second
|
||||
// 20 calls, then 4 per second
|
||||
limit: {
|
||||
duration: 1000,
|
||||
max: 2,
|
||||
type: 'bucket',
|
||||
size: 20,
|
||||
dripRate: 250,
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,10 +51,11 @@ export const meta = {
|
|||
},
|
||||
},
|
||||
|
||||
// 5 calls per second
|
||||
// Up to 20 calls, then 4/second
|
||||
limit: {
|
||||
duration: 1000,
|
||||
max: 5,
|
||||
type: 'bucket',
|
||||
size: 20,
|
||||
dripRate: 250,
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
|
@ -63,7 +64,6 @@ export const paramDef = {
|
|||
properties: {
|
||||
userId: { type: 'string', format: 'misskey:id' },
|
||||
withReplies: { type: 'boolean', default: false },
|
||||
withRepliesToSelf: { type: 'boolean', default: true },
|
||||
withQuotes: { type: 'boolean', default: true },
|
||||
withRenotes: { type: 'boolean', default: true },
|
||||
withBots: { type: 'boolean', default: true },
|
||||
|
|
@ -122,8 +122,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
withQuotes: ps.withQuotes,
|
||||
withBots: ps.withBots,
|
||||
withNonPublic: ps.withNonPublic,
|
||||
withRepliesToOthers: ps.withReplies,
|
||||
withRepliesToSelf: ps.withRepliesToSelf,
|
||||
withReplies: ps.withReplies,
|
||||
}, me);
|
||||
|
||||
return await this.noteEntityService.packMany(timeline, me);
|
||||
|
|
@ -146,15 +145,12 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
ignoreAuthorFromInstanceBlock: true,
|
||||
ignoreAuthorFromUserSuspension: true,
|
||||
ignoreAuthorFromUserSilence: true,
|
||||
excludeReplies: ps.withChannelNotes && !ps.withReplies, // userTimelineWithChannel may include replies
|
||||
excludeNoFiles: ps.withChannelNotes && ps.withFiles, // userTimelineWithChannel may include notes without files
|
||||
excludeReplies: !ps.withChannelNotes && !ps.withReplies, // userTimelineWithChannel may include replies
|
||||
excludeNoFiles: !ps.withChannelNotes && ps.withFiles, // userTimelineWithChannel may include notes without files
|
||||
excludePureRenotes: !ps.withRenotes,
|
||||
excludeBots: !ps.withBots,
|
||||
noteFilter: note => {
|
||||
if (note.channel?.isSensitive && !isSelf) return false;
|
||||
|
||||
// These are handled by DB fallback, but we duplicate them here in case a timeline was already populated with notes
|
||||
if (!ps.withRepliesToSelf && note.reply?.userId === note.userId) return false;
|
||||
if (!ps.withQuotes && isRenote(note) && isQuote(note)) return false;
|
||||
if (!ps.withNonPublic && note.visibility !== 'public') return false;
|
||||
|
||||
|
|
@ -171,8 +167,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
withQuotes: ps.withQuotes,
|
||||
withBots: ps.withBots,
|
||||
withNonPublic: ps.withNonPublic,
|
||||
withRepliesToOthers: ps.withReplies,
|
||||
withRepliesToSelf: ps.withRepliesToSelf,
|
||||
withReplies: ps.withReplies,
|
||||
}, me),
|
||||
});
|
||||
|
||||
|
|
@ -191,8 +186,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
withQuotes: boolean,
|
||||
withBots: boolean,
|
||||
withNonPublic: boolean,
|
||||
withRepliesToOthers: boolean,
|
||||
withRepliesToSelf: boolean,
|
||||
withReplies: boolean,
|
||||
}, me: MiLocalUser | null) {
|
||||
const isSelf = me && (me.id === ps.userId);
|
||||
|
||||
|
|
@ -236,12 +230,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
this.queryService.andIsNotQuote(query, 'note');
|
||||
}
|
||||
|
||||
if (!ps.withRepliesToOthers && !ps.withRepliesToSelf) {
|
||||
query.andWhere('reply.id IS NULL');
|
||||
} else if (!ps.withRepliesToOthers) {
|
||||
if (!ps.withReplies) {
|
||||
this.queryService.generateExcludedRepliesQueryForNotes(query, me);
|
||||
} else if (!ps.withRepliesToSelf) {
|
||||
query.andWhere('(reply.id IS NULL OR reply."userId" != note."userId")');
|
||||
}
|
||||
|
||||
if (!ps.withNonPublic) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue