Skip to content

Commit 05de107

Browse files
committed
Squashed commit of the following:
commit 677f4b5f95544b75ca17afa3539f4260c311455d Merge: 308d2cb 2b26355 Author: Luke Garceau <ltgarc768@gmail.com> Date: Mon Jan 12 13:18:34 2026 -0500 merge conflicts commit 308d2cb Author: Luke Garceau <ltgarc768@gmail.com> Date: Wed Dec 31 13:51:48 2025 -0500 Revert "Merge branch 'dev' of github.com:open-webui/open-webui into feat/google-oauth-groups-lgarceau" This reverts commit 6dd6e0c, reversing changes made to dd1e2b5. commit 6dd6e0c Merge: dd1e2b5 fe3047d Author: Luke Garceau <ltgarc768@gmail.com> Date: Mon Dec 29 17:14:48 2025 -0500 Merge branch 'dev' of github.com:open-webui/open-webui into feat/google-oauth-groups-lgarceau commit dd1e2b5 Merge: 943e4ca a727153 Author: Luke Garceau <ltgarc768@gmail.com> Date: Mon Dec 29 16:05:54 2025 -0500 Merge branch 'main' of personal:flexion/open-webui into feat/google-oauth-groups-lgarceau commit 943e4ca Author: Luke Garceau <ltgarc768@gmail.com> Date: Mon Dec 29 16:05:52 2025 -0500 resolve oauth issues commit 4b34300 Merge: 6f1486f 9eb4484 Author: Luke Garceau <ltgarc768@gmail.com> Date: Tue Dec 9 16:51:53 2025 -0500 init implementation commit commit 9eb4484 Merge: e0d5de1 d277696 Author: Luke Garceau <ltgarc768@gmail.com> Date: Thu Nov 27 15:46:49 2025 -0500 Merge pull request #2 from lgarceau768/main Version 0.6.34 Updates commit d277696 Merge: 6c86ff7 e0d5de1 Author: Luke Garceau <ltgarc768@gmail.com> Date: Sat Nov 22 11:24:58 2025 -0500 Merge branch 'main' into main commit 6c86ff7 Merge: 7a83e7d 6dbc01c Author: Luke Garceau <ltgarc768@gmail.com> Date: Wed Nov 5 12:05:23 2025 -0500 Merge pull request #1 from lgarceau768/feat/google-groups Google Groups Functionaliity on top of version 0.6.34 commit 6dbc01c Merge: 7a83e7d cc6a1a7 Author: Luke Garceau <ltgarc768@gmail.com> Date: Wed Nov 5 10:44:30 2025 -0500 - resolve merge conflicts commit cc6a1a7 Author: Brice Ruth <bruth@flexion.us> Date: Mon Jun 16 18:18:52 2025 -0500 update tests for adjusted query string & payload commit 64ce040 Author: Brice Ruth <bruth@flexion.us> Date: Mon Jun 16 17:49:42 2025 -0500 fix google cloud identity query string commit a909fd9 Author: Brice Ruth <bruth@flexion.us> Date: Mon Jun 16 11:35:47 2025 -0500 feat: Add Google Cloud Identity API support for OAuth group-based roles Enables Google Workspace group-based role assignment by integrating with Google Cloud Identity API to fetch user groups in real-time. Key improvements: - Fetches groups directly from Google API using cloud-identity.groups.readonly scope - Enables admin role assignment based on Google group membership - Maintains full backward compatibility with existing OAuth configurations - Includes comprehensive test suite with proper async mocking - Complete documentation with Google Cloud Console setup guide Addresses limitation where Google Workspace doesn't include group membership claims in OAuth JWT tokens, preventing group-based role assignment. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 2b26355 commit 05de107

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1436
-809
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ ENV APP_BUILD_HASH=${BUILD_HASH}
4343
RUN npm run build
4444

4545
######## WebUI backend ########
46-
FROM python:3.11.14-slim-bookworm AS base
46+
FROM python:3.11-slim-bookworm AS base
4747

4848
# Use args
4949
ARG USE_CUDA

