diff options
| author | dakkar <dakkar@thenautilus.net> | 2024-04-25 11:31:35 +0100 |
|---|---|---|
| committer | dakkar <dakkar@thenautilus.net> | 2024-04-25 11:44:24 +0100 |
| commit | 4fe8a260817d30385cddecad91a4e84c15889666 (patch) | |
| tree | 70ef7d0215767befa923b41b53cff67a5130eda2 /packages/backend/src/core | |
| parent | Merge branch 'develop' into future-2024-04-10-post (diff) | |
| parent | feat: improve emoji endpoint (#13742) (diff) | |
| download | sharkey-4fe8a260817d30385cddecad91a4e84c15889666.tar.gz sharkey-4fe8a260817d30385cddecad91a4e84c15889666.tar.bz2 sharkey-4fe8a260817d30385cddecad91a4e84c15889666.zip | |
Merge remote-tracking branch 'misskey/develop' into future-2024-04-25
Diffstat (limited to 'packages/backend/src/core')
| -rw-r--r-- | packages/backend/src/core/FanoutTimelineEndpointService.ts | 8 | ||||
| -rw-r--r-- | packages/backend/src/core/MfmService.ts | 5 | ||||
| -rw-r--r-- | packages/backend/src/core/NoteCreateService.ts | 23 | ||||
| -rw-r--r-- | packages/backend/src/core/NoteDeleteService.ts | 4 | ||||
| -rw-r--r-- | packages/backend/src/core/RoleService.ts | 34 | ||||
| -rw-r--r-- | packages/backend/src/core/entities/ClipEntityService.ts | 6 |
6 files changed, 65 insertions, 15 deletions
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts index 6aa63d7d55..2f4d98fab4 100644 --- a/packages/backend/src/core/FanoutTimelineEndpointService.ts +++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts @@ -13,7 +13,7 @@ import type { NotesRepository } from '@/models/_.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { FanoutTimelineName, FanoutTimelineService } from '@/core/FanoutTimelineService.js'; import { isUserRelated } from '@/misc/is-user-related.js'; -import { isPureRenote } from '@/misc/is-pure-renote.js'; +import { isQuote, isRenote } from '@/misc/is-renote.js'; import { CacheService } from '@/core/CacheService.js'; import { isReply } from '@/misc/is-reply.js'; import { isInstanceMuted } from '@/misc/is-instance-muted.js'; @@ -101,7 +101,7 @@ export class FanoutTimelineEndpointService { if (ps.excludePureRenotes) { const parentFilter = filter; - filter = (note) => !isPureRenote(note) && parentFilter(note); + filter = (note) => (!isRenote(note) || isQuote(note)) && parentFilter(note); } if (ps.me) { @@ -122,9 +122,7 @@ export class FanoutTimelineEndpointService { filter = (note) => { if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromBlock)) return false; if (isUserRelated(note, userIdsWhoMeMuting, ps.ignoreAuthorFromMute)) return false; - if (note.mentions.some(mention => userIdsWhoMeMuting.has(mention))) return false; - if (isPureRenote(note) && note.renote && note.renote.mentions.some(mention => userIdsWhoMeMuting.has(mention))) return false; - if (isPureRenote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false; + if (!ps.ignoreAuthorFromMute && isRenote(note) && !isQuote(note) && userIdsWhoMeMutingRenotes.has(note.userId)) return false; if (isInstanceMuted(note, userMutedInstances)) return false; return parentFilter(note); diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index b7c9064cef..79e810ce4e 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -10,6 +10,7 @@ import { Window } from 'happy-dom'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { intersperse } from '@/misc/prelude/array.js'; +import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import type { IMentionedRemoteUsers } from '@/models/Note.js'; import { bindThis } from '@/decorators.js'; import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js'; @@ -33,6 +34,8 @@ export class MfmService { // some AP servers like Pixelfed use br tags as well as newlines html = html.replace(/<br\s?\/?>\r?\n/gi, '\n'); + const normalizedHashtagNames = hashtagNames == null ? undefined : new Set<string>(hashtagNames.map(x => normalizeForSearch(x))); + const dom = parse5.parseFragment(html); let text = ''; @@ -85,7 +88,7 @@ export class MfmService { const href = node.attrs.find(x => x.name === 'href'); // ハッシュタグ - if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) { + if (normalizedHashtagNames && href && normalizedHashtagNames.has(normalizeForSearch(txt))) { text += txt; // メンション } else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) { diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 631d7074bd..9b6d4d2901 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -495,7 +495,7 @@ export class NoteCreateService implements OnApplicationShutdown { } // Check blocking - if (data.renote && !this.isQuote(data)) { + if (this.isRenote(data) && !this.isQuote(data)) { if (data.renote.userHost === null) { if (data.renote.userId !== user.id) { const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id); @@ -855,7 +855,7 @@ export class NoteCreateService implements OnApplicationShutdown { } // If it is renote - if (data.renote) { + if (this.isRenote(data)) { const type = this.isQuote(data) ? 'quote' : 'renote'; // Notify @@ -1055,9 +1055,20 @@ export class NoteCreateService implements OnApplicationShutdown { } @bindThis - private isQuote(note: Option): note is Option & { renote: MiNote } { - // sync with misc/is-quote.ts - return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll); + private isRenote(note: Option): note is Option & { renote: MiNote } { + return note.renote != null; + } + + @bindThis + private isQuote(note: Option & { renote: MiNote }): note is Option & { renote: MiNote } & ( + { text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] } + ) { + // NOTE: SYNC WITH misc/is-quote.ts + return note.text != null || + note.reply != null || + note.cw != null || + note.poll != null || + (note.files != null && note.files.length > 0); } @bindThis @@ -1133,7 +1144,7 @@ export class NoteCreateService implements OnApplicationShutdown { private async renderNoteOrRenoteActivity(data: Option, note: MiNote) { if (data.localOnly) return null; - const content = data.renote && !this.isQuote(data) + const content = this.isRenote(data) && !this.isQuote(data) ? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note) : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note); diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index 471ade92c7..af65750a01 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -24,7 +24,7 @@ import { bindThis } from '@/decorators.js'; import { MetaService } from '@/core/MetaService.js'; import { SearchService } from '@/core/SearchService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; -import { isPureRenote } from '@/misc/is-pure-renote.js'; +import { isQuote, isRenote } from '@/misc/is-renote.js'; @Injectable() export class NoteDeleteService { @@ -86,7 +86,7 @@ export class NoteDeleteService { let renote: MiNote | null = null; // if deleted note is renote - if (isPureRenote(note)) { + if (isRenote(note) && !isQuote(note)) { renote = await this.notesRepository.findOneBy({ id: note.renoteId, }); diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 2059a6e784..f5a753afc7 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -209,45 +209,79 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { private evalCond(user: MiUser, roles: MiRole[], value: RoleCondFormulaValue): boolean { try { switch (value.type) { + // ~かつ~ case 'and': { return value.values.every(v => this.evalCond(user, roles, v)); } + // ~または~ case 'or': { return value.values.some(v => this.evalCond(user, roles, v)); } + // ~ではない case 'not': { return !this.evalCond(user, roles, value.value); } + // マニュアルロールがアサインされている case 'roleAssignedTo': { return roles.some(r => r.id === value.roleId); } + // ローカルユーザのみ case 'isLocal': { return this.userEntityService.isLocalUser(user); } + // リモートユーザのみ case 'isRemote': { return this.userEntityService.isRemoteUser(user); } + // サスペンド済みユーザである + case 'isSuspended': { + return user.isSuspended; + } + // 鍵アカウントユーザである + case 'isLocked': { + return user.isLocked; + } + // botユーザである + case 'isBot': { + return user.isBot; + } + // 猫である + case 'isCat': { + return user.isCat; + } + // 「ユーザを見つけやすくする」が有効なアカウント + case 'isExplorable': { + return user.isExplorable; + } + // ユーザが作成されてから指定期間経過した case 'createdLessThan': { return this.idService.parse(user.id).date.getTime() > (Date.now() - (value.sec * 1000)); } + // ユーザが作成されてから指定期間経っていない case 'createdMoreThan': { return this.idService.parse(user.id).date.getTime() < (Date.now() - (value.sec * 1000)); } + // フォロワー数が指定値以下 case 'followersLessThanOrEq': { return user.followersCount <= value.value; } + // フォロワー数が指定値以上 case 'followersMoreThanOrEq': { return user.followersCount >= value.value; } + // フォロー数が指定値以下 case 'followingLessThanOrEq': { return user.followingCount <= value.value; } + // フォロー数が指定値以上 case 'followingMoreThanOrEq': { return user.followingCount >= value.value; } + // ノート数が指定値以下 case 'notesLessThanOrEq': { return user.notesCount <= value.value; } + // ノート数が指定値以上 case 'notesMoreThanOrEq': { return user.notesCount >= value.value; } diff --git a/packages/backend/src/core/entities/ClipEntityService.ts b/packages/backend/src/core/entities/ClipEntityService.ts index 26fcd6714d..ce49c3458c 100644 --- a/packages/backend/src/core/entities/ClipEntityService.ts +++ b/packages/backend/src/core/entities/ClipEntityService.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; -import type { ClipFavoritesRepository, ClipsRepository, MiUser } from '@/models/_.js'; +import type { ClipNotesRepository, ClipFavoritesRepository, ClipsRepository, MiUser } from '@/models/_.js'; import { awaitAll } from '@/misc/prelude/await-all.js'; import type { Packed } from '@/misc/json-schema.js'; import type { } from '@/models/Blocking.js'; @@ -20,6 +20,9 @@ export class ClipEntityService { @Inject(DI.clipsRepository) private clipsRepository: ClipsRepository, + @Inject(DI.clipNotesRepository) + private clipNotesRepository: ClipNotesRepository, + @Inject(DI.clipFavoritesRepository) private clipFavoritesRepository: ClipFavoritesRepository, @@ -47,6 +50,7 @@ export class ClipEntityService { isPublic: clip.isPublic, favoritedCount: await this.clipFavoritesRepository.countBy({ clipId: clip.id }), isFavorited: meId ? await this.clipFavoritesRepository.exists({ where: { clipId: clip.id, userId: meId } }) : undefined, + notesCount: meId ? await this.clipNotesRepository.countBy({ clipId: clip.id }) : undefined, }); } |