Rocket.Chat Apps 引擎:动作按钮的角色过滤 now 支持按角色名(hasOneRole / hasAllRoles)

发布时间:2026/9/6 22:51:20

Rocket.Chat Apps 引擎:动作按钮的角色过滤 now 支持按角色名(hasOneRole / hasAllRoles)
Rocket.Chat Apps 引擎动作按钮的角色过滤 now 支持按角色名hasOneRole / hasAllRoles【免费下载链接】Rocket.ChatThe Secure CommsOS™ for mission-critical operations项目地址: https://gitcode.com/GitHub_Trending/ro/Rocket.Chat本篇基于仓库中的变更集.changeset/app-action-button-role-names.md展开Rocket.Chat 的 Apps 引擎在应用动作按钮app action button的when过滤条件中让hasOneRole与hasAllRoles两个过滤器除了接受角色 ID 之外新增接受角色名role name。你将理解这一变更涉及哪两个包rocket.chat/apps-engine、rocket.chat/meteor均为 minor 级更新、为什么自定义角色必须用名字而非 ID 来匹配、客户端如何在渲染时完成名字 → ID解析以及按房间作用域授予的角色owner、moderator、leader等在哪些界面才能命中。一、变更集说了什么.changeset/app-action-button-role-names.md 的完整内容如下--- rocket.chat/apps-engine: minor rocket.chat/meteor: minor --- Accepts a role name in the when.hasOneRole and when.hasAllRoles filters of an app action button要点拆解变更语义应用动作按钮的when.hasOneRole持有列表中任意一个角色即显示按钮与when.hasAllRoles必须持有列表中全部角色才显示按钮过滤器条目现在既可以是角色 ID也可以是角色名。涉及包rocket.chat/apps-engineminor——负责动作按钮描述符的类型定义即IUActionButtonWhen接口的文档与约束更新rocket.chat/meteorminor——负责 Web 客户端在渲染按钮时的实际过滤逻辑更新。兼容性两个包均为 minor 版本提升说明这是向后兼容的增量能力——原来用角色 ID 写法的 App 不受影响新写法只是拓宽了可接受的取值。二、类型定义层IUActionButtonWhen的角色过滤器变更落在 IUIActionButtonDescriptor.ts 中的IUActionButtonWhen接口。与角色相关的两个字段及其官方注释JSDoc如下export interface IUActionButtonWhen { roomTypes?: ArrayRoomTypeFilter; messageActionContext?: ArrayMessageActionContext; hasOnePermission?: Arraystring; hasAllPermissions?: Arraystring; /** * Show the button when the user holds at least one of these roles. * * Each entry is a role id or a role name. Prefer the name for a custom role, * because its id differs between workspaces. * * A role scoped to Subscriptions — owner, moderator, leader, or a custom * one — is granted per room, so it matches only on surfaces bound to a room. On a * surface with no room of its own, the user dropdown for instance, only roles * scoped to Users match. */ hasOneRole?: Arraystring; /** * Show the button when the user holds every one of these roles. * …语义同上要求全部命中 */ hasAllRoles?: Arraystring; }注释明确了三条关键规则每个条目可以是角色 ID 或角色名对自定义角色推荐用名字因为同一个自定义角色在不同工作空间workspace里的_id不同而名字才是可移植的标识。作用域为Subscriptions的角色按房间授予——例如owner、moderator、leader以及自定义的按房间角色它们只对绑定到某个房间的界面生效。没有房间上下文的界面典型如用户下拉菜单 user dropdown只能匹配作用域为Users的工作空间级角色。外层按钮描述符IUIActionButtonDescriptor则通过可选的when字段挂接这些过滤条件并带有actionId、context、labelI18n、variant、category等字段运行时由 App 注入appId后成为IUIActionButton。三、客户端实现useApplyButtonAuthFilter如何解析角色名实际过滤发生在 Meteor 客户端的 useApplyButtonFilters.ts。核心是useApplyButtonAuthFilter它从AuthorizationContext取出权限查询函数与useRoleIdResolver对按钮执行四组检查并按 AND 逻辑聚合export const useApplyButtonAuthFilter (): ((button: IUIActionButton, room?: IRoom) boolean) { const uid useUserId(); const { queryAllPermissions, queryAtLeastOnePermission, queryRole } useContext(AuthorizationContext); // An app knows the name of a custom role, not the random id the workspace gave it, // so accept either form in the role filters. const resolveRoleId useRoleIdResolver(); return useCallback( (button: IUIActionButton, room?: IRoom) { const { hasAllPermissions, hasOnePermission, hasAllRoles, hasOneRole } button.when || {}; const hasAllPermissionsResult hasAllPermissions ? queryAllPermissions(hasAllPermissions)[1]() : true; const hasOnePermissionResult hasOnePermission ? queryAtLeastOnePermission(hasOnePermission)[1]() : true; const hasAllRolesResult hasAllRoles ? !!uid hasAllRoles.every((role) queryRole(resolveRoleId(role), room?._id)[1]()) : true; const hasOneRoleResult hasOneRole ? !!uid hasOneRole.some((role) queryRole(resolveRoleId(role), room?._id)[1]()) : true; return hasAllPermissionsResult hasOnePermissionResult hasAllRolesResult hasOneRoleResult; }, [queryAllPermissions, queryAtLeastOnePermission, queryRole, resolveRoleId, uid], ); };逐行看与本次变更直接相关的部分hasAllRoles使用Array.prototype.everyhasOneRole使用Array.prototype.some分别对应全部命中与任一命中的语义未配置过滤器时默认放行true。!!uid前置判断保证了未登录用户只要按钮声明了角色要求就一律被过滤。每个角色条目在进入queryRole之前先经过resolveRoleId(role)解析——这正是接受角色名能力的落点room?._id作为第二个参数传入把按房间授予的角色检查限定在当前房间内。同一文件中的useApplyButtonFilters则在房间上下文中组合三类过滤器权限/角色、房间类型roomTypes、category源码中的注释同样点明了作用域规则export const useApplyButtonFilters (category default): ((button: IUIActionButton) boolean) { const room useRoom(); if (!room) { throw new Error(useApplyButtonFilters must be used inside a room context); } const applyAuthFilter useApplyButtonAuthFilter(); return useCallback( // The room is the scope of the role check: without it a role scoped to // Subscriptions — owner, moderator, leader, or a custom one — can never match. (button: IUIActionButton) applyAuthFilter(button, room) applyRoomFilter(button, room) applyCategoryFilter(button, category), [applyAuthFilter, category, room], ); };其中applyRoomFilter通过enumToFilter把RoomTypeFilter枚举映射到对IRoom的判断函数公开/私有频道、团队、讨论、私信、Live Chat 等与角色过滤互为 AND 条件。四、名字到 ID 的解析useRoleIdResolver条目既可以是 ID 也可以是名字之所以成立依赖 useRoleIdResolver.ts由 ui-contexts 包导出。其实现export const useRoleIdResolver (): ((role: string) IRole[_id]) { const { getRoles, subscribeToRoles } useContext(AuthorizationContext); const roles useSyncExternalStore(subscribeToRoles, getRoles); const idsByName useMemo(() { const index new MapIRole[name], IRole[_id](); for (const role of roles.values()) { // roles.create and roles.update reject a name already taken by another role, so a // name maps to at most one role. Should duplicates still exist (e.g. written straight // to the database), the first one iterated wins instead of the last, so adding another // duplicate later does not silently repoint every check that names it. if (index.has(role.name)) { continue; } index.set(role.name, role._id); } return index; }, [roles]); return useCallback((role: string) (roles.has(role) ? role : (idsByName.get(role) ?? role)), [idsByName, roles]); };三个值得注意的设计决策ID 优先如果传入字符串本身已是某角色的_idroles.has(role)直接原样返回否则再查名字 → ID索引查不到则原样返回后续queryRole会判定为不匹配按钮被过滤而不是抛错。名字唯一性依赖服务端约束注释指出roles.create/roles.update会拒绝已被占用的名字因此名字最多映射到一个角色即便数据库里出现重复索引也采用先遇到的名字胜策略避免后来者静默改变所有按名检查的指向。响应式订阅通过useSyncExternalStore订阅角色集合角色增删后索引自动重建过滤器结果随之更新。五、测试用例行为边界的可验证依据useApplyButtonFilters.spec.ts 用mockAppRoot()覆盖了完整的角色过滤矩阵与上述实现一一对应基础过滤用户持有admin时hasAllRoles: [admin]通过仅有user角色时不通过hasOneRole: [admin, moderator]命中moderator即通过两个都不持有则不通过未声明角色过滤器的按钮默认显示匿名未登录用户遇到角色要求一律不通过。自定义角色名解析以{ _id: aBcDeF1234567890x, name: Support Agent }模拟自定义角色验证——按名字Support Agent要求能命中持有该角色 ID 的用户按 ID 要求同样命中向下兼容要求一个不存在的名字No Such Role时被过滤。ID 与重名冲突构造一个陷阱角色其name恰好等于另一角色的_id且用户只持有陷阱角色——测试断言按该 ID 要求时不显示按钮证明解析器ID 优先的规则不会因名字冲突误放行。房间作用域角色owner按Subscriptions作用域授予到某房间后——传入该房间时hasOneRole: [owner]通过不传房间如用户下拉时被过滤角色授予在别的房间时在当前房间也被过滤而工作空间级admin角色在房间上下文中依然能命中。组合过滤hasAllRoles与hasAllPermissions同时存在时按 AND 逻辑叠加全部满足才显示。这些用例共同划定了功能边界角色名解析只影响按什么键查角色不改变按房间作用域判定的既有语义。六、对 App 开发者的实际影响在应用的动作按钮描述符里现在可以这样按名字约束按钮的可见性示意字段取值遵循 IUIActionButtonDescriptor.ts 定义const button: IUIActionButtonDescriptor { actionId: close-support-ticket, context: UIActionButtonContext.ROOM_ACTION, labelI18n: close_ticket, when: { // 任一命中即显示对自定义角色推荐使用名字而非 ID hasOneRole: [Support Agent, moderator], }, };使用要点自定义角色优先写名字自定义角色的_id在不同工作空间各不相同用名字可保证同一份 App 代码在多实例间可移植系统内置角色admin等名字与 ID 一致两种写法等效。hasOneRole与hasAllRoles语义别混用前者是some任一命中后者是every全部命中对应按钮至少一个角色可见和必须同时具备多个角色两类需求。房间作用域角色的界面限制owner、moderator、leader及自定义的按房间角色只会在绑定房间的界面如房间工具栏动作命中在用户下拉这类无房间上下文的表面只有Users作用域的角色能命中。这是由 useApplyButtonFilters.ts 中把room?._id透传给queryRole的机制保证的。未登录与未知名字均安全失败未登录用户、以及解析不到任何角色的名字都会让按钮被过滤行为与按 ID 要求一个不存在的 ID一致。七、小结这条变更集对应的工作由三处源码支撑类型层在 IUIActionButtonDescriptor.ts 中把两个角色过滤器声明为ID 或名字解析层在 useRoleIdResolver.ts 中以ID 优先、名字索引、响应式重建完成名字到 ID 的归一执行层在 useApplyButtonFilters.ts 中把归一后的角色 ID 带入带房间作用域的queryRole检查。useApplyButtonFilters.spec.ts 中的测试矩阵含名字/ID 双写、重名冲突、房间作用域则给出了这一能力的可验证行为边界。对 App 作者而言最直接的价值是自定义角色第一次可以以跨工作空间可移植的名字形式出现在动作按钮的可见性条件里。【免费下载链接】Rocket.ChatThe Secure CommsOS™ for mission-critical operations项目地址: https://gitcode.com/GitHub_Trending/ro/Rocket.Chat创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