backend/open_webui/config.py

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
from open_webui.env import (
2020
DATA_DIR,
2121
DATABASE_URL,
22-
ENABLE_DB_MIGRATIONS,
2322
ENV,
2423
REDIS_URL,
2524
REDIS_KEY_PREFIX,
@@ -68,8 +67,7 @@ def run_migrations():
6867
log.exception(f"Error running migrations: {e}")
6968

7069

71-
if ENABLE_DB_MIGRATIONS:
72-
run_migrations()
70+
run_migrations()
7371

7472

7573
class Config(Base):
@@ -2373,51 +2371,6 @@ class BannerModel(BaseModel):
23732371
except Exception:
23742372
PGVECTOR_IVFFLAT_LISTS = 100
23752373

2376-
# openGauss
2377-
OPENGAUSS_DB_URL = os.environ.get("OPENGAUSS_DB_URL", DATABASE_URL)
2378-
2379-
OPENGAUSS_INITIALIZE_MAX_VECTOR_LENGTH = int(
2380-
os.environ.get("OPENGAUSS_INITIALIZE_MAX_VECTOR_LENGTH", "1536")
2381-
)
2382-
2383-
OPENGAUSS_POOL_SIZE = os.environ.get("OPENGAUSS_POOL_SIZE", None)
2384-
2385-
if OPENGAUSS_POOL_SIZE != None:
2386-
try:
2387-
OPENGAUSS_POOL_SIZE = int(OPENGAUSS_POOL_SIZE)
2388-
except Exception:
2389-
OPENGAUSS_POOL_SIZE = None
2390-
2391-
OPENGAUSS_POOL_MAX_OVERFLOW = os.environ.get("OPENGAUSS_POOL_MAX_OVERFLOW", 0)
2392-
2393-
if OPENGAUSS_POOL_MAX_OVERFLOW == "":
2394-
OPENGAUSS_POOL_MAX_OVERFLOW = 0
2395-
else:
2396-
try:
2397-
OPENGAUSS_POOL_MAX_OVERFLOW = int(OPENGAUSS_POOL_MAX_OVERFLOW)
2398-
except Exception:
2399-
OPENGAUSS_POOL_MAX_OVERFLOW = 0
2400-
2401-
OPENGAUSS_POOL_TIMEOUT = os.environ.get("OPENGAUSS_POOL_TIMEOUT", 30)
2402-
2403-
if OPENGAUSS_POOL_TIMEOUT == "":
2404-
OPENGAUSS_POOL_TIMEOUT = 30
2405-
else:
2406-
try:
2407-
OPENGAUSS_POOL_TIMEOUT = int(OPENGAUSS_POOL_TIMEOUT)
2408-
except Exception:
2409-
OPENGAUSS_POOL_TIMEOUT = 30
2410-
2411-
OPENGAUSS_POOL_RECYCLE = os.environ.get("OPENGAUSS_POOL_RECYCLE", 3600)
2412-
2413-
if OPENGAUSS_POOL_RECYCLE == "":
2414-
OPENGAUSS_POOL_RECYCLE = 3600
2415-
else:
2416-
try:
2417-
OPENGAUSS_POOL_RECYCLE = int(OPENGAUSS_POOL_RECYCLE)
2418-
except Exception:
2419-
OPENGAUSS_POOL_RECYCLE = 3600
2420-
24212374
# Pinecone
24222375
PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY", None)
24232376
PINECONE_ENVIRONMENT = os.environ.get("PINECONE_ENVIRONMENT", None)
@@ -3737,7 +3690,6 @@ class BannerModel(BaseModel):
37373690
os.getenv("WHISPER_MODEL", "base"),
37383691
)
37393692

3740-
WHISPER_COMPUTE_TYPE = os.getenv("WHISPER_COMPUTE_TYPE", "int8")
37413693
WHISPER_MODEL_DIR = os.getenv("WHISPER_MODEL_DIR", f"{CACHE_DIR}/whisper/models")
37423694
WHISPER_MODEL_AUTO_UPDATE = (
37433695
not OFFLINE_MODE

backend/open_webui/internal/db.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ def handle_peewee_migration(DATABASE_URL):
7777
assert db.is_closed(), "Database connection is still open."
7878

7979

80-
if ENABLE_DB_MIGRATIONS:
81-
handle_peewee_migration(DATABASE_URL)
80+
handle_peewee_migration(DATABASE_URL)
8281

8382

8483
SQLALCHEMY_DATABASE_URL = DATABASE_URL

backend/open_webui/main.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@
102102
get_rf,
103103
)
104104

105-
106-
from sqlalchemy.orm import Session
107-
from open_webui.internal.db import ScopedSession, engine, get_session
105+
from open_webui.internal.db import Session, ScopedSession, engine
108106

109107
from open_webui.models.functions import Functions
110108
from open_webui.models.models import Models
@@ -2315,13 +2313,8 @@ async def oauth_login(provider: str, request: Request):
23152313
# - Email addresses are considered unique, so we fail registration if the email address is already taken
23162314
@app.get("/oauth/{provider}/login/callback")
23172315
@app.get("/oauth/{provider}/callback") # Legacy endpoint
2318-
async def oauth_login_callback(
2319-
provider: str,
2320-
request: Request,
2321-
response: Response,
2322-
db: Session = Depends(get_session),
2323-
):
2324-
return await oauth_manager.handle_callback(request, provider, response, db=db)
2316+
async def oauth_login_callback(provider: str, request: Request, response: Response):
2317+
return await oauth_manager.handle_callback(request, provider, response)
23252318

