diff --git a/backend/open_webui/models/skills.py b/backend/open_webui/models/skills.py index b4a64fd02d..cff4778394 100644 --- a/backend/open_webui/models/skills.py +++ b/backend/open_webui/models/skills.py @@ -163,9 +163,30 @@ class SkillsTable: except Exception: return None - async def get_skills(self, db: Optional[AsyncSession] = None) -> list[SkillUserModel]: + async def get_skills( + self, + user_id: str | None = None, + ids: list[str] | None = None, + db: AsyncSession | None = None, + ) -> list[SkillUserModel]: async with get_async_db_context(db) as db: - result = await db.execute(select(Skill).order_by(Skill.updated_at.desc())) + stmt = select(Skill).order_by(Skill.updated_at.desc()) + + if ids is not None: + stmt = stmt.filter(Skill.id.in_(ids)) + + if user_id is not None: + user_group_ids = {group.id for group in await Groups.get_groups_by_member_id(user_id, db=db)} + stmt = AccessGrants.has_permission_filter( + db=db, + query=stmt, + DocumentModel=Skill, + filter={'user_id': user_id, 'group_ids': user_group_ids}, + resource_type='skill', + permission='read', + ) + + result = await db.execute(stmt) all_skills = result.scalars().all() user_ids = list(set(skill.user_id for skill in all_skills)) @@ -194,28 +215,6 @@ class SkillsTable: ) return skills - async def get_skills_by_user_id( - self, user_id: str, permission: str = 'write', db: Optional[AsyncSession] = None - ) -> list[SkillUserModel]: - skills = await self.get_skills(db=db) - user_groups = await Groups.get_groups_by_member_id(user_id, db=db) - user_group_ids = {group.id for group in user_groups} - - result = [] - for skill in skills: - if skill.user_id == user_id: - result.append(skill) - elif await AccessGrants.has_access( - user_id=user_id, - resource_type='skill', - resource_id=skill.id, - permission=permission, - user_group_ids=user_group_ids, - db=db, - ): - result.append(skill) - return result - async def search_skills( self, user_id: str, diff --git a/backend/open_webui/routers/skills.py b/backend/open_webui/routers/skills.py index 9c268d8dcc..75831fe58d 100644 --- a/backend/open_webui/routers/skills.py +++ b/backend/open_webui/routers/skills.py @@ -46,21 +46,7 @@ async def get_skills( if user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL: skills = await Skills.get_skills(db=db) else: - user_group_ids = {group.id for group in await Groups.get_groups_by_member_id(user.id, db=db)} - all_skills = await Skills.get_skills(db=db) - skills = [ - skill - for skill in all_skills - if skill.user_id == user.id - or await AccessGrants.has_access( - user_id=user.id, - resource_type='skill', - resource_id=skill.id, - permission='read', - user_group_ids=user_group_ids, - db=db, - ) - ] + skills = await Skills.get_skills(db=db, user_id=user.id) if query: q = query.casefold() @@ -99,30 +85,29 @@ async def get_skill_list( if direction: filter['direction'] = direction - if not (user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL): - groups = await Groups.get_groups_by_member_id(user.id, db=db) - if groups: - filter['group_ids'] = [group.id for group in groups] + is_bypass_admin = user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL + user_group_ids = {group.id for group in await Groups.get_groups_by_member_id(user.id, db=db)} + if not is_bypass_admin: + filter['group_ids'] = user_group_ids filter['user_id'] = user.id result = await Skills.search_skills(user.id, filter=filter, skip=skip, limit=limit, db=db) + writable_skill_ids = await AccessGrants.get_accessible_resource_ids( + user_id=user.id, + resource_type='skill', + resource_ids=[skill.id for skill in result.items], + permission='write', + user_group_ids=user_group_ids, + db=db, + ) + return SkillAccessListResponse( items=[ SkillAccessResponse( **skill.model_dump(), - write_access=( - (user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL) - or user.id == skill.user_id - or await AccessGrants.has_access( - user_id=user.id, - resource_type='skill', - resource_id=skill.id, - permission='write', - db=db, - ) - ), + write_access=(is_bypass_admin or user.id == skill.user_id or skill.id in writable_skill_ids), ) for skill in result.items ], @@ -155,7 +140,7 @@ async def export_skills( if user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL: return await Skills.get_skills(db=db) else: - return await Skills.get_skills_by_user_id(user.id, 'read', db=db) + return await Skills.get_skills(db=db, user_id=user.id) ############################ diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index a7576cd416..03e4dc72f8 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2643,9 +2643,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): if skill_ids: from open_webui.models.skills import Skills as SkillsModel - # Reuse the rows from the access query instead of re-fetching each - # skill by id. - accessible_skills = {s.id: s for s in await SkillsModel.get_skills_by_user_id(user.id, 'read')} + accessible_skills = {s.id: s for s in await SkillsModel.get_skills(user_id=user.id, ids=skill_ids)} for sid in skill_ids: s = accessible_skills.get(sid) if s and s.is_active: