users.py 7.64 KB
Newer Older
Timothy J. Baek's avatar
Timothy J. Baek committed
1
from fastapi import Response, Request
Timothy J. Baek's avatar
Timothy J. Baek committed
2
3
4
5
6
7
8
9
from fastapi import Depends, FastAPI, HTTPException, status
from datetime import datetime, timedelta
from typing import List, Union, Optional

from fastapi import APIRouter
from pydantic import BaseModel
import time
import uuid
10
import logging
Timothy J. Baek's avatar
Timothy J. Baek committed
11

12
from apps.webui.internal.db import get_db
13
14
15
16
17
18
19
from apps.webui.models.users import (
    UserModel,
    UserUpdateForm,
    UserRoleUpdateForm,
    UserSettings,
    Users,
)
20
21
from apps.webui.models.auths import Auths
from apps.webui.models.chats import Chats
Timothy J. Baek's avatar
Timothy J. Baek committed
22

23
24
25
26
27
28
from utils.utils import (
    get_verified_user,
    get_password_hash,
    get_current_user,
    get_admin_user,
)
Timothy J. Baek's avatar
Timothy J. Baek committed
29
30
from constants import ERROR_MESSAGES

31
from config import SRC_LOG_LEVELS
Timothy J. Baek's avatar
Timothy J. Baek committed
32

33
34
35
log = logging.getLogger(__name__)
log.setLevel(SRC_LOG_LEVELS["MODELS"])

Timothy J. Baek's avatar
Timothy J. Baek committed
36
37
38
39
40
41
42
43
router = APIRouter()

############################
# GetUsers
############################


@router.get("/", response_model=List[UserModel])
44
45
46
47
async def get_users(
    skip: int = 0, limit: int = 50, user=Depends(get_admin_user), db=Depends(get_db)
):
    return Users.get_users(db, skip, limit)
Timothy J. Baek's avatar
Timothy J. Baek committed
48
49


Timothy J. Baek's avatar
Timothy J. Baek committed
50
51
52
53
54
55
56
############################
# User Permissions
############################


@router.get("/permissions/user")
async def get_user_permissions(request: Request, user=Depends(get_admin_user)):
57
    return request.app.state.config.USER_PERMISSIONS
Timothy J. Baek's avatar
Timothy J. Baek committed
58
59
60
61
62
63


@router.post("/permissions/user")
async def update_user_permissions(
    request: Request, form_data: dict, user=Depends(get_admin_user)
):
64
65
    request.app.state.config.USER_PERMISSIONS = form_data
    return request.app.state.config.USER_PERMISSIONS
Timothy J. Baek's avatar
Timothy J. Baek committed
66
67


Timothy J. Baek's avatar
Timothy J. Baek committed
68
69
70
71
72
73
############################
# UpdateUserRole
############################


@router.post("/update/role", response_model=Optional[UserModel])
74
75
76
async def update_user_role(
    form_data: UserRoleUpdateForm, user=Depends(get_admin_user), db=Depends(get_db)
):
Timothy J. Baek's avatar
Timothy J. Baek committed
77

78
79
    if user.id != form_data.id and form_data.id != Users.get_first_user(db).id:
        return Users.update_user_role_by_id(db, form_data.id, form_data.role)
80
81
82
83
84

    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail=ERROR_MESSAGES.ACTION_PROHIBITED,
    )
Timothy J. Baek's avatar
Timothy J. Baek committed
85
86


87
88
89
90
91
92
############################
# GetUserSettingsBySessionUser
############################


@router.get("/user/settings", response_model=Optional[UserSettings])
93
94
95
96
async def get_user_settings_by_session_user(
    user=Depends(get_verified_user), db=Depends(get_db)
):
    user = Users.get_user_by_id(db, user.id)
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    if user:
        return user.settings
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


############################
# UpdateUserSettingsBySessionUser
############################


@router.post("/user/settings/update", response_model=UserSettings)
async def update_user_settings_by_session_user(
113
    form_data: UserSettings, user=Depends(get_verified_user), db=Depends(get_db)
114
):
115
    user = Users.update_user_by_id(db, user.id, {"settings": form_data.model_dump()})
116
117
118
119
120
121
122
123
124
    if user:
        return user.settings
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


Timothy J. Baek's avatar
Timothy J. Baek committed
125
126
127
128
129
130
############################
# GetUserInfoBySessionUser
############################


@router.get("/user/info", response_model=Optional[dict])
131
132
133
134
async def get_user_info_by_session_user(
    user=Depends(get_verified_user), db=Depends(get_db)
):
    user = Users.get_user_by_id(db, user.id)
Timothy J. Baek's avatar
Timothy J. Baek committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
    if user:
        return user.info
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


############################
# UpdateUserInfoBySessionUser
############################


@router.post("/user/info/update", response_model=Optional[dict])
150
151
async def update_user_info_by_session_user(
    form_data: dict, user=Depends(get_verified_user), db=Depends(get_db)
Timothy J. Baek's avatar
Timothy J. Baek committed
152
):
153
    user = Users.get_user_by_id(db, user.id)