精益六西格玛实战:用DMAIC框架与核心工具链破解流程改善难题

精益六西格玛实战:用DMAIC框架与核心工具链破解流程改善难题

2026/9/6 22:51:20

简介:这份71页PPT面向质量管理、流程优化及精益六西格玛入门学习者,系统梳理精益六西格玛的核心价值观与DMAIC五步法(定义、测量、分析、改善、控制),并按阶段介绍排列图、因果图、控制图、SIPOC、VOC/VOB、亲和图等常…

信息学奥赛C++启蒙:1-86课实战避坑与算法进阶路线

信息学奥赛C++启蒙:1-86课实战避坑与算法进阶路线

2026/9/6 22:41:20

简介:《信息学奥赛一本通编程启蒙 C版》1-86课合集以单个PDF形式呈现,面向零基础C学习者与准备GESP、信息学奥赛的入门选手。内容从第一个C程序、输入输出、整型与浮点型、字符类型,延伸到多分支if、switch、for/while/do-while循环、程序流程…

NBIoT+5G融合的智慧园区解决方案:从网络选型到落地实践

NBIoT+5G融合的智慧园区解决方案:从网络选型到落地实践

2026/9/6 22:41:20

简介:这份解决方案演示文稿面向智慧园区物联网及第五代移动通信技术应用相关从业者,系统梳理了政策驱动、行业现状与园区智慧化转型的核心诉求,并结合案例给出可落地的建设思路。内容涵盖行业理解、八大核心应用场景、场景化方案与成功案例&a…