23262319

23272320
@app.get("/manifest.json")
@@ -2380,7 +2373,7 @@ async def healthcheck():
23802373

23812374
@app.get("/health/db")
23822375
async def healthcheck_with_db():
2383-
ScopedSession.execute(text("SELECT 1;")).all()
2376+
Session.execute(text("SELECT 1;")).all()
23842377
return {"status": True}
23852378

23862379

backend/open_webui/models/auths.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
import uuid
33
from typing import Optional
44

5-
from sqlalchemy.orm import Session
6-
from open_webui.internal.db import Base, JSONField, get_db, get_db_context
5+
from open_webui.internal.db import Base, get_db, Session
76
from open_webui.models.users import UserModel, UserProfileImageResponse, Users
87
from pydantic import BaseModel
98
from sqlalchemy import Boolean, Column, String, Text
@@ -88,9 +87,8 @@ def insert_new_auth(
8887
profile_image_url: str = "/user.png",
8988
role: str = "pending",
9089
oauth: Optional[dict] = None,
91-
db: Optional[Session] = None,
9290
) -> Optional[UserModel]:
93-
with get_db_context(db) as db:
91+
with get_db() as db:
9492
log.info("insert_new_auth")
9593

9694
id = str(uuid.uuid4())
@@ -102,7 +100,7 @@ def insert_new_auth(
102100
db.add(result)
103101

104102
user = Users.insert_new_user(
105-
id, name, email, profile_image_url, role, oauth=oauth, db=db
103+
id, name, email, profile_image_url, role, oauth=oauth
106104
)
107105

108106
db.commit()
@@ -114,16 +112,16 @@ def insert_new_auth(
114112
return None
115113

116114
def authenticate_user(
117-
self, email: str, verify_password: callable, db: Optional[Session] = None
115+
self, email: str, verify_password: callable
118116
) -> Optional[UserModel]:
119117
log.info(f"authenticate_user: {email}")
120118

121-
user = Users.get_user_by_email(email, db=db)
119+
user = Users.get_user_by_email(email)
122120
if not user:
123121
return None
124122

125123
try:
126-
with get_db_context(db) as db:
124+
with get_db() as db:
127125
auth = db.query(Auth).filter_by(id=user.id, active=True).first()
128126
if auth:
129127
if verify_password(auth.password):
@@ -144,7 +142,7 @@ def authenticate_user_by_api_key(
144142
return None
145143

146144
try:
147-
user = Users.get_user_by_api_key(api_key, db=db)
145+
user = Users.get_user_by_api_key(api_key)
148146
return user if user else None
149147
except Exception:
150148
return False
@@ -154,10 +152,10 @@ def authenticate_user_by_email(
154152
) -> Optional[UserModel]:
155153
log.info(f"authenticate_user_by_email: {email}")
156154
try:
157-
with get_db_context(db) as db:
155+
with get_db() as db:
158156
auth = db.query(Auth).filter_by(email=email, active=True).first()
159157
if auth:
160-
user = Users.get_user_by_id(auth.id, db=db)
158+
user = Users.get_user_by_id(auth.id)
161159
return user
162160
except Exception:
163161
return None
@@ -166,7 +164,7 @@ def update_user_password_by_id(
166164
self, id: str, new_password: str, db: Optional[Session] = None
167165
) -> bool:
168166
try:
169-
with get_db_context(db) as db:
167+
with get_db() as db:
170168
result = (
171169
db.query(Auth).filter_by(id=id).update({"password": new_password})
172170
)
@@ -179,18 +177,18 @@ def update_email_by_id(
179177
self, id: str, email: str, db: Optional[Session] = None
180178
) -> bool:
181179
try:
182-
with get_db_context(db) as db:
180+
with get_db() as db:
183181
result = db.query(Auth).filter_by(id=id).update({"email": email})
184182
db.commit()
185183
return True if result == 1 else False
186184
except Exception:
187185
return False
188186

189-
def delete_auth_by_id(self, id: str, db: Optional[Session] = None) -> bool:
187+
def delete_auth_by_id(self, id: str) -> bool:
190188
try:
191-
with get_db_context(db) as db:
189+
with get_db() as db:
192190
# Delete User
193-
result = Users.delete_user_by_id(id, db=db)
191+
result = Users.delete_user_by_id(id)
194192

195193
if result:
196194
db.query(Auth).filter_by(id=id).delete()

backend/open_webui/models/notes.py

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
from typing import Optional
55
from functools import lru_cache
66

7-
from sqlalchemy.orm import Session
8-
from open_webui.internal.db import Base, get_db, get_db_context
7+
from open_webui.internal.db import Base, get_db
98
from open_webui.models.groups import Groups
109
from open_webui.utils.access_control import has_access
1110
from open_webui.models.users import User, UserModel, Users, UserResponse
@@ -212,9 +211,11 @@ def _has_permission(self, db, query, filter: dict, permission: str = "read"):
212211
return query
213212

214213
def insert_new_note(
215-
self, user_id: str, form_data: NoteForm, db: Optional[Session] = None
214+
self,
215+
form_data: NoteForm,
216+
user_id: str,
216217
) -> Optional[NoteModel]:
217-
with get_db_context(db) as db:
218+
with get_db() as db:
218219
note = NoteModel(
219220
**{
220221
"id": str(uuid.uuid4()),
@@ -232,9 +233,9 @@ def insert_new_note(
232233
return note
233234

234235
def get_notes(
235-
self, skip: int = 0, limit: int = 50, db: Optional[Session] = None
236+
self, skip: Optional[int] = None, limit: Optional[int] = None
236237
) -> list[NoteModel]:
237-
with get_db_context(db) as db:
238+
with get_db() as db:
238239
query = db.query(Note).order_by(Note.updated_at.desc())
239240
if skip is not None:
240241
query = query.offset(skip)
@@ -244,14 +245,9 @@ def get_notes(
244245
return [NoteModel.model_validate(note) for note in notes]
245246

246247
def search_notes(
247-
self,
248-
user_id: str,
249-
filter: dict = {},
250-
skip: int = 0,
251-
limit: int = 30,
252-
db: Optional[Session] = None,
248+
self, user_id: str, filter: dict = {}, skip: int = 0, limit: int = 30
253249
) -> NoteListResponse:
254-
with get_db_context(db) as db:
250+
with get_db() as db:
255251
query = db.query(Note, User).outerjoin(User, User.id == Note.user_id)
256252
if filter:
257253
query_key = filter.get("query")
@@ -345,13 +341,12 @@ def get_notes_by_user_id(
345341
self,
346342
user_id: str,
347343
permission: str = "read",
348-
skip: int = 0,
349-
limit: int = 50,
350-
db: Optional[Session] = None,
344+
skip: Optional[int] = None,
345+
limit: Optional[int] = None,
351346
) -> list[NoteModel]:
352-
with get_db_context(db) as db:
347+
with get_db() as db:
353348
user_group_ids = [
354-
group.id for group in Groups.get_groups_by_member_id(user_id, db=db)
349+
group.id for group in Groups.get_groups_by_member_id(user_id)
355350
]
356351

357352
query = db.query(Note).order_by(Note.updated_at.desc())
@@ -367,17 +362,15 @@ def get_notes_by_user_id(
367362
notes = query.all()
368363
return [NoteModel.model_validate(note) for note in notes]
369364

370-
def get_note_by_id(
371-
self, id: str, db: Optional[Session] = None
372-
) -> Optional[NoteModel]:
373-
with get_db_context(db) as db:
365+
def get_note_by_id(self, id: str) -> Optional[NoteModel]:
366+
with get_db() as db:
374367
note = db.query(Note).filter(Note.id == id).first()
375368
return NoteModel.model_validate(note) if note else None
376369

377370
def update_note_by_id(
378-
self, id: str, form_data: NoteUpdateForm, db: Optional[Session] = None
371+
self, id: str, form_data: NoteUpdateForm
379372
) -> Optional[NoteModel]:
380-
with get_db_context(db) as db:
373+
with get_db() as db:
381374
note = db.query(Note).filter(Note.id == id).first()
382375
if not note:
383376
return None
@@ -399,14 +392,11 @@ def update_note_by_id(
399392
db.commit()
400393
return NoteModel.model_validate(note) if note else None
401394

402-
def delete_note_by_id(self, id: str, db: Optional[Session] = None) -> bool:
403-
try:
404-
with get_db_context(db) as db:
405-
db.query(Note).filter(Note.id == id).delete()
406-
db.commit()
407-
return True
408-
except Exception:
409-
return False
395+
def delete_note_by_id(self, id: str):
396+
with get_db() as db:
397+
db.query(Note).filter(Note.id == id).delete()
398+
db.commit()
399+
return True
410400

411401

412402
Notes = NoteTable()

0 commit comments

Comments
 (0)