summaryrefslogtreecommitdiff
path: root/packages/backend/src
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-04-03 22:04:11 -0400
committerHazelnoot <acomputerdog@gmail.com>2025-04-03 22:06:37 -0400
commit3eeb53ff63a5e776327a9fd067d0c74b9dc727f4 (patch)
tree9b4ee01e1aaf1ab7b4a24ab897ccf14e1aa19a40 /packages/backend/src
parentrefactor bubble-timeline.ts to match global-timeline.ts and local-timeline.ts (diff)
parentNew Crowdin updates (#15740) (diff)
downloadsharkey-3eeb53ff63a5e776327a9fd067d0c74b9dc727f4.tar.gz
sharkey-3eeb53ff63a5e776327a9fd067d0c74b9dc727f4.tar.bz2
sharkey-3eeb53ff63a5e776327a9fd067d0c74b9dc727f4.zip
Merge branch 'misskey-develop' into merge/2025-03-24
# Conflicts: # package.json # packages/backend/src/core/AccountMoveService.ts # packages/frontend/src/components/MkDateSeparatedList.vue # packages/misskey-js/etc/misskey-js.api.md # pnpm-lock.yaml
Diffstat (limited to 'packages/backend/src')
-rw-r--r--packages/backend/src/core/AccountMoveService.ts29
-rw-r--r--packages/backend/src/core/ChatService.ts4
-rw-r--r--packages/backend/src/core/RoleService.ts1
-rw-r--r--packages/backend/src/core/entities/ChatEntityService.ts8
-rw-r--r--packages/backend/src/core/entities/RoleEntityService.ts4
-rw-r--r--packages/backend/src/misc/json-schema.ts4
-rw-r--r--packages/backend/src/models/Role.ts5
-rw-r--r--packages/backend/src/models/json-schema/chat-message.ts112
-rw-r--r--packages/backend/src/models/json-schema/role.ts5
-rw-r--r--packages/backend/src/server/api/endpoints/admin/roles/create.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/admin/roles/update.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/create-to-room.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/create-to-user.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/delete.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/react.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/unreact.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/chat/messages/user-timeline.ts2
-rw-r--r--packages/backend/src/server/api/stream/channels/bubble-timeline.ts1
-rw-r--r--packages/backend/src/server/api/stream/channels/global-timeline.ts1
-rw-r--r--packages/backend/src/server/api/stream/channels/local-timeline.ts1
21 files changed, 176 insertions, 13 deletions
diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts
index 2dbd16b5fe..5128caff60 100644
--- a/packages/backend/src/core/AccountMoveService.ts
+++ b/packages/backend/src/core/AccountMoveService.ts
@@ -24,6 +24,7 @@ import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import InstanceChart from '@/core/chart/charts/instance.js';
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { SystemAccountService } from '@/core/SystemAccountService.js';
+import { RoleService } from '@/core/RoleService.js';
@Injectable()
export class AccountMoveService {
@@ -64,6 +65,7 @@ export class AccountMoveService {
private relayService: RelayService,
private queueService: QueueService,
private systemAccountService: SystemAccountService,
+ private roleService: RoleService,
) {
}
@@ -123,6 +125,7 @@ export class AccountMoveService {
this.copyBlocking(src, dst),
this.copyMutings(src, dst),
this.deleteScheduledNotes(src),
+ this.copyRoles(src, dst),
this.updateLists(src, dst),
]);
} catch {
@@ -220,6 +223,32 @@ export class AccountMoveService {
});
}
+ @bindThis
+ public async copyRoles(src: ThinUser, dst: ThinUser): Promise<void> {
+ // Insert new roles with the same values except userId
+ // role service may have cache for roles so retrieve roles from service
+ const [oldRoleAssignments, roles] = await Promise.all([
+ this.roleService.getUserAssigns(src.id),
+ this.roleService.getRoles(),
+ ]);
+
+ if (oldRoleAssignments.length === 0) return;
+
+ // No promise all since the only async operation is writing to the database
+ for (const oldRoleAssignment of oldRoleAssignments) {
+ const role = roles.find(x => x.id === oldRoleAssignment.roleId);
+ if (role == null) continue; // Very unlikely however removing role may cause this case
+ if (!role.preserveAssignmentOnMoveAccount) continue;
+
+ try {
+ await this.roleService.assign(dst.id, role.id, oldRoleAssignment.expiresAt);
+ } catch (e) {
+ if (e instanceof RoleService.AlreadyAssignedError) continue;
+ throw e;
+ }
+ }
+ }
+
/**
* Update lists while moving accounts.
* - No removal of the old account from the lists
diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts
index 6194f624b1..3984cefc80 100644
--- a/packages/backend/src/core/ChatService.ts
+++ b/packages/backend/src/core/ChatService.ts
@@ -99,7 +99,7 @@ export class ChatService {
text?: string | null;
file?: MiDriveFile | null;
uri?: string | null;
- }): Promise<Packed<'ChatMessageLite'>> {
+ }): Promise<Packed<'ChatMessageLiteFor1on1'>> {
if (fromUser.id === toUser.id) {
throw new Error('yourself');
}
@@ -210,7 +210,7 @@ export class ChatService {
text?: string | null;
file?: MiDriveFile | null;
uri?: string | null;
- }): Promise<Packed<'ChatMessageLite'>> {
+ }): Promise<Packed<'ChatMessageLiteForRoom'>> {
const memberships = (await this.chatRoomMembershipsRepository.findBy({ roomId: toRoom.id })).map(m => ({
userId: m.userId,
isMuted: m.isMuted,
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 6e4346e22d..d4b5b07b38 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -639,6 +639,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
isModerator: values.isModerator,
isExplorable: values.isExplorable,
asBadge: values.asBadge,
+ preserveAssignmentOnMoveAccount: values.preserveAssignmentOnMoveAccount,
canEditMembersByModerator: values.canEditMembersByModerator,
displayOrder: values.displayOrder,
policies: values.policies,
diff --git a/packages/backend/src/core/entities/ChatEntityService.ts b/packages/backend/src/core/entities/ChatEntityService.ts
index 099a9e3ad2..da112d5444 100644
--- a/packages/backend/src/core/entities/ChatEntityService.ts
+++ b/packages/backend/src/core/entities/ChatEntityService.ts
@@ -128,7 +128,7 @@ export class ChatEntityService {
packedFiles: Map<MiChatMessage['fileId'], Packed<'DriveFile'> | null>;
};
},
- ): Promise<Packed<'ChatMessageLite'>> {
+ ): Promise<Packed<'ChatMessageLiteFor1on1'>> {
const packedFiles = options?._hint_?.packedFiles;
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
@@ -147,7 +147,7 @@ export class ChatEntityService {
createdAt: this.idService.parse(message.id).date.toISOString(),
text: message.text,
fromUserId: message.fromUserId,
- toUserId: message.toUserId,
+ toUserId: message.toUserId!,
fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions,
@@ -177,7 +177,7 @@ export class ChatEntityService {
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>;
};
},
- ): Promise<Packed<'ChatMessageLite'>> {
+ ): Promise<Packed<'ChatMessageLiteForRoom'>> {
const packedFiles = options?._hint_?.packedFiles;
const packedUsers = options?._hint_?.packedUsers;
@@ -199,7 +199,7 @@ export class ChatEntityService {
text: message.text,
fromUserId: message.fromUserId,
fromUser: packedUsers?.get(message.fromUserId) ?? await this.userEntityService.pack(message.fromUser ?? message.fromUserId),
- toRoomId: message.toRoomId,
+ toRoomId: message.toRoomId!,
fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions,
diff --git a/packages/backend/src/core/entities/RoleEntityService.ts b/packages/backend/src/core/entities/RoleEntityService.ts
index 2a7dc37bce..3fa38c9521 100644
--- a/packages/backend/src/core/entities/RoleEntityService.ts
+++ b/packages/backend/src/core/entities/RoleEntityService.ts
@@ -13,6 +13,7 @@ import type { MiRole } from '@/models/Role.js';
import { bindThis } from '@/decorators.js';
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
import { IdService } from '@/core/IdService.js';
+import { Packed } from '@/misc/json-schema.js';
@Injectable()
export class RoleEntityService {
@@ -31,7 +32,7 @@ export class RoleEntityService {
public async pack(
src: MiRole['id'] | MiRole,
me?: { id: MiUser['id'] } | null | undefined,
- ) {
+ ): Promise<Packed<'Role'>> {
const role = typeof src === 'object' ? src : await this.rolesRepository.findOneByOrFail({ id: src });
const assignedCount = await this.roleAssignmentsRepository.createQueryBuilder('assign')
@@ -67,6 +68,7 @@ export class RoleEntityService {
isModerator: role.isModerator,
isExplorable: role.isExplorable,
asBadge: role.asBadge,
+ preserveAssignmentOnMoveAccount: role.preserveAssignmentOnMoveAccount,
canEditMembersByModerator: role.canEditMembersByModerator,
displayOrder: role.displayOrder,
policies: policies,
diff --git a/packages/backend/src/misc/json-schema.ts b/packages/backend/src/misc/json-schema.ts
index bc9308ca9b..27aa3d89de 100644
--- a/packages/backend/src/misc/json-schema.ts
+++ b/packages/backend/src/misc/json-schema.ts
@@ -63,7 +63,7 @@ import {
} from '@/models/json-schema/meta.js';
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
-import { packedChatMessageSchema, packedChatMessageLiteSchema } from '@/models/json-schema/chat-message.js';
+import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js';
import { packedChatRoomSchema } from '@/models/json-schema/chat-room.js';
import { packedChatRoomInvitationSchema } from '@/models/json-schema/chat-room-invitation.js';
import { packedChatRoomMembershipSchema } from '@/models/json-schema/chat-room-membership.js';
@@ -126,6 +126,8 @@ export const refs = {
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
ChatMessage: packedChatMessageSchema,
ChatMessageLite: packedChatMessageLiteSchema,
+ ChatMessageLiteFor1on1: packedChatMessageLiteFor1on1Schema,
+ ChatMessageLiteForRoom: packedChatMessageLiteForRoomSchema,
ChatRoom: packedChatRoomSchema,
ChatRoomInvitation: packedChatRoomInvitationSchema,
ChatRoomMembership: packedChatRoomMembershipSchema,
diff --git a/packages/backend/src/models/Role.ts b/packages/backend/src/models/Role.ts
index a173971b2c..4c7da252bd 100644
--- a/packages/backend/src/models/Role.ts
+++ b/packages/backend/src/models/Role.ts
@@ -251,6 +251,11 @@ export class MiRole {
@Column('boolean', {
default: false,
})
+ public preserveAssignmentOnMoveAccount: boolean;
+
+ @Column('boolean', {
+ default: false,
+ })
public canEditMembersByModerator: boolean;
// UIに表示する際の並び順用(大きいほど先頭)
diff --git a/packages/backend/src/models/json-schema/chat-message.ts b/packages/backend/src/models/json-schema/chat-message.ts
index 44b7298702..3b5e85ab69 100644
--- a/packages/backend/src/models/json-schema/chat-message.ts
+++ b/packages/backend/src/models/json-schema/chat-message.ts
@@ -72,7 +72,7 @@ export const packedChatMessageSchema = {
},
user: {
type: 'object',
- optional: true, nullable: true,
+ optional: false, nullable: false,
ref: 'UserLite',
},
},
@@ -144,3 +144,113 @@ export const packedChatMessageLiteSchema = {
},
},
} as const;
+
+export const packedChatMessageLiteFor1on1Schema = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ createdAt: {
+ type: 'string',
+ format: 'date-time',
+ optional: false, nullable: false,
+ },
+ fromUserId: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ toUserId: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ text: {
+ type: 'string',
+ optional: true, nullable: true,
+ },
+ fileId: {
+ type: 'string',
+ optional: true, nullable: true,
+ },
+ file: {
+ type: 'object',
+ optional: true, nullable: true,
+ ref: 'DriveFile',
+ },
+ reactions: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ properties: {
+ reaction: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
+ },
+ },
+ },
+} as const;
+
+export const packedChatMessageLiteForRoomSchema = {
+ type: 'object',
+ properties: {
+ id: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ createdAt: {
+ type: 'string',
+ format: 'date-time',
+ optional: false, nullable: false,
+ },
+ fromUserId: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ fromUser: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'UserLite',
+ },
+ toRoomId: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ text: {
+ type: 'string',
+ optional: true, nullable: true,
+ },
+ fileId: {
+ type: 'string',
+ optional: true, nullable: true,
+ },
+ file: {
+ type: 'object',
+ optional: true, nullable: true,
+ ref: 'DriveFile',
+ },
+ reactions: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'object',
+ optional: false, nullable: false,
+ properties: {
+ reaction: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ user: {
+ type: 'object',
+ optional: false, nullable: false,
+ ref: 'UserLite',
+ },
+ },
+ },
+ },
+ },
+} as const;
diff --git a/packages/backend/src/models/json-schema/role.ts b/packages/backend/src/models/json-schema/role.ts
index 2537351dc0..285c10c4bd 100644
--- a/packages/backend/src/models/json-schema/role.ts
+++ b/packages/backend/src/models/json-schema/role.ts
@@ -397,6 +397,11 @@ export const packedRoleSchema = {
optional: false, nullable: false,
example: false,
},
+ preserveAssignmentOnMoveAccount: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ example: false,
+ },
canEditMembersByModerator: {
type: 'boolean',
optional: false, nullable: false,
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/create.ts b/packages/backend/src/server/api/endpoints/admin/roles/create.ts
index e0c02f7a5d..f92f7ebaeb 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/create.ts
@@ -36,6 +36,7 @@ export const paramDef = {
isAdministrator: { type: 'boolean' },
isExplorable: { type: 'boolean', default: false }, // optional for backward compatibility
asBadge: { type: 'boolean' },
+ preserveAssignmentOnMoveAccount: { type: 'boolean' },
canEditMembersByModerator: { type: 'boolean' },
displayOrder: { type: 'number' },
policies: {
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update.ts b/packages/backend/src/server/api/endpoints/admin/roles/update.ts
index 465ad7aaaf..175adcb63f 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/update.ts
@@ -41,6 +41,7 @@ export const paramDef = {
isAdministrator: { type: 'boolean' },
isExplorable: { type: 'boolean' },
asBadge: { type: 'boolean' },
+ preserveAssignmentOnMoveAccount: { type: 'boolean' },
canEditMembersByModerator: { type: 'boolean' },
displayOrder: { type: 'number' },
policies: {
@@ -78,6 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
isAdministrator: ps.isAdministrator,
isExplorable: ps.isExplorable,
asBadge: ps.asBadge,
+ preserveAssignmentOnMoveAccount: ps.preserveAssignmentOnMoveAccount,
canEditMembersByModerator: ps.canEditMembersByModerator,
displayOrder: ps.displayOrder,
policies: ps.policies,
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/create-to-room.ts b/packages/backend/src/server/api/endpoints/chat/messages/create-to-room.ts
index 1f334d5750..a988dc60b9 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/create-to-room.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/create-to-room.ts
@@ -30,7 +30,7 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
- ref: 'ChatMessageLite',
+ ref: 'ChatMessageLiteForRoom',
},
errors: {
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/create-to-user.ts b/packages/backend/src/server/api/endpoints/chat/messages/create-to-user.ts
index 6b77a026fb..bbaab8a6c3 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/create-to-user.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/create-to-user.ts
@@ -30,7 +30,7 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
- ref: 'ChatMessageLite',
+ ref: 'ChatMessageLiteFor1on1',
},
errors: {
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/delete.ts b/packages/backend/src/server/api/endpoints/chat/messages/delete.ts
index 959599ddcf..25fc774d4f 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/delete.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/delete.ts
@@ -13,6 +13,7 @@ export const meta = {
tags: ['chat'],
requireCredential: true,
+ requiredRolePolicy: 'canChat',
kind: 'write:chat',
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/react.ts b/packages/backend/src/server/api/endpoints/chat/messages/react.ts
index 561e36ed19..0145e380be 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/react.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/react.ts
@@ -13,6 +13,7 @@ export const meta = {
tags: ['chat'],
requireCredential: true,
+ requiredRolePolicy: 'canChat',
kind: 'write:chat',
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts b/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts
index 7aef35db04..b6d3356196 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/room-timeline.ts
@@ -23,7 +23,7 @@ export const meta = {
items: {
type: 'object',
optional: false, nullable: false,
- ref: 'ChatMessageLite',
+ ref: 'ChatMessageLiteForRoom',
},
},
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts b/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts
index 4eb25259fb..b97bad8a9c 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts
@@ -13,6 +13,7 @@ export const meta = {
tags: ['chat'],
requireCredential: true,
+ requiredRolePolicy: 'canChat',
kind: 'write:chat',
diff --git a/packages/backend/src/server/api/endpoints/chat/messages/user-timeline.ts b/packages/backend/src/server/api/endpoints/chat/messages/user-timeline.ts
index 9d308d79b0..a35f121bb1 100644
--- a/packages/backend/src/server/api/endpoints/chat/messages/user-timeline.ts
+++ b/packages/backend/src/server/api/endpoints/chat/messages/user-timeline.ts
@@ -24,7 +24,7 @@ export const meta = {
items: {
type: 'object',
optional: false, nullable: false,
- ref: 'ChatMessageLite',
+ ref: 'ChatMessageLiteFor1on1',
},
},
diff --git a/packages/backend/src/server/api/stream/channels/bubble-timeline.ts b/packages/backend/src/server/api/stream/channels/bubble-timeline.ts
index 08a7858e08..d29101cbc5 100644
--- a/packages/backend/src/server/api/stream/channels/bubble-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/bubble-timeline.ts
@@ -57,6 +57,7 @@ class BubbleTimelineChannel extends Channel {
if (note.channelId != null) return;
if (note.user.host == null) return;
if (!this.instance.bubbleInstances.includes(note.user.host)) return;
+ if (note.user.requireSigninToViewContents && this.user == null) return;
if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts
index 1b4dca3089..c90e99d930 100644
--- a/packages/backend/src/server/api/stream/channels/global-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts
@@ -53,6 +53,7 @@ class GlobalTimelineChannel extends Channel {
if (note.visibility !== 'public') return;
if (note.channelId != null) return;
+ if (note.user.requireSigninToViewContents && this.user == null) return;
if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts
index 2c31aab66d..630bcce8cf 100644
--- a/packages/backend/src/server/api/stream/channels/local-timeline.ts
+++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts
@@ -56,6 +56,7 @@ class LocalTimelineChannel extends Channel {
if (note.user.host !== null) return;
if (note.visibility !== 'public') return;
if (note.channelId != null) return;
+ if (note.user.requireSigninToViewContents && this.user == null) return;
// 関係ない返信は除外
if (note.reply && this.user && !this.following[note.userId]?.withReplies && !this.withReplies) {