users.py 7.68 KB
Newer Older
1
from pydantic import BaseModel, ConfigDict, parse_obj_as
2
3
from typing import List, Union, Optional
import time
4
5
6

from sqlalchemy import String, Column, BigInteger, Text

Timothy J. Baek's avatar
Timothy J. Baek committed
7
8
from utils.misc import get_gravatar_url

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
9
from apps.webui.internal.db import Base, JSONField, Session, get_db
10
from apps.webui.models.chats import Chats
11

12
13
14
15
16
####################
# User DB Schema
####################


17
18
class User(Base):
    __tablename__ = "user"
Timothy J. Baek's avatar
Timothy J. Baek committed
19

20
21
22
23
    id = Column(String, primary_key=True)
    name = Column(String)
    email = Column(String)
    role = Column(String)
24
    profile_image_url = Column(Text)
Timothy J. Baek's avatar
Timothy J. Baek committed
25

26
27
28
    last_active_at = Column(BigInteger)
    updated_at = Column(BigInteger)
    created_at = Column(BigInteger)
Timothy J. Baek's avatar
Timothy J. Baek committed
29

30
31
32
    api_key = Column(String, nullable=True, unique=True)
    settings = Column(JSONField, nullable=True)
    info = Column(JSONField, nullable=True)
33

34
    oauth_sub = Column(Text, unique=True)
Timothy J. Baek's avatar
Timothy J. Baek committed
35
36


37
38
39
40
41
42
class UserSettings(BaseModel):
    ui: Optional[dict] = {}
    model_config = ConfigDict(extra="allow")
    pass


43
44
45
46
class UserModel(BaseModel):
    id: str
    name: str
    email: str
Timothy J. Baek's avatar
Timothy J. Baek committed
47
    role: str = "pending"
48
    profile_image_url: str
Timothy J. Baek's avatar
Timothy J. Baek committed
49
50
51
52
53

    last_active_at: int  # timestamp in epoch
    updated_at: int  # timestamp in epoch
    created_at: int  # timestamp in epoch

54
    api_key: Optional[str] = None
55
    settings: Optional[UserSettings] = None
Timothy J. Baek's avatar
Timothy J. Baek committed
56
    info: Optional[dict] = None
57

58
59
    oauth_sub: Optional[str] = None

60
61
    model_config = ConfigDict(from_attributes=True)

62
63
64
65
66
67

####################
# Forms
####################


Timothy J. Baek's avatar
Timothy J. Baek committed
68
69
70
71
72
class UserRoleUpdateForm(BaseModel):
    id: str
    role: str


Timothy J. Baek's avatar
Timothy J. Baek committed
73
74
75
76
77
78
class UserUpdateForm(BaseModel):
    name: str
    email: str
    profile_image_url: str
    password: Optional[str] = None

79

Timothy J. Baek's avatar
Timothy J. Baek committed
80
class UsersTable:
81

Timothy J. Baek's avatar
Timothy J. Baek committed
82
    def insert_new_user(
Danny Liu's avatar
Danny Liu committed
83
84
85
86
        self,
        id: str,
        name: str,
        email: str,
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
87
        profile_image_url: str = "/user.png",
Danny Liu's avatar
Danny Liu committed
88
        role: str = "pending",
89
        oauth_sub: Optional[str] = None,
Timothy J. Baek's avatar
Timothy J. Baek committed
90
    ) -> Optional[UserModel]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
        with get_db() as db:
            user = UserModel(
                **{
                    "id": id,
                    "name": name,
                    "email": email,
                    "role": role,
                    "profile_image_url": profile_image_url,
                    "last_active_at": int(time.time()),
                    "created_at": int(time.time()),
                    "updated_at": int(time.time()),
                    "oauth_sub": oauth_sub,
                }
            )
            result = User(**user.model_dump())
            db.add(result)
            db.commit()
            db.refresh(result)
            if result:
                return user
            else:
                return None
113
114

    def get_user_by_id(self, id: str) -> Optional[UserModel]:
115
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
116
117
118
            with get_db() as db:
                user = db.query(User).filter_by(id=id).first()
                return UserModel.model_validate(user)
119
120
        except Exception as e:
            return None
121
122

    def get_user_by_api_key(self, api_key: str) -> Optional[UserModel]:
123
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
124
125
126
127
            with get_db() as db:

                user = db.query(User).filter_by(api_key=api_key).first()
                return UserModel.model_validate(user)
128
        except Exception:
129
            return None
130
131

    def get_user_by_email(self, email: str) -> Optional[UserModel]:
132
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
133
134
135
136
            with get_db() as db:

                user = db.query(User).filter_by(email=email).first()
                return UserModel.model_validate(user)
137
        except Exception:
138
            return None
139

140
    def get_user_by_oauth_sub(self, sub: str) -> Optional[UserModel]:
141
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
142
143
144
145
            with get_db() as db:

                user = db.query(User).filter_by(oauth_sub=sub).first()
                return UserModel.model_validate(user)
146
        except Exception:
147
            return None
148
149

    def get_users(self, skip: int = 0, limit: int = 50) -> List[UserModel]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
150
151
152
153
154
155
156
        with get_db() as db:
            users = (
                db.query(User)
                # .offset(skip).limit(limit)
                .all()
            )
            return [UserModel.model_validate(user) for user in users]
157
158

    def get_num_users(self) -> Optional[int]:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
159
160
        with get_db() as db:
            return db.query(User).count()
161
162

    def get_first_user(self) -> UserModel:
163
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
164
165
166
            with get_db() as db:
                user = db.query(User).order_by(User.created_at).first()
                return UserModel.model_validate(user)
167
        except Exception:
168
            return None
169

170
    def update_user_role_by_id(self, id: str, role: str) -> Optional[UserModel]:
171
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
172
173
174
175
176
            with get_db() as db:
                db.query(User).filter_by(id=id).update({"role": role})
                db.commit()
                user = db.query(User).filter_by(id=id).first()
                return UserModel.model_validate(user)
177
        except Exception:
178
            return None
Timothy J. Baek's avatar
Timothy J. Baek committed
179

180
    def update_user_profile_image_url_by_id(
181
        self, id: str, profile_image_url: str
182
    ) -> Optional[UserModel]:
183
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
184
185
186
187
188
189
190
191
            with get_db() as db:
                db.query(User).filter_by(id=id).update(
                    {"profile_image_url": profile_image_url}
                )
                db.commit()

                user = db.query(User).filter_by(id=id).first()
                return UserModel.model_validate(user)
192
        except Exception:
193
            return None
194

195
    def update_user_last_active_by_id(self, id: str) -> Optional[UserModel]:
196
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
197
198
199
200
201
202
            with get_db() as db:

                db.query(User).filter_by(id=id).update(
                    {"last_active_at": int(time.time())}
                )
                db.commit()
Timothy J. Baek's avatar
Timothy J. Baek committed
203

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
204
205
                user = db.query(User).filter_by(id=id).first()
                return UserModel.model_validate(user)
206
        except Exception:
207
            return None
Timothy J. Baek's avatar
Timothy J. Baek committed
208

209
    def update_user_oauth_sub_by_id(
210
        self, id: str, oauth_sub: str
211
    ) -> Optional[UserModel]:
212
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
213
214
            with get_db() as db:
                db.query(User).filter_by(id=id).update({"oauth_sub": oauth_sub})
Timothy J. Baek's avatar
Timothy J. Baek committed
215
                db.commit()
216

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
217
218
                user = db.query(User).filter_by(id=id).first()
                return UserModel.model_validate(user)
219
        except Exception:
220
            return None
221

222
    def update_user_by_id(self, id: str, updated: dict) -> Optional[UserModel]:
223
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
224
225
226
            with get_db() as db:
                db.query(User).filter_by(id=id).update(updated)
                db.commit()
Timothy J. Baek's avatar
Timothy J. Baek committed
227

Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
228
229
230
                user = db.query(User).filter_by(id=id).first()
                return UserModel.model_validate(user)
                # return UserModel(**user.dict())
231
232
        except Exception as e:
            return None
233
234

    def delete_user_by_id(self, id: str) -> bool:
235
236
237
238
239
        try:
            # Delete User Chats
            result = Chats.delete_chats_by_user_id(id)

            if result:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
240
241
242
243
                with get_db() as db:
                    # Delete User
                    db.query(User).filter_by(id=id).delete()
                    db.commit()
244
245
246

                return True
            else:
247
                return False
248
        except Exception:
249
            return False
250

251
    def update_user_api_key_by_id(self, id: str, api_key: str) -> str:
252
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
253
254
255
256
            with get_db() as db:
                result = db.query(User).filter_by(id=id).update({"api_key": api_key})
                db.commit()
                return True if result == 1 else False
257
        except Exception:
258
            return False
259

260
    def get_user_api_key_by_id(self, id: str) -> Optional[str]:
261
        try:
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
262
263
264
            with get_db() as db:
                user = db.query(User).filter_by(id=id).first()
                return user.api_key
265
266
        except Exception as e:
            return None
Timothy J. Baek's avatar
refac  
Timothy J. Baek committed
267

268

269
Users = UsersTable()