ChCore操作系统实验全解析:从启动到虚拟内存与异常处理

ChCore操作系统实验全解析:从启动到虚拟内存与异常处理

2026/9/6 23:51:23

简介:面向操作系统课程设计与实践备考的完整实验方案,围绕上海交通大学Chcore操作系统教学环境,覆盖内存管理、系统调用与缺页异常两大核心模块。文档对分页机制、页表管理、内存分配与回收、内存保护、换页流程以及系统调用、缺页处理、页替…

把树莓派装进铁盒:从系统配置到长期稳定运行的完整指南

把树莓派装进铁盒:从系统配置到长期稳定运行的完整指南

2026/9/6 23:51:23

我最近在整理一块树莓派主板,准备把它塞进一个小铁盒,放在路由器旁边当一台长期运行的小型服务器。这个项目的标题叫“把树莓派装进小铁盒”,听起来像是一个动手向的硬件改造,但真正做下来你会发现,核心难点根本不在铁…

基于游戏化量子密钥分发协议科普软件设计

基于游戏化量子密钥分发协议科普软件设计

2026/9/6 23:51:23

摘 要 随着网络安全需求的不断提升,量子密钥分发(QKD)作为一种具备物理安全性的技术备受关注。BB84协议是量子通信入门教学的核心内容,但由于涉及量子比特、偏振基、随机测量等抽象概念,初学者仅通过传统文本往往难以…

