mirror of
https://github.com/open-webui/open-webui.git
synced 2026-05-07 19:38:46 -05:00
refac: group share to settings
This commit is contained in:
@@ -159,40 +159,70 @@ class GroupTable:
|
|||||||
if filter:
|
if filter:
|
||||||
if "query" in filter:
|
if "query" in filter:
|
||||||
query = query.filter(Group.name.ilike(f"%{filter['query']}%"))
|
query = query.filter(Group.name.ilike(f"%{filter['query']}%"))
|
||||||
if "member_id" in filter:
|
|
||||||
query = query.join(
|
|
||||||
GroupMember, GroupMember.group_id == Group.id
|
|
||||||
).filter(GroupMember.user_id == filter["member_id"])
|
|
||||||
|
|
||||||
|
# When share filter is present, member check is handled in the share logic
|
||||||
if "share" in filter:
|
if "share" in filter:
|
||||||
share_value = filter["share"]
|
share_value = filter["share"]
|
||||||
json_share = Group.data["config"]["share"].as_boolean()
|
member_id = filter.get("member_id")
|
||||||
|
json_share = Group.data["config"]["share"]
|
||||||
|
json_share_bool = json_share.as_boolean()
|
||||||
|
json_share_str = json_share.as_string()
|
||||||
|
|
||||||
if share_value:
|
if share_value:
|
||||||
query = query.filter(
|
# Groups open to anyone: data is null, share is null, or share is true
|
||||||
or_(
|
anyone_can_share = or_(
|
||||||
Group.data.is_(None),
|
Group.data.is_(None),
|
||||||
json_share.is_(None),
|
json_share_bool.is_(None),
|
||||||
json_share == True,
|
json_share_bool == True,
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if member_id:
|
||||||
|
# Also include member-only groups where user is a member
|
||||||
|
member_groups_subq = (
|
||||||
|
db.query(GroupMember.group_id)
|
||||||
|
.filter(GroupMember.user_id == member_id)
|
||||||
|
.subquery()
|
||||||
|
)
|
||||||
|
members_only_and_is_member = and_(
|
||||||
|
json_share_str == "members",
|
||||||
|
Group.id.in_(member_groups_subq),
|
||||||
|
)
|
||||||
|
query = query.filter(
|
||||||
|
or_(anyone_can_share, members_only_and_is_member)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
query = query.filter(anyone_can_share)
|
||||||
else:
|
else:
|
||||||
query = query.filter(
|
query = query.filter(
|
||||||
and_(Group.data.isnot(None), json_share == False)
|
and_(Group.data.isnot(None), json_share_bool == False)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Only apply member_id filter when share filter is NOT present
|
||||||
|
if "member_id" in filter:
|
||||||
|
query = query.join(
|
||||||
|
GroupMember, GroupMember.group_id == Group.id
|
||||||
|
).filter(GroupMember.user_id == filter["member_id"])
|
||||||
|
|
||||||
groups = query.order_by(Group.updated_at.desc()).all()
|
groups = query.order_by(Group.updated_at.desc()).all()
|
||||||
return [
|
return [
|
||||||
GroupResponse.model_validate(
|
GroupResponse.model_validate(
|
||||||
{
|
{
|
||||||
**GroupModel.model_validate(group).model_dump(),
|
**GroupModel.model_validate(group).model_dump(),
|
||||||
"member_count": self.get_group_member_count_by_id(group.id, db=db),
|
"member_count": self.get_group_member_count_by_id(
|
||||||
|
group.id, db=db
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
for group in groups
|
for group in groups
|
||||||
]
|
]
|
||||||
|
|
||||||
def search_groups(
|
def search_groups(
|
||||||
self, filter: Optional[dict] = None, skip: int = 0, limit: int = 30, db: Optional[Session] = None
|
self,
|
||||||
|
filter: Optional[dict] = None,
|
||||||
|
skip: int = 0,
|
||||||
|
limit: int = 30,
|
||||||
|
db: Optional[Session] = None,
|
||||||
) -> GroupListResponse:
|
) -> GroupListResponse:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
query = db.query(Group)
|
query = db.query(Group)
|
||||||
@@ -228,7 +258,9 @@ class GroupTable:
|
|||||||
"total": total,
|
"total": total,
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_groups_by_member_id(self, user_id: str, db: Optional[Session] = None) -> list[GroupModel]:
|
def get_groups_by_member_id(
|
||||||
|
self, user_id: str, db: Optional[Session] = None
|
||||||
|
) -> list[GroupModel]:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
return [
|
return [
|
||||||
GroupModel.model_validate(group)
|
GroupModel.model_validate(group)
|
||||||
@@ -239,7 +271,9 @@ class GroupTable:
|
|||||||
.all()
|
.all()
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_group_by_id(self, id: str, db: Optional[Session] = None) -> Optional[GroupModel]:
|
def get_group_by_id(
|
||||||
|
self, id: str, db: Optional[Session] = None
|
||||||
|
) -> Optional[GroupModel]:
|
||||||
try:
|
try:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
group = db.query(Group).filter_by(id=id).first()
|
group = db.query(Group).filter_by(id=id).first()
|
||||||
@@ -247,7 +281,9 @@ class GroupTable:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_group_user_ids_by_id(self, id: str, db: Optional[Session] = None) -> Optional[list[str]]:
|
def get_group_user_ids_by_id(
|
||||||
|
self, id: str, db: Optional[Session] = None
|
||||||
|
) -> Optional[list[str]]:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
members = (
|
members = (
|
||||||
db.query(GroupMember.user_id).filter(GroupMember.group_id == id).all()
|
db.query(GroupMember.user_id).filter(GroupMember.group_id == id).all()
|
||||||
@@ -258,7 +294,9 @@ class GroupTable:
|
|||||||
|
|
||||||
return [m[0] for m in members]
|
return [m[0] for m in members]
|
||||||
|
|
||||||
def get_group_user_ids_by_ids(self, group_ids: list[str], db: Optional[Session] = None) -> dict[str, list[str]]:
|
def get_group_user_ids_by_ids(
|
||||||
|
self, group_ids: list[str], db: Optional[Session] = None
|
||||||
|
) -> dict[str, list[str]]:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
members = (
|
members = (
|
||||||
db.query(GroupMember.group_id, GroupMember.user_id)
|
db.query(GroupMember.group_id, GroupMember.user_id)
|
||||||
@@ -275,7 +313,9 @@ class GroupTable:
|
|||||||
|
|
||||||
return group_user_ids
|
return group_user_ids
|
||||||
|
|
||||||
def set_group_user_ids_by_id(self, group_id: str, user_ids: list[str], db: Optional[Session] = None) -> None:
|
def set_group_user_ids_by_id(
|
||||||
|
self, group_id: str, user_ids: list[str], db: Optional[Session] = None
|
||||||
|
) -> None:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
# Delete existing members
|
# Delete existing members
|
||||||
db.query(GroupMember).filter(GroupMember.group_id == group_id).delete()
|
db.query(GroupMember).filter(GroupMember.group_id == group_id).delete()
|
||||||
@@ -296,7 +336,9 @@ class GroupTable:
|
|||||||
db.add_all(new_members)
|
db.add_all(new_members)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
def get_group_member_count_by_id(self, id: str, db: Optional[Session] = None) -> int:
|
def get_group_member_count_by_id(
|
||||||
|
self, id: str, db: Optional[Session] = None
|
||||||
|
) -> int:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
count = (
|
count = (
|
||||||
db.query(func.count(GroupMember.user_id))
|
db.query(func.count(GroupMember.user_id))
|
||||||
@@ -306,7 +348,11 @@ class GroupTable:
|
|||||||
return count if count else 0
|
return count if count else 0
|
||||||
|
|
||||||
def update_group_by_id(
|
def update_group_by_id(
|
||||||
self, id: str, form_data: GroupUpdateForm, overwrite: bool = False, db: Optional[Session] = None
|
self,
|
||||||
|
id: str,
|
||||||
|
form_data: GroupUpdateForm,
|
||||||
|
overwrite: bool = False,
|
||||||
|
db: Optional[Session] = None,
|
||||||
) -> Optional[GroupModel]:
|
) -> Optional[GroupModel]:
|
||||||
try:
|
try:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
@@ -341,7 +387,9 @@ class GroupTable:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def remove_user_from_all_groups(self, user_id: str, db: Optional[Session] = None) -> bool:
|
def remove_user_from_all_groups(
|
||||||
|
self, user_id: str, db: Optional[Session] = None
|
||||||
|
) -> bool:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
try:
|
try:
|
||||||
# Find all groups the user belongs to
|
# Find all groups the user belongs to
|
||||||
@@ -401,7 +449,9 @@ class GroupTable:
|
|||||||
continue
|
continue
|
||||||
return new_groups
|
return new_groups
|
||||||
|
|
||||||
def sync_groups_by_group_names(self, user_id: str, group_names: list[str], db: Optional[Session] = None) -> bool:
|
def sync_groups_by_group_names(
|
||||||
|
self, user_id: str, group_names: list[str], db: Optional[Session] = None
|
||||||
|
) -> bool:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
try:
|
try:
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
@@ -462,7 +512,10 @@ class GroupTable:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def add_users_to_group(
|
def add_users_to_group(
|
||||||
self, id: str, user_ids: Optional[list[str]] = None, db: Optional[Session] = None
|
self,
|
||||||
|
id: str,
|
||||||
|
user_ids: Optional[list[str]] = None,
|
||||||
|
db: Optional[Session] = None,
|
||||||
) -> Optional[GroupModel]:
|
) -> Optional[GroupModel]:
|
||||||
try:
|
try:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
@@ -500,7 +553,10 @@ class GroupTable:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def remove_users_from_group(
|
def remove_users_from_group(
|
||||||
self, id: str, user_ids: Optional[list[str]] = None, db: Optional[Session] = None
|
self,
|
||||||
|
id: str,
|
||||||
|
user_ids: Optional[list[str]] = None,
|
||||||
|
db: Optional[Session] = None,
|
||||||
) -> Optional[GroupModel]:
|
) -> Optional[GroupModel]:
|
||||||
try:
|
try:
|
||||||
with get_db_context(db) as db:
|
with get_db_context(db) as db:
|
||||||
|
|||||||
@@ -39,11 +39,12 @@ async def get_groups(
|
|||||||
):
|
):
|
||||||
|
|
||||||
filter = {}
|
filter = {}
|
||||||
|
|
||||||
|
# Admins can share to all groups regardless of share setting
|
||||||
if user.role != "admin":
|
if user.role != "admin":
|
||||||
filter["member_id"] = user.id
|
filter["member_id"] = user.id
|
||||||
|
if share is not None:
|
||||||
if share is not None:
|
filter["share"] = share
|
||||||
filter["share"] = share
|
|
||||||
|
|
||||||
groups = Groups.get_groups(filter=filter, db=db)
|
groups = Groups.get_groups(filter=filter, db=db)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import { getContext } from 'svelte';
|
import { getContext } from 'svelte';
|
||||||
import Textarea from '$lib/components/common/Textarea.svelte';
|
import Textarea from '$lib/components/common/Textarea.svelte';
|
||||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
import Switch from '$lib/components/common/Switch.svelte';
|
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@@ -73,21 +72,30 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class=" flex w-full justify-between">
|
<div class=" flex w-full justify-between">
|
||||||
<div class=" self-center text-xs">
|
<div class=" self-center text-xs">
|
||||||
{$i18n.t('Allow Group Sharing')}
|
{$i18n.t('Who can share to this group')}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center gap-2 p-1">
|
<div class="flex items-center gap-2 p-1">
|
||||||
<Switch
|
<select
|
||||||
tooltip={true}
|
class="text-sm bg-transparent dark:bg-gray-900 outline-hidden rounded-lg px-2"
|
||||||
state={data?.config?.share ?? true}
|
value={data?.config?.share ?? true}
|
||||||
on:change={(e) => {
|
on:change={(e) => {
|
||||||
if (data?.config?.share) {
|
const value = e.target.value;
|
||||||
data.config.share = e.detail;
|
let shareValue;
|
||||||
|
if (value === 'false') {
|
||||||
|
shareValue = false;
|
||||||
|
} else if (value === 'true') {
|
||||||
|
shareValue = true;
|
||||||
} else {
|
} else {
|
||||||
data.config = { ...(data?.config ?? {}), share: e.detail };
|
shareValue = value;
|
||||||
}
|
}
|
||||||
|
data.config = { ...(data?.config ?? {}), share: shareValue };
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
<option value={false}>{$i18n.t('No one')}</option>
|
||||||
|
<option value="members">{$i18n.t('Members')}</option>
|
||||||
|
<option value={true}>{$i18n.t('Anyone')}</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user