feat: Reaction acceptance (#10256)

* wip

* wip

* デフォルト設定
This commit is contained in:
syuilo
2023-03-08 08:56:47 +09:00
committed by GitHub
parent 4c2f7c64cc
commit dd6569a1bb
17 changed files with 131 additions and 27 deletions

View File

@@ -0,0 +1,11 @@
export class perNoteReactionAcceptance1678164627293 {
name = 'perNoteReactionAcceptance1678164627293'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" ADD "reactionAcceptance" character varying(64)`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "reactionAcceptance"`);
}
}

View File

@@ -125,6 +125,7 @@ type Option = {
files?: DriveFile[] | null;
poll?: IPoll | null;
localOnly?: boolean | null;
reactionAcceptance?: Note['reactionAcceptance'];
cw?: string | null;
visibility?: string;
visibleUsers?: MinimumUser[] | null;
@@ -346,6 +347,7 @@ export class NoteCreateService implements OnApplicationShutdown {
emojis,
userId: user.id,
localOnly: data.localOnly!,
reactionAcceptance: data.reactionAcceptance,
visibility: data.visibility as any,
visibleUserIds: data.visibility === 'specified'
? data.visibleUsers

View File

@@ -99,8 +99,12 @@ export class ReactionService {
throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.');
}
// TODO: cache
reaction = await this.toDbReaction(reaction, user.host);
if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote') && (user.host != null))) {
reaction = '❤️';
} else {
// TODO: cache
reaction = await this.toDbReaction(reaction, user.host);
}
const record: NoteReaction = {
id: this.idService.genId(),

View File

@@ -314,6 +314,7 @@ export class NoteEntityService implements OnModuleInit {
cw: note.cw,
visibility: note.visibility,
localOnly: note.localOnly ?? undefined,
reactionAcceptance: note.reactionAcceptance,
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
renoteCount: note.renoteCount,
repliesCount: note.repliesCount,

View File

@@ -95,7 +95,7 @@ export interface Schema extends OfSchema {
readonly example?: any;
readonly format?: string;
readonly ref?: keyof typeof refs;
readonly enum?: ReadonlyArray<string>;
readonly enum?: ReadonlyArray<string | null>;
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
readonly maxLength?: number;
readonly minLength?: number;
@@ -161,7 +161,7 @@ export type SchemaTypeDef<p extends Schema> =
p['type'] extends 'integer' ? number :
p['type'] extends 'number' ? number :
p['type'] extends 'string' ? (
p['enum'] extends readonly string[] ?
p['enum'] extends readonly (string | null)[] ?
p['enum'][number] :
p['format'] extends 'date-time' ? string : // Dateにする
string

View File

@@ -87,6 +87,11 @@ export class Note {
})
public localOnly: boolean;
@Column('varchar', {
length: 64, nullable: true,
})
public reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | null;
@Column('smallint', {
default: 0,
})

View File

@@ -141,6 +141,10 @@ export const packedNoteSchema = {
type: 'boolean',
optional: true, nullable: false,
},
reactionAcceptance: {
type: 'string',
optional: false, nullable: true,
},
reactions: {
type: 'object',
optional: false, nullable: false,

View File

@@ -148,6 +148,7 @@ function serialize(favorite: NoteFavorite & { note: Note & { user: User } }, pol
visibility: favorite.note.visibility,
visibleUserIds: favorite.note.visibleUserIds,
localOnly: favorite.note.localOnly,
reactionAcceptance: favorite.note.reactionAcceptance,
uri: favorite.note.uri,
url: favorite.note.url,
user: {

View File

@@ -10,10 +10,10 @@ import { DriveService } from '@/core/DriveService.js';
import { createTemp } from '@/misc/create-temp.js';
import type { Poll } from '@/models/entities/Poll.js';
import type { Note } from '@/models/entities/Note.js';
import { bindThis } from '@/decorators.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type Bull from 'bull';
import type { DbUserJobData } from '../types.js';
import { bindThis } from '@/decorators.js';
@Injectable()
export class ExportNotesProcessorService {
@@ -141,5 +141,6 @@ function serialize(note: Note, poll: Poll | null = null): Record<string, unknown
visibility: note.visibility,
visibleUserIds: note.visibleUserIds,
localOnly: note.localOnly,
reactionAcceptance: note.reactionAcceptance,
};
}

View File

@@ -97,6 +97,7 @@ export const paramDef = {
} },
cw: { type: 'string', nullable: true, maxLength: 100 },
localOnly: { type: 'boolean', default: false },
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote'], default: null },
noExtractMentions: { type: 'boolean', default: false },
noExtractHashtags: { type: 'boolean', default: false },
noExtractEmojis: { type: 'boolean', default: false },
@@ -110,7 +111,7 @@ export const paramDef = {
type: 'string',
minLength: 1,
maxLength: MAX_NOTE_TEXT_LENGTH,
nullable: false
nullable: false,
},
fileIds: {
type: 'array',
@@ -280,6 +281,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
renote,
cw: ps.cw,
localOnly: ps.localOnly,
reactionAcceptance: ps.reactionAcceptance,
visibility: ps.visibility,
visibleUsers,
channel,