mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat(access): add guest chat ACL (#235)
This commit is contained in:
@@ -559,6 +559,7 @@
|
||||
"skills": "Skills",
|
||||
"email": "Email",
|
||||
"files": "Files",
|
||||
"access": "Access",
|
||||
"terminal": "Terminal",
|
||||
"settings": "Settings"
|
||||
},
|
||||
@@ -767,6 +768,65 @@
|
||||
"deleteBotDescription": "Deleting this bot cannot be undone. Proceed with caution.",
|
||||
"deleteBot": "Delete Bot"
|
||||
},
|
||||
"access": {
|
||||
"title": "Access Control",
|
||||
"subtitle": "Guest chat trigger access is controlled by allow guest, whitelist, and blacklist together.",
|
||||
"allowGuestDescription": "When enabled, guests may trigger chat by default. Blacklist rules still take precedence.",
|
||||
"saveGuestAccess": "Save Guest Access",
|
||||
"guestAccessSaved": "Guest access updated",
|
||||
"guestRulesTitle": "Rule Summary",
|
||||
"guestRulesDescription": "Owners and members always bypass these rules. The rules below only apply to guest chat triggers.",
|
||||
"whitelistTitle": "Whitelist",
|
||||
"whitelistDescription": "Whitelisted guests can still trigger chat even when guest access is not open.",
|
||||
"blacklistTitle": "Blacklist",
|
||||
"blacklistDescription": "Blacklisted guests are denied chat trigger even when guest access is open.",
|
||||
"userSelector": "Select User",
|
||||
"identitySelector": "Select Platform Identity",
|
||||
"selectUser": "Search and select a user",
|
||||
"selectIdentity": "Search and select a platform identity",
|
||||
"searchUser": "Search users",
|
||||
"searchIdentity": "Search platform identities",
|
||||
"noUserCandidates": "No user candidates",
|
||||
"noIdentityCandidates": "No platform identity candidates",
|
||||
"userId": "User ID",
|
||||
"userIdPlaceholder": "Enter user ID",
|
||||
"channelIdentityId": "Channel Identity ID",
|
||||
"channelIdentityIdPlaceholder": "Enter channel identity ID",
|
||||
"addWhitelist": "Add to Whitelist",
|
||||
"addBlacklist": "Add to Blacklist",
|
||||
"clearSelection": "Clear Selection",
|
||||
"whitelistEmpty": "No whitelist rules yet",
|
||||
"blacklistEmpty": "No blacklist rules yet",
|
||||
"validation": "Fill exactly one subject: user_id or channel_identity_id",
|
||||
"validationConversationRequiresChannel": "Select a source platform before restricting by conversation or thread ID",
|
||||
"validationThreadRequiresConversation": "Thread ID requires a conversation ID",
|
||||
"whitelistSaved": "Whitelist updated",
|
||||
"blacklistSaved": "Blacklist updated",
|
||||
"saveFailed": "Failed to save access rule",
|
||||
"deleteSuccess": "Rule deleted",
|
||||
"deleteFailed": "Failed to delete rule",
|
||||
"sourceScopeTitle": "Source Scope",
|
||||
"sourceScopeDescription": "Optionally restrict a rule to a platform, conversation type, or specific conversation/thread.",
|
||||
"sourceChannel": "Source Platform",
|
||||
"anyChannel": "Any platform",
|
||||
"conversationType": "Conversation Type",
|
||||
"anyConversationType": "Any conversation type",
|
||||
"privateConversationType": "Private",
|
||||
"groupConversationType": "Group",
|
||||
"threadConversationType": "Thread",
|
||||
"observedConversation": "Observed Conversation",
|
||||
"selectObservedConversation": "Select an observed conversation",
|
||||
"searchObservedConversation": "Search observed conversations",
|
||||
"noObservedConversations": "No observed conversations",
|
||||
"selectIdentityFirst": "Select a platform identity first to load observed conversations",
|
||||
"observedConversationHint": "Choosing an observed conversation auto-fills the platform, conversation ID, and thread ID.",
|
||||
"conversationId": "Conversation ID",
|
||||
"conversationIdPlaceholder": "Enter conversation ID",
|
||||
"threadId": "Thread ID",
|
||||
"threadIdPlaceholder": "Enter thread ID",
|
||||
"clearScope": "Clear Scope",
|
||||
"lastObserved": "Last seen"
|
||||
},
|
||||
"channels": {
|
||||
"title": "Platforms",
|
||||
"addChannel": "Add Platform",
|
||||
|
||||
@@ -555,6 +555,7 @@
|
||||
"skills": "技能",
|
||||
"email": "邮件",
|
||||
"files": "文件",
|
||||
"access": "访问控制",
|
||||
"terminal": "终端",
|
||||
"settings": "设置"
|
||||
},
|
||||
@@ -763,6 +764,65 @@
|
||||
"deleteBotDescription": "删除此 Bot 后无法恢复,请谨慎操作。",
|
||||
"deleteBot": "删除 Bot"
|
||||
},
|
||||
"access": {
|
||||
"title": "访问控制",
|
||||
"subtitle": "游客聊天触发权限由 allow guest、白名单和黑名单共同决定。",
|
||||
"allowGuestDescription": "开启后,游客默认可触发聊天;黑名单仍然会优先阻止。",
|
||||
"saveGuestAccess": "保存游客访问设置",
|
||||
"guestAccessSaved": "游客访问设置已保存",
|
||||
"guestRulesTitle": "规则说明",
|
||||
"guestRulesDescription": "Owner 和成员始终可用;这里的规则只作用于游客的聊天触发。",
|
||||
"whitelistTitle": "白名单",
|
||||
"whitelistDescription": "当未开放游客时,白名单中的游客仍可触发聊天。",
|
||||
"blacklistTitle": "黑名单",
|
||||
"blacklistDescription": "即使已开放游客,黑名单中的游客也会被拒绝触发聊天。",
|
||||
"userSelector": "选择用户",
|
||||
"identitySelector": "选择平台身份",
|
||||
"selectUser": "搜索并选择用户",
|
||||
"selectIdentity": "搜索并选择平台身份",
|
||||
"searchUser": "搜索用户",
|
||||
"searchIdentity": "搜索平台身份",
|
||||
"noUserCandidates": "暂无可选用户",
|
||||
"noIdentityCandidates": "暂无可选平台身份",
|
||||
"userId": "用户 ID",
|
||||
"userIdPlaceholder": "输入用户 ID",
|
||||
"channelIdentityId": "Channel Identity ID",
|
||||
"channelIdentityIdPlaceholder": "输入 channel identity ID",
|
||||
"addWhitelist": "添加到白名单",
|
||||
"addBlacklist": "添加到黑名单",
|
||||
"clearSelection": "清空选择",
|
||||
"whitelistEmpty": "暂无白名单规则",
|
||||
"blacklistEmpty": "暂无黑名单规则",
|
||||
"validation": "请只填写一个主体:user_id 或 channel_identity_id",
|
||||
"validationConversationRequiresChannel": "按会话或线程限制时,请先选择来源平台",
|
||||
"validationThreadRequiresConversation": "填写线程 ID 前必须先填写会话 ID",
|
||||
"whitelistSaved": "白名单已更新",
|
||||
"blacklistSaved": "黑名单已更新",
|
||||
"saveFailed": "保存访问规则失败",
|
||||
"deleteSuccess": "规则已删除",
|
||||
"deleteFailed": "删除规则失败",
|
||||
"sourceScopeTitle": "来源范围",
|
||||
"sourceScopeDescription": "可选地将规则限制到某个平台、会话类型或指定会话/线程。",
|
||||
"sourceChannel": "来源平台",
|
||||
"anyChannel": "任意平台",
|
||||
"conversationType": "会话类型",
|
||||
"anyConversationType": "任意会话类型",
|
||||
"privateConversationType": "私聊",
|
||||
"groupConversationType": "群聊",
|
||||
"threadConversationType": "线程",
|
||||
"observedConversation": "历史会话",
|
||||
"selectObservedConversation": "选择一个历史会话",
|
||||
"searchObservedConversation": "搜索历史会话",
|
||||
"noObservedConversations": "暂无历史会话",
|
||||
"selectIdentityFirst": "请先选择平台身份以加载历史会话",
|
||||
"observedConversationHint": "选择历史会话后会自动填充平台、会话 ID 和线程 ID。",
|
||||
"conversationId": "会话 ID",
|
||||
"conversationIdPlaceholder": "输入会话 ID",
|
||||
"threadId": "线程 ID",
|
||||
"threadIdPlaceholder": "输入线程 ID",
|
||||
"clearScope": "清空范围",
|
||||
"lastObserved": "最近出现"
|
||||
},
|
||||
"channels": {
|
||||
"title": "平台",
|
||||
"addChannel": "添加平台",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -258,18 +258,6 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Allow Guest: only for public bot -->
|
||||
<template v-if="isPublicBot">
|
||||
<div class="flex items-center justify-between">
|
||||
<Label>{{ $t('bots.settings.allowGuest') }}</Label>
|
||||
<Switch
|
||||
:model-value="form.allow_guest"
|
||||
@update:model-value="(val) => form.allow_guest = !!val"
|
||||
/>
|
||||
</div>
|
||||
<Separator />
|
||||
</template>
|
||||
|
||||
<!-- Save -->
|
||||
<div class="flex justify-end">
|
||||
<Button
|
||||
@@ -352,8 +340,6 @@ const props = defineProps<{
|
||||
botType?: string
|
||||
}>()
|
||||
|
||||
const isPublicBot = computed(() => props.botType === 'public')
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
@@ -567,7 +553,6 @@ const form = reactive({
|
||||
max_context_load_time: 0,
|
||||
max_context_tokens: 0,
|
||||
language: '',
|
||||
allow_guest: false,
|
||||
reasoning_enabled: false,
|
||||
reasoning_effort: 'medium',
|
||||
})
|
||||
@@ -582,7 +567,6 @@ watch(settings, (val) => {
|
||||
form.max_context_load_time = val.max_context_load_time ?? 0
|
||||
form.max_context_tokens = val.max_context_tokens ?? 0
|
||||
form.language = val.language ?? ''
|
||||
form.allow_guest = val.allow_guest ?? false
|
||||
form.reasoning_enabled = val.reasoning_enabled ?? false
|
||||
form.reasoning_effort = val.reasoning_effort || 'medium'
|
||||
}
|
||||
@@ -602,9 +586,6 @@ const hasChanges = computed(() => {
|
||||
|| form.language !== (s.language ?? '')
|
||||
|| form.reasoning_enabled !== (s.reasoning_enabled ?? false)
|
||||
|| form.reasoning_effort !== (s.reasoning_effort || 'medium')
|
||||
if (isPublicBot.value) {
|
||||
changed = changed || form.allow_guest !== (s.allow_guest ?? false)
|
||||
}
|
||||
return changed
|
||||
})
|
||||
|
||||
|
||||
@@ -250,6 +250,7 @@ import BotSchedule from './components/bot-schedule.vue'
|
||||
import BotContainer from './components/bot-container.vue'
|
||||
import BotTerminal from './components/bot-terminal.vue'
|
||||
import BotFiles from './components/bot-files.vue'
|
||||
import BotAccess from './components/bot-access.vue'
|
||||
import { resolveApiErrorMessage } from '@/utils/api-error'
|
||||
import { useAvatarInitials } from '@/composables/useAvatarInitials'
|
||||
import { useSyncedQueryParam } from '@/composables/useSyncedQueryParam'
|
||||
@@ -289,6 +290,7 @@ const tabList = computed(() => {
|
||||
{ value: 'schedule', label: 'bots.tabs.schedule', component: BotSchedule, params: { 'bot-id': bot_id } },
|
||||
{ value: 'history', label: 'bots.tabs.history', component: BotHistory, params: { 'bot-id': bot_id } },
|
||||
{ value: 'skills', label: 'bots.tabs.skills', component: BotSkills, params: { 'bot-id': bot_id } },
|
||||
{ value: 'access', label: 'bots.tabs.access', component: BotAccess, params: { 'bot-id': bot_id, 'bot-type': bot.value?.type } },
|
||||
{ value: 'settings', label: 'bots.tabs.settings', component: BotSettings, params: { 'bot-id': bot_id, 'bot-type': bot.value?.type } }
|
||||
]
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user