wip
This commit is contained in:
82
locales/index.d.ts
vendored
82
locales/index.d.ts
vendored
@@ -5358,31 +5358,63 @@ export interface Locale extends ILocale {
|
||||
* チャット
|
||||
*/
|
||||
"chat": string;
|
||||
/**
|
||||
* 個人チャット
|
||||
*/
|
||||
"individualChat": string;
|
||||
/**
|
||||
* 特定ユーザーとの一対一のチャットができます。
|
||||
*/
|
||||
"individualChat_description": string;
|
||||
/**
|
||||
* ルームチャット
|
||||
*/
|
||||
"roomChat": string;
|
||||
/**
|
||||
* 複数人でのチャットができます。
|
||||
* また、個人チャットを許可していないユーザーとでも、相手が受け入れればチャットができます。
|
||||
*/
|
||||
"roomChat_description": string;
|
||||
/**
|
||||
* このユーザーとのチャットを開始できません
|
||||
*/
|
||||
"cannotChatWithTheUser": string;
|
||||
/**
|
||||
* チャットが使えない状態になっているか、相手がチャットを開放していません。
|
||||
*/
|
||||
"cannotChatWithTheUser_description": string;
|
||||
"_chat": {
|
||||
/**
|
||||
* 個人チャット
|
||||
*/
|
||||
"individualChat": string;
|
||||
/**
|
||||
* 特定ユーザーとの一対一のチャットができます。
|
||||
*/
|
||||
"individualChat_description": string;
|
||||
/**
|
||||
* ルームチャット
|
||||
*/
|
||||
"roomChat": string;
|
||||
/**
|
||||
* 複数人でのチャットができます。
|
||||
* また、個人チャットを許可していないユーザーとでも、相手が受け入れればチャットができます。
|
||||
*/
|
||||
"roomChat_description": string;
|
||||
/**
|
||||
* このユーザーとのチャットを開始できません
|
||||
*/
|
||||
"cannotChatWithTheUser": string;
|
||||
/**
|
||||
* チャットが使えない状態になっているか、相手がチャットを開放していません。
|
||||
*/
|
||||
"cannotChatWithTheUser_description": string;
|
||||
/**
|
||||
* チャットを許可する相手
|
||||
*/
|
||||
"chatAllowedUsers": string;
|
||||
/**
|
||||
* 自分からチャットメッセージを送った相手とはこの設定に関わらずチャットが可能です。
|
||||
*/
|
||||
"chatAllowedUsers_note": string;
|
||||
"_chatAllowedUsers": {
|
||||
/**
|
||||
* 誰でも
|
||||
*/
|
||||
"everyone": string;
|
||||
/**
|
||||
* 自分のフォロワーのみ
|
||||
*/
|
||||
"followers": string;
|
||||
/**
|
||||
* 自分がフォローしているユーザーのみ
|
||||
*/
|
||||
"following": string;
|
||||
/**
|
||||
* 相互フォローのユーザーのみ
|
||||
*/
|
||||
"mutual": string;
|
||||
/**
|
||||
* 誰も許可しない
|
||||
*/
|
||||
"none": string;
|
||||
};
|
||||
};
|
||||
"_emojiPalette": {
|
||||
/**
|
||||
* パレット
|
||||
|
@@ -1335,12 +1335,23 @@ postForm: "投稿フォーム"
|
||||
textCount: "文字数"
|
||||
information: "情報"
|
||||
chat: "チャット"
|
||||
individualChat: "個人チャット"
|
||||
individualChat_description: "特定ユーザーとの一対一のチャットができます。"
|
||||
roomChat: "ルームチャット"
|
||||
roomChat_description: "複数人でのチャットができます。\nまた、個人チャットを許可していないユーザーとでも、相手が受け入れればチャットができます。"
|
||||
cannotChatWithTheUser: "このユーザーとのチャットを開始できません"
|
||||
cannotChatWithTheUser_description: "チャットが使えない状態になっているか、相手がチャットを開放していません。"
|
||||
|
||||
_chat:
|
||||
individualChat: "個人チャット"
|
||||
individualChat_description: "特定ユーザーとの一対一のチャットができます。"
|
||||
roomChat: "ルームチャット"
|
||||
roomChat_description: "複数人でのチャットができます。\nまた、個人チャットを許可していないユーザーとでも、相手が受け入れればチャットができます。"
|
||||
cannotChatWithTheUser: "このユーザーとのチャットを開始できません"
|
||||
cannotChatWithTheUser_description: "チャットが使えない状態になっているか、相手がチャットを開放していません。"
|
||||
|
||||
chatAllowedUsers: "チャットを許可する相手"
|
||||
chatAllowedUsers_note: "自分からチャットメッセージを送った相手とはこの設定に関わらずチャットが可能です。"
|
||||
_chatAllowedUsers:
|
||||
everyone: "誰でも"
|
||||
followers: "自分のフォロワーのみ"
|
||||
following: "自分がフォローしているユーザーのみ"
|
||||
mutual: "相互フォローのユーザーのみ"
|
||||
none: "誰も許可しない"
|
||||
|
||||
_emojiPalette:
|
||||
palettes: "パレット"
|
||||
|
26
packages/backend/migration/1742617546147-chat-3.js
Normal file
26
packages/backend/migration/1742617546147-chat-3.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class Chat31742617546147 {
|
||||
name = 'Chat31742617546147'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`CREATE TABLE "chat_approval" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "otherId" character varying(32) NOT NULL, CONSTRAINT "PK_fbbb95d60acf5c85388345b5f5d" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_530257863e1381a7f2f1d3282f" ON "chat_approval" ("userId") `);
|
||||
await queryRunner.query(`CREATE INDEX "IDX_b1d46037f23d170da5c05fdf75" ON "chat_approval" ("otherId") `);
|
||||
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_12c4768a2f706fc267f2078903" ON "chat_approval" ("userId", "otherId") `);
|
||||
await queryRunner.query(`ALTER TABLE "chat_approval" ADD CONSTRAINT "FK_530257863e1381a7f2f1d3282fe" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "chat_approval" ADD CONSTRAINT "FK_b1d46037f23d170da5c05fdf755" FOREIGN KEY ("otherId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "chat_approval" DROP CONSTRAINT "FK_b1d46037f23d170da5c05fdf755"`);
|
||||
await queryRunner.query(`ALTER TABLE "chat_approval" DROP CONSTRAINT "FK_530257863e1381a7f2f1d3282fe"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_12c4768a2f706fc267f2078903"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_b1d46037f23d170da5c05fdf75"`);
|
||||
await queryRunner.query(`DROP INDEX "public"."IDX_530257863e1381a7f2f1d3282f"`);
|
||||
await queryRunner.query(`DROP TABLE "chat_approval"`);
|
||||
}
|
||||
}
|
@@ -16,7 +16,7 @@ import { ChatMessageEntityService } from '@/core/entities/ChatMessageEntityServi
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import type { ChatMessagesRepository, MiChatMessage, MiChatRoom, MiDriveFile, MiUser, MutingsRepository, UsersRepository } from '@/models/_.js';
|
||||
import type { ChatApprovalsRepository, ChatMessagesRepository, ChatRoomMembershipsRepository, ChatRoomsRepository, MiChatMessage, MiChatRoom, MiDriveFile, MiUser, MutingsRepository, UsersRepository } from '@/models/_.js';
|
||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||
import { QueryService } from '@/core/QueryService.js';
|
||||
import { RoleService } from '@/core/RoleService.js';
|
||||
@@ -37,6 +37,15 @@ export class ChatService {
|
||||
@Inject(DI.chatMessagesRepository)
|
||||
private chatMessagesRepository: ChatMessagesRepository,
|
||||
|
||||
@Inject(DI.chatApprovalsRepository)
|
||||
private chatApprovalsRepository: ChatApprovalsRepository,
|
||||
|
||||
@Inject(DI.chatRoomsRepository)
|
||||
private chatRoomsRepository: ChatRoomsRepository,
|
||||
|
||||
@Inject(DI.chatRoomMembershipsRepository)
|
||||
private chatRoomMembershipsRepository: ChatRoomMembershipsRepository,
|
||||
|
||||
@Inject(DI.mutingsRepository)
|
||||
private mutingsRepository: MutingsRepository,
|
||||
|
||||
@@ -64,22 +73,39 @@ export class ChatService {
|
||||
throw new Error('yourself');
|
||||
}
|
||||
|
||||
if (toUser.chatScope === 'none') {
|
||||
throw new Error('recipient is cannot chat');
|
||||
} else if (toUser.chatScope === 'followers') {
|
||||
const isFollower = await this.userFollowingService.isFollowing(fromUser.id, toUser.id);
|
||||
if (!isFollower) {
|
||||
throw new Error('recipient is cannot chat');
|
||||
}
|
||||
} else if (toUser.chatScope === 'following') {
|
||||
const isFollowing = await this.userFollowingService.isFollowing(toUser.id, fromUser.id);
|
||||
if (!isFollowing) {
|
||||
throw new Error('recipient is cannot chat');
|
||||
}
|
||||
} else if (toUser.chatScope === 'mutual') {
|
||||
const isMutual = await this.userFollowingService.isMutual(fromUser.id, toUser.id);
|
||||
if (!isMutual) {
|
||||
const approvals = await this.chatApprovalsRepository.createQueryBuilder('approval')
|
||||
.where(new Brackets(qb => { // 自分が相手を許可しているか
|
||||
qb.where('approval.userId = :fromUserId', { fromUserId: fromUser.id })
|
||||
.andWhere('approval.otherId = :toUserId', { toUserId: toUser.id });
|
||||
}))
|
||||
.orWhere(new Brackets(qb => { // 相手が自分を許可しているか
|
||||
qb.where('approval.userId = :toUserId', { toUserId: toUser.id })
|
||||
.andWhere('approval.otherId = :fromUserId', { fromUserId: fromUser.id });
|
||||
}))
|
||||
.take(2)
|
||||
.getMany();
|
||||
|
||||
const otherApprovedMe = approvals.some(approval => approval.userId === toUser.id);
|
||||
const iApprovedOther = approvals.some(approval => approval.userId === fromUser.id);
|
||||
|
||||
if (!otherApprovedMe) {
|
||||
if (toUser.chatScope === 'none') {
|
||||
throw new Error('recipient is cannot chat');
|
||||
} else if (toUser.chatScope === 'followers') {
|
||||
const isFollower = await this.userFollowingService.isFollowing(fromUser.id, toUser.id);
|
||||
if (!isFollower) {
|
||||
throw new Error('recipient is cannot chat');
|
||||
}
|
||||
} else if (toUser.chatScope === 'following') {
|
||||
const isFollowing = await this.userFollowingService.isFollowing(toUser.id, fromUser.id);
|
||||
if (!isFollowing) {
|
||||
throw new Error('recipient is cannot chat');
|
||||
}
|
||||
} else if (toUser.chatScope === 'mutual') {
|
||||
const isMutual = await this.userFollowingService.isMutual(fromUser.id, toUser.id);
|
||||
if (!isMutual) {
|
||||
throw new Error('recipient is cannot chat');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +130,15 @@ export class ChatService {
|
||||
|
||||
const inserted = await this.chatMessagesRepository.insertOne(message);
|
||||
|
||||
// 相手を許可しておく
|
||||
if (!iApprovedOther) {
|
||||
this.chatApprovalsRepository.insertOne({
|
||||
id: this.idService.gen(),
|
||||
userId: fromUser.id,
|
||||
otherId: toUser.id,
|
||||
});
|
||||
}
|
||||
|
||||
const packedMessage = await this.chatMessageEntityService.packLite(inserted);
|
||||
|
||||
if (this.userEntityService.isLocalUser(toUser)) {
|
||||
|
@@ -558,6 +558,7 @@ export class UserEntityService implements OnModuleInit {
|
||||
publicReactions: this.isLocalUser(user) ? profile!.publicReactions : false, // https://github.com/misskey-dev/misskey/issues/12964
|
||||
followersVisibility: profile!.followersVisibility,
|
||||
followingVisibility: profile!.followingVisibility,
|
||||
chatScope: user.chatScope,
|
||||
roles: this.roleService.getUserRoles(user.id).then(roles => roles.filter(role => role.isPublic).sort((a, b) => b.displayOrder - a.displayOrder).map(role => ({
|
||||
id: role.id,
|
||||
name: role.name,
|
||||
|
@@ -84,6 +84,7 @@ export const DI = {
|
||||
flashLikesRepository: Symbol('flashLikesRepository'),
|
||||
userMemosRepository: Symbol('userMemosRepository'),
|
||||
chatMessagesRepository: Symbol('chatMessagesRepository'),
|
||||
chatApprovalsRepository: Symbol('chatApprovalsRepository'),
|
||||
chatRoomsRepository: Symbol('chatRoomsRepository'),
|
||||
chatRoomMembershipsRepository: Symbol('chatRoomMembershipsRepository'),
|
||||
bubbleGameRecordsRepository: Symbol('bubbleGameRecordsRepository'),
|
||||
|
39
packages/backend/src/models/ChatApproval.ts
Normal file
39
packages/backend/src/models/ChatApproval.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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';
|
||||
|
||||
@Entity('chat_approval')
|
||||
@Index(['userId', 'otherId'], { unique: true })
|
||||
export class MiChatApproval {
|
||||
@PrimaryColumn(id())
|
||||
public id: string;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
})
|
||||
public userId: MiUser['id'];
|
||||
|
||||
@ManyToOne(type => MiUser, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public user: MiUser | null;
|
||||
|
||||
@Index()
|
||||
@Column({
|
||||
...id(),
|
||||
})
|
||||
public otherId: MiUser['id'];
|
||||
|
||||
@ManyToOne(type => MiUser, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn()
|
||||
public other: MiUser | null;
|
||||
}
|
@@ -81,6 +81,7 @@ import {
|
||||
MiChatMessage,
|
||||
MiChatRoom,
|
||||
MiChatRoomMembership,
|
||||
MiChatApproval,
|
||||
} from './_.js';
|
||||
import type { Provider } from '@nestjs/common';
|
||||
import type { DataSource } from 'typeorm';
|
||||
@@ -511,6 +512,12 @@ const $chatRoomMembershipsRepository: Provider = {
|
||||
inject: [DI.db],
|
||||
};
|
||||
|
||||
const $chatApprovalsRepository: Provider = {
|
||||
provide: DI.chatApprovalsRepository,
|
||||
useFactory: (db: DataSource) => db.getRepository(MiChatApproval),
|
||||
inject: [DI.db],
|
||||
};
|
||||
|
||||
const $bubbleGameRecordsRepository: Provider = {
|
||||
provide: DI.bubbleGameRecordsRepository,
|
||||
useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository<MiBubbleGameRecord>),
|
||||
@@ -597,6 +604,7 @@ const $reversiGamesRepository: Provider = {
|
||||
$chatMessagesRepository,
|
||||
$chatRoomsRepository,
|
||||
$chatRoomMembershipsRepository,
|
||||
$chatApprovalsRepository,
|
||||
$bubbleGameRecordsRepository,
|
||||
$reversiGamesRepository,
|
||||
],
|
||||
@@ -672,6 +680,7 @@ const $reversiGamesRepository: Provider = {
|
||||
$chatMessagesRepository,
|
||||
$chatRoomsRepository,
|
||||
$chatRoomMembershipsRepository,
|
||||
$chatApprovalsRepository,
|
||||
$bubbleGameRecordsRepository,
|
||||
$reversiGamesRepository,
|
||||
],
|
||||
|
@@ -78,6 +78,7 @@ import { MiUserListFavorite } from '@/models/UserListFavorite.js';
|
||||
import { MiChatMessage } from '@/models/ChatMessage.js';
|
||||
import { MiChatRoom } from '@/models/ChatRoom.js';
|
||||
import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
|
||||
import { MiChatApproval } from '@/models/ChatApproval.js';
|
||||
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
|
||||
import { MiReversiGame } from '@/models/ReversiGame.js';
|
||||
import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
|
||||
@@ -197,6 +198,7 @@ export {
|
||||
MiChatMessage,
|
||||
MiChatRoom,
|
||||
MiChatRoomMembership,
|
||||
MiChatApproval,
|
||||
MiBubbleGameRecord,
|
||||
MiReversiGame,
|
||||
};
|
||||
@@ -272,5 +274,6 @@ export type UserMemoRepository = Repository<MiUserMemo> & MiRepository<MiUserMem
|
||||
export type ChatMessagesRepository = Repository<MiChatMessage> & MiRepository<MiChatMessage>;
|
||||
export type ChatRoomsRepository = Repository<MiChatRoom> & MiRepository<MiChatRoom>;
|
||||
export type ChatRoomMembershipsRepository = Repository<MiChatRoomMembership> & MiRepository<MiChatRoomMembership>;
|
||||
export type ChatApprovalsRepository = Repository<MiChatApproval> & MiRepository<MiChatApproval>;
|
||||
export type BubbleGameRecordsRepository = Repository<MiBubbleGameRecord> & MiRepository<MiBubbleGameRecord>;
|
||||
export type ReversiGamesRepository = Repository<MiReversiGame> & MiRepository<MiReversiGame>;
|
||||
|
@@ -358,6 +358,11 @@ export const packedUserDetailedNotMeOnlySchema = {
|
||||
nullable: false, optional: false,
|
||||
enum: ['public', 'followers', 'private'],
|
||||
},
|
||||
chatScope: {
|
||||
type: 'string',
|
||||
nullable: false, optional: false,
|
||||
enum: ['everyone', 'following', 'followers', 'mutual', 'none'],
|
||||
},
|
||||
roles: {
|
||||
type: 'array',
|
||||
nullable: false, optional: false,
|
||||
|
@@ -8,6 +8,9 @@ import pg from 'pg';
|
||||
import { DataSource, Logger } from 'typeorm';
|
||||
import * as highlight from 'cli-highlight';
|
||||
import { entities as charts } from '@/core/chart/entities.js';
|
||||
import { Config } from '@/config.js';
|
||||
import MisskeyLogger from '@/logger.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
|
||||
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
|
||||
import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
|
||||
@@ -81,11 +84,8 @@ import { MiChatRoom } from '@/models/ChatRoom.js';
|
||||
import { MiChatRoomMembership } from '@/models/ChatRoomMembership.js';
|
||||
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
|
||||
import { MiReversiGame } from '@/models/ReversiGame.js';
|
||||
|
||||
import { Config } from '@/config.js';
|
||||
import MisskeyLogger from '@/logger.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { MiSystemAccount } from './models/SystemAccount.js';
|
||||
import { MiChatApproval } from '@/models/ChatApproval.js';
|
||||
import { MiSystemAccount } from '@/models/SystemAccount.js';
|
||||
|
||||
pg.types.setTypeParser(20, Number);
|
||||
|
||||
@@ -242,6 +242,7 @@ export const entities = [
|
||||
MiChatMessage,
|
||||
MiChatRoom,
|
||||
MiChatRoomMembership,
|
||||
MiChatApproval,
|
||||
MiBubbleGameRecord,
|
||||
MiReversiGame,
|
||||
...charts,
|
||||
|
@@ -190,6 +190,7 @@ export const paramDef = {
|
||||
autoSensitive: { type: 'boolean' },
|
||||
followingVisibility: { type: 'string', enum: ['public', 'followers', 'private'] },
|
||||
followersVisibility: { type: 'string', enum: ['public', 'followers', 'private'] },
|
||||
chatScope: { type: 'string', enum: ['everyone', 'followers', 'following', 'mutual', 'none'] },
|
||||
pinnedPageId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||
mutedWords: muteWords,
|
||||
hardMutedWords: muteWords,
|
||||
@@ -288,6 +289,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
if (ps.birthday !== undefined) profileUpdates.birthday = ps.birthday;
|
||||
if (ps.followingVisibility !== undefined) profileUpdates.followingVisibility = ps.followingVisibility;
|
||||
if (ps.followersVisibility !== undefined) profileUpdates.followersVisibility = ps.followersVisibility;
|
||||
if (ps.chatScope !== undefined) updates.chatScope = ps.chatScope;
|
||||
|
||||
function checkMuteWordCount(mutedWords: (string[] | string)[], limit: number) {
|
||||
// TODO: ちゃんと数える
|
||||
|
@@ -15,7 +15,7 @@ describe('ユーザー', () => {
|
||||
// エンティティとしてのユーザーを主眼においたテストを記述する
|
||||
// (Userを返すエンドポイントとUserエンティティを書き換えるエンドポイントをテストする)
|
||||
|
||||
const stripUndefined = <T extends { [key: string]: any }, >(orig: T): Partial<T> => {
|
||||
const stripUndefined = <T extends { [key: string]: any } >(orig: T): Partial<T> => {
|
||||
return Object.entries({ ...orig })
|
||||
.filter(([, value]) => value !== undefined)
|
||||
.reduce((obj: Partial<T>, [key, value]) => {
|
||||
@@ -83,6 +83,7 @@ describe('ユーザー', () => {
|
||||
publicReactions: user.publicReactions,
|
||||
followingVisibility: user.followingVisibility,
|
||||
followersVisibility: user.followersVisibility,
|
||||
chatScope: user.chatScope,
|
||||
roles: user.roles,
|
||||
memo: user.memo,
|
||||
});
|
||||
@@ -343,6 +344,7 @@ describe('ユーザー', () => {
|
||||
assert.strictEqual(response.publicReactions, true);
|
||||
assert.strictEqual(response.followingVisibility, 'public');
|
||||
assert.strictEqual(response.followersVisibility, 'public');
|
||||
assert.strictEqual(response.chatScope, 'mutual');
|
||||
assert.deepStrictEqual(response.roles, []);
|
||||
assert.strictEqual(response.memo, null);
|
||||
|
||||
|
@@ -66,13 +66,13 @@ const history = ref<{
|
||||
|
||||
function start(ev: MouseEvent) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.individualChat,
|
||||
caption: i18n.ts.individualChat_description,
|
||||
text: i18n.ts._chat.individualChat,
|
||||
caption: i18n.ts._chat.individualChat_description,
|
||||
icon: 'ti ti-user',
|
||||
action: () => { startUser(); },
|
||||
}, { type: 'divider' }, {
|
||||
text: i18n.ts.roomChat,
|
||||
caption: i18n.ts.roomChat_description,
|
||||
text: i18n.ts._chat.roomChat,
|
||||
caption: i18n.ts._chat.roomChat_description,
|
||||
icon: 'ti ti-users',
|
||||
action: () => { startRoom(); },
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
|
@@ -78,6 +78,20 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkSwitch>
|
||||
</SearchMarker>
|
||||
|
||||
<FormSection>
|
||||
<SearchMarker :keywords="['chat']">
|
||||
<MkSelect v-model="chatScope" @update:modelValue="save()">
|
||||
<template #label><SearchLabel>{{ i18n.ts._chat.chatAllowedUsers }}</SearchLabel></template>
|
||||
<option value="everyone">{{ i18n.ts._chat._chatAllowedUsers.everyone }}</option>
|
||||
<option value="followers">{{ i18n.ts._chat._chatAllowedUsers.followers }}</option>
|
||||
<option value="following">{{ i18n.ts._chat._chatAllowedUsers.following }}</option>
|
||||
<option value="mutual">{{ i18n.ts._chat._chatAllowedUsers.mutual }}</option>
|
||||
<option value="none">{{ i18n.ts._chat._chatAllowedUsers.none }}</option>
|
||||
<template #caption>{{ i18n.ts._chat.chatAllowedUsers_note }}</template>
|
||||
</MkSelect>
|
||||
</SearchMarker>
|
||||
</FormSection>
|
||||
|
||||
<SearchMarker :keywords="['lockdown']">
|
||||
<FormSection>
|
||||
<template #label><SearchLabel>{{ i18n.ts.lockdown }}</SearchLabel><span class="_beta">{{ i18n.ts.beta }}</span></template>
|
||||
@@ -208,6 +222,7 @@ const hideOnlineStatus = ref($i.hideOnlineStatus);
|
||||
const publicReactions = ref($i.publicReactions);
|
||||
const followingVisibility = ref($i.followingVisibility);
|
||||
const followersVisibility = ref($i.followersVisibility);
|
||||
const chatScope = ref($i.chatScope);
|
||||
|
||||
const makeNotesFollowersOnlyBefore_type = computed(() => {
|
||||
if (makeNotesFollowersOnlyBefore.value == null) {
|
||||
@@ -260,6 +275,7 @@ function save() {
|
||||
publicReactions: !!publicReactions.value,
|
||||
followingVisibility: followingVisibility.value,
|
||||
followersVisibility: followersVisibility.value,
|
||||
chatScope: chatScope.value,
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -240,20 +240,25 @@ export const searchIndexes: SearchIndexItem[] = [
|
||||
keywords: ['explore', i18n.ts.makeExplorableDescription],
|
||||
},
|
||||
{
|
||||
id: '7vr04wKol',
|
||||
id: 'xEYlOghao',
|
||||
label: i18n.ts._chat.chatAllowedUsers,
|
||||
keywords: ['chat'],
|
||||
},
|
||||
{
|
||||
id: 'BnOtlyaAh',
|
||||
children: [
|
||||
{
|
||||
id: 'Av7fAaHv8',
|
||||
id: 'BzMIVBpL0',
|
||||
label: i18n.ts._accountSettings.requireSigninToViewContents,
|
||||
keywords: ['login', 'signin'],
|
||||
},
|
||||
{
|
||||
id: '5RbESWefG',
|
||||
id: 'jJUqPqBAv',
|
||||
label: i18n.ts._accountSettings.makeNotesFollowersOnlyBefore,
|
||||
keywords: ['follower', i18n.ts._accountSettings.makeNotesFollowersOnlyBeforeDescription],
|
||||
},
|
||||
{
|
||||
id: 'hdzwDs3qd',
|
||||
id: 'ra10txIFV',
|
||||
label: i18n.ts._accountSettings.makeNotesHiddenBefore,
|
||||
keywords: ['hidden', i18n.ts._accountSettings.makeNotesHiddenBeforeDescription],
|
||||
},
|
||||
|
@@ -3875,6 +3875,8 @@ export type components = {
|
||||
followingVisibility: 'public' | 'followers' | 'private';
|
||||
/** @enum {string} */
|
||||
followersVisibility: 'public' | 'followers' | 'private';
|
||||
/** @enum {string} */
|
||||
chatScope: 'everyone' | 'following' | 'followers' | 'mutual' | 'none';
|
||||
roles: components['schemas']['RoleLite'][];
|
||||
followedMessage?: string | null;
|
||||
memo: string | null;
|
||||
@@ -21330,6 +21332,8 @@ export type operations = {
|
||||
followingVisibility?: 'public' | 'followers' | 'private';
|
||||
/** @enum {string} */
|
||||
followersVisibility?: 'public' | 'followers' | 'private';
|
||||
/** @enum {string} */
|
||||
chatScope?: 'everyone' | 'followers' | 'following' | 'mutual' | 'none';
|
||||
/** Format: misskey:id */
|
||||
pinnedPageId?: string | null;
|
||||
mutedWords?: (string[] | string)[];
|
||||
|
Reference in New Issue
Block a user