Timothy J. Baek's avatar
Timothy J. Baek committed
154
155
156
157
    if user:
        if user.info is None:
            user.info = {}

158
159
160
        user = Users.update_user_by_id(
            db, user.id, {"info": {**user.info, **form_data}}
        )
Timothy J. Baek's avatar
Timothy J. Baek committed
161
162
163
164
165
166
167
168
169
170
171
172
173
174
        if user:
            return user.info
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=ERROR_MESSAGES.USER_NOT_FOUND,
            )
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


175
176
177
178
179
180
181
182
183
184
185
############################
# GetUserById
############################


class UserResponse(BaseModel):
    name: str
    profile_image_url: str


@router.get("/{user_id}", response_model=UserResponse)
186
187
188
async def get_user_by_id(
    user_id: str, user=Depends(get_verified_user), db=Depends(get_db)
):
189

190
191
    # Check if user_id is a shared chat
    # If it is, get the user_id from the chat
Timothy J. Baek's avatar
Timothy J. Baek committed
192
193
    if user_id.startswith("shared-"):
        chat_id = user_id.replace("shared-", "")
194
        chat = Chats.get_chat_by_id(db, chat_id)
Timothy J. Baek's avatar
Timothy J. Baek committed
195
196
197
198
199
200
201
202
        if chat:
            user_id = chat.user_id
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=ERROR_MESSAGES.USER_NOT_FOUND,
            )

203
    user = Users.get_user_by_id(db, user_id)
204
205
206
207
208
209
210
211
212
213

    if user:
        return UserResponse(name=user.name, profile_image_url=user.profile_image_url)
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.USER_NOT_FOUND,
        )


Timothy J. Baek's avatar
Timothy J. Baek committed
214
############################
Timothy J. Baek's avatar
Timothy J. Baek committed
215
# UpdateUserById
Timothy J. Baek's avatar
Timothy J. Baek committed
216
217
218
############################


Timothy J. Baek's avatar
Timothy J. Baek committed
219
220
@router.post("/{user_id}/update", response_model=Optional[UserModel])
async def update_user_by_id(
221
222
223
224
    user_id: str,
    form_data: UserUpdateForm,
    session_user=Depends(get_admin_user),
    db=Depends(get_db),
Timothy J. Baek's avatar
Timothy J. Baek committed
225
):
226
    user = Users.get_user_by_id(db, user_id)
Timothy J. Baek's avatar
Timothy J. Baek committed
227
228

    if user:
Timothy J. Baek's avatar
Timothy J. Baek committed
229
        if form_data.email.lower() != user.email:
230
            email_user = Users.get_user_by_email(db, form_data.email.lower())
Timothy J. Baek's avatar
Timothy J. Baek committed
231
232
233
234
235
236
237
238
            if email_user:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=ERROR_MESSAGES.EMAIL_TAKEN,
                )

        if form_data.password:
            hashed = get_password_hash(form_data.password)
239
            log.debug(f"hashed: {hashed}")
240
            Auths.update_user_password_by_id(db, user_id, hashed)
Timothy J. Baek's avatar
Timothy J. Baek committed
241

242
        Auths.update_email_by_id(db, user_id, form_data.email.lower())
Timothy J. Baek's avatar
Timothy J. Baek committed
243
        updated_user = Users.update_user_by_id(
244
            db,
Timothy J. Baek's avatar
Timothy J. Baek committed
245
246
247
            user_id,
            {
                "name": form_data.name,
Timothy J. Baek's avatar
Timothy J. Baek committed
248
                "email": form_data.email.lower(),
Timothy J. Baek's avatar
Timothy J. Baek committed
249
250
251
252
253
254
255
                "profile_image_url": form_data.profile_image_url,
            },
        )

        if updated_user:
            return updated_user

Timothy J. Baek's avatar
Timothy J. Baek committed
256
        raise HTTPException(
Timothy J. Baek's avatar
Timothy J. Baek committed
257
            status_code=status.HTTP_400_BAD_REQUEST,
258
            detail=ERROR_MESSAGES.DEFAULT(),
Timothy J. Baek's avatar
Timothy J. Baek committed
259
        )
260

261
262
263
264
265
    raise HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST,
        detail=ERROR_MESSAGES.USER_NOT_FOUND,
    )

266
267

############################
Timothy J. Baek's avatar
Timothy J. Baek committed
268
# DeleteUserById
269
270
271
272
############################


@router.delete("/{user_id}", response_model=bool)
273
274
275
async def delete_user_by_id(
    user_id: str, user=Depends(get_admin_user), db=Depends(get_db)
):
276
    if user.id != user_id:
277
        result = Auths.delete_auth_by_id(db, user_id)
278
279
280
281

        if result:
            return True

282
        raise HTTPException(
283
284
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=ERROR_MESSAGES.DELETE_USER_ERROR,
285
        )
286
287
288
289
290

    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail=ERROR_MESSAGES.ACTION_PROHIBITED,
    )