基于Android的汝州青瓷博物馆文化推广APP实现

基于Android的汝州青瓷博物馆文化推广APP实现

2026/9/6 23:51:23

摘 要 本文针对汝州青瓷博物馆文化推广手段单一、受众面受限等现状,设计并实现了一套基于Android平台的文化推广APP。系统采用前后端分离的架构模式,后端基于SpringBoot框架构建,利用其强大的依赖管理与自动配置特性确保数据处理的高效性与…

虚拟机入门避坑指南:从心智模型到长期维护实践

虚拟机入门避坑指南:从心智模型到长期维护实践

2026/9/6 23:51:23

别急着先打开软件新建虚拟机。我在工作里见过太多人,包括我自己第一次接触虚拟机的时候,都是先下载一个大体积的镜像,然后不断试错,最后卡在某个报错上,对着英文弹窗发呆。 “春岚但是 vm”,这是一个很典型…

煤矿测量规程实战:从矿井定向到贯通测量的关键技术与经验

煤矿测量规程实战:从矿井定向到贯通测量的关键技术与经验

2026/9/6 23:41:23

简介:《煤矿测量规程(2011版)》文档资源是一份系统梳理煤矿测量规范与知识点总览的专业资料,面向矿山测量技术人员、安全生产管理人员、测绘专业学生及备考相关资格考试的读者,能够帮助快速建立煤矿测量知识体系&#…

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

中国人民大学杨琳团队《Nature Communications》 | 全球潮汐湿地土壤有机碳时空格局与环境驱动:一项2009-2020年的全球评估

2026/9/6 1:19:56

本文首发于“生态学者”!从“湿地面积”到“土壤碳密度”:为什么需要重新认识潮汐湿地蓝碳变化?潮汐湿地位于陆地与海洋的交汇地带,包括红树林、盐沼和潮滩,是全球重要的蓝碳生态系统。其土壤能够长期储存大量有机碳&a…

adb抓包

adb抓包

2026/9/6 1:19:56

前言 本文介绍如何通过 tcpdump 在 Android 手机上抓取网络数据包,并在电脑端使用 Wireshark 进行分析。适用于需要排查 App 网络请求、分析接口调用或调试网络问题的开发与测试场景。1. 手机要有 root 权限2. 下载 tcpdump3. adb push C:\Users\zhangkuixun\Downlo…

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战

2026/9/6 1:19:56

大模型推理镜像极简瘦身:从 25GB 巨无霸到 3GB 精简镜像实战 在云原生基础设施中,容器镜像体积直接决定了服务的部署速度与弹性扩容敏捷度。对于传统的 Go / Java 微服务,镜像体积通常被严格控制在 50MB 到 200MB 以内,拉取镜像只…

远程协作的工作台整理

远程协作的工作台整理

2026/9/3 6:56:24

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/4 7:42:10

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/6 23:21:51

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…