;
+type PropertiesToUnion = p['properties'] extends NonNullable ? keyof p['properties'] : never;
+
type TypeStringef = 'null' | 'boolean' | 'integer' | 'number' | 'string' | 'array' | 'object' | 'any';
type StringDefToType =
T extends 'null' ? null :
@@ -114,6 +119,7 @@ export interface Schema extends OfSchema {
readonly example?: any;
readonly format?: string;
readonly ref?: keyof typeof refs;
+ readonly selfRef?: boolean;
readonly enum?: ReadonlyArray;
readonly default?: (this['type'] extends TypeStringef ? StringDefToType : any) | null;
readonly maxLength?: number;
diff --git a/packages/backend/src/models/Announcement.ts b/packages/backend/src/models/Announcement.ts
index 8f8be88fed..c2d9e9878c 100644
--- a/packages/backend/src/models/Announcement.ts
+++ b/packages/backend/src/models/Announcement.ts
@@ -38,7 +38,7 @@ export class MiAnnouncement {
length: 256, nullable: false,
default: 'info',
})
- public icon: string;
+ public icon: 'info' | 'warning' | 'error' | 'success';
// normal ... お知らせページ掲載
// banner ... お知らせページ掲載 + バナー表示
@@ -47,7 +47,7 @@ export class MiAnnouncement {
length: 256, nullable: false,
default: 'normal',
})
- public display: string;
+ public display: 'normal' | 'banner' | 'dialog';
@Column('boolean', {
default: false,
diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts
index 78a98872b2..57fd7d605d 100644
--- a/packages/backend/src/models/json-schema/announcement.ts
+++ b/packages/backend/src/models/json-schema/announcement.ts
@@ -37,10 +37,12 @@ export const packedAnnouncementSchema = {
icon: {
type: 'string',
optional: false, nullable: false,
+ enum: ['info', 'warning', 'error', 'success'],
},
display: {
type: 'string',
optional: false, nullable: false,
+ enum: ['dialog', 'normal', 'banner'],
},
needConfirmationToRead: {
type: 'boolean',
diff --git a/packages/backend/src/models/json-schema/blocking.ts b/packages/backend/src/models/json-schema/blocking.ts
index 0b58f1f8d7..1b3227d455 100644
--- a/packages/backend/src/models/json-schema/blocking.ts
+++ b/packages/backend/src/models/json-schema/blocking.ts
@@ -25,7 +25,7 @@ export const packedBlockingSchema = {
blockee: {
type: 'object',
optional: false, nullable: false,
- ref: 'UserDetailed',
+ ref: 'UserDetailedNotMe',
},
},
} as const;
diff --git a/packages/backend/src/models/json-schema/following.ts b/packages/backend/src/models/json-schema/following.ts
index e92cff20a1..dd3234ee5a 100644
--- a/packages/backend/src/models/json-schema/following.ts
+++ b/packages/backend/src/models/json-schema/following.ts
@@ -30,12 +30,12 @@ export const packedFollowingSchema = {
followee: {
type: 'object',
optional: true, nullable: false,
- ref: 'UserDetailed',
+ ref: 'UserDetailedNotMe',
},
follower: {
type: 'object',
optional: true, nullable: false,
- ref: 'UserDetailed',
+ ref: 'UserDetailedNotMe',
},
},
} as const;
diff --git a/packages/backend/src/models/json-schema/muting.ts b/packages/backend/src/models/json-schema/muting.ts
index dde9dc0288..c3d0bb603c 100644
--- a/packages/backend/src/models/json-schema/muting.ts
+++ b/packages/backend/src/models/json-schema/muting.ts
@@ -30,7 +30,7 @@ export const packedMutingSchema = {
mutee: {
type: 'object',
optional: false, nullable: false,
- ref: 'UserDetailed',
+ ref: 'UserDetailedNotMe',
},
},
} as const;
diff --git a/packages/backend/src/models/json-schema/note.ts b/packages/backend/src/models/json-schema/note.ts
index 2b7722129b..929f697e8a 100644
--- a/packages/backend/src/models/json-schema/note.ts
+++ b/packages/backend/src/models/json-schema/note.ts
@@ -69,6 +69,7 @@ export const packedNoteSchema = {
visibility: {
type: 'string',
optional: false, nullable: false,
+ enum: ['public', 'home', 'followers', 'specified'],
},
mentions: {
type: 'array',
@@ -117,6 +118,48 @@ export const packedNoteSchema = {
poll: {
type: 'object',
optional: true, nullable: true,
+ properties: {
+ expiresAt: {
+ type: 'string',
+ optional: true, nullable: true,
+ format: 'date-time',
+ },
+ multiple: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ choices: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ properties: {
+ isVoted: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ text: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ votes: {
+ type: 'number',
+ optional: false, nullable: false,
+ },
+ },
+ },
+ },
+ },
+ },
+ emojis: {
+ type: 'object',
+ optional: true, nullable: false,
+ additionalProperties: {
+ anyOf: [{
+ type: 'string',
+ }],
+ },
},
channelId: {
type: 'string',
@@ -162,9 +205,23 @@ export const packedNoteSchema = {
type: 'string',
optional: false, nullable: true,
},
+ reactionEmojis: {
+ type: 'object',
+ optional: false, nullable: false,
+ additionalProperties: {
+ anyOf: [{
+ type: 'string',
+ }],
+ },
+ },
reactions: {
type: 'object',
optional: false, nullable: false,
+ additionalProperties: {
+ anyOf: [{
+ type: 'number',
+ }],
+ },
},
renoteCount: {
type: 'number',
@@ -196,7 +253,7 @@ export const packedNoteSchema = {
},
myReaction: {
- type: 'object',
+ type: 'string',
optional: true, nullable: true,
},
},
diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts
index c6d6e84317..6286950de5 100644
--- a/packages/backend/src/models/json-schema/notification.ts
+++ b/packages/backend/src/models/json-schema/notification.ts
@@ -5,7 +5,7 @@
import { notificationTypes } from '@/types.js';
-export const packedNotificationSchema = {
+const baseSchema = {
type: 'object',
properties: {
id: {
@@ -23,68 +23,368 @@ export const packedNotificationSchema = {
optional: false, nullable: false,
enum: [...notificationTypes, 'reaction:grouped', 'renote:grouped'],
},
- user: {
- type: 'object',
- ref: 'UserLite',
- optional: true, nullable: true,
- },
- userId: {
- type: 'string',
- optional: true, nullable: true,
- format: 'id',
- },
- note: {
- type: 'object',
- ref: 'Note',
- optional: true, nullable: true,
- },
- reaction: {
- type: 'string',
- optional: true, nullable: true,
- },
- achievement: {
- type: 'string',
- optional: true, nullable: false,
- },
- body: {
- type: 'string',
- optional: true, nullable: true,
- },
- header: {
- type: 'string',
- optional: true, nullable: true,
- },
- icon: {
- type: 'string',
- optional: true, nullable: true,
- },
- reactions: {
- type: 'array',
- optional: true, nullable: true,
- items: {
- type: 'object',
- properties: {
- user: {
- type: 'object',
- ref: 'UserLite',
- optional: false, nullable: false,
- },
- reaction: {
- type: 'string',
- optional: false, nullable: false,
- },
- },
- required: ['user', 'reaction'],
+ },
+} as const;
+
+export const packedNotificationSchema = {
+ type: 'object',
+ oneOf: [{
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['note'],
},
- },
- users: {
- type: 'array',
- optional: true, nullable: true,
- items: {
+ 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,
+ },
},
- },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['mention'],
+ },
+ 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,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['reply'],
+ },
+ 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,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['renote'],
+ },
+ 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,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['quote'],
+ },
+ 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,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['reaction'],
+ },
+ 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: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['pollEnded'],
+ },
+ 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,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['follow'],
+ },
+ user: {
+ type: 'object',
+ ref: 'UserLite',
+ optional: false, nullable: false,
+ },
+ userId: {
+ type: 'string',
+ optional: false, nullable: false,
+ format: 'id',
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['receiveFollowRequest'],
+ },
+ user: {
+ type: 'object',
+ ref: 'UserLite',
+ optional: false, nullable: false,
+ },
+ userId: {
+ type: 'string',
+ optional: false, nullable: false,
+ format: 'id',
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['followRequestAccepted'],
+ },
+ user: {
+ type: 'object',
+ ref: 'UserLite',
+ optional: false, nullable: false,
+ },
+ userId: {
+ type: 'string',
+ optional: false, nullable: false,
+ format: 'id',
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['roleAssigned'],
+ },
+ role: {
+ type: 'object',
+ ref: 'Role',
+ optional: false, nullable: false,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['achievementEarned'],
+ },
+ achievement: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['app'],
+ },
+ body: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ header: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ icon: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['reaction:grouped'],
+ },
+ note: {
+ type: 'object',
+ ref: 'Note',
+ optional: false, nullable: false,
+ },
+ reactions: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ properties: {
+ user: {
+ type: 'object',
+ ref: 'UserLite',
+ optional: false, nullable: false,
+ },
+ reaction: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+ required: ['user', 'reaction'],
+ },
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['renote:grouped'],
+ },
+ note: {
+ type: 'object',
+ ref: 'Note',
+ optional: false, nullable: false,
+ },
+ users: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ ref: 'UserLite',
+ optional: false, nullable: false,
+ },
+ },
+ },
+ }, {
+ type: 'object',
+ properties: {
+ ...baseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['test'],
+ },
+ },
+ }],
} as const;
diff --git a/packages/backend/src/models/json-schema/page.ts b/packages/backend/src/models/json-schema/page.ts
index 9baacd6884..e4d844645e 100644
--- a/packages/backend/src/models/json-schema/page.ts
+++ b/packages/backend/src/models/json-schema/page.ts
@@ -3,6 +3,108 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+const blockBaseSchema = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+} as const;
+
+const textBlockSchema = {
+ type: 'object',
+ properties: {
+ ...blockBaseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['text'],
+ },
+ text: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+} as const;
+
+const sectionBlockSchema = {
+ type: 'object',
+ properties: {
+ ...blockBaseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['section'],
+ },
+ title: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ children: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'PageBlock',
+ selfRef: true,
+ },
+ },
+ },
+} as const;
+
+const imageBlockSchema = {
+ type: 'object',
+ properties: {
+ ...blockBaseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['image'],
+ },
+ fileId: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ },
+} as const;
+
+const noteBlockSchema = {
+ type: 'object',
+ properties: {
+ ...blockBaseSchema.properties,
+ type: {
+ type: 'string',
+ optional: false, nullable: false,
+ enum: ['note'],
+ },
+ detailed: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ note: {
+ type: 'string',
+ optional: false, nullable: true,
+ },
+ },
+} as const;
+
+export const packedPageBlockSchema = {
+ type: 'object',
+ oneOf: [
+ textBlockSchema,
+ sectionBlockSchema,
+ imageBlockSchema,
+ noteBlockSchema,
+ ],
+} as const;
+
export const packedPageSchema = {
type: 'object',
properties: {
@@ -38,6 +140,7 @@ export const packedPageSchema = {
items: {
type: 'object',
optional: false, nullable: false,
+ ref: 'PageBlock',
},
},
variables: {
diff --git a/packages/backend/src/models/json-schema/renote-muting.ts b/packages/backend/src/models/json-schema/renote-muting.ts
index feed1ceb09..769b33f515 100644
--- a/packages/backend/src/models/json-schema/renote-muting.ts
+++ b/packages/backend/src/models/json-schema/renote-muting.ts
@@ -25,7 +25,7 @@ export const packedRenoteMutingSchema = {
mutee: {
type: 'object',
optional: false, nullable: false,
- ref: 'UserDetailed',
+ ref: 'UserDetailedNotMe',
},
},
} as const;
diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts
index b0c6804bb8..55348d4f3d 100644
--- a/packages/backend/src/models/json-schema/role.ts
+++ b/packages/backend/src/models/json-schema/role.ts
@@ -1,26 +1,103 @@
-const rolePolicyValue = {
+export const packedRolePoliciesSchema = {
type: 'object',
+ optional: false, nullable: false,
properties: {
- value: {
- oneOf: [
- {
- type: 'integer',
- optional: false, nullable: false,
- },
- {
- type: 'boolean',
- optional: false, nullable: false,
- },
- ],
+ gtlAvailable: {
+ type: 'boolean',
+ optional: false, nullable: false,
},
- priority: {
+ ltlAvailable: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ canPublicNote: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ canInvite: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ inviteLimit: {
type: 'integer',
optional: false, nullable: false,
},
- useDefault: {
+ inviteLimitCycle: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ inviteExpirationTime: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ canManageCustomEmojis: {
type: 'boolean',
optional: false, nullable: false,
},
+ canManageAvatarDecorations: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ canSearchNotes: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ canUseTranslator: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ canHideAds: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ driveCapacityMb: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ alwaysMarkNsfw: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
+ pinLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ antennaLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ wordMuteLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ webhookLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ clipLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ noteEachClipsLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ userListLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ userEachUserListsLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ rateLimitFactor: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
+ avatarDecorationLimit: {
+ type: 'integer',
+ optional: false, nullable: false,
+ },
},
} as const;
@@ -121,31 +198,28 @@ export const packedRoleSchema = {
policies: {
type: 'object',
optional: false, nullable: false,
- properties: {
- pinLimit: rolePolicyValue,
- canInvite: rolePolicyValue,
- clipLimit: rolePolicyValue,
- canHideAds: rolePolicyValue,
- inviteLimit: rolePolicyValue,
- antennaLimit: rolePolicyValue,
- gtlAvailable: rolePolicyValue,
- ltlAvailable: rolePolicyValue,
- webhookLimit: rolePolicyValue,
- canPublicNote: rolePolicyValue,
- userListLimit: rolePolicyValue,
- wordMuteLimit: rolePolicyValue,
- alwaysMarkNsfw: rolePolicyValue,
- canSearchNotes: rolePolicyValue,
- driveCapacityMb: rolePolicyValue,
- rateLimitFactor: rolePolicyValue,
- inviteLimitCycle: rolePolicyValue,
- noteEachClipsLimit: rolePolicyValue,
- inviteExpirationTime: rolePolicyValue,
- canManageCustomEmojis: rolePolicyValue,
- userEachUserListsLimit: rolePolicyValue,
- canManageAvatarDecorations: rolePolicyValue,
- canUseTranslator: rolePolicyValue,
- avatarDecorationLimit: rolePolicyValue,
+ additionalProperties: {
+ anyOf: [{
+ type: 'object',
+ properties: {
+ value: {
+ oneOf: [
+ {
+ type: 'integer',
+ },
+ {
+ type: 'boolean',
+ },
+ ],
+ },
+ priority: {
+ type: 'integer',
+ },
+ useDefault: {
+ type: 'boolean',
+ },
+ },
+ }],
},
},
usersCount: {
diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts
index 6a0d43b1ac..ca51755317 100644
--- a/packages/backend/src/models/json-schema/user.ts
+++ b/packages/backend/src/models/json-schema/user.ts
@@ -590,104 +590,7 @@ export const packedMeDetailedOnlySchema = {
policies: {
type: 'object',
nullable: false, optional: false,
- properties: {
- gtlAvailable: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- ltlAvailable: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- canPublicNote: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- canInvite: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- inviteLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- inviteLimitCycle: {
- type: 'number',
- nullable: false, optional: false,
- },
- inviteExpirationTime: {
- type: 'number',
- nullable: false, optional: false,
- },
- canManageCustomEmojis: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- canManageAvatarDecorations: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- canSearchNotes: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- canUseTranslator: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- canHideAds: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- driveCapacityMb: {
- type: 'number',
- nullable: false, optional: false,
- },
- alwaysMarkNsfw: {
- type: 'boolean',
- nullable: false, optional: false,
- },
- pinLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- antennaLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- wordMuteLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- webhookLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- clipLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- noteEachClipsLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- userListLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- userEachUserListsLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- rateLimitFactor: {
- type: 'number',
- nullable: false, optional: false,
- },
- avatarDecorationLimit: {
- type: 'number',
- nullable: false, optional: false,
- },
- },
+ ref: 'RolePolicies',
},
//#region secrets
email: {
@@ -782,13 +685,5 @@ export const packedUserSchema = {
type: 'object',
ref: 'UserDetailed',
},
- {
- type: 'object',
- ref: 'UserDetailedNotMe',
- },
- {
- type: 'object',
- ref: 'MeDetailed',
- },
],
} as const;
diff --git a/packages/backend/src/queue/QueueProcessorService.ts b/packages/backend/src/queue/QueueProcessorService.ts
index bcc1a69f80..cc64c9f5a3 100644
--- a/packages/backend/src/queue/QueueProcessorService.ts
+++ b/packages/backend/src/queue/QueueProcessorService.ts
@@ -283,9 +283,9 @@ export class QueueProcessorService implements OnApplicationShutdown {
}, {
...baseQueueOptions(this.config, QUEUE.RELATIONSHIP),
autorun: false,
- concurrency: this.config.relashionshipJobConcurrency ?? 16,
+ concurrency: this.config.relationshipJobConcurrency ?? 16,
limiter: {
- max: this.config.relashionshipJobPerSec ?? 64,
+ max: this.config.relationshipJobPerSec ?? 64,
duration: 1000,
},
});
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index 632a7692cd..0b65c1ea74 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -204,7 +204,7 @@ export class ServerService implements OnApplicationShutdown {
});
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts
index 1758c03aca..386e593636 100644
--- a/packages/backend/src/server/api/ApiServerService.ts
+++ b/packages/backend/src/server/api/ApiServerService.ts
@@ -157,7 +157,7 @@ export class ApiServerService {
return {
ok: true,
token: token.token,
- user: await this.userEntityService.pack(token.userId, null, { detail: true }),
+ user: await this.userEntityService.pack(token.userId, null, { schema: 'UserDetailedNotMe' }),
};
} else {
return {
diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index 6b4d9d9f70..95016cdba6 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -213,7 +213,7 @@ export class SignupApiService {
});
const res = await this.userEntityService.pack(account, account, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
});
diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts
index 4a88216d06..75e6395f18 100644
--- a/packages/backend/src/server/api/endpoints.ts
+++ b/packages/backend/src/server/api/endpoints.ts
@@ -4,8 +4,7 @@
*/
import { permissions } from 'misskey-js';
-import type { Schema } from '@/misc/json-schema.js';
-import { RolePolicies } from '@/core/RoleService.js';
+import type { KeyOf, Schema } from '@/misc/json-schema.js';
import * as ep___admin_meta from './endpoints/admin/meta.js';
import * as ep___admin_abuseUserReports from './endpoints/admin/abuse-user-reports.js';
@@ -776,7 +775,7 @@ interface IEndpointMetaBase {
*/
readonly requireAdmin?: boolean;
- readonly requireRolePolicy?: keyof RolePolicies;
+ readonly requireRolePolicy?: KeyOf<'RolePolicies'>;
/**
* 引っ越し済みのユーザーによるリクエストを禁止するか
diff --git a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
index 3484d6707a..4ffefa05b7 100644
--- a/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
+++ b/packages/backend/src/server/api/endpoints/admin/abuse-user-reports.ts
@@ -62,17 +62,17 @@ export const meta = {
reporter: {
type: 'object',
nullable: false, optional: false,
- ref: 'User',
+ ref: 'UserDetailedNotMe',
},
targetUser: {
type: 'object',
nullable: false, optional: false,
- ref: 'User',
+ ref: 'UserDetailedNotMe',
},
assignee: {
type: 'object',
nullable: true, optional: true,
- ref: 'User',
+ ref: 'UserDetailedNotMe',
},
},
},
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
index f54d567fff..14fd69a1a2 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
@@ -9,8 +9,10 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/_.js';
import { SignupService } from '@/core/SignupService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { InstanceActorService } from '@/core/InstanceActorService.js';
import { localUsernameSchema, passwordSchema } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
+import { Packed } from '@/misc/json-schema.js';
export const meta = {
tags: ['admin'],
@@ -18,7 +20,7 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
- ref: 'User',
+ ref: 'MeDetailed',
properties: {
token: {
type: 'string',
@@ -45,13 +47,12 @@ export default class extends Endpoint { // eslint-
private userEntityService: UserEntityService,
private signupService: SignupService,
+ private instanceActorService: InstanceActorService,
) {
super(meta, paramDef, async (ps, _me, token) => {
const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null;
- const noUsers = (await this.usersRepository.countBy({
- host: IsNull(),
- })) === 0;
- if ((!noUsers && !me?.isRoot) || token !== null) throw new Error('access denied');
+ const realUsers = await this.instanceActorService.realLocalUsersPresent();
+ if ((realUsers && !me?.isRoot) || token !== null) throw new Error('access denied');
const { account, secret } = await this.signupService.signup({
username: ps.username,
@@ -60,11 +61,11 @@ export default class extends Endpoint { // eslint-
});
const res = await this.userEntityService.pack(account, account, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
- });
+ }) as Packed<'MeDetailed'> & { token: string };
- (res as any).token = secret;
+ res.token = secret;
return res;
});
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts
index 93673453d6..80b198eb80 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/find-by-email.ts
@@ -27,7 +27,7 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
- ref: 'User',
+ ref: 'UserDetailedNotMe',
},
} as const;
@@ -58,7 +58,7 @@ export default class extends Endpoint { // eslint-
}
const res = await this.userEntityService.pack(profile.user!, null, {
- detail: true,
+ schema: 'UserDetailedNotMe',
});
return res;
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/users.ts b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
index 66f4d9d26b..1e05685991 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/users.ts
@@ -40,7 +40,7 @@ export const meta = {
},
required: ['id', 'createdAt', 'user'],
},
- }
+ },
} as const;
export const paramDef = {
@@ -92,7 +92,7 @@ export default class extends Endpoint { // eslint-
return await Promise.all(assigns.map(async assign => ({
id: assign.id,
createdAt: this.idService.parse(assign.id).date.toISOString(),
- user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
+ user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
expiresAt: assign.expiresAt?.toISOString() ?? null,
})));
});
diff --git a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts
index f3601be9bb..51b5a02600 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-moderation-logs.ts
@@ -50,7 +50,7 @@ export const meta = {
user: {
type: 'object',
optional: false, nullable: false,
- ref: 'UserDetailed',
+ ref: 'UserDetailedNotMe',
},
},
},
diff --git a/packages/backend/src/server/api/endpoints/admin/show-users.ts b/packages/backend/src/server/api/endpoints/admin/show-users.ts
index 1d31e5e80f..80611266df 100644
--- a/packages/backend/src/server/api/endpoints/admin/show-users.ts
+++ b/packages/backend/src/server/api/endpoints/admin/show-users.ts
@@ -114,7 +114,7 @@ export default class extends Endpoint { // eslint-
const users = await query.getMany();
- return await this.userEntityService.packMany(users, me, { detail: true });
+ return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts
index 7e5c7a917c..4c1236eaa1 100644
--- a/packages/backend/src/server/api/endpoints/ap/show.ts
+++ b/packages/backend/src/server/api/endpoints/ap/show.ts
@@ -148,7 +148,7 @@ export default class extends Endpoint { // eslint-
if (user != null) {
return {
type: 'User',
- object: await this.userEntityService.pack(user, me, { detail: true }),
+ object: await this.userEntityService.pack(user, me, { schema: 'UserDetailedNotMe' }),
};
} else if (note != null) {
try {
diff --git a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts
index ffddda090b..eeb580cead 100644
--- a/packages/backend/src/server/api/endpoints/auth/session/userkey.ts
+++ b/packages/backend/src/server/api/endpoints/auth/session/userkey.ts
@@ -112,7 +112,7 @@ export default class extends Endpoint { // eslint-
return {
accessToken: accessToken.token,
user: await this.userEntityService.pack(session.userId, null, {
- detail: true,
+ schema: 'UserDetailedNotMe',
}),
};
});
diff --git a/packages/backend/src/server/api/endpoints/blocking/create.ts b/packages/backend/src/server/api/endpoints/blocking/create.ts
index 3c7d7ac8cd..1dc4563180 100644
--- a/packages/backend/src/server/api/endpoints/blocking/create.ts
+++ b/packages/backend/src/server/api/endpoints/blocking/create.ts
@@ -102,7 +102,7 @@ export default class extends Endpoint { // eslint-
await this.userBlockingService.block(blocker, blockee);
return await this.userEntityService.pack(blockee.id, blocker, {
- detail: true,
+ schema: 'UserDetailedNotMe',
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/blocking/delete.ts b/packages/backend/src/server/api/endpoints/blocking/delete.ts
index 0ce334d559..a6e6bcb5b3 100644
--- a/packages/backend/src/server/api/endpoints/blocking/delete.ts
+++ b/packages/backend/src/server/api/endpoints/blocking/delete.ts
@@ -103,7 +103,7 @@ export default class extends Endpoint { // eslint-
await this.userBlockingService.unblock(blocker, blockee);
return await this.userEntityService.pack(blockee.id, blocker, {
- detail: true,
+ schema: 'UserDetailedNotMe',
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts b/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts
index 9c057760ca..731bcc5b65 100644
--- a/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts
+++ b/packages/backend/src/server/api/endpoints/bubble-game/ranking.ts
@@ -61,7 +61,7 @@ export default class extends Endpoint { // eslint-
relations: ['user'],
});
- const users = await this.userEntityService.packMany(records.map(r => r.user!), null, { detail: false });
+ const users = await this.userEntityService.packMany(records.map(r => r.user!), null);
return records.map(r => ({
id: r.id,
diff --git a/packages/backend/src/server/api/endpoints/federation/users.ts b/packages/backend/src/server/api/endpoints/federation/users.ts
index d97171865a..df8b66ab44 100644
--- a/packages/backend/src/server/api/endpoints/federation/users.ts
+++ b/packages/backend/src/server/api/endpoints/federation/users.ts
@@ -54,7 +54,7 @@ export default class extends Endpoint { // eslint-
.limit(ps.limit)
.getMany();
- return await this.userEntityService.packMany(users, me, { detail: true });
+ return await this.userEntityService.packMany(users, me, { schema: 'UserDetailedNotMe' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/hashtags/users.ts b/packages/backend/src/server/api/endpoints/hashtags/users.ts
index 8302d2380f..5071dd22b7 100644
--- a/packages/backend/src/server/api/endpoints/hashtags/users.ts
+++ b/packages/backend/src/server/api/endpoints/hashtags/users.ts
@@ -76,7 +76,7 @@ export default class extends Endpoint { // eslint-
const users = await query.limit(ps.limit).getMany();
- return await this.userEntityService.packMany(users, me, { detail: true });
+ return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/i.ts b/packages/backend/src/server/api/endpoints/i.ts
index c24e049180..c613794589 100644
--- a/packages/backend/src/server/api/endpoints/i.ts
+++ b/packages/backend/src/server/api/endpoints/i.ts
@@ -71,8 +71,8 @@ export default class extends Endpoint { // eslint-
userProfile.loggedInDates = [...userProfile.loggedInDates, today];
}
- return await this.userEntityService.pack(userProfile.user!, userProfile.user!, {
- detail: true,
+ return await this.userEntityService.pack(userProfile.user!, userProfile.user!, {
+ schema: 'MeDetailed',
includeSecrets: isSecure,
userProfile,
});
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/done.ts b/packages/backend/src/server/api/endpoints/i/2fa/done.ts
index 9f8e2894b8..7aaf3982d1 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/done.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/done.ts
@@ -64,7 +64,7 @@ export default class extends Endpoint { // eslint-
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
index a7be47fd0f..a88a1e50de 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/key-done.ts
@@ -111,7 +111,7 @@ export default class extends Endpoint {
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts
index 2ed701014d..b68f23bf8a 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/password-less.ts
@@ -74,7 +74,7 @@ export default class extends Endpoint { // eslint-
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
});
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts
index da8ac98556..74a9cd77f0 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/remove-key.ts
@@ -97,7 +97,7 @@ export default class extends Endpoint { // eslint-
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts
index 338f12c5cd..6508c8b4e7 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/unregister.ts
@@ -76,7 +76,7 @@ export default class extends Endpoint { // eslint-
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
});
diff --git a/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts b/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts
index 1a140c1d05..8d894e8f85 100644
--- a/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts
+++ b/packages/backend/src/server/api/endpoints/i/2fa/update-key.ts
@@ -69,7 +69,7 @@ export default class extends Endpoint { // eslint-
// Publish meUpdated event
this.globalEventService.publishMainStream(me.id, 'meUpdated', await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
}));
diff --git a/packages/backend/src/server/api/endpoints/i/pin.ts b/packages/backend/src/server/api/endpoints/i/pin.ts
index c89cdfa3a4..71182cc29a 100644
--- a/packages/backend/src/server/api/endpoints/i/pin.ts
+++ b/packages/backend/src/server/api/endpoints/i/pin.ts
@@ -66,8 +66,8 @@ export default class extends Endpoint { // eslint-
throw err;
});
- return await this.userEntityService.pack(me.id, me, {
- detail: true,
+ return await this.userEntityService.pack(me.id, me, {
+ schema: 'MeDetailed',
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/i/unpin.ts b/packages/backend/src/server/api/endpoints/i/unpin.ts
index b59c0e954f..1e5f66f4a8 100644
--- a/packages/backend/src/server/api/endpoints/i/unpin.ts
+++ b/packages/backend/src/server/api/endpoints/i/unpin.ts
@@ -51,8 +51,8 @@ export default class extends Endpoint { // eslint-
throw err;
});
- return await this.userEntityService.pack(me.id, me, {
- detail: true,
+ return await this.userEntityService.pack(me.id, me, {
+ schema: 'MeDetailed',
});
});
}
diff --git a/packages/backend/src/server/api/endpoints/i/update-email.ts b/packages/backend/src/server/api/endpoints/i/update-email.ts
index 52977f5a07..cc3ec11708 100644
--- a/packages/backend/src/server/api/endpoints/i/update-email.ts
+++ b/packages/backend/src/server/api/endpoints/i/update-email.ts
@@ -43,7 +43,7 @@ export const meta = {
res: {
type: 'object',
- ref: 'UserDetailed',
+ ref: 'MeDetailed',
},
} as const;
@@ -106,7 +106,7 @@ export default class extends Endpoint { // eslint-
});
const iObj = await this.userEntityService.pack(me.id, me, {
- detail: true,
+ schema: 'MeDetailed',
includeSecrets: true,
});
diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts
index eed3082258..584321557b 100644
--- a/packages/backend/src/server/api/endpoints/i/update.ts
+++ b/packages/backend/src/server/api/endpoints/i/update.ts
@@ -446,8 +446,8 @@ export default class extends Endpoint { // eslint-
verifiedLinks: [],
});
- const iObj = await this.userEntityService.pack(user.id, user, {
- detail: true,
+ const iObj = await this.userEntityService.pack(user.id, user, {
+ schema: 'MeDetailed',
includeSecrets: isSecure,
});
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 529e82678d..c6489f67ac 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -6,11 +6,12 @@
import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
import JSON5 from 'json5';
-import type { AdsRepository, UsersRepository } from '@/models/_.js';
+import type { AdsRepository } from '@/models/_.js';
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { MetaService } from '@/core/MetaService.js';
+import { InstanceActorService } from '@/core/InstanceActorService.js';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
@@ -303,6 +304,11 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
+ policies: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'RolePolicies',
+ },
},
},
} as const;
@@ -321,14 +327,12 @@ export default class extends Endpoint { // eslint-
@Inject(DI.config)
private config: Config,
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
-
@Inject(DI.adsRepository)
private adsRepository: AdsRepository,
private userEntityService: UserEntityService,
private metaService: MetaService,
+ private instanceActorService: InstanceActorService,
) {
super(meta, paramDef, async (ps, me) => {
const instance = await this.metaService.fetch(true);
@@ -407,9 +411,7 @@ export default class extends Endpoint { // eslint-
...(ps.detail ? {
cacheRemoteFiles: instance.cacheRemoteFiles,
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
- requireSetup: (await this.usersRepository.countBy({
- host: IsNull(),
- })) === 0,
+ requireSetup: !await this.instanceActorService.realLocalUsersPresent(),
} : {}),
};
diff --git a/packages/backend/src/server/api/endpoints/page-push.ts b/packages/backend/src/server/api/endpoints/page-push.ts
index 0a68516586..49fcaf061b 100644
--- a/packages/backend/src/server/api/endpoints/page-push.ts
+++ b/packages/backend/src/server/api/endpoints/page-push.ts
@@ -55,7 +55,7 @@ export default class extends Endpoint { // eslint-
var: ps.var,
userId: me.id,
user: await this.userEntityService.pack(me.id, { id: page.userId }, {
- detail: true,
+ schema: 'UserDetailed',
}),
});
});
diff --git a/packages/backend/src/server/api/endpoints/pinned-users.ts b/packages/backend/src/server/api/endpoints/pinned-users.ts
index 390042c815..415633e8b6 100644
--- a/packages/backend/src/server/api/endpoints/pinned-users.ts
+++ b/packages/backend/src/server/api/endpoints/pinned-users.ts
@@ -52,7 +52,7 @@ export default class extends Endpoint { // eslint-
host: acct.host ?? IsNull(),
})));
- return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { detail: true });
+ return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { schema: 'UserDetailed' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/retention.ts b/packages/backend/src/server/api/endpoints/retention.ts
index dac6d65407..2631693139 100644
--- a/packages/backend/src/server/api/endpoints/retention.ts
+++ b/packages/backend/src/server/api/endpoints/retention.ts
@@ -14,6 +14,32 @@ export const meta = {
requireCredential: false,
res: {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ createdAt: {
+ type: 'string',
+ format: 'date-time',
+ },
+ users: {
+ type: 'number',
+ },
+ data: {
+ type: 'object',
+ additionalProperties: {
+ anyOf: [{
+ type: 'number',
+ }],
+ },
+ },
+ },
+ required: [
+ 'createdAt',
+ 'users',
+ 'data',
+ ],
+ },
},
allowGet: true,
diff --git a/packages/backend/src/server/api/endpoints/roles/users.ts b/packages/backend/src/server/api/endpoints/roles/users.ts
index d304d075b2..2e43af5c52 100644
--- a/packages/backend/src/server/api/endpoints/roles/users.ts
+++ b/packages/backend/src/server/api/endpoints/roles/users.ts
@@ -33,11 +33,11 @@ export const meta = {
properties: {
id: {
type: 'string',
- format: 'misskey:id'
+ format: 'misskey:id',
},
user: {
type: 'object',
- ref: 'User'
+ ref: 'UserDetailed',
},
},
required: ['id', 'user'],
@@ -94,7 +94,7 @@ export default class extends Endpoint { // eslint-
return await Promise.all(assigns.map(async assign => ({
id: assign.id,
- user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
+ user: await this.userEntityService.pack(assign.user!, me, { schema: 'UserDetailed' }),
})));
});
}
diff --git a/packages/backend/src/server/api/endpoints/users.ts b/packages/backend/src/server/api/endpoints/users.ts
index 8dc5841314..b886dd4a60 100644
--- a/packages/backend/src/server/api/endpoints/users.ts
+++ b/packages/backend/src/server/api/endpoints/users.ts
@@ -89,7 +89,7 @@ export default class extends Endpoint { // eslint-
const users = await query.getMany();
- return await this.userEntityService.packMany(users, me, { detail: true });
+ return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
index d6fb65cecb..6c04a06cbc 100644
--- a/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
+++ b/packages/backend/src/server/api/endpoints/users/get-frequently-replied-users.ts
@@ -122,7 +122,7 @@ export default class extends Endpoint { // eslint-
// Make replies object (includes weights)
const repliesObj = await Promise.all(topRepliedUsers.map(async (user) => ({
- user: await this.userEntityService.pack(user, me, { detail: true }),
+ user: await this.userEntityService.pack(user, me, { schema: 'UserDetailed' }),
weight: repliedUsers[user] / peak,
})));
diff --git a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts
index 985141515e..1fd3232de6 100644
--- a/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts
+++ b/packages/backend/src/server/api/endpoints/users/lists/get-memberships.ts
@@ -46,7 +46,7 @@ export const meta = {
},
user: {
type: 'object',
- ref: 'User',
+ ref: 'UserLite',
},
withReplies: {
type: 'boolean',
diff --git a/packages/backend/src/server/api/endpoints/users/reactions.ts b/packages/backend/src/server/api/endpoints/users/reactions.ts
index 372ab80c4c..69a842dbfb 100644
--- a/packages/backend/src/server/api/endpoints/users/reactions.ts
+++ b/packages/backend/src/server/api/endpoints/users/reactions.ts
@@ -9,6 +9,9 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import { NoteReactionEntityService } from '@/core/entities/NoteReactionEntityService.js';
import { DI } from '@/di-symbols.js';
+import { CacheService } from '@/core/CacheService.js';
+import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -34,6 +37,11 @@ export const meta = {
code: 'REACTIONS_NOT_PUBLIC',
id: '673a7dd2-6924-1093-e0c0-e68456ceae5c',
},
+ isRemoteUser: {
+ message: 'Currently unavailable to display reactions of remote users. See https://github.com/misskey-dev/misskey/issues/12964',
+ code: 'IS_REMOTE_USER',
+ id: '6b95fa98-8cf9-2350-e284-f0ffdb54a805',
+ },
},
} as const;
@@ -59,14 +67,24 @@ export default class extends Endpoint { // eslint-
@Inject(DI.noteReactionsRepository)
private noteReactionsRepository: NoteReactionsRepository,
+ private cacheService: CacheService,
+ private userEntityService: UserEntityService,
private noteReactionEntityService: NoteReactionEntityService,
private queryService: QueryService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
- const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
+ const iAmModerator = me ? await this.roleService.isModerator(me) : false; // Moderators can see reactions of all users
+ if (!iAmModerator) {
+ const user = await this.cacheService.findUserById(ps.userId);
+ if (this.userEntityService.isRemoteUser(user)) {
+ throw new ApiError(meta.errors.isRemoteUser);
+ }
- if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
- throw new ApiError(meta.errors.reactionsNotPublic);
+ const profile = await this.userProfilesRepository.findOneByOrFail({ userId: ps.userId });
+ if ((me == null || me.id !== ps.userId) && !profile.publicReactions) {
+ throw new ApiError(meta.errors.reactionsNotPublic);
+ }
}
const query = this.queryService.makePaginationQuery(this.noteReactionsRepository.createQueryBuilder('reaction'),
diff --git a/packages/backend/src/server/api/endpoints/users/recommendation.ts b/packages/backend/src/server/api/endpoints/users/recommendation.ts
index 1b30e99b15..c73495e3c7 100644
--- a/packages/backend/src/server/api/endpoints/users/recommendation.ts
+++ b/packages/backend/src/server/api/endpoints/users/recommendation.ts
@@ -76,7 +76,7 @@ export default class extends Endpoint { // eslint-
const users = await query.limit(ps.limit).offset(ps.offset).getMany();
- return await this.userEntityService.packMany(users, me, { detail: true });
+ return await this.userEntityService.packMany(users, me, { schema: 'UserDetailed' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
index 4bf25d9fbb..7d36f6f932 100644
--- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
+++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts
@@ -131,7 +131,7 @@ export default class extends Endpoint { // eslint-
.getMany();
}
- return await this.userEntityService.packMany(users, me, { detail: !!ps.detail });
+ return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts
index 32b5c12372..bc86136592 100644
--- a/packages/backend/src/server/api/endpoints/users/search.ts
+++ b/packages/backend/src/server/api/endpoints/users/search.ts
@@ -141,7 +141,7 @@ export default class extends Endpoint { // eslint-
}
}
- return await this.userEntityService.packMany(users, me, { detail: ps.detail });
+ return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/show.ts b/packages/backend/src/server/api/endpoints/users/show.ts
index 389497301d..4cf3858494 100644
--- a/packages/backend/src/server/api/endpoints/users/show.ts
+++ b/packages/backend/src/server/api/endpoints/users/show.ts
@@ -116,7 +116,7 @@ export default class extends Endpoint { // eslint-
}
return await Promise.all(_users.map(u => this.userEntityService.pack(u, me, {
- detail: true,
+ schema: 'UserDetailed',
})));
} else {
// Lookup user
@@ -146,7 +146,7 @@ export default class extends Endpoint { // eslint-
}
return await this.userEntityService.pack(user, me, {
- detail: true,
+ schema: 'UserDetailed',
});
}
});
diff --git a/packages/backend/src/server/api/openapi/gen-spec.ts b/packages/backend/src/server/api/openapi/gen-spec.ts
index 971a6116bf..5dbd4a01e1 100644
--- a/packages/backend/src/server/api/openapi/gen-spec.ts
+++ b/packages/backend/src/server/api/openapi/gen-spec.ts
@@ -6,9 +6,9 @@
import type { Config } from '@/config.js';
import endpoints, { IEndpoint } from '../endpoints.js';
import { errors as basicErrors } from './errors.js';
-import { schemas, convertSchemaToOpenApiSchema } from './schemas.js';
+import { getSchemas, convertSchemaToOpenApiSchema } from './schemas.js';
-export function genOpenapiSpec(config: Config) {
+export function genOpenapiSpec(config: Config, includeSelfRef = false) {
const spec = {
openapi: '3.1.0',
@@ -30,7 +30,7 @@ export function genOpenapiSpec(config: Config) {
paths: {} as any,
components: {
- schemas: schemas,
+ schemas: getSchemas(includeSelfRef),
securitySchemes: {
bearerAuth: {
@@ -56,7 +56,7 @@ export function genOpenapiSpec(config: Config) {
}
}
- const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res') : {};
+ const resSchema = endpoint.meta.res ? convertSchemaToOpenApiSchema(endpoint.meta.res, 'res', includeSelfRef) : {};
let desc = (endpoint.meta.description ? endpoint.meta.description : 'No description provided.') + '\n\n';
@@ -71,7 +71,7 @@ export function genOpenapiSpec(config: Config) {
}
const requestType = endpoint.meta.requireFile ? 'multipart/form-data' : 'application/json';
- const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param') };
+ const schema = { ...convertSchemaToOpenApiSchema(endpoint.params, 'param', false) };
if (endpoint.meta.requireFile) {
schema.properties = {
diff --git a/packages/backend/src/server/api/openapi/schemas.ts b/packages/backend/src/server/api/openapi/schemas.ts
index a862a7b742..61ce913b74 100644
--- a/packages/backend/src/server/api/openapi/schemas.ts
+++ b/packages/backend/src/server/api/openapi/schemas.ts
@@ -6,10 +6,10 @@
import type { Schema } from '@/misc/json-schema.js';
import { refs } from '@/misc/json-schema.js';
-export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res') {
+export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 'res', includeSelfRef: boolean): any {
// optional, nullable, refはスキーマ定義に含まれないので分離しておく
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- const { optional, nullable, ref, ...res }: any = schema;
+ const { optional, nullable, ref, selfRef, ...res }: any = schema;
if (schema.type === 'object' && schema.properties) {
if (type === 'res') {
@@ -21,20 +21,20 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
}
for (const k of Object.keys(schema.properties)) {
- res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type);
+ res.properties[k] = convertSchemaToOpenApiSchema(schema.properties[k], type, includeSelfRef);
}
}
if (schema.type === 'array' && schema.items) {
- res.items = convertSchemaToOpenApiSchema(schema.items, type);
+ res.items = convertSchemaToOpenApiSchema(schema.items, type, includeSelfRef);
}
for (const o of ['anyOf', 'oneOf', 'allOf'] as const) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type));
+ if (o in schema) res[o] = schema[o]!.map(schema => convertSchemaToOpenApiSchema(schema, type, includeSelfRef));
}
- if (type === 'res' && schema.ref) {
+ if (type === 'res' && schema.ref && (!schema.selfRef || includeSelfRef)) {
const $ref = `#/components/schemas/${schema.ref}`;
if (schema.nullable || schema.optional) {
res.allOf = [{ $ref }];
@@ -54,35 +54,37 @@ export function convertSchemaToOpenApiSchema(schema: Schema, type: 'param' | 're
return res;
}
-export const schemas = {
- Error: {
- type: 'object',
- properties: {
- error: {
- type: 'object',
- description: 'An error object.',
- properties: {
- code: {
- type: 'string',
- description: 'An error code. Unique within the endpoint.',
- },
- message: {
- type: 'string',
- description: 'An error message.',
- },
- id: {
- type: 'string',
- format: 'uuid',
- description: 'An error ID. This ID is static.',
+export function getSchemas(includeSelfRef: boolean) {
+ return {
+ Error: {
+ type: 'object',
+ properties: {
+ error: {
+ type: 'object',
+ description: 'An error object.',
+ properties: {
+ code: {
+ type: 'string',
+ description: 'An error code. Unique within the endpoint.',
+ },
+ message: {
+ type: 'string',
+ description: 'An error message.',
+ },
+ id: {
+ type: 'string',
+ format: 'uuid',
+ description: 'An error ID. This ID is static.',
+ },
},
+ required: ['code', 'id', 'message'],
},
- required: ['code', 'id', 'message'],
},
+ required: ['error'],
},
- required: ['error'],
- },
- ...Object.fromEntries(
- Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res')]),
- ),
-};
+ ...Object.fromEntries(
+ Object.entries(refs).map(([key, schema]) => [key, convertSchemaToOpenApiSchema(schema, 'res', includeSelfRef)]),
+ ),
+ };
+}
diff --git a/packages/frontend/@types/global.d.ts b/packages/frontend/@types/global.d.ts
index 7d9335cc52..936e74decf 100644
--- a/packages/frontend/@types/global.d.ts
+++ b/packages/frontend/@types/global.d.ts
@@ -16,3 +16,8 @@ declare const _DATA_TRANSFER_DECK_COLUMN_: string;
// for dev-mode
declare const _LANGS_FULL_: string[][];
+
+// TagCanvas
+interface Window {
+ TagCanvas: any;
+}
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index eeac6dcea3..d614f75886 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -20,15 +20,15 @@
"@discordapp/twemoji": "15.0.2",
"@github/webauthn-json": "2.1.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
- "@misskey-dev/browser-image-resizer": "2.2.1-misskey.10",
+ "@misskey-dev/browser-image-resizer": "2024.1.0",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "5.0.5",
"@rollup/pluginutils": "5.1.0",
"@syuilo/aiscript": "0.17.0",
"@tabler/icons-webfont": "2.44.0",
"@twemoji/parser": "15.0.0",
- "@vitejs/plugin-vue": "5.0.2",
- "@vue/compiler-sfc": "3.4.3",
+ "@vitejs/plugin-vue": "5.0.3",
+ "@vue/compiler-sfc": "3.4.15",
"aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.0.6",
"astring": "1.8.6",
"broadcast-channel": "7.0.0",
@@ -39,7 +39,7 @@
"chartjs-chart-matrix": "2.0.1",
"chartjs-plugin-gradient": "0.6.1",
"chartjs-plugin-zoom": "2.0.1",
- "chromatic": "10.3.1",
+ "chromatic": "10.6.1",
"compare-versions": "6.1.0",
"cropperjs": "2.0.0-beta.4",
"date-fns": "2.30.0",
@@ -60,10 +60,10 @@
"rollup": "4.9.6",
"sanitize-html": "2.11.0",
"sass": "1.70.0",
- "shiki": "0.14.7",
+ "shiki": "1.0.0-beta.3",
"strict-event-emitter-types": "2.0.0",
"textarea-caret": "3.1.0",
- "three": "0.160.0",
+ "three": "0.160.1",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tsc-alias": "1.8.8",
@@ -76,8 +76,8 @@
"vuedraggable": "next"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "^1.0.0",
- "@misskey-dev/summaly": "^5.0.3",
+ "@misskey-dev/eslint-plugin": "1.0.0",
+ "@misskey-dev/summaly": "5.0.3",
"@storybook/addon-actions": "7.6.10",
"@storybook/addon-essentials": "7.6.10",
"@storybook/addon-interactions": "7.6.10",
@@ -101,12 +101,12 @@
"@types/estree": "1.0.5",
"@types/matter-js": "0.19.6",
"@types/micromatch": "4.0.6",
- "@types/node": "20.11.5",
+ "@types/node": "20.11.10",
"@types/punycode": "2.1.3",
"@types/sanitize-html": "2.9.5",
"@types/throttle-debounce": "5.0.2",
"@types/tinycolor2": "1.4.6",
- "@types/uuid": "9.0.7",
+ "@types/uuid": "9.0.8",
"@types/ws": "8.5.10",
"@typescript-eslint/eslint-plugin": "6.18.1",
"@typescript-eslint/parser": "6.18.1",
@@ -134,7 +134,8 @@
"vite-plugin-turbosnap": "1.0.3",
"vitest": "0.34.6",
"vitest-fetch-mock": "0.2.2",
- "vue-eslint-parser": "9.4.0",
+ "vue-component-type-helpers": "^1.8.27",
+ "vue-eslint-parser": "9.4.2",
"vue-tsc": "1.8.27"
}
}
diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts
index c67911c9c3..fd5a03a70d 100644
--- a/packages/frontend/src/boot/common.ts
+++ b/packages/frontend/src/boot/common.ts
@@ -22,7 +22,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id.js';
import { deckStore } from '@/ui/deck/deck-store.js';
import { miLocalStorage } from '@/local-storage.js';
import { fetchCustomEmojis } from '@/custom-emojis.js';
-import { setupRouter } from '@/global/router/definition.js';
+import { setupRouter } from '@/router/definition.js';
export async function common(createVue: () => App) {
console.info(`Misskey v${version}`);
diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts
index eb0ac43da7..fc7c2f136a 100644
--- a/packages/frontend/src/boot/main-boot.ts
+++ b/packages/frontend/src/boot/main-boot.ts
@@ -19,7 +19,7 @@ import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js
import { initializeSw } from '@/scripts/initialize-sw.js';
import { deckStore } from '@/ui/deck/deck-store.js';
import { emojiPicker } from '@/scripts/emoji-picker.js';
-import { mainRouter } from '@/global/router/main.js';
+import { mainRouter } from '@/router/main.js';
export async function mainBoot() {
const { isClientUpdated } = await common(() => createApp(
@@ -81,13 +81,18 @@ export async function mainBoot() {
// ▼南半球
if (month === 7 || month === 8) {
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
- new SnowfallEffect().render();
+ new SnowfallEffect({}).render();
}
} else {
// ▼北半球
if (month === 12 || month === 1) {
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
- new SnowfallEffect().render();
+ new SnowfallEffect({}).render();
+ } else if (month === 3 || month === 4) {
+ const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect;
+ new SakuraEffect({
+ sakura: true,
+ }).render();
}
}
}
diff --git a/packages/frontend/src/components/MkAbuseReportWindow.vue b/packages/frontend/src/components/MkAbuseReportWindow.vue
index 7814681ea2..39745a97ce 100644
--- a/packages/frontend/src/components/MkAbuseReportWindow.vue
+++ b/packages/frontend/src/components/MkAbuseReportWindow.vue
@@ -39,7 +39,7 @@ import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
- user: Misskey.entities.User;
+ user: Misskey.entities.UserDetailed;
initialComment?: string;
}>();
diff --git a/packages/frontend/src/components/MkAchievements.vue b/packages/frontend/src/components/MkAchievements.vue
index 1137eaf970..ff8a9fa1a5 100644
--- a/packages/frontend/src/components/MkAchievements.vue
+++ b/packages/frontend/src/components/MkAchievements.vue
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
-
{{ c.text }}
-
+
{{ c.text }}
+
{{ c.text }}
{{ button.text }}
@@ -20,19 +20,19 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ c.label }}
{{ c.caption }}
-
+
{{ c.label }}
{{ c.caption }}
-
+
{{ c.label }}
{{ c.caption }}
-
+
{{ c.label }}
{{ c.caption }}
-
+
{{ c.label }}
{{ c.caption }}
@@ -42,8 +42,8 @@ SPDX-License-Identifier: AGPL-3.0-only
@@ -52,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
@@ -68,7 +68,7 @@ import MkInput from '@/components/MkInput.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkSelect from '@/components/MkSelect.vue';
-import { AsUiComponent } from '@/scripts/aiscript/ui.js';
+import { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/scripts/aiscript/ui.js';
import MkFolder from '@/components/MkFolder.vue';
import MkPostForm from '@/components/MkPostForm.vue';
@@ -85,20 +85,32 @@ const props = withDefaults(defineProps<{
const c = props.component;
function g(id) {
- return props.components.find(x => x.value.id === id).value;
+ const v = props.components.find(x => x.value.id === id)?.value;
+ if (v) return v;
+
+ return {
+ id: 'dummy',
+ type: 'root',
+ children: [],
+ } as AsUiRoot;
}
-const valueForSwitch = ref(c.default ?? false);
+const valueForSwitch = ref('default' in c && typeof c.default === 'boolean' ? c.default : false);
function onSwitchUpdate(v) {
valueForSwitch.value = v;
- if (c.onChange) c.onChange(v);
+ if ('onChange' in c && c.onChange) {
+ c.onChange(v as never);
+ }
}
function openPostForm() {
+ const form = (c as AsUiPostFormButton).form;
+ if (!form) return;
+
os.post({
- initialText: c.form.text,
- initialCw: c.form.cw,
+ initialText: form.text,
+ initialCw: form.cw,
instant: true,
});
}
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue
index 9d03eab2cb..a428d85c76 100644
--- a/packages/frontend/src/components/MkAutocomplete.vue
+++ b/packages/frontend/src/components/MkAutocomplete.vue
@@ -431,7 +431,7 @@ function applySelect() {
function chooseUser() {
props.close();
- os.selectUser().then(user => {
+ os.selectUser({ includeSelf: true }).then(user => {
complete('user', user);
props.textarea.focus();
});
diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue
index 8d4631968d..70de6a851a 100644
--- a/packages/frontend/src/components/MkButton.vue
+++ b/packages/frontend/src/components/MkButton.vue
@@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue
index f60c721eae..7aa08cf51f 100644
--- a/packages/frontend/src/components/MkCaptcha.vue
+++ b/packages/frontend/src/components/MkCaptcha.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
{{ i18n.ts.waiting }}
+
Loading
@@ -17,7 +17,6 @@ SPDX-License-Identifier: AGPL-3.0-only
-
diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue
index 04244ac308..9a1dce2d8e 100644
--- a/packages/frontend/src/components/MkUserPopup.vue
+++ b/packages/frontend/src/components/MkUserPopup.vue
@@ -86,6 +86,7 @@ const top = ref(0);
const left = ref(0);
function showMenu(ev: MouseEvent) {
+ if (user.value == null) return;
const { menu, cleanup } = getUserMenu(user.value);
os.popupMenu(menu, ev.currentTarget ?? ev.target).finally(cleanup);
}
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
index ad11ba1940..740b122fac 100644
--- a/packages/frontend/src/components/MkUserSelectDialog.vue
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -16,7 +16,11 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.selectUser }}
-
+
+ {{ i18n.ts.username }}
+ @
+
+
{{ i18n.ts.username }}
@
@@ -66,7 +70,7 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
-import { hostname } from '@/config.js';
+import { host as currentHost, hostname } from '@/config.js';
const emit = defineEmits<{
(ev: 'ok', selected: Misskey.entities.UserDetailed): void;
@@ -74,15 +78,19 @@ const emit = defineEmits<{
(ev: 'closed'): void;
}>();
-const props = defineProps<{
+const props = withDefaults(defineProps<{
includeSelf?: boolean;
-}>();
+ localOnly?: boolean;
+}>(), {
+ includeSelf: false,
+ localOnly: false,
+});
const username = ref('');
const host = ref('');
-const users = ref([]);
+const users = ref([]);
const recentUsers = ref([]);
-const selected = ref(null);
+const selected = ref(null);
const dialogEl = ref();
function search() {
@@ -92,22 +100,33 @@ function search() {
}
misskeyApi('users/search-by-username-and-host', {
username: username.value,
- host: host.value,
+ host: props.localOnly ? '.' : host.value,
limit: 10,
detail: false,
}).then(_users => {
- users.value = _users;
+ users.value = _users.filter((u) => {
+ if (props.includeSelf) {
+ return true;
+ } else {
+ return u.id !== $i?.id;
+ }
+ });
});
}
-function ok() {
+async function ok() {
if (selected.value == null) return;
- emit('ok', selected.value);
+
+ const user = await misskeyApi('users/show', {
+ userId: selected.value.id,
+ });
+ emit('ok', user);
+
dialogEl.value.close();
// 最近使ったユーザー更新
let recents = defaultStore.state.recentlyUsedUsers;
- recents = recents.filter(x => x !== selected.value.id);
+ recents = recents.filter(x => x !== selected.value?.id);
recents.unshift(selected.value.id);
defaultStore.set('recentlyUsedUsers', recents.splice(0, 16));
}
@@ -120,12 +139,23 @@ function cancel() {
onMounted(() => {
misskeyApi('users/show', {
userIds: defaultStore.state.recentlyUsedUsers,
- }).then(users => {
- if (props.includeSelf && users.find(x => $i ? x.id === $i.id : true) == null) {
- recentUsers.value = [$i, ...users];
- } else {
- recentUsers.value = users;
- }
+ }).then(foundUsers => {
+ let _users = foundUsers;
+ _users = _users.filter((u) => {
+ if (props.localOnly) {
+ return u.host == null;
+ } else {
+ return true;
+ }
+ });
+ _users = _users.filter((u) => {
+ if (props.includeSelf) {
+ return true;
+ } else {
+ return u.id !== $i?.id;
+ }
+ });
+ recentUsers.value = _users;
});
});
@@ -133,7 +163,7 @@ onMounted(() => {