Compare commits
6 Commits
develop
...
sp-reactio
| Author | SHA1 | Date |
|---|---|---|
|
|
f08d6e46df | |
|
|
d53b2f532a | |
|
|
40f6acd720 | |
|
|
9dc4762fe0 | |
|
|
f3d26722bb | |
|
|
5eb873ff91 |
|
|
@ -1778,6 +1778,12 @@ _serverSettings:
|
||||||
entrancePageStyle: "エントランスページのスタイル"
|
entrancePageStyle: "エントランスページのスタイル"
|
||||||
showTimelineForVisitor: "タイムラインを表示する"
|
showTimelineForVisitor: "タイムラインを表示する"
|
||||||
showActivitiesForVisitor: "アクティビティを表示する"
|
showActivitiesForVisitor: "アクティビティを表示する"
|
||||||
|
features: "機能"
|
||||||
|
|
||||||
|
_spReactions:
|
||||||
|
enable: "スペシャルリアクションを有効にする"
|
||||||
|
description1: "通常のリアクションより目立つ「スペシャルリアクション」をノートに送れる機能です。"
|
||||||
|
description2: "有効にする場合、ロールポリシーで、毎月送ることのできる最大数を設定してください。"
|
||||||
|
|
||||||
_userGeneratedContentsVisibilityForVisitor:
|
_userGeneratedContentsVisibilityForVisitor:
|
||||||
all: "全て公開"
|
all: "全て公開"
|
||||||
|
|
@ -2890,6 +2896,7 @@ _notification:
|
||||||
renote: "リノート"
|
renote: "リノート"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "リアクション"
|
reaction: "リアクション"
|
||||||
|
spReaction: "スペシャルリアクション"
|
||||||
pollEnded: "アンケートが終了"
|
pollEnded: "アンケートが終了"
|
||||||
scheduledNotePosted: "予約投稿が成功した"
|
scheduledNotePosted: "予約投稿が成功した"
|
||||||
scheduledNotePostFailed: "予約投稿が失敗した"
|
scheduledNotePostFailed: "予約投稿が失敗した"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class SpReactions1769664628306 {
|
||||||
|
name = 'SpReactions1769664628306'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {QueryRunner} queryRunner
|
||||||
|
*/
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`CREATE TABLE "note_sp_reaction" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "noteId" character varying(32) NOT NULL, "reaction" character varying(260) NOT NULL, "noteUserId" character varying(32) NOT NULL, CONSTRAINT "PK_11fd5ecdd9bb91517edfcf890d9" PRIMARY KEY ("id")); COMMENT ON COLUMN "note_sp_reaction"."noteUserId" IS '[Denormalized]'`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_3463a48b09fa41e1826ebd9f58" ON "note_sp_reaction" ("userId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_bfe4caa46cc0526bc2932d6dbe" ON "note_sp_reaction" ("noteId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_8be6eb3f4edc9940a3f8142669" ON "note_sp_reaction" ("noteUserId") `);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_b5f210b20bd987fe8584c85d33" ON "note_sp_reaction" ("userId", "noteId") `);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "enableSpReaction" boolean NOT NULL DEFAULT false`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "note_sp_reaction" ADD CONSTRAINT "FK_3463a48b09fa41e1826ebd9f585" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "note_sp_reaction" ADD CONSTRAINT "FK_bfe4caa46cc0526bc2932d6dbed" FOREIGN KEY ("noteId") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {QueryRunner} queryRunner
|
||||||
|
*/
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "note_sp_reaction" DROP CONSTRAINT "FK_bfe4caa46cc0526bc2932d6dbed"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "note_sp_reaction" DROP CONSTRAINT "FK_3463a48b09fa41e1826ebd9f585"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableSpReaction"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_b5f210b20bd987fe8584c85d33"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_8be6eb3f4edc9940a3f8142669"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_bfe4caa46cc0526bc2932d6dbe"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "public"."IDX_3463a48b09fa41e1826ebd9f58"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "note_sp_reaction"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import * as Redis from 'ioredis';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, MiMeta } from '@/models/_.js';
|
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, MiMeta, MiNoteSpReaction, NoteSpReactionsRepository } from '@/models/_.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
|
|
@ -73,6 +74,9 @@ export class ReactionService {
|
||||||
@Inject(DI.meta)
|
@Inject(DI.meta)
|
||||||
private meta: MiMeta,
|
private meta: MiMeta,
|
||||||
|
|
||||||
|
@Inject(DI.redis)
|
||||||
|
private redisClient: Redis.Redis,
|
||||||
|
|
||||||
@Inject(DI.usersRepository)
|
@Inject(DI.usersRepository)
|
||||||
private usersRepository: UsersRepository,
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
|
@ -82,6 +86,9 @@ export class ReactionService {
|
||||||
@Inject(DI.noteReactionsRepository)
|
@Inject(DI.noteReactionsRepository)
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
private noteReactionsRepository: NoteReactionsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.noteSpReactionsRepository)
|
||||||
|
private noteSpReactionsRepository: NoteSpReactionsRepository,
|
||||||
|
|
||||||
@Inject(DI.emojisRepository)
|
@Inject(DI.emojisRepository)
|
||||||
private emojisRepository: EmojisRepository,
|
private emojisRepository: EmojisRepository,
|
||||||
|
|
||||||
|
|
@ -337,6 +344,118 @@ export class ReactionService {
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async createSp(user: { id: MiUser['id']; isBot: MiUser['isBot'] }, note: MiNote, reaction: string) {
|
||||||
|
if (!this.meta.enableSpReaction) {
|
||||||
|
throw new IdentifiableError('52c432ea-b166-491c-a73b-5dd703221b20');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note.userId === user.id) {
|
||||||
|
throw new IdentifiableError('afa694bf-6661-4d72-b8f7-bfb86a7545a1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note.userHost !== null) {
|
||||||
|
throw new IdentifiableError('b59abda2-0d81-49e3-8148-80cf35ac4402');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (note.reactionAcceptance === 'likeOnly') {
|
||||||
|
throw new IdentifiableError('1b168811-a1aa-470a-9b61-7fcf807cf9c1');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await this.noteEntityService.isVisibleForMe(note, user.id)) {
|
||||||
|
throw new IdentifiableError('3ce0e3bc-7d48-4e87-a902-578c6ffd369e', 'Note not accessible for you.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// monthly limit
|
||||||
|
const policies = await this.roleService.getUserPolicies(user.id);
|
||||||
|
if (policies.spReactionsMonthlyLimit === 0) {
|
||||||
|
throw new IdentifiableError('e371be02-9478-4133-90ef-8401ee38e474');
|
||||||
|
}
|
||||||
|
const month = new Date().getUTCMonth() + 1;
|
||||||
|
const monthlySpReactionsCountMapKey = `monthlySpReactionsCountMap:${user.id}:${month}`;
|
||||||
|
const count = await this.redisClient.get(monthlySpReactionsCountMapKey);
|
||||||
|
if (count != null && parseInt(count, 10) >= policies.spReactionsMonthlyLimit) {
|
||||||
|
throw new IdentifiableError('82e1a10c-52a8-4ccb-8ff7-3678bff68444');
|
||||||
|
}
|
||||||
|
|
||||||
|
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
||||||
|
if (blocked) {
|
||||||
|
throw new IdentifiableError('388ee683-8720-4aea-9ac8-b8c92d260815');
|
||||||
|
}
|
||||||
|
|
||||||
|
const custom = reaction.match(isCustomEmojiRegexp);
|
||||||
|
if (custom) {
|
||||||
|
const name = custom[1];
|
||||||
|
const emoji = (await this.customEmojiService.localEmojisCache.fetch()).get(name);
|
||||||
|
|
||||||
|
if (emoji == null) {
|
||||||
|
throw new IdentifiableError('47c098e2-d0b6-4197-8d00-5a68bbb156be');
|
||||||
|
}
|
||||||
|
|
||||||
|
// センシティブ
|
||||||
|
if ((note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && emoji.isSensitive) {
|
||||||
|
throw new IdentifiableError('7fc2efbd-2652-4a60-975b-6eb65f60c7b3');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 && !(await this.roleService.getUserRoles(user.id)).some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id))) {
|
||||||
|
// リアクションとして使う権限がない
|
||||||
|
throw new IdentifiableError('63288e20-4251-4c62-a9d5-9da4e0bdd41e');
|
||||||
|
}
|
||||||
|
|
||||||
|
reaction = `:${name}:`;
|
||||||
|
} else {
|
||||||
|
reaction = this.normalize(reaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
const record: MiNoteSpReaction = {
|
||||||
|
id: this.idService.gen(),
|
||||||
|
noteId: note.id,
|
||||||
|
userId: user.id,
|
||||||
|
reaction,
|
||||||
|
noteUserId: note.userId,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.noteSpReactionsRepository.insert(record);
|
||||||
|
} catch (e) {
|
||||||
|
if (isDuplicateKeyValueError(e)) {
|
||||||
|
throw new IdentifiableError('c9e8b0d0-d532-4453-8cc1-5cf8e95ba764');
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment monthly reactions count
|
||||||
|
const redisPipeline = this.redisClient.pipeline();
|
||||||
|
redisPipeline.incr(monthlySpReactionsCountMapKey);
|
||||||
|
redisPipeline.expireat(monthlySpReactionsCountMapKey,
|
||||||
|
(Date.now() / 1000) + (60 * 60 * 24 * 40), // TTLは最低でも一か月存続しさえすれば厳密でなくていい
|
||||||
|
'NX',
|
||||||
|
);
|
||||||
|
redisPipeline.exec();
|
||||||
|
|
||||||
|
// 3日以内に投稿されたノートの場合ハイライト用ランキング更新
|
||||||
|
if (
|
||||||
|
(Date.now() - this.idService.parse(note.id).date.getTime()) < 1000 * 60 * 60 * 24 * 3
|
||||||
|
) {
|
||||||
|
if (note.channelId != null) {
|
||||||
|
if (note.replyId == null) {
|
||||||
|
this.featuredService.updateInChannelNotesRanking(note.channelId, note.id, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (note.visibility === 'public' && note.replyId == null) {
|
||||||
|
this.featuredService.updateGlobalNotesRanking(note.id, 1);
|
||||||
|
this.featuredService.updatePerUserNotesRanking(note.userId, note.id, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notificationService.createNotification(note.userId, 'spReaction', {
|
||||||
|
noteId: note.id,
|
||||||
|
reaction: reaction,
|
||||||
|
}, user.id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - 文字列タイプのレガシーな形式のリアクションを現在の形式に変換する
|
* - 文字列タイプのレガシーな形式のリアクションを現在の形式に変換する
|
||||||
* - ローカルのリアクションのホストを `@.` にする(`decodeReaction()`の効果)
|
* - ローカルのリアクションのホストを `@.` にする(`decodeReaction()`の効果)
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,7 @@ export type RolePolicies = {
|
||||||
noteDraftLimit: number;
|
noteDraftLimit: number;
|
||||||
scheduledNoteLimit: number;
|
scheduledNoteLimit: number;
|
||||||
watermarkAvailable: boolean;
|
watermarkAvailable: boolean;
|
||||||
|
spReactionsMonthlyLimit: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DEFAULT_POLICIES: RolePolicies = {
|
export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
|
|
@ -118,6 +119,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
noteDraftLimit: 10,
|
noteDraftLimit: 10,
|
||||||
scheduledNoteLimit: 1,
|
scheduledNoteLimit: 1,
|
||||||
watermarkAvailable: true,
|
watermarkAvailable: true,
|
||||||
|
spReactionsMonthlyLimit: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set([
|
||||||
'renote:grouped',
|
'renote:grouped',
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
|
'spReaction',
|
||||||
'reaction:grouped',
|
'reaction:grouped',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
'scheduledNotePosted',
|
'scheduledNotePosted',
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ export const DI = {
|
||||||
noteFavoritesRepository: Symbol('noteFavoritesRepository'),
|
noteFavoritesRepository: Symbol('noteFavoritesRepository'),
|
||||||
noteThreadMutingsRepository: Symbol('noteThreadMutingsRepository'),
|
noteThreadMutingsRepository: Symbol('noteThreadMutingsRepository'),
|
||||||
noteReactionsRepository: Symbol('noteReactionsRepository'),
|
noteReactionsRepository: Symbol('noteReactionsRepository'),
|
||||||
|
noteSpReactionsRepository: Symbol('noteSpReactionsRepository'),
|
||||||
pollsRepository: Symbol('pollsRepository'),
|
pollsRepository: Symbol('pollsRepository'),
|
||||||
pollVotesRepository: Symbol('pollVotesRepository'),
|
pollVotesRepository: Symbol('pollVotesRepository'),
|
||||||
userProfilesRepository: Symbol('userProfilesRepository'),
|
userProfilesRepository: Symbol('userProfilesRepository'),
|
||||||
|
|
|
||||||
|
|
@ -722,6 +722,11 @@ export class MiMeta {
|
||||||
})
|
})
|
||||||
public showRoleBadgesOfRemoteUsers: boolean;
|
public showRoleBadgesOfRemoteUsers: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
public enableSpReaction: boolean;
|
||||||
|
|
||||||
@Column('jsonb', {
|
@Column('jsonb', {
|
||||||
default: { },
|
default: { },
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { PrimaryColumn, Entity, Index, JoinColumn, Column, ManyToOne } from 'typeorm';
|
||||||
|
import { id } from './util/id.js';
|
||||||
|
import { MiUser } from './User.js';
|
||||||
|
import { MiNote } from './Note.js';
|
||||||
|
|
||||||
|
@Entity('note_sp_reaction')
|
||||||
|
@Index(['userId', 'noteId'], { unique: true })
|
||||||
|
export class MiNoteSpReaction {
|
||||||
|
@PrimaryColumn(id())
|
||||||
|
public id: string;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column(id())
|
||||||
|
public userId: MiUser['id'];
|
||||||
|
|
||||||
|
@ManyToOne(() => MiUser, {
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
})
|
||||||
|
@JoinColumn()
|
||||||
|
public user?: MiUser | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column(id())
|
||||||
|
public noteId: MiNote['id'];
|
||||||
|
|
||||||
|
@ManyToOne(() => MiNote, {
|
||||||
|
onDelete: 'CASCADE',
|
||||||
|
})
|
||||||
|
@JoinColumn()
|
||||||
|
public note?: MiNote | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 260,
|
||||||
|
})
|
||||||
|
public reaction: string;
|
||||||
|
|
||||||
|
//#region Denormalized fields
|
||||||
|
@Index()
|
||||||
|
@Column({
|
||||||
|
...id(),
|
||||||
|
comment: '[Denormalized]',
|
||||||
|
})
|
||||||
|
public noteUserId: MiUser['id'];
|
||||||
|
//#endregion
|
||||||
|
}
|
||||||
|
|
@ -55,6 +55,13 @@ export type MiNotification = {
|
||||||
notifierId: MiUser['id'];
|
notifierId: MiUser['id'];
|
||||||
noteId: MiNote['id'];
|
noteId: MiNote['id'];
|
||||||
reaction: string;
|
reaction: string;
|
||||||
|
} | {
|
||||||
|
type: 'spReaction';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
notifierId: MiUser['id'];
|
||||||
|
noteId: MiNote['id'];
|
||||||
|
reaction: string;
|
||||||
} | {
|
} | {
|
||||||
type: 'pollEnded';
|
type: 'pollEnded';
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ import {
|
||||||
MiNote,
|
MiNote,
|
||||||
MiNoteFavorite,
|
MiNoteFavorite,
|
||||||
MiNoteReaction,
|
MiNoteReaction,
|
||||||
|
MiNoteSpReaction,
|
||||||
MiNoteThreadMuting,
|
MiNoteThreadMuting,
|
||||||
MiNoteDraft,
|
MiNoteDraft,
|
||||||
MiPage,
|
MiPage,
|
||||||
|
|
@ -142,6 +143,12 @@ const $noteReactionsRepository: Provider = {
|
||||||
inject: [DI.db],
|
inject: [DI.db],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const $noteSpReactionsRepository: Provider = {
|
||||||
|
provide: DI.noteSpReactionsRepository,
|
||||||
|
useFactory: (db: DataSource) => db.getRepository(MiNoteSpReaction).extend(miRepository as MiRepository<MiNoteSpReaction>),
|
||||||
|
inject: [DI.db],
|
||||||
|
};
|
||||||
|
|
||||||
const $noteDraftsRepository: Provider = {
|
const $noteDraftsRepository: Provider = {
|
||||||
provide: DI.noteDraftsRepository,
|
provide: DI.noteDraftsRepository,
|
||||||
useFactory: (db: DataSource) => db.getRepository(MiNoteDraft).extend(miRepository as MiRepository<MiNoteDraft>),
|
useFactory: (db: DataSource) => db.getRepository(MiNoteDraft).extend(miRepository as MiRepository<MiNoteDraft>),
|
||||||
|
|
@ -556,6 +563,7 @@ const $reversiGamesRepository: Provider = {
|
||||||
$noteFavoritesRepository,
|
$noteFavoritesRepository,
|
||||||
$noteThreadMutingsRepository,
|
$noteThreadMutingsRepository,
|
||||||
$noteReactionsRepository,
|
$noteReactionsRepository,
|
||||||
|
$noteSpReactionsRepository,
|
||||||
$noteDraftsRepository,
|
$noteDraftsRepository,
|
||||||
$pollsRepository,
|
$pollsRepository,
|
||||||
$pollVotesRepository,
|
$pollVotesRepository,
|
||||||
|
|
@ -634,6 +642,7 @@ const $reversiGamesRepository: Provider = {
|
||||||
$noteFavoritesRepository,
|
$noteFavoritesRepository,
|
||||||
$noteThreadMutingsRepository,
|
$noteThreadMutingsRepository,
|
||||||
$noteReactionsRepository,
|
$noteReactionsRepository,
|
||||||
|
$noteSpReactionsRepository,
|
||||||
$noteDraftsRepository,
|
$noteDraftsRepository,
|
||||||
$pollsRepository,
|
$pollsRepository,
|
||||||
$pollVotesRepository,
|
$pollVotesRepository,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
|
||||||
import { MiChannel } from '@/models/Channel.js';
|
import { MiChannel } from '@/models/Channel.js';
|
||||||
import { MiChannelFavorite } from '@/models/ChannelFavorite.js';
|
import { MiChannelFavorite } from '@/models/ChannelFavorite.js';
|
||||||
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
|
import { MiChannelFollowing } from '@/models/ChannelFollowing.js';
|
||||||
import { MiChannelMuting } from "@/models/ChannelMuting.js";
|
import { MiChannelMuting } from '@/models/ChannelMuting.js';
|
||||||
import { MiChatApproval } from '@/models/ChatApproval.js';
|
import { MiChatApproval } from '@/models/ChatApproval.js';
|
||||||
import { MiChatMessage } from '@/models/ChatMessage.js';
|
import { MiChatMessage } from '@/models/ChatMessage.js';
|
||||||
import { MiChatRoom } from '@/models/ChatRoom.js';
|
import { MiChatRoom } from '@/models/ChatRoom.js';
|
||||||
|
|
@ -50,6 +50,7 @@ import { MiNote } from '@/models/Note.js';
|
||||||
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
||||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||||
|
import { MiNoteSpReaction } from '@/models/NoteSpReaction.js';
|
||||||
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
||||||
import { MiPage } from '@/models/Page.js';
|
import { MiPage } from '@/models/Page.js';
|
||||||
import { MiPageLike } from '@/models/PageLike.js';
|
import { MiPageLike } from '@/models/PageLike.js';
|
||||||
|
|
@ -131,6 +132,7 @@ export {
|
||||||
MiNoteDraft,
|
MiNoteDraft,
|
||||||
MiNoteFavorite,
|
MiNoteFavorite,
|
||||||
MiNoteReaction,
|
MiNoteReaction,
|
||||||
|
MiNoteSpReaction,
|
||||||
MiNoteThreadMuting,
|
MiNoteThreadMuting,
|
||||||
MiPage,
|
MiPage,
|
||||||
MiPageLike,
|
MiPageLike,
|
||||||
|
|
@ -211,6 +213,7 @@ export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
|
||||||
export type NoteDraftsRepository = Repository<MiNoteDraft> & MiRepository<MiNoteDraft>;
|
export type NoteDraftsRepository = Repository<MiNoteDraft> & MiRepository<MiNoteDraft>;
|
||||||
export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
|
export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
|
||||||
export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
|
export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
|
||||||
|
export type NoteSpReactionsRepository = Repository<MiNoteSpReaction> & MiRepository<MiNoteSpReaction>;
|
||||||
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
|
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
|
||||||
export type PagesRepository = Repository<MiPage> & MiRepository<MiPage>;
|
export type PagesRepository = Repository<MiPage> & MiRepository<MiPage>;
|
||||||
export type PageLikesRepository = Repository<MiPageLike> & MiRepository<MiPageLike>;
|
export type PageLikesRepository = Repository<MiPageLike> & MiRepository<MiPageLike>;
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,35 @@ export const packedNotificationSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
...baseSchema.properties,
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
enum: ['spReaction'],
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: 'object',
|
||||||
|
ref: 'UserLite',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
userId: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'object',
|
||||||
|
ref: 'Note',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
reaction: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
||||||
|
|
@ -608,6 +608,7 @@ export const packedMeDetailedOnlySchema = {
|
||||||
renote: { optional: true, ...notificationRecieveConfig },
|
renote: { optional: true, ...notificationRecieveConfig },
|
||||||
quote: { optional: true, ...notificationRecieveConfig },
|
quote: { optional: true, ...notificationRecieveConfig },
|
||||||
reaction: { optional: true, ...notificationRecieveConfig },
|
reaction: { optional: true, ...notificationRecieveConfig },
|
||||||
|
spReaction: { optional: true, ...notificationRecieveConfig },
|
||||||
pollEnded: { optional: true, ...notificationRecieveConfig },
|
pollEnded: { optional: true, ...notificationRecieveConfig },
|
||||||
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
||||||
scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
|
scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import { MiRenoteMuting } from '@/models/RenoteMuting.js';
|
||||||
import { MiNote } from '@/models/Note.js';
|
import { MiNote } from '@/models/Note.js';
|
||||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||||
|
import { MiNoteSpReaction } from '@/models/NoteSpReaction.js';
|
||||||
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
||||||
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
||||||
import { MiPage } from '@/models/Page.js';
|
import { MiPage } from '@/models/Page.js';
|
||||||
|
|
@ -204,6 +205,7 @@ export const entities = [
|
||||||
MiNote,
|
MiNote,
|
||||||
MiNoteFavorite,
|
MiNoteFavorite,
|
||||||
MiNoteReaction,
|
MiNoteReaction,
|
||||||
|
MiNoteSpReaction,
|
||||||
MiNoteThreadMuting,
|
MiNoteThreadMuting,
|
||||||
MiNoteDraft,
|
MiNoteDraft,
|
||||||
MiPage,
|
MiPage,
|
||||||
|
|
|
||||||
|
|
@ -596,6 +596,10 @@ export const meta = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
|
enableSpReaction: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
@ -752,6 +756,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
remoteNotesCleaningExpiryDaysForEachNotes: instance.remoteNotesCleaningExpiryDaysForEachNotes,
|
remoteNotesCleaningExpiryDaysForEachNotes: instance.remoteNotesCleaningExpiryDaysForEachNotes,
|
||||||
remoteNotesCleaningMaxProcessingDurationInMinutes: instance.remoteNotesCleaningMaxProcessingDurationInMinutes,
|
remoteNotesCleaningMaxProcessingDurationInMinutes: instance.remoteNotesCleaningMaxProcessingDurationInMinutes,
|
||||||
showRoleBadgesOfRemoteUsers: instance.showRoleBadgesOfRemoteUsers,
|
showRoleBadgesOfRemoteUsers: instance.showRoleBadgesOfRemoteUsers,
|
||||||
|
enableSpReaction: instance.enableSpReaction,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,7 @@ export const paramDef = {
|
||||||
remoteNotesCleaningExpiryDaysForEachNotes: { type: 'number' },
|
remoteNotesCleaningExpiryDaysForEachNotes: { type: 'number' },
|
||||||
remoteNotesCleaningMaxProcessingDurationInMinutes: { type: 'number' },
|
remoteNotesCleaningMaxProcessingDurationInMinutes: { type: 'number' },
|
||||||
showRoleBadgesOfRemoteUsers: { type: 'boolean' },
|
showRoleBadgesOfRemoteUsers: { type: 'boolean' },
|
||||||
|
enableSpReaction: { type: 'boolean' },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
@ -762,6 +763,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
set.showRoleBadgesOfRemoteUsers = ps.showRoleBadgesOfRemoteUsers;
|
set.showRoleBadgesOfRemoteUsers = ps.showRoleBadgesOfRemoteUsers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.enableSpReaction !== undefined) {
|
||||||
|
set.enableSpReaction = ps.enableSpReaction;
|
||||||
|
}
|
||||||
|
|
||||||
const before = await this.metaService.fetch(true);
|
const before = await this.metaService.fetch(true);
|
||||||
|
|
||||||
await this.metaService.update(set);
|
await this.metaService.update(set);
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,7 @@ export const paramDef = {
|
||||||
renote: notificationRecieveConfig,
|
renote: notificationRecieveConfig,
|
||||||
quote: notificationRecieveConfig,
|
quote: notificationRecieveConfig,
|
||||||
reaction: notificationRecieveConfig,
|
reaction: notificationRecieveConfig,
|
||||||
|
spReaction: notificationRecieveConfig,
|
||||||
pollEnded: notificationRecieveConfig,
|
pollEnded: notificationRecieveConfig,
|
||||||
scheduledNotePosted: notificationRecieveConfig,
|
scheduledNotePosted: notificationRecieveConfig,
|
||||||
scheduledNotePostFailed: notificationRecieveConfig,
|
scheduledNotePostFailed: notificationRecieveConfig,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
* renote - 投稿がRenoteされた
|
* renote - 投稿がRenoteされた
|
||||||
* quote - 投稿が引用Renoteされた
|
* quote - 投稿が引用Renoteされた
|
||||||
* reaction - 投稿にリアクションされた
|
* reaction - 投稿にリアクションされた
|
||||||
|
* spReaction - スペシャルリアクションされた
|
||||||
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
||||||
* scheduledNotePosted - 予約したノートが投稿された
|
* scheduledNotePosted - 予約したノートが投稿された
|
||||||
* scheduledNotePostFailed - 予約したノートの投稿に失敗した
|
* scheduledNotePostFailed - 予約したノートの投稿に失敗した
|
||||||
|
|
@ -33,6 +34,7 @@ export const notificationTypes = [
|
||||||
'renote',
|
'renote',
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
|
'spReaction',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
'scheduledNotePosted',
|
'scheduledNotePosted',
|
||||||
'scheduledNotePostFailed',
|
'scheduledNotePostFailed',
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
|
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
|
||||||
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
||||||
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
||||||
|
<i v-else-if="notification.type === 'spReaction'" class="ti ti-octahedron-plus"></i>
|
||||||
<i v-else-if="notification.type === 'scheduledNotePosted'" class="ti ti-send"></i>
|
<i v-else-if="notification.type === 'scheduledNotePosted'" class="ti ti-send"></i>
|
||||||
<i v-else-if="notification.type === 'scheduledNotePostFailed'" class="ti ti-alert-triangle"></i>
|
<i v-else-if="notification.type === 'scheduledNotePostFailed'" class="ti ti-alert-triangle"></i>
|
||||||
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
||||||
|
|
@ -74,7 +75,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<span v-else-if="notification.type === 'createToken'">{{ i18n.ts._notification.createToken }}</span>
|
<span v-else-if="notification.type === 'createToken'">{{ i18n.ts._notification.createToken }}</span>
|
||||||
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
<span v-else-if="notification.type === 'test'">{{ i18n.ts._notification.testNotification }}</span>
|
||||||
<span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span>
|
<span v-else-if="notification.type === 'exportCompleted'">{{ i18n.tsx._notification.exportOfXCompleted({ x: exportEntityName[notification.exportedEntity] }) }}</span>
|
||||||
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
<MkA v-else-if="notification.type === 'follow' || notification.type === 'mention' || notification.type === 'reply' || notification.type === 'renote' || notification.type === 'quote' || notification.type === 'reaction' || notification.type === 'spReaction' || notification.type === 'receiveFollowRequest' || notification.type === 'followRequestAccepted'" v-user-preview="notification.user.id" :class="$style.headerName" :to="userPage(notification.user)"><MkUserName :user="notification.user"/></MkA>
|
||||||
<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
<span v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'">{{ i18n.tsx._notification.likedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
||||||
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
<span v-else-if="notification.type === 'reaction:grouped'">{{ i18n.tsx._notification.reactedBySomeUsers({ n: getActualReactedUsersCount(notification) }) }}</span>
|
||||||
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
|
<span v-else-if="notification.type === 'renote:grouped'">{{ i18n.tsx._notification.renotedBySomeUsers({ n: notification.users.length }) }}</span>
|
||||||
|
|
@ -82,7 +83,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
||||||
</header>
|
</header>
|
||||||
<div>
|
<div>
|
||||||
<MkA v-if="notification.type === 'reaction' || notification.type === 'reaction:grouped'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'reaction' || notification.type === 'reaction:grouped' || notification.type === 'spReaction'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
||||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,28 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
|
||||||
|
<SearchMarker v-slot="slotProps" :keywords="['features']">
|
||||||
|
<MkFolder :defaultOpen="slotProps.isParentOfTarget">
|
||||||
|
<template #icon><SearchIcon><i class="ti ti-puzzle"></i></SearchIcon></template>
|
||||||
|
<template #label><SearchLabel>{{ i18n.ts._serverSettings.features }}</SearchLabel></template>
|
||||||
|
<template v-if="featuresForm.modified.value" #footer>
|
||||||
|
<MkFormFooter :form="featuresForm"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="_gaps">
|
||||||
|
<SearchMarker>
|
||||||
|
<MkSwitch v-model="featuresForm.state.enableSpReaction">
|
||||||
|
<template #label><SearchLabel>{{ i18n.ts._serverSettings._spReactions.enable }}</SearchLabel><span v-if="featuresForm.modifiedStates.enableSpReaction" class="_modified">{{ i18n.ts.modified }}</span></template>
|
||||||
|
<template #caption>
|
||||||
|
<SearchText>{{ i18n.ts._serverSettings._spReactions.description1 }}</SearchText>
|
||||||
|
<div>{{ i18n.ts._serverSettings._spReactions.description2 }}</div>
|
||||||
|
</template>
|
||||||
|
</MkSwitch>
|
||||||
|
</SearchMarker>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
</SearchMarker>
|
||||||
|
|
||||||
<SearchMarker v-slot="slotProps" :keywords="['pinned', 'users']">
|
<SearchMarker v-slot="slotProps" :keywords="['pinned', 'users']">
|
||||||
<MkFolder :defaultOpen="slotProps.isParentOfTarget">
|
<MkFolder :defaultOpen="slotProps.isParentOfTarget">
|
||||||
<template #icon><SearchIcon><i class="ti ti-user-star"></i></SearchIcon></template>
|
<template #icon><SearchIcon><i class="ti ti-user-star"></i></SearchIcon></template>
|
||||||
|
|
@ -426,6 +448,15 @@ const infoForm = useForm({
|
||||||
fetchInstance(true);
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const featuresForm = useForm({
|
||||||
|
enableSpReaction: meta.enableSpReaction,
|
||||||
|
}, async (state) => {
|
||||||
|
await os.apiWithDialog('admin/update-meta', {
|
||||||
|
enableSpReaction: state.enableSpReaction,
|
||||||
|
});
|
||||||
|
fetchInstance(true);
|
||||||
|
});
|
||||||
|
|
||||||
const pinnedUsersForm = useForm({
|
const pinnedUsersForm = useForm({
|
||||||
pinnedUsers: meta.pinnedUsers.join('\n'),
|
pinnedUsers: meta.pinnedUsers.join('\n'),
|
||||||
}, async (state) => {
|
}, async (state) => {
|
||||||
|
|
|
||||||
|
|
@ -6972,6 +6972,24 @@ export interface Locale extends ILocale {
|
||||||
* アクティビティを表示する
|
* アクティビティを表示する
|
||||||
*/
|
*/
|
||||||
"showActivitiesForVisitor": string;
|
"showActivitiesForVisitor": string;
|
||||||
|
/**
|
||||||
|
* 機能
|
||||||
|
*/
|
||||||
|
"features": string;
|
||||||
|
"_spReactions": {
|
||||||
|
/**
|
||||||
|
* スペシャルリアクションを有効にする
|
||||||
|
*/
|
||||||
|
"enable": string;
|
||||||
|
/**
|
||||||
|
* 通常のリアクションより目立つ「スペシャルリアクション」をノートに送れる機能です。
|
||||||
|
*/
|
||||||
|
"description1": string;
|
||||||
|
/**
|
||||||
|
* 有効にする場合、ロールポリシーで、毎月送ることのできる最大数を設定してください。
|
||||||
|
*/
|
||||||
|
"description2": string;
|
||||||
|
};
|
||||||
"_userGeneratedContentsVisibilityForVisitor": {
|
"_userGeneratedContentsVisibilityForVisitor": {
|
||||||
/**
|
/**
|
||||||
* 全て公開
|
* 全て公開
|
||||||
|
|
@ -10929,6 +10947,10 @@ export interface Locale extends ILocale {
|
||||||
* リアクション
|
* リアクション
|
||||||
*/
|
*/
|
||||||
"reaction": string;
|
"reaction": string;
|
||||||
|
/**
|
||||||
|
* スペシャルリアクション
|
||||||
|
*/
|
||||||
|
"spReaction": string;
|
||||||
/**
|
/**
|
||||||
* アンケートが終了
|
* アンケートが終了
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3251,7 +3251,7 @@ type Notification_2 = components['schemas']['Notification'];
|
||||||
type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
|
type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollEnded", "scheduledNotePosted", "scheduledNotePostFailed", "receiveFollowRequest", "followRequestAccepted", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
|
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "spReaction", "pollEnded", "scheduledNotePosted", "scheduledNotePostFailed", "receiveFollowRequest", "followRequestAccepted", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function nyaize(text: string): string;
|
export function nyaize(text: string): string;
|
||||||
|
|
@ -3466,7 +3466,7 @@ type RoleLite = components['schemas']['RoleLite'];
|
||||||
type RolePolicies = components['schemas']['RolePolicies'];
|
type RolePolicies = components['schemas']['RolePolicies'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const rolePolicies: readonly ["gtlAvailable", "ltlAvailable", "canPublicNote", "mentionLimit", "canInvite", "inviteLimit", "inviteLimitCycle", "inviteExpirationTime", "canManageCustomEmojis", "canManageAvatarDecorations", "canSearchNotes", "canSearchUsers", "canUseTranslator", "canHideAds", "driveCapacityMb", "maxFileSizeMb", "alwaysMarkNsfw", "canUpdateBioMedia", "pinLimit", "antennaLimit", "wordMuteLimit", "webhookLimit", "clipLimit", "noteEachClipsLimit", "userListLimit", "userEachUserListsLimit", "rateLimitFactor", "avatarDecorationLimit", "canImportAntennas", "canImportBlocking", "canImportFollowing", "canImportMuting", "canImportUserLists", "chatAvailability", "uploadableFileTypes", "noteDraftLimit", "scheduledNoteLimit", "watermarkAvailable"];
|
export const rolePolicies: readonly ["gtlAvailable", "ltlAvailable", "canPublicNote", "mentionLimit", "canInvite", "inviteLimit", "inviteLimitCycle", "inviteExpirationTime", "canManageCustomEmojis", "canManageAvatarDecorations", "canSearchNotes", "canSearchUsers", "canUseTranslator", "canHideAds", "driveCapacityMb", "maxFileSizeMb", "alwaysMarkNsfw", "canUpdateBioMedia", "pinLimit", "antennaLimit", "wordMuteLimit", "webhookLimit", "clipLimit", "noteEachClipsLimit", "userListLimit", "userEachUserListsLimit", "rateLimitFactor", "avatarDecorationLimit", "canImportAntennas", "canImportBlocking", "canImportFollowing", "canImportMuting", "canImportUserLists", "chatAvailability", "uploadableFileTypes", "noteDraftLimit", "scheduledNoteLimit", "watermarkAvailable", "spReactionsMonthlyLimit"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
||||||
|
|
|
||||||
|
|
@ -4186,6 +4186,15 @@ export type components = {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
|
spReaction?: {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
} | {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'list';
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userListId: string;
|
||||||
|
};
|
||||||
pollEnded?: {
|
pollEnded?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
|
@ -4622,6 +4631,18 @@ export type components = {
|
||||||
userId: string;
|
userId: string;
|
||||||
note: components['schemas']['Note'];
|
note: components['schemas']['Note'];
|
||||||
reaction: string;
|
reaction: string;
|
||||||
|
} | {
|
||||||
|
/** Format: id */
|
||||||
|
id: string;
|
||||||
|
/** Format: date-time */
|
||||||
|
createdAt: string;
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'spReaction';
|
||||||
|
user: components['schemas']['UserLite'];
|
||||||
|
/** Format: id */
|
||||||
|
userId: string;
|
||||||
|
note: components['schemas']['Note'];
|
||||||
|
reaction: string;
|
||||||
} | {
|
} | {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -9520,6 +9541,7 @@ export interface operations {
|
||||||
remoteNotesCleaningExpiryDaysForEachNotes: number;
|
remoteNotesCleaningExpiryDaysForEachNotes: number;
|
||||||
remoteNotesCleaningMaxProcessingDurationInMinutes: number;
|
remoteNotesCleaningMaxProcessingDurationInMinutes: number;
|
||||||
showRoleBadgesOfRemoteUsers: boolean;
|
showRoleBadgesOfRemoteUsers: boolean;
|
||||||
|
enableSpReaction: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -12846,6 +12868,7 @@ export interface operations {
|
||||||
remoteNotesCleaningExpiryDaysForEachNotes?: number;
|
remoteNotesCleaningExpiryDaysForEachNotes?: number;
|
||||||
remoteNotesCleaningMaxProcessingDurationInMinutes?: number;
|
remoteNotesCleaningMaxProcessingDurationInMinutes?: number;
|
||||||
showRoleBadgesOfRemoteUsers?: boolean;
|
showRoleBadgesOfRemoteUsers?: boolean;
|
||||||
|
enableSpReaction?: boolean;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -26250,8 +26273,8 @@ export interface operations {
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
markAsRead?: boolean;
|
markAsRead?: boolean;
|
||||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'spReaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'spReaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -26335,8 +26358,8 @@ export interface operations {
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
markAsRead?: boolean;
|
markAsRead?: boolean;
|
||||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'spReaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'spReaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -27601,6 +27624,15 @@ export interface operations {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
|
spReaction?: {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
} | {
|
||||||
|
/** @enum {string} */
|
||||||
|
type: 'list';
|
||||||
|
/** Format: misskey:id */
|
||||||
|
userListId: string;
|
||||||
|
};
|
||||||
pollEnded?: {
|
pollEnded?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ export const notificationTypes = [
|
||||||
'renote',
|
'renote',
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
|
'spReaction',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
'scheduledNotePosted',
|
'scheduledNotePosted',
|
||||||
'scheduledNotePostFailed',
|
'scheduledNotePostFailed',
|
||||||
|
|
@ -229,6 +230,7 @@ export const rolePolicies = [
|
||||||
'noteDraftLimit',
|
'noteDraftLimit',
|
||||||
'scheduledNoteLimit',
|
'scheduledNoteLimit',
|
||||||
'watermarkAvailable',
|
'watermarkAvailable',
|
||||||
|
'spReactionsMonthlyLimit',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const queueTypes = [
|
export const queueTypes = [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue