Compare commits
6 Commits
develop
...
sp-reactio
| Author | SHA1 | Date |
|---|---|---|
|
|
f08d6e46df | |
|
|
d53b2f532a | |
|
|
40f6acd720 | |
|
|
9dc4762fe0 | |
|
|
f3d26722bb | |
|
|
5eb873ff91 |
|
|
@ -31,7 +31,6 @@
|
|||
- JSONによるClient Information Discoveryを行うには、レスポンスの`Content-Type`ヘッダーが`application/json`である必要があります
|
||||
- 従来の実装(12 February 2022版・HTML Microformat形式)も引き続きサポートされます
|
||||
- Enhance: メモリ使用量を削減
|
||||
- Fix: `/admin/get-user-ips` エンドポイントのアクセス権限を管理者のみに修正
|
||||
|
||||
## 2025.12.2
|
||||
|
||||
|
|
|
|||
|
|
@ -1778,6 +1778,12 @@ _serverSettings:
|
|||
entrancePageStyle: "エントランスページのスタイル"
|
||||
showTimelineForVisitor: "タイムラインを表示する"
|
||||
showActivitiesForVisitor: "アクティビティを表示する"
|
||||
features: "機能"
|
||||
|
||||
_spReactions:
|
||||
enable: "スペシャルリアクションを有効にする"
|
||||
description1: "通常のリアクションより目立つ「スペシャルリアクション」をノートに送れる機能です。"
|
||||
description2: "有効にする場合、ロールポリシーで、毎月送ることのできる最大数を設定してください。"
|
||||
|
||||
_userGeneratedContentsVisibilityForVisitor:
|
||||
all: "全て公開"
|
||||
|
|
@ -2890,6 +2896,7 @@ _notification:
|
|||
renote: "リノート"
|
||||
quote: "引用"
|
||||
reaction: "リアクション"
|
||||
spReaction: "スペシャルリアクション"
|
||||
pollEnded: "アンケートが終了"
|
||||
scheduledNotePosted: "予約投稿が成功した"
|
||||
scheduledNotePostFailed: "予約投稿が失敗した"
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
"ignore-walk": "8.0.0",
|
||||
"js-yaml": "4.1.1",
|
||||
"postcss": "8.5.6",
|
||||
"tar": "7.5.7",
|
||||
"tar": "7.5.6",
|
||||
"terser": "5.46.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -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 * as Redis from 'ioredis';
|
||||
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 type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||
import type { MiNote } from '@/models/Note.js';
|
||||
|
|
@ -73,6 +74,9 @@ export class ReactionService {
|
|||
@Inject(DI.meta)
|
||||
private meta: MiMeta,
|
||||
|
||||
@Inject(DI.redis)
|
||||
private redisClient: Redis.Redis,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
|
|
@ -82,6 +86,9 @@ export class ReactionService {
|
|||
@Inject(DI.noteReactionsRepository)
|
||||
private noteReactionsRepository: NoteReactionsRepository,
|
||||
|
||||
@Inject(DI.noteSpReactionsRepository)
|
||||
private noteSpReactionsRepository: NoteSpReactionsRepository,
|
||||
|
||||
@Inject(DI.emojisRepository)
|
||||
private emojisRepository: EmojisRepository,
|
||||
|
||||
|
|
@ -337,6 +344,118 @@ export class ReactionService {
|
|||
//#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()`の効果)
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ export type RolePolicies = {
|
|||
noteDraftLimit: number;
|
||||
scheduledNoteLimit: number;
|
||||
watermarkAvailable: boolean;
|
||||
spReactionsMonthlyLimit: number;
|
||||
};
|
||||
|
||||
export const DEFAULT_POLICIES: RolePolicies = {
|
||||
|
|
@ -118,6 +119,7 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
|||
noteDraftLimit: 10,
|
||||
scheduledNoteLimit: 1,
|
||||
watermarkAvailable: true,
|
||||
spReactionsMonthlyLimit: 0,
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set([
|
|||
'renote:grouped',
|
||||
'quote',
|
||||
'reaction',
|
||||
'spReaction',
|
||||
'reaction:grouped',
|
||||
'pollEnded',
|
||||
'scheduledNotePosted',
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export const DI = {
|
|||
noteFavoritesRepository: Symbol('noteFavoritesRepository'),
|
||||
noteThreadMutingsRepository: Symbol('noteThreadMutingsRepository'),
|
||||
noteReactionsRepository: Symbol('noteReactionsRepository'),
|
||||
noteSpReactionsRepository: Symbol('noteSpReactionsRepository'),
|
||||
pollsRepository: Symbol('pollsRepository'),
|
||||
pollVotesRepository: Symbol('pollVotesRepository'),
|
||||
userProfilesRepository: Symbol('userProfilesRepository'),
|
||||
|
|
|
|||
|
|
@ -722,6 +722,11 @@ export class MiMeta {
|
|||
})
|
||||
public showRoleBadgesOfRemoteUsers: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public enableSpReaction: boolean;
|
||||
|
||||
@Column('jsonb', {
|
||||
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'];
|
||||
noteId: MiNote['id'];
|
||||
reaction: string;
|
||||
} | {
|
||||
type: 'spReaction';
|
||||
id: string;
|
||||
createdAt: string;
|
||||
notifierId: MiUser['id'];
|
||||
noteId: MiNote['id'];
|
||||
reaction: string;
|
||||
} | {
|
||||
type: 'pollEnded';
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import {
|
|||
MiNote,
|
||||
MiNoteFavorite,
|
||||
MiNoteReaction,
|
||||
MiNoteSpReaction,
|
||||
MiNoteThreadMuting,
|
||||
MiNoteDraft,
|
||||
MiPage,
|
||||
|
|
@ -142,6 +143,12 @@ const $noteReactionsRepository: Provider = {
|
|||
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 = {
|
||||
provide: DI.noteDraftsRepository,
|
||||
useFactory: (db: DataSource) => db.getRepository(MiNoteDraft).extend(miRepository as MiRepository<MiNoteDraft>),
|
||||
|
|
@ -556,6 +563,7 @@ const $reversiGamesRepository: Provider = {
|
|||
$noteFavoritesRepository,
|
||||
$noteThreadMutingsRepository,
|
||||
$noteReactionsRepository,
|
||||
$noteSpReactionsRepository,
|
||||
$noteDraftsRepository,
|
||||
$pollsRepository,
|
||||
$pollVotesRepository,
|
||||
|
|
@ -634,6 +642,7 @@ const $reversiGamesRepository: Provider = {
|
|||
$noteFavoritesRepository,
|
||||
$noteThreadMutingsRepository,
|
||||
$noteReactionsRepository,
|
||||
$noteSpReactionsRepository,
|
||||
$noteDraftsRepository,
|
||||
$pollsRepository,
|
||||
$pollVotesRepository,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
|
|||
import { MiChannel } from '@/models/Channel.js';
|
||||
import { MiChannelFavorite } from '@/models/ChannelFavorite.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 { MiChatMessage } from '@/models/ChatMessage.js';
|
||||
import { MiChatRoom } from '@/models/ChatRoom.js';
|
||||
|
|
@ -50,6 +50,7 @@ import { MiNote } from '@/models/Note.js';
|
|||
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||
import { MiNoteSpReaction } from '@/models/NoteSpReaction.js';
|
||||
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
||||
import { MiPage } from '@/models/Page.js';
|
||||
import { MiPageLike } from '@/models/PageLike.js';
|
||||
|
|
@ -131,6 +132,7 @@ export {
|
|||
MiNoteDraft,
|
||||
MiNoteFavorite,
|
||||
MiNoteReaction,
|
||||
MiNoteSpReaction,
|
||||
MiNoteThreadMuting,
|
||||
MiPage,
|
||||
MiPageLike,
|
||||
|
|
@ -211,6 +213,7 @@ export type NotesRepository = Repository<MiNote> & MiRepository<MiNote>;
|
|||
export type NoteDraftsRepository = Repository<MiNoteDraft> & MiRepository<MiNoteDraft>;
|
||||
export type NoteFavoritesRepository = Repository<MiNoteFavorite> & MiRepository<MiNoteFavorite>;
|
||||
export type NoteReactionsRepository = Repository<MiNoteReaction> & MiRepository<MiNoteReaction>;
|
||||
export type NoteSpReactionsRepository = Repository<MiNoteSpReaction> & MiRepository<MiNoteSpReaction>;
|
||||
export type NoteThreadMutingsRepository = Repository<MiNoteThreadMuting> & MiRepository<MiNoteThreadMuting>;
|
||||
export type PagesRepository = Repository<MiPage> & MiRepository<MiPage>;
|
||||
export type PageLikesRepository = Repository<MiPageLike> & MiRepository<MiPageLike>;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,35 @@ export const packedNotificationSchema = {
|
|||
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',
|
||||
properties: {
|
||||
|
|
|
|||
|
|
@ -608,6 +608,7 @@ export const packedMeDetailedOnlySchema = {
|
|||
renote: { optional: true, ...notificationRecieveConfig },
|
||||
quote: { optional: true, ...notificationRecieveConfig },
|
||||
reaction: { optional: true, ...notificationRecieveConfig },
|
||||
spReaction: { optional: true, ...notificationRecieveConfig },
|
||||
pollEnded: { optional: true, ...notificationRecieveConfig },
|
||||
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
||||
scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import { MiRenoteMuting } from '@/models/RenoteMuting.js';
|
|||
import { MiNote } from '@/models/Note.js';
|
||||
import { MiNoteFavorite } from '@/models/NoteFavorite.js';
|
||||
import { MiNoteReaction } from '@/models/NoteReaction.js';
|
||||
import { MiNoteSpReaction } from '@/models/NoteSpReaction.js';
|
||||
import { MiNoteThreadMuting } from '@/models/NoteThreadMuting.js';
|
||||
import { MiNoteDraft } from '@/models/NoteDraft.js';
|
||||
import { MiPage } from '@/models/Page.js';
|
||||
|
|
@ -204,6 +205,7 @@ export const entities = [
|
|||
MiNote,
|
||||
MiNoteFavorite,
|
||||
MiNoteReaction,
|
||||
MiNoteSpReaction,
|
||||
MiNoteThreadMuting,
|
||||
MiNoteDraft,
|
||||
MiPage,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export const meta = {
|
|||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireAdmin: true,
|
||||
requireModerator: true,
|
||||
kind: 'read:admin:user-ips',
|
||||
res: {
|
||||
type: 'array',
|
||||
|
|
|
|||
|
|
@ -596,6 +596,10 @@ export const meta = {
|
|||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableSpReaction: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
|
@ -752,6 +756,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
remoteNotesCleaningExpiryDaysForEachNotes: instance.remoteNotesCleaningExpiryDaysForEachNotes,
|
||||
remoteNotesCleaningMaxProcessingDurationInMinutes: instance.remoteNotesCleaningMaxProcessingDurationInMinutes,
|
||||
showRoleBadgesOfRemoteUsers: instance.showRoleBadgesOfRemoteUsers,
|
||||
enableSpReaction: instance.enableSpReaction,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ export const paramDef = {
|
|||
remoteNotesCleaningExpiryDaysForEachNotes: { type: 'number' },
|
||||
remoteNotesCleaningMaxProcessingDurationInMinutes: { type: 'number' },
|
||||
showRoleBadgesOfRemoteUsers: { type: 'boolean' },
|
||||
enableSpReaction: { type: 'boolean' },
|
||||
},
|
||||
required: [],
|
||||
} as const;
|
||||
|
|
@ -762,6 +763,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
|||
set.showRoleBadgesOfRemoteUsers = ps.showRoleBadgesOfRemoteUsers;
|
||||
}
|
||||
|
||||
if (ps.enableSpReaction !== undefined) {
|
||||
set.enableSpReaction = ps.enableSpReaction;
|
||||
}
|
||||
|
||||
const before = await this.metaService.fetch(true);
|
||||
|
||||
await this.metaService.update(set);
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ export const paramDef = {
|
|||
renote: notificationRecieveConfig,
|
||||
quote: notificationRecieveConfig,
|
||||
reaction: notificationRecieveConfig,
|
||||
spReaction: notificationRecieveConfig,
|
||||
pollEnded: notificationRecieveConfig,
|
||||
scheduledNotePosted: notificationRecieveConfig,
|
||||
scheduledNotePostFailed: notificationRecieveConfig,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
* renote - 投稿がRenoteされた
|
||||
* quote - 投稿が引用Renoteされた
|
||||
* reaction - 投稿にリアクションされた
|
||||
* spReaction - スペシャルリアクションされた
|
||||
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
||||
* scheduledNotePosted - 予約したノートが投稿された
|
||||
* scheduledNotePostFailed - 予約したノートの投稿に失敗した
|
||||
|
|
@ -33,6 +34,7 @@ export const notificationTypes = [
|
|||
'renote',
|
||||
'quote',
|
||||
'reaction',
|
||||
'spReaction',
|
||||
'pollEnded',
|
||||
'scheduledNotePosted',
|
||||
'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 === '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 === '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 === 'scheduledNotePostFailed'" class="ti ti-alert-triangle"></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 === 'test'">{{ i18n.ts._notification.testNotification }}</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'">{{ 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>
|
||||
|
|
@ -82,7 +83,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
||||
</header>
|
||||
<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>
|
||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||
|
|
|
|||
|
|
@ -96,6 +96,28 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkFolder>
|
||||
</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']">
|
||||
<MkFolder :defaultOpen="slotProps.isParentOfTarget">
|
||||
<template #icon><SearchIcon><i class="ti ti-user-star"></i></SearchIcon></template>
|
||||
|
|
@ -426,6 +448,15 @@ const infoForm = useForm({
|
|||
fetchInstance(true);
|
||||
});
|
||||
|
||||
const featuresForm = useForm({
|
||||
enableSpReaction: meta.enableSpReaction,
|
||||
}, async (state) => {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
enableSpReaction: state.enableSpReaction,
|
||||
});
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
||||
const pinnedUsersForm = useForm({
|
||||
pinnedUsers: meta.pinnedUsers.join('\n'),
|
||||
}, async (state) => {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<div :class="$style.body">
|
||||
<div :class="$style.top">
|
||||
<button v-tooltip.noDelay.right="instance.name ?? i18n.ts.instance" class="_button" :class="$style.instance" @click="openInstanceMenu">
|
||||
<img :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon" style="view-transition-name: navbar-serverIcon;"/>
|
||||
<img :src="instance.iconUrl || '/favicon.ico'" alt="" :class="$style.instanceIcon" style="viewTransitionName: navbar-serverIcon;"/>
|
||||
</button>
|
||||
<button v-if="!iconOnly" v-tooltip.noDelay.right="i18n.ts.realtimeMode" class="_button" :class="[$style.realtimeMode, store.r.realtimeMode.value ? $style.on : null]" @click="toggleRealtimeMode">
|
||||
<i v-if="store.r.realtimeMode.value" class="ti ti-bolt ti-fw"></i>
|
||||
|
|
@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
<div :class="$style.middle">
|
||||
<MkA v-tooltip.noDelay.right="i18n.ts.timeline" :class="$style.item" :activeClass="$style.active" to="/" exact>
|
||||
<i :class="$style.itemIcon" class="ti ti-home ti-fw" style="view-transition-name: navbar-homeIcon;"></i><span :class="$style.itemText">{{ i18n.ts.timeline }}</span>
|
||||
<i :class="$style.itemIcon" class="ti ti-home ti-fw" style="viewTransitionName: navbar-homeIcon;"></i><span :class="$style.itemText">{{ i18n.ts.timeline }}</span>
|
||||
</MkA>
|
||||
<template v-for="item in prefer.r.menu.value">
|
||||
<div v-if="item === '-'" :class="$style.divider"></div>
|
||||
|
|
@ -43,14 +43,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</template>
|
||||
<div :class="$style.divider"></div>
|
||||
<MkA v-if="$i != null && ($i.isAdmin || $i.isModerator)" v-tooltip.noDelay.right="i18n.ts.controlPanel" :class="$style.item" :activeClass="$style.active" to="/admin">
|
||||
<i :class="$style.itemIcon" class="ti ti-dashboard ti-fw" style="view-transition-name: navbar-controlPanel;"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
|
||||
<i :class="$style.itemIcon" class="ti ti-dashboard ti-fw" style="viewTransitionName: navbar-controlPanel;"></i><span :class="$style.itemText">{{ i18n.ts.controlPanel }}</span>
|
||||
</MkA>
|
||||
<button class="_button" :class="$style.item" @click="more">
|
||||
<i :class="$style.itemIcon" class="ti ti-grid-dots ti-fw" style="view-transition-name: navbar-more;"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
|
||||
<i :class="$style.itemIcon" class="ti ti-grid-dots ti-fw" style="viewTransitionName: navbar-more;"></i><span :class="$style.itemText">{{ i18n.ts.more }}</span>
|
||||
<span v-if="otherMenuItemIndicated" :class="$style.itemIndicator" class="_blink"><i class="_indicatorCircle"></i></span>
|
||||
</button>
|
||||
<MkA v-tooltip.noDelay.right="i18n.ts.settings" :class="$style.item" :activeClass="$style.active" to="/settings">
|
||||
<i :class="$style.itemIcon" class="ti ti-settings ti-fw" style="view-transition-name: navbar-settings;"></i><span :class="$style.itemText">{{ i18n.ts.settings }}</span>
|
||||
<i :class="$style.itemIcon" class="ti ti-settings ti-fw" style="viewTransitionName: navbar-settings;"></i><span :class="$style.itemText">{{ i18n.ts.settings }}</span>
|
||||
</MkA>
|
||||
</div>
|
||||
<div :class="$style.bottom">
|
||||
|
|
@ -65,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<i class="ti ti-pencil ti-fw" :class="$style.postIcon"></i><span :class="$style.postText">{{ i18n.ts.note }}</span>
|
||||
</button>
|
||||
<button v-if="$i != null" v-tooltip.noDelay.right="`${i18n.ts.account}: @${$i.username}`" class="_button" :class="[$style.account]" @click="openAccountMenu">
|
||||
<MkAvatar :user="$i" :class="$style.avatar" style="view-transition-name: navbar-avatar;"/><MkAcct class="_nowrap" :class="$style.acct" :user="$i"/>
|
||||
<MkAvatar :user="$i" :class="$style.avatar" style="viewTransitionName: navbar-avatar;"/><MkAcct class="_nowrap" :class="$style.acct" :user="$i"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6972,6 +6972,24 @@ export interface Locale extends ILocale {
|
|||
* アクティビティを表示する
|
||||
*/
|
||||
"showActivitiesForVisitor": string;
|
||||
/**
|
||||
* 機能
|
||||
*/
|
||||
"features": string;
|
||||
"_spReactions": {
|
||||
/**
|
||||
* スペシャルリアクションを有効にする
|
||||
*/
|
||||
"enable": string;
|
||||
/**
|
||||
* 通常のリアクションより目立つ「スペシャルリアクション」をノートに送れる機能です。
|
||||
*/
|
||||
"description1": string;
|
||||
/**
|
||||
* 有効にする場合、ロールポリシーで、毎月送ることのできる最大数を設定してください。
|
||||
*/
|
||||
"description2": string;
|
||||
};
|
||||
"_userGeneratedContentsVisibilityForVisitor": {
|
||||
/**
|
||||
* 全て公開
|
||||
|
|
@ -10929,6 +10947,10 @@ export interface Locale extends ILocale {
|
|||
* リアクション
|
||||
*/
|
||||
"reaction": string;
|
||||
/**
|
||||
* スペシャルリアクション
|
||||
*/
|
||||
"spReaction": string;
|
||||
/**
|
||||
* アンケートが終了
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3251,7 +3251,7 @@ type Notification_2 = components['schemas']['Notification'];
|
|||
type NotificationsCreateRequest = operations['notifications___create']['requestBody']['content']['application/json'];
|
||||
|
||||
// @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)
|
||||
export function nyaize(text: string): string;
|
||||
|
|
@ -3466,7 +3466,7 @@ type RoleLite = components['schemas']['RoleLite'];
|
|||
type RolePolicies = components['schemas']['RolePolicies'];
|
||||
|
||||
// @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)
|
||||
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
||||
|
|
|
|||
|
|
@ -4186,6 +4186,15 @@ export type components = {
|
|||
/** Format: misskey:id */
|
||||
userListId: string;
|
||||
};
|
||||
spReaction?: {
|
||||
/** @enum {string} */
|
||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||
} | {
|
||||
/** @enum {string} */
|
||||
type: 'list';
|
||||
/** Format: misskey:id */
|
||||
userListId: string;
|
||||
};
|
||||
pollEnded?: {
|
||||
/** @enum {string} */
|
||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||
|
|
@ -4622,6 +4631,18 @@ export type components = {
|
|||
userId: string;
|
||||
note: components['schemas']['Note'];
|
||||
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 */
|
||||
id: string;
|
||||
|
|
@ -9520,6 +9541,7 @@ export interface operations {
|
|||
remoteNotesCleaningExpiryDaysForEachNotes: number;
|
||||
remoteNotesCleaningMaxProcessingDurationInMinutes: number;
|
||||
showRoleBadgesOfRemoteUsers: boolean;
|
||||
enableSpReaction: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -12846,6 +12868,7 @@ export interface operations {
|
|||
remoteNotesCleaningExpiryDaysForEachNotes?: number;
|
||||
remoteNotesCleaningMaxProcessingDurationInMinutes?: number;
|
||||
showRoleBadgesOfRemoteUsers?: boolean;
|
||||
enableSpReaction?: boolean;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -26250,8 +26273,8 @@ export interface operations {
|
|||
untilDate?: number;
|
||||
/** @default true */
|
||||
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')[];
|
||||
excludeTypes?: ('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' | '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;
|
||||
/** @default true */
|
||||
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')[];
|
||||
excludeTypes?: ('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' | '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 */
|
||||
userListId: string;
|
||||
};
|
||||
spReaction?: {
|
||||
/** @enum {string} */
|
||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||
} | {
|
||||
/** @enum {string} */
|
||||
type: 'list';
|
||||
/** Format: misskey:id */
|
||||
userListId: string;
|
||||
};
|
||||
pollEnded?: {
|
||||
/** @enum {string} */
|
||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export const notificationTypes = [
|
|||
'renote',
|
||||
'quote',
|
||||
'reaction',
|
||||
'spReaction',
|
||||
'pollEnded',
|
||||
'scheduledNotePosted',
|
||||
'scheduledNotePostFailed',
|
||||
|
|
@ -229,6 +230,7 @@ export const rolePolicies = [
|
|||
'noteDraftLimit',
|
||||
'scheduledNoteLimit',
|
||||
'watermarkAvailable',
|
||||
'spReactionsMonthlyLimit',
|
||||
] as const;
|
||||
|
||||
export const queueTypes = [
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ importers:
|
|||
specifier: 8.5.6
|
||||
version: 8.5.6
|
||||
tar:
|
||||
specifier: 7.5.7
|
||||
version: 7.5.7
|
||||
specifier: 7.5.6
|
||||
version: 7.5.6
|
||||
terser:
|
||||
specifier: 5.46.0
|
||||
version: 5.46.0
|
||||
|
|
@ -10178,8 +10178,8 @@ packages:
|
|||
engines: {node: '>=10'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me
|
||||
|
||||
tar@7.5.7:
|
||||
resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==}
|
||||
tar@7.5.6:
|
||||
resolution: {integrity: sha512-xqUeu2JAIJpXyvskvU3uvQW8PAmHrtXp2KDuMJwQqW8Sqq0CaZBAQ+dKS3RBXVhU4wC5NjAdKrmh84241gO9cA==}
|
||||
engines: {node: '>=18'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exhorbitant rates) by contacting i@izs.me
|
||||
|
||||
|
|
@ -20126,7 +20126,7 @@ snapshots:
|
|||
nopt: 9.0.0
|
||||
proc-log: 6.1.0
|
||||
semver: 7.7.3
|
||||
tar: 7.5.7
|
||||
tar: 7.5.6
|
||||
tinyglobby: 0.2.15
|
||||
which: 6.0.0
|
||||
transitivePeerDependencies:
|
||||
|
|
@ -21992,7 +21992,7 @@ snapshots:
|
|||
yallist: 4.0.0
|
||||
optional: true
|
||||
|
||||
tar@7.5.7:
|
||||
tar@7.5.6:
|
||||
dependencies:
|
||||
'@isaacs/fs-minipass': 4.0.1
|
||||
chownr: 3.0.0
|
||||
|
|
|
|||
Loading…
Reference in New Issue