Merge branch 'develop' into pr/12085

This commit is contained in:
syuilo 2023-10-30 16:24:24 +09:00
commit 6a8375b045
51 changed files with 543 additions and 129 deletions

View file

@ -24,6 +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';
@Injectable()
export class NoteDeleteService {
@ -77,8 +78,8 @@ export class NoteDeleteService {
if (this.userEntityService.isLocalUser(user) && !note.localOnly) {
let renote: MiNote | null = null;
// if deletd note is renote
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
// if deleted note is renote
if (isPureRenote(note)) {
renote = await this.notesRepository.findOneBy({
id: note.renoteId,
});

View file

@ -33,6 +33,7 @@ export type RolePolicies = {
inviteExpirationTime: number;
canManageCustomEmojis: boolean;
canRequestCustomEmojis: boolean;
canManageAvatarDecorations: boolean;
canSearchNotes: boolean;
canUseTranslator: boolean;
canHideAds: boolean;
@ -59,6 +60,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
inviteExpirationTime: 0,
canManageCustomEmojis: false,
canRequestCustomEmojis: false,
canManageAvatarDecorations: false,
canSearchNotes: false,
canUseTranslator: true,
canHideAds: false,
@ -309,6 +311,7 @@ export class RoleService implements OnApplicationShutdown {
inviteExpirationTime: calc('inviteExpirationTime', vs => Math.max(...vs)),
canManageCustomEmojis: calc('canManageCustomEmojis', vs => vs.some(v => v === true)),
canRequestCustomEmojis: calc('canRequestCustomEmojis', vs => vs.some(v => v === true)),
canManageAvatarDecorations: calc('canManageAvatarDecorations', vs => vs.some(v => v === true)),
canSearchNotes: calc('canSearchNotes', vs => vs.some(v => v === true)),
canUseTranslator: calc('canUseTranslator', vs => vs.some(v => v === true)),
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),

View file

@ -495,6 +495,7 @@ export class ApRendererService {
preferredUsername: user.username,
name: user.name,
summary: profile.description ? this.mfmService.toHtml(mfm.parse(profile.description)) : null,
_misskey_summary: profile.description,
icon: avatar ? this.renderImage(avatar) : null,
image: banner ? this.renderImage(banner) : null,
tag,
@ -644,6 +645,7 @@ export class ApRendererService {
'_misskey_quote': 'misskey:_misskey_quote',
'_misskey_reaction': 'misskey:_misskey_reaction',
'_misskey_votes': 'misskey:_misskey_votes',
'_misskey_summary': 'misskey:_misskey_summary',
'isCat': 'misskey:isCat',
// vcard
vcard: 'http://www.w3.org/2006/vcard/ns#',

View file

@ -319,9 +319,17 @@ export class ApPersonService implements OnModuleInit {
emojis,
})) as MiRemoteUser;
let _description: string | null = null;
if (person._misskey_summary) {
_description = truncate(person._misskey_summary, summaryLength);
} else if (person.summary) {
_description = this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag);
}
await transactionalEntityManager.save(new MiUserProfile({
userId: user.id,
description: person.summary ? this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
description: _description,
url,
fields,
birthday: bday?.[0] ?? null,
@ -487,10 +495,18 @@ export class ApPersonService implements OnModuleInit {
});
}
let _description: string | null = null;
if (person._misskey_summary) {
_description = truncate(person._misskey_summary, summaryLength);
} else if (person.summary) {
_description = this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag);
}
await this.userProfilesRepository.update({ userId: exist.id }, {
url,
fields,
description: person.summary ? this.apMfmService.htmlToMfm(truncate(person.summary, summaryLength), person.tag) : null,
description: _description,
birthday: bday?.[0] ?? null,
location: person['vcard:Address'] ?? null,
});

View file

@ -12,6 +12,7 @@ export interface IObject {
id?: string;
name?: string | null;
summary?: string;
_misskey_summary?: string;
published?: string;
cc?: ApObject;
to?: ApObject;

View file

@ -0,0 +1,10 @@
import type { MiNote } from '@/models/Note.js';
export function isPureRenote(note: MiNote): note is MiNote & { renoteId: NonNullable<MiNote['renoteId']> } {
if (!note.renoteId) return false;
if (note.text) return false; // it's quoted with text
if (note.fileIds.length !== 0) return false; // it's quoted with files
if (note.hasPoll) return false; // it's quoted with poll
return true;
}

View file

@ -26,6 +26,7 @@ import { UtilityService } from '@/core/UtilityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import { IActivity } from '@/core/activitypub/type.js';
import { isPureRenote } from '@/misc/is-pure-renote.js';
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions } from 'fastify';
import type { FindOptionsWhere } from 'typeorm';
@ -88,7 +89,7 @@ export class ActivityPubServerService {
*/
@bindThis
private async packActivity(note: MiNote): Promise<any> {
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
if (isPureRenote(note)) {
const renote = await this.notesRepository.findOneByOrFail({ id: note.renoteId });
return this.apRendererService.renderAnnounce(renote.uri ? renote.uri : `${this.config.url}/notes/${renote.id}`, note);
}

View file

@ -11,7 +11,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
requireRolePolicy: 'canManageAvatarDecorations',
} as const;
export const paramDef = {

View file

@ -13,8 +13,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
requireRolePolicy: 'canManageAvatarDecorations',
errors: {
},
} as const;

View file

@ -16,7 +16,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
requireRolePolicy: 'canManageAvatarDecorations',
res: {
type: 'array',

View file

@ -13,7 +13,7 @@ export const meta = {
tags: ['admin'],
requireCredential: true,
requireModerator: true,
requireRolePolicy: 'canManageAvatarDecorations',
errors: {
},

View file

@ -17,6 +17,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { NoteCreateService } from '@/core/NoteCreateService.js';
import { DI } from '@/di-symbols.js';
import { ApiError } from '../../error.js';
import { isPureRenote } from '@/misc/is-pure-renote.js';
export const meta = {
tags: ['notes'],
@ -221,7 +222,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (renote == null) {
throw new ApiError(meta.errors.noSuchRenoteTarget);
} else if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) {
} else if (isPureRenote(renote)) {
throw new ApiError(meta.errors.cannotReRenote);
}
@ -254,7 +255,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
if (reply == null) {
throw new ApiError(meta.errors.noSuchReplyTarget);
} else if (reply.renoteId && !reply.text && !reply.fileIds && !reply.hasPoll) {
} else if (isPureRenote(reply)) {
throw new ApiError(meta.errors.cannotReplyToPureRenote);
}

View file

@ -239,7 +239,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
query.andWhere(new Brackets(qb => {
qb.where('note.channelId IN (:...followingChannelIds)', { followingChannelIds });
qb.andWhere('note.channelId IS NULL');
qb.orWhere('note.channelId IS NULL');
}));
} else {
query.andWhere('note.channelId IS NULL');

View file

@ -183,7 +183,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const followingChannelIds = followingChannels.map(x => x.followeeId);
query.andWhere(new Brackets(qb => {
qb
.where('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds })
.where(new Brackets(qb2 => {
qb2
.where('note.userId IN (:...meOrFolloweeIds)', { meOrFolloweeIds: meOrFolloweeIds })
.andWhere('note.channelId IS NULL');
}))
.orWhere('note.channelId IN (:...followingChannelIds)', { followingChannelIds });
}));
} else if (followees.length > 0) {